本帖最后由 shane007 于 2023-9-5 16:49 编辑 + u" I" @' Z4 |& g( n" |/ {9 k' B# y
7 n `/ Q2 _" b: y2 j
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
! Y8 e, b3 v+ r8 G' y0 l因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。/ W0 s5 k/ y) M8 z. o
https://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
7 \/ O) B. m$ Q* {第1处
/ `* v$ t6 C" [, i- void sub_451474(char *a1, ...)" ]3 }: Y y( k% Z _
- {% ?" k3 a u9 C9 u) r$ M7 |
- GLsizei v1; // eax
4 Q9 r* T, v4 }' r! f - char lists; // [esp+4h] [ebp-800h]
) _& l5 [, q6 g+ Z - va_list va; // [esp+810h] [ebp+Ch]% M7 n- j8 K" D4 {
- . z+ @" W' J s' F, t% i
- va_start(va, a1);
3 Z% y7 g [1 |- H. m - if ( a1 )& q3 W6 l: U* `8 A
- {
" l7 Q0 z* S% `7 w0 y - vsprintf(&lists, a1, va);
" i- t2 L$ J% d - glPushAttrib(0x20000u);' {( [% z) |) M+ i
- glListBase(base);) a0 c7 _* p& g# b" W$ u. P9 \7 O
- v1 = strlen(&lists);
+ ?# V2 A9 t0 T - glCallLists(v1, 0x1401u, &lists);6 Q& N& Z5 c% x" ]) r
- glPopAttrib();. T- u+ q! `/ v* a
- }2 D8 x5 {% ^, [& h
- }
复制代码
* `0 r3 p5 O1 Y% n
2 f5 L f' F" r0 @1 B! a4 B$ h. J7 _5 a6 \) |6 A! D3 O. x
第2处9 J! d) t! k, \8 `7 W3 K! z
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
; h! F5 T5 }. `( s9 A- q' U - {3 f2 F7 u9 ?7 x7 m4 p
- int v4; // eax
- U4 L/ D2 `( X% N+ q/ e' r; {1 } - GLsizei v5; // eax; j( M4 z5 m9 i6 c) W' B* U( b M2 C
- char lists; // [esp+4h] [ebp-800h]+ D% b# \% l$ i+ K- O
- va_list va; // [esp+81Ch] [ebp+18h]( J: q! L+ r" m
$ c/ C" u6 [8 _- va_start(va, a4);6 m, [! [3 s' {' G
- if ( a4 )4 s A% g+ }: y! t" _
- {4 [/ ~, _- Q/ G$ V' z6 `# b) b9 F2 E
- sub_44F8A0(a3);
7 {: u1 V& E8 S3 s - v4 = sub_40BB44();
5 Y6 H( E) ~# V4 I3 j2 R* r" { - glRasterPos2i(x, v4 - a2);/ Y) @7 _( i6 p* L1 d8 Q; Y0 ?
- vsprintf(&lists, a4, va);
- `/ v3 }, c$ Q/ W' O! F& U) a - glPushAttrib(0x20000u);. H, \4 D y4 X- E- p, [8 L6 b
- glListBase(base);
6 Z6 z3 T2 c- u - v5 = strlen(&lists);
& }% a/ v; i. i: p& i - glCallLists(v5, 0x1401u, &lists);9 Q5 U( y3 b# w, @' o
- glPopAttrib();7 k j! W! }% H2 P% R
- }( a+ m6 [* J4 y$ E4 v4 i, b5 h+ K7 y
- }
复制代码 $ t/ Z& c. Z1 B5 r) q& x. C, t
' R9 Y" r, X' e. d) Q
$ e5 R% A6 C4 u: s第3处
& Y1 S9 m2 D! k$ ?- 4 @' g: L# c7 K& e6 J" X
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)9 @1 u' Y# k6 |
- {
9 R) g& @5 x5 j" z - GLvoid *v7; // ST08_4
0 c/ D9 w5 _. e# ~1 e4 l - GLsizei v8; // eax
. P7 D. W- F( j7 N& C) X - int v9; // [esp+0h] [ebp-1018h]
0 q$ ?; r" e7 i( y: `4 L, L: q - char v10; // [esp+8h] [ebp-1010h]
$ ]: |0 T1 Y% T: a+ ` - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
0 t4 d( o6 R3 C# ~ - char v12[5]; // [esp+1013h] [ebp-5h]
z; j0 d& h M1 o: @6 t - va_list va; // [esp+103Ch] [ebp+24h]
0 _2 K8 C1 Q+ `7 | - 8 b" U; U2 r$ f! u. B4 o; n* D" g$ K, L, D
- va_start(va, a7);
: t& ?# P3 t; G - v9 = 1;
% N; \/ @# Q# V ~2 @5 i& {8 y - if ( a7 )! \0 [1 H1 i- a
- {' K+ N. m$ w( {) p& i
- vsprintf(&v10, a7, va);
& v, U0 y/ e/ _& q; i. h! f0 k+ s9 v" m - glPushAttrib(0x20000u);( Q5 k! F6 l W9 p9 r
- glListBase(base);
* F3 n8 N! J9 S& `7 j& O - lists = &v10;
$ u! H8 E" J2 G% P5 P# H" d+ u - do; y; j3 ^5 a: G. Y4 D* i' I; f6 [
- {
' J2 Y0 C- f, ?; h4 O - *(_DWORD *)&v12[1] = lists;. i4 g, U7 {% h5 O& x
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )0 _' @0 D7 }7 Q% F
- ++*(_DWORD *)&v12[1];& }# K* z) g$ r; y/ W
- v12[0] = **(_BYTE **)&v12[1]; H2 U% h, i3 v8 n8 x {/ ^) m3 O
- **(_BYTE **)&v12[1] = 0;% U1 v5 H v2 E
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )
, h# t6 i7 F. g8 _7 y( K - *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
; i; Y- {; s/ [$ V" M - y -= a5;
9 D [3 E" t- f" T, I. D - glRasterPos2i(*(_DWORD *)a4 + a1, y);
6 h+ R0 {( l: G7 R7 g& c - v7 = lists;" ^+ m3 p; P- @5 {
- v8 = strlen((const char *)lists);' ~# t9 Q' B- ]& P1 u
- glCallLists(v8, 0x1401u, v7);
' g5 g, S' O/ t. f2 Y& ^ - if ( v9 < a3 )
* ~# I" Y# K7 n M- {- ^ - a4 += 4;
# D: |: S5 m# w - ++v9;
1 Y* A) w% k1 X- Q/ q; y! V3 V - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1); U: ?8 g9 H7 P$ @7 ^/ @* c
- }
+ H6 i; C) w6 ?" Y- p" M. N - while ( v12[0] );; O5 a% K# C: `* q3 c) G
- glPopAttrib();$ ^' @- e& ]8 T8 L
- }
% ]- G: U* o) Y M. p( _ - }
2 v) u( U1 U) R
复制代码
# n* C" c, J5 Z5 C d调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_4518100 _- o3 J1 t8 [1 g
- M$ \1 E9 V' m4 V
- .text:004512B1 52 push edx ; char *
7 T* H+ P- m( b8 ^0 e - .text:004512B2 8B 45 30 mov eax, [ebp+base]
" X4 @8 N+ C" Y( l$ e) ^1 i. K - .text:004512B5 50 push eax ; base g4 @/ a! [* q" {
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
! N" b& C, y* C - .text:004512B9 51 push ecx ; int
2 R4 c' w8 g+ H% g. S! D - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]- O$ r8 D. C3 M+ `, r& E
- .text:004512BD 52 push edx ; int- Z7 ^7 d$ I- H' ?2 w4 i
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
( i& A+ L7 Y0 ^- L/ p/ A: }* v3 B2 y ? - .text:004512C1 50 push eax ; int
( X+ f& `% N9 `. U - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]3 X2 R- F& Y0 K
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
) q M* a7 H2 N7 z1 f$ V" [ - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]) N6 o+ |2 b' _! W6 {
- .text:004512CB 51 push ecx ; y
3 z% H O1 a1 J) Y' b2 I. V - .text:004512CC 8B 55 08 mov edx, [ebp+x]
# T" |9 j2 s: p - .text:004512CF 52 push edx ; int
* z& M& O! j) [5 _ - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 # W { z: T w4 X" e6 d
chatGPT整理过之后,如下: {# P! b) [& B+ N+ ]6 y! g
1 j" j, D7 ?# V% `- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)) `. O c4 T& u4 N) g) c
- {
0 j' a/ r! Y- j1 x) {" c - GLvoid *textData; // 存储字符数据的指针
, n6 G4 O. l: _, q: M) A - GLsizei textLength; // 字符数据的长度9 M8 h- ~* u1 M. e5 [
- int lineIndex; // 行索引0 ], M2 C, x2 Y
- char formattedText[5]; // 存储格式化后的字符数据
5 V' ~" N6 f5 w - GLvoid *currentLine; // 当前行的字符数据指针1 g+ I5 y8 w9 G1 @7 j
- char buffer[5]; // 字符数据缓冲区
' `' h- X4 _: _# q4 ` - va_list args; // 变长参数列表
/ G1 h1 m+ a9 p
9 F, s4 s- v/ }& T- va_start(args, text); // 初始化变长参数列表5 f$ N6 K8 o. E6 ~4 G' Y( J
- lineIndex = 1; // 初始化行索引为1
7 o+ B4 E: g( S$ ? - ( V: k$ \& g% X r8 S
- if (text) // 如果文本不为空( _% m0 M! e7 {& z P' b8 h0 e+ f
- {
; \/ n, o) Y( B3 _ - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中4 c, Z9 B7 W# j2 D
- glPushAttrib(0x20000u); // 推送OpenGL属性状态* |3 z. e+ v: K9 S3 \3 H
- glListBase(displayListBase); // 设置显示列表的基础值
* L; R& i F1 [8 i* R$ c" L - currentLine = formattedText; // 将currentLine指向formattedText的内存位置. w5 r4 T4 p: i8 q
- 3 d% N& \! w) w& p
- do
3 x$ _& K0 y A" v9 ]4 H6 @ - {
, c. E; q4 e1 B K - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
1 I7 _* I+ G# v, h2 q" u
2 `7 X& G. i! k. B& w% X. l5 u- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
# H0 Y5 i. C8 k. H1 ? - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
. @2 `: O' \5 ~2 }+ s U2 s" C - * ]0 O3 p, q" w0 y' g r
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素' O& G$ N; C4 G7 A5 M" y
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符2 @' \0 v* s$ n" i7 k3 j) ~
* w9 k4 T e' G' p- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
; \- Y2 q5 h9 u+ ~ - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符# c! Y, `6 T. d% w( S8 @: w) T
- % m$ L: O6 ~6 c4 \
- yOffset -= lineHeight; // 更新y坐标
0 d4 W- w) ~7 f; e - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置/ g0 {+ N1 W3 `! n, y
- textData = currentLine; // 将textData指向currentLine
9 {6 d0 \$ l1 ^/ F0 Z( S7 t) Z - textLength = strlen((const char *)textData); // 计算字符数据的长度6 h, V+ s2 J% E+ m* j
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
' N- V3 g2 A0 B# \# Y - & E- E8 T3 M% U& g
- if (lineIndex < numLines)0 v; X5 ?4 H2 @
- lineOffset += 4; // 更新lineOffset$ r9 m1 i' s& {- i1 Q, _
- ++lineIndex; // 递增行索引
' ?7 S3 P; d6 }; \ - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据! M' `, L/ b. b& | E3 r) i
- }* `9 Z) F; G& _% _9 y6 k
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环+ _4 J2 f) d0 E1 A
- glPopAttrib(); // 恢复OpenGL属性状态/ P7 \ P- S; w4 v9 `# G( }
- }
3 n/ [" J' @( O - }3 ~/ { }* U; x" J# @! F
复制代码 ' k4 d$ `& c i6 [: g
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
6 E. y/ _" z" \" I& g7 h& D; X
6 K$ t: S1 T; e& N% h3 o8 O* mint xOffset, 字幕的x坐标
) z: r) x3 Q% h# w" vGLint yOffset, 字幕的y坐标3 [2 L2 J) P5 @. g
int numLines, 字幕的行数(较长的字幕为2,一般为1)
1 I& F# `+ [( t( `& `int lineOffset, 这个需要再研究' K# E+ Q% D ~# W2 c
int lineHeight, 字体高度(或行高)
\/ }/ y: k) Z7 R1 IGLuint displayListBase, 这个字体对应的base值
3 }6 d# e& t* V# F( ]char *text, ... 字符串, o/ ?, X1 A( N6 H/ T; E
6 \) t1 }' { g/ w |