标题: DOS版三国志英杰传的研究心得——叁, 部队在战场的数据
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 42
编号 545816
注册 2023-12-25


发表于 2025-2-22 19:19 资料 短消息 只看该作者
DOS版三国志英杰传的研究心得——叁

想必大家都曾经看过下面的分析,说实话迫切地想弄清楚下面内容在代码中的具体细节也是我当初想进行反汇编研究的研究方向之一,这一章内容就是在龙吟前辈在写出下面分析之后,时隔20余年之后再次让它们展示出来。

QUOTE:
偏移+00  占2字节  人物代码(刘备=0000,关羽=0001)
偏移+02  占1字节  战场代码(00=我军第1只部队、0E=我军第15只部队,0F=敌军第1只部队)
      (注:00-0E是我军,共15个位置,但不一定用完,0F-2C是敌军,共30个位置,但不一定用完)
偏移+03  占1字节  部队横坐标(以左上角为0,0)
偏移+04  占1字节  部队纵坐标
偏移+05  占1字节  仇人代码(FF表示没有仇人)
偏移+06  占2字节  目标横纵坐标(0000表示没有目标)
偏移+08  占1字节  不明
偏移+09  占1字节  部队撤退标志(00=消失 01=未出场 02=正常 04=撤退)
偏移+0A  占1字节  部队状态(从低位开始:第2位为1表示混乱,第3位为1表示全屏移动,第6位为0表示伏兵,第8位为1表示行动结束)
偏移+0B  占1字节  部队AI类型(见后)
偏移+0C  占1字节  部队士气
偏移+0D  占1字节  部队策略值

根据前面的分析,不难看出这也是存储在DS段的一块内存空间,可是龙吟前辈并没有写出这块内存空间的具体地址,还有空间究竟有多大,还有这些偏移以及数据的内容是如何得出的,这章就简单来分析一下这些内容。


顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 42
编号 545816
注册 2023-12-25


发表于 2025-2-22 19:19 资料 短消息 只看该作者
一、战场数据所在位置

这块地址的起始地址是DS: D076,每只在战场上的部队使用14字节的大小,一共45只部队,所以一共是14*45=630字节大小,从DS: D076到DS: D2EB这部分长达0x276大小的空间,存储的都是上面龙吟分析的内容。
接下来我们简要把上述的数据内容进行初步解释,比如说D076, 14, 45这样的数据都是怎么来的。
如何证明是上述的内容保存在D076是不容易的,因为需要花费大量的时间进行研究,而我们可以推测以DS: D076为起始,由此往后的0x276的大小的内存空间被占用,这是目前能分析出来的。
在IDAPro搜索常量(按下Alt+I)0xD076,可以在其中看到Instruction这一列代码中包含D076的代码,出现的比较频繁的语句一条语句是add ax, 0D076h。


图片附件: 搜索常量.png (2025-2-22 19:44, 7.47 K)




图片附件: 搜索结果.png (2025-2-22 19:44, 26.86 K)


我们在Address这一列中找到seg002:774B,点击就会弹到下面代码的位置。

seg002:7742 C6 46 FF 00                    mov     [bp+var_1], 0                           ;var_1=0...2C
seg002:7746                             loc_34666:                                                 ; CODE XREF: sub_3460C+98↓j
seg002:7746 B0 0E                          mov     al, 0Eh
seg002:7748 F6 66 FF                       mul     [bp+var_1]                              ; 部队战场代码
seg002:774B 05 76 D0                       add     ax, 0D076h
...
seg002:777D FE 46 FF                       inc     [bp+var_1]
seg002:7780 80 7E FF 2D                    cmp     [bp+var_1], 2Dh
seg002:7784 72 C0                          jb      short _for_loc_34666

从中不难看出这段代码是印证龙吟的部分分析,var_1代表循环的战场代码(0...2Ch)共45个战场代码,而从中的mov al, 0Eh可以看出,每个战场代码需要占用14字节大小的空间,而add ax, 0D076h表示这些数据都是从D076开始的。
seg002:7746 — seg002:774B就是其中计算部队战场数据的首地址的过程,可以列2个16进制的公式:
部队战场数据的首地址 = D076+部队战场代码*E
部队战场数据占用地址 = (D076+部队战场代码*E — D076+部队战场代码*E+D)
根据计算,部队战场代码为0部队占用地址是(D076 — D083 ),部队战场代码为1部队占用地址(D084 — D091 ),部队战场代码为F部队数据的首地址为D148,而部队战场代码为C部队占用地址(D2DE— D2EB ),可能有人会想要扩容其中的数据,但是DS: D075以及前面的地址和DS: D2EC以及后面的地址都保存数据,如果想扩容需要把其中的数据进行“搬移”,而且所需要修改的代码量相当大,并且有可能会有遗漏并且出现BUG。

[ 本帖最后由 漫漫苦短 于 2025-2-22 19:49 编辑 ]


顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 42
编号 545816
注册 2023-12-25


发表于 2025-2-25 19:19 资料 短消息 只看该作者
二、战场数据的简单方法(一)

第一节说明了在D076到D2EB之间的14*45字节的内容保存了其中部队在战场上的一些数据,并且通过各自的战场代码可以找到其占用地址以及连续的14字节,而龙吟前辈已经将这14字节对应的含义列举出来了,那么先看看这些数据是怎么被使用的,也就是它们的一些方法。

首先最简单的,就是每一项数据需要拿到(Get)和设置(Set),下列介绍部分数据的这两个方法。

以下未说明,arg_0的值都是以D076为首项,D(14)为公差,2D(45)为项数的一个十六进制下的等差数列中的一个地址值,就是说arg_0的值并不是唯一的,不像前一章介绍的CF6A,它的值可以有变动,但是这些函数的意义都是类似的。

部队人物代码的Get方法,注意一下 mov ax, [bx]和 mov ax, bx的区别,前者是将bx这个地址的保存的数据的值传给ax,后者是将bx的值传给ax。
例如bx为D076,mov ax, [bx]就是将bx地址所在的人物代码传给ax,mov ax, bx就是让ax也变为D076。

seg002:4062                sub_30F82 proc far
seg002:4062                arg_0           = word ptr  6
seg002:4062
seg002:4062 55                             push    bp
seg002:4063 8B EC                          mov     bp, sp
seg002:4065 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:4068 8B 07                          mov     ax, [bx]
seg002:406A C9                             leave
seg002:406B CA 02 00                       retf    2
seg002:406B                sub_30F82 endp

部队仇人代码的两个方法

seg002:93A6                sub_362C6 proc far
seg002:93A6                arg_0           = word ptr  6
seg002:93A6
seg002:93A6 55                             push    bp
seg002:93A7 8B EC                          mov     bp, sp
seg002:93A9 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:93AC 8A 47 05                       mov     al, [bx+5]
seg002:93AF C9                             leave
seg002:93B0 CA 02 00                       retf    2
seg002:93B0                sub_362C6 endp

seg002:93B4                sub_362D4 proc far
seg002:93B4
seg002:93B4                arg_0           = word ptr  6
seg002:93B4                arg_2           = byte ptr  8
seg002:93B4
seg002:93B4 55                             push    bp
seg002:93B5 8B EC                          mov     bp, sp
seg002:93B7 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:93BA 8A 46 08                       mov     al, [bp+arg_2]
seg002:93BD 88 47 05                       mov     [bx+5], al
seg002:93C0 C9                             leave
seg002:93C1 CA 04 00                       retf    4
seg002:93C1                sub_362D4 endp

部队撤退标志的两个方法

seg002:40D8                sub_30FF8 proc far
seg002:40D8
seg002:40D8                arg_0           = word ptr  6
seg002:40D8                arg_2           = byte ptr  8
seg002:40D8
seg002:40D8 55                             push    bp
seg002:40D9 8B EC                          mov     bp, sp
seg002:40DB 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:40DE 8A 46 08                       mov     al, [bp+arg_2]
seg002:40E1 88 47 09                       mov     [bx+9], al
seg002:40E4 C9                             leave
seg002:40E5 CA 04 00                       retf    4
seg002:40E5                sub_30FF8 endp

seg002:40E8                sub_31008 proc far
seg002:40E8                arg_0           = word ptr  6
seg002:40E8
seg002:40E8 55                             push    bp
seg002:40E9 8B EC                          mov     bp, sp
seg002:40EB 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:40EE 8A 47 09                       mov     al, [bx+9]
seg002:40F1 C9                             leave
seg002:40F2 CA 02 00                       retf    2
seg002:40F2                sub_31008 endp

部队AI类型的两个方法

seg002:410E                sub_3102E proc far
seg002:410E
seg002:410E                arg_0           = word ptr  6
seg002:410E
seg002:410E 55                             push    bp
seg002:410F 8B EC                          mov     bp, sp
seg002:4111 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:4114 8A 47 0B                       mov     al, [bx+0Bh]
seg002:4117 C9                             leave
seg002:4118 CA 02 00                       retf    2
seg002:4118                sub_3102E endp

seg002:7C4A                sub_34B6A proc far
seg002:7C4A
seg002:7C4A                arg_0= word ptr  6
seg002:7C4A                arg_2= byte ptr  8                       ;部队AI类型
seg002:7C4A
seg002:7C4A 55                             push    bp
seg002:7C4B 8B EC                          mov     bp, sp
seg002:7C4D 80 7E 08 07                    cmp     [bp+arg_2], 7
seg002:7C51 77 09                          ja      short locret_34B7C             ;arg_2大于7,是不合法的AI类型,跳出函数
seg002:7C53 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:7C56 8A 46 08                       mov     al, [bp+arg_2]
seg002:7C59 88 47 0B                       mov     [bx+0Bh], al
seg002:7C5C
seg002:7C5C                locret_34B7C:                                                   ; CODE XREF: sub_34B6A+7↑j
seg002:7C5C C9                             leave
seg002:7C5D CA 04 00                       retf    4
seg002:7C5D                sub_34B6A endp

部队策略值一个方法,还有两个方法,一个是计算最大策略值,就是导致94智力值的部队到99级策略值为0的那个,还有一个是补充策略值的方法,这两个方法到时候再介绍。

[code]
seg002:406E                sub_30F8E proc far
seg002:406E
seg002:406E                arg_0           = word ptr  6
seg002:406E                arg_2           = byte ptr  8
seg002:406E
seg002:406E 55                             push    bp
seg002:406F 8B EC                          mov     bp, sp
seg002:4071 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:4074 8A 46 08                       mov     al, [bp+arg_2]
seg002:4077 88 47 0D                       mov     [bx+0Dh], al
seg002:407A C9                             leave
seg002:407B CA 04 00                       retf    4
seg002:407B                sub_30F8E endp

很神奇的一点是,我暂时没有找到并没有部队策略值的Get方法,因为在程序的代码中都是直接获取的,并没有单独构造出一个函数,见以下两个例子。

seg002:8FF2 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:8FF5 8A 47 0D                       mov     al, [bx+0Dh]



seg002:A4D2 8B 76 06                       mov     si, [bp+arg_0]
...
seg002:A510 8A 44 0D                       mov     al, [si+0Dh]

部队战场坐标的Get方法,准确来说是取一个偏移地址。

seg002:409C                sub_30FBC proc far                               ; CODE XREF: _InitBattle_sub_2FB7A+25B↑P ...
seg002:409C
seg002:409C                arg_0           = word ptr  6
seg002:409C
seg002:409C 55                             push    bp
seg002:409D 8B EC                          mov     bp, sp
seg002:409F 8B 46 06                       mov     ax, [bp+arg_0]
seg002:40A2 05 03 00                       add     ax, 3
seg002:40A5 C9                             leave
seg002:40A6 CA 02 00                       retf    2
seg002:40A6                sub_30FBC endp

然后在函数外获得这个地址保存的具体坐标值数据,见以下两个例子

seg002:2EB2 68 76 D0                       push    0D076h
seg002:2EB5 9A 9C 40 F2 2C                 call    sub_30FBC                ; 获取我军主将战场坐标偏移地址
seg002:2EBA 8B D8                          mov     bx, ax
seg002:2EBC 8B 07                          mov     ax, [bx]



seg002:3008 B0 0E                          mov     al, 14
seg002:300A F6 66 FF                       mul     [bp+var_1]                  ; 部队战场代码
seg002:300D 05 76 D0                       add     ax, 0D076h
seg002:3010 89 46 F8                       mov     [bp+var_8], ax
seg002:3013 50                             push    ax
seg002:3014 9A 9C 40 F2 2C                 call    sub_30FBC                ; 获取部队横纵坐标偏移地址
seg002:3019 8B D8                          mov     bx, ax
seg002:301B 8B 07                          mov     ax, [bx]

注意D076地址放的不一定是劉備的数据,虽然这个地址战场代码是0,但是劉備也不是每一战都出,不过劉備出的每一战战场代码都是0。

[ 本帖最后由 漫漫苦短 于 2025-3-1 19:19 编辑 ]
顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 42
编号 545816
注册 2023-12-25


发表于 2025-3-1 19:19 资料 短消息 只看该作者
三、战场数据的简单方法(二)

上节讲了人物代码、仇人代码、撤退标志、AI类型、策略值、战场坐标偏移地址的最简单方法,从这些方法是看不出来的它们的含义的,这节介绍的这几个方法,或许能从它们的代码中窥见其中的奥秘。

以下未说明,arg_0的值都是以D076为首项,D(14)为公差,2D(45)为项数的一个十六进制下的等差数列中的一个地址值。
一个是部队的战场代码,就是0-2C中的一个值。

seg002:AE9A                sub_37DBA proc far
seg002:AE9A
seg002:AE9A                arg_0           = word ptr  6
seg002:AE9A
seg002:AE9A 55                             push    bp
seg002:AE9B 8B EC                          mov     bp, sp
seg002:AE9D 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:AEA0 8A 47 02                       mov     al, [bx+2]
seg002:AEA3 C9                             leave
seg002:AEA4 CA 02 00                       retf    2
seg002:AEA4                sub_37DBA endp

这时就需要引出关键问题了,游戏是如何是如何根据战场代码判断是这支部队是我方(我军加友军)还是敌方。

seg002:40F6                sub_31016 proc far
seg002:40F6
seg002:40F6                arg_0           = word ptr  6
seg002:40F6
seg002:40F6 55                             push    bp
seg002:40F7 8B EC                          mov     bp, sp
seg002:40F9 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:40FC 80 7F 02 0F                    cmp     byte ptr [bx+2], 0Fh                    ; 比较部队战场代码与0F
seg002:4100 72 04                          jb      short loc_31026                         ; 无符号小于跳转
seg002:4102 33 C0                          xor     ax, ax                                  ; 返回0,属于敌军
seg002:4104 EB 03                          jmp     short locret_31029
seg002:4106                loc_31026:                                                      ; CODE XREF: sub_31016+A↑j
seg002:4106 B8 01 00                       mov     ax, 1                                   ; 返回1,属于我军
seg002:4109                locret_31029:                                                   ; CODE XREF: sub_31016+E↑j
seg002:4109 C9                             leave
seg002:410A CA 02 00                       retf    2
seg002:410A                sub_31016 endp

这段就可以简单地印证以上龙吟前辈的结论:

QUOTE:
(注:00-0E是我军,共15个位置,但不一定用完,0F-2C是敌军,共30个位置,但不一定用完)

但其实还有一个小问题,英杰传存在战场倒戈的情形,有的敌军会变成我军,战场代码到底会不会改变,那么是不是这个函数就不适用了。我们先提出两个设想:

  1. 敌军即我军,这些敌军的战场代码一开始就是我军(0-E),只是在敌军回合被操作,某种意义上来说这是个“友军”。
  2. 一开始就属于敌军,战场代码一开始是敌军(F-2C),在倒戈后战场代码为我军(0-E)。

1的设想与未倒戈敌军的实际情况不符合,未倒戈敌军在敌军中并不特殊,比如说这种敌军获取经验的方式是敌军的方式(只有策略才能获得),如果加上特殊判断就太多余了,不过能印证上我军的包括倒戈的人从来就没有超过15人的缘故,而且使用剧情修改器也无法实现超出15人吧,雒II为啥就只倒戈了吴兰和李严,吴懿雷铜费观不是不想倒戈拿经验,实在是劉備军中位置不够
2的设想能解决1中未倒戈敌军在敌军中行为正常的情况,但反而不能印证上面的问题了。

实际上,英杰传使用了第3种方式,在2的基础上还有加上一个过程,这里先暂时不叙述,以后还会给出说明的,评论也可以给出一些猜想。

接下来是士气值的2个方法。

获取士气值

seg002:9398                sub_362B8 proc far
seg002:9398
seg002:9398                arg_0           = word ptr  6
seg002:9398
seg002:9398 55                             push    bp
seg002:9399 8B EC                          mov     bp, sp
seg002:939B 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:939E 8A 47 0C                       mov     al, [bx+0Ch]
seg002:93A1 C9                             leave
seg002:93A2 CA 02 00                       retf    2
seg002:93A2                sub_362B8 endp

士气值变动的一部分代码。

seg002:7B7E                sub_34A9E proc far
seg002:7B7E
seg002:7B7E                var_1           = byte ptr -1
seg002:7B7E                arg_0= word ptr  6
seg002:7B7E                arg_2= word ptr  8                   ;新士气值
seg002:7B7E
seg002:7B7E C8 02 00 00                    enter   2, 0
seg002:7B82 8B 5E 06                       mov     bx, [bp+arg_0]
seg002:7B85 8B 56 08                       mov     dx, [bp+arg_2]
seg002:7B88 8A 47 0C                       mov     al, [bx+0Ch]
seg002:7B8B 88 46 FF                       mov     [bp+var_1], al                   ; var_1保存原士气值
seg002:7B8E 0B D2                          or      dx, dx                                  ; 判断新士气值是不是小于0
seg002:7B90 7D 06                          jge     short loc_34AB8                         ; 有符号大于等于跳转
seg002:7B92 C6 47 0C 00                    mov     byte ptr [bx+0Ch], 0                    ; 新士气值设为0
seg002:7B96 EB 0E                          jmp     short loc_34AC6
seg002:7B98                loc_34AB8:                                                      ; CODE XREF: sub_34A9E+12↑j
seg002:7B98 83 FA 64                       cmp     dx, 100                                 ; 判断新士气值是不是大于100
seg002:7B9B 7E 06                          jle     short loc_34AC3                         ; 有符号大于等于跳转
seg002:7B9D C6 47 0C 64                    mov     byte ptr [bx+0Ch], 100                  ; 新士气值设为100
seg002:7BA1 EB 03                          jmp     short loc_34AC6
seg002:7BA3                loc_34AC3:                                                      ; CODE XREF: sub_34A9E+1D↑j
seg002:7BA3 88 57 0C                       mov     [bx+0Ch], dl                            ; 修改部队战场数据的士气值
seg002:7BA6                loc_34AC6:
seg002:7BA6 8A 46 FF                       mov     al, [bp+var_1]
seg002:7BA9 2A E4                          sub     ah, ah
seg002:7BAB 3B C2                          cmp     ax, dx                                  ; 比较原士气值和新士气值
seg002:7BAD 7E 1D                          jle     short loc_34AEC                         ; 有符号小于等于跳转
seg002:7BAF 83 FA 1E                       cmp     dx, 30                                  ; 比较新士气值与30
seg002:7BB2 73 2E                          jnb     short locret_34B02                      ; 无符号不小于跳转
seg002:7BB7 9A E0 3D F6 1C                 call    sub_20D40                               ; 0-4混亂随机数
seg002:7BBC 3C 03                          cmp     al, 3                                   ; 比较随机数与3
seg002:7BBE 73 22                          jnb     short locret_34B02                      ; 无符号不小于跳转
...           ;隐藏的内容为部队陷入混亂的代码
seg002:7BCA EB 16                          jmp     short locret_34B02
seg002:7BCC                loc_34AEC:                                                      ; CODE XREF: sub_34A9E+2F↑j
seg002:7BCC 8A 46 FF                       mov     al, [bp+var_1]
seg002:7BCF 2A E4                          sub     ah, ah
seg002:7BD1 3B C2                          cmp     ax, dx                                  ; 比较原士气值和新士气值
seg002:7BD3 7C 05                          jl      short loc_34AFA              ; 有符号小于则跳转
seg002:7BD5 83 FA 64                       cmp     dx, 100                                 ; 判断新士气值是不是100
seg002:7BD8 75 08                          jnz     short locret_34B02
seg002:7BDA                loc_34AFA:                                           ; CODE XREF: sub_34A9E+55↑j
...           ;隐藏的内容为部队混乱恢复的代码
seg002:7BE2                locret_34B02:
seg002:7BE2 C9                             leave
seg002:7BE3 CA 04 00                       retf    4
seg002:7BE3                sub_34A9E endp

[ 本帖最后由 漫漫苦短 于 2025-3-1 19:39 编辑 ]
顶部
性别:未知-离线 漫漫苦短

Rank: 1
组别 百姓
级别 在野武将
功绩 0
帖子 42
编号 545816
注册 2023-12-25


发表于 2025-3-2 19:19 资料 短消息 只看该作者
四、战场数据的简单方法(三)

接下来介绍的就是要和前章内容有所联动的,如果有看不明白的可以复习一下以前的知识点。

seg002:AFB2                sub_37ED2 proc far
seg002:AFB2 57                             push    di
seg002:AFB3 56                             push    si
seg002:AFB4 8B F3                          mov     si, bx                                  ; bx=部队横纵坐标地址
seg002:AFB6 8A 04                          mov     al, [si]
seg002:AFB8 38 06 68 CF                    cmp     byte_4D738, al            ; 比较地图W与部队横坐标X
seg002:AFBC 76 2C                          jbe     short loc_37F0A               ; 无符号小于等于跳转
seg002:AFBE A0 69 CF                       mov     al, byte_4D739
seg002:AFC1 38 44 01                       cmp     [si+1], al                              ; 比较部队纵坐标Y与地图H
seg002:AFC4 73 24                          jnb     short loc_37F0A               ; 无符号不小于跳转
seg002:AFC6 68 08 55                       push    5508h
seg002:AFC9 9A 08 1D F6 1C                 call    sub_1EC68
seg002:AFCE 5B                             pop     bx
seg002:AFCF 8E C2                          mov     es, dx
seg002:AFD1 8B D8                          mov     bx, ax
seg002:AFD3 8A 04                          mov     al, [si]                                ; X
seg002:AFD5 2A E4                          sub     ah, ah
seg002:AFD7 03 D8                          add     bx, ax
seg002:AFD9 80 C7 0F                       add     bh, 0Fh
seg002:AFDC 8A 44 01                       mov     al, [si+1]                              ; Y
seg002:AFDF F6 26 68 CF                    mul     byte_4D738
seg002:AFE3 8B F8                          mov     di, ax                                  ; di=W*Y
seg002:AFE5 26 8A 01                       mov     al, es:[bx+di]                          ; 部队地形代码 es{5508}:[W*Y+X+0F00h]
seg002:AFE8 EB 02                          jmp     short loc_37F0C
seg002:AFEA                loc_37F0A:                                            ; CODE XREF: sub_37ED2+A↑j sub_37ED2+12↑j
seg002:AFEA B0 FF                          mov     al, 0FFh
seg002:AFEC
seg002:AFEC                loc_37F0C:                                                      ; CODE XREF: sub_37ED2+36↑j
seg002:AFEC 5E                             pop     si
seg002:AFED 5F                             pop     di
seg002:AFEE CB                             retf
seg002:AFEE                sub_37ED2 endp

byte_4D738和byte_4D739就是用到了第二章的内容

总体来进行分析吧,seg002:AFB4到seg002:AFC4中是这个函数的第一部分,这部分内容就是看传入bx这个部队横纵坐标地址的数据是否合法,就是说横纵坐标不能大于这个地图的W和H。
如果数据合法就执行第二部分seg002:AFC6到seg002:AFE8,这部分注意seg002:AFD9 add bh, 0Fh,bh加0Fh,但后面是+0F00h,就像是一个十进制两位数AB,给A加1,新的数实际上是加10,而单字节寄存器BH和BL构成双字节寄存器BX,BH加1,BX就增加100h。最后AL返回对应的地形代码。
而数据不合法,执行第三部分seg002:AFEA这一行,AL返回FF。

有了这个函数的基础,还可以介绍下面这个函数。

seg002:AEEA                sub_37E0A       proc far
seg002:AEEA 9A B2 AF F2 2C                 call    sub_37ED2
seg002:AEEF 3C 08                          cmp     al, 8                                   ; 08村莊
seg002:AEF1 74 0C                          jz      short loc_37E1F
seg002:AEF3 3C 0D                          cmp     al, 0Dh                                 ; 0D鹿砦
seg002:AEF5 74 08                          jz      short loc_37E1F
seg002:AEF7 3C 0E                          cmp     al, 0Eh                                 ; 0E兵營
seg002:AEF9 74 04                          jz      short loc_37E1F
seg002:AEFB 33 C0                          xor     ax, ax
seg002:AEFD EB 03                          jmp     short locret_37E22
seg002:AEFF                loc_37E1F:
seg002:AEFF B8 01 00                       mov     ax, 1
seg002:AF02
seg002:AF02                locret_37E22:                                                   ; CODE XREF: sub_37E0A+13↑j
seg002:AF02 CB                             retf
seg002:AF02                sub_37E0A       endp

seg002:AEEA这句先横纵坐标地址获取对应的地形代码。seg002:AEEF到seg002:AEF9依次判断这个地形代码是不是08村莊0D鹿砦0E兵營,如果是其中一个就跳到seg002:AEFF这行执行返回1,而都不是就不跳转seg002:AEFB这行执行返回0。
这里有个疑问,是部分把对应的地形代码修改,就能实现在不同的地形实现回合初兵力和士气值的自动恢复。其一,不仅仅可以修改这其中的地形代码,还能修改三个jz的比较,可以修改为jnz, ja, jb, jbe, jnb等等,这样就有可能实现不仅仅识别三个地形,可以识别一个区间的地形加上另一个地形,或者一个区间中减去其中一个地形,这样就能实现更丰富的修改;其二就是泼个冷水了,这个函数很明显没有区分村莊鹿砦恢复兵力和士气值而兵營只回复兵力的实际情况,因为这三种地形都是返回1,如果真的仅仅改了这部分,那么只会敌军的行为发生改变。
实际上,这个函数的判断被两个部分的函数使用,一是前辈们总结的敌军和友军的行动顺序中的第一行动梯队——村莊鹿砦兵營中的部队,那部分需要这个函数的判断部队是否在村莊鹿砦兵營,二是龙吟的分析结果中会在行动价值额外加50中判断地图中是否有可恢复地形,用这个函数判断这些某一个坐标是否满足其中的条件。
所以如果仅仅修改这个函数,有可能只是让敌军扎堆在某个地形,而对应地形没有回复的话,部队只是会提前行动而不会离开这个地形等等情况。

[ 本帖最后由 漫漫苦短 于 2025-3-2 19:48 编辑 ]
顶部

正在浏览此帖的会员 - 共 1 人在线




当前时区 GMT+8, 现在时间是 2025-4-2 05:46
京ICP备2023018092号 轩辕春秋 2003-2023 www.xycq.org.cn

Powered by Discuz! 5.0.0 2001-2006 Comsenz Inc.
Processed in 0.013471 second(s), 9 queries , Gzip enabled

清除 Cookies - 联系我们 - 轩辕春秋 - Archiver - WAP