北大侠客行MUD论坛

 找回密码
 注册
搜索
热搜: 新手 wiki 升级
查看: 11088|回复: 12

【转贴】combatd中skill_power的溢出及解决办法

[复制链接]
发表于 2010-5-10 22:02:34 | 显示全部楼层 |阅读模式
原始地址:http://www.52mud.com/show.aspx?&id=1402&cid=13

combatd中skill_power的溢出及解决办法

[日期:2010-05-01]来源:  作者:52mudWIZ


1.在LPC中int的最大值为2^31=2147483648
2. 现在的公式中level的上限为3000, 那么根据公式计算的最大值为:
   a. 技能等级:3000*3000/25*3000/6=180000000
   b. 精神影响:180000000*100/100*120=21600000000
3. 步骤2的值大于int的最大值,造成有时高位为1,溢出。

4. 所以允许的最大level为:2147483648/120*(25*6)=x^3
   x = 1389.
以上步骤得出最高level只能为1389,但是如此低的level当各位高手的
级别上去后应该很容易达到,最后就造成以后大家都一样啦。
为了让高手们显得cool一点,我觉得应该再增加一个skill_power_level的
方法,这个方法就是返回该高手的level是1300的多少倍,根据不同倍数显
示不同的颜色(在skillpt里),在战斗中,如果两人的级别有差别时,那么
击中/躲避的几率为:
          Random( 100-(10-level_trap) ) //level_trap为级别差
这样可以保证高级别的能有效的击中/躲避对手。
方法
#define APPLY_ATTACK_LIMIT 400
#define FIGHT_ATTACK_LIMIT 200
#define APPLY_DODGE_LIMIT 30
#define FIGHT_DODGE_LIMIT 200
#define APPLY_PARRY_LIMIT 30
#define FIGHT_PARRY_LIMIT 200

#define APPLY_DEFENSE_LIMIT 200
        varargs int skill_power(object ob, string skill, int usage)
        {
                int status, level, power, a_d_ratio,a_d_ratio_set, gin_ratio,sen_ratio;
                int eff_level,afford,tmp;
                string map_skill;
                if( !living(ob) )
                        return 0;
                a_d_ratio = 0;
                a_d_ratio_set = 0;
                if( objectp(ob) )
                {
                        if( intp(ob->query("env/attack")) )
                                a_d_ratio = (int)ob->query("env/attack");
                        else
                                a_d_ratio = 50;
                }
                if( a_d_ratio == 0)
                        a_d_ratio = 50;
                else if( a_d_ratio > 100)
                        a_d_ratio = 100;
                else if( a_d_ratio < 0)
                        a_d_ratio = 1;
                if( a_d_ratio != a_d_ratio_set )
                        ob->set("env/attack",a_d_ratio);
                // if enable parry as weapon but no weapon  then set no_parry skill
                if( skill == "no_parry")
                        level = ob->query_skill("parry",1)/2;
                else
                        level = ob->query_skill(skill);
                switch(usage) {
                                case SKILL_USAGE_ATTACK:
                                        tmp=ob->query_temp("apply/attack");
                                        if(tmp>APPLY_ATTACK_LIMIT) tmp=APPLY_ATTACK_LIMIT;
                                        level += tmp;
                                        // for action["attack"] cmy
                                        //                      CHANNEL_D->do_channel(ob,"sys",sprintf("origin:%d,add %d " , level,ob->query_temp("fighting/attack")));
                                        tmp=ob->query_temp("fighting/attack");
                                        if(tmp>FIGHT_ATTACK_LIMIT) tmp=FIGHT_ATTACK_LIMIT;
                                        level = level * (100 + tmp) / 100;
                                        //                      CHANNEL_D->do_channel(ob,"sys",skill+ sprintf(" after:%d " , level));
                                        break;
                                case SKILL_USAGE_DEFENSE:
                                        tmp=ob->query_temp("apply/defense");
                                        if(tmp>APPLY_DEFENSE_LIMIT) tmp=APPLY_DEFENSE_LIMIT;
                                        level += tmp;
                                        // for action["dodge"] cmy
                                        if (ob->is_fighting()) {
                                                //                      CHANNEL_D->do_channel(ob,"sys",sprintf("%s origin:%d,add %d ", skill,level,ob->query_temp("fighting/"+skill)));
                                                if( skill == "dodge") {
                                                        tmp = ob->query_temp("apply/dodge");
                                                        if( tmp > APPLY_DODGE_LIMIT ) tmp = APPLY_DODGE_LIMIT;
                                                        level += tmp;
                                                        if( stringp(map_skill= (ob->query_skill_mapped(skill))) && ( eff_level = SKILL_D(map_skill)->effective_level()) > 0)
                                                                level = level * eff_level / 10;      
                                                        //                      CHANNEL_D->do_channel(ob,"sys", sprintf(" dodge eff_level:%d " , eff_level));
                                                        tmp=ob->query_temp("fighting/dodge");
                                                        if(tmp>FIGHT_DODGE_LIMIT) tmp=FIGHT_DODGE_LIMIT;
                                                        level = level * (100 + tmp) / 100;
                                                }
                                                else /*if( skill == "parry")*/
                                                {
                                                        tmp = ob->query_temp("apply/parry");
                                                        if( tmp > APPLY_PARRY_LIMIT) tmp = APPLY_PARRY_LIMIT;
                                                        level += tmp;
                                                        if( stringp(map_skill= (ob->query_skill_mapped(skill))) && ( eff_level = SKILL_D(map_skill)->effective_level()) > 0)
                                                                level = level * eff_level / 10;      
                                                        tmp=ob->query_temp("fighting/parry");
                                                        if(tmp>FIGHT_PARRY_LIMIT) tmp=FIGHT_PARRY_LIMIT;
                                                        level = level * (100 + tmp) / 100;
                                                }
                                                //                      CHANNEL_D->do_channel(ob,"sys",skill+ sprintf(" after:%d " , level));
                                        }
                                        break;
                }
                if( !level ) return (int)ob->query("combat_exp") / 2;
                /********************changed by meteoric*******************/
                if(level>3000) level=3000; //防止溢出
                power = (level*level/25)*(level/6);
                //if set attack 100,then ap*=2 and dp = 0
                //if set attack 0,then ap = 0 and dp*=2
                power = power + ob->query("combat_exp")/25;
                /***************************end**************************/
                gin_ratio = 100;
                sen_ratio = 100;
                //神影响攻击,精影响防御
                if( (status = ob->query("max_sen")) > 0 && power > 1000 ) sen_ratio = 100 * ob->query("sen") / status;
                if( (status = ob->query("max_gin")) > 0 && power > 1000 ) gin_ratio = 100 * ob->query("gin") / status;
                if(gin_ratio < 50 )   gin_ratio = 50;
                if(sen_ratio < 50 )     sen_ratio = 50;
                //允许部分超常发挥的情况        
                if(gin_ratio > 120 )    gin_ratio = 120;
                if(sen_ratio > 120 )    sen_ratio = 120;

                if( usage == SKILL_USAGE_ATTACK)       power = power*a_d_ratio/100*sen_ratio;
                else if( usage == SKILL_USAGE_DEFENSE) power = power*(100-a_d_ratio)/100*gin_ratio;
                afford = (int)ob->query_encumbrance() * 100 / (int)ob->query_max_encumbrance();
                //负重(>10%)影响攻击与躲闪
                if( afford > 10 && (skill == "dodge" || usage == SKILL_USAGE_ATTACK) ) power -= power/100*afford;
                if( power < 100 ) power = 100;
                return power;         
        }  
1. 将一下代码替换combatd.c里的varargs int skill_power(object ob, string skill, int usage)方法:
        varargs int skill_level(object ob, string skill, int usage)
        {
                int level, tmp;
                if( !living(ob) )
                        return 0;
                // if enable parry as weapon but no weapon  then set no_parry skill
                if( skill == "no_parry")
                        level = ob->query_skill("parry",1)/2;
                else
                        level = ob->query_skill(skill);
                switch(usage) {
                                case SKILL_USAGE_ATTACK:
                                        tmp=ob->query_temp("apply/attack");
                                        if(tmp>APPLY_ATTACK_LIMIT) tmp=APPLY_ATTACK_LIMIT;
                                        level += tmp;
                                        // for action["attack"] cmy
                                        //                      CHANNEL_D->do_channel(ob,"sys",sprintf("origin:%d,add %d " , level,ob->query_temp("fighting/attack")));
                                        tmp=ob->query_temp("fighting/attack");
                                        if(tmp>FIGHT_ATTACK_LIMIT) tmp=FIGHT_ATTACK_LIMIT;
                                        level = level * (100 + tmp) / 100;
                                        //                      CHANNEL_D->do_channel(ob,"sys",skill+ sprintf(" after:%d " , level));
                                        break;
                                case SKILL_USAGE_DEFENSE:
                                        tmp=ob->query_temp("apply/defense");
                                        if(tmp>APPLY_DEFENSE_LIMIT) tmp=APPLY_DEFENSE_LIMIT;
                                        level += tmp;
                                        // for action["dodge"] cmy
                                        if (ob->is_fighting()) {
                                                //                      CHANNEL_D->do_channel(ob,"sys",sprintf("%s origin:%d,add %d ", skill,level,ob->query_temp("fighting/"+skill)));
                                                if( skill == "dodge") {
                                                        tmp = ob->query_temp("apply/dodge");
                                                        if( tmp > APPLY_DODGE_LIMIT ) tmp = APPLY_DODGE_LIMIT;
                                                        level += tmp;
                                                        if( stringp(map_skill= (ob->query_skill_mapped(skill))) && ( eff_level = SKILL_D(map_skill)->effective_level()) > 0)
                                                                level = level * eff_level / 10;      
                                                        //                      CHANNEL_D->do_channel(ob,"sys", sprintf(" dodge eff_level:%d " , eff_level));
                                                        tmp=ob->query_temp("fighting/dodge");
                                                        if(tmp>FIGHT_DODGE_LIMIT) tmp=FIGHT_DODGE_LIMIT;
                                                        level = level * (100 + tmp) / 100;
                                                }
                                                else /*if( skill == "parry")*/
                                                {
                                                        tmp = ob->query_temp("apply/parry");
                                                        if( tmp > APPLY_PARRY_LIMIT) tmp = APPLY_PARRY_LIMIT;
                                                        level += tmp;
                                                        if( stringp(map_skill= (ob->query_skill_mapped(skill))) && ( eff_level = SKILL_D(map_skill)->effective_level()) > 0)
                                                                level = level * eff_level / 10;      
                                                        tmp=ob->query_temp("fighting/parry");
                                                        if(tmp>FIGHT_PARRY_LIMIT) tmp=FIGHT_PARRY_LIMIT;
                                                        level = level * (100 + tmp) / 100;
                                                }
                                                //                      CHANNEL_D->do_channel(ob,"sys",skill+ sprintf(" after:%d " , level));
                                        }
                                        break;
                }
                return level;
        }
        varargs int skill_power(object ob, string skill, int usage)
        {
                int status, level, power, a_d_ratio,a_d_ratio_set, gin_ratio,sen_ratio;
                int eff_level,afford,tmp;
                string map_skill;
                if( !living(ob) )
                        return 0;
                //level
                level = skill_level(ob, skill, usage);
                if( !level ) return (int)ob->query("combat_exp") / 2;
                if(level>1500) level=1500; //防止溢出
                power = (level*level/25)*(level/25);
                tmp = ob->query("combat_exp");
                if( tmp < 0 )
                        tmp = 1;
                if( tmp > 10000000 )
                        tmp = 10000000;
                power = power + tmp/100;
                //神影响攻击,精影响防御
                gin_ratio = 100;
                sen_ratio = 100;
                if( (status = ob->query("max_sen")) > 0 && power > 1000 ) sen_ratio = 100 * ob->query("sen") / status;
                if( (status = ob->query("max_gin")) > 0 && power > 1000 ) gin_ratio = 100 * ob->query("gin") / status;
                if(gin_ratio < 50 )                gin_ratio = 50;
                if(sen_ratio < 50 )                sen_ratio = 50;
                if(gin_ratio > 120 )    gin_ratio = 120;        //允许部分超常发挥的情况
                if(sen_ratio > 120 )    sen_ratio = 120;
                //set attack
                a_d_ratio = 0;
                a_d_ratio_set = 0;
                if( objectp(ob) )
                {
                        if( intp(ob->query("env/attack")) )
                                a_d_ratio = (int)ob->query("env/attack");
                        else
                                a_d_ratio = 50;
                }
                if( a_d_ratio == 0)
                        a_d_ratio = 50;
                else if( a_d_ratio > 100)
                        a_d_ratio = 100;
                else if( a_d_ratio < 0)
                        a_d_ratio = 1;
                if( a_d_ratio != a_d_ratio_set )        //yisheng: only set again when set value is invalid
                        ob->set("env/attack",a_d_ratio);
               
                if( usage == SKILL_USAGE_ATTACK)       power = power*a_d_ratio/100*sen_ratio/25;                //yisheng: 1/4
                else if( usage == SKILL_USAGE_DEFENSE) power = power*(100-a_d_ratio)/100*gin_ratio/25;        //yisheng: 1/4
                //负重(>10%)影响攻击与躲闪
                afford = (int)ob->query_encumbrance() * 100 / (int)ob->query_max_encumbrance();
                if( afford > 10 && afford <= 100 && (skill == "dodge" || usage == SKILL_USAGE_ATTACK) ) power -= power/100*afford;
                if( power < 100 ) power = 100;
                return power;         
        }
        varargs int skill_candodgeorparray(object ob, object victim, string attack_skill, string defense_skill)
        {
                int level_ob, level_victim, n_ob, n_victim, ntrap;
                level_ob = skill_power(ob, attack_skill, SKILL_USAGE_ATTACK);
                level_victim = skill_power(victim, defense_skill, SKILL_USAGE_DEFENSE);
                n_ob = level_ob/1500;
                n_victim = level_victim/1500;
                if( n_ob == n_victim )
                {
                        return 0;        //如果等级相同,让随机数来决定吧
                }
                else
                {
                        ntrap = n_ob - n_victim;
                        if( ntrap > 0 )
                        {
                                ntrap = 10 - ntrap;
                                if( ntrap < 1 )
                                        ntrap = 1;
                                return skill_random(ntrap);        //如果攻击方的等级是防守方的n倍,那么防守方能躲避的几率就很小很小
                        }
                        else
                        {
                                ntrap = 90 + ntrap;
                                if( ntrap > 99 )
                                        ntrap = 99;
                                return skill_random(ntrap); //如果防守方的等级是攻击方的n倍,那么防守方能躲避的几率就很大很大
                        }
                }
        }
        int skill_random(int range)
        {
                //如果返回1,表示在范围内,否则返回0
                if(random(100)< range )
                        return 1;
        }
        varargs int skill_candodge(object ob, object victim, string attack_skill)
        {
                return skill_candodgeorparray(ob, victim, "dodge");
        }
        varargs int skill_canparry(object ob, object victim, string attack_skill)
        {
                return skill_candodgeorparray(ob, victim, "parry");
        }
2. 修改do_attack()方法里的判断是否dodge和是否parray的两句话为如下(Does the victim dodge this hit?和Does the victim dodge this hit?两句):
if( (me != victim) && ( skill_candodge(ob, victim, attack_skill) > 0 || (random(ap+dp) if( (victim != me) && ( skill_canparry(ob, victim, attack_skill) > 0 || (random(ap+pp) 这两句话的修改是通过skill_candodge和skill_canparry来判断攻击方和防守方的level是不是有差别,如果有差别,那么取random(100-差别)的几率能躲过去,返回值为1,无差别的时候,那么返回值为0,继续做random(ap+dp)
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-10 22:19:45 | 显示全部楼层
可不可以这样?
exp*10=skill^3
那么我们用exp计算skill时,就用(exp^0.33)/(10^0.33)
这样只要exp不会溢出,skill计算就不会溢出吧?
不过我不知道开跟的计算方式是什么。。。。
如果使用立方去凑的话,还是会溢出,那么就用
skill/10*skill*skill,这样溢出上限还是exp,那么按理说就能支持到2000M了
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 06:08:31 | 显示全部楼层
#define APPLY_ATTACK_LIMIT 400
#define FIGHT_ATTACK_LIMIT 200
#define APPLY_DODGE_LIMIT 30
#define FIGHT_DODGE_LIMIT 200
#define APPLY_PARRY_LIMIT 30
#define FIGHT_PARRY_LIMIT 200

这个貌似很土啊
其实吧
应该把mudos升级成为64位的。。。。

至于combatd....
重新写吧
pkuxkx的wiz如果稳定的话
绝对值得重新写
写的时候可以把转生啊
天赋啊这些全部写进去
可以参考fy2005的ability
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 09:37:11 | 显示全部楼层
现在已经有一个64位的mud系统了,貌似ddid他们讨论过
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 10:45:21 | 显示全部楼层
不管怎样,学习是需要的。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 11:48:37 | 显示全部楼层
官方xkx中已经用最大支持的skill等级代替了exp来进行计算,解决了溢出问题
这样skill可以到2700+,有生之年,player是达不到了
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 19:29:16 | 显示全部楼层
来一个简单的方法
mud里内置一张exp和level对应表,这个表就用其他不溢出的软件算了填进去,到时候直接对着表确认level,这样就不会溢出了
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 19:41:36 | 显示全部楼层
完全不知道你门在讲什么玩意
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 20:33:20 | 显示全部楼层
原帖由 frankli 于 2010-5-29 07:41 PM 发表
完全不知道你门在讲什么玩意


一看你就是初中生理卫生课没好好听该你听的那部分,别没事往女生那边凑,“满则溢”,懂吗?
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
发表于 2010-5-29 21:05:08 | 显示全部楼层
我觉得mudos内部的老版公式本身有问题,应该有一个新的平衡公式,抛弃level^3的判定方式,至少要做一种妥协判定。少改动的话在判定区域修改变量为double型就解决问题了。combatd里面计算立方的使用用double型,计算完结果做完判定再该怎么样还是怎么样,这样子仅仅修改combatd,不用大动,出bug也好控制。
缺点就是治标不治本。
最好的版本是重新设计一套核心平衡算法,这个修改量估计非常大,和重新写一个没有区别,比如将游戏里面的level作为根基判定,经验就和其他游戏一样仅仅是level之间的升级经验,skills和level直接相关。
北大侠客行Mud(pkuxkx.net),最好的中文Mud游戏!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|北大侠客行MUD ( 京ICP备16065414号-1 )

GMT+8, 2024-4-20 08:08 PM , Processed in 0.011369 second(s), 14 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表