mirror of
				https://github.com/MarioSpore/Grinch-AP.git
				synced 2025-10-21 20:21:32 -06:00 
			
		
		
		
	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:
		| @@ -136,6 +136,7 @@ def generate_mod(world: "Factorio", output_directory: str): | ||||
|         "goal": multiworld.goal[player].value, | ||||
|         "energy_link": multiworld.energy_link[player].value, | ||||
|         "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: | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| from __future__ import annotations | ||||
| import typing | ||||
| import datetime | ||||
|  | ||||
| from Options import Choice, OptionDict, OptionSet, ItemDict, Option, DefaultOnToggle, Range, DeathLink, Toggle | ||||
| from schema import Schema, Optional, And, Or | ||||
| @@ -197,6 +198,14 @@ class RecipeIngredients(Choice): | ||||
|     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): | ||||
|     """Mapping of Factorio internal item-name to amount granted on start.""" | ||||
|     display_name = "Starting Items" | ||||
| @@ -223,9 +232,36 @@ class AttackTrapCount(TrapCount): | ||||
|     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): | ||||
|     """Trap items that when received increase the enemy evolution.""" | ||||
|     display_name = "Evolution Traps" | ||||
|     range_end = 10 | ||||
|  | ||||
|  | ||||
| class EvolutionTrapIncrease(Range): | ||||
| @@ -404,12 +440,31 @@ factorio_options: typing.Dict[str, type(Option)] = { | ||||
|     "free_sample_whitelist": FactorioFreeSampleWhitelist, | ||||
|     "recipe_time": RecipeTime, | ||||
|     "recipe_ingredients": RecipeIngredients, | ||||
|     "recipe_ingredients_offset": RecipeIngredientsOffset, | ||||
|     "imported_blueprints": ImportedBlueprint, | ||||
|     "world_gen": FactorioWorldGen, | ||||
|     "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, | ||||
|     "evolution_traps": EvolutionTrapCount, | ||||
|     "evolution_trap_increase": EvolutionTrapIncrease, | ||||
|     "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["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 | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
|  | ||||
| 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 | ||||
| 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) | ||||
|     local item = game.item_prototypes[name] | ||||
|     if item ~= nil then | ||||
| @@ -50,4 +21,19 @@ function split(s, sep) | ||||
|     string.gsub(s, pattern, function(c) fields[#fields + 1] = c end) | ||||
|  | ||||
|     return fields | ||||
| 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 }} | ||||
| GOAL = {{ goal }} | ||||
| 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 | ||||
|  | ||||
| if settings.global[ARCHIPELAGO_DEATH_LINK_SETTING].value then | ||||
| @@ -22,6 +22,119 @@ end | ||||
|  | ||||
| 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) | ||||
|     --- assuming 1 MJ increment and 5MJ battery: | ||||
|     --- first 2 MJ request fill, last 2 MJ push energy, middle 1 MJ does nothing | ||||
| @@ -180,8 +293,8 @@ script.on_event(defines.events.on_player_removed, on_player_removed) | ||||
|  | ||||
| function on_rocket_launched(event) | ||||
|     if event.rocket and event.rocket.valid and global.forcedata[event.rocket.force.name]['victory'] == 0 then | ||||
| 		if event.rocket.get_item_count("satellite") > 0 or GOAL == 0 then | ||||
| 			global.forcedata[event.rocket.force.name]['victory'] = 1 | ||||
|         if event.rocket.get_item_count("satellite") > 0 or GOAL == 0 then | ||||
|             global.forcedata[event.rocket.force.name]['victory'] = 1 | ||||
|             dumpInfo(event.rocket.force) | ||||
|             game.set_game_state | ||||
|             { | ||||
| @@ -190,8 +303,8 @@ function on_rocket_launched(event) | ||||
|                 can_continue = true, | ||||
|                 victorious_force = event.rocket.force | ||||
|             } | ||||
| 		end | ||||
| 	end | ||||
|         end | ||||
|     end | ||||
| end | ||||
| script.on_event(defines.events.on_rocket_launched, on_rocket_launched) | ||||
|  | ||||
| @@ -236,7 +349,7 @@ function update_player(index) | ||||
|             end | ||||
|         else | ||||
|             player.print("Unable to receive " .. count .. "x [item=" .. name .. "] as this item does not exist.") | ||||
| 			samples[name] = nil | ||||
|             samples[name] = nil | ||||
|         end | ||||
|     end | ||||
|  | ||||
| @@ -254,9 +367,9 @@ script.on_event(defines.events.on_player_main_inventory_changed, update_player_e | ||||
| function add_samples(force, name, count) | ||||
|     local function add_to_table(t) | ||||
|         if count <= 0 then | ||||
| 			-- Fixes a bug with single craft, if a recipe gives 0 of a given item. | ||||
| 			return | ||||
| 		end | ||||
|             -- Fixes a bug with single craft, if a recipe gives 0 of a given item. | ||||
|             return | ||||
|         end | ||||
|         t[name] = (t[name] or 0) + count | ||||
|     end | ||||
|     -- Add to global table of earned samples for future new players | ||||
| @@ -298,8 +411,8 @@ script.on_event(defines.events.on_research_finished, function(event) | ||||
|         --Don't acknowledge AP research as an Editor Extensions test force | ||||
|         --Also no need for free samples in the Editor extensions testing surfaces, as these testing surfaces | ||||
|         --are worked on exclusively in editor mode. | ||||
| 		return | ||||
| 	end | ||||
|         return | ||||
|     end | ||||
|     if technology.researched and string.find(technology.name, "ap%-") == 1 then | ||||
|         -- check if it came from the server anyway, then we don't need to double send. | ||||
|         dumpInfo(technology.force) --is sendable | ||||
| @@ -510,6 +623,37 @@ commands.add_command("ap-print", "Used by the Archipelago client to print messag | ||||
|     game.print(call.parameter) | ||||
| 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) | ||||
|     if global.index_sync == nil then | ||||
|         global.index_sync = {} | ||||
| @@ -552,18 +696,11 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi | ||||
|                 tech.researched = true | ||||
|             end | ||||
|         end | ||||
|     elseif item_name == "Attack Trap" 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 | ||||
|     elseif TRAP_TABLE[item_name] ~= nil then | ||||
|         if global.index_sync[index] == nil then -- not yet received trap | ||||
|             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 Evolution Trap from ", source, ". New factor:", game.forces["enemy"].evolution_factor}) | ||||
|             game.print({"", "Received ", item_name, " from ", source}) | ||||
|             TRAP_TABLE[item_name]() | ||||
|         end | ||||
|     else | ||||
|         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.minable.result = "ap-energy-bridge" | ||||
| energy_bridge.localised_name = "Archipelago EnergyLink Bridge" | ||||
| energy_bridge.energy_source.buffer_capacity = "5MJ" | ||||
| energy_bridge.energy_source.input_flow_limit = "1MW" | ||||
| energy_bridge.energy_source.output_flow_limit = "1MW" | ||||
| energy_bridge.energy_source.buffer_capacity = "50MJ" | ||||
| energy_bridge.energy_source.input_flow_limit = "10MW" | ||||
| energy_bridge.energy_source.output_flow_limit = "10MW" | ||||
| tint_icon(energy_bridge, energy_bridge_tint()) | ||||
| energy_bridge.picture.layers[1].tint = energy_bridge_tint() | ||||
| energy_bridge.picture.layers[1].hr_version.tint = energy_bridge_tint() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Fabian Dill
					Fabian Dill