Skip to content

Commit

Permalink
Merge pull request ArchipelagoMW#9 from agilbert1412/StardewValley/5.…
Browse files Browse the repository at this point in the history
…x.x-mod-rewrite

Logic Mixins
  • Loading branch information
agilbert1412 authored Nov 22, 2023
2 parents 9a1107b + 64a7c26 commit 4dd49a3
Show file tree
Hide file tree
Showing 50 changed files with 1,450 additions and 2,031 deletions.
17 changes: 8 additions & 9 deletions worlds/stardew_valley/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from .items import item_table, create_items, ItemData, Group, items_by_group
from .locations import location_table, create_locations, LocationData
from .logic.bundle_logic import BundleLogic
from .logic.cached_logic import function_total_times, function_call_numbers
from .logic.logic import StardewLogic
from .logic.time_logic import MAX_MONTHS
from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \
Expand Down Expand Up @@ -230,35 +229,35 @@ def setup_victory(self):
self.create_event_location(location_table[GoalName.greatest_walnut_hunter],
self.logic.has_walnut(130),
Event.victory)
elif self.options.goal == options.Goal.option_protector_of_the_valley:
elif self.options.goal == Goal.option_protector_of_the_valley:
self.create_event_location(location_table[GoalName.protector_of_the_valley],
self.logic.can_complete_all_monster_slaying_goals(),
Event.victory)
elif self.options.goal == options.Goal.option_full_shipment:
elif self.options.goal == Goal.option_full_shipment:
self.create_event_location(location_table[GoalName.full_shipment],
self.logic.shipping.can_ship_everything(),
Event.victory)
elif self.options.goal == options.Goal.option_gourmet_chef:
elif self.options.goal == Goal.option_gourmet_chef:
self.create_event_location(location_table[GoalName.gourmet_chef],
self.logic.cooking.can_cook_everything,
Event.victory)
elif self.options.goal == options.Goal.option_craft_master:
elif self.options.goal == Goal.option_craft_master:
self.create_event_location(location_table[GoalName.craft_master],
self.logic.crafting.can_craft_everything,
Event.victory)
elif self.options.goal == options.Goal.option_legend:
elif self.options.goal == Goal.option_legend:
self.create_event_location(location_table[GoalName.legend],
self.logic.money.can_have_earned_total(10_000_000),
Event.victory)
elif self.options.goal == options.Goal.option_mystery_of_the_stardrops:
elif self.options.goal == Goal.option_mystery_of_the_stardrops:
self.create_event_location(location_table[GoalName.mystery_of_the_stardrops],
self.logic.has_all_stardrops(),
Event.victory)
elif self.options.goal == options.Goal.option_allsanity:
elif self.options.goal == Goal.option_allsanity:
self.create_event_location(location_table[GoalName.allsanity],
CountPercent(self.player, 100),
Event.victory)
elif self.options.goal == options.Goal.option_perfection:
elif self.options.goal == Goal.option_perfection:
self.create_event_location(location_table[GoalName.perfection],
CountPercent(self.player, 100),
Event.victory)
Expand Down
4 changes: 2 additions & 2 deletions worlds/stardew_valley/bundles.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from random import Random
from typing import List, Dict, Union

from .logic.logic import StardewLogic
from .data.bundle_data import *
from .logic.logic import StardewLogic
from .options import BundleRandomization, BundlePrice

vanilla_bundles = {
Expand Down Expand Up @@ -188,7 +188,7 @@ def shuffle_bundles_completely(random: Random, logic: StardewLogic, bundles: Dic
random.sample(quality_crops_items, 10)
choices = random.sample(all_bundle_items_without_quality_and_money, total_required_item_number - 4)

items_sorted = sorted(choices, key=lambda x: logic.item_rules[x.item.name].get_difficulty())
items_sorted = sorted(choices, key=lambda x: logic.registry.item_rules[x.item.name].get_difficulty())

keys = sorted(bundles.keys())
random.shuffle(keys)
Expand Down
74 changes: 27 additions & 47 deletions worlds/stardew_valley/logic/ability_logic.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,50 @@
from .cached_logic import profile_rule
from .mine_logic import MineLogic
from .received_logic import ReceivedLogic
from .region_logic import RegionLogic
from .skill_logic import SkillLogic
from .tool_logic import ToolLogic
from ..options import NumberOfMovementBuffs, NumberOfLuckBuffs
from ..mods.logic.magic_logic import MagicLogic
from ..mods.logic.skills_logic import ModSkillLogic
from typing import Union

from .base_logic import BaseLogicMixin, BaseLogic
from .mine_logic import MineLogicMixin
from .received_logic import ReceivedLogicMixin
from .region_logic import RegionLogicMixin
from .skill_logic import SkillLogicMixin
from .tool_logic import ToolLogicMixin
from ..mods.logic.magic_logic import MagicLogicMixin
from ..stardew_rule import StardewRule
from ..strings.ap_names.buff_names import Buff
from ..strings.region_names import Region
from ..strings.skill_names import Skill, ModSkill
from ..strings.tool_names import ToolMaterial, Tool


class AbilityLogic:
player: int
movement_buff_option: NumberOfMovementBuffs
luck_buff_option: NumberOfLuckBuffs
received: ReceivedLogic
region: RegionLogic
tool: ToolLogic
skill: SkillLogic
mine: MineLogic
magic: MagicLogic
mod_skill: ModSkillLogic
class AbilityLogicMixin(BaseLogicMixin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ability = AbilityLogic(*args, **kwargs)

def __init__(self, player: int, movement_buff_option: NumberOfMovementBuffs, luck_buff_option: NumberOfLuckBuffs, received: ReceivedLogic, region: RegionLogic, tool: ToolLogic,
skill: SkillLogic, mine: MineLogic):
self.player = player
self.movement_buff_option = movement_buff_option
self.luck_buff_option = luck_buff_option
self.received = received
self.region = region
self.tool = tool
self.skill = skill
self.mine = mine

def set_magic(self, magic: MagicLogic, mod_skill: ModSkillLogic):
self.magic = magic
self.mod_skill = mod_skill

class AbilityLogic(BaseLogic[Union[AbilityLogicMixin, RegionLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, MineLogicMixin, MagicLogicMixin]]):
def can_mine_perfectly(self) -> StardewRule:
return self.mine.can_progress_in_the_mines_from_floor(160)
return self.logic.mine.can_progress_in_the_mines_from_floor(160)

def can_mine_perfectly_in_the_skull_cavern(self) -> StardewRule:
return (self.can_mine_perfectly() &
self.region.can_reach(Region.skull_cavern))
return (self.logic.ability.can_mine_perfectly() &
self.logic.region.can_reach(Region.skull_cavern))

def can_farm_perfectly(self) -> StardewRule:
tool_rule = self.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.tool.can_water(4)
return tool_rule & self.skill.has_farming_level(10)
tool_rule = self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.logic.tool.can_water(4)
return tool_rule & self.logic.skill.has_farming_level(10)

def can_fish_perfectly(self) -> StardewRule:
skill_rule = self.skill.has_level(Skill.fishing, 10)
return skill_rule & self.tool.has_fishing_rod(4)
skill_rule = self.logic.skill.has_level(Skill.fishing, 10)
return skill_rule & self.logic.tool.has_fishing_rod(4)

def can_chop_trees(self) -> StardewRule:
return self.tool.has_tool(Tool.axe) & self.region.can_reach(Region.forest)
return self.logic.tool.has_tool(Tool.axe) & self.logic.region.can_reach(Region.forest)

def can_chop_perfectly(self) -> StardewRule:
magic_rule = (self.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.mod_skill.has_mod_level(ModSkill.magic, 10)
tool_rule = self.tool.has_tool(Tool.axe, ToolMaterial.iridium)
foraging_rule = self.skill.has_level(Skill.foraging, 10)
region_rule = self.region.can_reach(Region.forest)
magic_rule = (self.logic.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.logic.mod.skill.has_mod_level(ModSkill.magic, 10)
tool_rule = self.logic.tool.has_tool(Tool.axe, ToolMaterial.iridium)
foraging_rule = self.logic.skill.has_level(Skill.foraging, 10)
region_rule = self.logic.region.can_reach(Region.forest)
return region_rule & ((tool_rule & foraging_rule) | magic_rule)

def has_max_buffs(self) -> StardewRule:
return self.received(Buff.movement, self.movement_buff_option.value) & self.received(Buff.luck, self.luck_buff_option.value)
return self.logic.received(Buff.movement, self.options.movement_buff_number.value) & self.logic.received(Buff.luck, self.options.luck_buff_number.value)
38 changes: 18 additions & 20 deletions worlds/stardew_valley/logic/action_logic.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
from typing import Union

from Utils import cache_self1
from .cached_logic import CachedLogic
from .has_logic import HasLogic, CachedRules
from .received_logic import ReceivedLogic
from .region_logic import RegionLogic
from .base_logic import BaseLogic, BaseLogicMixin
from .has_logic import HasLogicMixin
from .received_logic import ReceivedLogicMixin
from .region_logic import RegionLogicMixin
from ..stardew_rule import StardewRule, True_, Or
from ..strings.generic_names import Generic
from ..strings.geode_names import Geode
from ..strings.region_names import Region


class ActionLogic(CachedLogic):
received: ReceivedLogic
has: HasLogic
region: RegionLogic
class ActionLogicMixin(BaseLogicMixin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.action = ActionLogic(*args, **kwargs)


def __init__(self, player: int, cached_rules: CachedRules, received: ReceivedLogic, has: HasLogic,
region: RegionLogic):
super().__init__(player, cached_rules)
self.received = received
self.has = has
self.region = region
class ActionLogic(BaseLogic[Union[ActionLogicMixin, RegionLogicMixin, ReceivedLogicMixin, HasLogicMixin]]):

def can_watch(self, channel: str = None):
tv_rule = True_()
if channel is None:
return tv_rule
return self.received(channel) & tv_rule
return self.logic.received(channel) & tv_rule

def can_pan(self) -> StardewRule:
return self.received("Glittering Boulder Removed") & self.region.can_reach(Region.mountain)
return self.logic.received("Glittering Boulder Removed") & self.logic.region.can_reach(Region.mountain)

def can_pan_at(self, region: str) -> StardewRule:
return self.region.can_reach(region) & self.can_pan()
return self.logic.region.can_reach(region) & self.logic.action.can_pan()

@cache_self1
def can_open_geode(self, geode: str) -> StardewRule:
blacksmith_access = self.region.can_reach(Region.blacksmith)
blacksmith_access = self.logic.region.can_reach(Region.blacksmith)
geodes = [Geode.geode, Geode.frozen, Geode.magma, Geode.omni]
if geode == Generic.any:
return blacksmith_access & Or(*(self.has(geode_type) for geode_type in geodes))
return blacksmith_access & self.has(geode)
return blacksmith_access & Or(*(self.logic.has(geode_type) for geode_type in geodes))
return blacksmith_access & self.logic.has(geode)
38 changes: 18 additions & 20 deletions worlds/stardew_valley/logic/arcade_logic.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
from .received_logic import ReceivedLogic
from .region_logic import RegionLogic
from typing import Union

from .base_logic import BaseLogic, BaseLogicMixin
from .received_logic import ReceivedLogicMixin
from .region_logic import RegionLogicMixin
from .. import options
from ..options import ArcadeMachineLocations
from ..stardew_rule import StardewRule, True_
from ..strings.region_names import Region


class ArcadeLogic:
player: int
arcade_option: ArcadeMachineLocations
received = ReceivedLogic
region: RegionLogic
class ArcadeLogicMixin(BaseLogicMixin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.arcade = ArcadeLogic(*args, **kwargs)


def __init__(self, player: int, arcade_option: ArcadeMachineLocations, received: ReceivedLogic, region: RegionLogic):
self.player = player
self.arcade_option = arcade_option
self.received = received
self.region = region
class ArcadeLogic(BaseLogic[Union[ArcadeLogicMixin, RegionLogicMixin, ReceivedLogicMixin]]):

def has_jotpk_power_level(self, power_level: int) -> StardewRule:
if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling:
if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling:
return True_()
jotpk_buffs = ("JotPK: Progressive Boots", "JotPK: Progressive Gun", "JotPK: Progressive Ammo", "JotPK: Extra Life", "JotPK: Increased Drop Rate")
return self.received(jotpk_buffs, power_level)
return self.logic.received(jotpk_buffs, power_level)

def has_junimo_kart_power_level(self, power_level: int) -> StardewRule:
if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling:
if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling:
return True_()
return self.received("Junimo Kart: Extra Life", power_level)
return self.logic.received("Junimo Kart: Extra Life", power_level)

def has_junimo_kart_max_level(self) -> StardewRule:
play_rule = self.region.can_reach(Region.junimo_kart_3)
if self.arcade_option != options.ArcadeMachineLocations.option_full_shuffling:
play_rule = self.logic.region.can_reach(Region.junimo_kart_3)
if self.options.arcade_machine_locations != options.ArcadeMachineLocations.option_full_shuffling:
return play_rule
return self.has_junimo_kart_power_level(8)
return self.logic.arcade.has_junimo_kart_power_level(8)
46 changes: 22 additions & 24 deletions worlds/stardew_valley/logic/artisan_logic.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,53 @@
from typing import Union

from .cached_logic import profile_rule
from .has_logic import HasLogic
from .time_logic import TimeLogic
from .base_logic import BaseLogic, BaseLogicMixin
from .has_logic import HasLogicMixin
from .time_logic import TimeLogicMixin
from ..stardew_rule import StardewRule
from ..strings.crop_names import all_vegetables, all_fruits, Vegetable, Fruit
from ..strings.generic_names import Generic
from ..strings.machine_names import Machine


class ArtisanLogic:
player: int
has: HasLogic
time: TimeLogic
class ArtisanLogicMixin(BaseLogicMixin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.artisan = ArtisanLogic(*args, **kwargs)

def __init__(self, player: int, has: HasLogic, time: TimeLogic):
self.player = player
self.has = has
self.time = time

class ArtisanLogic(BaseLogic[Union[ArtisanLogicMixin, TimeLogicMixin, HasLogicMixin]]):

def has_jelly(self) -> StardewRule:
return self.can_preserves_jar(Fruit.any)
return self.logic.artisan.can_preserves_jar(Fruit.any)

def has_pickle(self) -> StardewRule:
return self.can_preserves_jar(Vegetable.any)
return self.logic.artisan.can_preserves_jar(Vegetable.any)

def can_preserves_jar(self, item: str) -> StardewRule:
machine_rule = self.has(Machine.preserves_jar)
machine_rule = self.logic.has(Machine.preserves_jar)
if item == Generic.any:
return machine_rule
if item == Fruit.any:
return machine_rule & self.has(all_fruits, 1)
return machine_rule & self.logic.has(all_fruits, 1)
if item == Vegetable.any:
return machine_rule & self.has(all_vegetables, 1)
return machine_rule & self.has(item)
return machine_rule & self.logic.has(all_vegetables, 1)
return machine_rule & self.logic.has(item)

def has_wine(self) -> StardewRule:
return self.can_keg(Fruit.any)
return self.logic.artisan.can_keg(Fruit.any)

def has_juice(self) -> StardewRule:
return self.can_keg(Vegetable.any)
return self.logic.artisan.can_keg(Vegetable.any)

def can_keg(self, item: str) -> StardewRule:
machine_rule = self.has(Machine.keg)
machine_rule = self.logic.has(Machine.keg)
if item == Generic.any:
return machine_rule
if item == Fruit.any:
return machine_rule & self.has(all_fruits, 1)
return machine_rule & self.logic.has(all_fruits, 1)
if item == Vegetable.any:
return machine_rule & self.has(all_vegetables, 1)
return machine_rule & self.has(item)
return machine_rule & self.logic.has(all_vegetables, 1)
return machine_rule & self.logic.has(item)

def can_mayonnaise(self, item: str) -> StardewRule:
return self.has(Machine.mayonnaise_machine) & self.has(item)
return self.logic.has(Machine.mayonnaise_machine) & self.logic.has(item)
Loading

0 comments on commit 4dd49a3

Please sign in to comment.