| 
|  |  |  |  |  | 刘国公
 广南东路经略使
 枢密直学士
 ★★★★★★★★★★★★
 ★★★
   
    
     |  |  |  |  |  |  |  |  
|  |  |  |  |  | 
|  组别 | 经略使 |  |  级别 | 卫将军 |  |  好贴 | 1 |  |  功绩 | 1314 |  |  帖子 | 6207 |  |  编号 | 111321 |  |  注册 | 2007-2-18 |  |  来自 | 我家 |  |  家族 | 轩辕学院 |  |  |  |  |  |  |  |  |  
 
 | 
|  |  | 最终方案的代码 
 
 首先将7项能力的升级值另外保存起来:004074A2   . E8 69140D00    CALL 004D8910
 
 004D8910   55               PUSH EBP
 004D8911   8BEC             MOV EBP,ESP
 004D8913   51               PUSH ECX
 004D8914   FF75 0C          PUSH DWORD PTR SS:[EBP+C]
 004D8917   FF75 08          PUSH DWORD PTR SS:[EBP+8]
 004D891A   E8 F8E4F2FF      CALL 00406E17
 004D891F   0FB655 08        MOVZX EDX,BYTE PTR SS:[EBP+8]
 004D8923   8B45 0C          MOV EAX,DWORD PTR SS:[EBP+C]
 004D8926   890495 50CA4800  MOV DWORD PTR DS:[EDX*4+48CA50],EAX
 004D892D   8BE5             MOV ESP,EBP
 004D892F   5D               POP EBP
 004D8930   C2 0800          RETN 8
 懒得找其他空的内存了,直接将48CA50开始的7*4个字节置零,每次有人升级的时候就会将7项能力的升级值存到这里。
 PS:这里是原来教学的文字部分。
 
 用武将说话来显示升级值:
 00407506   . 90             NOP
 00407507   . 90             NOP
 00407508   . 90             NOP
 00407509   . 90             NOP
 0040750A   . 90             NOP
 0040750B   . 90             NOP
 0040750C   . 90             NOP
 0040750D   . 90             NOP
 0040750E   . 90             NOP
 0040750F   . 8B4D E8        MOV ECX,DWORD PTR SS:[EBP-18]
 00407512   . E8 B9BF0200    CALL 004334D0
 00407517   . 90             NOP
 00407518   . 90             NOP
 00407519   . 90             NOP
 0040751A   . 90             NOP
 0040751B   . 90             NOP
 0040751C   . 90             NOP
 0040751D   . 90             NOP
 0040751E   . 90             NOP
 0040751F   . 90             NOP
 00407520   . 90             NOP
 00407521   . 90             NOP
 00407522   . 90             NOP
 00407523   . 90             NOP
 00407524   . 90             NOP
 
 004334D0  /$ 55             PUSH EBP
 004334D1  |. 8BEC           MOV EBP,ESP
 004334D3  |. 81EC 04040000  SUB ESP,404
 004334D9  |. 894D FC        MOV DWORD PTR SS:[EBP-4],ECX
 004334DC  |. E8 EF30FDFF    CALL 004065D0
 004334E1  |. 83C1 08        ADD ECX,8
 004334E4  |. 50             PUSH EAX                                 ; /Arg4
 004334E5  |. 51             PUSH ECX                                 ; |Arg3
 004334E6  |. 68 50B14800    PUSH 0048B150                      ; |Arg2 = 0048B150
 004334EB  |. 6A 02          PUSH 2                                   ; |Arg1 = 00000002
 004334ED  |. E8 A7C1FFFF    CALL 0042F699                      ; \WaGan.0042F699
 004334F2  |. 83C4 10        ADD ESP,10
 上面这部分是显示“某某升为N级”,我将这段代码从原来位置调了过来。
 004334F5  |. 8D8D FCFBFFFF  LEA ECX,DWORD PTR SS:[EBP-404]
 004334FB  |. 51             PUSH ECX                                 ; /Arg1
 004334FC  |. E8 AFFEFFFF    CALL 004333B0                      ; \WaGan.004333B0
 另外再写一个函数用来文字显示的准备工作。
 00433501  |. 8B4D FC        MOV ECX,DWORD PTR SS:[EBP-4]
 00433504  |. E8 F75FFDFF    CALL 00409500
 00433509  |. 50             PUSH EAX                                 ; /Arg2
 0043350A  |. 8D95 FCFBFFFF  LEA EDX,DWORD PTR SS:[EBP-404]           ; |
 00433510  |. 52             PUSH EDX                                 ; |Arg1
 00433511  |. B9 F05D4B00    MOV ECX,004B5DF0                   ; |
 00433516  |. E8 42610200    CALL 0045965D                      ; \WaGan.0045965D
 0043351B  |. 8BE5           MOV ESP,EBP
 0043351D  |. 5D             POP EBP
 0043351E  \. C3             RETN
 
 文字显示的准备工作。(另外还需要在原教学的文字部分写上一些固定的格式,见附图。)
 
 
 
  图片附件:  wagan.gif (2011-2-17 12:22, 4.77 K) 
 
  工作原理是先从固定格式中读取文字,并加上由能力值转化而成的能力显示数字,按照显示的顺序将所有文字存入一个临时地址中,即[EBP+8]所在的内存地址开始的一大段内存中,最后再从这一大段内存读取代码显示给玩家看。
 004333B0  /$ 55             PUSH EBP
 004333B1  |. 8BEC           MOV EBP,ESP
 004333B3  |. 83EC 0C        SUB ESP,0C
 004333B6  |. 33C0           XOR EAX,EAX
 004333B8  |. 8945 FC        MOV DWORD PTR SS:[EBP-4],EAX
 004333BB  |. EB 03          JMP SHORT 004333C0
 004333BD  |> FF45 FC        /INC DWORD PTR SS:[EBP-4]
 004333C0  |> 837D FC 07      CMP DWORD PTR SS:[EBP-4],7  因为有7项升级,所以需要循环7次。
 004333C4  |. 0F8D 60000000  |JGE 0043342A
 004333CA  |. 8B45 FC        |MOV EAX,DWORD PTR SS:[EBP-4]
 004333CD  |. 6BC0 10        |IMUL EAX,EAX,10
 004333D0  |. 05 70CA4800    |ADD EAX,0048CA70  每一个固定格式占用16个字节,加上起始地址48CA70就可以确定每个升级项的文字格式地址。
 004333D5  |. 8945 F8        |MOV DWORD PTR SS:[EBP-8],EAX
 004333D8  |> 8B4D F8        |/MOV ECX,DWORD PTR SS:[EBP-8]
 004333DB  |. 33C0           ||XOR EAX,EAX
 004333DD  |. 8A01           ||MOV AL,BYTE PTR DS:[ECX]  从文字固定格式中读取一个字节。
 004333DF  |. 85C0           ||TEST EAX,EAX  判断这个字节是否为00,是就要跳出这次循环。
 004333E1  |. 0F84 41000000  ||JE 00433428
 004333E7  |. 83F8 30        ||CMP EAX,30
 004333EA  |. 72 15          ||JB SHORT 00433401
 004333EC  |. 83F8 36        ||CMP EAX,36  该字节不为00,就要判断是否30--36这7个数值。小于或大于这一段的数值就要跳过。
 004333EF  |. 77 10          ||JA SHORT 00433401
 004333F1  |. FF75 08        ||PUSH DWORD PTR SS:[EBP+8]              ; /Arg2
 004333F4  |. FF75 FC        ||PUSH DWORD PTR SS:[EBP-4]              ; |Arg1
 004333F7  |. E8 54000000    ||CALL 00433450                    ; \WaGan.00433450
 另外再写一条函数,用来将上升/下降的能力值转化为文字显示,所以之前的30--36就是为了区分固定格式中的固定文字与随能力值变化的能力显示文字。
 004333FC  |. 8945 08        ||MOV DWORD PTR SS:[EBP+8],EAX
 004333FF  |. EB 1F          ||JMP SHORT 00433420
 00433401  |> 3C FC          ||CMP AL,0FC
 00433403  |. 75 16          ||JNZ SHORT 0043341B
 00433405  |. 8079 FF A1     ||CMP BYTE PTR DS:[ECX-1],0A1
 00433409  |. 75 10          ||JNZ SHORT 0043341B
 这里又是一个特殊的显示,A1FC是向上箭头,A1FD是向下箭头,这里是判断出是否读取到箭头这里。
 0043340B  |. 8B4D FC        ||MOV ECX,DWORD PTR SS:[EBP-4]
 0043340E  |. 8B148D 50CA480>||MOV EDX,DWORD PTR DS:[ECX*4+48CA50]
 00433415  |. 83FA 00        ||CMP EDX,0
 00433418  |. 7D 01          ||JGE SHORT 0043341B
 0043341A  |. 40             ||INC EAX
 这里是判断升级的能力值是否为负数,即HP和MP独有的下降情况,如果是负数,就将前面的FC加1就变成FD,也就是变成向下箭头了。
 0043341B  |> 8B55 08        ||MOV EDX,DWORD PTR SS:[EBP+8]
 0043341E  |. 8802           ||MOV BYTE PTR DS:[EDX],AL
 00433420  |> FF45 F8        ||INC DWORD PTR SS:[EBP-8]
 00433423  |. FF45 08        ||INC DWORD PTR SS:[EBP+8]
 00433426  |.^EB B0          |\JMP SHORT 004333D8
 00433428  |>^EB 93          \JMP SHORT 004333BD
 然后就是将从固定格式中读取出来的字符存入临时内存中,然后临时内存地址和固定格式地址均加一后跳回前面继续循环。
 0043342A  |> 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
 0043342D  |. C600 00        MOV BYTE PTR DS:[EAX],0
 最后所有循环都完成后,将最后一个字节置为00,表示完全结束。
 00433430  |. 8BE5           MOV ESP,EBP
 00433432  |. 5D             POP EBP
 00433433  \. C2 0400        RETN 4
 
 数值转化为文字字符函数:
 00433450  /$ 55             PUSH EBP
 00433451  |. 8BEC           MOV EBP,ESP
 00433453  |. 8B4D 08        MOV ECX,DWORD PTR SS:[EBP+8]
 00433456  |. 8B048D 50CA480>MOV EAX,DWORD PTR DS:[ECX*4+48CA50]  读取升降数值。
 0043345D  |. 50             PUSH EAX
 0043345E  |. 83F8 00        CMP EAX,0  判断是否为负数
 00433461  |. 7D 05          JGE SHORT 00433468
 00433463  |. F7D8           NEG EAX  负数要取反变回正数
 00433465  |. 8945 FC        MOV DWORD PTR SS:[EBP-4],EAX
 00433468  |> 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
 0043346B  |. 33D2           XOR EDX,EDX
 0043346D  |. B9 0A000000    MOV ECX,0A  除以10(如果等级过大会产生MP减少超过10点的,慎重起见还是加上这一段)
 00433472  |. F7F1           DIV ECX
 00433474  |. 85C0           TEST EAX,EAX  除10后,EAX的值相当于十位数,EDX的值相当于个位数,这里就判断升降数值是否超过10。
 00433476  |. 74 0B          JE SHORT 00433483
 00433478  |. 8B4D 0C        MOV ECX,DWORD PTR SS:[EBP+C]
 0043347B  |. 83C0 30        ADD EAX,30
 0043347E  |. 8801           MOV BYTE PTR DS:[ECX],AL
 00433480  |. FF45 0C        INC DWORD PTR SS:[EBP+C]
 00433483  |> 8B4D 0C        MOV ECX,DWORD PTR SS:[EBP+C]
 00433486  |. 83C2 30        ADD EDX,30
 00433489  |. 8811           MOV BYTE PTR DS:[ECX],DL
 然后十位和个位数值各加上30后保存到临时内存中。
 0043348B  |. 8B45 0C        MOV EAX,DWORD PTR SS:[EBP+C]
 0043348E  |. 8BE5           MOV ESP,EBP
 00433490  |. 5D             POP EBP
 00433491  \. C2 0800        RETN 8
 
 这样就完成了。
 |  |  |  |