Factorio: content update
Energy Link: * Transfer and Storage increased by 10X * Cost of building increased by roughly 10X * This is a way to address their effect on performance, as users now need a tenth of them to get the same throughput, it also differentiates them from Accumulators 5 new Traps: * Teleport Trap * Grenade Trap * Cluster Grenade Trap * Artillery Trap * Atomic Rocket Trap When max science is lower than min science, the two are now swapped. Max Evolution Trap count was changed from 25 -> 10. New option: Ingredients Offset * When creating random recipes, use this many more or less ingredients in the new recipe.
This commit is contained in:
@@ -35,6 +35,11 @@ class FactorioItem(Item):
|
||||
all_items = tech_table.copy()
|
||||
all_items["Attack Trap"] = factorio_base_id - 1
|
||||
all_items["Evolution Trap"] = factorio_base_id - 2
|
||||
all_items["Teleport Trap"] = factorio_base_id - 3
|
||||
all_items["Grenade Trap"] = factorio_base_id - 4
|
||||
all_items["Cluster Grenade Trap"] = factorio_base_id - 5
|
||||
all_items["Artillery Trap"] = factorio_base_id - 6
|
||||
all_items["Atomic Rocket Trap"] = factorio_base_id - 7
|
||||
|
||||
|
||||
class Factorio(World):
|
||||
@@ -43,7 +48,7 @@ class Factorio(World):
|
||||
Nauvis, an inhospitable world filled with dangerous creatures called biters. Build a factory,
|
||||
research new technologies, and become more efficient in your quest to build a rocket and return home.
|
||||
"""
|
||||
game: str = "Factorio"
|
||||
game = "Factorio"
|
||||
special_nodes = {"automation", "logistics", "rocket-silo"}
|
||||
custom_recipes: typing.Dict[str, Recipe]
|
||||
location_pool: typing.List[FactorioScienceLocation]
|
||||
@@ -52,12 +57,11 @@ class Factorio(World):
|
||||
web = FactorioWeb()
|
||||
|
||||
item_name_to_id = all_items
|
||||
# TODO: remove base_tech_table ~ 0.3.7
|
||||
location_name_to_id = {**base_tech_table, **location_table}
|
||||
location_name_to_id = location_table
|
||||
item_name_groups = {
|
||||
"Progressive": set(progressive_tech_table.keys()),
|
||||
}
|
||||
data_version = 6
|
||||
data_version = 7
|
||||
required_client_version = (0, 3, 6)
|
||||
|
||||
ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
|
||||
@@ -73,8 +77,10 @@ class Factorio(World):
|
||||
generate_output = generate_mod
|
||||
|
||||
def generate_early(self) -> None:
|
||||
self.multiworld.max_tech_cost[self.player] = max(self.multiworld.max_tech_cost[self.player],
|
||||
self.multiworld.min_tech_cost[self.player])
|
||||
# if max < min, then swap max and min
|
||||
if self.multiworld.max_tech_cost[self.player] < self.multiworld.min_tech_cost[self.player]:
|
||||
self.multiworld.min_tech_cost[self.player].value, self.multiworld.max_tech_cost[self.player].value = \
|
||||
self.multiworld.max_tech_cost[self.player].value, self.multiworld.min_tech_cost[self.player].value
|
||||
self.tech_mix = self.multiworld.tech_cost_mix[self.player]
|
||||
self.skip_silo = self.multiworld.silo[self.player].value == Silo.option_spawn
|
||||
|
||||
@@ -87,14 +93,25 @@ class Factorio(World):
|
||||
nauvis = Region("Nauvis", player, self.multiworld)
|
||||
|
||||
location_count = len(base_tech_table) - len(useless_technologies) - self.skip_silo + \
|
||||
self.multiworld.evolution_traps[player].value + self.multiworld.attack_traps[player].value
|
||||
self.multiworld.evolution_traps[player] + \
|
||||
self.multiworld.attack_traps[player] + \
|
||||
self.multiworld.teleport_traps[player] + \
|
||||
self.multiworld.grenade_traps[player] + \
|
||||
self.multiworld.cluster_grenade_traps[player] + \
|
||||
self.multiworld.atomic_rocket_traps[player] + \
|
||||
self.multiworld.artillery_traps[player]
|
||||
|
||||
location_pool = []
|
||||
|
||||
for pack in sorted(self.multiworld.max_science_pack[self.player].get_allowed_packs()):
|
||||
location_pool.extend(location_pools[pack])
|
||||
try:
|
||||
location_names = self.multiworld.random.sample(location_pool, location_count)
|
||||
except ValueError as e:
|
||||
# should be "ValueError: Sample larger than population or is negative"
|
||||
raise Exception("Too many traps for too few locations. Either decrease the trap count, "
|
||||
f"or increase the location count (higher max science pack). (Player {self.player})") from e
|
||||
|
||||
location_names = self.multiworld.random.sample(location_pool, location_count)
|
||||
self.locations = [FactorioScienceLocation(player, loc_name, self.location_name_to_id[loc_name], nauvis)
|
||||
for loc_name in location_names]
|
||||
distribution: TechCostDistribution = self.multiworld.tech_cost_distribution[self.player]
|
||||
@@ -132,6 +149,14 @@ class Factorio(World):
|
||||
crash.connect(nauvis)
|
||||
self.multiworld.regions += [menu, nauvis]
|
||||
|
||||
def create_items(self) -> None:
|
||||
player = self.player
|
||||
traps = ("Evolution", "Attack", "Teleport", "Grenade", "Cluster Grenade", "Artillery", "Atomic Rocket")
|
||||
for trap_name in traps:
|
||||
self.multiworld.itempool.extend(self.create_item(f"{trap_name} Trap") for _ in
|
||||
range(getattr(self.multiworld,
|
||||
f"{trap_name.lower().replace(' ', '_')}_traps")[player]))
|
||||
|
||||
def set_rules(self):
|
||||
world = self.multiworld
|
||||
player = self.player
|
||||
@@ -184,10 +209,6 @@ class Factorio(World):
|
||||
player = self.player
|
||||
want_progressives = collections.defaultdict(lambda: self.multiworld.progressive[player].
|
||||
want_progressives(self.multiworld.random))
|
||||
self.multiworld.itempool.extend(self.create_item("Evolution Trap") for _ in
|
||||
range(self.multiworld.evolution_traps[player].value))
|
||||
self.multiworld.itempool.extend(self.create_item("Attack Trap") for _ in
|
||||
range(self.multiworld.attack_traps[player].value))
|
||||
|
||||
cost_sorted_locations = sorted(self.locations, key=lambda location: location.name)
|
||||
special_index = {"automation": 0,
|
||||
@@ -265,10 +286,11 @@ class Factorio(World):
|
||||
2: "chemistry"}
|
||||
return categories.get(liquids, category)
|
||||
|
||||
def make_quick_recipe(self, original: Recipe, pool: list, allow_liquids: int = 2) -> Recipe:
|
||||
def make_quick_recipe(self, original: Recipe, pool: list, allow_liquids: int = 2,
|
||||
ingredients_offset: int = 0) -> Recipe:
|
||||
new_ingredients = {}
|
||||
liquids_used = 0
|
||||
for _ in original.ingredients:
|
||||
for _ in range(len(original.ingredients) + ingredients_offset):
|
||||
new_ingredient = pool.pop()
|
||||
if new_ingredient in fluids:
|
||||
while liquids_used == allow_liquids and new_ingredient in fluids:
|
||||
@@ -282,7 +304,7 @@ class Factorio(World):
|
||||
original.products, original.energy)
|
||||
|
||||
def make_balanced_recipe(self, original: Recipe, pool: typing.Set[str], factor: float = 1,
|
||||
allow_liquids: int = 2) -> Recipe:
|
||||
allow_liquids: int = 2, ingredients_offset: int = 0) -> Recipe:
|
||||
"""Generate a recipe from pool with time and cost similar to original * factor"""
|
||||
new_ingredients = {}
|
||||
# have to first sort for determinism, while filtering out non-stacking items
|
||||
@@ -291,7 +313,7 @@ class Factorio(World):
|
||||
self.multiworld.random.shuffle(pool)
|
||||
target_raw = int(sum((count for ingredient, count in original.base_cost.items())) * factor)
|
||||
target_energy = original.total_energy * factor
|
||||
target_num_ingredients = len(original.ingredients)
|
||||
target_num_ingredients = len(original.ingredients) + ingredients_offset
|
||||
remaining_raw = target_raw
|
||||
remaining_energy = target_energy
|
||||
remaining_num_ingredients = target_num_ingredients
|
||||
@@ -382,12 +404,13 @@ class Factorio(World):
|
||||
return custom_technologies
|
||||
|
||||
def set_custom_recipes(self):
|
||||
ingredients_offset = self.multiworld.recipe_ingredients_offset[self.player]
|
||||
original_rocket_part = recipes["rocket-part"]
|
||||
science_pack_pools = get_science_pack_pools()
|
||||
valid_pool = sorted(science_pack_pools[self.multiworld.max_science_pack[self.player].get_max_pack()] & valid_ingredients)
|
||||
self.multiworld.random.shuffle(valid_pool)
|
||||
self.custom_recipes = {"rocket-part": Recipe("rocket-part", original_rocket_part.category,
|
||||
{valid_pool[x]: 10 for x in range(3)},
|
||||
{valid_pool[x]: 10 for x in range(3 + ingredients_offset)},
|
||||
original_rocket_part.products,
|
||||
original_rocket_part.energy)}
|
||||
|
||||
@@ -397,7 +420,8 @@ class Factorio(World):
|
||||
valid_pool += sorted(science_pack_pools[pack])
|
||||
self.multiworld.random.shuffle(valid_pool)
|
||||
if pack in recipes: # skips over space science pack
|
||||
new_recipe = self.make_quick_recipe(recipes[pack], valid_pool)
|
||||
new_recipe = self.make_quick_recipe(recipes[pack], valid_pool, ingredients_offset=
|
||||
ingredients_offset)
|
||||
self.custom_recipes[pack] = new_recipe
|
||||
|
||||
if self.multiworld.silo[self.player].value == Silo.option_randomize_recipe \
|
||||
@@ -407,21 +431,27 @@ class Factorio(World):
|
||||
valid_pool |= science_pack_pools[pack]
|
||||
|
||||
if self.multiworld.silo[self.player].value == Silo.option_randomize_recipe:
|
||||
new_recipe = self.make_balanced_recipe(recipes["rocket-silo"], valid_pool,
|
||||
factor=(self.multiworld.max_science_pack[self.player].value + 1) / 7)
|
||||
new_recipe = self.make_balanced_recipe(
|
||||
recipes["rocket-silo"], valid_pool,
|
||||
factor=(self.multiworld.max_science_pack[self.player].value + 1) / 7,
|
||||
ingredients_offset=ingredients_offset)
|
||||
self.custom_recipes["rocket-silo"] = new_recipe
|
||||
|
||||
if self.multiworld.satellite[self.player].value == Satellite.option_randomize_recipe:
|
||||
new_recipe = self.make_balanced_recipe(recipes["satellite"], valid_pool,
|
||||
factor=(self.multiworld.max_science_pack[self.player].value + 1) / 7)
|
||||
new_recipe = self.make_balanced_recipe(
|
||||
recipes["satellite"], valid_pool,
|
||||
factor=(self.multiworld.max_science_pack[self.player].value + 1) / 7,
|
||||
ingredients_offset=ingredients_offset)
|
||||
self.custom_recipes["satellite"] = new_recipe
|
||||
bridge = "ap-energy-bridge"
|
||||
new_recipe = self.make_quick_recipe(
|
||||
Recipe(bridge, "crafting", {"replace_1": 1, "replace_2": 1, "replace_3": 1},
|
||||
Recipe(bridge, "crafting", {"replace_1": 1, "replace_2": 1, "replace_3": 1,
|
||||
"replace_4": 1, "replace_5": 1, "replace_6": 1},
|
||||
{bridge: 1}, 10),
|
||||
sorted(science_pack_pools[self.multiworld.max_science_pack[self.player].get_ordered_science_packs()[0]]))
|
||||
sorted(science_pack_pools[self.multiworld.max_science_pack[self.player].get_ordered_science_packs()[0]]),
|
||||
ingredients_offset=ingredients_offset)
|
||||
for ingredient_name in new_recipe.ingredients:
|
||||
new_recipe.ingredients[ingredient_name] = self.multiworld.random.randint(10, 100)
|
||||
new_recipe.ingredients[ingredient_name] = self.multiworld.random.randint(50, 500)
|
||||
self.custom_recipes[bridge] = new_recipe
|
||||
|
||||
needed_recipes = self.multiworld.max_science_pack[self.player].get_allowed_packs() | {"rocket-part"}
|
||||
@@ -452,7 +482,7 @@ class Factorio(World):
|
||||
tech_table[name], self.player)
|
||||
|
||||
item = FactorioItem(name,
|
||||
ItemClassification.trap if "Trap" in name else ItemClassification.filler,
|
||||
ItemClassification.trap if name.endswith("Trap") else ItemClassification.filler,
|
||||
all_items[name], self.player)
|
||||
return item
|
||||
|
||||
|
||||
Reference in New Issue
Block a user