三国志9内政系统之一:收益<==>金钱篇
作者:三国十
--------------------------------------------------------------------------------
三国9的内政系统,总的说来还算合理吧(我不怎么玩游戏,说得不对不要扔鸡蛋过来 ),本帖无意就此展开评论,只想定量地介绍一下收益与金钱的关系。(在继续阅读之前,假定你还有那么一点点的数学知识)。
首先,根据经验,基本上城市的收益越高,金钱收入也就越多;另外,城市的人口越多,金钱收入似乎也越多,因此可以认为城市的金钱收入是城市收益和城市人口(非兵役人口+兵役人口)的二元函数,可记为
金钱收入=f(城市收益,城市人口)
要考察这个函数关系有很多办法,其中之一就是数字试验。即使用游戏自带的修改功能分别改变收益和人口然后观察金钱收入的变化,最后数据拟合。然而,本帖的方法是从游戏程序汇编源代码入手,解读出其间的定量关系。
由于函数中有两个变量,不便同时考察,可以一个一个地进行。
一、金钱收入与城市收益的关系
首先假定人口是一个常量,那么金钱收入就变成收益的一个一元函数。用数据修改做过试验的朋友应该会发现,这个函数并不是单调递增的。关于这一点,翻看了一下精华区的帖子,首屠执行官已经提到过,当收益超过1300时金钱收入变成收益的减函数。他说的是s9普通版,我不知道普通版的具体极点,然而在PK1.01下,这个准确的数字是1250。也就是说,当收益<=1250时,金钱收入是收益的增函数;而当收益>1250时,金钱收入是收益的减函数。而且,做过数字试验的朋友应该会发现,这个函数还有两个零点:0和2500(意思就是:收益为0或2500时,金钱收入为0)。根据上面这些信息,很容易地想象出这个函数的图象。进一步猜测:这是一个二次函数,而且函数表达式应该是:
金钱收入=A*收益*(2500-收益)
再从汇编代码的角度来考察金钱收入与城市收益的关系(汇编代码及其详细注释见三)。将汇编代码翻译最原始的计算公式:
金钱收入=B*f1(收益)*f2(收益)
其中,
B=f(人口)
f1(收益)=0x10624DD3*(收益*3/2)/(2^32)/(2^6)
f2(收益)=0x68BD8BAD*(2500-收益)/(2^32)/(2^10)
或者合起来写成一大串
金钱收入=f(人口)*0x10624DD3*(收益*3/2)/(2^32)/64*0x68BD8BAD*(2500-收益)/(2^32)/(2^10)
把一些常数进行简记处理后就变成:
金钱收入=f(人口)*C*收益*(2500-收益)
这与前面猜测的公式是相符合的,这就是金钱收入与人口、收益的关系。
二、金钱收入与人口的关系
前面已经考察出人口固定的情况下,金钱收入是收益的二次函数,而且极点是1250。然而及钱收入人口的关系却不是那么直接。我没有做数字试验,因此不知道用数字试验绘制出来的金钱收入~人口的关系曲线是怎么样的。仅从汇编代码来查看,很难看出这个函数关系。
根据汇编代码逻辑,前面的人口因子基数B可以写成
B=f(人口)=g(人口)+0x258
关于g(人口)的计算,大概分成2步:
1. 计算出与(人口^1/2*2)这个数最接近而且是2的幂次的整数,记为c,这一步可以近似地认为是取人口数算数平方根的2倍;
2. 进行以下迭代:
1) t = c;
2) k = [人口数/c];
3) m = 人口数 mod c;
4) c = (k + t - m) / 2;
5) 若c < t则转1),否则迭代结束。
难就难在不知道这段迭代到底是什么含意,那位数值分析学得好的朋友来看看这个迭代是什么运算,若能看出,便可知道那个人口基数因子B与人口的函数关系式。关于金钱收入与人口的关系,其实只需要记住:人口越多越好。
三、计算金钱收入的汇编代码
s9PK1.01中计算金钱收入的汇编代码在0x43A5C0处,下面列出这些代码及其注释。前面的公式其实就是从这些代码翻译过来的。
; 43A5C0: 计算金钱收入的函数入口
; 函数原型:
; int CalcCityMoney( int );
; 入口参数:
; ecx:指向城市数据块的指针
43A5C0 push esi
43A5C1 mov esi, ecx
43A5C3 mov eax, dword ptr [esi]
43A5C5 push edi
43A5C6 call [eax + 0DCh]
; 上面的这个call指令调用一个子例程,那个子例程将城市兵役人口与非兵役人口相加以
; 得到城市人口数,并将人口数存于寄存器eax中返回
43A5CC push eax
43A5CD call [5FF31C]
;上面这个call指令实际上调用了SanCalc.dll中的一个计算函数(s9PK中涉及计算的代码几乎都在
; SanCalc.dll中)。该函数计算出一个人口因子基数,大概分两步计算,见二中的描述。这里不
; 再列出SanCalc.dll中的这个计算函数的汇编代码,有兴趣的朋友自己去查看。
43A5D3 mov edx, [esi]
43A5D5 mov edi, eax
43A5D7 add esp, 4
43A5DA mov ecx, esi
43A5DC add edi, 258h
43A5E2 call [edx + 0F0h]
; 上面的这个call指令调用一个子例程,该子例程读取城市收益,并存于eax中返回
;
; 下面的代码(从43A5E8到43A605)便是前面公式中f1(收益)函数的体现
;
43A5E8 imul edi, eax
; edi <= 人口因子基数*收益
43A5EB lea ecx, [edi * 2 + edi]
; ecx <= edi * 3
43A5EE shl ecx, 1
; ecx <= ecx / 2
43A5F0 mov eax, 10624DD3
43A5F5 imul ecx
; eax <= 10624DD3 * ecx
43A5F7 sar edx, 6
43A5FA mov eax, edx
43A5FC shr eax, 1F
43A601 mov edi, edx
; 至此,edi = f1(收益)
;
; 下面的代码(43A603至43A625)完成其余计算,此处从略。
;
四、如何修改
很多朋友关心的可能是如何修改商业上限、改动上限后如何使金钱不减少以及如何使较少的收益能够带来较多的金钱收入等问题。
1、如何改收益上限
默认情况下,收益上限<=1000。事实上,每个城市都有它的收益上限,可以在内存中修改。以西平为例,收益上限位于地址0x12F01FC处。比如要将西平的收益上限改为5000,那么可以在0x12F01FC处写入该数值(注意little endian)。其他城市怎么办?fpe大法……
2、如何改金钱收入的极值点
看了前面的公式,应该很容易明白,金钱收入~收益函数关系的极值点在收益=1250处。要改变这个极值点,只需要改动那个2500即可。这个数值在内存中位于0x43A60E处。找到这里,比如要想将极值点设成3000,那么就需要在0x43A60E那儿填入6000的数值(注意little endian)。
3、如何改变金钱收入~收益关系
其实2中的修改也会附带带来金钱收入~收益关系的修改。其实要想以较少的收益获得较高的金钱收入,改法有很多,自己回去查看前面的汇编代码,然后想想怎么改(举个例子,比如那些右移6的地方,让它少移一点,就可以增加)。
|