Skip to content

Commit a79b38e

Browse files
committed
modded home points
1 parent 293d97b commit a79b38e

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

worlds/crystal_project/__init__.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
display_region_levels_dictionary
2323
from .options import CrystalProjectOptions, create_option_groups
2424
from .rules import CrystalProjectLogic
25-
from .mod_helper import ModLocationData, get_modded_items, get_modded_locations, \
25+
from .mod_helper import ModLocationData, get_modded_items, get_modded_locations, get_modded_home_points, \
2626
get_modded_shopsanity_locations, get_modded_bosses, build_condition_rule, update_item_classification, get_mod_info, get_removed_locations
2727
from typing import List, Set, Dict, Any
2828
from worlds.AutoWorld import World, WebWorld
@@ -94,6 +94,15 @@ class CrystalProjectWorld(World):
9494
for modded_boss in modded_bosses:
9595
location_name_to_id[modded_boss.name] = modded_boss.code
9696

97+
modded_home_points = get_modded_home_points(mod_info)
98+
99+
for modded_home_point in modded_home_points:
100+
location_name_to_id[modded_home_point.name] = modded_home_point.code + home_point_location_index_offset
101+
if modded_home_point.name in item_name_to_id and item_name_to_id[modded_home_point.name] != modded_home_point.code:
102+
raise Exception(f"A modded item({modded_home_point.name}) with id {modded_home_point.code} tried to change the code of item_name_to_id and it can never change!")
103+
item_name_to_id[modded_home_point.name] = modded_home_point.code + home_point_item_index_offset
104+
item_name_groups.setdefault(MOD, set()).add(modded_home_point.name)
105+
97106
removed_locations = get_removed_locations(mod_info)
98107

99108
web = CrystalProjectWeb()
@@ -221,10 +230,20 @@ def create_regions(self) -> None:
221230
if self.options.home_point_hustle.value != self.options.home_point_hustle.option_disabled:
222231
home_points = get_home_points()
223232

233+
# todo removed home points
224234
for home_point in home_points:
225235
home_point_location = LocationData(home_point.ap_region, home_point.name, (home_point.code + home_point_location_index_offset), home_point.rule)
226236
locations.append(home_point_location)
227237

238+
if self.options.use_mods.value == self.options.use_mods.option_true:
239+
for modded_home_point in self.modded_home_points:
240+
location = LocationData(display_region_subregions_dictionary[modded_home_point.display_region][0],
241+
modded_home_point.name,
242+
modded_home_point.code + home_point_location_index_offset,
243+
build_condition_rule(modded_home_point.display_region,
244+
modded_home_point.rule_condition, self))
245+
locations.append(location)
246+
228247
#Regionsanity completion locations need to be added after all other locations so they can be removed if the region is empty (e.g. Neptune Shrine w/o Shopsanity)
229248
if self.options.regionsanity.value != self.options.regionsanity.option_disabled:
230249
region_completions = get_region_completion_locations()
@@ -381,8 +400,14 @@ def create_item(self, name: str) -> Item:
381400
return Item(name, data.classification, data.code, self.player)
382401
else:
383402
matches_mod = [item for (index, item) in enumerate(self.modded_items) if item.name == name]
403+
matches_mod_home_point = [item for (index, item) in enumerate(self.modded_home_points) if item.name == name]
384404

385-
return Item(matches_mod[0].name, matches_mod[0].classification, matches_mod[0].code, self.player)
405+
if len(matches_mod) > 0:
406+
return Item(matches_mod[0].name, matches_mod[0].classification, matches_mod[0].code, self.player)
407+
elif len(matches_mod_home_point) > 0:
408+
return Item(matches_mod_home_point[0].name, ItemClassification.progression, matches_mod_home_point[0].code + home_point_item_index_offset, self.player)
409+
else:
410+
raise Exception(f"No matches found for name {name}")
386411

387412
def create_items(self) -> None:
388413
pool = self.get_item_pool(self.get_excluded_items())
@@ -656,6 +681,12 @@ def get_item_pool(self, excluded_items: Set[str]) -> List[Item]:
656681
item = self.create_item(modded_item.name)
657682
pool.append(item)
658683

684+
if self.options.home_point_hustle != self.options.home_point_hustle.option_disabled:
685+
for modded_home_point in self.modded_home_points:
686+
item = self.create_item(modded_home_point.name)
687+
update_item_classification(item, [location.rule_condition for location in combined_locations], self)
688+
pool.append(item)
689+
659690
if not self.options.level_gating.value == self.options.level_gating.option_none:
660691
#guarantee space for 2 clamshells
661692
min_clamshells = 2
@@ -710,7 +741,10 @@ def get_job_id_list(self) -> List[int]:
710741
def fill_slot_data(self) -> Dict[str, Any]:
711742
mod_info = []
712743
slot_data_locations = []
744+
slot_data_home_points = []
713745
slot_data_removed_locations = []
746+
slot_data_removed_home_points = []
747+
714748
if self.options.use_mods:
715749
for mod in self.mod_info:
716750
mod_info.append({ "Id": mod.mod_id, "Name": mod.mod_name, "LoadOrder": mod.load_order })
@@ -740,10 +774,21 @@ def fill_slot_data(self) -> Dict[str, Any]:
740774
"BiomeId": boss.biomeId,
741775
"Rule": None })
742776

777+
if self.options.home_point_hustle != self.options.home_point_hustle.option_disabled:
778+
for home_point in self.modded_home_points:
779+
slot_data_home_points.append({ "Id": home_point.offsetless_code,
780+
"APRegion": display_region_subregions_dictionary[home_point.display_region][0],
781+
"Name": home_point.name,
782+
"Coordinates": home_point.coordinates,
783+
"BiomeId": home_point.biomeId,
784+
"Rule": None })
785+
743786
for location in self.removed_locations:
744787
slot_data_removed_locations.append({"Id": location.code,
745788
"APRegion": location.ap_region})
746789

790+
#TODO removed home points
791+
747792
# look into replacing this big chonky return block with self.options.as_dict() and then just adding the extras to the dict after
748793
return {
749794
"apworldVersion": self.world_version.as_simple_string(),
@@ -782,6 +827,7 @@ def fill_slot_data(self) -> Dict[str, Any]:
782827
"useMods": self.options.use_mods.value,
783828
"modInfo": mod_info,
784829
"moddedLocations": slot_data_locations,
830+
"moddedHomePoints": slot_data_home_points,
785831
"removedLocations": slot_data_removed_locations,
786832
# "moddedLocationsForUT": self.modded_locations,
787833
# "moddedShopsForUT": self.modded_shops,

worlds/crystal_project/mod_helper.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .items import item_table, equipment_index_offset, item_index_offset, job_index_offset
1010
from .locations import LocationData, get_treasure_and_npc_locations, get_shop_locations, get_boss_locations, npc_index_offset, treasure_index_offset, crystal_index_offset, \
1111
boss_index_offset, shop_index_offset, get_crystal_locations
12+
from .home_point_locations import get_home_points
1213
from .unused_locations import get_unused_locations
1314
from .constants.biomes import get_display_region_by_id
1415
from .constants.display_regions import *
@@ -18,12 +19,13 @@
1819
import json
1920

2021
if TYPE_CHECKING:
21-
from . import CrystalProjectWorld
22+
from . import CrystalProjectWorld, home_point_location_index_offset
2223

2324
MAX_SUPPORTED_EDITOR_VERSION: int = 32
2425

2526
NPC_ENTITY_TYPE: int = 0 #Could be a boss or an npc check or a store or not a check at all
2627
SPARK_ENTITY_TYPE: int = 2 #Could be a boss or not a boss
28+
HOME_POINT_ENTITY_TYPE: int = 4
2729
TREASURE_ENTITY_TYPE: int = 5
2830
CRYSTAL_ENTITY_TYPE: int = 6
2931

@@ -327,6 +329,21 @@ def get_modded_bosses(mod_info: List[ModInfoModel]) -> List[ModLocationData]:
327329

328330
return locations
329331

332+
def get_modded_home_points(mod_info: List[ModInfoModel]) -> List[ModLocationData]:
333+
locations: List[ModLocationData] = []
334+
335+
for mod in mod_info:
336+
for location in mod.data_model.Entities:
337+
entity_type = location['EntityType']
338+
339+
# Entity type 0 is NPC
340+
if entity_type == HOME_POINT_ENTITY_TYPE:
341+
location = build_home_point_location(location, mod.shifted_entity_ids)
342+
if location is not None:
343+
locations.append(location)
344+
345+
return locations
346+
330347
def get_removed_locations(mod_info: List[ModInfoModel]) -> List[LocationData]:
331348
removed_locations: List[LocationData] = []
332349
vanilla_treasures_and_npcs = get_treasure_and_npc_locations(-1, None)
@@ -694,6 +711,29 @@ def build_spark_location(location, shifted_entity_ids: List[ModIncrementedIdData
694711

695712
return None
696713

714+
def build_home_point_location(location, shifted_entity_ids: List[ModIncrementedIdData]) -> Optional[ModLocationData]:
715+
biome_id = location['BiomeID']
716+
display_region = get_display_region_by_id(biome_id)
717+
item_id = location['ID']
718+
name = location['HomePointData']['Name']
719+
720+
new_id = item_id
721+
for incremented_id in shifted_entity_ids:
722+
if incremented_id.original_id == item_id:
723+
new_id = incremented_id.new_id
724+
725+
name = 'Home Point - Modded Home Point ' + name + ' ' + str(new_id)
726+
coord = location['Coord']
727+
coordinates = str(coord['X']) + ',' + str(coord['Y']) + ',' + str(coord['Z'])
728+
729+
location_in_pool = any(location.code == item_id for location in get_home_points())
730+
731+
if not location_in_pool:
732+
location = ModLocationData(display_region, name, new_id, new_id, coordinates, biome_id, None)
733+
return location
734+
735+
return None
736+
697737
def build_condition_rule(region, condition, world: "CrystalProjectWorld") -> Optional[Callable[[CollectionState], bool]]:
698738
logic = CrystalProjectLogic(world.player, world.options)
699739
job_id = None

0 commit comments

Comments
 (0)