“它山之石,可以攻玉”--从某mudlib 透视下战斗计算
/** ****** 代码来自 2001年 xkx北美combatd,因此很有可能与pkuxkx计算大不相同 ********/// : deWolf注, Dec.8th,2005
///
///MUD 的编译运行系统使用的语法 LPC 是一种即用即编译的 类C语言 ,学过 c 的同学们看起来应该很容易.
/// 贴这个代码目的是想给初学者讲解一下战斗伤害的大致(请注意!是大致)计算规律,令大家
/// 在选择武功和战斗时不过于盲目。并无对 pkuxkx 的游戏本身、制作人员、管理人员以及
/// 任何玩家有任何消极目的,如果 wiz 反对,本人愿意收回本贴。
///chat* consider; chat 玩家们不会反对罢?; chat* haha
///
///因对高手有班门弄斧之嫌,您可以略过本文。
///
///说明: 本代码对 2001 北美xkx有效, pkuxkx 数据未知,请万万不要等同套用。但由于是同源 mudlib (都是xkx嘛),仅供参考。
/// 本文先列举了几段代码,并在后半部分给出计算实例。
///说明: 某人 [ 气血:123/234(46%) ] ,其中 qi=123, eff_qi=234, max_qi=234/0.46=500
**/
------------------------------------------------------------------------------------------
//////// 注:以下代码来自命中的部分,攻击不命中的这里不讨论
//
// (5) We hit the victim and the victim failed to parry
//
1: damage = me->query_temp("apply/damage");
2: damage = (damage + random(damage)) / 2;
// increase attack power for npc who doesn't have special skills
/// FOR NPC
if (!userp(me))
damage += ((int)me->query_temp("apply/attack") + 1) /10 * (damage /10);
// disable action["damage"] temporarily
// untill we find a consistent damage sys.
if( action["damage"] )
3: damage += action["damage"] /10 * (damage / 30);
// equal skill, equal power
4: damage += ((int)me->query_skill(attack_skill) + 1) /10 * (damage /10);
5: damage_bonus = me->query_str();
// Let force skill take effect.
if( my["jiali"] && (my["neili"] > my["jiali"]) ) {
if( force_skill = me->query_skill_mapped("force") ) {
6: foo = SKILL_D(force_skill)->hit_ob(me, victim, damage_bonus, my["jiali"]);
7: if( stringp(foo) ) result += foo;
else if( intp(foo) ) {
if( !objectp(weapon) ) damage_bonus += foo;
else damage_bonus += foo / 3;
} else if( mapp(foo) ) {
result += foo["result"];
if( !objectp(weapon) ) damage_bonus += foo["damage"];
else damage_bonus += foo["damage"] / 3;
}
}
}
if( action["force"] ) {
if( !objectp(weapon) )
8: damage_bonus += action["force"] /10 * (damage_bonus / 100);
else
damage_bonus += action["force"] /10 * (damage_bonus / 300);
}
// equal skill, equal power
if (!objectp(weapon))
9: damage_bonus += ((int)me->query_skill(attack_skill)/4
9: + (int)me->query_skill("force")/2+1)/10* (damage_bonus /10);
else
damage_bonus += ((int)me->query_skill(attack_skill)/4+1) /10* (damage_bonus /10);
if( martial_skill = me->query_skill_mapped(attack_skill) ) {
10: foo = SKILL_D(martial_skill)->hit_ob(me, victim, damage_bonus);
11: if( stringp(foo) ) result += foo;
else if(intp(foo) ) damage_bonus += foo;
}
// Let weapon or monster have their special damage.
if( weapon ) {
foo = weapon->hit_ob(me, victim, damage_bonus);
if( stringp(foo) ) result += foo;
else if(intp(foo) ) damage_bonus += foo;
} else {
12: foo = me->hit_ob(me, victim, damage_bonus);
13: if( stringp(foo) ) result += foo;
else if(intp(foo) ) damage_bonus += foo;
}
// quick attack only inflict half damage
if( attack_type==TYPE_QUICK) damage /= 2;
if( damage_bonus > 0 )
14: damage += (damage_bonus + random(damage_bonus))/2;
else damage += (damage_bonus - random(-damage_bonus))/2;
if( damage < 0 ) damage = 0;
// Let combat exp take effect
defense_factor = your["combat_exp"];
while( random(defense_factor) > my["combat_exp"] ) {
15: damage -= damage / 3;
16: defense_factor /= 2;
}
// Let special armor take effect.
if( objectp(foo = victim->query_temp("armor/cloth"))
&& foo->is_special() ) {
foo = foo->hit_by(me, victim, damage, weapon);
if (stringp(foo)) result += foo;
else if (intp(foo)) damage = foo;
else if (mapp(foo)) {
result += (string)foo["result"];
damage = (int)foo["damage"];
}
}
// Let special dodge skills take effect.
17: dodge_skill = victim->query_skill_mapped("dodge");
if( dodge_skill && SKILL_D(dodge_skill)->is_special() ) {
foo = SKILL_D(dodge_skill)->hit_by(me, victim, damage);
if (stringp(foo)) result += foo;
else if (intp(foo)) damage = foo;
else if (mapp(foo)) {
result += (string)foo["result"];
damage = (int)foo["damage"];
}
}
//
// (6) Inflict the damage.
//
18: damage = victim->receive_damage("qi", damage, me );
19: if( random(damage) > (int)victim->query_temp("apply/armor")
&& ( (me->is_killing(victim->query("id")))
&& ((!weapon) && !random(4) || weapon && !random(2) )
|| ( (!weapon) && !random(7) || weapon && !random(4) ) ))
{
// We are sure that damage is greater than victim's armor here.
20: victim->receive_wound("qi",
damage - (int)victim->query_temp("apply/armor"), me);
wounded = 1;
}
21: result += damage_msg(damage, action["damage_type"]);
//
// (7) Give experience and yield gain(省略)
//
------------------------------------------------------------------
一般内功的 打中计算 (下边假设的内功要用到这个)
mixed hit_ob(object me, object victim, int damage_bonus, int factor)
{
int damage, myneili, yourneili, my_max, your_max;
string force_skill;
mixed foo;
string result;
myneili = (int)me->query("neili");
yourneili = (int)victim->query("neili");
my_max = (int)me->query("max_neili")*2;
your_max = (int)victim->query("max_neili")*2;
myneili = my_max > myneili ? myneili : my_max;
yourneili = your_max > yourneili ? yourneili : your_max;
me->add("neili", - factor );
damage = myneili/20 + factor - yourneili/25;
if (force_skill = victim->query_skill_mapped("force") ) {
foo = SKILL_D(force_skill)->hit_by(me, victim, damage, damage_bonus, factor);
if (stringp(foo)) return (string)foo;
else if (intp(foo)) damage = (int)foo;
else if (mapp(foo)) return foo;
}
if ( damage > 0 )
damage = damage * factor / (int)me->query_skill("force") * 2;
if( damage < 0 ) {
if( !me->query_temp("weapon")
&& random(victim->query_skill("force")) > me->query_skill("force")/2 ) {
damage = - damage;
me->receive_damage( "qi", damage * 2, victim);
me->receive_wound( "qi", damage, victim );
if( damage < 10 ) result = "$N受到$n的内力反震,闷哼一声。\n";
else if( damage < 20 ) result = "$N被$n以内力反震,「嘿」地一声退了两步。\n";
else if( damage < 40 ) result = "$N被$n以内力一震,胸口有如受到一记重锤,连退了五六步!\n";
else result = "$N被$n的内力一震,眼前一黑,身子向后飞出丈许!!\n";
result += "( $N"+ COMBAT_D->status_msg((int)me->query("qi")*100/(int)me->query("max_qi")) + " )\n";
damage_bonus = -5000; // just a number negative enough
return ([ "result" : result, "damage" : damage_bonus ]);
}
if( damage_bonus + damage < 0 ) return - damage_bonus;
return damage;
}
damage -= victim->query_temp("apply/armor_vs_force");
if( damage_bonus + damage < 0 ) return - damage_bonus;
if( random(me->query_skill("force")) < damage )
return damage;
}
…………………………字数限制,下续
[ Last edited by dewolf on 2005-11-2 at 05:06 PM ]
Re:“它山之石,可以攻玉”--从某mudlib 透视下战斗伤害计算
-------------------------------------------------------------------------------六脉神剑的 hot_ob(),看看 6脉打中人会如何
mixed hit_ob(object me, object victim, int damage_bonus, int factor)
{
int damage, i, level, me_power, victim_power;
string weapon, me_weapon, op_skill, *pname,result, str, msg;
object weap;
level = (int)me->query_skill("liumai-shenjian", 1);
weap = victim->query_temp("weapon");
if( level > 200)
{
if((level <= 240) && (me->query("neili") > 200)
&& (me->query_temp("marks/sword_add") != 1) )
{
i = (int)me->query_skill("liumai-shenjian", 1) / 2;
me->add_temp("apply/attack", i);
me->add_temp("apply/defense", i);
me->add_temp("apply/dodge", i);
me->add_temp("apply/damage", i);
me->add("neili", -50);
me->set_temp("marks/sword_add", 1);
call_out("reset_temp", level/10, me);
return 1;
}
if( (level >220) && (me->query("neili") > 1000)
&& (victim->query_temp("weapon"))
&& (random(me->query_str()) > victim->query_str()/3) )
{
if (random((int)weap->query("rigidity"))<5)
{
message_vision(HIW "突然间拍的一声响,$N手中" + weap->name() + HIW"为无形气剑所断,化为寸许的二三十截,飞上半空!\n" NOR, victim );
// add by xuanyuan
//// 这是慕容的斗转星移克制断剑....
if( (int)victim->query_skill("murong-jianfa", 1) > 119
&& (int)victim->query_skill("douzhuan-xingyi", 1) > 119
&& victim->query("neili") > 500
&& victim->query("jingli") > 200){
message_vision(HIG"\n$n猛吃一惊,却不慌乱,右掌急挥,将二三十断刃化作暗器,以满天花雨手法向$N激射去。\n"NOR, me, victim);
victim_power = victim->query_skill("sword") + victim->query_skill("strike") + victim->query_skill("force")
+ victim->query_skill("dodge") + victim->query("combat_exp") / 1000;
me_power = me->query_skill(op_skill) + me->query_skill("dodge") + me->query_skill("force")
+ me->query_skill("parry") + me->query("combat_exp") / 1000;
if ( random(victim_power) > me_power/3 )
{
if ( random(victim->query_kar()) > (me->query_kar())*4/5 )
{
message_vision(HIR "\n$N未曾料到$n还有此招,一呆之下,反应不及,无数断刃透体而过。\n" NOR, me ,victim);
me->receive_damage("qi", me->query("max_qi")/8 + random(me->query("max_qi")/4), me);
str = COMBAT_D->status_msg((int)me->query("qi") * 100 /(int)me->query("max_qi"));
message_vision("($N"+str+")\n", me);
}
else // if ( random(victim->query_kar()) > (me->query_kar())*3/5 )
{
message_vision(HIR "\n$N大叫:“啊哟!”手足无措,慌作一团,急忙伏地。不料动作稍慢,背上被断刃划出几条血痕。\n" NOR, me);
me->receive_damage("qi", me->query("max_qi")/10 + random(me->query("max_qi")/8), me);
str = COMBAT_D->status_msg((int)me->query("qi") * 100 /(int)me->query("max_qi"));
message_vision("($N"+str+")\n", me);
}
}
else
{
if ( objectp(me_weapon = me->query_temp("weapon")))
{
message_vision(WHT"\n$N一惊之下,反应神速,舞开手中兵刃,将断刃一一荡开。\n" NOR, me);
}
else
{
message_vision(HIY "\n$N大叫:“啊哟!”手足无措,慌作一团,急忙伏地。数十枚断刃都从他头顶飞过,高手比武,竟出到形如“狗吃屎”的丢脸招数,实在难看已极。\n" NOR, me);
}
}
victim->add("neili", -200);
victim->add("jingli", -100);
}
weap->move(environment(me));
weap->set("name", "断掉的"+weap->query("name"));
weap->set("value", 0);
weap->set("weapon_prop", 0);
} else {
message_vision(HIW "只听见「当」地一声,$N手中的" + weap->name()
+ HIW"被剑气震落到地上!\n" NOR, victim );
weap->move(environment(me));
}
victim->reset_action();
me->add("neili", -100);
return 1;
}
}
}
-------------------------------------------------------------------------------
--------------------------------------------------------------------------------
来做个计算实例:(注意:所有数据均为虚构,如有雷同,纯属巧合)
某男性人物属性先天 str(力量) 15 由于下边的 finger 技能,后天 str=25
人物当前状态内力300/ 500 (+40) , exp 30w
combat skill = force 100, kurong-shengong 100, finger 100, liumai-shenjian 100, enforce = 40
空手战斗, 战斗开始 powerup 后"apply/damage" 为25,"apply/dodge" 为25
某次随机出 六脉神剑 的 「中冲剑」,「中冲剑」假设数据如下
{"force" : 580, "dodge" : 600, "weapon": "无形剑气", "lvl" : 50, "damage_type" : "刺伤"}
对手 npc 梅剑 dodge 80, yueying-wubu 80, "apply/armor"=0(女生,不像熊皮那么厚),"apply/armor_vs_force"=0,
装甲 "armor/cloth"=doupeng(斗篷,设定 "material"="cloth", "armor_prop/armor"=10)
梅剑当前状态内力820/ 1000 (+60) , exp 50w, 没有exert powerup
开始计算:
1,2 行 ::12 <= damage <= 24
3 行 ::12 <= damage <= 24 (..... apply/dam 太低,武功效果为零)
4 行 ::31 <= damage <= 54
5 行 ::damage_bounce = 25
6 行 ::得到内功打中目标的特效,假设这次返回 ""(空字符串,也有小概率返回3,具体看第二个函数)
7 行 ::返回消息附加 ""
8 行 ::damage_bonus = 25 (很不幸,enforce 太低的得不到这个加成 ... 就是说低经验者用高强武功效果不明显)
9 行 ::damage_bonus = 47 (有效内功 比 有效攻击 更有效果)
10 行 ::很明显,通过第三段代码,此人 6脉不够级别,返回""
11 行 ::返回消息附加 ""
12 行 ::玩家打中 mei ,返回 ".....中指一竖,一招「中冲剑」,迅疾的向$n的$l划去,大开大合,气势雄伟"
13 行 ::返回消息附加 " .....中指一竖,一招「中冲剑」,迅疾的向$n的$l划去,大开大合,气势雄伟"
14 行 ::54 <= damage <= 100
15 行 ::36 <= damage <= 66 (郁闷,没她经验高,攻击折为2/3,如果此人exp=20w,攻击要减为4/9 ...)
16 行 ::攻击折1/3同时,防御系数折半 (就是说 exp 是自己5倍的,伤害变为 9/27... chat* sigh)
17 行 ::得到 月影舞步 这个轻功,当然没有后续伤害。某些功夫克制某些功夫,可以在这里加代码。
18 行 ::终于伤害到她的 气血了。伤害就是上边的 damage
19 行 ::加重打击(奋力一击),由于斗篷防御10 而 mei 皮厚0,总防御10(她还没powerup),那么在kill指令有
概率(有武器 1/2,没武器 1/4);其他指令有概率(1/4和1/7)来执行20行
20 行 ::对气造成wound ,伤害 26 - 56 的 eff_qi(eff_qi 见顶部说明)
21 行 ::把伤害信息转为描述,例如“造成了轻微刺伤”之类。
以下还有点东西,不过与本题已不相关。
再次声明,代码非北侠的,具体来源是 小熊泥苑(http://www1.nd169.com/nd/mud/) 下载中的 2001北美xkx,
如果有兴趣,可以计算下带武器的伤害,
本人愿意提供虚拟参考数据:
1 顶级武功分两类
1.1 攻击类(玄铁剑法、侠客剑法、6脉神剑、降龙18掌、英雄剑法为代表的)
招式的"force" 在 400-600间, 空手类稍高,在450-650 (高级招式的force比低级的高)
1.2 防御类(独孤9剑,辟邪剑法为代表的)
招式的"force" 在 300-500间
2 中级武功
以达摩剑、回风拂柳剑、华山剑法等
招式的"force" 在 250-450间,个别最强招式也许能到达550, 空手类稍高
3 入门武功
以天山六阳掌、如来千叶手、太极刀等为代表的
招式的"force" 在 100-300间,个别最强招式也许能到达450, 空手类稍高
注意招式的"force" 逢10有效,经常看到有些 wiz 写 42,48 之类的force,chat* fly
不过总的说来,exp高的人,用入门武功,同样可以打 exp 低的人落花流水,这一点上所有mud 好像都是。
到了exp差不多的时候(互相不超过对方4倍?),才去比较功夫伤害的。
另,本文只讨论伤害计算,并不涉及任何 perform ,有很多入门武功的 perform 巨好,当然也是好东东。
附带提一下,这个代码前边写道 busy 时的轻功系数 减为1/3,招架系数减为1/2。还有这段代码是命中目标的代码,
判断命中的,有空再说啦。
……版权问题,参考 LGPL. chat* bow deWolf, Dec.8th,2005
[ Last edited by dewolf on 2005-10-25 at 09:52 AM ]
书剑2 中的战斗命中计算
//--------------------------------------------------------------//以下代码来自 sj2@2003 , 与 pkuxkx 无关 , 如有雷同, 纯属巧合
//--------------------------------------------------------------
// This function calculates the combined skill/combat_exp power of a certain
// skill. This value is used for A/(A+B) probability use.
varargs int skill_power(object ob, string skill, int usage)
{
//本函数计算技能的威力
int level, power;
// 鬼魂等非生存对象即使有skill ,也视为无效
if( !living(ob) ) return 0;
1 :: level = ob->query_skill(skill);
switch(usage) {
// 攻击技能附加 apply/attack ,防御技能附加 apply/defence 这个与 powerup, 装甲等相关
case SKILL_USAGE_ATTACK:
2 :: level += ob->query_temp("apply/attack");
break;
case SKILL_USAGE_DEFENSE:
level += ob->query_temp("apply/defense");
if (ob->is_fighting()){
level = level * (100 + ob->query_temp("fight/dodge")) / 100;
// add parry by snowman.
level = level * (100 + ob->query_temp("fight/parry")) / 100;
}
}
if( level < 1 ) return (int)ob->query("combat_exp") / 2;
// 技能威力正比于 (level+apply/attack 之类) 的立方
3 :: power = (level*level*level) / 3;
// 根据用途进行经验加成
if (usage == SKILL_USAGE_ATTACK)
4 :: return (power + ob->query("combat_exp")) /30 * ob->query_dex();
return (power + ob->query("combat_exp"))
/30 * (skill == "dodge"?ob->query_dex():ob->query_int());
}
varargs void do_attack(object me, object victim, object weapon, int attack_type, string attack_msg, string damtype)
{
//本函数负责战斗回合
........
........省略
........
//
// (2) Prepare AP, DP for checking if hit. 预备攻击点数 和 防御点数
//
limbs = victim->query("limbs");
limb = limbs;
message_vision(adj_msg(result, limb, weapon, action, attack_skill), me, victim);
// 用上边函数计算攻击点数
ap = skill_power(me, attack_skill, SKILL_USAGE_ATTACK);
if( ap < 1) ap = 1;
// 获取技能中某招式附加的 dodge,parry 点数,为下一招准备
if (userp(me) && intp(action["dodge"]))
me->set_temp("fight/dodge", action["dodge"]);
if (userp(me) && intp(action["parry"]))
me->set_temp("fight/parry", action["parry"]);
dp = skill_power(victim, "dodge", SKILL_USAGE_DEFENSE);
if( dp < 1 ) dp = 1;
// busy 中的目标,防御点数降为 1/3
if( victim->is_busy() ) dp /= 3;
if( !living(victim)) dp = 1;
//攻防点数准备完毕
//--------------------------------------------------------------
// (3) Fight!
// here added by snowman, fainted object cant dodge :)
// 这里看出对等攻防有1/2 概率躲避
if( random(ap + dp) < dp && living(victim)) { // Does the victim dodge this hit?
.......
.......省略轻功部分
.......
} else {
// 轻功躲避完毕
//--------------------------------------------------------
//
// (4) Check if the victim can parry this attack.
//
if( vweapon ) {
// 敌人有武器,计算点数;如果自己空手,招架系数加倍
pp = skill_power(victim, "parry", SKILL_USAGE_DEFENSE);
if( !weapon ) pp *= 2;
} else {
// 敌人没有有武器,计算招架;如果自己有武器,禁止招架;
pp = skill_power(victim, attack_skill, SKILL_USAGE_DEFENSE);
if( weapon ) pp = 0;
}
// busy 中,招架降为 1/3
if( victim->is_busy() ) pp /= 3;
if( pp < 1 ) pp = 1;
// added by snowman, fainted object cant parry :)
// 相同攻击招架点数,1/2 概率招架
if( random(ap + pp) < pp && living(victim)) {
.......
.......省略招架细节
.......
} else {
// 招架判断完毕
//--------------------------------------------------
//
// (5) We hit the victim and the victim failed to parry
//
// 以下紧接着继续 本主题 1楼内容。
=====================================================================================
分析 sj2 点数计算可以看出,700 sword enable 700 tianyu-qijian, 700 force enable 700 bahuanggong, exp 40M 的玩家 先天dex 20 ,700 dodge,后天身法 90
1 使用竹剑 ,
2 powerup 得到apply/attack 350
之后,
计算skill_power:
1 level:=1050
2 level:=1400
3 pwoer:=1400*1400*1400/3=246037500/3(!!!注意:注意这个自左向右的运算次序!!! 这里超出了int范围,max_int=2147483647)=-1550967295/3=-516989098 (|||-_-,溢出了,其实wiz 只要用power:=level/3*level*level 就可以把溢出上限提高很多)
....
如果 不powerup
1 level:=1050
2 level:=1050
3 power:=1157625000/3=385875000
4 power:=385875000+40M/30*90=386M+120M=506M
高等级功夫一个powerup 竟然可以加倍攻击点数的 |||-_-
防御类似。
[ Last edited by dewolf on 2005-11-2 at 05:53 PM ]
wiz 和 攻击溢出的老手可以参考下3楼
不知 pkuxkx 现在 all 750, 用 特殊force powerup 后溢出不?上次看丐帮大米 在bwc powerup 就再也打不中目标了。
而且 powerup 后期加成是非常bt的,听说 yjj 加成 1/2 ……
我猜在忽略exp下, all 500(1/2系数下 skill 600溢出) 用 yjj powerup 相当于 all 600 用 侠客神功 powerup(听说侠客神功系数1/4 :() 。是这样么?
powerup 本来可以调节门派强弱,比如灵鹫的bahuanggong 在众多mudlib中都有 1/3 系数,而功夫比较强的门派系数多在 1/4 到 1/5 ,有些干脆没有。
powerup 涉及命中率,功夫强弱涉及招式中的 force,damage,dodge,parry 设定。
给弱门派强化powerup,强门派削弱powerup,这样功夫每招伤害高的,命中低一些;伤害低的,命中高一些。 大致是八九不离十。 如果550 无影剑+ yjj powerup 就达到可能的最大命中率,说起来是在有点…… :( 。
在外地上不了pkuxkx,特来唠叨几句。;)
---------------------------------------------
powerup系数消息来源:http://www.pkuxkx.com/forum/viewthread.php?tid=966&highlight=powerup&page=2
[ Last edited by dewolf on 2005-11-3 at 10:05 AM ]
Re:“它山之石,可以攻玉”--从某mudlib 透视下战斗计算
dewolf的想法很好,有兴趣不妨申请wiz,说说你的改进计划。Re:“它山之石,可以攻玉”--从某mudlib 透视下战斗计算
不错啊,可惜不懂 经典好贴,要顶dewolf是哪位大神? 小刀,加精后转巫师学堂 挖坟啊 原帖由 zgbl 于 2010-4-28 11:07 PM 发表 http://www.pkuxkx.com/forum/images/common/back.gif
小刀,加精后转巫师学堂
嗯,知道了.现在就处理
页:
[1]
2