2021-07-18 23:02:23 +00:00
|
|
|
from __future__ import annotations
|
2024-09-17 22:18:17 +00:00
|
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
import typing
|
2021-06-25 21:32:13 +00:00
|
|
|
|
2021-07-18 23:02:23 +00:00
|
|
|
from schema import Schema, Optional, And, Or
|
|
|
|
|
2024-11-11 10:43:16 +00:00
|
|
|
from Options import Choice, OptionDict, OptionSet, DefaultOnToggle, Range, DeathLink, Toggle, \
|
2024-11-30 03:08:17 +00:00
|
|
|
StartInventoryPool, PerGameCommonOptions, OptionGroup
|
2024-09-17 22:18:17 +00:00
|
|
|
|
2021-07-18 23:02:23 +00:00
|
|
|
# schema helpers
|
2021-07-22 16:21:31 +00: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 21:32:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
class MaxSciencePack(Choice):
|
2022-11-27 03:01:10 +00: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 15:29:29 +00:00
|
|
|
display_name = "Maximum Required Science Pack"
|
2021-06-25 21:32:13 +00: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 08:14:58 +00: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 21:32:13 +00:00
|
|
|
|
2021-07-22 16:21:31 +00:00
|
|
|
|
2021-12-01 07:18:17 +00:00
|
|
|
class Goal(Choice):
|
|
|
|
"""Goal required to complete the game."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Goal"
|
2021-12-01 07:18:17 +00:00
|
|
|
option_rocket = 0
|
|
|
|
option_satellite = 1
|
|
|
|
default = 0
|
|
|
|
|
|
|
|
|
2022-10-28 19:00:06 +00: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-27 23:38:12 +00: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 19:00:06 +00: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 21:32:13 +00:00
|
|
|
|
|
|
|
|
2023-01-27 23:30:05 +00: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-23 23:41:41 +00:00
|
|
|
class Silo(Choice):
|
2021-07-25 20:12:03 +00:00
|
|
|
"""Ingredients to craft rocket silo or auto-place if set to spawn."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Rocket Silo"
|
2021-07-23 23:41:41 +00:00
|
|
|
option_vanilla = 0
|
|
|
|
option_randomize_recipe = 1
|
2021-07-25 20:12:03 +00:00
|
|
|
option_spawn = 2
|
2021-07-23 23:41:41 +00:00
|
|
|
default = 0
|
|
|
|
|
|
|
|
|
2021-11-21 00:27:17 +00:00
|
|
|
class Satellite(Choice):
|
|
|
|
"""Ingredients to craft satellite."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Satellite"
|
2021-11-21 04:20:38 +00:00
|
|
|
option_vanilla = 0
|
2021-11-21 00:27:17 +00:00
|
|
|
option_randomize_recipe = 1
|
|
|
|
default = 0
|
|
|
|
|
|
|
|
|
2021-06-25 21:32:13 +00:00
|
|
|
class FreeSamples(Choice):
|
2021-07-22 16:21:31 +00:00
|
|
|
"""Get free items with your technologies."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Free Samples"
|
2021-06-25 21:32:13 +00:00
|
|
|
option_none = 0
|
|
|
|
option_single_craft = 1
|
|
|
|
option_half_stack = 2
|
|
|
|
option_stack = 3
|
|
|
|
default = 3
|
|
|
|
|
|
|
|
|
2024-11-11 10:43:16 +00:00
|
|
|
class FreeSamplesQuality(Choice):
|
|
|
|
"""If free samples are on, determine the quality of the granted items.
|
|
|
|
Requires the quality mod, which is part of the Space Age DLC. Without it, normal quality is given."""
|
|
|
|
display_name = "Free Samples Quality"
|
|
|
|
option_normal = 0
|
|
|
|
option_uncommon = 1
|
|
|
|
option_rare = 2
|
|
|
|
option_epic = 3
|
|
|
|
option_legendary = 4
|
|
|
|
default = 0
|
|
|
|
|
|
|
|
|
2021-06-25 21:32:13 +00:00
|
|
|
class TechTreeLayout(Choice):
|
2022-11-27 03:01:10 +00: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 15:29:29 +00:00
|
|
|
display_name = "Technology Tree Layout"
|
2021-06-25 21:32:13 +00: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 12:01:24 +00:00
|
|
|
option_trees = 10
|
|
|
|
option_choices = 11
|
2021-06-25 21:32:13 +00:00
|
|
|
default = 0
|
|
|
|
|
|
|
|
|
|
|
|
class TechTreeInformation(Choice):
|
2022-11-27 03:01:10 +00:00
|
|
|
"""How much information should be displayed in the tech tree.
|
2023-09-10 22:13:39 +00:00
|
|
|
None: No indication of what a research unlocks.
|
|
|
|
Advancement: Indicates if a research unlocks an item that is considered logical advancement, but not who it is for.
|
2022-11-27 03:01:10 +00:00
|
|
|
Full: Labels with exact names and recipients of unlocked items; all researches are prefilled into the !hint command.
|
|
|
|
"""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Technology Tree Information"
|
2021-06-25 21:32:13 +00:00
|
|
|
option_none = 0
|
|
|
|
option_advancement = 1
|
|
|
|
option_full = 2
|
|
|
|
default = 2
|
|
|
|
|
|
|
|
|
|
|
|
class RecipeTime(Choice):
|
2021-11-23 18:10:26 +00: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 15:29:29 +00:00
|
|
|
display_name = "Recipe Time"
|
2021-06-25 21:32:13 +00:00
|
|
|
option_vanilla = 0
|
|
|
|
option_fast = 1
|
|
|
|
option_normal = 2
|
|
|
|
option_slow = 4
|
|
|
|
option_chaos = 5
|
2021-11-23 18:10:26 +00:00
|
|
|
option_new_fast = 6
|
|
|
|
option_new_normal = 7
|
|
|
|
option_new_slow = 8
|
2021-06-25 21:32:13 +00:00
|
|
|
|
2021-07-22 16:21:31 +00:00
|
|
|
|
2021-07-07 08:14:58 +00:00
|
|
|
class Progressive(Choice):
|
2021-12-22 13:00:41 +00:00
|
|
|
"""Merges together Technologies like "automation-1" to "automation-3" into 3 copies of "Progressive Automation",
|
|
|
|
which awards them in order."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Progressive Technologies"
|
2021-07-07 08:14:58 +00:00
|
|
|
option_off = 0
|
2021-08-09 07:15:41 +00:00
|
|
|
option_grouped_random = 1
|
2021-07-07 08:14:58 +00:00
|
|
|
option_on = 2
|
|
|
|
default = 2
|
|
|
|
|
|
|
|
def want_progressives(self, random):
|
2021-08-09 08:05:45 +00:00
|
|
|
return random.choice([True, False]) if self.value == self.option_grouped_random else bool(self.value)
|
2021-07-07 08:14:58 +00:00
|
|
|
|
2021-07-07 22:02:17 +00:00
|
|
|
|
2021-07-07 08:14:58 +00:00
|
|
|
class RecipeIngredients(Choice):
|
2021-07-22 16:21:31 +00:00
|
|
|
"""Select if rocket, or rocket + science pack ingredients should be random."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Random Recipe Ingredients Level"
|
2021-07-07 08:14:58 +00:00
|
|
|
option_rocket = 0
|
|
|
|
option_science_pack = 1
|
2021-06-25 21:32:13 +00:00
|
|
|
|
2021-07-07 22:02:17 +00:00
|
|
|
|
2023-03-15 16:03:33 +00: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
|
|
|
|
|
|
|
|
|
2023-12-10 05:10:01 +00:00
|
|
|
class FactorioStartItems(OptionDict):
|
2021-12-22 13:00:41 +00:00
|
|
|
"""Mapping of Factorio internal item-name to amount granted on start."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Starting Items"
|
2023-12-28 13:30:10 +00:00
|
|
|
default = {"burner-mining-drill": 4, "stone-furnace": 4, "raw-fish": 50}
|
2021-06-25 21:32:13 +00:00
|
|
|
|
|
|
|
|
2021-12-02 23:27:00 +00:00
|
|
|
class FactorioFreeSampleBlacklist(OptionSet):
|
2021-12-22 13:00:41 +00:00
|
|
|
"""Set of items that should never be granted from Free Samples"""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Free Sample Blacklist"
|
2021-12-02 17:26:51 +00:00
|
|
|
|
|
|
|
|
2021-12-02 23:27:48 +00:00
|
|
|
class FactorioFreeSampleWhitelist(OptionSet):
|
2021-12-22 13:00:41 +00:00
|
|
|
"""Overrides any free sample blacklist present. This may ruin the balance of the mod, be warned."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Free Sample Whitelist"
|
2021-12-02 23:27:48 +00:00
|
|
|
|
|
|
|
|
2021-08-04 03:40:51 +00:00
|
|
|
class TrapCount(Range):
|
2022-10-28 19:00:06 +00:00
|
|
|
range_end = 25
|
2021-08-04 03:40:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
class AttackTrapCount(TrapCount):
|
|
|
|
"""Trap items that when received trigger an attack on your base."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Attack Traps"
|
2021-08-04 03:40:51 +00:00
|
|
|
|
|
|
|
|
2023-03-15 16:03:33 +00: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"
|
|
|
|
|
|
|
|
|
2024-11-30 05:53:28 +00:00
|
|
|
class AtomicCliffRemoverTrapCount(TrapCount):
|
|
|
|
"""Trap items that when received trigger an atomic rocket explosion on a random cliff.
|
|
|
|
Warning: there is no warning. The launch is instantaneous."""
|
|
|
|
display_name = "Atomic Cliff Remover Traps"
|
|
|
|
|
|
|
|
|
2021-08-04 03:40:51 +00:00
|
|
|
class EvolutionTrapCount(TrapCount):
|
|
|
|
"""Trap items that when received increase the enemy evolution."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Evolution Traps"
|
2023-03-15 16:03:33 +00:00
|
|
|
range_end = 10
|
2021-08-04 03:40:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
class EvolutionTrapIncrease(Range):
|
2022-01-18 01:15:09 +00: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 15:29:29 +00:00
|
|
|
display_name = "Evolution Trap % Effect"
|
2021-08-04 03:40:51 +00:00
|
|
|
range_start = 1
|
|
|
|
default = 10
|
|
|
|
range_end = 100
|
|
|
|
|
|
|
|
|
2021-07-01 23:29:49 +00:00
|
|
|
class FactorioWorldGen(OptionDict):
|
2021-12-22 13:00:41 +00: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 15:29:29 +00:00
|
|
|
display_name = "World Generation"
|
2021-07-18 23:02:23 +00:00
|
|
|
# FIXME: do we want default be a rando-optimized default or in-game DS?
|
2024-11-30 03:08:17 +00:00
|
|
|
value: dict[str, dict[str, typing.Any]]
|
2021-07-22 22:47:18 +00:00
|
|
|
default = {
|
|
|
|
"autoplace_controls": {
|
2024-11-11 10:43:16 +00:00
|
|
|
# terrain
|
|
|
|
"water": {"frequency": 1, "size": 1, "richness": 1},
|
|
|
|
"nauvis_cliff": {"frequency": 1, "size": 1, "richness": 1},
|
|
|
|
"starting_area_moisture": {"frequency": 1, "size": 1, "richness": 1},
|
|
|
|
# resources
|
2021-07-22 22:47:18 +00:00
|
|
|
"coal": {"frequency": 1, "size": 3, "richness": 6},
|
|
|
|
"copper-ore": {"frequency": 1, "size": 3, "richness": 6},
|
|
|
|
"crude-oil": {"frequency": 1, "size": 3, "richness": 6},
|
|
|
|
"iron-ore": {"frequency": 1, "size": 3, "richness": 6},
|
|
|
|
"stone": {"frequency": 1, "size": 3, "richness": 6},
|
2024-11-11 10:43:16 +00:00
|
|
|
"uranium-ore": {"frequency": 1, "size": 3, "richness": 6},
|
|
|
|
# misc
|
2021-07-22 22:47:18 +00:00
|
|
|
"trees": {"frequency": 1, "size": 1, "richness": 1},
|
2024-11-11 10:43:16 +00:00
|
|
|
"enemy-base": {"frequency": 1, "size": 1, "richness": 1},
|
2021-07-22 22:47:18 +00:00
|
|
|
},
|
|
|
|
"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-18 23:02:23 +00:00
|
|
|
schema = Schema({
|
|
|
|
"basic": {
|
|
|
|
Optional("autoplace_controls"): {
|
|
|
|
str: {
|
2021-07-22 16:21:31 +00:00
|
|
|
"frequency": FloatRange(0, 6),
|
|
|
|
"size": FloatRange(0, 6),
|
2021-07-22 22:47:18 +00:00
|
|
|
"richness": FloatRange(0.166, 6)
|
|
|
|
}
|
|
|
|
},
|
2021-07-22 16:21:31 +00:00
|
|
|
Optional("seed"): Or(None, And(int, lambda n: n >= 0)),
|
2022-05-04 23:59:41 +00:00
|
|
|
Optional("width"): And(int, lambda n: n >= 0),
|
|
|
|
Optional("height"): And(int, lambda n: n >= 0),
|
2021-07-22 16:21:31 +00:00
|
|
|
Optional("starting_area"): FloatRange(0.166, 6),
|
2021-07-18 23:02:23 +00:00
|
|
|
Optional("peaceful_mode"): LuaBool,
|
|
|
|
Optional("cliff_settings"): {
|
2021-07-22 16:21:31 +00:00
|
|
|
"name": str, "cliff_elevation_0": FloatRange(0, 99),
|
|
|
|
"cliff_elevation_interval": FloatRange(0.066, 241), # 40/frequency
|
2021-07-22 22:47:18 +00:00
|
|
|
"richness": FloatRange(0, 6)
|
|
|
|
},
|
|
|
|
Optional("property_expression_names"): Schema({
|
2022-05-05 00:02:50 +00: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-18 23:02:23 +00:00
|
|
|
},
|
|
|
|
"advanced": {
|
|
|
|
Optional("pollution"): {
|
|
|
|
Optional("enabled"): LuaBool,
|
2021-07-22 16:21:31 +00: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-22 22:47:18 +00: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-18 23:02:23 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2024-11-30 03:08:17 +00:00
|
|
|
def __init__(self, value: dict[str, typing.Any]):
|
2021-07-22 22:47:18 +00:00
|
|
|
advanced = {"pollution", "enemy_evolution", "enemy_expansion"}
|
2021-07-18 23:02:23 +00:00
|
|
|
self.value = {
|
2023-09-22 19:32:03 +00:00
|
|
|
"basic": {k: v for k, v in value.items() if k not in advanced},
|
|
|
|
"advanced": {k: v for k, v in value.items() if k in advanced}
|
2021-07-18 23:02:23 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 22:47:18 +00: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-18 23:02:23 +00:00
|
|
|
@classmethod
|
2024-11-30 03:08:17 +00:00
|
|
|
def from_any(cls, data: dict[str, typing.Any]) -> FactorioWorldGen:
|
2021-07-18 23:02:23 +00:00
|
|
|
if type(data) == dict:
|
|
|
|
return cls(data)
|
|
|
|
else:
|
|
|
|
raise NotImplementedError(f"Cannot Convert from non-dictionary, got {type(data)}")
|
|
|
|
|
2021-08-04 03:40:51 +00:00
|
|
|
|
2021-08-02 02:57:57 +00:00
|
|
|
class ImportedBlueprint(DefaultOnToggle):
|
2021-12-22 13:00:41 +00:00
|
|
|
"""Allow or Disallow Blueprints from outside the current savegame."""
|
2022-02-02 15:29:29 +00:00
|
|
|
display_name = "Blueprints"
|
2021-08-02 02:57:57 +00:00
|
|
|
|
2021-08-04 03:40:51 +00:00
|
|
|
|
2022-02-24 21:40:16 +00:00
|
|
|
class EnergyLink(Toggle):
|
|
|
|
"""Allow sending energy to other worlds. 25% of the energy is lost in the transfer."""
|
2024-11-30 03:08:17 +00:00
|
|
|
display_name = "Energy Link"
|
2022-02-24 21:40:16 +00:00
|
|
|
|
|
|
|
|
2024-09-17 22:18:17 +00:00
|
|
|
@dataclass
|
|
|
|
class FactorioOptions(PerGameCommonOptions):
|
|
|
|
max_science_pack: MaxSciencePack
|
|
|
|
goal: Goal
|
|
|
|
tech_tree_layout: TechTreeLayout
|
|
|
|
min_tech_cost: MinTechCost
|
|
|
|
max_tech_cost: MaxTechCost
|
|
|
|
tech_cost_distribution: TechCostDistribution
|
|
|
|
tech_cost_mix: TechCostMix
|
|
|
|
ramping_tech_costs: RampingTechCosts
|
|
|
|
silo: Silo
|
|
|
|
satellite: Satellite
|
|
|
|
free_samples: FreeSamples
|
2024-11-11 10:43:16 +00:00
|
|
|
free_samples_quality: FreeSamplesQuality
|
2024-09-17 22:18:17 +00:00
|
|
|
tech_tree_information: TechTreeInformation
|
|
|
|
starting_items: FactorioStartItems
|
|
|
|
free_sample_blacklist: FactorioFreeSampleBlacklist
|
|
|
|
free_sample_whitelist: FactorioFreeSampleWhitelist
|
|
|
|
recipe_time: RecipeTime
|
|
|
|
recipe_ingredients: RecipeIngredients
|
|
|
|
recipe_ingredients_offset: RecipeIngredientsOffset
|
|
|
|
imported_blueprints: ImportedBlueprint
|
|
|
|
world_gen: FactorioWorldGen
|
|
|
|
progressive: Progressive
|
|
|
|
teleport_traps: TeleportTrapCount
|
|
|
|
grenade_traps: GrenadeTrapCount
|
|
|
|
cluster_grenade_traps: ClusterGrenadeTrapCount
|
|
|
|
artillery_traps: ArtilleryTrapCount
|
|
|
|
atomic_rocket_traps: AtomicRocketTrapCount
|
2024-11-30 05:53:28 +00:00
|
|
|
atomic_cliff_remover_traps: AtomicCliffRemoverTrapCount
|
2024-09-17 22:18:17 +00:00
|
|
|
attack_traps: AttackTrapCount
|
|
|
|
evolution_traps: EvolutionTrapCount
|
|
|
|
evolution_trap_increase: EvolutionTrapIncrease
|
|
|
|
death_link: DeathLink
|
|
|
|
energy_link: EnergyLink
|
|
|
|
start_inventory_from_pool: StartInventoryPool
|
2024-11-30 03:08:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
option_groups: list[OptionGroup] = [
|
|
|
|
OptionGroup(
|
|
|
|
"Technologies",
|
|
|
|
[
|
|
|
|
TechTreeLayout,
|
|
|
|
Progressive,
|
|
|
|
MinTechCost,
|
|
|
|
MaxTechCost,
|
|
|
|
TechCostDistribution,
|
|
|
|
TechCostMix,
|
|
|
|
RampingTechCosts,
|
|
|
|
TechTreeInformation,
|
|
|
|
]
|
|
|
|
),
|
|
|
|
OptionGroup(
|
|
|
|
"Traps",
|
|
|
|
[
|
|
|
|
AttackTrapCount,
|
|
|
|
EvolutionTrapCount,
|
|
|
|
EvolutionTrapIncrease,
|
|
|
|
TeleportTrapCount,
|
|
|
|
GrenadeTrapCount,
|
|
|
|
ClusterGrenadeTrapCount,
|
|
|
|
ArtilleryTrapCount,
|
|
|
|
AtomicRocketTrapCount,
|
2024-11-30 05:53:28 +00:00
|
|
|
AtomicCliffRemoverTrapCount,
|
2024-11-30 03:08:17 +00:00
|
|
|
],
|
|
|
|
start_collapsed=True
|
|
|
|
),
|
|
|
|
]
|