Elin:解析/ダメージ計算

バージョン EA23.115: この記事は、Elin最新の安定版リリースに遅れをとっていますが、信頼できる範囲にあるかもしれません。

DamageHP()を参照しています。

Evalue

意味
55 物理軽減
56 属性軽減
93 反魔法
961 魔法耐性
1218 メタル
1238 古代種
1421 マナの体

PV

ApplyProtection(int dmg, int mod = 100)
   {
       int armorSkill = GetArmorSkill();
       Element orCreateElement = elements.GetOrCreateElement(armorSkill);
       int num = PV + orCreateElement.Value + DEX / 10;
       int num2 = 1;
       int sides = 1;
       int bonus = 0;
       if (num > 0)
       {
           int num3 = num / 4;
           num2 = num3 / 10 + 1;
           sides = num3 / num2 + 1;
           bonus = 0;
           dmg = dmg * 100 / (100 + num);
       }
       int num4 = Dice.Roll(num2, sides, bonus, this);
       dmg -= num4 * mod / 100;
       if (dmg < 0)
       {
           dmg = 0;
       }
       return dmg;
   }

軽装備か重装備かを取得します。

PV + 軽or重装備のスキル + 器用/10として変数numを定めて、

その値が正である場合、4で割った値を変数num3に保管し、num2=num3/10 +1とし、

更にそこから sides = num3/num2 + 1を定義し、bonus=0とします。

そののち、ダメージを100/(100+num)倍にします。

さらに、Dice.cs中のRoll関数を用いて、運は被ダメージ者のもの、ダイス数はnum2、面数はsides、ボーナスは0でダイスロールをします。

ダメージからnum4 * 100[1] / 100 を引き算します。

最後に、ダメージが負になっていたら0に変更します。

ダメージ計算

上から見ていくので、計算の順序もこの通りになります。

反魔法による物理ダメージ増加

Element e;
       if (ele == 0 || ele == 926)
       {
           e = Element.Void;
           if (origin != null)
           {
               dmg = dmg * Mathf.Max(100 + origin.Evalue(93) / 2, 10) / 100;
           }
       }
       

この箇所は攻撃属性ごとの処理をしていて、Voidが物理に相当し、物理は攻撃者の反魔法によって強化されます。 強度を2で割ったあまり%だけ上昇します。ただし、下限10により、反魔法が負の大きい強度であっても最低限のダメージが出ます。

 else
       {
           e = Element.Create(ele);
           if (attackSource != AttackSource.Condition && showEffect)
           {
               ActEffect.TryDelay(delegate
               {
                   PlayEffect(e.id, useRenderPos: true, 0.25f);
                   EClass.Sound.Play("atk_" + e.source.alias);
               });

不明。演出関連か?

属性耐性による軽減

まずElement.cs中のGetResistLvを見ると、

  {
       int num = v / 5;
       if (num < -2)
       {
           num = -2;
       }
       if (num > 4)
       {
           num = 4;
       }
       return num;
   }

耐性値を5で割った商を求め、それを必要であれば下限-2、上限4に押し込めます。この値はゲーム内で見られる"免疫"などの耐性評価と一致します。

次に同じくElement.cs中のGetResisistDamageを見ると、

  {
       int resistLv = GetResistLv(v);
       resistLv -= power;
       if (resistLv >= 4)
       {
           return 0;
       }
       return resistLv switch
       {
           3 => dmg / 4, 
           2 => dmg / 3, 
           1 => dmg / 2, 
           0 => dmg, 
           -1 => dmg * 3 / 2, 
           -2 => dmg * 2, 
           _ => dmg * 2, 
       };
   }

耐性評価を計算した後、そこからpowerの数値分減らしています。これは古代種フィートの耐性貫通だと考えられます。 その後、4以上ならダメージ0倍、3なら0.25倍と、よく知られている属性軽減が起きます。

実際に計算に組み込まれているのはDamageHP中の以下の箇所です。

   if (!e.source.aliasRef.IsEmpty() && attackSource != AttackSource.ManaBackfire)
           {
               dmg = Element.GetResistDamage(dmg, Evalue(e.source.aliasRef), (origin != null) ? origin.Evalue(1238) : 0);
               dmg = dmg * 100 / (100 + Mathf.Clamp(Evalue(961) * 5, -50, 200));
               dmg = dmg * Mathf.Max(100 - Evalue(93), 10) / 100;
           }

属性が無でなく、ダメージ源がマナの反動ではないとき、 属性耐性に応じたダメージ軽減が起き、(Evalue.1238は不明)。 次の行で、魔法耐性の、属性全般軽減が起きます。 これは100/(100+魔法耐性*5)をかけるというものです。 ただし、魔法耐性*5は下限-50、上限200に押し込められます。 最後に、反魔法による属性軽減があり、 これは(100-強度)/100 をかけるというものです。 ただし、100-強度には下限100があります。

濡れ補正

switch (e.id)
           {
           case 910:
           {
               Chara chara2 = Chara;
               if (chara2 != null && chara2.isWet)
               {
                   dmg /= 3;
               }
               break;
           }
           case 912:
           {
               Chara chara = Chara;
               if (chara != null && chara.isWet)
               {
                   dmg = dmg * 150 / 100;
               }
               break;
           }

濡れ状態でダメージが増減する処理です。

火炎は濡れ状態でダメージ三分の一。

電撃はダメージ1.5倍。

制圧による与ダメージ減少

if (origin != null && origin.isChara && origin.Chara.HasCondition<ConSupress>())
       {
           dmg = dmg * 2 / 3;
       }

制圧状態のキャラの与ダメージが減る処理です。

ダメージが、2/3倍になります。

※ここからはしばらく、AttackTypeがFinishでないときの計算です。

敵のレベルに応じたダメージ軽減

レベル50を超えた敵が受けるダメージ軽減量は以下の通りです:

まず、レベル50以下の敵の軽減率は0%、レベル1074以上の敵は軽減率80%となります。

if (!this.IsPCFaction && this.LV > 50)
{
    dmg = dmg * (100 - (int)Mathf.Min(80f, Mathf.Sqrt((float)(this.LV - 50)) * 2.5f)) / 100;
}


プレイヤーのファクションに属さないキャラで、レベルがLv50より高い場合:

与えるダメージに、* (100 - [ 2.5 * √(敵のレベル - 50) か 80 かのうち小さいほう ][2]) / 100が掛けられます。

つまり、Lv1074以上の敵に対してはダメージが80%減少し、Lv51~Lv1073の敵に対しては[sqrt(敵Lv-50) * 2.5]%減少します。

レベル毎のダメージ軽減
敵のLv 軽減率(%)
51 2
100 17
150 25
200 30
250 35
300 39
350 43
400 46
450 50
500 53
550 55
600 58
650 61
700 63
750 66
800 68
850 70
900 72
950 75
1000 77
1050 79
1074 80
1100 80

物理軽減と属性軽減によるダメージ減少

dmg = dmg * Mathf.Max(0, 100 - Evalue((e == Element.Void || e.id == 926) ? 55 : 56)) / 100;

属性が無いなら物理軽減、あるなら属性軽減を用いて、ダメージを(100-その値)/100内にします。

100-その値の下限は0となっており、ダメージがマイナスになるのを防いでいます。

これらの軽減は基本的には種族特性ですが、信仰AFの一部にはこれらを上昇させるものが存在します。

弱点の知識による与ダメージ減少

if (origin != null && origin.IsPC && EClass.player.codex.Has(id))
           {
               dmg = dmg * (100 + Mathf.Min(10, EClass.player.codex.GetOrCreate(id).weakspot)) / 100;
           }

危ない本かカード収集によるそのモンスターへの与ダメージ増加を示しています。

(100+収集数[3])%増加します。

ただし、上限は110%です。

盾による軽減

           if (isChara && Chara.body.GetAttackStyle() == AttackStyle.Shield && elements.ValueWithoutLink(123) >= 5 && (e == Element.Void || e.id == 926))
           {
               dmg = dmg * 90 / 100;
           }

スタイルが盾持ちのキャラには物理ダメージが0.9倍になります。

ダメージ耐性

if (Evalue(971) > 0)
           {
               dmg = dmg * 100 / Mathf.Clamp(100 + Evalue(971), 25, 1000);
           }

ダメージ耐性を持つなら、被ダメージが100/(100+その値)倍になります。

ただし、(100+その値)は下限25、上限1000に押し込められます。

ダメージ耐性は詳細は不明ですが、内部的には物理という属性への耐性であり、物理属性は通常の属性軽減の式では計算が除外されていることから、

ここで計算している可能性があります。魔法属性のファンネルが無属性に弱点であり、この計算式に関連する可能性があります。

大地の加護

           if (HasElement(1305))
           {
               dmg = dmg * 90 / 100;
           }

オパートス信仰による大地の加護を持つなら被ダメージが0.9倍。

狐守

           if (EClass.pc.HasElement(1207) && isChara)
           {
               int num = 0;
               int num2 = 0;
               foreach (Condition condition2 in Chara.conditions)
               {
                   if (condition2.Type == ConditionType.Buff)
                   {
                       num++;
                   }
                   else if (condition2.Type == ConditionType.Debuff)
                   {
                       num2++;
                   }
               }
               if (IsPCParty)
               {
                   dmg = dmg * 100 / Mathf.Min(100 + num * 5, 120);
               }
               else
               {
                   dmg = dmg * Mathf.Min(100 + num2 * 5, 120) / 100;
               }
           }

プレイヤーが狐守フィートを持っていると、 まず、バフの数をnum、デバフの数をnum2として、 プレイヤーのパーティ内のキャラなら、被ダメージが100/(100+num*5)倍になります。ただし、(100+num*5)は上限120を持ちます。 そうでないとき、被ダメージが(100+num*5)/100倍になります。ただし、(100+num*5)は上限120を持ちます。

フィートの説明文に反して、だれがつけたバフ・デバフであろうと、狐守持ちのプレイヤーがいれば発動する効果のようです。

味方ミニオンへの配慮がないために、味方ミニオンが敵からデバフをもらうと、被ダメージが増加すると考えられます。

オートコンバット時の被ダメージ減少

           if (IsPCParty && EClass.pc.ai is GoalAutoCombat)
           {
               dmg = dmg * 100 / Mathf.Clamp(105 + EClass.pc.Evalue(135) / 10, 10, 110);
           }

プレイヤーのパーティ内のキャラなら、オートコンバット中はダメージが100/(105+戦略スキル/10)倍になります。

ただし、(105+戦略スキル/10)は下限10、上限110に押し込められます。

つまり、戦略スキル50で軽減が上限に達します。

メタルフィートによるダメージ軽減

           if (HasElement(1218) && attackSource != AttackSource.ManaBackfire && (hp > 0 || Evalue(1421) <= 0))
           {
               dmg = dmg * (1000 - Evalue(1218)) / 1000;
               if (dmg <= 0 && EClass.rnd(4) == 0)
               {
                   dmg++;
               }
           }

メタルによるダメージ軽減です。(マナの反動によるダメージや、マナの体の恩恵でHP0に踏みとどまっているときに受けるダメージには適用されません。)

まず、ダメージが(1000-メタルのフィートLv.)/1000倍になります。メタルのフィートLv.は基本的に999なので、

ダメージは1000分の一になります。

そして、ダメージが0以下かつ、0-3が均等に出る乱数で0が出たとき、

ダメージが1増えます。

これはメタルにほとんどダメージを与えられない時でも、ときどきダメージが入る現象を起こしています。

致命傷防御によるダメージ軽減

           if (dmg >= MaxHP / 10 && Evalue(68) > 0)
           {
               int num3 = MaxHP / 10;
               int num4 = dmg - num3;
               num4 = num4 * 100 / (200 + Evalue(68) * 10);
               dmg = num3 + num4;
           }

致命傷防御を持っているとき、被ダメージが最大HPの10%を超えるようであれば、ダメージは、num3 + num4になります。

num3は最大HPの10%で、

num4は元のダメージが最大HPの10%を超えた量に、100/(200 + 致命傷防御の値*10)をかけたものです。

現状、致命傷防御は黄金の騎士で100、防衛者で50です。

※ここからはAttackTypeがFinishでも発生します。

暴力禁止による与ダメージ消滅

       if (origin != null && origin.IsPC && EClass.pc.Evalue(654) > 0)
       {
           dmg = 0;
       }

子狐丸の、暴力禁止エンチャントの効果です。

ダメージがプレイヤーに由来するなら0にします。

フェイルセーフ的符号確認

 if (dmg < 0)
       {
           dmg = 0;
       }

もしダメージがマイナスなら、0にします。

攻撃の手痛さ

int num5 = Mathf.Clamp(dmg * 6 / MaxHP, 0, 4) + ((dmg > 0) ? 1 : 0);

しばらく後に使われるnum5を計算します。

num5は攻撃の手痛さを示すと考えられます。

まず、ダメージの6倍を最大HPで割ったものを上限4、下限0に押し込めます。

次に、ダメージが正の数なら、それに1を足し、そうでないなら0を足したものがnum5です。

マナの体の仕様

こちらのページで説明されています

ダメージを受ける

 else
       {
           hp -= dmg;
       }

マナの体を持たない場合はただダメージを受けます。

被ダメージ時の処理

出血アニメーション

if (isSynced && dmg != 0)
       {
           float ratio = (float)dmg / (float)MaxHP;
           Card c = ((parent is Chara) ? (parent as Chara) : this);
           ActEffect.TryDelay(delegate
           {
               c.PlayEffect("blood").SetParticleColor(EClass.Colors.matColors[material.alias].main).Emit(20 + (int)(30f * ratio));
               if (EClass.core.config.test.showNumbers || isThing)
               {
                   Popper popper = EClass.scene.popper.Pop(renderer.PositionCenter(), "DamageNum");
                   Color c2 = (c.IsPC ? EClass.Colors.textColors.damagePC : (c.IsPCFaction ? EClass.Colors.textColors.damagePCParty : EClass.Colors.textColors.damage));
                   if (e != Element.Void)
                   {
                       c2 = EClass.Colors.elementColors.TryGetValue(e.source.alias);
                       float num14 = (c2.r + c2.g + c2.b) / 3f;
                       num14 = ((num14 > 0.5f) ? 0f : (0.6f - num14));
                       c2 = new Color(c2.r + num14, c2.g + num14, c2.b + num14, 1f);
                   }
                   popper.SetText(dmg.ToString() ?? "", c2);
               }
           });
       }

被ダメージのエフェクト、例えば普通の生物なら血、機械なら金属クズなどを発生させる処理と、

ダメージを表示するオプションがONになっている際のダメージ表記を行っています。

死を回避する

       void EvadeDeath()
       {
           hp = 0;
           if (Evalue(1421) > 0 && isChara && Chara.mana.value < 0)
           {
               Chara.mana.value = 0;
           }
       }

HPを0にし(HPがマイナスにならないとキャラクターは死亡しない)、マナの体を持っているキャラならば、MPを0にします。

スタミナ消費による

               else
               {
                   if (attackSource != AttackSource.Finish && IsPCParty && Chara.host == null)
                   {
                       if (EClass.pc.ai is GoalAutoCombat && !EClass.player.invlunerable && (EClass.pc.ai as GoalAutoCombat).listHealthy.Contains(Chara))
                       {
                           EClass.core.actionsNextFrame.Add(delegate
                           {
                               Msg.Say(IsPC ? "abort_damage" : "abort_damgeAlly");
                           });
                           EClass.player.invlunerable = true;
                           EClass.player.TryAbortAutoCombat();
                           EClass.pc.stamina.Mod(-EClass.pc.stamina.max / 5);
                       }
                       if (EClass.player.invlunerable)
                       {
                           EvadeDeath();
                           goto IL_0a8f;
                       }
                   }

受けた攻撃がFinishでなく、かつPCに騎乗も寄生もしていないペットのとき、スタミナを消費して耐えます。


運命の誓約による即死回避

                   if (IsPC && Evalue(1220) > 0 && Chara.stamina.value >= Chara.stamina.max / 2)
                   {
                       Chara.stamina.Mod(-Chara.stamina.max / 2);
                       Chara.AddCondition<ConInvulnerable>();
                       EvadeDeath();
                   }
               }

もし、運命の誓約モードかつ、スタミナが最大値の半分以上残っているなら、

スタミナを最大値の半分減らし、死を回避します。

状態異常付与

飛んで、4213行目から状態異常に関する記述がみられます。

詳細は、こちらでご覧ください。

  1. この100は冒頭で出てきたmodであり、バランス調整用に変数になっているものの、ただの定数値だと考えられます。。
  2. 正確には小さい方を四捨五入したもの
  3. 未確認