summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/map/atcommand.cpp12
-rw-r--r--src/map/battle.cpp256
-rw-r--r--src/map/map.hpp4
-rw-r--r--src/map/pc.cpp36
-rw-r--r--src/mmo/clif.t.hpp8
5 files changed, 190 insertions, 126 deletions
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index d7d47c9..b537431 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -2570,12 +2570,22 @@ ATCE atcommand_character_stats_full(Session *s, dumb_ptr<map_session_data>,
clif_displaymessage(s, output);
output = STRPRINTF("PERFECT_HIT_RATE: %d | PERFECT_HIT_ADD_RATE: %d | CRITICAL: %d | CRITICAL_RATE: %d | HIT: %d | HIT_RATE: %d"_fmt,
pl_sd->perfect_hit,
- pl_sd->perfect_hit_add,
+ pl_sd->perfect_hit_add_rate,
pl_sd->critical,
pl_sd->critical_rate,
pl_sd->hit,
pl_sd->hit_rate);
clif_displaymessage(s, output);
+ output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d"_fmt,
+ pl_sd->deadly_strike,
+ pl_sd->deadly_strike_add_rate);
+ clif_displaymessage(s, output);
+ output = STRPRINTF("arrow_atk: %d | arrow_cri: %d | arrow_hit: %d | arrow_range: %d"_fmt,
+ pl_sd->arrow_atk,
+ pl_sd->arrow_cri,
+ pl_sd->arrow_hit,
+ pl_sd->arrow_range);
+ clif_displaymessage(s, output);
output = STRPRINTF("HP_DRAIN_RATE: %d | HP_DRAIN_RATE per: %d | SP_DRAIN_RATE: %d | SP_DRAIN_RATE per: %d"_fmt,
pl_sd->hp_drain_rate,
pl_sd->hp_drain_per,
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index 3b7c6b2..eaa37a0 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -1469,7 +1469,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src,
ATK dmg_lv = ATK::ZERO;
eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data, t_sc_data;
int watk;
- bool da = false;
+ bool da = false, ds = false;
int ac_flag = 0;
int target_distance;
@@ -1482,7 +1482,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src,
sd->state.attack_type = BF::WEAPON; // 攻撃タイプは武器攻撃 | Attack type is weapon attack
- // ターゲット
+ // ターゲット | target
if (target->bl_type == BL::PC) // 対象がPCなら | If the target is a PC
tsd = target->is_player(); // tsdに代入(tmdはNULL) | Assign to tsd (tmd is NULL)
else if (target->bl_type == BL::MOB) // 対象がMobなら | If the target is a mob
@@ -1575,143 +1575,154 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src,
if (atkmin > atkmax && !(sd->state.arrow_atk))
atkmin = atkmax; // 弓は最低が上回る場合あり | Bow may exceed minimum
- if (sd->double_rate > 0 && skill_num == SkillID::ZERO && skill_lv >= 0)
- da = random_::chance({sd->double_rate, 100});
-
- if (!da)
- { // ダブルアタックが発動していない | Double Attack is not activated
- // クリティカル計算 | critical calculation
- cri = battle_get_critical(src);
-
- if (sd->state.arrow_atk)
- cri += sd->arrow_cri;
- cri -= battle_get_luk(target) * 3;
- if (ac_flag)
- cri = 1000;
- }
-
- if (tsd && tsd->critical_def)
- cri = cri * (100 - tsd->critical_def) / 100;
- else if (tmd && tmd->stats[mob_stat::CRITICAL_DEF])
- cri = cri * (100 - tmd->stats[mob_stat::CRITICAL_DEF]) / 100;
+ if (tmd && !bool(t_mode & MobMode::BOSS)) // deadly strike works only on mobs but not on mobs with boss flag
+ if (sd->deadly_strike > 0)
+ ds = random_::chance({sd->deadly_strike, 100});
- // ダブルアタックが発動していない | Double Attack is not activated
- // 判定(スキルの場合は無視) | Judgment (ignored for skills)
- if (!da && skill_num == SkillID::ZERO && skill_lv >= 0
- && random_::chance({cri, 1000}))
+ if (!ds) // no double, crit and normal damage calculation needed if it is a deadly strike
{
- damage += atkmax;
- if (sd->atk_rate != 100)
- {
- damage = (damage * sd->atk_rate) / 100;
- }
- if (sd->state.arrow_atk)
- damage += sd->arrow_atk;
- type = DamageType::CRITICAL;
- }
- else
- {
- int vitbonusmax;
+ if (sd->double_rate > 0 && skill_num == SkillID::ZERO && skill_lv >= 0)
+ da = random_::chance({sd->double_rate, 100});
- if (atkmax > atkmin)
- damage += random_::in(atkmin, atkmax);
- else
- damage += atkmin;
- if (sd->atk_rate != 100)
+ if (!da)
{
- damage = (damage * sd->atk_rate) / 100;
+ // ダブルアタックが発動していない | Double Attack is not activated
+ // クリティカル計算 | critical calculation
+ cri = battle_get_critical(src);
+
+ if (sd->state.arrow_atk)
+ cri += sd->arrow_cri;
+ cri -= battle_get_luk(target) * 3;
+ if (ac_flag)
+ cri = 1000;
}
- if (sd->state.arrow_atk)
+ if (tsd && tsd->critical_def)
+ cri = cri * (100 - tsd->critical_def) / 100;
+ else if (tmd && tmd->stats[mob_stat::CRITICAL_DEF])
+ cri = cri * (100 - tmd->stats[mob_stat::CRITICAL_DEF]) / 100;
+
+ // ダブルアタックが発動していない | Double Attack is not activated
+ // 判定(スキルの場合は無視) | Judgment (ignored for skills)
+ if (!da && skill_num == SkillID::ZERO && skill_lv >= 0
+ && random_::chance({cri, 1000}))
{
- if (sd->arrow_atk > 0)
- damage += random_::in(0, sd->arrow_atk);
- hitrate += sd->arrow_hit;
+ damage += atkmax;
+ if (sd->atk_rate != 100)
+ {
+ damage = (damage * sd->atk_rate) / 100;
+ }
+ if (sd->state.arrow_atk)
+ damage += sd->arrow_atk;
+ type = DamageType::CRITICAL;
}
-
- if (skill_num != SkillID::ZERO && skill_num != SkillID::NEGATIVE)
+ else
{
- flag = (flag & ~BF::SKILLMASK) | BF::SKILL;
- }
+ int vitbonusmax;
- {
- // 対 象の防御力によるダメージの減少 | Decreased damage due to target's defense
- // ディバインプロテクション(ここでいいのかな?) | Divine Protection (maybe here?)
- if (def1 < 1000000)
- { // DEF, VIT無視 | DEF, VIT ignore
- int t_def;
- target_count =
- 1 + battle_counttargeted(target, src,
- battle_config.vit_penaly_count_lv);
- if (battle_config.vit_penaly_type > 0)
- {
- if (target_count >= battle_config.vit_penaly_count)
+ if (atkmax > atkmin)
+ damage += random_::in(atkmin, atkmax);
+ else
+ damage += atkmin;
+ if (sd->atk_rate != 100)
+ {
+ damage = (damage * sd->atk_rate) / 100;
+ }
+
+ if (sd->state.arrow_atk)
+ {
+ if (sd->arrow_atk > 0)
+ damage += random_::in(0, sd->arrow_atk);
+ hitrate += sd->arrow_hit;
+ }
+
+ if (skill_num != SkillID::ZERO && skill_num != SkillID::NEGATIVE)
+ {
+ flag = (flag & ~BF::SKILLMASK) | BF::SKILL;
+ }
+
+ {
+ // 対 象の防御力によるダメージの減少 | Decreased damage due to target's defense
+ // ディバインプロテクション(ここでいいのかな?) | Divine Protection (maybe here?)
+ if (def1 < 1000000)
+ { // DEF, VIT無視 | DEF, VIT ignore
+ int t_def;
+ target_count =
+ 1 + battle_counttargeted(target, src,
+ battle_config.vit_penaly_count_lv);
+ if (battle_config.vit_penaly_type > 0)
{
- if (battle_config.vit_penaly_type == 1)
+ if (target_count >= battle_config.vit_penaly_count)
{
- def1 =
- (def1 *
- (100 -
- (target_count -
- (battle_config.vit_penaly_count -
- 1)) * battle_config.vit_penaly_num)) /
- 100;
- def2 =
- (def2 *
- (100 -
- (target_count -
- (battle_config.vit_penaly_count -
- 1)) * battle_config.vit_penaly_num)) /
- 100;
- t_vit =
- (t_vit *
- (100 -
- (target_count -
- (battle_config.vit_penaly_count -
- 1)) * battle_config.vit_penaly_num)) /
- 100;
- }
- else if (battle_config.vit_penaly_type == 2)
- {
- def1 -=
- (target_count -
- (battle_config.vit_penaly_count -
- 1)) * battle_config.vit_penaly_num;
- def2 -=
- (target_count -
- (battle_config.vit_penaly_count -
- 1)) * battle_config.vit_penaly_num;
- t_vit -=
- (target_count -
- (battle_config.vit_penaly_count -
- 1)) * battle_config.vit_penaly_num;
+ if (battle_config.vit_penaly_type == 1)
+ {
+ def1 =
+ (def1 *
+ (100 -
+ (target_count -
+ (battle_config.vit_penaly_count -
+ 1)) * battle_config.vit_penaly_num)) /
+ 100;
+ def2 =
+ (def2 *
+ (100 -
+ (target_count -
+ (battle_config.vit_penaly_count -
+ 1)) * battle_config.vit_penaly_num)) /
+ 100;
+ t_vit =
+ (t_vit *
+ (100 -
+ (target_count -
+ (battle_config.vit_penaly_count -
+ 1)) * battle_config.vit_penaly_num)) /
+ 100;
+ }
+ else if (battle_config.vit_penaly_type == 2)
+ {
+ def1 -=
+ (target_count -
+ (battle_config.vit_penaly_count -
+ 1)) * battle_config.vit_penaly_num;
+ def2 -=
+ (target_count -
+ (battle_config.vit_penaly_count -
+ 1)) * battle_config.vit_penaly_num;
+ t_vit -=
+ (target_count -
+ (battle_config.vit_penaly_count -
+ 1)) * battle_config.vit_penaly_num;
+ }
+ if (def1 < 0)
+ def1 = 0;
+ if (def2 < 1)
+ def2 = 1;
+ if (t_vit < 1)
+ t_vit = 1;
}
- if (def1 < 0)
- def1 = 0;
- if (def2 < 1)
- def2 = 1;
- if (t_vit < 1)
- t_vit = 1;
}
- }
- t_def = def2 * 8 / 10;
- vitbonusmax = (t_vit / 20) * (t_vit / 20) - 1;
+ t_def = def2 * 8 / 10;
+ vitbonusmax = (t_vit / 20) * (t_vit / 20) - 1;
- {
{
- damage = damage * (100 - def1) / 100;
- damage -= t_def;
- if (vitbonusmax > 0)
- damage -= random_::in(0, vitbonusmax);
+ {
+ damage = damage * (100 - def1) / 100;
+ damage -= t_def;
+ if (vitbonusmax > 0)
+ damage -= random_::in(0, vitbonusmax);
+ }
}
}
}
}
+ // 精錬ダメージの追加 | Add refining damage
+ { // DEF, VIT無視 | DEF, VIT ignore
+ damage += battle_get_atk2(src);
+ }
}
- // 精錬ダメージの追加 | Add refining damage
- { // DEF, VIT無視 | DEF, VIT ignore
- damage += battle_get_atk2(src);
- }
+ else
+ if (sd->state.arrow_atk)
+ hitrate += sd->arrow_hit;
// 0未満だった場合1に補正 | Corrected to 1 if less than 0
if (damage < 1)
@@ -1743,6 +1754,15 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src,
if (damage < 0)
damage = 0;
+ if (ds)
+ {
+ damage = tmd->hp;
+ //type = DamageType::DEADLY;
+ // M+ does not support this value on package 0x008a it lags a bit and displays an error message.
+ // This can be implemented if ManaVerse is the only supported client so long DamageType::CRITICAL will do
+ type = DamageType::CRITICAL;
+ }
+
// 右手,短剣のみ | right hand, dagger only
if (da)
{ // ダブルアタックが発動しているか | Is double attack activated?
diff --git a/src/map/map.hpp b/src/map/map.hpp
index af074ba..a4295fd 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -259,10 +259,10 @@ struct map_session_data : block_list, SessionData
int aspd_rate, speed_rate, hprecov_rate, sprecov_rate, critical_def,
double_rate;
int matk_rate;
- int perfect_hit;
+ int perfect_hit, deadly_strike;
int critical_rate, hit_rate, flee_rate, flee2_rate, def_rate, def2_rate,
mdef_rate, mdef2_rate;
- int double_add_rate, speed_add_rate, aspd_add_rate, perfect_hit_add;
+ int double_add_rate, speed_add_rate, aspd_add_rate, perfect_hit_add_rate, deadly_strike_add_rate;
short hp_drain_rate, hp_drain_per, sp_drain_rate, sp_drain_per;
int die_counter;
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index 9fd23b9..3e8cd6e 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -1193,11 +1193,11 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
sd->double_rate = 0;
sd->atk_rate = sd->matk_rate = 100;
sd->arrow_cri = 0;
- sd->perfect_hit = 0;
+ sd->perfect_hit = sd->deadly_strike = 0;
sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
sd->speed_add_rate = sd->aspd_add_rate = 100;
- sd->double_add_rate = sd->perfect_hit_add = 0;
+ sd->double_add_rate = sd->perfect_hit_add_rate = sd->deadly_strike_add_rate = 0;
sd->hp_drain_rate = sd->hp_drain_per = sd->sp_drain_rate =
sd->sp_drain_per = 0;
@@ -1328,7 +1328,8 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
if (sd->status.weapon == ItemLook::BOW)
sd->attackrange += sd->arrow_range;
sd->double_rate += sd->double_add_rate;
- sd->perfect_hit += sd->perfect_hit_add;
+ sd->perfect_hit += sd->perfect_hit_add_rate;
+ sd->deadly_strike += sd->deadly_strike_add_rate;
if (sd->speed_add_rate != 100)
sd->speed_rate += sd->speed_add_rate - 100;
if (sd->aspd_add_rate != 100)
@@ -1797,7 +1798,7 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val)
break;
case SP::PERFECT_HIT_ADD_RATE:
if (!sd->state.lr_flag_is_arrow_2)
- sd->perfect_hit_add += val;
+ sd->perfect_hit_add_rate += val;
break;
case SP::CRITICAL_RATE:
if (!sd->state.lr_flag_is_arrow_2)
@@ -1836,10 +1837,35 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val)
break;
case SP::SPEED_CAP:
if (!sd->state.lr_flag_is_arrow_2)
- // lowest cap is taken others are ignored
+ // highest value (slowest speed) is taken others are ignored
if (sd->speed_cap < interval_t(val))
sd->speed_cap = interval_t(val);
break;
+ case SP::ALL_STATS:
+ sd->parame[ATTR::STR] += val;
+ sd->parame[ATTR::AGI] += val;
+ sd->parame[ATTR::VIT] += val;
+ sd->parame[ATTR::INT] += val;
+ sd->parame[ATTR::DEX] += val;
+ sd->parame[ATTR::LUK] += val;
+ break;
+ case SP::AGI_VIT:
+ sd->parame[ATTR::AGI] += val;
+ sd->parame[ATTR::VIT] += val;
+ break;
+ case SP::AGI_DEX_STR:
+ sd->parame[ATTR::AGI] += val;
+ sd->parame[ATTR::DEX] += val;
+ sd->parame[ATTR::STR] += val;
+ break;
+ case SP::DEADLY_STRIKE_RATE:
+ if (!sd->state.lr_flag_is_arrow_2 && sd->deadly_strike < val)
+ sd->deadly_strike = val;
+ break;
+ case SP::DEADLY_STRIKE_ADD_RATE:
+ if (!sd->state.lr_flag_is_arrow_2)
+ sd->deadly_strike_add_rate += val;
+ break;
default:
if (battle_config.error_log)
PRINTF("pc_bonus: unknown type %d %d !\n"_fmt,
diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp
index 830c5bd..e92c349 100644
--- a/src/mmo/clif.t.hpp
+++ b/src/mmo/clif.t.hpp
@@ -153,6 +153,7 @@ enum class DamageType : uint8_t
DOUBLED = 0x08,
CRITICAL = 0x0a,
FLEE2 = 0x0b,
+ DEADLY = 0x0c,
};
enum class LOOK : uint8_t
@@ -474,6 +475,13 @@ enum class SP : uint16_t
AUTOMOD = 1086,
SPEED_CAP = 1087,
+
+ ALL_STATS = 1088,
+ AGI_VIT = 1089,
+ AGI_DEX_STR = 1090,
+
+ DEADLY_STRIKE_RATE = 1091,
+ DEADLY_STRIKE_ADD_RATE = 1092,
};
constexpr