石器时代宠物转身的原理(源代码分析)

2018-01-30 15:50:12 石器时代电脑版PC端(已停运) 网站编辑

第一个函数:
int PETTRANS_PetTransManStatus( int toindex, int petindex1, int petindex2)
{
        int petrank=0,i;
        int total1,total2,total,petLV,ans;
        int petID,enemynum,ret=-1;
        int work[4]={0,0,0,0};
        int base[4]={0,0,0,0};

#define RAND(x,y)   ((x-1)+1+ (int)( (double)(y-(x-1))*rand()/(RAND_MAX+1.0)) )
        total1 = PETTRANS_getPetBase( petindex1, work, &petrank);
        total2 = PETTRANS_getPetBase( petindex2, base, &petrank);
        petLV        = CHAR_getInt( petindex2, CHAR_LV);
//======================第一部分===================================
#ifdef _PET_2TRANS
        ans = NPC_PetTransManGetAns( total1, total2, petLV, petrank, CHAR_getInt( petindex2, CHAR_TRANSMIGRATION ) );
#else
        ans = NPC_PetTransManGetAns( total1, total2, petLV, petrank );
#endif
//=========================================================

        total = total1 + (total2*4);
        total2 = 0;
        for( i=0; i<4; i++)        {
                work = work*4;
                total2 += work;
        }
        total = total1 + total2;
        for( i=0; i<4; i++)        {
                base = (ans * (base+work)) /total;
        }
        enemynum = ENEMY_getEnemyNum();
        petID = CHAR_getInt( petindex2, CHAR_PETID);
        for( i=0; i<enemynum; i++)        {
                if( ENEMY_getInt(i, ENEMY_TEMPNO) == petID )
                        break;
        }
        if( i == enemynum )
                return -1;

        ret = GetNewPet( toindex, petindex2, i, base);        if( ret < 0 )
                return -1;
        return ret;
}
这个函数大致上应该是宠物转生的入口函数,从第一部分红色代码就可以判断,这段代码判断是一转还是二转,我们现在只研究一转的情况.
ans = NPC_PetTransManGetAns( total1, total2, petLV, petrank );
从这个ans不用说,是一个影响转身的系数,从它后面的用法可以看得出,而toital1和total2代表的大致是MM和转宠的一个什么合值,后面有分析.petLv不用说代表宠的等级,petRank代表的大致是宠物的成长方面的东西,rank代表的是成长方面的数值,这个后面有分析.

接下来我们再看后面这段:
total = total1 + (total2*4);
        total2 = 0;
        for( i=0; i<4; i++)        {
                work = work*4;
                total2 += work;
        }
        total = total1 + total2;
        for( i=0; i<4; i++)        {
                base = (ans * (base+work)) /total;
        }
这里有两个关键变量,一个是total1,一个是total2,从这段代码推测:
total1 = PETTRANS_getPetBase( petindex1, work, &petrank);
total2 = PETTRANS_getPetBase( petindex2, base, &petrank);
total1和total2分别传入了petindex1,和petindex2.petindex不用说,都代表一个宠物的指针,也就是可以这个宠物的代号,那么至少可以说明,这两个total,一个代表人宠,一个代表转生宠.

再看这句:
for( i=0; i<4; i++)        {
                work = work*4;
                total2 += work;
        }
        total = total1 + total2;
for( i=0; i<4; i++)        {
                base = (ans * (base+work)) /total;
        }
base是一个int数组,经我研究,这个数组是4位长,从0-3的下标,分别代表:血,攻,防,敏.看这段代码就知道:
//最终启动的转身函数
ret = GetNewPet( toindex, petindex2, i, base);
//=============
(这个base最终被当作一个参数传给了GetNewPet,GetNewPet不用说,就代表了获取新的宠物的函数)再看GetNewPet的定义中
int GetNewPet( int toindex , int petindex, int array, int *work)
{
     ......前面的先省略
     work[0] += ( RAND(0,4) - 2 );
     work[1] += ( RAND(0,4) - 2 );
     work[2] += ( RAND(0,4) - 2 );
     work[3] += ( RAND(0,4) - 2 );
  ///而参数work,刚好就是前面传入的base数组
     CHAR_setInt( petindex, CHAR_VITAL, ( PARAM_CAL(E_T_BASEVITAL) * work[0] ));
    CHAR_setInt( petindex, CHAR_STR , ( PARAM_CAL(E_T_BASESTR) * work[1] ));
    CHAR_setInt( petindex, CHAR_TOUGH , ( PARAM_CAL(E_T_BASETGH) * work[2] ));
    CHAR_setInt( petindex, CHAR_DEX , ( PARAM_CAL(E_T_BASEDEX) * work[3] ));
   //看到没,char_serInt,字面上的意思,就是character_setInital,也就是特征初始化,work[0]对应BASEVITAL,work[1]对应BASESTR,work[2]对应BASETGH,work[3]对应BASEDEX,很显然,BASEVITAL就是基本血量,BASESTR就是基本攻击力,BASEDEX就是基本敏捷,BASETGH虽然我不太理解TGH的意思,但不用说就是指防御了.
}
所以,base = (ans * (base+work)) /total;就是关键,按这个公式,ans越大越好,而total却并不一定越小越好,为什么,再看ans的获取代码:
int NPC_PetTransManGetAns( int total1, int total2, int LV, int rank )
#endif
{
        int ans=0 , TransLV = 100;
        float total = 0.00;
        int Fx=1;

        if( LV > 130 ) LV = 130;
        total = ( (float)total1/100 ); // 嚎立程蔼 total1=200
        total = total*total*total*total*total; 
        if( total < 1 ) total = 0;
        else total= total*1.3; // ┮?total程?=41.6 程?=0


        Fx = (int)((5-rank)*1.2)+5; // rank=0~6 ┮? Fx程?=11(rank=0)程?=4(rank=6)
        ans = (int)total + total2 + ((LV-TransLV)/Fx); //42+150+30/11=194

#ifdef _PET_2TRANS
        if( tran == 0 ){
                if( ans > 150 )        
                        ans = 150;
        }
        else{
                if( ans > 200 )        
                        ans = 200;
        }
#else
        if( ans > 150 )        {
                ans = 150;
        }
#endif
        print("\n ans = %d", ans);
        return ans;
}
没错,等级大于130,按130计算,同时:
total = ( (float)total1/100 ); // 嚎立程蔼 total1=200
        total = total*total*total*total*total; 
        if( total < 1 ) total = 0;
        else total= total*1.3;
这个total=total1/100,然后再=自己的4次方,还会被判断是否<1,由此可见,如果total1>100,则total=total*1.3,否则total=0,从这里可以判断,total1是关于人宠的,因为只有人宠的基数才会有一个如此明确的标准来决定转生的成功与失败.(结合73级喂满灵石的MM转宠无差别,这个total绝对不是指4围的合,而应该是4围成长的一个系数的合).
ans = (int)total + total2 + ((LV-TransLV)/Fx); 
所以base = (ans * (base+work)) /total这个公式的total不是那么单纯,因为它同时影响分子和分母,这个我们先不研究了,太多假设.
而可以确定的,就是work[]和base[]越大越好,base数组已经清楚了,work数组也是4位,而且是影响total2的,从下面的代码可以看出:

    total2 = 0;
    for( i=0; i<4; i++)        
   {
        work = work*4;
        total2 += work;
   }
所以大胆推测,work代表的也是关于转宠4围方面的东西,结合起来可以确定基础宠的4围方面的条件,越高越好,

最后我们回过头来来看下GetNewPet( toindex, petindex2, i, base)这个函数的整体.
int GetNewPet( int toindex , int petindex, int array, int *work)
{
    int     *p;
    int                tp[E_T_DATAINTNUM];
    int                tarray, i;
        int                level, workrank, petrank=0;
        int                LevelUpPoint;

        struct         {
            int                num;
            float        rank;
    }ranktbl[] = {
            { 130, 2.5},
            { 100, 2.0},
            { 95, 1.5},
            { 85, 1.0},
            { 80, 0.5},
            { 0, 0.0},
    };
这里有个ranktbl的数组,这个数组一看就知道是什么意思,它表示每个等级段转身,所获得的rank系数,rank也就是评级系数,或者是能力系数,证明了前面:
total1 = PETTRANS_getPetBase( petindex1, work, &petrank);
total2 = PETTRANS_getPetBase( petindex2, base, &petrank);
中,petRank参数的意思,就是0转时的成长系数,充分证明了0转宠的成长率,和MM的成长率,对转身的影响,虽然大家都知道这点了.
同时再次证明了130+的宠物转身可以得到最高的2.5.接下来:        
level = 1;
#define RAND(x,y)   ((x-1)+1+ (int)( (double)(y-(x-1))*rand()/(RAND_MAX+1.0)) )
#define                E_PAR( a)                (*(p + (a)))
#define                ET_PAR( a)                (*(tp + (a)))
#define                PARAM_CAL( l)         ( ( level -1) * ET_PAR( E_T_LVUPPOINT) + ET_PAR( E_T_INITNUM) )
        work[0] += ( RAND(0,4) - 2 );
        work[1] += ( RAND(0,4) - 2 );
        work[2] += ( RAND(0,4) - 2 );
        work[3] += ( RAND(0,4) - 2 );
这段代码的前半部分注释掉了,搞不懂什么意思,后半部分,说的是一个人品问题,前面我们说了,work数组,也就是base数组,代表了宠物的4围,而这里,就是把初始的4围,随机增加(0-4的随机数)-2,对,有可能会加负数,不然怎么说是人品问题,这里也说明了大家平时所谓的暴成长问题,其实真的不是因为太高而暴掉了,而是人品太差了,呵呵.再接着看:
LevelUpPoint = ( work[0] << 24 )
                + (work[1] << 16)
                + (work[2] << 8 )
                + (work[3] << 0 );
CHAR_setInt( petindex, CHAR_ALLOCPOINT, LevelUpPoint);
levelUpPoint这个变量,字面上的意思,是成长关键,我个人理解为成长,这个地方我的理解就是得到内定成长系数.我为什么这么猜,因为接下来第一件事就是把这个POINT给setInt了,之后才setInt的四维,下面会说.在这里至少说明一个问题,成长率是内定的,并且是先于4围初始的,当然也是由4围决定的,这个基本上是废话了,大家都知道.
这个系数怎么算的,呵呵,按照这个公式我给大家解释一下:
内定成长系数=(血*2的24次方)+(攻*2的16次方)+(防*2的8次方)+敏,(当然这里面的血攻防敏不是指纯粹的血攻防敏,不然那数字大得不得了拉)
所以,从这里大胆地得出一个结论,血是关键中的关键,攻是关键,防和敏次要.这个结论其实相信大家已经发现了,比如人龙,普遍情况下,蓝龙成长最好,红龙次之,就是这个道理啊.再接下来:
for( i = 0; i < 10; i ++ ){
                int rnt = RAND( 0, 3 );
                if( rnt == 0 ) work[0]++;
                if( rnt == 1 ) work[1]++;
                if( rnt == 2 ) work[2]++;
                if( rnt == 3 ) work[3]++;
        }
这不用看又是一个人品问题,这段代码重复10次随即把4围中的一项+1,给我的感觉就是在做4围分布的微调,但是一没搞好这段代码,就容易造出那种某项很NB的畸形宠.

CHAR_setInt( petindex, CHAR_VITAL, ( PARAM_CAL(E_T_BASEVITAL) * work[0] ));
    CHAR_setInt( petindex, CHAR_STR , ( PARAM_CAL(E_T_BASESTR) * work[1] ));
    CHAR_setInt( petindex, CHAR_TOUGH , ( PARAM_CAL(E_T_BASETGH) * work[2] ));
    CHAR_setInt( petindex, CHAR_DEX , ( PARAM_CAL(E_T_BASEDEX) * work[3] ));
这段代码就是收尾了,前面说了,是初始化4围的4个函数,因为petindex是不变的,所以是针对同一只宠物,加上是在getNewPet函数的最后面,所以,不解释了.

整个转宠的代码最关键的部分基本上就是这些了,我总结一下:
第一关键点,等级上130,这个很明显代码里交代得是清楚的.
第二关键点,MM和宠0转的成长率,这个决定了total值,虽然不是很清楚之间怎么起作用的.
第三关键点,人品,getNewPoint函数里的那两段随机数人品代码,就说明了一切.当然,这个人品并不是算命决定的,这个很遗憾,我恐怕算命和转宠无关,因为我没看到任何这类型的代码出现.
第四关键点,一转后的血和攻,这个在最后的代码中,四围数组的位移运算,说明了这点.

最近发表
友情链接
标签列表