From 1aa3f064601e5115dd9ef9403350782bd59e9f2d Mon Sep 17 00:00:00 2001 From: LondonClass <43668206+LondonClass@users.noreply.github.com> Date: Sun, 21 Aug 2022 22:46:43 +0800 Subject: [PATCH 1/8] Update core.py --- pvz/core.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pvz/core.py b/pvz/core.py index ecaf447..08929c7 100644 --- a/pvz/core.py +++ b/pvz/core.py @@ -733,6 +733,12 @@ def asm_push(code): asm_add_dword(code) +# push byte +def asm_push(code): + asm_add_byte(0x6a) + asm_add_dword(code) + + # mov exx, 0x12345678 asm_mov_exx_code = { "eax": [0xB8], From cba697be20b62c9884a6281f7a1dd195f1813fb6 Mon Sep 17 00:00:00 2001 From: LondonClass <43668206+LondonClass@users.noreply.github.com> Date: Sun, 21 Aug 2022 23:01:26 +0800 Subject: [PATCH 2/8] Update core.py --- pvz/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvz/core.py b/pvz/core.py index 08929c7..ab74461 100644 --- a/pvz/core.py +++ b/pvz/core.py @@ -733,10 +733,10 @@ def asm_push(code): asm_add_dword(code) -# push byte -def asm_push(code): +# push 0x12 +def asm_push_byte(code): asm_add_byte(0x6a) - asm_add_dword(code) + asm_add_byte(code) # mov exx, 0x12345678 From 335fefba6a33ee0a3d3e33d44f1b71a22238c36b Mon Sep 17 00:00:00 2001 From: LondonClass <43668206+LondonClass@users.noreply.github.com> Date: Mon, 22 Aug 2022 09:53:01 +0800 Subject: [PATCH 3/8] Update core.py --- pvz/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvz/core.py b/pvz/core.py index ab74461..f1d1e98 100644 --- a/pvz/core.py +++ b/pvz/core.py @@ -735,7 +735,7 @@ def asm_push(code): # push 0x12 def asm_push_byte(code): - asm_add_byte(0x6a) + asm_add_byte(0x6A) asm_add_byte(code) From f9622dcb8935614182db0dd3ba8a259a4d33d39b Mon Sep 17 00:00:00 2001 From: LondonClass <43668206+LondonClass@users.noreply.github.com> Date: Sat, 27 Aug 2022 22:45:36 +0800 Subject: [PATCH 4/8] Update core.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 抛出异常前,应当先解除内存锁,否则再次调用时会死锁 --- pvz/core.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pvz/core.py b/pvz/core.py index f1d1e98..12b8040 100644 --- a/pvz/core.py +++ b/pvz/core.py @@ -567,6 +567,7 @@ def read_memory(data_type, *address, array=1): size = ctypes.sizeof(buffer) success = ReadProcessMemory(pvz_handle, offset, ctypes.byref(buffer), size, ctypes.byref(bytes_read)) if success == 0 or bytes_read.value != size: + memory_lock.release() critical("读取内存失败, 错误代码 %d." % GetLastError()) else: @@ -575,6 +576,7 @@ def read_memory(data_type, *address, array=1): buff = ctypes.create_string_buffer(size) # 目标数据缓冲 success = ReadProcessMemory(pvz_handle, offset, ctypes.byref(buff), size, ctypes.byref(bytes_read)) if success == 0 or bytes_read.value != size: + memory_lock.release() critical("读取内存失败, 错误代码 %d." % GetLastError()) result = struct.unpack(fmt_str, buff.raw) @@ -627,6 +629,7 @@ def write_memory(data_type, values, *address): size = ctypes.sizeof(buffer) success = ReadProcessMemory(pvz_handle, offset, ctypes.byref(buffer), size, ctypes.byref(bytes_read)) if success == 0 or bytes_read.value != size: + memory_lock.release() critical("读取内存失败, 错误代码 %d." % GetLastError()) else: @@ -637,6 +640,7 @@ def write_memory(data_type, values, *address): buff.value = struct.pack(fmt_str, *values) # 将目标数据载入缓冲区 success = WriteProcessMemory(pvz_handle, offset, ctypes.byref(buff), size, ctypes.byref(bytes_written)) if success == 0 or bytes_written.value != size: + memory_lock.release() critical("写入内存失败, 错误代码 %d." % GetLastError()) memory_lock.release() From 8a26c2a6457f457bd946eec820d189c24d61bd2e Mon Sep 17 00:00:00 2001 From: shiawasenahikari Date: Fri, 6 Jan 2023 10:48:48 +0800 Subject: [PATCH 5/8] 20230106 Added support for Steam version. --- pvz/__init__.py | 2 +- pvz/core.py | 14 +++- pvz/extra.py | 215 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 175 insertions(+), 56 deletions(-) diff --git a/pvz/__init__.py b/pvz/__init__.py index 4935f79..7ef174b 100644 --- a/pvz/__init__.py +++ b/pvz/__init__.py @@ -153,7 +153,7 @@ def _on_start(): else: critical("游戏未开启或者游戏版本不受支持!") - enable_logging(False) # 是否输出调试日志 + enable_logging(True) # 是否输出调试日志 set_logging_level("INFO") diff --git a/pvz/core.py b/pvz/core.py index 12b8040..3ac7cf4 100644 --- a/pvz/core.py +++ b/pvz/core.py @@ -477,6 +477,12 @@ def find_pvz(): pvz_version = "1.2.0.1065" info("已找到游戏 1.2.0.1065 !!!") return True + elif True: + # TODO 缺少 steam 版检测机制 + # 暂时默认非 1051、1065 的版本一定是 steam 版 + pvz_version = "1.2.0.1096" + info("已找到游戏 1.2.0.1096 !!!") + return True else: pvz_version = None warning("不支持的游戏版本 !!!") @@ -912,15 +918,19 @@ def asm_code_inject(): def asm_code_inject_safely(): if pvz_ver() == "1.0.0.1051": write_memory("unsigned char", 0xFE, 0x00552014) - else: + elif pvz_ver() == "1.2.0.1065": write_memory("unsigned char", 0xFE, 0x00552244) + else: + write_memory("unsigned char", 0xFE, 0x005DD25E) time.sleep(0.01) if is_valid(): asm_code_inject() if pvz_ver() == "1.0.0.1051": write_memory("unsigned char", 0xDB, 0x00552014) - else: + elif pvz_ver() == "1.2.0.1065": write_memory("unsigned char", 0xDB, 0x00552244) + else: + write_memory("unsigned char", 0xC8, 0x005DD25E) ### 键盘操作 diff --git a/pvz/extra.py b/pvz/extra.py index 0e75596..7dc07a8 100644 --- a/pvz/extra.py +++ b/pvz/extra.py @@ -9,10 +9,7 @@ def game_on(): """ @返回值 (bool): 游戏是否开启, 没开则会尝试重新查找一次. """ - if is_valid(): - return True - else: - return find_pvz() + return is_valid() or find_pvz() def game_ui(): @@ -21,14 +18,20 @@ def game_ui(): 1: 主界面, 2: 选卡, 3: 正常游戏/战斗, 4: 僵尸进屋, 7: 模式选择. """ - return read_memory("int", 0x6A9EC0, 0x7FC) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x7FC) + else: + return read_memory("int", 0x731C50, 0x7FC + 0x120) def game_mode(): """ @返回值 (int): 游戏模式, 13 为生存无尽. """ - return read_memory("int", 0x6A9EC0, 0x7F8) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x7F8) + else: + return read_memory("int", 0x731C50, 0x7F8 + 0x120) def game_scene(): @@ -37,63 +40,90 @@ def game_scene(): 0: 白天, 1: 黑夜, 2: 泳池, 3: 浓雾, 4: 屋顶, 5: 月夜, 6: 蘑菇园, 7: 禅境花园, 8: 水族馆, 9: 智慧树. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x554C) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x554C) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x554C + 0x18) def game_paused(): """ @返回值 (bool): 当前游戏是否暂停. """ - return read_memory("bool", 0x6A9EC0, 0x768, 0x164) + if pvz_ver() != "1.2.0.1096": + return read_memory("bool", 0x6A9EC0, 0x768, 0x164) + else: + return read_memory("bool", 0x731C50, 0x768 + 0x100, 0x164 + 0x18) def mouse_in_game(): """ @返回值 (bool): 鼠标是否在游戏窗口内部. """ - return read_memory("bool", 0x6A9EC0, 0x768, 0x138, 0x18) # 0x6A9EC0, 0x768, 0x59 + if pvz_ver() != "1.2.0.1096": + return read_memory("bool", 0x6A9EC0, 0x768, 0x138, 0x18) + else: + return read_memory("bool", 0x731C50, 0x768 + 0x100, 0x138 + 0x18, 0x18) def mouse_have_something(): """ @返回值 (bool): 鼠标是否选中卡炮或铲子. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x138, 0x30) in (1, 6, 8) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x138, 0x30) in (1, 6, 8) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x138 + 0x18, 0x30) in (1, 6, 8) def game_clock(): """ @返回值 (int): 内部时钟, 游戏暂停和选卡时会暂停计时. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x5568) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x5568) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x5568 + 0x18) def wave_init_countdown(): """ @返回值 (int): 刷新倒计时初始值. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x55A0) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x55A0) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x55A0 + 0x18) def wave_countdown(): """ @返回值 (int): 下一波刷新倒计时, 触发刷新时重置为 200, 减少至 1 后刷出下一波. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x559C) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x559C) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x559C + 0x18) def huge_wave_countdown(): """ @返回值 (int): 大波刷新倒计时, 对于旗帜波, 刷新倒计时减少至 4 后停滞, 由该值代替减少. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x55A4) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x55A4) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x55A4 + 0x18) def current_wave(): """ @返回值 (int): 已刷新波数. """ - return read_memory("int", 0x6A9EC0, 0x768, 0x557C) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x557C) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x557C + 0x18) ### 修改出怪 @@ -101,6 +131,9 @@ def current_wave(): # 从出怪种子生成出怪类型 def update_zombies_type(): + if pvz_ver() == "1.2.0.1096": + info("Steam 版暂不支持生成出怪类型") + return write_memory("bool", [False] * 33, 0x6A9EC0, 0x768, 0x54D4) asm_init() asm_mov_exx_dword_ptr("esi", 0x6A9EC0) @@ -113,6 +146,9 @@ def update_zombies_type(): # 从出怪类型生成出怪列表 def update_zombies_list(): + if pvz_ver() == "1.2.0.1096": + info("Steam 版暂不支持生成出怪列表") + return asm_init() asm_mov_exx_dword_ptr("edi", 0x6A9EC0) asm_mov_exx_dword_ptr_exx_add("edi", 0x768) @@ -123,6 +159,9 @@ def update_zombies_list(): # 更新选卡界面出怪预览 def update_zombies_preview(): + if pvz_ver() == "1.2.0.1096": + info("Steam 版暂不支持更新出怪预览") + return write_memory("byte", 0x80, 0x0043A153) if pvz_ver() == "1.0.0.1051" else write_memory("byte", 0x80, 0x0043A1C3) asm_init() asm_mov_exx_dword_ptr("ebx", 0x6A9EC0) @@ -162,6 +201,10 @@ def set_internal_spawn(zombies=None): if not (game_on() and game_ui() in (2, 3)): return + if pvz_ver() == "1.2.0.1096": + info("Steam 版暂不支持修改出怪") + return + if zombies is None: zombies = [] zombies += [0] # 普僵必出 @@ -186,6 +229,10 @@ def set_customize_spawn(zombies=None): if not (game_on() and game_ui() in (2, 3)): return + if pvz_ver() == "1.2.0.1096": + info("Steam 版暂不支持修改出怪") + return + if zombies is None: zombies = [0] # 默认普僵 zombies = [zombie_name_to_index(z) for z in zombies] @@ -287,8 +334,8 @@ def set_zombies(zombies=None, mode="极限刷怪"): IMITATER_SEED_0_0_Y = 160 SEED_WIDTH = 50 SEED_HEIGHT = 70 -IMITATER_X = 490 -IMITATER_Y = 550 +IMITATER_X = 470 +IMITATER_Y = 580 IMITATER_SHOW_UP = 0 SEED_DELAY_TIME = 5 @@ -325,7 +372,10 @@ def select_seed_by_crood(row, col, imitater=False): y = SEED_0_0_Y + (row - 1) * (SEED_HEIGHT + 0) # 不小心点进了图鉴或者商店 - window_type = read_memory("int", 0x6A9EC0, 0x320, 0x88, 0xC) + if pvz_ver() != "1.2.0.1096": + window_type = read_memory("int", 0x6A9EC0, 0x320, 0x88, 0xC) + else: + window_type = read_memory("int", 0x731C50, 0x320, 0x88 + 0x18, 0x1C) if window_type == 1: left_click(720, 580) thread_sleep_for(5) @@ -404,8 +454,12 @@ def _(seed): # 检查已选卡片是否完全相符 def slots_exact_match(seeds_selected): - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - slots_selected = read_memory("int", 0x6A9EC0, 0x774, 0xD24) + if pvz_ver() != "1.2.0.1096": + slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + slots_selected = read_memory("int", 0x6A9EC0, 0x774, 0xD24) + else: + slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) + slots_selected = read_memory("int", 0x731C50, 0x774 + 0x100, 0xD24 + 0x18) if slots_selected < slots_count: return False match = True @@ -414,8 +468,12 @@ def slots_exact_match(seeds_selected): seed_index = (row - 1) * 8 + (col - 1) if imitater: seed_index = 48 - seed_plant = read_memory("int", 0x6A9EC0, 0x774, 0xC4 + seed_index * 0x3C) - seed_status = read_memory("int", 0x6A9EC0, 0x774, 0xC8 + seed_index * 0x3C) + if pvz_ver() != "1.2.0.1096": + seed_plant = read_memory("int", 0x6A9EC0, 0x774, 0xC4 + seed_index * 0x3C) + seed_status = read_memory("int", 0x6A9EC0, 0x774, 0xC8 + seed_index * 0x3C) + else: + seed_plant = read_memory("int", 0x731C50, 0x774 + 0x100, 0xC4 + 0x18 + seed_index * 0x3C) + seed_status = read_memory("int", 0x731C50, 0x774 + 0x100, 0xC8 + 0x18 + seed_index * 0x3C) # !卡片对应的植物正确并且位于卡槽中 if not (seed_plant == seed_index and seed_status == 1): match = False @@ -425,7 +483,10 @@ def slots_exact_match(seeds_selected): # 清空卡槽所有卡片 def clear_slots(): - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + if pvz_ver() != "1.2.0.1096": + slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + else: + slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) for slot_index in reversed(range(slots_count)): # 逆序 slot_index += 1 if slots_count == 10: @@ -451,7 +512,10 @@ def select_all_seeds(seeds_selected=None): """ # 不小心点进了图鉴或者商店 - window_type = read_memory("int", 0x6A9EC0, 0x320, 0x88, 0xC) + if pvz_ver() != "1.2.0.1096": + window_type = read_memory("int", 0x6A9EC0, 0x320, 0x88, 0xC) + else: + window_type = read_memory("int", 0x731C50, 0x320, 0x88 + 0x18, 0x1C) if window_type == 1: left_click(720, 580) thread_sleep_for(5) @@ -460,7 +524,10 @@ def select_all_seeds(seeds_selected=None): thread_sleep_for(5) default_seeds = [40, 41, 42, 43, 44, 45, 46, 47, 8, 8 + 48] - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + if pvz_ver() != "1.2.0.1096": + slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + else: + slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) # 默认八张紫卡和两张免费卡 if seeds_selected is None: @@ -501,14 +568,24 @@ def select_all_seeds(seeds_selected=None): def lets_rock(): - while read_memory("bool", 0x6A9EC0, 0x768, 0x15C, 0x2C): # 位于选卡界面 - left_down(234, 567) - thread_sleep_for(1) - left_up(234, 567) - thread_sleep_for(10) - while read_memory("int", 0x6A9EC0, 0x320, 0x94) != 0: # 出现了对话框 - left_click(320, 400) + if pvz_ver() != "1.2.0.1096": + while read_memory("bool", 0x6A9EC0, 0x768, 0x15C, 0x2C): # 位于选卡界面 + left_down(234, 567) + thread_sleep_for(1) + left_up(234, 567) + thread_sleep_for(10) + while read_memory("int", 0x6A9EC0, 0x320, 0x94) != 0: # 出现了对话框 + left_click(320, 400) + thread_sleep_for(10) + else: + while read_memory("bool", 0x731C50, 0x768 + 0x100, 0x15C + 0x18, 0x2C): # 位于选卡界面 + left_down(234, 567) + thread_sleep_for(1) + left_up(234, 567) thread_sleep_for(10) + while read_memory("int", 0x731C50, 0x320, 0x94 + 0x18) != 0: # 出现了对话框 + left_click(320, 400) + thread_sleep_for(10) def select_seeds_and_lets_rock(seeds_selected=None): @@ -584,8 +661,12 @@ def update_seeds_list(): seeds_in_slot = [None] * (48 * 2) slot_seeds = [None] * 10 - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) + if pvz_ver() != "1.2.0.1096": + slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) + else: + slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) + slots_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18) for i in range(slots_count): seed_type = read_memory("int", slots_offset + 0x5C + i * 0x50) seed_imitater_type = read_memory("int", slots_offset + 0x60 + i * 0x50) @@ -670,8 +751,12 @@ def get_seed_by_index(index): # 更新卡槽格数和场景地图 def update_game_scene(): global slots_count, game_scene - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - game_scene = read_memory("int", 0x6A9EC0, 0x768, 0x554C) + if pvz_ver() != "1.2.0.1096": + slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + game_scene = read_memory("int", 0x6A9EC0, 0x768, 0x554C) + else: + slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) + game_scene = read_memory("int", 0x731C50, 0x768 + 0x100, 0x554C + 0x18) info("更新卡槽格数 %d." % slots_count) info("更新场景地图 %s." % scenes[game_scene]) @@ -855,8 +940,12 @@ def update_cob_cannon_list(cobs=None): global cob_list, cob_index cob_list_tmp = [] - plants_count_max = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xB0) - plants_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xAC) + if pvz_ver() != "1.2.0.1096": + plants_count_max = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xB0) + plants_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xAC) + else: + plants_count_max = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xB0 + 0x18) + plants_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xAC + 0x18) for i in range(plants_count_max): plant_dead = read_memory("bool", plants_offset + 0x141 + 0x14C * i) plant_crushed = read_memory("bool", plants_offset + 0x142 + 0x14C * i) @@ -1417,9 +1506,14 @@ def auto_collect(collect_items=None, interval_cs=12): info("启动自动收集线程.") while game_ui() == 3: - items_count = read_memory("int", 0x6A9EC0, 0x768, 0xF4) - items_count_max = read_memory("int", 0x6A9EC0, 0x768, 0xE8) - items_offset = read_memory("int", 0x6A9EC0, 0x768, 0xE4) + if pvz_ver() != "1.2.0.1096": + items_count = read_memory("int", 0x6A9EC0, 0x768, 0xF4) + items_count_max = read_memory("int", 0x6A9EC0, 0x768, 0xE8) + items_offset = read_memory("int", 0x6A9EC0, 0x768, 0xE4) + else: + items_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0xF4 + 0x18) + items_count_max = read_memory("int", 0x731C50, 0x768 + 0x100, 0xE8 + 0x18) + items_offset = read_memory("int", 0x731C50, 0x768 + 0x100, 0xE4 + 0x18) if items_count == 0: thread_sleep_for(interval_cs) @@ -1483,8 +1577,12 @@ def get_seeds_index(seed): seed %= 48 seed_indexes = [] - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) + if pvz_ver() != "1.2.0.1096": + slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) + slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) + else: + slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) + slots_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18) for i in range(slots_count): seed_type = read_memory("int", slots_offset + 0x5C + i * 0x50) seed_imitater_type = read_memory("int", slots_offset + 0x60 + i * 0x50) @@ -1498,8 +1596,12 @@ def get_plants_croods(): 获取场上植物坐标. """ croods = [] - plants_count_max = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xB0) - plants_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xAC) + if pvz_ver() != "1.2.0.1096": + plants_count_max = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xB0) + plants_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xAC) + else: + plants_count_max = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xB0 + 0x18) + plants_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xAC + 0x18) for i in range(plants_count_max): plant_dead = read_memory("bool", plants_offset + 0x141 + 0x14C * i) plant_crushed = read_memory("bool", plants_offset + 0x142 + 0x14C * i) @@ -1520,7 +1622,10 @@ def get_block_type(*crood): else: row, col = crood row, col = row - 1, col - 1 - return read_memory("int", 0x6a9ec0, 0x768, 0x168 + row * 0x04 + col * 0x18) + if pvz_ver() != "1.2.0.1096": + return read_memory("int", 0x6A9EC0, 0x768, 0x168 + row * 0x04 + col * 0x18) + else: + return read_memory("int", 0x731C50, 0x768 + 0x100, 0x168 + 0x18 + row * 0x04 + col * 0x18) # 存冰位 @@ -1564,7 +1669,10 @@ def auto_fill_ice(spots=None, total=0x7FFFFFFF): ice_spots = spots ice_total = total - slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) + if pvz_ver() != "1.2.0.1096": + slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) + else: + slots_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18) ice_seeds_index = get_seeds_index("寒冰菇") # 获取所有寒冰菇卡片的下标 if ice_seeds_index == []: @@ -1612,18 +1720,18 @@ def auto_fill_ice(spots=None, total=0x7FFFFFFF): break # 如果该位置无植物则尝试存冰 - if pvz_ver() == "1.0.0.1051": - seed_ice_cost = read_memory("int", 0x69F2C0 + 14 * 0x24) + if pvz_ver() != "1.2.0.1096": + sun = read_memory("int", 0x6A9EC0, 0x768, 0x5560) else: - seed_ice_cost = read_memory("int", 0x69F2D0 + 14 * 0x24) - sun = read_memory("int", 0x6A9EC0, 0x768, 0x5560) - if sun < seed_ice_cost: + sun = read_memory("int", 0x731C50, 0x768 + 0x100, 0x5560 + 0x18) + + if sun < 75: thread_sleep_for(1) continue block_type = get_block_type(spot) # 1.草地 2.裸地 3.泳池 16.睡莲 33.花盆 if (spot not in ice_spot_which_has_plant \ - and sun >= seed_ice_cost \ + and sun >= 75 \ and ((block_type == 1 and game_scene not in (4, 5)) \ or (block_type == 1 and game_scene in (4, 5) and (33, spot[0], spot[1]) in plants) \ or (block_type == 3 and (16, spot[0], spot[1]) in plants))): @@ -1671,3 +1779,4 @@ def activate_ice(): click_grid((row, col)) safe_click() mouse_lock.release() + info("唤醒寒冰菇.") From f5dbcc982028061b2a7be7b6fc2d9f6f28b55d82 Mon Sep 17 00:00:00 2001 From: shiawasenahikari Date: Mon, 6 Feb 2023 22:23:23 +0800 Subject: [PATCH 6/8] =?UTF-8?q?20230206=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E4=BD=BF=E7=94=A8=E9=BB=98=E8=AE=A4=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E7=9A=84=20bug=E3=80=82=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E7=A6=BB=E5=BC=80=E6=88=98=E6=96=97=E7=95=8C=E9=9D=A2=E5=90=8E?= =?UTF-8?q?=20Delay=20=E5=87=BD=E6=95=B0=E5=8D=A1=E6=AD=BB=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E7=9A=84=20bug=E3=80=82=20=E7=8E=89=E7=B1=B3=E7=82=AE?= =?UTF-8?q?=E5=8F=AF=E6=8D=8F=E5=9C=A8=E6=89=8B=E4=B8=8A=E4=B8=80=E6=AE=B5?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=90=8E=E5=86=8D=E5=8F=91=E5=B0=84=EF=BC=8C?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=E7=82=AE=E7=B2=98=E6=89=8B=E3=80=82=E7=94=A8?= =?UTF-8?q?=E6=B3=95=EF=BC=9A=20Pao(y,=20x,=20delay=5Fcs)=20=E5=B0=86?= =?UTF-8?q?=E7=82=AE=E6=8D=8F=E5=9C=A8=E6=89=8B=E4=B8=8A=20delay=5Fcs=20?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=90=8E=E5=8F=91=E5=BE=80=20(y,=20x)?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pvz/extra.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pvz/extra.py b/pvz/extra.py index 7dc07a8..a8755df 100644 --- a/pvz/extra.py +++ b/pvz/extra.py @@ -523,7 +523,7 @@ def select_all_seeds(seeds_selected=None): left_click(430, 550) thread_sleep_for(5) - default_seeds = [40, 41, 42, 43, 44, 45, 46, 47, 8, 8 + 48] + default_seeds = [8 + 48, 8, 40, 41, 42, 43, 44, 45, 46, 47] if pvz_ver() != "1.2.0.1096": slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) else: @@ -1097,7 +1097,7 @@ def fire_cob(*croods): @fire_cob.register(int) -def _(fall_row, fall_col): +def _(fall_row, fall_col, delay_cs = 0): global cob_list, cob_index cob_count = len(cob_list) if cob_count == 0: @@ -1105,7 +1105,7 @@ def _(fall_row, fall_col): cob_lock.acquire() cob_row, cob_col = cob_list[cob_index] - fire_cob_by_crood(cob_row, cob_col, fall_row, fall_col) + fire_cob_by_crood(cob_row, cob_col, fall_row, fall_col, delay_cs) cob_index += 1 cob_index %= cob_count cob_lock.release() @@ -1241,18 +1241,21 @@ def skip_cob_index(num): # 无视内置炮列表直接指定炮位和落点 -def fire_cob_by_crood(cob_row, cob_col, fall_row, fall_col): +def fire_cob_by_crood(cob_row, cob_col, fall_row, fall_col, delay_cs = 0): mouse_lock.acquire() safe_click() for _ in range(CLICK_COUNT): # 点炮位置稍微偏离, 配合改内存解决炮粘手的问题 click_grid(cob_row + 2 / 85, cob_col - 2 / 80) + if delay_cs > 0: + info("(%d, %d) 炮已捏在手上, 将于 %dcs 后发射至 (%d, %d)." % (cob_row, cob_col, delay_cs, fall_row, fall_col)) + game_delay_for(delay_cs) click_grid(fall_row, fall_col) safe_click() mouse_lock.release() - info("从 (%d, %d) 向 (%d, %d) 发射玉米炮." % (cob_row, cob_col, fall_row, fall_col)) + info("从 (%d, %d) 向 (%d, %.1f) 发射玉米炮." % (cob_row, cob_col, fall_row, fall_col)) ### 阻塞延时 @@ -1272,7 +1275,7 @@ def game_delay_for(time_cs): if time_cs > 0: clock = game_clock() - while (game_clock() - clock) < time_cs: + while game_ui() == 3 and (game_clock() - clock) < time_cs: delay_a_little_time() elif time_cs == 0: pass From 8c9e1bacceb48fa3e65d85dfbfd728892cd4fe3c Mon Sep 17 00:00:00 2001 From: shiawasenahikari Date: Tue, 12 Dec 2023 16:03:03 +0800 Subject: [PATCH 7/8] =?UTF-8?q?20231212=20=E5=8E=BB=E9=99=A4=E4=BA=86?= =?UTF-8?q?=EF=BC=AE=E5=A4=9A=E4=B8=AA=E4=B8=A5=E9=87=8D=E5=BD=B1=E5=93=8D?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2=E6=AF=94?= =?UTF-8?q?=E8=BE=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pvz/__init__.py | 4 + pvz/extra.py | 212 ++++++++++++++++-------------------------------- 2 files changed, 72 insertions(+), 144 deletions(-) diff --git a/pvz/__init__.py b/pvz/__init__.py index 7ef174b..4294849 100644 --- a/pvz/__init__.py +++ b/pvz/__init__.py @@ -143,6 +143,10 @@ def _on_start(): # set_dpi_scale(1.25) # 出错则手动设置 if find_pvz(): + if pvz_ver() != "1.2.0.1096": + set_addr(0x6A9EC0, 0x768, 0x00) + else: + set_addr(0x731C50, 0x868, 0x18) ui = game_ui() if ui in (2, 3): set_pvz_foreground() diff --git a/pvz/extra.py b/pvz/extra.py index a8755df..8332a51 100644 --- a/pvz/extra.py +++ b/pvz/extra.py @@ -2,6 +2,19 @@ from .core import * +# 内存基址、二级偏移、三级偏移 +base_addr = 0x6A9EC0 +off2 = 0x768 +off3 = 0x00 + + +def set_addr(_base, _off2, _off3): + global base_addr, off2, off3 + base_addr = _base + off2 = _off2 + off3 = _off3 + + ### 读取常用信息 @@ -18,20 +31,20 @@ def game_ui(): 1: 主界面, 2: 选卡, 3: 正常游戏/战斗, 4: 僵尸进屋, 7: 模式选择. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x7FC) + if base_addr == 0x6A9EC0: + return read_memory("int", base_addr, 0x7FC) else: - return read_memory("int", 0x731C50, 0x7FC + 0x120) + return read_memory("int", base_addr, 0x91C) def game_mode(): """ @返回值 (int): 游戏模式, 13 为生存无尽. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x7F8) + if base_addr == 0x6A9EC0: + return read_memory("int", base_addr, 0x7F8) else: - return read_memory("int", 0x731C50, 0x7F8 + 0x120) + return read_memory("int", base_addr, 0x918) def game_scene(): @@ -40,90 +53,63 @@ def game_scene(): 0: 白天, 1: 黑夜, 2: 泳池, 3: 浓雾, 4: 屋顶, 5: 月夜, 6: 蘑菇园, 7: 禅境花园, 8: 水族馆, 9: 智慧树. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x554C) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x554C + 0x18) + return read_memory(base_addr, off2, off3 + 0x554C) def game_paused(): """ @返回值 (bool): 当前游戏是否暂停. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("bool", 0x6A9EC0, 0x768, 0x164) - else: - return read_memory("bool", 0x731C50, 0x768 + 0x100, 0x164 + 0x18) + return read_memory("bool", base_addr, off2, off3 + 0x164) def mouse_in_game(): """ @返回值 (bool): 鼠标是否在游戏窗口内部. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("bool", 0x6A9EC0, 0x768, 0x138, 0x18) - else: - return read_memory("bool", 0x731C50, 0x768 + 0x100, 0x138 + 0x18, 0x18) + return read_memory("bool", base_addr, off2, off3 + 0x138, 0x18) def mouse_have_something(): """ @返回值 (bool): 鼠标是否选中卡炮或铲子. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x138, 0x30) in (1, 6, 8) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x138 + 0x18, 0x30) in (1, 6, 8) + return read_memory("int", base_addr, off2, off3 + 0x138, 0x30) in (1, 6, 8) def game_clock(): """ @返回值 (int): 内部时钟, 游戏暂停和选卡时会暂停计时. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x5568) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x5568 + 0x18) + return read_memory("int", base_addr, off2, off3 + 0x5568) def wave_init_countdown(): """ @返回值 (int): 刷新倒计时初始值. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x55A0) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x55A0 + 0x18) + return read_memory("int", base_addr, off2, off3 + 0x55A0) def wave_countdown(): """ @返回值 (int): 下一波刷新倒计时, 触发刷新时重置为 200, 减少至 1 后刷出下一波. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x559C) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x559C + 0x18) + return read_memory("int", base_addr, off2, off3 + 0x559C) def huge_wave_countdown(): """ @返回值 (int): 大波刷新倒计时, 对于旗帜波, 刷新倒计时减少至 4 后停滞, 由该值代替减少. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x55A4) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x55A4 + 0x18) + return read_memory("int", base_addr, off2, off3 + 0x55A4) def current_wave(): """ @返回值 (int): 已刷新波数. """ - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x557C) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x557C + 0x18) + return read_memory("int", base_addr, off2, off3 + 0x557C) ### 修改出怪 @@ -131,7 +117,7 @@ def current_wave(): # 从出怪种子生成出怪类型 def update_zombies_type(): - if pvz_ver() == "1.2.0.1096": + if base_addr != 0x6A9EC0: info("Steam 版暂不支持生成出怪类型") return write_memory("bool", [False] * 33, 0x6A9EC0, 0x768, 0x54D4) @@ -146,7 +132,7 @@ def update_zombies_type(): # 从出怪类型生成出怪列表 def update_zombies_list(): - if pvz_ver() == "1.2.0.1096": + if base_addr != 0x6A9EC0: info("Steam 版暂不支持生成出怪列表") return asm_init() @@ -159,7 +145,7 @@ def update_zombies_list(): # 更新选卡界面出怪预览 def update_zombies_preview(): - if pvz_ver() == "1.2.0.1096": + if base_addr != 0x6A9EC0: info("Steam 版暂不支持更新出怪预览") return write_memory("byte", 0x80, 0x0043A153) if pvz_ver() == "1.0.0.1051" else write_memory("byte", 0x80, 0x0043A1C3) @@ -201,7 +187,7 @@ def set_internal_spawn(zombies=None): if not (game_on() and game_ui() in (2, 3)): return - if pvz_ver() == "1.2.0.1096": + if base_addr != 0x6A9EC0: info("Steam 版暂不支持修改出怪") return @@ -229,7 +215,7 @@ def set_customize_spawn(zombies=None): if not (game_on() and game_ui() in (2, 3)): return - if pvz_ver() == "1.2.0.1096": + if base_addr != 0x6A9EC0: info("Steam 版暂不支持修改出怪") return @@ -372,10 +358,10 @@ def select_seed_by_crood(row, col, imitater=False): y = SEED_0_0_Y + (row - 1) * (SEED_HEIGHT + 0) # 不小心点进了图鉴或者商店 - if pvz_ver() != "1.2.0.1096": - window_type = read_memory("int", 0x6A9EC0, 0x320, 0x88, 0xC) + if base_addr == 0x6A9EC0: + window_type = read_memory("int", base_addr, 0x320, 0x88, 0xC) else: - window_type = read_memory("int", 0x731C50, 0x320, 0x88 + 0x18, 0x1C) + window_type = read_memory("int", base_addr, 0x320, 0xA0, 0x1C) if window_type == 1: left_click(720, 580) thread_sleep_for(5) @@ -454,12 +440,8 @@ def _(seed): # 检查已选卡片是否完全相符 def slots_exact_match(seeds_selected): - if pvz_ver() != "1.2.0.1096": - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - slots_selected = read_memory("int", 0x6A9EC0, 0x774, 0xD24) - else: - slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) - slots_selected = read_memory("int", 0x731C50, 0x774 + 0x100, 0xD24 + 0x18) + slots_count = read_memory("int", base_addr, off2, off3 + 0x144, 0x24) + slots_selected = read_memory("int", base_addr, off2 + 0x0C, off3 + 0xD24) if slots_selected < slots_count: return False match = True @@ -468,12 +450,8 @@ def slots_exact_match(seeds_selected): seed_index = (row - 1) * 8 + (col - 1) if imitater: seed_index = 48 - if pvz_ver() != "1.2.0.1096": - seed_plant = read_memory("int", 0x6A9EC0, 0x774, 0xC4 + seed_index * 0x3C) - seed_status = read_memory("int", 0x6A9EC0, 0x774, 0xC8 + seed_index * 0x3C) - else: - seed_plant = read_memory("int", 0x731C50, 0x774 + 0x100, 0xC4 + 0x18 + seed_index * 0x3C) - seed_status = read_memory("int", 0x731C50, 0x774 + 0x100, 0xC8 + 0x18 + seed_index * 0x3C) + seed_plant = read_memory("int", base_addr, off2 + 0x0C, off3 + 0xC4 + seed_index * 0x3C) + seed_status = read_memory("int", base_addr, off2 + 0x0C, off3 + 0xC8 + seed_index * 0x3C) # !卡片对应的植物正确并且位于卡槽中 if not (seed_plant == seed_index and seed_status == 1): match = False @@ -483,10 +461,7 @@ def slots_exact_match(seeds_selected): # 清空卡槽所有卡片 def clear_slots(): - if pvz_ver() != "1.2.0.1096": - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - else: - slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) + slots_count = read_memory("int", base_addr, off2, off3 + 0x144, 0x24) for slot_index in reversed(range(slots_count)): # 逆序 slot_index += 1 if slots_count == 10: @@ -512,10 +487,10 @@ def select_all_seeds(seeds_selected=None): """ # 不小心点进了图鉴或者商店 - if pvz_ver() != "1.2.0.1096": - window_type = read_memory("int", 0x6A9EC0, 0x320, 0x88, 0xC) + if base_addr == 0x6A9EC0: + window_type = read_memory("int", base_addr, 0x320, 0x88, 0xC) else: - window_type = read_memory("int", 0x731C50, 0x320, 0x88 + 0x18, 0x1C) + window_type = read_memory("int", base_addr, 0x320, 0xA0, 0x1C) if window_type == 1: left_click(720, 580) thread_sleep_for(5) @@ -524,10 +499,7 @@ def select_all_seeds(seeds_selected=None): thread_sleep_for(5) default_seeds = [8 + 48, 8, 40, 41, 42, 43, 44, 45, 46, 47] - if pvz_ver() != "1.2.0.1096": - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - else: - slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) + slots_count = read_memory("int", base_addr, off2, off3 + 0x144, 0x24) # 默认八张紫卡和两张免费卡 if seeds_selected is None: @@ -568,24 +540,14 @@ def select_all_seeds(seeds_selected=None): def lets_rock(): - if pvz_ver() != "1.2.0.1096": - while read_memory("bool", 0x6A9EC0, 0x768, 0x15C, 0x2C): # 位于选卡界面 - left_down(234, 567) - thread_sleep_for(1) - left_up(234, 567) - thread_sleep_for(10) - while read_memory("int", 0x6A9EC0, 0x320, 0x94) != 0: # 出现了对话框 - left_click(320, 400) - thread_sleep_for(10) - else: - while read_memory("bool", 0x731C50, 0x768 + 0x100, 0x15C + 0x18, 0x2C): # 位于选卡界面 - left_down(234, 567) - thread_sleep_for(1) - left_up(234, 567) + while read_memory("bool", base_addr, off2, off3 + 0x15C, 0x2C): # 位于选卡界面 + left_down(234, 567) + thread_sleep_for(1) + left_up(234, 567) + thread_sleep_for(10) + while read_memory("int", base_addr, 0x320, off3 + 0x94) != 0: # 出现了对话框 + left_click(320, 400) thread_sleep_for(10) - while read_memory("int", 0x731C50, 0x320, 0x94 + 0x18) != 0: # 出现了对话框 - left_click(320, 400) - thread_sleep_for(10) def select_seeds_and_lets_rock(seeds_selected=None): @@ -661,12 +623,8 @@ def update_seeds_list(): seeds_in_slot = [None] * (48 * 2) slot_seeds = [None] * 10 - if pvz_ver() != "1.2.0.1096": - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) - else: - slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) - slots_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18) + slots_count = read_memory("int", base_addr, off2, off3 + 0x144, 0x24) + slots_offset = read_memory("unsigned int", base_addr, off2, off3 + 0x144) for i in range(slots_count): seed_type = read_memory("int", slots_offset + 0x5C + i * 0x50) seed_imitater_type = read_memory("int", slots_offset + 0x60 + i * 0x50) @@ -751,12 +709,8 @@ def get_seed_by_index(index): # 更新卡槽格数和场景地图 def update_game_scene(): global slots_count, game_scene - if pvz_ver() != "1.2.0.1096": - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - game_scene = read_memory("int", 0x6A9EC0, 0x768, 0x554C) - else: - slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) - game_scene = read_memory("int", 0x731C50, 0x768 + 0x100, 0x554C + 0x18) + slots_count = read_memory("int", base_addr, off2, off3 + 0x144, 0x24) + game_scene = read_memory("int", base_addr, off2, off3 + 0x554C) info("更新卡槽格数 %d." % slots_count) info("更新场景地图 %s." % scenes[game_scene]) @@ -940,12 +894,8 @@ def update_cob_cannon_list(cobs=None): global cob_list, cob_index cob_list_tmp = [] - if pvz_ver() != "1.2.0.1096": - plants_count_max = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xB0) - plants_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xAC) - else: - plants_count_max = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xB0 + 0x18) - plants_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xAC + 0x18) + plants_count_max = read_memory("unsigned int", base_addr, off2, off3 + 0xB0) + plants_offset = read_memory("unsigned int", base_addr, off2, off3 + 0xAC) for i in range(plants_count_max): plant_dead = read_memory("bool", plants_offset + 0x141 + 0x14C * i) plant_crushed = read_memory("bool", plants_offset + 0x142 + 0x14C * i) @@ -1509,15 +1459,9 @@ def auto_collect(collect_items=None, interval_cs=12): info("启动自动收集线程.") while game_ui() == 3: - if pvz_ver() != "1.2.0.1096": - items_count = read_memory("int", 0x6A9EC0, 0x768, 0xF4) - items_count_max = read_memory("int", 0x6A9EC0, 0x768, 0xE8) - items_offset = read_memory("int", 0x6A9EC0, 0x768, 0xE4) - else: - items_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0xF4 + 0x18) - items_count_max = read_memory("int", 0x731C50, 0x768 + 0x100, 0xE8 + 0x18) - items_offset = read_memory("int", 0x731C50, 0x768 + 0x100, 0xE4 + 0x18) - + items_count = read_memory("int", base_addr, off2, off3 + 0xF4) + items_count_max = read_memory("int", base_addr, off2, off3 + 0xE8) + items_offset = read_memory("int", base_addr, off2, off3 + 0xE4) if items_count == 0: thread_sleep_for(interval_cs) continue @@ -1580,12 +1524,8 @@ def get_seeds_index(seed): seed %= 48 seed_indexes = [] - if pvz_ver() != "1.2.0.1096": - slots_count = read_memory("int", 0x6A9EC0, 0x768, 0x144, 0x24) - slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) - else: - slots_count = read_memory("int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18, 0x24) - slots_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18) + slots_count = read_memory("int", base_addr, off2, off3 + 0x144, 0x24) + slots_offset = read_memory("unsigned int", base_addr, off2, off3 + 0x144) for i in range(slots_count): seed_type = read_memory("int", slots_offset + 0x5C + i * 0x50) seed_imitater_type = read_memory("int", slots_offset + 0x60 + i * 0x50) @@ -1599,12 +1539,8 @@ def get_plants_croods(): 获取场上植物坐标. """ croods = [] - if pvz_ver() != "1.2.0.1096": - plants_count_max = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xB0) - plants_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0xAC) - else: - plants_count_max = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xB0 + 0x18) - plants_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0xAC + 0x18) + plants_count_max = read_memory("unsigned int", base_addr, off2, off3 + 0xB0) + plants_offset = read_memory("unsigned int", base_addr, off2, off3 + 0xAC) for i in range(plants_count_max): plant_dead = read_memory("bool", plants_offset + 0x141 + 0x14C * i) plant_crushed = read_memory("bool", plants_offset + 0x142 + 0x14C * i) @@ -1625,10 +1561,7 @@ def get_block_type(*crood): else: row, col = crood row, col = row - 1, col - 1 - if pvz_ver() != "1.2.0.1096": - return read_memory("int", 0x6A9EC0, 0x768, 0x168 + row * 0x04 + col * 0x18) - else: - return read_memory("int", 0x731C50, 0x768 + 0x100, 0x168 + 0x18 + row * 0x04 + col * 0x18) + return read_memory("int", base_addr, off2, off3 + 0x168 + row * 0x04 + col * 0x18) # 存冰位 @@ -1671,12 +1604,7 @@ def auto_fill_ice(spots=None, total=0x7FFFFFFF): global ice_spots, ice_total ice_spots = spots ice_total = total - - if pvz_ver() != "1.2.0.1096": - slots_offset = read_memory("unsigned int", 0x6A9EC0, 0x768, 0x144) - else: - slots_offset = read_memory("unsigned int", 0x731C50, 0x768 + 0x100, 0x144 + 0x18) - + slots_offset = read_memory("unsigned int", base_addr, off2, off3 + 0x144) ice_seeds_index = get_seeds_index("寒冰菇") # 获取所有寒冰菇卡片的下标 if ice_seeds_index == []: error("卡槽没有寒冰菇, 退出自动存冰.") @@ -1723,11 +1651,7 @@ def auto_fill_ice(spots=None, total=0x7FFFFFFF): break # 如果该位置无植物则尝试存冰 - if pvz_ver() != "1.2.0.1096": - sun = read_memory("int", 0x6A9EC0, 0x768, 0x5560) - else: - sun = read_memory("int", 0x731C50, 0x768 + 0x100, 0x5560 + 0x18) - + sun = read_memory("int", base_addr, off2, off3 + 0x5560) if sun < 75: thread_sleep_for(1) continue From 19822c060c42822519ffac218f454aa929c5d59c Mon Sep 17 00:00:00 2001 From: shiawasenahikari Date: Wed, 4 Sep 2024 20:15:00 +0800 Subject: [PATCH 8/8] =?UTF-8?q?20240904=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E5=8F=91=E7=82=AE=E6=97=B6=E6=9C=89=E6=A6=82=E7=8E=87=E7=82=B9?= =?UTF-8?q?=E5=88=B0=E9=92=B1=E5=AF=BC=E8=87=B4=E5=8F=91=E7=82=AE=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E7=9A=84=20bug=20=E4=BF=AE=E5=A4=8D=E4=BA=86=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E5=A4=A7=E6=B3=A2=E5=80=92=E8=AE=A1=E6=97=B6=E6=97=B6?= =?UTF-8?q?=E6=9C=89=E6=A6=82=E7=8E=87=E6=8A=9B=E5=87=BA=E2=80=9C=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E7=9B=B8=E5=AF=B9=E6=97=B6=E9=97=B4=200=E2=80=9D?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E7=9A=84=20bug=20=E6=96=B0=E5=A2=9E=20API:?= =?UTF-8?q?=20GetZombies=EF=BC=8C=E8=AF=BB=E5=8F=96=E7=89=B9=E5=AE=9A?= =?UTF-8?q?=E5=83=B5=E5=B0=B8=E5=9C=A8=E6=AF=8F=E4=B8=AA=E6=B3=A2=E6=AC=A1?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E5=8F=AA=E6=95=B0=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20API:=20Coffee=EF=BC=8C=E5=8F=82=E6=95=B0=E4=B8=AD?= =?UTF-8?q?=E5=85=81=E8=AE=B8=E6=8C=87=E5=AE=9A=E4=B8=B4=E6=97=B6=E7=82=B9?= =?UTF-8?q?=E5=86=B0=E5=9D=90=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pvz/__init__.py | 2 ++ pvz/extra.py | 48 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/pvz/__init__.py b/pvz/__init__.py index 4294849..162b3a1 100644 --- a/pvz/__init__.py +++ b/pvz/__init__.py @@ -53,6 +53,7 @@ ## 功能修改 from .extra import set_zombies as SetZombies +from .extra import get_zombies as GetZombies ## 选卡/更新炮列表 from .extra import select_seeds_and_lets_rock as SelectCards @@ -99,6 +100,7 @@ "PressKeys", # 功能修改 "SetZombies", + "GetZombies", # 选卡/更新炮列表 "SelectCards", "UpdatePaoList", diff --git a/pvz/extra.py b/pvz/extra.py index 8332a51..e0c3b50 100644 --- a/pvz/extra.py +++ b/pvz/extra.py @@ -306,6 +306,28 @@ def set_zombies(zombies=None, mode="极限刷怪"): error("未知刷怪模式: %s." % mode) +def get_zombies(zombie="红眼"): + """ + 检查指定的僵尸在本次选卡的每波里各出现多少只. + + @参数 zombie(str/int): 指定要查询的僵尸名字或代号. + + @返回值 (list[int]): 长度为 21 的数组. 下标 0 占位, + + 下标 1~20 依次对应指定的僵尸在对应波次里的出现数量. + """ + index = zombie_name_to_index(zombie) # 转换成数字 + z = read_memory("int", base_addr, off2, off3 + 0x6B4, array=1000) + counts = [0] * 21 # 20 波各出了多少只 + for i in range(20): # 共 20 波 + for j in range(50): # 每波 50 只 + if z[50 * i + j] == -1: + break + if z[50 * i + j] == index: + counts[i + 1] += 1 + return counts + + ### 选卡 # (50, 160) 为左上角卡片中心坐标 @@ -748,7 +770,7 @@ def safe_click(): 即右键单击左上角, 用于取消之前的 (可能未完成的) 操作以避免冲突. """ - right_click(0, 0) + right_click(40, 40) def click_seed(seed): @@ -1187,7 +1209,7 @@ def skip_cob_index(num): ### 直接发炮 # 炮身点击次数 -CLICK_COUNT = 3 +CLICK_COUNT = 9 # 无视内置炮列表直接指定炮位和落点 @@ -1311,15 +1333,13 @@ def until_relative_time_after_refresh(time_relative_cs, wave): until_countdown(refresh_trigger[wave - 1], is_huge_wave) # 计算实际倒计时数值 - _wave_countdown = wave_countdown() _huge_wave_countdown = huge_wave_countdown() - if is_huge_wave: - if _wave_countdown in (4, 5): - countdown = _huge_wave_countdown - else: - countdown = _wave_countdown - 5 + 750 + if not is_huge_wave: + countdown = wave_countdown() + elif _huge_wave_countdown > 0: + countdown = _huge_wave_countdown else: - countdown = _wave_countdown + countdown = wave_countdown() - 5 + 750 # 计算刷新时间点(倒计时变为下一波初始值时)的时钟数值 _game_clock = game_clock() @@ -1687,11 +1707,17 @@ def auto_fill_ice(spots=None, total=0x7FFFFFFF): info("停止自动存冰线程.") -def activate_ice(): +def activate_ice(spots=None): """ 点冰. 使用咖啡豆激活存冰, 优先点临时位. 该函数需要配合自动存冰线程 IceSpots() 使用. + + @参数 spots(list): 咖啡豆的放置位置. 函数会选中咖啡豆, 并按指定的坐标顺序依次尝试放置. + + 如空置, 则默认为调用 IceSpots() 时指定的存冰点的逆序. + + 指定该参数可激活未在 IceSpots() 指定的位置里存的冰. """ coffee_index = get_index_by_seed(35) # 咖啡豆位置 if coffee_index is None: @@ -1700,7 +1726,7 @@ def activate_ice(): mouse_lock.acquire() safe_click() click_seed(coffee_index) - for spot in reversed(ice_spots): # 优先点临时位 + for spot in spots or reversed(ice_spots): # 优先点临时位 row, col = spot row -= 0.3 # 咖啡豆 理想种植坐标偏上约 30px click_grid((row, col))