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:
		
							parent
							
								
									5d6184f1fd
								
							
						
					
					
						commit
						d825576f12
					
				| 
						 | 
					@ -136,6 +136,7 @@ def generate_mod(world: "Factorio", output_directory: str):
 | 
				
			||||||
        "goal": multiworld.goal[player].value,
 | 
					        "goal": multiworld.goal[player].value,
 | 
				
			||||||
        "energy_link": multiworld.energy_link[player].value,
 | 
					        "energy_link": multiworld.energy_link[player].value,
 | 
				
			||||||
        "useless_technologies": useless_technologies,
 | 
					        "useless_technologies": useless_technologies,
 | 
				
			||||||
 | 
					        "chunk_shuffle": multiworld.chunk_shuffle[player].value if hasattr(multiworld, "chunk_shuffle") else 0,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for factorio_option in Options.factorio_options:
 | 
					    for factorio_option in Options.factorio_options:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
from __future__ import annotations
 | 
					from __future__ import annotations
 | 
				
			||||||
import typing
 | 
					import typing
 | 
				
			||||||
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from Options import Choice, OptionDict, OptionSet, ItemDict, Option, DefaultOnToggle, Range, DeathLink, Toggle
 | 
					from Options import Choice, OptionDict, OptionSet, ItemDict, Option, DefaultOnToggle, Range, DeathLink, Toggle
 | 
				
			||||||
from schema import Schema, Optional, And, Or
 | 
					from schema import Schema, Optional, And, Or
 | 
				
			||||||
| 
						 | 
					@ -197,6 +198,14 @@ class RecipeIngredients(Choice):
 | 
				
			||||||
    option_science_pack = 1
 | 
					    option_science_pack = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FactorioStartItems(ItemDict):
 | 
					class FactorioStartItems(ItemDict):
 | 
				
			||||||
    """Mapping of Factorio internal item-name to amount granted on start."""
 | 
					    """Mapping of Factorio internal item-name to amount granted on start."""
 | 
				
			||||||
    display_name = "Starting Items"
 | 
					    display_name = "Starting Items"
 | 
				
			||||||
| 
						 | 
					@ -223,9 +232,36 @@ class AttackTrapCount(TrapCount):
 | 
				
			||||||
    display_name = "Attack Traps"
 | 
					    display_name = "Attack Traps"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EvolutionTrapCount(TrapCount):
 | 
					class EvolutionTrapCount(TrapCount):
 | 
				
			||||||
    """Trap items that when received increase the enemy evolution."""
 | 
					    """Trap items that when received increase the enemy evolution."""
 | 
				
			||||||
    display_name = "Evolution Traps"
 | 
					    display_name = "Evolution Traps"
 | 
				
			||||||
 | 
					    range_end = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EvolutionTrapIncrease(Range):
 | 
					class EvolutionTrapIncrease(Range):
 | 
				
			||||||
| 
						 | 
					@ -404,12 +440,31 @@ factorio_options: typing.Dict[str, type(Option)] = {
 | 
				
			||||||
    "free_sample_whitelist": FactorioFreeSampleWhitelist,
 | 
					    "free_sample_whitelist": FactorioFreeSampleWhitelist,
 | 
				
			||||||
    "recipe_time": RecipeTime,
 | 
					    "recipe_time": RecipeTime,
 | 
				
			||||||
    "recipe_ingredients": RecipeIngredients,
 | 
					    "recipe_ingredients": RecipeIngredients,
 | 
				
			||||||
 | 
					    "recipe_ingredients_offset": RecipeIngredientsOffset,
 | 
				
			||||||
    "imported_blueprints": ImportedBlueprint,
 | 
					    "imported_blueprints": ImportedBlueprint,
 | 
				
			||||||
    "world_gen": FactorioWorldGen,
 | 
					    "world_gen": FactorioWorldGen,
 | 
				
			||||||
    "progressive": Progressive,
 | 
					    "progressive": Progressive,
 | 
				
			||||||
    "evolution_traps": EvolutionTrapCount,
 | 
					    "teleport_traps": TeleportTrapCount,
 | 
				
			||||||
 | 
					    "grenade_traps": GrenadeTrapCount,
 | 
				
			||||||
 | 
					    "cluster_grenade_traps": ClusterGrenadeTrapCount,
 | 
				
			||||||
 | 
					    "artillery_traps": ArtilleryTrapCount,
 | 
				
			||||||
 | 
					    "atomic_rocket_traps": AtomicRocketTrapCount,
 | 
				
			||||||
    "attack_traps": AttackTrapCount,
 | 
					    "attack_traps": AttackTrapCount,
 | 
				
			||||||
 | 
					    "evolution_traps": EvolutionTrapCount,
 | 
				
			||||||
    "evolution_trap_increase": EvolutionTrapIncrease,
 | 
					    "evolution_trap_increase": EvolutionTrapIncrease,
 | 
				
			||||||
    "death_link": DeathLink,
 | 
					    "death_link": DeathLink,
 | 
				
			||||||
    "energy_link": EnergyLink
 | 
					    "energy_link": EnergyLink,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,11 @@ class FactorioItem(Item):
 | 
				
			||||||
all_items = tech_table.copy()
 | 
					all_items = tech_table.copy()
 | 
				
			||||||
all_items["Attack Trap"] = factorio_base_id - 1
 | 
					all_items["Attack Trap"] = factorio_base_id - 1
 | 
				
			||||||
all_items["Evolution Trap"] = factorio_base_id - 2
 | 
					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):
 | 
					class Factorio(World):
 | 
				
			||||||
| 
						 | 
					@ -43,7 +48,7 @@ class Factorio(World):
 | 
				
			||||||
    Nauvis, an inhospitable world filled with dangerous creatures called biters. Build a factory,
 | 
					    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.
 | 
					    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"}
 | 
					    special_nodes = {"automation", "logistics", "rocket-silo"}
 | 
				
			||||||
    custom_recipes: typing.Dict[str, Recipe]
 | 
					    custom_recipes: typing.Dict[str, Recipe]
 | 
				
			||||||
    location_pool: typing.List[FactorioScienceLocation]
 | 
					    location_pool: typing.List[FactorioScienceLocation]
 | 
				
			||||||
| 
						 | 
					@ -52,12 +57,11 @@ class Factorio(World):
 | 
				
			||||||
    web = FactorioWeb()
 | 
					    web = FactorioWeb()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    item_name_to_id = all_items
 | 
					    item_name_to_id = all_items
 | 
				
			||||||
    # TODO: remove base_tech_table ~ 0.3.7
 | 
					    location_name_to_id = location_table
 | 
				
			||||||
    location_name_to_id = {**base_tech_table, **location_table}
 | 
					 | 
				
			||||||
    item_name_groups = {
 | 
					    item_name_groups = {
 | 
				
			||||||
        "Progressive": set(progressive_tech_table.keys()),
 | 
					        "Progressive": set(progressive_tech_table.keys()),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    data_version = 6
 | 
					    data_version = 7
 | 
				
			||||||
    required_client_version = (0, 3, 6)
 | 
					    required_client_version = (0, 3, 6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
 | 
					    ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
 | 
				
			||||||
| 
						 | 
					@ -73,8 +77,10 @@ class Factorio(World):
 | 
				
			||||||
    generate_output = generate_mod
 | 
					    generate_output = generate_mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generate_early(self) -> None:
 | 
					    def generate_early(self) -> None:
 | 
				
			||||||
        self.multiworld.max_tech_cost[self.player] = max(self.multiworld.max_tech_cost[self.player],
 | 
					        # if max < min, then swap max and min
 | 
				
			||||||
                                                    self.multiworld.min_tech_cost[self.player])
 | 
					        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.tech_mix = self.multiworld.tech_cost_mix[self.player]
 | 
				
			||||||
        self.skip_silo = self.multiworld.silo[self.player].value == Silo.option_spawn
 | 
					        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)
 | 
					        nauvis = Region("Nauvis", player, self.multiworld)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        location_count = len(base_tech_table) - len(useless_technologies) - self.skip_silo + \
 | 
					        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 = []
 | 
					        location_pool = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for pack in sorted(self.multiworld.max_science_pack[self.player].get_allowed_packs()):
 | 
					        for pack in sorted(self.multiworld.max_science_pack[self.player].get_allowed_packs()):
 | 
				
			||||||
            location_pool.extend(location_pools[pack])
 | 
					            location_pool.extend(location_pools[pack])
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
            location_names = self.multiworld.random.sample(location_pool, location_count)
 | 
					            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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.locations = [FactorioScienceLocation(player, loc_name, self.location_name_to_id[loc_name], nauvis)
 | 
					        self.locations = [FactorioScienceLocation(player, loc_name, self.location_name_to_id[loc_name], nauvis)
 | 
				
			||||||
                          for loc_name in location_names]
 | 
					                          for loc_name in location_names]
 | 
				
			||||||
        distribution: TechCostDistribution = self.multiworld.tech_cost_distribution[self.player]
 | 
					        distribution: TechCostDistribution = self.multiworld.tech_cost_distribution[self.player]
 | 
				
			||||||
| 
						 | 
					@ -132,6 +149,14 @@ class Factorio(World):
 | 
				
			||||||
        crash.connect(nauvis)
 | 
					        crash.connect(nauvis)
 | 
				
			||||||
        self.multiworld.regions += [menu, 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):
 | 
					    def set_rules(self):
 | 
				
			||||||
        world = self.multiworld
 | 
					        world = self.multiworld
 | 
				
			||||||
        player = self.player
 | 
					        player = self.player
 | 
				
			||||||
| 
						 | 
					@ -184,10 +209,6 @@ class Factorio(World):
 | 
				
			||||||
        player = self.player
 | 
					        player = self.player
 | 
				
			||||||
        want_progressives = collections.defaultdict(lambda: self.multiworld.progressive[player].
 | 
					        want_progressives = collections.defaultdict(lambda: self.multiworld.progressive[player].
 | 
				
			||||||
                                                    want_progressives(self.multiworld.random))
 | 
					                                                    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)
 | 
					        cost_sorted_locations = sorted(self.locations, key=lambda location: location.name)
 | 
				
			||||||
        special_index = {"automation": 0,
 | 
					        special_index = {"automation": 0,
 | 
				
			||||||
| 
						 | 
					@ -265,10 +286,11 @@ class Factorio(World):
 | 
				
			||||||
                      2: "chemistry"}
 | 
					                      2: "chemistry"}
 | 
				
			||||||
        return categories.get(liquids, category)
 | 
					        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 = {}
 | 
					        new_ingredients = {}
 | 
				
			||||||
        liquids_used = 0
 | 
					        liquids_used = 0
 | 
				
			||||||
        for _ in original.ingredients:
 | 
					        for _ in range(len(original.ingredients) + ingredients_offset):
 | 
				
			||||||
            new_ingredient = pool.pop()
 | 
					            new_ingredient = pool.pop()
 | 
				
			||||||
            if new_ingredient in fluids:
 | 
					            if new_ingredient in fluids:
 | 
				
			||||||
                while liquids_used == allow_liquids and 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)
 | 
					                      original.products, original.energy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def make_balanced_recipe(self, original: Recipe, pool: typing.Set[str], factor: float = 1,
 | 
					    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"""
 | 
					        """Generate a recipe from pool with time and cost similar to original * factor"""
 | 
				
			||||||
        new_ingredients = {}
 | 
					        new_ingredients = {}
 | 
				
			||||||
        # have to first sort for determinism, while filtering out non-stacking items
 | 
					        # have to first sort for determinism, while filtering out non-stacking items
 | 
				
			||||||
| 
						 | 
					@ -291,7 +313,7 @@ class Factorio(World):
 | 
				
			||||||
        self.multiworld.random.shuffle(pool)
 | 
					        self.multiworld.random.shuffle(pool)
 | 
				
			||||||
        target_raw = int(sum((count for ingredient, count in original.base_cost.items())) * factor)
 | 
					        target_raw = int(sum((count for ingredient, count in original.base_cost.items())) * factor)
 | 
				
			||||||
        target_energy = original.total_energy * 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_raw = target_raw
 | 
				
			||||||
        remaining_energy = target_energy
 | 
					        remaining_energy = target_energy
 | 
				
			||||||
        remaining_num_ingredients = target_num_ingredients
 | 
					        remaining_num_ingredients = target_num_ingredients
 | 
				
			||||||
| 
						 | 
					@ -382,12 +404,13 @@ class Factorio(World):
 | 
				
			||||||
        return custom_technologies
 | 
					        return custom_technologies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_custom_recipes(self):
 | 
					    def set_custom_recipes(self):
 | 
				
			||||||
 | 
					        ingredients_offset = self.multiworld.recipe_ingredients_offset[self.player]
 | 
				
			||||||
        original_rocket_part = recipes["rocket-part"]
 | 
					        original_rocket_part = recipes["rocket-part"]
 | 
				
			||||||
        science_pack_pools = get_science_pack_pools()
 | 
					        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)
 | 
					        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.multiworld.random.shuffle(valid_pool)
 | 
				
			||||||
        self.custom_recipes = {"rocket-part": Recipe("rocket-part", original_rocket_part.category,
 | 
					        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.products,
 | 
				
			||||||
                                                     original_rocket_part.energy)}
 | 
					                                                     original_rocket_part.energy)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,7 +420,8 @@ class Factorio(World):
 | 
				
			||||||
                valid_pool += sorted(science_pack_pools[pack])
 | 
					                valid_pool += sorted(science_pack_pools[pack])
 | 
				
			||||||
                self.multiworld.random.shuffle(valid_pool)
 | 
					                self.multiworld.random.shuffle(valid_pool)
 | 
				
			||||||
                if pack in recipes:  # skips over space science pack
 | 
					                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
 | 
					                    self.custom_recipes[pack] = new_recipe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.multiworld.silo[self.player].value == Silo.option_randomize_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]
 | 
					                valid_pool |= science_pack_pools[pack]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.multiworld.silo[self.player].value == Silo.option_randomize_recipe:
 | 
					            if self.multiworld.silo[self.player].value == Silo.option_randomize_recipe:
 | 
				
			||||||
                new_recipe = self.make_balanced_recipe(recipes["rocket-silo"], valid_pool,
 | 
					                new_recipe = self.make_balanced_recipe(
 | 
				
			||||||
                                                       factor=(self.multiworld.max_science_pack[self.player].value + 1) / 7)
 | 
					                    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
 | 
					                self.custom_recipes["rocket-silo"] = new_recipe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.multiworld.satellite[self.player].value == Satellite.option_randomize_recipe:
 | 
					            if self.multiworld.satellite[self.player].value == Satellite.option_randomize_recipe:
 | 
				
			||||||
                new_recipe = self.make_balanced_recipe(recipes["satellite"], valid_pool,
 | 
					                new_recipe = self.make_balanced_recipe(
 | 
				
			||||||
                                                       factor=(self.multiworld.max_science_pack[self.player].value + 1) / 7)
 | 
					                    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
 | 
					                self.custom_recipes["satellite"] = new_recipe
 | 
				
			||||||
        bridge = "ap-energy-bridge"
 | 
					        bridge = "ap-energy-bridge"
 | 
				
			||||||
        new_recipe = self.make_quick_recipe(
 | 
					        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),
 | 
					                   {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:
 | 
					        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
 | 
					        self.custom_recipes[bridge] = new_recipe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        needed_recipes = self.multiworld.max_science_pack[self.player].get_allowed_packs() | {"rocket-part"}
 | 
					        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)
 | 
					                                tech_table[name], self.player)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        item = FactorioItem(name,
 | 
					        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)
 | 
					                            all_items[name], self.player)
 | 
				
			||||||
        return item
 | 
					        return item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The MIT License (MIT)
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Copyright (c) 2021 Berserker55 and Dewiniaid
 | 
					Copyright (c) 2023 Berserker55
 | 
				
			||||||
 | 
					Copyright (c) 2021 Dewiniaid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,32 +1,3 @@
 | 
				
			||||||
function filter_ingredients(ingredients, ingredient_filter)
 | 
					 | 
				
			||||||
    local new_ingredient_list = {}
 | 
					 | 
				
			||||||
    for _, ingredient_table in pairs(ingredients) do
 | 
					 | 
				
			||||||
        if ingredient_filter[ingredient_table[1]] then -- name of ingredient_table
 | 
					 | 
				
			||||||
            table.insert(new_ingredient_list, ingredient_table)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return new_ingredient_list
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function add_ingredients(ingredients, added_ingredients)
 | 
					 | 
				
			||||||
    local new_ingredient_list = table.deepcopy(ingredients)
 | 
					 | 
				
			||||||
    for new_ingredient, count in pairs(added_ingredients) do
 | 
					 | 
				
			||||||
        local found = false
 | 
					 | 
				
			||||||
        for _, old_ingredient in pairs(ingredients) do
 | 
					 | 
				
			||||||
            if old_ingredient[1] == new_ingredient then
 | 
					 | 
				
			||||||
                found = true
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
            end
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
        if not found then
 | 
					 | 
				
			||||||
            table.insert(new_ingredient_list, {new_ingredient, count})
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return new_ingredient_list
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function get_any_stack_size(name)
 | 
					function get_any_stack_size(name)
 | 
				
			||||||
    local item = game.item_prototypes[name]
 | 
					    local item = game.item_prototypes[name]
 | 
				
			||||||
    if item ~= nil then
 | 
					    if item ~= nil then
 | 
				
			||||||
| 
						 | 
					@ -51,3 +22,18 @@ function split(s, sep)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return fields
 | 
					    return fields
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function random_offset_position(position, offset)
 | 
				
			||||||
 | 
					    return {x=position.x+math.random(-offset, offset), y=position.y+math.random(-1024, 1024)}
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fire_entity_at_players(entity_name, speed)
 | 
				
			||||||
 | 
					    for _, player in ipairs(game.forces["player"].players) do
 | 
				
			||||||
 | 
					        current_character = player.character
 | 
				
			||||||
 | 
					        if current_character ~= nil then
 | 
				
			||||||
 | 
					            current_character.surface.create_entity{name=entity_name,
 | 
				
			||||||
 | 
					                position=random_offset_position(current_character.position, 128),
 | 
				
			||||||
 | 
					                target=current_character, speed=speed}
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ TRAP_EVO_FACTOR = {{ evolution_trap_increase }} / 100
 | 
				
			||||||
MAX_SCIENCE_PACK = {{ max_science_pack }}
 | 
					MAX_SCIENCE_PACK = {{ max_science_pack }}
 | 
				
			||||||
GOAL = {{ goal }}
 | 
					GOAL = {{ goal }}
 | 
				
			||||||
ARCHIPELAGO_DEATH_LINK_SETTING = "archipelago-death-link-{{ slot_player }}-{{ seed_name }}"
 | 
					ARCHIPELAGO_DEATH_LINK_SETTING = "archipelago-death-link-{{ slot_player }}-{{ seed_name }}"
 | 
				
			||||||
ENERGY_INCREMENT = {{ energy_link * 1000000 }}
 | 
					ENERGY_INCREMENT = {{ energy_link * 10000000 }}
 | 
				
			||||||
ENERGY_LINK_EFFICIENCY = 0.75
 | 
					ENERGY_LINK_EFFICIENCY = 0.75
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if settings.global[ARCHIPELAGO_DEATH_LINK_SETTING].value then
 | 
					if settings.global[ARCHIPELAGO_DEATH_LINK_SETTING].value then
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,119 @@ end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CURRENTLY_DEATH_LOCK = 0
 | 
					CURRENTLY_DEATH_LOCK = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% if chunk_shuffle %}
 | 
				
			||||||
 | 
					LAST_POSITIONS = {}
 | 
				
			||||||
 | 
					GENERATOR = nil
 | 
				
			||||||
 | 
					NORTH = 1
 | 
				
			||||||
 | 
					EAST = 2
 | 
				
			||||||
 | 
					SOUTH = 3
 | 
				
			||||||
 | 
					WEST = 4
 | 
				
			||||||
 | 
					ER_COLOR = {1, 1, 1, 0.2}
 | 
				
			||||||
 | 
					ER_SEED = {{ random.randint(4294967295, 2*4294967295)}}
 | 
				
			||||||
 | 
					CURRENTLY_MOVING = false
 | 
				
			||||||
 | 
					ER_FRAMES = {}
 | 
				
			||||||
 | 
					CHUNK_OFFSET = {
 | 
				
			||||||
 | 
					[NORTH] = {0, 1},
 | 
				
			||||||
 | 
					[EAST] = {1, 0},
 | 
				
			||||||
 | 
					[SOUTH] = {0, -1},
 | 
				
			||||||
 | 
					[WEST] = {-1, 0}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function on_player_changed_position(event)
 | 
				
			||||||
 | 
					    if CURRENTLY_MOVING == true then
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    local player_id = event.player_index
 | 
				
			||||||
 | 
					    local player = game.get_player(player_id)
 | 
				
			||||||
 | 
					    local character = player.character -- can be nil, such as spectators
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if character == nil then
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    local last_position = LAST_POSITIONS[player_id]
 | 
				
			||||||
 | 
					    if last_position == nil then
 | 
				
			||||||
 | 
					        LAST_POSITIONS[player_id] = character.position
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    last_x_chunk = math.floor(last_position.x / 32)
 | 
				
			||||||
 | 
					    current_x_chunk = math.floor(character.position.x / 32)
 | 
				
			||||||
 | 
					    last_y_chunk = math.floor(last_position.y / 32)
 | 
				
			||||||
 | 
					    current_y_chunk = math.floor(character.position.y / 32)
 | 
				
			||||||
 | 
					    if (ER_FRAMES[player_id] ~= nil and rendering.is_valid(ER_FRAMES[player_id])) then
 | 
				
			||||||
 | 
					        rendering.destroy(ER_FRAMES[player_id])
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    ER_FRAMES[player_id] = rendering.draw_rectangle{
 | 
				
			||||||
 | 
					        color=ER_COLOR, width=1, filled=false, left_top = {current_x_chunk*32, current_y_chunk*32},
 | 
				
			||||||
 | 
					        right_bottom={current_x_chunk*32+32, current_y_chunk*32+32}, players={player}, time_to_live=60,
 | 
				
			||||||
 | 
					        draw_on_ground= true, only_in_alt_mode = true, surface=character.surface}
 | 
				
			||||||
 | 
					    if current_x_chunk == last_x_chunk and current_y_chunk == last_y_chunk then -- nothing needs doing
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    if ((last_position.x - character.position.x) ^ 2 + (last_position.y - character.position.y) ^ 2) > 4000 then
 | 
				
			||||||
 | 
					        -- distance too high, death or other teleport took place
 | 
				
			||||||
 | 
					        LAST_POSITIONS[player_id] = character.position
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    -- we'll need a deterministic random state
 | 
				
			||||||
 | 
					    if GENERATOR == nil or not GENERATOR.valid then
 | 
				
			||||||
 | 
					        GENERATOR = game.create_random_generator()
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- sufficiently random pattern
 | 
				
			||||||
 | 
					    GENERATOR.re_seed((ER_SEED + (last_x_chunk * 1730000000) + (last_y_chunk * 97000)) % 4294967295)
 | 
				
			||||||
 | 
					    -- we now need all 4 exit directions deterministically shuffled to the 4 outgoing directions.
 | 
				
			||||||
 | 
					    local exit_table = {
 | 
				
			||||||
 | 
					    [1] = 1,
 | 
				
			||||||
 | 
					    [2] = 2,
 | 
				
			||||||
 | 
					    [3] = 3,
 | 
				
			||||||
 | 
					    [4] = 4
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    exit_table = fisher_yates_shuffle(exit_table)
 | 
				
			||||||
 | 
					    if current_x_chunk > last_x_chunk then -- going right/east
 | 
				
			||||||
 | 
					        outbound_direction = EAST
 | 
				
			||||||
 | 
					    elseif current_x_chunk < last_x_chunk then -- going left/west
 | 
				
			||||||
 | 
					        outbound_direction = WEST
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if current_y_chunk > last_y_chunk then -- going down/south
 | 
				
			||||||
 | 
					        outbound_direction = SOUTH
 | 
				
			||||||
 | 
					    elseif current_y_chunk < last_y_chunk then -- going up/north
 | 
				
			||||||
 | 
					        outbound_direction = NORTH
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    local target_direction = exit_table[outbound_direction]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local target_position = {(CHUNK_OFFSET[target_direction][1] + last_x_chunk) * 32 + 16,
 | 
				
			||||||
 | 
												 (CHUNK_OFFSET[target_direction][2] + last_y_chunk) * 32 + 16}
 | 
				
			||||||
 | 
					    target_position = character.surface.find_non_colliding_position(character.prototype.name,
 | 
				
			||||||
 | 
					                                                                    target_position, 32, 0.5)
 | 
				
			||||||
 | 
					    if target_position ~= nil then
 | 
				
			||||||
 | 
					        rendering.draw_circle{color = ER_COLOR, radius = 1, filled = true,
 | 
				
			||||||
 | 
					                              target = {character.position.x, character.position.y}, surface = character.surface,
 | 
				
			||||||
 | 
					                              time_to_live = 300, draw_on_ground = true}
 | 
				
			||||||
 | 
					        rendering.draw_line{color = ER_COLOR, width = 3, gap_length = 0.5, dash_length = 0.5,
 | 
				
			||||||
 | 
					                            from = {character.position.x, character.position.y}, to = target_position,
 | 
				
			||||||
 | 
					                            surface = character.surface,
 | 
				
			||||||
 | 
					                            time_to_live = 300, draw_on_ground = true}
 | 
				
			||||||
 | 
					        CURRENTLY_MOVING = true -- prevent recursive event
 | 
				
			||||||
 | 
					        character.teleport(target_position)
 | 
				
			||||||
 | 
					        CURRENTLY_MOVING = false
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    LAST_POSITIONS[player_id] = character.position
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fisher_yates_shuffle(tbl)
 | 
				
			||||||
 | 
					    for i = #tbl, 2, -1 do
 | 
				
			||||||
 | 
					        local j = GENERATOR(i)
 | 
				
			||||||
 | 
					        tbl[i], tbl[j] = tbl[j], tbl[i]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					    return tbl
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					script.on_event(defines.events.on_player_changed_position, on_player_changed_position)
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function on_check_energy_link(event)
 | 
					function on_check_energy_link(event)
 | 
				
			||||||
    --- assuming 1 MJ increment and 5MJ battery:
 | 
					    --- assuming 1 MJ increment and 5MJ battery:
 | 
				
			||||||
    --- first 2 MJ request fill, last 2 MJ push energy, middle 1 MJ does nothing
 | 
					    --- first 2 MJ request fill, last 2 MJ push energy, middle 1 MJ does nothing
 | 
				
			||||||
| 
						 | 
					@ -510,6 +623,37 @@ commands.add_command("ap-print", "Used by the Archipelago client to print messag
 | 
				
			||||||
    game.print(call.parameter)
 | 
					    game.print(call.parameter)
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TRAP_TABLE = {
 | 
				
			||||||
 | 
					["Attack Trap"] = function ()
 | 
				
			||||||
 | 
					    game.surfaces["nauvis"].build_enemy_base(game.forces["player"].get_spawn_position(game.get_surface(1)), 25)
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					["Evolution Trap"] = function ()
 | 
				
			||||||
 | 
					    game.forces["enemy"].evolution_factor = game.forces["enemy"].evolution_factor + (TRAP_EVO_FACTOR * (1 - game.forces["enemy"].evolution_factor))
 | 
				
			||||||
 | 
					    game.print({"", "New evolution factor:", game.forces["enemy"].evolution_factor})
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					["Teleport Trap"] = function ()
 | 
				
			||||||
 | 
					    for _, player in ipairs(game.forces["player"].players) do
 | 
				
			||||||
 | 
					        current_character = player.character
 | 
				
			||||||
 | 
					        if current_character ~= nil then
 | 
				
			||||||
 | 
					            current_character.teleport(current_character.surface.find_non_colliding_position(
 | 
				
			||||||
 | 
					                current_character.prototype.name, random_offset_position(current_character.position, 1024), 0, 1))
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					["Grenade Trap"] = function ()
 | 
				
			||||||
 | 
					    fire_entity_at_players("grenade", 0.1)
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					["Cluster Grenade Trap"] = function ()
 | 
				
			||||||
 | 
					    fire_entity_at_players("cluster-grenade", 0.1)
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					["Artillery Trap"] = function ()
 | 
				
			||||||
 | 
					    fire_entity_at_players("artillery-projectile", 1)
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					["Atomic Rocket Trap"] = function ()
 | 
				
			||||||
 | 
					    fire_entity_at_players("atomic-rocket", 0.1)
 | 
				
			||||||
 | 
					end,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
commands.add_command("ap-get-technology", "Grant a technology, used by the Archipelago Client.", function(call)
 | 
					commands.add_command("ap-get-technology", "Grant a technology, used by the Archipelago Client.", function(call)
 | 
				
			||||||
    if global.index_sync == nil then
 | 
					    if global.index_sync == nil then
 | 
				
			||||||
        global.index_sync = {}
 | 
					        global.index_sync = {}
 | 
				
			||||||
| 
						 | 
					@ -552,18 +696,11 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
 | 
				
			||||||
                tech.researched = true
 | 
					                tech.researched = true
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    elseif item_name == "Attack Trap" then
 | 
					    elseif TRAP_TABLE[item_name] ~= nil then
 | 
				
			||||||
        if global.index_sync[index] == nil then -- not yet received trap
 | 
					 | 
				
			||||||
            game.print({"", "Received Attack Trap from ", source})
 | 
					 | 
				
			||||||
            global.index_sync[index] = item_name
 | 
					 | 
				
			||||||
            local spawn_position = force.get_spawn_position(game.get_surface(1))
 | 
					 | 
				
			||||||
            game.surfaces["nauvis"].build_enemy_base(spawn_position, 25)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
    elseif item_name == "Evolution Trap" then
 | 
					 | 
				
			||||||
        if global.index_sync[index] == nil then -- not yet received trap
 | 
					        if global.index_sync[index] == nil then -- not yet received trap
 | 
				
			||||||
            global.index_sync[index] = item_name
 | 
					            global.index_sync[index] = item_name
 | 
				
			||||||
            game.forces["enemy"].evolution_factor = game.forces["enemy"].evolution_factor + (TRAP_EVO_FACTOR * (1 - game.forces["enemy"].evolution_factor))
 | 
					            game.print({"", "Received ", item_name, " from ", source})
 | 
				
			||||||
            game.print({"", "Received Evolution Trap from ", source, ". New factor:", game.forces["enemy"].evolution_factor})
 | 
					            TRAP_TABLE[item_name]()
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        game.print("Unknown Item " .. item_name)
 | 
					        game.print("Unknown Item " .. item_name)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,9 +14,9 @@ local energy_bridge = table.deepcopy(data.raw["accumulator"]["accumulator"])
 | 
				
			||||||
energy_bridge.name = "ap-energy-bridge"
 | 
					energy_bridge.name = "ap-energy-bridge"
 | 
				
			||||||
energy_bridge.minable.result = "ap-energy-bridge"
 | 
					energy_bridge.minable.result = "ap-energy-bridge"
 | 
				
			||||||
energy_bridge.localised_name = "Archipelago EnergyLink Bridge"
 | 
					energy_bridge.localised_name = "Archipelago EnergyLink Bridge"
 | 
				
			||||||
energy_bridge.energy_source.buffer_capacity = "5MJ"
 | 
					energy_bridge.energy_source.buffer_capacity = "50MJ"
 | 
				
			||||||
energy_bridge.energy_source.input_flow_limit = "1MW"
 | 
					energy_bridge.energy_source.input_flow_limit = "10MW"
 | 
				
			||||||
energy_bridge.energy_source.output_flow_limit = "1MW"
 | 
					energy_bridge.energy_source.output_flow_limit = "10MW"
 | 
				
			||||||
tint_icon(energy_bridge, energy_bridge_tint())
 | 
					tint_icon(energy_bridge, energy_bridge_tint())
 | 
				
			||||||
energy_bridge.picture.layers[1].tint = energy_bridge_tint()
 | 
					energy_bridge.picture.layers[1].tint = energy_bridge_tint()
 | 
				
			||||||
energy_bridge.picture.layers[1].hr_version.tint = energy_bridge_tint()
 | 
					energy_bridge.picture.layers[1].hr_version.tint = energy_bridge_tint()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue