def __init__(self): self.nextDoomExplodeAt = None self.itemCollector = ItemCollector() self.pumpkinFixer = PumpkinFixer() self.fumeFixer = FumeFixer() self.fodderOperator = FodderOperator() self.balloonTracker = BalloonTracker() self.memoryObserver = [self.itemCollector, self.pumpkinFixer, self.fumeFixer, self.fodderOperator, self.balloonTracker] self.gameStartObserver = [] self.baseAddr = read_game_memory(ctypes.c_uint32(), 0x6a9ec0) + 0x768 self.baseAddr = read_game_memory(ctypes.c_uint32(), self.baseAddr) self.itemBase = self.read_int32_from_base(0xe4) self.gridItemBase = self.read_int32_from_base(0x11c) self.cardBase = self.read_int32_from_base(0x144) self.plantBase = self.read_int32_from_base(0xac) self.zombieBase = self.read_int32_from_base(0x90) self.gridStatus = [] self.sunCount = 0 self.timestamp = 0 self.nextSpawn = 0 self.spawnedAt = 0 self.nZombies = 0 self.triggerHp = None self.nPlants = 0 self.plants = [] self.nItems = 0 self.items = [] self.nGridItems = 0 self.craters = [] self.icePath = [] self.icePathCountdown = [] self.nZombieWaves = 0 self.cards = {} self.zombies = [] self.minZombieX = [{}, {}, {}, {}, {}, {}] self.maxZombieX = [{}, {}, {}, {}, {}, {}] self.maxZombieHp = [{}, {}, {}, {}, {}, {}] self.hasZombie = {} self.optrQueue = [] self.strategy = None self.jackExploding = False self.newWave = False
def update_item_info(self): self.items = [] self.nItems = self.read_int32_from_base(0xf4) for i in range(0, 256): try: itemx = int(read_game_memory(ctypes.c_float(), self.itemBase + 0x24 + 0xd8 * i)) itemy = int(read_game_memory(ctypes.c_float(), self.itemBase + 0x28 + 0xd8 * i)) except: continue if itemx not in range(1, 801) or itemy not in range(1, 601): continue picked = read_game_memory(ctypes.c_uint8(), self.itemBase + 0x50 + 0xd8 * i) if picked != 0: continue self.items.append(Item(itemx, itemy))
def update_plant_info(self): self.plants = [] self.nPlants = self.read_int32_from_base(0xbc) for i in range(0, self.read_int32_from_base(0xb0)): disappeared = read_game_memory(ctypes.c_uint8(), self.plantBase + 0x141 + 0x14c * i) flattened = read_game_memory(ctypes.c_uint8(), self.plantBase + 0x141 + 0x14c * i) if disappeared != 0 or flattened != 0: continue self.plants.append(Plant( x=read_game_memory(ctypes.c_int32(), self.plantBase + 0x8 + 0x14c * i), y=read_game_memory(ctypes.c_int32(), self.plantBase + 0xc + 0x14c * i), row=read_game_memory(ctypes.c_int32(), self.plantBase + 0x1c + 0x14c * i), col=read_game_memory(ctypes.c_int32(), self.plantBase + 0x28 + 0x14c * i), hp=read_game_memory(ctypes.c_int32(), self.plantBase + 0x40 + 0x14c * i), plant_type=read_game_memory(ctypes.c_int32(), self.plantBase + 0x24 + 0x14c * i) )) last = self.plants[-1] self.gridStatus[last.row][last.col] &= last.type in [Plant.PUMPKIN, Plant.LILY_PAD]
def update_card_info(self): self.cards = {} for i in range(0, 10): imitater_type = None plant_type = read_game_memory(ctypes.c_int32(), self.cardBase + 0x5c + 0x50 * i) if plant_type == Plant.IMITATER: imitater_type = read_game_memory(ctypes.c_int32(), self.cardBase + 0x60 + 0x50 * i) self.cards[plant_type] = Card( plant_type=plant_type, imitater_type=imitater_type, card_x=read_game_memory(ctypes.c_int32(), self.cardBase + 0x30 + 0x50 * i), time_remain=read_game_memory(ctypes.c_int32(), self.cardBase + 0x50 + 0x50 * i) - read_game_memory(ctypes.c_int32(), self.cardBase + 0x4c + 0x50 * i), usable=read_game_memory(ctypes.c_uint8(), self.cardBase + 0x70 + 0x50 * i) != 0 )
def update_crater_info(self): self.craters = [] self.nGridItems = self.read_int32_from_base(0x12c) for i in range(0, read_game_memory(ctypes.c_int32(), self.baseAddr + 0x120)): item_type = read_game_memory(ctypes.c_int32(), self.gridItemBase + 0x8 + 0xec * i) if item_type != 2: continue disappeared = read_game_memory(ctypes.c_int32(), self.gridItemBase + 0x20 + 0xec * i) if disappeared != 0: continue row = read_game_memory(ctypes.c_int32(), self.gridItemBase + 0x14 + 0xec * i) col = read_game_memory(ctypes.c_int32(), self.gridItemBase + 0x10 + 0xec * i) timeout = read_game_memory(ctypes.c_int32(), self.gridItemBase + 0x18 + 0xec * i) if row not in range(0, 6) or col not in range(0, 9) or timeout not in range(1, 18001): continue self.craters.append(Crater(row, col, timeout)) last = self.craters[-1] self.gridStatus[last.row][last.col] = False
def update_zombie_info(self): self.zombies = [] self.jackExploding = False for i in range(0, 33): self.hasZombie[i] = False for row in range(0, 6): for zombie_type in range(0, 33): self.minZombieX[row][zombie_type] = None self.maxZombieX[row][zombie_type] = None self.maxZombieHp[row][zombie_type] = None for i in range(0, self.read_int32_from_base(0x94)): disappeared = read_game_memory(ctypes.c_uint8(), self.zombieBase + 0xec + 0x15c * i) living = read_game_memory(ctypes.c_uint8(), self.zombieBase + 0xba + 0x15c * i) hp = read_game_memory(ctypes.c_int32(), self.zombieBase + 0xc8 + 0x15c * i) status = read_game_memory(ctypes.c_int32(), self.zombieBase + 0x28 + 0x15c * i) if status in [1, 2, 3] or read_game_memory(ctypes.c_uint8(), self.zombieBase + 0x24 + 0x15c * i) in [9, 20, 24]: continue zombie_type = read_game_memory(ctypes.c_uint8(), self.zombieBase + 0x24 + 0x15c * i) if zombie_type not in range(0, 33): continue row = read_game_memory(ctypes.c_uint8(), self.zombieBase + 0x1c + 0x15c * i) if row not in range(0, 6): continue if disappeared != 0 or hp < 1 or not living: continue zombie = Zombie( hp=hp, x=read_game_memory(ctypes.c_float(), self.zombieBase + 0x2c + 0x15c * i), y=read_game_memory(ctypes.c_float(), self.zombieBase + 0x30 + 0x15c * i), row=row, zombie_type=zombie_type ) self.zombies.append(zombie) if self.minZombieX[zombie.row][zombie.type] is None: self.minZombieX[zombie.row][zombie.type] = zombie.x elif self.minZombieX[zombie.row][zombie.type] > zombie.x: self.minZombieX[zombie.row][zombie.type] = zombie.x if self.maxZombieX[zombie.row][zombie.type] is None: self.maxZombieX[zombie.row][zombie.type] = zombie.x elif self.maxZombieX[zombie.row][zombie.type] < zombie.x: self.maxZombieX[zombie.row][zombie.type] = zombie.x if self.maxZombieHp[zombie.row][zombie.type] is None: self.maxZombieHp[zombie.row][zombie.type] = zombie.hp elif self.maxZombieHp[zombie.row][zombie.type] < zombie.hp: self.maxZombieHp[zombie.row][zombie.type] = zombie.hp zombie_status = read_game_memory(ctypes.c_float(), self.zombieBase + 0x60 + 0x15c * i) if zombie_status < 100: self.hasZombie[zombie.type] = True if zombie.type == Zombie.JACK_IN_THE_BOX and zombie_status == 16: self.jackExploding = True
def read_memory_from_base(self, datatype, *addrs): p = self.baseAddr + addrs[0] for addr in addrs[1:-1]: p = read_game_memory(ctypes.c_void_p, p) + addr return read_game_memory(datatype, p)