2025-09-04 23:48:53 -04:00
import time
2025-08-04 23:03:31 -04:00
from typing import TYPE_CHECKING
2025-08-26 21:28:02 -04:00
import asyncio
2025-08-16 02:24:19 -04:00
import NetUtils
2025-08-30 17:26:06 -04:00
import copy
2025-09-09 00:04:09 -04:00
import Utils
2025-08-17 21:22:12 -04:00
from . Locations import grinch_locations , GrinchLocation
2025-08-31 13:59:20 -04:00
from . Items import ALL_ITEMS_TABLE , MISSION_ITEMS_TABLE , GADGETS_TABLE , KEYS_TABLE , GrinchItemData #, SLEIGH_PARTS_TABLE
2025-08-04 23:03:31 -04:00
import worlds . _bizhawk as bizhawk
from worlds . _bizhawk . client import BizHawkClient
2025-08-14 00:23:40 -04:00
2025-08-04 23:03:31 -04:00
if TYPE_CHECKING :
from worlds . _bizhawk . context import BizHawkClientContext
2025-08-06 23:34:52 -04:00
from CommonClient import logger
2025-08-04 23:03:31 -04:00
2025-08-30 16:33:21 -04:00
2025-08-19 01:59:18 -04:00
# Stores received index of last item received in PS1 memory card save data
# By storing this index, it will remember the last item received and prevent item duplication loops
2025-08-30 09:09:35 -04:00
RECV_ITEM_ADDR = 0x010068
2025-08-19 01:59:18 -04:00
RECV_ITEM_BITSIZE = 4
2025-08-04 23:03:31 -04:00
2025-08-26 21:28:02 -04:00
# Maximum number of times we check if we are in demo mode or not
MAX_DEMO_MODE_CHECK = 30
2025-08-30 16:33:21 -04:00
# List of Menu Map IDs
MENU_MAP_IDS : list [ int ] = [ 0x00 , 0x02 , 0x35 , 0x36 , 0x37 ]
2025-09-09 00:04:09 -04:00
MAX_EGGS : int = 200
EGG_COUNT_ADDR : int = 0x010058
EGG_ADDR_BYTESIZE : int = 2
2025-08-04 23:03:31 -04:00
class GrinchClient ( BizHawkClient ) :
game = " The Grinch "
system = " PSX "
patch_suffix = " .apgrinch "
2025-08-06 23:34:52 -04:00
items_handling = 0b111
2025-08-26 21:28:02 -04:00
demo_mode_buffer = 0
last_map_location = - 1
ingame_log = False
2025-09-09 00:04:09 -04:00
previous_egg_count : int = 0
2025-08-06 23:34:52 -04:00
def __init__ ( self ) :
super ( ) . __init__ ( )
2025-08-14 00:23:40 -04:00
self . last_received_index = 0
self . loading_bios_msg = False
self . loc_unlimited_eggs = False
2025-08-04 23:03:31 -04:00
async def validate_rom ( self , ctx : " BizHawkClientContext " ) - > bool :
2025-08-07 00:38:42 -04:00
from CommonClient import logger
# TODO Check the ROM data to see if it matches against bytes expected
2025-08-04 23:03:31 -04:00
grinch_identifier_ram_address : int = 0x00928C
2025-08-14 00:23:40 -04:00
bios_identifier_ram_address : int = 0x097F30
2025-08-04 23:03:31 -04:00
try :
bytes_actual : bytes = ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
2025-08-06 23:34:52 -04:00
grinch_identifier_ram_address , 11 , " MainRAM " ) ] ) ) [ 0 ]
psx_rom_name = bytes_actual . decode ( " ascii " )
if psx_rom_name != " SLUS_011.97 " :
2025-08-14 00:23:40 -04:00
bios_bytes_check : bytes = ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
bios_identifier_ram_address , 24 , " MainRAM " ) ] ) ) [ 0 ]
if " System ROM Version " in bios_bytes_check . decode ( " ascii " ) :
if not self . loading_bios_msg :
self . loading_bios_msg = True
logger . error ( " BIOS is currently loading. Will wait up to 5 seconds before retrying. " )
return False
2025-08-07 00:38:42 -04:00
logger . error ( " Invalid rom detected. You are not playing Grinch USA Version. " )
2025-08-06 23:34:52 -04:00
raise Exception ( " Invalid rom detected. You are not playing Grinch USA Version. " )
2025-08-14 00:23:40 -04:00
except Exception :
2025-08-06 23:34:52 -04:00
return False
ctx . game = self . game
ctx . items_handling = self . items_handling
ctx . want_slot_data = True
2025-08-30 16:33:21 -04:00
ctx . watcher_timeout = 0.25
2025-08-14 00:23:40 -04:00
self . loading_bios_msg = False
2025-08-06 23:34:52 -04:00
return True
2025-09-09 01:29:32 -04:00
def on_package ( self , ctx : " BizHawkClientContext " , cmd : str , args : dict ) - > None :
2025-08-31 13:45:51 -04:00
from CommonClient import logger
2025-08-19 01:59:18 -04:00
super ( ) . on_package ( ctx , cmd , args )
match cmd :
case " Connected " : # On Connect
self . loc_unlimited_eggs = bool ( ctx . slot_data [ " give_unlimited_eggs " ] )
2025-08-31 13:47:30 -04:00
logger . info ( " You are now connected to the client. " +
" There may be a slight delay to check you are not in demo mode before locations start to send. " )
2025-09-09 00:04:09 -04:00
ring_link_enabled = bool ( ctx . slot_data [ " ring_link " ] )
tags = copy . deepcopy ( ctx . tags )
if ring_link_enabled :
Utils . async_start ( self . ring_link_output ( ctx ) , name = " EggLink " )
ctx . tags . add ( " RingLink " )
else :
ctx . tags - = { " RingLink " }
if tags != ctx . tags :
2025-09-09 01:29:32 -04:00
Utils . async_start ( ctx . send_msgs ( [ { " cmd " : " ConnectUpdate " , " tags " : ctx . tags } ] ) , " Update RingLink Tags " )
2025-09-09 00:04:09 -04:00
case " Bounced " :
if " tags " not in args :
return
if " RingLink " in ctx . tags and " RingLink " in args [ " tags " ] and args [ " data " ] [ " source " ] != ctx . player_names [ ctx . slot ] :
2025-09-09 01:29:32 -04:00
Utils . async_start ( self . ring_link_input ( args [ " data " ] [ " amount " ] , ctx ) , " SyncEggs " )
2025-08-14 00:23:40 -04:00
2025-08-06 23:34:52 -04:00
async def set_auth ( self , ctx : " BizHawkClientContext " ) - > None :
await ctx . get_username ( )
2025-08-04 23:03:31 -04:00
async def game_watcher ( self , ctx : " BizHawkClientContext " ) - > None :
2025-08-30 16:33:21 -04:00
from CommonClient import logger
2025-08-06 23:34:52 -04:00
#If the player is not connected to an AP Server, or their connection was disconnected.
2025-09-06 20:05:36 -04:00
if not ctx . slot :
2025-08-06 23:34:52 -04:00
return
2025-08-04 23:03:31 -04:00
try :
2025-08-19 01:59:18 -04:00
if not await self . ingame_checker ( ctx ) :
2025-08-14 00:23:40 -04:00
return
2025-08-26 21:28:02 -04:00
2025-08-06 23:34:52 -04:00
await self . location_checker ( ctx )
2025-08-07 00:38:42 -04:00
await self . receiving_items_handler ( ctx )
2025-08-16 02:24:19 -04:00
await self . goal_checker ( ctx )
2025-08-19 01:59:18 -04:00
await self . option_handler ( ctx )
2025-08-30 19:59:56 -04:00
await self . constant_address_update ( ctx )
2025-08-04 23:03:31 -04:00
2025-08-30 16:33:21 -04:00
except bizhawk . RequestFailedError as ex :
2025-08-04 23:03:31 -04:00
# The connector didn't respond. Exit handler and return to main loop to reconnect
2025-08-30 16:33:21 -04:00
logger . error ( " Failure to connect / authenticate the grinch. Error details: " + str ( ex ) )
2025-08-06 23:34:52 -04:00
pass
2025-09-06 19:37:46 -04:00
except Exception as genericEx :
2025-09-06 19:43:57 -04:00
# For all other errors, catch this and let the client gracefully disconnect
2025-09-06 19:37:46 -04:00
logger . error ( " Unknown error occurred while playing the grinch. Error details: " + str ( genericEx ) )
await ctx . disconnect ( False )
pass
2025-08-06 23:34:52 -04:00
async def location_checker ( self , ctx : " BizHawkClientContext " ) :
2025-08-30 17:26:06 -04:00
from CommonClient import logger
2025-08-06 23:34:52 -04:00
# Update the AP Server to know what locations are not checked yet.
2025-08-14 00:23:40 -04:00
local_locations_checked : list [ int ] = [ ]
2025-08-30 17:26:06 -04:00
local_ap_locations : set [ int ] = copy . deepcopy ( ctx . missing_locations )
for missing_location in local_ap_locations :
2025-08-17 21:22:12 -04:00
# local_location = ctx.location_names.lookup_in_game(missing_location)
2025-08-06 23:34:52 -04:00
# Missing location is the AP ID & we need to convert it back to a location name within our game.
# Using the location name, we can then get the Grinch ram data from there.
2025-08-30 17:26:06 -04:00
grinch_loc_name = ctx . location_names . lookup_in_game ( missing_location )
grinch_loc_ram_data = grinch_locations [ grinch_loc_name ]
2025-08-06 23:34:52 -04:00
# Grinch ram data may have more than one address to update, so we are going to loop through all addresses in a location
2025-08-25 17:03:48 -04:00
# We use a list here to keep track of all our checks. If they are all true, then and only then do we mark that location as checked.
ram_checked_list : list [ bool ] = [ ]
2025-08-06 23:34:52 -04:00
for addr_to_update in grinch_loc_ram_data . update_ram_addr :
is_binary = True if not addr_to_update . binary_bit_pos is None else False
current_ram_address_value = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
2025-08-07 00:38:42 -04:00
addr_to_update . ram_address , addr_to_update . bit_size , " MainRAM " ) ] ) ) [ 0 ] , " little " )
2025-08-06 23:34:52 -04:00
if is_binary :
2025-08-25 17:03:48 -04:00
ram_checked_list . append ( ( current_ram_address_value & ( 1 << addr_to_update . binary_bit_pos ) ) > 0 )
2025-08-06 23:34:52 -04:00
else :
expected_int_value = addr_to_update . value
2025-08-25 17:03:48 -04:00
ram_checked_list . append ( expected_int_value == current_ram_address_value )
2025-09-01 15:49:09 -04:00
if all ( ram_checked_list ) :
local_locations_checked . append ( GrinchLocation . get_apid ( grinch_loc_ram_data . id ) )
2025-08-06 23:34:52 -04:00
# Update the AP server with the locally checked list of locations (In other words, locations I found in Grinch)
2025-08-30 17:26:06 -04:00
locations_sent_to_ap : set [ int ] = await ctx . check_locations ( local_locations_checked )
if len ( locations_sent_to_ap ) > 0 :
2025-08-30 19:59:56 -04:00
await self . remove_physical_items ( ctx )
2025-08-14 00:23:40 -04:00
ctx . locations_checked = set ( local_locations_checked )
2025-08-06 23:34:52 -04:00
async def receiving_items_handler ( self , ctx : " BizHawkClientContext " ) :
2025-08-07 00:38:42 -04:00
# Len will give us the size of the items received list & we will track that against how many items we received already
# If the list says that we have 3 items and we already received items, we will ignore and continue.
# Otherwise, we will get the new items and give them to the player.
2025-08-19 01:59:18 -04:00
self . last_received_index = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
2025-08-30 16:33:21 -04:00
RECV_ITEM_ADDR , RECV_ITEM_BITSIZE , " MainRAM " ) ] ) ) [ 0 ] , " little " )
2025-08-07 00:38:42 -04:00
if len ( ctx . items_received ) == self . last_received_index :
return
# Ensures we only get the new items that we want to give the player
new_items_only = ctx . items_received [ self . last_received_index : ]
for item_received in new_items_only :
local_item = ctx . item_names . lookup_in_game ( item_received . item )
2025-08-06 23:34:52 -04:00
grinch_item_ram_data = ALL_ITEMS_TABLE [ local_item ]
for addr_to_update in grinch_item_ram_data . update_ram_addr :
2025-08-07 00:38:42 -04:00
is_binary = True if not addr_to_update . binary_bit_pos is None else False
2025-08-14 00:23:40 -04:00
current_ram_address_value = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
addr_to_update . ram_address , addr_to_update . bit_size , " MainRAM " ) ] ) ) [ 0 ] , " little " )
2025-08-07 00:38:42 -04:00
if is_binary :
current_ram_address_value = ( current_ram_address_value | ( 1 << addr_to_update . binary_bit_pos ) )
2025-08-14 00:23:40 -04:00
elif addr_to_update . update_existing_value :
2025-08-16 02:24:19 -04:00
# Grabs minimum value of a list of numbers and makes sure it does not go above max count possible
2025-08-17 21:22:12 -04:00
current_ram_address_value + = addr_to_update . value
current_ram_address_value = min ( current_ram_address_value , addr_to_update . max_count )
2025-08-07 00:38:42 -04:00
else :
current_ram_address_value = addr_to_update . value
# Write the updated value back into RAM
2025-08-17 21:22:12 -04:00
await self . update_and_validate_address ( ctx , addr_to_update . ram_address , current_ram_address_value , addr_to_update . bit_size )
2025-09-09 00:04:09 -04:00
2025-08-07 00:38:42 -04:00
2025-08-14 00:23:40 -04:00
self . last_received_index + = 1
2025-08-19 01:59:18 -04:00
await self . update_and_validate_address ( ctx , RECV_ITEM_ADDR , self . last_received_index , RECV_ITEM_BITSIZE )
2025-08-14 00:23:40 -04:00
2025-08-16 02:24:19 -04:00
async def goal_checker ( self , ctx : " BizHawkClientContext " ) :
if not ctx . finished_game :
goal_loc = grinch_locations [ " Neutralizing Santa " ]
goal_ram_address = goal_loc . update_ram_addr [ 0 ]
current_ram_address_value = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
goal_ram_address . ram_address , goal_ram_address . bit_size , " MainRAM " ) ] ) ) [ 0 ] , " little " )
if ( current_ram_address_value & ( 1 << goal_ram_address . binary_bit_pos ) ) > 0 :
ctx . finished_game = True
await ctx . send_msgs ( [ {
" cmd " : " StatusUpdate " ,
" status " : NetUtils . ClientStatus . CLIENT_GOAL ,
} ] )
2025-08-30 16:33:21 -04:00
# This function's entire purpose is to take away items we physically received ingame, but have not received from AP
2025-08-30 19:59:56 -04:00
async def remove_physical_items ( self , ctx : " BizHawkClientContext " ) :
2025-08-25 18:27:19 -04:00
list_recv_itemids : list [ int ] = [ netItem . item for netItem in ctx . items_received ]
2025-08-31 13:21:54 -04:00
items_to_check : dict [ str , GrinchItemData ] = { * * GADGETS_TABLE } #, **SLEIGH_PARTS_TABLE
2025-08-25 18:49:44 -04:00
heart_count = len ( list ( item_id for item_id in list_recv_itemids if item_id == 42570 ) )
heart_item_data = ALL_ITEMS_TABLE [ " Heart of Stone " ]
await self . update_and_validate_address ( ctx , heart_item_data . update_ram_addr [ 0 ] . ram_address , min ( heart_count , 4 ) , 1 )
2025-08-31 13:21:54 -04:00
# Setting Who Lake Mission Count back to 0 to prevent warping after completing 3 missions
2025-08-31 16:23:46 -04:00
await self . update_and_validate_address ( ctx , 0x0100F0 , 0 , 4 )
2025-08-31 13:21:54 -04:00
2025-08-25 18:27:19 -04:00
for ( item_name , item_data ) in items_to_check . items ( ) :
# If item is an event or already been received, ignore.
if item_data . id is None or GrinchLocation . get_apid ( item_data . id ) in list_recv_itemids :
continue
# This assumes we don't have the item so we must set all the data to 0
for addr_to_update in item_data . update_ram_addr :
is_binary = True if not addr_to_update . binary_bit_pos is None else False
if is_binary :
2025-08-30 19:59:56 -04:00
current_bin_value = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
addr_to_update . ram_address , addr_to_update . bit_size , " MainRAM " ) ] ) ) [ 0 ] , " little " )
current_bin_value & = ~ ( 1 << addr_to_update . binary_bit_pos )
await self . update_and_validate_address ( ctx , addr_to_update . ram_address , current_bin_value , 1 )
else :
await self . update_and_validate_address ( ctx , addr_to_update . ram_address , 0 , 1 )
# Removes the regional access until you actually received it from AP.
async def constant_address_update ( self , ctx : " BizHawkClientContext " ) :
list_recv_itemids : list [ int ] = [ netItem . item for netItem in ctx . items_received ]
2025-08-31 13:21:54 -04:00
items_to_check : dict [ str , GrinchItemData ] = { * * KEYS_TABLE , * * MISSION_ITEMS_TABLE }
2025-08-30 19:59:56 -04:00
for ( item_name , item_data ) in items_to_check . items ( ) :
# If item is an event or already been received, ignore.
2025-09-06 19:22:34 -04:00
if item_data . id is None : # or GrinchLocation.get_apid(item_data.id) in list_recv_itemids:
2025-08-30 19:59:56 -04:00
continue
2025-09-06 19:22:34 -04:00
# This will either constantly update the item to ensure you still have it or take it away if you don't deserve it
2025-08-30 19:59:56 -04:00
for addr_to_update in item_data . update_ram_addr :
is_binary = True if not addr_to_update . binary_bit_pos is None else False
if is_binary :
current_bin_value = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
addr_to_update . ram_address , addr_to_update . bit_size , " MainRAM " ) ] ) ) [ 0 ] , " little " )
2025-09-06 19:22:34 -04:00
if GrinchLocation . get_apid ( item_data . id ) in list_recv_itemids :
current_bin_value | = ( 1 << addr_to_update . binary_bit_pos )
else :
current_bin_value & = ~ ( 1 << addr_to_update . binary_bit_pos )
2025-08-30 19:59:56 -04:00
await self . update_and_validate_address ( ctx , addr_to_update . ram_address , current_bin_value , 1 )
2025-08-25 18:27:19 -04:00
else :
2025-09-06 19:22:34 -04:00
if GrinchLocation . get_apid ( item_data . id ) in list_recv_itemids :
await self . update_and_validate_address ( ctx , addr_to_update . ram_address , addr_to_update . value , 1 )
else :
await self . update_and_validate_address ( ctx , addr_to_update . ram_address , 0 , 1 )
2025-08-16 02:24:19 -04:00
2025-08-14 00:23:40 -04:00
async def ingame_checker ( self , ctx : " BizHawkClientContext " ) :
2025-08-30 16:33:21 -04:00
from CommonClient import logger
2025-08-26 21:28:02 -04:00
ingame_map_id = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
0x010000 , 1 , " MainRAM " ) ] ) ) [ 0 ] , " little " )
2025-08-14 00:23:40 -04:00
2025-08-30 16:33:21 -04:00
#If not in game or at a menu, or loading the publisher logos
2025-08-26 21:28:02 -04:00
if ingame_map_id < = 0x04 or ingame_map_id > = 0x35 :
2025-08-14 00:23:40 -04:00
return False
2025-08-26 21:28:02 -04:00
2025-08-30 16:33:21 -04:00
#If grinch has changed maps
if not ingame_map_id == self . last_map_location :
# If the last "map" we were on was a menu or a publisher logo
if self . last_map_location in MENU_MAP_IDS :
# Reset our demo mode checker just in case the game is in demo mode.
self . demo_mode_buffer = 0
self . ingame_log = False
return False
2025-08-31 13:45:51 -04:00
# Update the previous map we were on to be the current map.
2025-08-30 16:33:21 -04:00
self . last_map_location = ingame_map_id
# Use this as a delayed check to make sure we are in game
2025-08-26 21:28:02 -04:00
if not self . demo_mode_buffer == MAX_DEMO_MODE_CHECK :
await asyncio . sleep ( 0.1 )
self . demo_mode_buffer + = 1
return False
2025-08-30 16:33:21 -04:00
demo_mode = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ (
0x01008A , 1 , " MainRAM " ) ] ) ) [ 0 ] , " little " )
if demo_mode == 1 :
return False
2025-08-26 21:28:02 -04:00
if not self . ingame_log :
2025-08-30 16:33:21 -04:00
logger . info ( " You can now start sending locations from the Grinch! " )
2025-08-26 21:28:02 -04:00
self . ingame_log = True
2025-08-14 00:23:40 -04:00
return True
async def option_handler ( self , ctx : " BizHawkClientContext " ) :
if self . loc_unlimited_eggs :
2025-09-09 00:04:09 -04:00
await bizhawk . write ( ctx . bizhawk_ctx , [ ( EGG_COUNT_ADDR , MAX_EGGS . to_bytes ( 2 , " little " ) , " MainRAM " ) ] )
2025-08-17 21:22:12 -04:00
async def update_and_validate_address ( self , ctx : " BizHawkClientContext " , address_to_validate : int , expected_value : int , byte_size : int ) :
await bizhawk . write ( ctx . bizhawk_ctx , [ ( address_to_validate , expected_value . to_bytes ( byte_size , " little " ) , " MainRAM " ) ] )
current_value = int . from_bytes ( ( await bizhawk . read ( ctx . bizhawk_ctx , [ ( address_to_validate , byte_size , " MainRAM " ) ] ) ) [ 0 ] , " little " )
if not current_value == expected_value :
2025-09-09 21:01:56 -04:00
if address_to_validate == 0x010000 or address_to_validate == 0x08FB94 or address_to_validate == 0x010058 : # TODO Temporairly skips teleportation addresses; to be changed later on.
2025-08-25 17:07:21 -04:00
return
2025-09-04 23:48:53 -04:00
raise Exception ( " Unable to update address as expected. Address: " + str ( address_to_validate ) + " ; Expected Value: " + str ( expected_value ) )
2025-09-09 00:04:09 -04:00
async def ring_link_output ( self , ctx : " BizHawkClientContext " ) :
2025-09-09 01:29:32 -04:00
from CommonClient import logger
2025-09-09 21:01:56 -04:00
while not ctx . exit_event or ctx . slot :
try :
current_egg_count = int . from_bytes (
( await bizhawk . read ( ctx . bizhawk_ctx , [ ( EGG_COUNT_ADDR , EGG_ADDR_BYTESIZE , " MainRAM " ) ] ) ) [ 0 ] , " little " )
if ( current_egg_count - self . previous_egg_count ) != 0 :
msg = {
" cmd " : " Bounce " ,
" data " : {
" time " : time . time ( ) ,
" source " : ctx . player_names [ ctx . slot ] ,
" amount " : current_egg_count - self . previous_egg_count
} ,
" tags " : [ " RingLink " ]
}
await ctx . send_msgs ( [ msg ] )
self . previous_egg_count = current_egg_count
except Exception as ex :
logger . error ( " While monitoring grinch ' s egg count ingame, an error occured. Details: " + str ( ex ) )
2025-09-09 00:04:09 -04:00
async def ring_link_input ( self , egg_amount : int , ctx : " BizHawkClientContext " ) :
2025-09-09 21:01:56 -04:00
from CommonClient import logger
2025-09-09 00:04:09 -04:00
current_egg_count = int . from_bytes (
( await bizhawk . read ( ctx . bizhawk_ctx , [ ( EGG_COUNT_ADDR , EGG_ADDR_BYTESIZE , " MainRAM " ) ] ) ) [ 0 ] , " little " )
current_egg_count = min ( current_egg_count + egg_amount , MAX_EGGS )
2025-09-09 21:01:56 -04:00
await bizhawk . write ( ctx . bizhawk_ctx , [ ( EGG_COUNT_ADDR ,
int ( current_egg_count ) . to_bytes ( EGG_ADDR_BYTESIZE , " little " ) , " MainRAM " ) ] )
self . previous_egg_count = current_egg_count