Skip to content

Commit

Permalink
Merge pull request #30 from Frank-Pasqualini/animal-well
Browse files Browse the repository at this point in the history
More client changes for making things work better
  • Loading branch information
ScipioWright authored Jun 1, 2024
2 parents 7020f0f + 07dcc88 commit 10297c3
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 66 deletions.
155 changes: 101 additions & 54 deletions worlds/animal_well/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def __init__(self, server_address, password):
self.process_handle = None
self.start_address = None
self.connection_status = CONNECTION_INITIAL_STATUS
self.slot_data = {}
self.first_m_disc = True
self.used_firecrackers = 0
self.used_berries = 0
Expand Down Expand Up @@ -156,6 +157,10 @@ class AnimalWellManager(GameManager):
self.ui = AnimalWellManager(self)
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")

def on_package(self, cmd: str, args: dict):
if cmd == 'Connected':
self.slot_data = args.get("slot_data", {})

def get_active_game_slot(self) -> int:
"""
Get the game slot currently being played
Expand Down Expand Up @@ -213,7 +218,7 @@ def __init__(self):

self.medal_e = False
self.medal_s = False
self.medal_k = False # TODO K shard logic
# self.medal_k = False

# event only for now until modding tools maybe
self.flame_blue = False
Expand Down Expand Up @@ -328,9 +333,7 @@ def __init__(self):
self.candle_bear = False

# extras
# self.mama_cha = False
# self.squirrel_acorn = false
# kangaroo medal drops
self.mama_cha = False

def read_from_game(self, ctx):
"""
Expand All @@ -355,7 +358,7 @@ def read_from_game(self, ctx):

self.egg_vanity = bool(flags >> 8 & 1)
self.egg_service = bool(flags >> 9 & 1)
# self.mama_cha = bool(flags >> 10 & 1)
self.mama_cha = bool(flags >> 10 & 1)
self.match_dog_switch_bounce = bool(flags >> 11 & 1)
self.egg_depraved = bool(flags >> 12 & 1)
self.match_bear = bool(flags >> 13 & 1)
Expand Down Expand Up @@ -459,42 +462,44 @@ def read_from_game(self, ctx):
self.fanny_pack_chest = bool(flags >> 100 & 1)

# Read Flames
# self.flame_blue = ctx.process_handle.read_bytes(slot_address + 0x21E, 1)[0] >= 4
# self.flame_pink = ctx.process_handle.read_bytes(slot_address + 0x21F, 1)[0] >= 4
# self.flame_violet = ctx.process_handle.read_bytes(slot_address + 0x220, 1)[0] >= 4
# self.flame_green = ctx.process_handle.read_bytes(slot_address + 0x221, 1)[0] >= 4
self.flame_blue = ctx.process_handle.read_bytes(slot_address + 0x21E, 1)[0] >= 4
self.flame_pink = ctx.process_handle.read_bytes(slot_address + 0x21F, 1)[0] >= 4
self.flame_violet = ctx.process_handle.read_bytes(slot_address + 0x220, 1)[0] >= 4
self.flame_green = ctx.process_handle.read_bytes(slot_address + 0x221, 1)[0] >= 4

# Read Bunnies
# flags = int.from_bytes(ctx.process_handle.read_bytes(slot_address + 0x198, 4), byteorder="little")
#
# self.bunny_water_spike = bool(flags >> 0 & 1)
# self.bunny_barcode = bool(flags >> 2 & 1)
# self.bunny_crow = bool(flags >> 3 & 1)
# self.bunny_face = bool(flags >> 4 & 1)
# self.bunny_fish = bool(flags >> 6 & 1)
# self.bunny_map = bool(flags >> 7 & 1)
# self.bunny_tv = bool(flags >> 8 & 1)
# self.bunny_uv = bool(flags >> 9 & 1)
# self.bunny_file_bud = bool(flags >> 10 & 1)
# self.bunny_chinchilla_vine = bool(flags >> 11 & 1)
# self.bunny_mural = bool(flags >> 15 & 1)
# self.bunny_duck = bool(flags >> 22 & 1)
# self.bunny_ghost_dog = bool(flags >> 25 & 1)
# self.bunny_dream = bool(flags >> 28 & 1)
# self.bunny_lava = bool(flags >> 30 & 1)
# self.bunny_disc_spike = bool(flags >> 31 & 1)
flags = int.from_bytes(ctx.process_handle.read_bytes(slot_address + 0x198, 4), byteorder="little")
self.bunny_water_spike = bool(flags >> 0 & 1)
self.bunny_barcode = bool(flags >> 2 & 1)
self.bunny_crow = bool(flags >> 3 & 1)
self.bunny_face = bool(flags >> 4 & 1)
self.bunny_fish = bool(flags >> 6 & 1)
self.bunny_map = bool(flags >> 7 & 1)

self.bunny_tv = bool(flags >> 8 & 1)
self.bunny_uv = bool(flags >> 9 & 1)
self.bunny_file_bud = bool(flags >> 10 & 1)
self.bunny_chinchilla_vine = bool(flags >> 11 & 1)
self.bunny_mural = bool(flags >> 15 & 1)

self.bunny_duck = bool(flags >> 22 & 1)
self.bunny_ghost_dog = bool(flags >> 25 & 1)
self.bunny_dream = bool(flags >> 28 & 1)
self.bunny_lava = bool(flags >> 30 & 1)
self.bunny_disc_spike = bool(flags >> 31 & 1)

# Read Candles (I am not very confident in these at all)
# flags = int.from_bytes(ctx.process_handle.read_bytes(slot_address + 0x1E0, 2), byteorder="little")
# self.candle_dog_disc_switches = bool(flags >> 0 & 1)
# self.candle_dog_bat = bool(flags >> 1 & 1)
# self.candle_dog_switch_box = bool(flags >> 2 & 1)
# self.candle_dog_many_switches = bool(flags >> 3 & 1)
# self.candle_dog_dark = bool(flags >> 4 & 1)
# self.candle_bear = bool(flags >> 5 & 1)
# self.candle_first = bool(flags >> 6 & 1)
# self.candle_frog = bool(flags >> 7 & 1)
# self.candle_fish = bool(flags >> 8 & 1)
flags = int.from_bytes(ctx.process_handle.read_bytes(slot_address + 0x1E0, 2), byteorder="little")
self.candle_dog_disc_switches = bool(flags >> 0 & 1)
self.candle_dog_bat = bool(flags >> 1 & 1)
self.candle_dog_switch_box = bool(flags >> 2 & 1)
self.candle_dog_many_switches = bool(flags >> 3 & 1)
self.candle_dog_dark = bool(flags >> 4 & 1)
self.candle_bear = bool(flags >> 5 & 1)
self.candle_first = bool(flags >> 6 & 1)
self.candle_frog = bool(flags >> 7 & 1)

self.candle_fish = bool(flags >> 8 & 1)

# Read Startup State
flags = int.from_bytes(ctx.process_handle.read_bytes(slot_address + 0x21C, 2), byteorder="little")
Expand Down Expand Up @@ -598,8 +603,8 @@ async def write_to_archipelago(self, ctx):
ctx.locations_checked.add(location_name_to_id[lname.medal_e.value])
if self.medal_s:
ctx.locations_checked.add(location_name_to_id[lname.medal_s.value])
if self.medal_k:
ctx.locations_checked.add(location_name_to_id[lname.medal_k.value])
# if self.medal_k:
# ctx.locations_checked.add(location_name_to_id[lname.medal_k.value])

# event only for now until modding tools maybe
if self.flame_blue:
Expand Down Expand Up @@ -745,8 +750,9 @@ async def write_to_archipelago(self, ctx):
if self.egg_golden:
ctx.locations_checked.add(location_name_to_id[lname.egg_golden.value])

if self.egg_65:
ctx.locations_checked.add(location_name_to_id[lname.egg_65.value])
if "final_egg_location" not in ctx.slot_data or ctx.slot_data["final_egg_location"] == 1:
if self.egg_65:
ctx.locations_checked.add(location_name_to_id[lname.egg_65.value])

# map things
if self.map_chest:
Expand Down Expand Up @@ -811,16 +817,13 @@ async def write_to_archipelago(self, ctx):
ctx.locations_checked.add(location_name_to_id[lname.candle_bear.value])

# extras
# if self.mama_cha:
# ctx.locations_checked.add(location_name_to_id[lname.mama_cha.value])
# if self.squirrel_acorn:
# ctx.locations_checked.add(location_name_to_id[lname.squirrel_acorn.value])
# kangaroo medal drops
if self.mama_cha:
ctx.locations_checked.add(location_name_to_id[lname.mama_cha.value])

# TODO other victory conditions
if not ctx.finished_game and self.key_house:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
ctx.finished_game = True
if "goal" not in ctx.slot_data or ctx.slot_data["goal"] == 1:
if not ctx.finished_game and self.key_house:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
ctx.finished_game = True

locations_checked = []
for location in ctx.missing_locations:
Expand Down Expand Up @@ -871,7 +874,7 @@ def __init__(self):

self.e_medal = False
self.s_medal = False
self.k_shard = 0 # TODO K shard logic
self.k_shard = 0

# self.blue_flame = False
# self.green_flame = False
Expand Down Expand Up @@ -953,7 +956,7 @@ def __init__(self):
self.firecracker_refill = 0
self.big_blue_fruit = 0

def read_from_archipelago(self, ctx):
async def read_from_archipelago(self, ctx):
"""
Read inventory state from archipelago
"""
Expand Down Expand Up @@ -1065,6 +1068,27 @@ def read_from_archipelago(self, ctx):
self.egg_crystal = item_name_to_id[iname.egg_crystal.value] in items
self.egg_golden = item_name_to_id[iname.egg_golden.value] in items

if "goal" in ctx.slot_data and ctx.slot_data["goal"] == 3:
if (not ctx.finished_game and
self.egg_reference and self.egg_brown and self.egg_raw and self.egg_pickled and
self.egg_big and self.egg_swan and self.egg_forbidden and self.egg_shadow and
self.egg_vanity and self.egg_service and self.egg_depraved and self.egg_chaos and
self.egg_upside_down and self.egg_evil and self.egg_sweet and self.egg_chocolate and
self.egg_value and self.egg_plant and self.egg_red and self.egg_orange and
self.egg_sour and self.egg_post_modern and self.egg_universal and self.egg_lf and
self.egg_zen and self.egg_future and self.egg_friendship and self.egg_truth and
self.egg_transcendental and self.egg_ancient and self.egg_magic and self.egg_mystic and
self.egg_holiday and self.egg_rain and self.egg_razzle and self.egg_dazzle and
self.egg_virtual and self.egg_normal and self.egg_great and self.egg_gorgeous and
self.egg_planet and self.egg_moon and self.egg_galaxy and self.egg_sunset and
self.egg_goodnight and self.egg_dream and self.egg_travel and self.egg_promise and
self.egg_ice and self.egg_fire and self.egg_bubble and self.egg_desert and
self.egg_clover and self.egg_brick and self.egg_neon and self.egg_iridescent and
self.egg_rust and self.egg_scarlet and self.egg_sapphire and self.egg_ruby and
self.egg_jade and self.egg_obsidian and self.egg_crystal and self.egg_golden):
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
ctx.finished_game = True

self.egg_65 = item_name_to_id[iname.egg_65.value] in items

self.firecracker_refill = len([item for item in items if item == item_name_to_id["Firecracker Refill"]])
Expand Down Expand Up @@ -1092,6 +1116,10 @@ def write_to_game(self, ctx):
if self.bubble < 0 or self.bubble > 2:
raise AssertionError("Invalid number of bubble wand upgrades %d", self.bubble)

egg_65 = self.egg_65
if "final_egg_location" not in ctx.slot_data or ctx.slot_data["final_egg_location"] == 1:
egg_65 = bool(flags >> 20 & 1)

bits = ((str(flags >> 0 & 1)) + # House Opened
(str(flags >> 1 & 1)) + # Office Opened
(str(flags >> 2 & 1)) + # Closet Opened
Expand All @@ -1112,7 +1140,7 @@ def write_to_game(self, ctx):
(str(flags >> 17 & 1)) + # Wings Acquired
(str(flags >> 18 & 1)) + # Woke Up
("1" if self.bubble == 2 else "0") + # B.B. Wand Upgrade
("1" if self.egg_65 else "0") + # Egg 65 Collected
("1" if egg_65 else "0") + # Egg 65 Collected
(str(flags >> 21 & 1)) + # All Candles Lit
(str(flags >> 22 & 1)) + # Singularity Active
(str(flags >> 23 & 1)) + # Manticore Egg Placed
Expand Down Expand Up @@ -1282,6 +1310,25 @@ def write_to_game(self, ctx):
buffer = int(bits, 2).to_bytes((len(bits) + 7) // 8, byteorder="little")
ctx.process_handle.write_bytes(slot_address + 0x1DE, buffer, 1)

# Read K Shards
if self.k_shard < 0 or self.k_shard > 3:
raise AssertionError("Invalid number of k shards %d", self.k_shard)

k_shard_1 = bytes([0])
if self.k_shard >= 1:
k_shard_1 = bytes([max(2, ctx.process_handle.read_bytes(slot_address + 0x1FE, 1)[0])])
k_shard_2 = bytes([0])
if self.k_shard >= 2:
k_shard_2 = bytes([max(2, ctx.process_handle.read_bytes(slot_address + 0x20A, 1)[0])])
k_shard_3 = bytes([0])
if self.k_shard == 3:
k_shard_3 = bytes([max(2, ctx.process_handle.read_bytes(slot_address + 0x216, 1)[0])])

# Write K Shards
ctx.process_handle.write_bytes(slot_address + 0x1FE, k_shard_1, 1)
ctx.process_handle.write_bytes(slot_address + 0x20A, k_shard_2, 1)
ctx.process_handle.write_bytes(slot_address + 0x216, k_shard_3, 1)

# Berries
berries_to_use = self.big_blue_fruit - ctx.used_berries
total_hearts = int.from_bytes(ctx.process_handle.read_bytes(slot_address + 0x1B4, 1),
Expand Down Expand Up @@ -1466,7 +1513,7 @@ async def process_sync_task(ctx: AnimalWellContext):

locations.read_from_game(ctx)
await locations.write_to_archipelago(ctx)
items.read_from_archipelago(ctx)
await items.read_from_archipelago(ctx)
items.write_to_game(ctx)
await asyncio.sleep(0.1)

Expand Down
6 changes: 2 additions & 4 deletions worlds/animal_well/locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class AWLocationData(NamedTuple):

lname.medal_e.value: AWLocationData(31, ["Keys", "Medals"]),
lname.medal_s.value: AWLocationData(32, ["Keys", "Medals"]),
lname.medal_k.value: AWLocationData(33, ["Keys", "Medals"]),
# lname.medal_k.value: AWLocationData(33, ["Keys", "Medals"]),

# event only for now until modding tools maybe
lname.flame_blue.value: AWLocationData(34, ["Flames"]),
Expand Down Expand Up @@ -163,9 +163,7 @@ class AWLocationData(NamedTuple):
lname.candle_bear.value: AWLocationData(130, ["Candles"]),

# extras
# lname.mama_cha.value: AWLocationData(),
# lname.squirrel_acorn.value: AWLocationData(),
# kangaroo medal drops
lname.mama_cha.value: AWLocationData(131, ["Extras"]),
}

location_name_to_id: Dict[str, int] = {name: location_base_id + index for index, name in enumerate(location_table)}
Expand Down
3 changes: 1 addition & 2 deletions worlds/animal_well/names.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,12 @@ def __str__(self) -> str:
fanny_pack_chest = "Fanny Pack Chest"
key_house = "House Key Drop"
key_office = "Office Key Chest"
medal_k = "K. Medal Shard Bag" # you need three to open the kangaroo door
# medal_k = "K. Medal Shard Bag" # you need three to open the kangaroo door
medal_s = "S. Medal Chest"
medal_e = "E. Medal Chest"

# minor unique items
mama_cha = "Mama Cha Chest" # the same place as the barcode bunny at grass bowl
squirrel_acorn = "Steal Squirrel's Acorn"

# match chests
match_start_ceiling = "Match in Tutorial Chest"
Expand Down
8 changes: 4 additions & 4 deletions worlds/animal_well/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Goal(Choice):
display_name = "Goal"
option_fireworks = 1
# option_bunny_land = 2
# option_egg_hunt = 3
option_egg_hunt = 3
default = 1


Expand Down Expand Up @@ -49,8 +49,8 @@ class BunniesAsChecks(Choice):
internal_name = "bunnies_as_checks"
display_name = "Bunnies as Checks"
option_off = 0
# option_exclude_tedious = 1 # figure out which are tedious
# option_all_bunnies = 2
option_exclude_tedious = 1 # figure out which are tedious
option_all_bunnies = 2
default = 0


Expand All @@ -61,7 +61,7 @@ class CandleChecks(Choice): # choice so we can comment out non-working ones the
internal_name = "candle_checks"
display_name = "Candle Checks"
option_off = 0
# option_on = 1
option_on = 1
default = 0


Expand Down
4 changes: 2 additions & 2 deletions worlds/animal_well/region_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,8 @@ class AWData(NamedTuple):
AWData(AWType.region, [[iname.can_distract_dogs]]), # need to get past the 3 dogs
# rname.barcode_bunny: # region since you can get this in two spots
# AWData(AWType.region, [[iname.flute, iname.song_barcode]]),
# lname.mama_cha: # removing for now, may shuffle later
# AWData(AWType.location, [[iname.flute]]), # add song req if we're shuffling songs
lname.mama_cha: # removing for now, may shuffle later
AWData(AWType.location, [[iname.flute]]), # add song req if we're shuffling songs
lname.bunny_lava:
AWData(AWType.location, [[iname.bubble_long, iname.remote]], loc_type="bunny"),
rname.dog_many_switches:
Expand Down

0 comments on commit 10297c3

Please sign in to comment.