Skip to content

Commit f549afc

Browse files
agilbert1412FlySniper
authored andcommitted
Stardew Valley: Added missing logic rules for dating and marriage (ArchipelagoMW#2160)
* - Added missing logic rules where, to earn hearts above 8 and 10, you need access to dating and marriage respectively. * - Slight cleanup based on Black Sliver's suggestion
1 parent 1168e16 commit f549afc

File tree

2 files changed

+78
-6
lines changed

2 files changed

+78
-6
lines changed

worlds/stardew_valley/logic.py

+18-6
Original file line numberDiff line numberDiff line change
@@ -1043,11 +1043,12 @@ def can_reproduce(self, number_children: int = 1) -> StardewRule:
10431043
def has_relationship(self, npc: str, hearts: int = 1) -> StardewRule:
10441044
if hearts <= 0:
10451045
return True_()
1046-
if self.options[options.Friendsanity] == options.Friendsanity.option_none:
1046+
friendsanity = self.options[options.Friendsanity]
1047+
if friendsanity == options.Friendsanity.option_none:
10471048
return self.can_earn_relationship(npc, hearts)
10481049
if npc not in all_villagers_by_name:
10491050
if npc == NPC.pet:
1050-
if self.options[options.Friendsanity] == options.Friendsanity.option_bachelors:
1051+
if friendsanity == options.Friendsanity.option_bachelors:
10511052
return self.can_befriend_pet(hearts)
10521053
return self.received_hearts(NPC.pet, hearts)
10531054
if npc == Generic.any or npc == Generic.bachelor:
@@ -1077,12 +1078,12 @@ def has_relationship(self, npc: str, hearts: int = 1) -> StardewRule:
10771078
if not self.npc_is_in_current_slot(npc):
10781079
return True_()
10791080
villager = all_villagers_by_name[npc]
1080-
if self.options[options.Friendsanity] == options.Friendsanity.option_bachelors and not villager.bachelor:
1081+
if friendsanity == options.Friendsanity.option_bachelors and not villager.bachelor:
10811082
return self.can_earn_relationship(npc, hearts)
1082-
if self.options[options.Friendsanity] == options.Friendsanity.option_starting_npcs and not villager.available:
1083+
if friendsanity == options.Friendsanity.option_starting_npcs and not villager.available:
10831084
return self.can_earn_relationship(npc, hearts)
1084-
if self.options[
1085-
options.Friendsanity] != options.Friendsanity.option_all_with_marriage and villager.bachelor and hearts > 8:
1085+
is_capped_at_8 = villager.bachelor and friendsanity != options.Friendsanity.option_all_with_marriage
1086+
if is_capped_at_8 and hearts > 8:
10861087
return self.received_hearts(villager, 8) & self.can_earn_relationship(npc, hearts)
10871088
return self.received_hearts(villager, hearts)
10881089

@@ -1136,11 +1137,22 @@ def can_earn_relationship(self, npc: str, hearts: int = 0) -> StardewRule:
11361137
rule_if_birthday = self.has_season(villager.birthday) & self.has_any_universal_love() & self.has_lived_months(hearts // 2)
11371138
rule_if_not_birthday = self.has_lived_months(hearts)
11381139
earn_rule = self.can_meet(npc) & (rule_if_birthday | rule_if_not_birthday)
1140+
if villager.bachelor:
1141+
if hearts > 8:
1142+
earn_rule = earn_rule & self.can_date(npc)
1143+
if hearts > 10:
1144+
earn_rule = earn_rule & self.can_marry(npc)
11391145
else:
11401146
earn_rule = self.has_lived_months(min(hearts // 2, 8))
11411147

11421148
return previous_heart_rule & earn_rule
11431149

1150+
def can_date(self, npc: str) -> StardewRule:
1151+
return self.has_relationship(npc, 8) & self.has(Gift.bouquet)
1152+
1153+
def can_marry(self, npc: str) -> StardewRule:
1154+
return self.has_relationship(npc, 10) & self.has(Gift.mermaid_pendant)
1155+
11441156
def can_befriend_pet(self, hearts: int):
11451157
if hearts <= 0:
11461158
return True_()

worlds/stardew_valley/test/TestRules.py

+60
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,63 @@ def collect_all_except(multiworld, item_to_not_collect: str):
444444
for item in multiworld.get_items():
445445
if item.name != item_to_not_collect:
446446
multiworld.state.collect(item)
447+
448+
449+
class TestFriendsanityDatingRules(SVTestBase):
450+
options = {
451+
options.SeasonRandomization.internal_name: options.SeasonRandomization.option_randomized_not_winter,
452+
options.Friendsanity.internal_name: options.Friendsanity.option_all_with_marriage,
453+
options.FriendsanityHeartSize.internal_name: 3
454+
}
455+
456+
def test_earning_dating_heart_requires_dating(self):
457+
month_name = "Month End"
458+
for i in range(12):
459+
month_item = self.world.create_item(month_name)
460+
self.multiworld.state.collect(month_item, event=True)
461+
self.multiworld.state.collect(self.world.create_item("Beach Bridge"), event=False)
462+
self.multiworld.state.collect(self.world.create_item("Progressive House"), event=False)
463+
self.multiworld.state.collect(self.world.create_item("Adventurer's Guild"), event=False)
464+
self.multiworld.state.collect(self.world.create_item("Galaxy Hammer"), event=False)
465+
for i in range(3):
466+
self.multiworld.state.collect(self.world.create_item("Progressive Pickaxe"), event=False)
467+
self.multiworld.state.collect(self.world.create_item("Progressive Axe"), event=False)
468+
self.multiworld.state.collect(self.world.create_item("Progressive Barn"), event=False)
469+
for i in range(10):
470+
self.multiworld.state.collect(self.world.create_item("Foraging Level"), event=False)
471+
self.multiworld.state.collect(self.world.create_item("Farming Level"), event=False)
472+
self.multiworld.state.collect(self.world.create_item("Mining Level"), event=False)
473+
self.multiworld.state.collect(self.world.create_item("Combat Level"), event=False)
474+
self.multiworld.state.collect(self.world.create_item("Progressive Mine Elevator"), event=False)
475+
self.multiworld.state.collect(self.world.create_item("Progressive Mine Elevator"), event=False)
476+
477+
npc = "Abigail"
478+
heart_name = f"{npc} <3"
479+
step = 3
480+
481+
self.assert_can_reach_heart_up_to(npc, 3, step)
482+
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
483+
self.assert_can_reach_heart_up_to(npc, 6, step)
484+
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
485+
self.assert_can_reach_heart_up_to(npc, 8, step)
486+
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
487+
self.assert_can_reach_heart_up_to(npc, 10, step)
488+
self.multiworld.state.collect(self.world.create_item(heart_name), event=False)
489+
self.assert_can_reach_heart_up_to(npc, 14, step)
490+
491+
def assert_can_reach_heart_up_to(self, npc: str, max_reachable: int, step: int):
492+
prefix = "Friendsanity: "
493+
suffix = " <3"
494+
for i in range(1, max_reachable + 1):
495+
if i % step != 0 and i != 14:
496+
continue
497+
location = f"{prefix}{npc} {i}{suffix}"
498+
can_reach = self.world.logic.can_reach_location(location)(self.multiworld.state)
499+
self.assertTrue(can_reach, f"Should be able to earn relationship up to {i} hearts")
500+
for i in range(max_reachable + 1, 14 + 1):
501+
if i % step != 0 and i != 14:
502+
continue
503+
location = f"{prefix}{npc} {i}{suffix}"
504+
can_reach = self.world.logic.can_reach_location(location)(self.multiworld.state)
505+
self.assertFalse(can_reach, f"Should not be able to earn relationship up to {i} hearts")
506+

0 commit comments

Comments
 (0)