| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  | from __future__ import annotations | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  | import datetime | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-24 22:40:16 +01:00
										 |  |  | from Options import Choice, OptionDict, OptionSet, ItemDict, Option, DefaultOnToggle, Range, DeathLink, Toggle | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  | from schema import Schema, Optional, And, Or | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # schema helpers | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  | FloatRange = lambda low, high: And(Or(int, float), lambda f: low <= f <= high) | 
					
						
							|  |  |  | LuaBool = Or(bool, And(int, lambda n: n in (0, 1))) | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MaxSciencePack(Choice): | 
					
						
							| 
									
										
										
										
											2022-11-27 04:01:10 +01:00
										 |  |  |     """Maximum level of science pack required to complete the game.
 | 
					
						
							|  |  |  |     This also affects the relative cost of silo and satellite recipes if they are randomized. | 
					
						
							|  |  |  |     That is the only thing in which the Utility Science Pack and Space Science Pack settings differ."""
 | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Maximum Required Science Pack" | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     option_automation_science_pack = 0 | 
					
						
							|  |  |  |     option_logistic_science_pack = 1 | 
					
						
							|  |  |  |     option_military_science_pack = 2 | 
					
						
							|  |  |  |     option_chemical_science_pack = 3 | 
					
						
							|  |  |  |     option_production_science_pack = 4 | 
					
						
							|  |  |  |     option_utility_science_pack = 5 | 
					
						
							|  |  |  |     option_space_science_pack = 6 | 
					
						
							|  |  |  |     default = 6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_allowed_packs(self): | 
					
						
							|  |  |  |         return {option.replace("_", "-") for option, value in self.options.items() if value <= self.value} - \ | 
					
						
							|  |  |  |                {"space-science-pack"}  # with rocket launch being the goal, post-launch techs don't make sense | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def get_ordered_science_packs(cls): | 
					
						
							|  |  |  |         return [option.replace("_", "-") for option, value in sorted(cls.options.items(), key=lambda pair: pair[1])] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_max_pack(self): | 
					
						
							|  |  |  |         return self.get_ordered_science_packs()[self.value].replace("_", "-") | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 23:18:17 -08:00
										 |  |  | class Goal(Choice): | 
					
						
							|  |  |  |     """Goal required to complete the game.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Goal" | 
					
						
							| 
									
										
										
										
											2021-11-30 23:18:17 -08:00
										 |  |  |     option_rocket = 0 | 
					
						
							|  |  |  |     option_satellite = 1 | 
					
						
							|  |  |  |     default = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-28 21:00:06 +02:00
										 |  |  | class TechCost(Range): | 
					
						
							|  |  |  |     range_start = 1 | 
					
						
							|  |  |  |     range_end = 10000 | 
					
						
							|  |  |  |     default = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MinTechCost(TechCost): | 
					
						
							|  |  |  |     """The cheapest a Technology can be in Science Packs.""" | 
					
						
							|  |  |  |     display_name = "Minimum Science Pack Cost" | 
					
						
							|  |  |  |     default = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MaxTechCost(TechCost): | 
					
						
							|  |  |  |     """The most expensive a Technology can be in Science Packs.""" | 
					
						
							|  |  |  |     display_name = "Maximum Science Pack Cost" | 
					
						
							|  |  |  |     default = 500 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-28 00:38:12 +01:00
										 |  |  | class TechCostDistribution(Choice): | 
					
						
							|  |  |  |     """Random distribution of costs of the Science Packs.
 | 
					
						
							|  |  |  |     Even: any number between min and max is equally likely. | 
					
						
							|  |  |  |     Low: low costs, near the minimum, are more likely. | 
					
						
							|  |  |  |     Middle: medium costs, near the average, are more likely. | 
					
						
							|  |  |  |     High: high costs, near the maximum, are more likely."""
 | 
					
						
							|  |  |  |     display_name = "Tech Cost Distribution" | 
					
						
							|  |  |  |     option_even = 0 | 
					
						
							|  |  |  |     option_low = 1 | 
					
						
							|  |  |  |     option_middle = 2 | 
					
						
							|  |  |  |     option_high = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-28 21:00:06 +02:00
										 |  |  | class TechCostMix(Range): | 
					
						
							|  |  |  |     """Percent chance that a preceding Science Pack is also required.
 | 
					
						
							|  |  |  |     Chance is rolled per preceding pack."""
 | 
					
						
							|  |  |  |     display_name = "Science Pack Cost Mix" | 
					
						
							|  |  |  |     range_end = 100 | 
					
						
							|  |  |  |     default = 70 | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-28 00:30:05 +01:00
										 |  |  | class RampingTechCosts(Toggle): | 
					
						
							|  |  |  |     """Forces the amount of Science Packs required to ramp up with the highest involved Pack. Average is preserved.
 | 
					
						
							|  |  |  |     For example: | 
					
						
							|  |  |  |     off: Automation (red)/Logistics (green) sciences can range from 1 to 1000 Science Packs, | 
					
						
							|  |  |  |     on: Automation (red) ranges to ~500 packs and Logistics (green) from ~500 to 1000 Science Packs"""
 | 
					
						
							|  |  |  |     display_name = "Ramping Tech Costs" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 01:41:41 +02:00
										 |  |  | class Silo(Choice): | 
					
						
							| 
									
										
										
										
											2021-07-25 22:12:03 +02:00
										 |  |  |     """Ingredients to craft rocket silo or auto-place if set to spawn.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Rocket Silo" | 
					
						
							| 
									
										
										
										
											2021-07-24 01:41:41 +02:00
										 |  |  |     option_vanilla = 0 | 
					
						
							|  |  |  |     option_randomize_recipe = 1 | 
					
						
							| 
									
										
										
										
											2021-07-25 22:12:03 +02:00
										 |  |  |     option_spawn = 2 | 
					
						
							| 
									
										
										
										
											2021-07-24 01:41:41 +02:00
										 |  |  |     default = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 16:27:17 -08:00
										 |  |  | class Satellite(Choice): | 
					
						
							|  |  |  |     """Ingredients to craft satellite.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Satellite" | 
					
						
							| 
									
										
										
										
											2021-11-20 20:20:38 -08:00
										 |  |  |     option_vanilla = 0 | 
					
						
							| 
									
										
										
										
											2021-11-20 16:27:17 -08:00
										 |  |  |     option_randomize_recipe = 1 | 
					
						
							|  |  |  |     default = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | class FreeSamples(Choice): | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |     """Get free items with your technologies.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Free Samples" | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     option_none = 0 | 
					
						
							|  |  |  |     option_single_craft = 1 | 
					
						
							|  |  |  |     option_half_stack = 2 | 
					
						
							|  |  |  |     option_stack = 3 | 
					
						
							|  |  |  |     default = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TechTreeLayout(Choice): | 
					
						
							| 
									
										
										
										
											2022-11-27 04:01:10 +01:00
										 |  |  |     """Selects how the tech tree nodes are interwoven.
 | 
					
						
							|  |  |  |     Single: No dependencies | 
					
						
							|  |  |  |     Diamonds: Several grid graphs (4/9/16 nodes each) | 
					
						
							|  |  |  |     Pyramids: Several top halves of diamonds (6/10/15 nodes each) | 
					
						
							|  |  |  |     Funnels: Several bottom halves of diamonds (6/10/15 nodes each) | 
					
						
							|  |  |  |     Trees: Several trees | 
					
						
							|  |  |  |     Choices: A single balanced binary tree | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Technology Tree Layout" | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     option_single = 0 | 
					
						
							|  |  |  |     option_small_diamonds = 1 | 
					
						
							|  |  |  |     option_medium_diamonds = 2 | 
					
						
							|  |  |  |     option_large_diamonds = 3 | 
					
						
							|  |  |  |     option_small_pyramids = 4 | 
					
						
							|  |  |  |     option_medium_pyramids = 5 | 
					
						
							|  |  |  |     option_large_pyramids = 6 | 
					
						
							|  |  |  |     option_small_funnels = 7 | 
					
						
							|  |  |  |     option_medium_funnels = 8 | 
					
						
							|  |  |  |     option_large_funnels = 9 | 
					
						
							| 
									
										
										
										
											2021-12-18 13:01:24 +01:00
										 |  |  |     option_trees = 10 | 
					
						
							|  |  |  |     option_choices = 11 | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     default = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TechTreeInformation(Choice): | 
					
						
							| 
									
										
										
										
											2022-11-27 04:01:10 +01:00
										 |  |  |     """How much information should be displayed in the tech tree.
 | 
					
						
							|  |  |  |     None: No indication what a research unlocks | 
					
						
							|  |  |  |     Advancement: Indicators which researches unlock items that are considered logical advancements | 
					
						
							|  |  |  |     Full: Labels with exact names and recipients of unlocked items; all researches are prefilled into the !hint command. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Technology Tree Information" | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     option_none = 0 | 
					
						
							|  |  |  |     option_advancement = 1 | 
					
						
							|  |  |  |     option_full = 2 | 
					
						
							|  |  |  |     default = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RecipeTime(Choice): | 
					
						
							| 
									
										
										
										
											2021-11-23 19:10:26 +01:00
										 |  |  |     """Randomize the time it takes for any recipe to craft, this includes smelting, chemical lab, hand crafting etc.
 | 
					
						
							|  |  |  |     Fast: 0.25X - 1X | 
					
						
							|  |  |  |     Normal: 0.5X - 2X | 
					
						
							|  |  |  |     Slow: 1X - 4X | 
					
						
							|  |  |  |     Chaos: 0.25X - 4X | 
					
						
							|  |  |  |     New category: ignores vanilla recipe time and rolls new one | 
					
						
							|  |  |  |     New Fast: 0.25 - 2 seconds | 
					
						
							|  |  |  |     New Normal: 0.25 - 10 seconds | 
					
						
							|  |  |  |     New Slow:  5 - 10 seconds | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Recipe Time" | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     option_vanilla = 0 | 
					
						
							|  |  |  |     option_fast = 1 | 
					
						
							|  |  |  |     option_normal = 2 | 
					
						
							|  |  |  |     option_slow = 4 | 
					
						
							|  |  |  |     option_chaos = 5 | 
					
						
							| 
									
										
										
										
											2021-11-23 19:10:26 +01:00
										 |  |  |     option_new_fast = 6 | 
					
						
							|  |  |  |     option_new_normal = 7 | 
					
						
							|  |  |  |     option_new_slow = 8 | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  | class Progressive(Choice): | 
					
						
							| 
									
										
										
										
											2021-12-22 14:00:41 +01:00
										 |  |  |     """Merges together Technologies like "automation-1" to "automation-3" into 3 copies of "Progressive Automation",
 | 
					
						
							|  |  |  |     which awards them in order."""
 | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Progressive Technologies" | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  |     option_off = 0 | 
					
						
							| 
									
										
										
										
											2021-08-09 09:15:41 +02:00
										 |  |  |     option_grouped_random = 1 | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  |     option_on = 2 | 
					
						
							|  |  |  |     default = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def want_progressives(self, random): | 
					
						
							| 
									
										
										
										
											2021-08-09 10:05:45 +02:00
										 |  |  |         return random.choice([True, False]) if self.value == self.option_grouped_random else bool(self.value) | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-08 00:02:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  | class RecipeIngredients(Choice): | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |     """Select if rocket, or rocket + science pack ingredients should be random.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Random Recipe Ingredients Level" | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  |     option_rocket = 0 | 
					
						
							|  |  |  |     option_science_pack = 1 | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-08 00:02:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  | class RecipeIngredientsOffset(Range): | 
					
						
							|  |  |  |     """When randomizing ingredients, remove or add this many "slots" of items.
 | 
					
						
							|  |  |  |     For example, at -1 a randomized Automation Science Pack will only require 1 ingredient, instead of 2."""
 | 
					
						
							|  |  |  |     display_name = "Randomized Recipe Ingredients Offset" | 
					
						
							|  |  |  |     range_start = -1 | 
					
						
							|  |  |  |     range_end = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-25 04:13:25 +02:00
										 |  |  | class FactorioStartItems(ItemDict): | 
					
						
							| 
									
										
										
										
											2021-12-22 14:00:41 +01:00
										 |  |  |     """Mapping of Factorio internal item-name to amount granted on start.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Starting Items" | 
					
						
							| 
									
										
										
										
											2021-10-25 04:13:25 +02:00
										 |  |  |     verify_item_name = False | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     default = {"burner-mining-drill": 19, "stone-furnace": 19} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-02 15:27:00 -08:00
										 |  |  | class FactorioFreeSampleBlacklist(OptionSet): | 
					
						
							| 
									
										
										
										
											2021-12-22 14:00:41 +01:00
										 |  |  |     """Set of items that should never be granted from Free Samples""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Free Sample Blacklist" | 
					
						
							| 
									
										
										
										
											2021-12-02 09:26:51 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-02 15:27:48 -08:00
										 |  |  | class FactorioFreeSampleWhitelist(OptionSet): | 
					
						
							| 
									
										
										
										
											2021-12-22 14:00:41 +01:00
										 |  |  |     """Overrides any free sample blacklist present. This may ruin the balance of the mod, be warned.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Free Sample Whitelist" | 
					
						
							| 
									
										
										
										
											2021-12-02 15:27:48 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | class TrapCount(Range): | 
					
						
							| 
									
										
										
										
											2022-10-28 21:00:06 +02:00
										 |  |  |     range_end = 25 | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AttackTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received trigger an attack on your base.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Attack Traps" | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  | class TeleportTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received trigger a random teleport.""" | 
					
						
							|  |  |  |     display_name = "Teleport Traps" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GrenadeTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received trigger a grenade explosion on each player.""" | 
					
						
							|  |  |  |     display_name = "Grenade Traps" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ClusterGrenadeTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received trigger a cluster grenade explosion on each player.""" | 
					
						
							|  |  |  |     display_name = "Cluster Grenade Traps" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ArtilleryTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received trigger an artillery shell on each player.""" | 
					
						
							|  |  |  |     display_name = "Artillery Traps" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AtomicRocketTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received trigger an atomic rocket explosion on each player.
 | 
					
						
							|  |  |  |     Warning: there is no warning. The launch is instantaneous."""
 | 
					
						
							|  |  |  |     display_name = "Atomic Rocket Traps" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | class EvolutionTrapCount(TrapCount): | 
					
						
							|  |  |  |     """Trap items that when received increase the enemy evolution.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Evolution Traps" | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  |     range_end = 10 | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EvolutionTrapIncrease(Range): | 
					
						
							| 
									
										
										
										
											2022-01-17 19:15:09 -06:00
										 |  |  |     """How much an Evolution Trap increases the enemy evolution.
 | 
					
						
							|  |  |  |     Increases scale down proportionally to the session's current evolution factor | 
					
						
							|  |  |  |     (40 increase at 0.50 will add 0.20... 40 increase at 0.75 will add 0.10...)"""
 | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Evolution Trap % Effect" | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  |     range_start = 1 | 
					
						
							|  |  |  |     default = 10 | 
					
						
							|  |  |  |     range_end = 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-02 01:29:49 +02:00
										 |  |  | class FactorioWorldGen(OptionDict): | 
					
						
							| 
									
										
										
										
											2021-12-22 14:00:41 +01:00
										 |  |  |     """World Generation settings. Overview of options at https://wiki.factorio.com/Map_generator,
 | 
					
						
							|  |  |  |     with in-depth documentation at https://lua-api.factorio.com/latest/Concepts.html#MapGenSettings""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "World Generation" | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |     # FIXME: do we want default be a rando-optimized default or in-game DS? | 
					
						
							|  |  |  |     value: typing.Dict[str, typing.Dict[str, typing.Any]] | 
					
						
							| 
									
										
										
										
											2021-07-23 00:47:18 +02:00
										 |  |  |     default = { | 
					
						
							|  |  |  |         "terrain_segmentation": 0.5, | 
					
						
							|  |  |  |         "water": 1.5, | 
					
						
							|  |  |  |         "autoplace_controls": { | 
					
						
							|  |  |  |             "coal": {"frequency": 1, "size": 3, "richness": 6}, | 
					
						
							|  |  |  |             "copper-ore": {"frequency": 1, "size": 3, "richness": 6}, | 
					
						
							|  |  |  |             "crude-oil": {"frequency": 1, "size": 3, "richness": 6}, | 
					
						
							|  |  |  |             "enemy-base": {"frequency": 1, "size": 1, "richness": 1}, | 
					
						
							|  |  |  |             "iron-ore": {"frequency": 1, "size": 3, "richness": 6}, | 
					
						
							|  |  |  |             "stone": {"frequency": 1, "size": 3, "richness": 6}, | 
					
						
							|  |  |  |             "trees": {"frequency": 1, "size": 1, "richness": 1}, | 
					
						
							|  |  |  |             "uranium-ore": {"frequency": 1, "size": 3, "richness": 6} | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "seed": None, | 
					
						
							|  |  |  |         "starting_area": 1, | 
					
						
							|  |  |  |         "peaceful_mode": False, | 
					
						
							|  |  |  |         "cliff_settings": { | 
					
						
							|  |  |  |             "name": "cliff", | 
					
						
							|  |  |  |             "cliff_elevation_0": 10, | 
					
						
							|  |  |  |             "cliff_elevation_interval": 40, | 
					
						
							|  |  |  |             "richness": 1 | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "property_expression_names": { | 
					
						
							|  |  |  |             "control-setting:moisture:bias": 0, | 
					
						
							|  |  |  |             "control-setting:moisture:frequency:multiplier": 1, | 
					
						
							|  |  |  |             "control-setting:aux:bias": 0, | 
					
						
							|  |  |  |             "control-setting:aux:frequency:multiplier": 1 | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "pollution": { | 
					
						
							|  |  |  |             "enabled": True, | 
					
						
							|  |  |  |             "diffusion_ratio": 0.02, | 
					
						
							|  |  |  |             "ageing": 1, | 
					
						
							|  |  |  |             "enemy_attack_pollution_consumption_modifier": 1, | 
					
						
							|  |  |  |             "min_pollution_to_damage_trees": 60, | 
					
						
							|  |  |  |             "pollution_restored_per_tree_damage": 10 | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "enemy_evolution": { | 
					
						
							|  |  |  |             "enabled": True, | 
					
						
							|  |  |  |             "time_factor": 40.0e-7, | 
					
						
							|  |  |  |             "destroy_factor": 200.0e-5, | 
					
						
							|  |  |  |             "pollution_factor": 9.0e-7 | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "enemy_expansion": { | 
					
						
							|  |  |  |             "enabled": True, | 
					
						
							|  |  |  |             "max_expansion_distance": 7, | 
					
						
							|  |  |  |             "settler_group_min_size": 5, | 
					
						
							|  |  |  |             "settler_group_max_size": 20, | 
					
						
							|  |  |  |             "min_expansion_cooldown": 14400, | 
					
						
							|  |  |  |             "max_expansion_cooldown": 216000 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |     schema = Schema({ | 
					
						
							|  |  |  |         "basic": { | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |             Optional("terrain_segmentation"): FloatRange(0.166, 6), | 
					
						
							|  |  |  |             Optional("water"): FloatRange(0.166, 6), | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |             Optional("autoplace_controls"): { | 
					
						
							|  |  |  |                 str: { | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |                     "frequency": FloatRange(0, 6), | 
					
						
							|  |  |  |                     "size": FloatRange(0, 6), | 
					
						
							| 
									
										
										
										
											2021-07-23 00:47:18 +02:00
										 |  |  |                     "richness": FloatRange(0.166, 6) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |             Optional("seed"): Or(None, And(int, lambda n: n >= 0)), | 
					
						
							| 
									
										
										
										
											2022-05-05 01:59:41 +02:00
										 |  |  |             Optional("width"): And(int, lambda n: n >= 0), | 
					
						
							|  |  |  |             Optional("height"): And(int, lambda n: n >= 0), | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |             Optional("starting_area"): FloatRange(0.166, 6), | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |             Optional("peaceful_mode"): LuaBool, | 
					
						
							|  |  |  |             Optional("cliff_settings"): { | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |                 "name": str, "cliff_elevation_0": FloatRange(0, 99), | 
					
						
							|  |  |  |                 "cliff_elevation_interval": FloatRange(0.066, 241),  # 40/frequency | 
					
						
							| 
									
										
										
										
											2021-07-23 00:47:18 +02:00
										 |  |  |                 "richness": FloatRange(0, 6) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             Optional("property_expression_names"): Schema({ | 
					
						
							| 
									
										
										
										
											2022-05-05 02:02:50 +02:00
										 |  |  |                 Optional("control-setting:moisture:bias"): FloatRange(-0.5, 0.5), | 
					
						
							|  |  |  |                 Optional("control-setting:moisture:frequency:multiplier"): FloatRange(0.166, 6), | 
					
						
							|  |  |  |                 Optional("control-setting:aux:bias"): FloatRange(-0.5, 0.5), | 
					
						
							|  |  |  |                 Optional("control-setting:aux:frequency:multiplier"): FloatRange(0.166, 6), | 
					
						
							|  |  |  |                 Optional(str): object  # allow overriding all properties | 
					
						
							|  |  |  |             }), | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |         }, | 
					
						
							|  |  |  |         "advanced": { | 
					
						
							|  |  |  |             Optional("pollution"): { | 
					
						
							|  |  |  |                 Optional("enabled"): LuaBool, | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |                 Optional("diffusion_ratio"): FloatRange(0, 0.25), | 
					
						
							|  |  |  |                 Optional("ageing"): FloatRange(0.1, 4), | 
					
						
							|  |  |  |                 Optional("enemy_attack_pollution_consumption_modifier"): FloatRange(0.1, 4), | 
					
						
							|  |  |  |                 Optional("min_pollution_to_damage_trees"): FloatRange(0, 9999), | 
					
						
							| 
									
										
										
										
											2021-07-23 00:47:18 +02:00
										 |  |  |                 Optional("pollution_restored_per_tree_damage"): FloatRange(0, 9999) | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             Optional("enemy_evolution"): { | 
					
						
							|  |  |  |                 Optional("enabled"): LuaBool, | 
					
						
							|  |  |  |                 Optional("time_factor"): FloatRange(0, 1000e-7), | 
					
						
							|  |  |  |                 Optional("destroy_factor"): FloatRange(0, 1000e-5), | 
					
						
							|  |  |  |                 Optional("pollution_factor"): FloatRange(0, 1000e-7), | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             Optional("enemy_expansion"): { | 
					
						
							|  |  |  |                 Optional("enabled"): LuaBool, | 
					
						
							|  |  |  |                 Optional("max_expansion_distance"): FloatRange(2, 20), | 
					
						
							|  |  |  |                 Optional("settler_group_min_size"): FloatRange(1, 20), | 
					
						
							|  |  |  |                 Optional("settler_group_max_size"): FloatRange(1, 50), | 
					
						
							|  |  |  |                 Optional("min_expansion_cooldown"): FloatRange(3600, 216000), | 
					
						
							|  |  |  |                 Optional("max_expansion_cooldown"): FloatRange(18000, 648000) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value: typing.Dict[str, typing.Any]): | 
					
						
							| 
									
										
										
										
											2021-07-23 00:47:18 +02:00
										 |  |  |         advanced = {"pollution", "enemy_evolution", "enemy_expansion"} | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |         self.value = { | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |             "basic": {key: value[key] for key in value.keys() - advanced}, | 
					
						
							|  |  |  |             "advanced": {key: value[key] for key in value.keys() & advanced} | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-23 00:47:18 +02:00
										 |  |  |         # verify min_values <= max_values | 
					
						
							|  |  |  |         def optional_min_lte_max(container, min_key, max_key): | 
					
						
							|  |  |  |             min_val = container.get(min_key, None) | 
					
						
							|  |  |  |             max_val = container.get(max_key, None) | 
					
						
							|  |  |  |             if min_val is not None and max_val is not None and min_val > max_val: | 
					
						
							|  |  |  |                 raise ValueError(f"{min_key} can't be bigger than {max_key}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         enemy_expansion = self.value["advanced"].get("enemy_expansion", {}) | 
					
						
							|  |  |  |         optional_min_lte_max(enemy_expansion, "settler_group_min_size", "settler_group_max_size") | 
					
						
							|  |  |  |         optional_min_lte_max(enemy_expansion, "min_expansion_cooldown", "max_expansion_cooldown") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-19 01:02:23 +02:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_any(cls, data: typing.Dict[str, typing.Any]) -> FactorioWorldGen: | 
					
						
							|  |  |  |         if type(data) == dict: | 
					
						
							|  |  |  |             return cls(data) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise NotImplementedError(f"Cannot Convert from non-dictionary, got {type(data)}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 04:57:57 +02:00
										 |  |  | class ImportedBlueprint(DefaultOnToggle): | 
					
						
							| 
									
										
										
										
											2021-12-22 14:00:41 +01:00
										 |  |  |     """Allow or Disallow Blueprints from outside the current savegame.""" | 
					
						
							| 
									
										
										
										
											2022-02-02 16:29:29 +01:00
										 |  |  |     display_name = "Blueprints" | 
					
						
							| 
									
										
										
										
											2021-08-02 04:57:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-24 22:40:16 +01:00
										 |  |  | class EnergyLink(Toggle): | 
					
						
							|  |  |  |     """Allow sending energy to other worlds. 25% of the energy is lost in the transfer.""" | 
					
						
							|  |  |  |     display_name = "EnergyLink" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  | factorio_options: typing.Dict[str, type(Option)] = { | 
					
						
							|  |  |  |     "max_science_pack": MaxSciencePack, | 
					
						
							| 
									
										
										
										
											2021-11-30 23:18:17 -08:00
										 |  |  |     "goal": Goal, | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     "tech_tree_layout": TechTreeLayout, | 
					
						
							| 
									
										
										
										
											2022-10-28 21:00:06 +02:00
										 |  |  |     "min_tech_cost": MinTechCost, | 
					
						
							|  |  |  |     "max_tech_cost": MaxTechCost, | 
					
						
							| 
									
										
										
										
											2023-01-28 00:38:12 +01:00
										 |  |  |     "tech_cost_distribution": TechCostDistribution, | 
					
						
							| 
									
										
										
										
											2022-10-28 21:00:06 +02:00
										 |  |  |     "tech_cost_mix": TechCostMix, | 
					
						
							| 
									
										
										
										
											2023-01-28 00:30:05 +01:00
										 |  |  |     "ramping_tech_costs": RampingTechCosts, | 
					
						
							| 
									
										
										
										
											2021-07-24 01:41:41 +02:00
										 |  |  |     "silo": Silo, | 
					
						
							| 
									
										
										
										
											2021-11-20 16:27:17 -08:00
										 |  |  |     "satellite": Satellite, | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     "free_samples": FreeSamples, | 
					
						
							|  |  |  |     "tech_tree_information": TechTreeInformation, | 
					
						
							|  |  |  |     "starting_items": FactorioStartItems, | 
					
						
							| 
									
										
										
										
											2021-12-02 09:26:51 -08:00
										 |  |  |     "free_sample_blacklist": FactorioFreeSampleBlacklist, | 
					
						
							| 
									
										
										
										
											2021-12-02 15:27:48 -08:00
										 |  |  |     "free_sample_whitelist": FactorioFreeSampleWhitelist, | 
					
						
							| 
									
										
										
										
											2021-06-25 23:32:13 +02:00
										 |  |  |     "recipe_time": RecipeTime, | 
					
						
							| 
									
										
										
										
											2021-07-07 10:14:58 +02:00
										 |  |  |     "recipe_ingredients": RecipeIngredients, | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  |     "recipe_ingredients_offset": RecipeIngredientsOffset, | 
					
						
							| 
									
										
										
										
											2021-08-02 04:57:57 +02:00
										 |  |  |     "imported_blueprints": ImportedBlueprint, | 
					
						
							| 
									
										
										
										
											2021-07-04 22:21:53 +02:00
										 |  |  |     "world_gen": FactorioWorldGen, | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  |     "progressive": Progressive, | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  |     "teleport_traps": TeleportTrapCount, | 
					
						
							|  |  |  |     "grenade_traps": GrenadeTrapCount, | 
					
						
							|  |  |  |     "cluster_grenade_traps": ClusterGrenadeTrapCount, | 
					
						
							|  |  |  |     "artillery_traps": ArtilleryTrapCount, | 
					
						
							|  |  |  |     "atomic_rocket_traps": AtomicRocketTrapCount, | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  |     "attack_traps": AttackTrapCount, | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  |     "evolution_traps": EvolutionTrapCount, | 
					
						
							| 
									
										
										
										
											2021-08-04 05:40:51 +02:00
										 |  |  |     "evolution_trap_increase": EvolutionTrapIncrease, | 
					
						
							| 
									
										
										
										
											2022-02-24 22:40:16 +01:00
										 |  |  |     "death_link": DeathLink, | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  |     "energy_link": EnergyLink, | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-03-15 17:03:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | # spoilers below. If you spoil it for yourself, please at least don't spoil it for anyone else. | 
					
						
							|  |  |  | if datetime.datetime.today().month == 4: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ChunkShuffle(Toggle): | 
					
						
							|  |  |  |         """Entrance Randomizer.""" | 
					
						
							|  |  |  |         display_name = "Chunk Shuffle" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if datetime.datetime.today().day > 1: | 
					
						
							|  |  |  |         ChunkShuffle.__doc__ += """
 | 
					
						
							|  |  |  |         2023 April Fool's option. Shuffles chunk border transitions.""" | 
					
						
							|  |  |  |     factorio_options["chunk_shuffle"] = ChunkShuffle |