|  |  |  
 | 
                           
 刘国公 广南东路经略使 枢密直学士 ★★★★★★★★★★★★ ★★★
                                
    
                                           
   
   
 |  |  
 |  |  |  
 |  
 
 |  |  |  
 | 
  组别 |   经略使 |  
  级别 |   卫将军 |  
  好贴 |   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 
 
这样就完成了。 
 |  
| 
 |  
  |