浏览代码

Random options update (#3993)

* Implemented additional random options from official server
Fixed #3988

Thanks to @Stolao @cydh @aleos89
Jittapan Pluemsumran 4 年之前
父节点
当前提交
2e04ca98b0
共有 10 个文件被更改,包括 214 次插入47 次删除
  1. 46 22
      db/const.txt
  2. 39 16
      db/re/item_randomopt_db.txt
  3. 1 1
      doc/atcommands.txt
  4. 3 0
      doc/item_bonus.txt
  5. 49 6
      src/map/battle.cpp
  6. 1 1
      src/map/map.hpp
  7. 60 1
      src/map/pc.cpp
  8. 10 0
      src/map/pc.hpp
  9. 3 0
      src/map/script_constants.hpp
  10. 2 0
      src/map/status.cpp

+ 46 - 22
db/const.txt

@@ -48,7 +48,7 @@ RDMOPT_ATTR_TOLERACE_SAINT	31
 RDMOPT_ATTR_TOLERACE_DARKNESS	32
 RDMOPT_ATTR_TOLERACE_DARKNESS	32
 RDMOPT_ATTR_TOLERACE_TELEKINESIS	33
 RDMOPT_ATTR_TOLERACE_TELEKINESIS	33
 RDMOPT_ATTR_TOLERACE_UNDEAD	34
 RDMOPT_ATTR_TOLERACE_UNDEAD	34
-RDMOPT_ATTR_TOLERACE_ALL	35
+RDMOPT_ATTR_TOLERACE_ALLBUTNOTHING	35
 RDMOPT_DAMAGE_PROPERTY_NOTHING_USER	36
 RDMOPT_DAMAGE_PROPERTY_NOTHING_USER	36
 RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET	37
 RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET	37
 RDMOPT_DAMAGE_PROPERTY_WATER_USER	38
 RDMOPT_DAMAGE_PROPERTY_WATER_USER	38
@@ -186,27 +186,51 @@ RDMOPT_HEAL_MODIFY_PERCENT	169
 RDMOPT_DEC_SPELL_CAST_TIME	170
 RDMOPT_DEC_SPELL_CAST_TIME	170
 RDMOPT_DEC_SPELL_DELAY_TIME	171
 RDMOPT_DEC_SPELL_DELAY_TIME	171
 RDMOPT_DEC_SP_CONSUMPTION	172
 RDMOPT_DEC_SP_CONSUMPTION	172
-RDMOPT_HP_DRAIN	173
-RDMOPT_SP_DRAIN	174
-RDMOPT_WEAPON_ATTR_NOTHING	175
-RDMOPT_WEAPON_ATTR_WATER	176
-RDMOPT_WEAPON_ATTR_GROUND	177
-RDMOPT_WEAPON_ATTR_FIRE	178
-RDMOPT_WEAPON_ATTR_WIND	179
-RDMOPT_WEAPON_ATTR_POISON	180
-RDMOPT_WEAPON_ATTR_SAINT	181
-RDMOPT_WEAPON_ATTR_DARKNESS	182
-RDMOPT_WEAPON_ATTR_TELEKINESIS	183
-RDMOPT_WEAPON_ATTR_UNDEAD	184
-RDMOPT_WEAPON_INDESTRUCTIBLE	185
-RDMOPT_BODY_INDESTRUCTIBLE	186
-RDMOPT_MDAMAGE_SIZE_SMALL_TARGET	187
-RDMOPT_MDAMAGE_SIZE_MIDIUM_TARGET	188
-RDMOPT_MDAMAGE_SIZE_LARGE_TARGET	189
-RDMOPT_MDAMAGE_SIZE_SMALL_USER	190
-RDMOPT_MDAMAGE_SIZE_MIDIUM_USER	191
-RDMOPT_MDAMAGE_SIZE_LARGE_USER	192
-//RDMOPT_ATTR_TOLERACE_ALL	193
+RDMOPT_WEAPON_ATTR_NOTHING	173
+RDMOPT_WEAPON_ATTR_WATER	174
+RDMOPT_WEAPON_ATTR_GROUND	175
+RDMOPT_WEAPON_ATTR_FIRE	176
+RDMOPT_WEAPON_ATTR_WIND	177
+RDMOPT_WEAPON_ATTR_POISON	178
+RDMOPT_WEAPON_ATTR_SAINT	179
+RDMOPT_WEAPON_ATTR_DARKNESS	180
+RDMOPT_WEAPON_ATTR_TELEKINESIS	181
+RDMOPT_WEAPON_ATTR_UNDEAD	182
+RDMOPT_WEAPON_INDESTRUCTIBLE	183
+RDMOPT_BODY_INDESTRUCTIBLE	184
+RDMOPT_MDAMAGE_SIZE_SMALL_TARGET	185
+RDMOPT_MDAMAGE_SIZE_MIDIUM_TARGET	186
+RDMOPT_MDAMAGE_SIZE_LARGE_TARGET	187
+RDMOPT_MDAMAGE_SIZE_SMALL_USER	188
+RDMOPT_MDAMAGE_SIZE_MIDIUM_USER	189
+RDMOPT_MDAMAGE_SIZE_LARGE_USER	190
+RDMOPT_ATTR_TOLERACE_ALL	191
+RDMOPT_RACE_WEAPON_TOLERACE_NOTHING	192
+RDMOPT_RACE_WEAPON_TOLERACE_UNDEAD	193
+RDMOPT_RACE_WEAPON_TOLERACE_ANIMAL	194
+RDMOPT_RACE_WEAPON_TOLERACE_PLANT	195
+RDMOPT_RACE_WEAPON_TOLERACE_INSECT	196
+RDMOPT_RACE_WEAPON_TOLERACE_FISHS	197
+RDMOPT_RACE_WEAPON_TOLERACE_DEVIL	198
+RDMOPT_RACE_WEAPON_TOLERACE_HUMAN	199
+RDMOPT_RACE_WEAPON_TOLERACE_ANGEL	200
+RDMOPT_RACE_WEAPON_TOLERACE_DRAGON	201
+RDMOPT_RANGE_WEAPON_ATTACK_DAMAGE_TARGET	202
+RDMOPT_RANGE_WEAPON_ATTACK_DAMAGE_USER	203
+RDMOPT_RACE_TOLERACE_PLAYER_DORAM	204
+RDMOPT_RACE_DAMAGE_PLAYER_HUMAN	205
+RDMOPT_RACE_DAMAGE_PLAYER_DORAM	206
+RDMOPT_RACE_MDAMAGE_PLAYER_HUMAN	207
+RDMOPT_RACE_MDAMAGE_PLAYER_DORAM	208
+RDMOPT_RACE_CRI_PERCENT_PLAYER_HUMAN	209
+RDMOPT_RACE_CRI_PERCENT_PLAYER_DORAM	210
+RDMOPT_RACE_IGNORE_DEF_PERCENT_PLAYER_HUMAN	211
+RDMOPT_RACE_IGNORE_DEF_PERCENT_PLAYER_DORAM	212
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLAYER_HUMAN	213
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLAYER_DORAM	214
+RDMOPT_REFLECT_DAMAGE_PERCENT	215
+RDMOPT_MELEE_ATTACK_DAMAGE_TARGET	216
+RDMOPT_MELEE_ATTACK_DAMAGE_USER	217
 
 
 SWORDCLAN	1
 SWORDCLAN	1
 ARCWANDCLAN	2
 ARCWANDCLAN	2

+ 39 - 16
db/re/item_randomopt_db.txt

@@ -36,9 +36,7 @@ RDMOPT_ATTR_TOLERACE_SAINT,{ bonus2 bSubEle,Ele_Holy,getrandomoptinfo(ROA_VALUE)
 RDMOPT_ATTR_TOLERACE_DARKNESS,{ bonus2 bSubEle,Ele_Dark,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_ATTR_TOLERACE_DARKNESS,{ bonus2 bSubEle,Ele_Dark,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_ATTR_TOLERACE_TELEKINESIS,{ bonus2 bSubEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_ATTR_TOLERACE_TELEKINESIS,{ bonus2 bSubEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_ATTR_TOLERACE_UNDEAD,{ bonus2 bSubEle,Ele_Undead,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_ATTR_TOLERACE_UNDEAD,{ bonus2 bSubEle,Ele_Undead,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_ATTR_TOLERACE_ALL,{ bonus2 bSubEle,Ele_All,getrandomoptinfo(ROA_VALUE); }
-// TODO: Confirm if damage reduction is implemented correctly.
-// kRO desc : <ELEMENT> 몬스터로부터 받는 물리 데미지 %d%% 감소.
+RDMOPT_ATTR_TOLERACE_ALLBUTNOTHING,{ for(.@i = Ele_Water; .@i < Ele_Undead; ++.@i) bonus2 bSubEle,.@i,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_PROPERTY_NOTHING_USER,{ bonus2 bSubDefEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_PROPERTY_NOTHING_USER,{ bonus2 bSubDefEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET,{ bonus2 bAddEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET,{ bonus2 bAddEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_PROPERTY_WATER_USER,{ bonus2 bSubDefEle,Ele_Water,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_PROPERTY_WATER_USER,{ bonus2 bSubDefEle,Ele_Water,getrandomoptinfo(ROA_VALUE); }
@@ -89,7 +87,7 @@ RDMOPT_BODY_ATTR_SAINT,{ bonus bDefEle,Ele_Holy; }
 RDMOPT_BODY_ATTR_DARKNESS,{ bonus bDefEle,Ele_Dark; }
 RDMOPT_BODY_ATTR_DARKNESS,{ bonus bDefEle,Ele_Dark; }
 RDMOPT_BODY_ATTR_TELEKINESIS,{ bonus bDefEle,Ele_Ghost; }
 RDMOPT_BODY_ATTR_TELEKINESIS,{ bonus bDefEle,Ele_Ghost; }
 RDMOPT_BODY_ATTR_UNDEAD,{ bonus bDefEle,Ele_Undead; }
 RDMOPT_BODY_ATTR_UNDEAD,{ bonus bDefEle,Ele_Undead; }
-//RDMOPT_BODY_ATTR_ALL,{ /* Needs more info */ }
+//RDMOPT_BODY_ATTR_ALL,{}
 RDMOPT_RACE_TOLERACE_NOTHING,{ bonus2 bSubRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_NOTHING,{ bonus2 bSubRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_UNDEAD,{ bonus2 bSubRace,RC_Undead,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_UNDEAD,{ bonus2 bSubRace,RC_Undead,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_ANIMAL,{ bonus2 bSubRace,RC_Brute,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_ANIMAL,{ bonus2 bSubRace,RC_Brute,getrandomoptinfo(ROA_VALUE); }
@@ -97,7 +95,7 @@ RDMOPT_RACE_TOLERACE_PLANT,{ bonus2 bSubRace,RC_Plant,getrandomoptinfo(ROA_VALUE
 RDMOPT_RACE_TOLERACE_INSECT,{ bonus2 bSubRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_INSECT,{ bonus2 bSubRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_FISHS,{ bonus2 bSubRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_FISHS,{ bonus2 bSubRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_DEVIL,{ bonus2 bSubRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_DEVIL,{ bonus2 bSubRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_RACE_TOLERACE_HUMAN,{ bonus2 bSubRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bSubRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_HUMAN,{ bonus2 bSubRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_ANGEL,{ bonus2 bSubRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_ANGEL,{ bonus2 bSubRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_DRAGON,{ bonus2 bSubRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_TOLERACE_DRAGON,{ bonus2 bSubRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_NOTHING,{ bonus2 bAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_NOTHING,{ bonus2 bAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
@@ -107,7 +105,7 @@ RDMOPT_RACE_DAMAGE_PLANT,{ bonus2 bAddRace,RC_Plant,getrandomoptinfo(ROA_VALUE);
 RDMOPT_RACE_DAMAGE_INSECT,{ bonus2 bAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_INSECT,{ bonus2 bAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_FISHS,{ bonus2 bAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_FISHS,{ bonus2 bAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_DEVIL,{ bonus2 bAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_DEVIL,{ bonus2 bAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_RACE_DAMAGE_HUMAN,{ bonus2 bAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bAddRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_HUMAN,{ bonus2 bAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_ANGEL,{ bonus2 bAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_ANGEL,{ bonus2 bAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_DRAGON,{ bonus2 bAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_DAMAGE_DRAGON,{ bonus2 bAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_NOTHING,{ bonus2 bMagicAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_NOTHING,{ bonus2 bMagicAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
@@ -117,7 +115,7 @@ RDMOPT_RACE_MDAMAGE_PLANT,{ bonus2 bMagicAddRace,RC_Plant,getrandomoptinfo(ROA_V
 RDMOPT_RACE_MDAMAGE_INSECT,{ bonus2 bMagicAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_INSECT,{ bonus2 bMagicAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_FISHS,{ bonus2 bMagicAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_FISHS,{ bonus2 bMagicAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_DEVIL,{ bonus2 bMagicAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_DEVIL,{ bonus2 bMagicAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_RACE_MDAMAGE_HUMAN,{ bonus2 bMagicAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bMagicAddRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_HUMAN,{ bonus2 bMagicAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_ANGEL,{ bonus2 bMagicAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_ANGEL,{ bonus2 bMagicAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_DRAGON,{ bonus2 bMagicAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_MDAMAGE_DRAGON,{ bonus2 bMagicAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_CRI_PERCENT_NOTHING,{ bonus2 bCriticalAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_NOTHING,{ bonus2 bCriticalAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE)/10; }
@@ -127,7 +125,7 @@ RDMOPT_RACE_CRI_PERCENT_PLANT,{ bonus2 bCriticalAddRace,RC_Plant,getrandomoptinf
 RDMOPT_RACE_CRI_PERCENT_INSECT,{ bonus2 bCriticalAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_INSECT,{ bonus2 bCriticalAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_FISHS,{ bonus2 bCriticalAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_FISHS,{ bonus2 bCriticalAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_DEVIL,{ bonus2 bCriticalAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_DEVIL,{ bonus2 bCriticalAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE)/10; }
-RDMOPT_RACE_CRI_PERCENT_HUMAN,{ bonus2 bCriticalAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE)/10; bonus2 bCriticalAddRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_HUMAN,{ bonus2 bCriticalAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_ANGEL,{ bonus2 bCriticalAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_ANGEL,{ bonus2 bCriticalAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_DRAGON,{ bonus2 bCriticalAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_CRI_PERCENT_DRAGON,{ bonus2 bCriticalAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE)/10; }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_NOTHING,{ bonus2 bIgnoreDefRaceRate,RC_Formless,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_NOTHING,{ bonus2 bIgnoreDefRaceRate,RC_Formless,getrandomoptinfo(ROA_VALUE); }
@@ -137,7 +135,7 @@ RDMOPT_RACE_IGNORE_DEF_PERCENT_PLANT,{ bonus2 bIgnoreDefRaceRate,RC_Plant,getran
 RDMOPT_RACE_IGNORE_DEF_PERCENT_INSECT,{ bonus2 bIgnoreDefRaceRate,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_INSECT,{ bonus2 bIgnoreDefRaceRate,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_FISHS,{ bonus2 bIgnoreDefRaceRate,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_FISHS,{ bonus2 bIgnoreDefRaceRate,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_DEVIL,{ bonus2 bIgnoreDefRaceRate,RC_Demon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_DEVIL,{ bonus2 bIgnoreDefRaceRate,RC_Demon,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_RACE_IGNORE_DEF_PERCENT_HUMAN,{ bonus2 bIgnoreDefRaceRate,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bIgnoreDefRaceRate,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_HUMAN,{ bonus2 bIgnoreDefRaceRate,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_ANGEL,{ bonus2 bIgnoreDefRaceRate,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_ANGEL,{ bonus2 bIgnoreDefRaceRate,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_DRAGON,{ bonus2 bIgnoreDefRaceRate,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_DEF_PERCENT_DRAGON,{ bonus2 bIgnoreDefRaceRate,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_NOTHING,{ bonus2 bIgnoreMdefRaceRate,RC_Formless,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_NOTHING,{ bonus2 bIgnoreMdefRaceRate,RC_Formless,getrandomoptinfo(ROA_VALUE); }
@@ -147,7 +145,7 @@ RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLANT,{ bonus2 bIgnoreMdefRaceRate,RC_Plant,getr
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_INSECT,{ bonus2 bIgnoreMdefRaceRate,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_INSECT,{ bonus2 bIgnoreMdefRaceRate,RC_Insect,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_FISHS,{ bonus2 bIgnoreMdefRaceRate,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_FISHS,{ bonus2 bIgnoreMdefRaceRate,RC_Fish,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_DEVIL,{ bonus2 bIgnoreMdefRaceRate,RC_Demon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_DEVIL,{ bonus2 bIgnoreMdefRaceRate,RC_Demon,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_RACE_IGNORE_MDEF_PERCENT_HUMAN,{ bonus2 bIgnoreMdefRaceRate,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bIgnoreMdefRaceRate,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_HUMAN,{ bonus2 bIgnoreMdefRaceRate,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_ANGEL,{ bonus2 bIgnoreMdefRaceRate,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_ANGEL,{ bonus2 bIgnoreMdefRaceRate,RC_Angel,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_DRAGON,{ bonus2 bIgnoreMdefRaceRate,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RACE_IGNORE_MDEF_PERCENT_DRAGON,{ bonus2 bIgnoreMdefRaceRate,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_CLASS_DAMAGE_NORMAL_TARGET,{ bonus2 bAddClass,Class_Normal,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_CLASS_DAMAGE_NORMAL_TARGET,{ bonus2 bAddClass,Class_Normal,getrandomoptinfo(ROA_VALUE); }
@@ -168,7 +166,7 @@ RDMOPT_DAMAGE_SIZE_MIDIUM_USER,{ bonus2 bSubSize,Size_Medium,getrandomoptinfo(RO
 RDMOPT_DAMAGE_SIZE_LARGE_USER,{ bonus2 bSubSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_SIZE_LARGE_USER,{ bonus2 bSubSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_SIZE_PERFECT,{ bonus bNoSizeFix,1; }
 RDMOPT_DAMAGE_SIZE_PERFECT,{ bonus bNoSizeFix,1; }
 RDMOPT_DAMAGE_CRI_TARGET,{ bonus bCritAtkRate,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_DAMAGE_CRI_TARGET,{ bonus bCritAtkRate,getrandomoptinfo(ROA_VALUE); }
-RDMOPT_DAMAGE_CRI_USER,{ bonus bCriticalDef,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_CRI_USER,{ bonus bCritDefRate,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RANGE_ATTACK_DAMAGE_TARGET,{ bonus bLongAtkRate,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RANGE_ATTACK_DAMAGE_TARGET,{ bonus bLongAtkRate,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RANGE_ATTACK_DAMAGE_USER,{ bonus bLongAtkDef,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_RANGE_ATTACK_DAMAGE_USER,{ bonus bLongAtkDef,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_HEAL_VALUE,{ bonus bHealPower,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_HEAL_VALUE,{ bonus bHealPower,getrandomoptinfo(ROA_VALUE); }
@@ -193,8 +191,33 @@ RDMOPT_BODY_INDESTRUCTIBLE,{ bonus bUnbreakableArmor,1; }
 RDMOPT_MDAMAGE_SIZE_SMALL_TARGET,{ bonus2 bMagicAddSize,Size_Small,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_MDAMAGE_SIZE_SMALL_TARGET,{ bonus2 bMagicAddSize,Size_Small,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_MDAMAGE_SIZE_MIDIUM_TARGET,{ bonus2 bMagicAddSize,Size_Medium,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_MDAMAGE_SIZE_MIDIUM_TARGET,{ bonus2 bMagicAddSize,Size_Medium,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_MDAMAGE_SIZE_LARGE_TARGET,{ bonus2 bMagicAddSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
 RDMOPT_MDAMAGE_SIZE_LARGE_TARGET,{ bonus2 bMagicAddSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
-//RDMOPT_MDAMAGE_SIZE_SMALL_USER,{}
-//RDMOPT_MDAMAGE_SIZE_MIDIUM_USER,{}
-//RDMOPT_MDAMAGE_SIZE_LARGE_USER,{}
-//redefined?
-//RDMOPT_ATTR_TOLERACE_ALL,{}
+RDMOPT_MDAMAGE_SIZE_SMALL_USER,{ bonus2 bMagicSubSize,Size_Small,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_SIZE_MIDIUM_USER,{ bonus2 bMagicSubSize,Size_Medium,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_SIZE_LARGE_USER,{ bonus2 bMagicSubSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_ALL,{ bonus2 bSubEle,Ele_All,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_WEAPON_TOLERACE_NOTHING,{ bonus3 bSubRace,RC_Formless,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_UNDEAD,{ bonus3 bSubRace,RC_Undead,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_ANIMAL,{ bonus3 bSubRace,RC_Brute,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_PLANT,{ bonus3 bSubRace,RC_Plant,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_INSECT,{ bonus3 bSubRace,RC_Insect,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_FISHS,{ bonus3 bSubRace,RC_Fish,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_DEVIL,{ bonus3 bSubRace,RC_Demon,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_HUMAN,{ bonus3 bSubRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_ANGEL,{ bonus3 bSubRace,RC_Angel,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+RDMOPT_RACE_WEAPON_TOLERACE_DRAGON,{ bonus3 bSubRace,RC_Dragon,getrandomoptinfo(ROA_VALUE),BF_WEAPON; }
+// RDMOPT_RANGE_WEAPON_ATTACK_DAMAGE_TARGET,{}
+// RDMOPT_RANGE_WEAPON_ATTACK_DAMAGE_USER,{}
+RDMOPT_RACE_TOLERACE_PLAYER_DORAM,{ bonus2 bSubRace,RC_Player_Doram,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_PLAYER_HUMAN,{ bonus2 bAddRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_PLAYER_DORAM,{ bonus2 bAddRace,RC_Player_Doram,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_PLAYER_HUMAN,{ bonus2 bMagicAddRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE);  }
+RDMOPT_RACE_MDAMAGE_PLAYER_DORAM,{ bonus2 bMagicAddRace,RC_Player_Doram,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_CRI_PERCENT_PLAYER_HUMAN,{ bonus2 bCriticalAddRace,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_CRI_PERCENT_PLAYER_DORAM,{ bonus2 bCriticalAddRace,RC_Player_Doram,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_PLAYER_HUMAN,{ bonus2 bIgnoreDefRaceRate,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_PLAYER_DORAM,{ bonus2 bIgnoreDefRaceRate,RC_Player_Doram,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLAYER_HUMAN,{ bonus2 bIgnoreMdefRaceRate,RC_Player_Human,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLAYER_DORAM,{ bonus2 bIgnoreMdefRaceRate,RC_Player_Doram,getrandomoptinfo(ROA_VALUE); }
+// RDMOPT_REFLECT_DAMAGE_PERCENT,{}
+RDMOPT_MELEE_ATTACK_DAMAGE_TARGET,{ bonus bShortAtkRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MELEE_ATTACK_DAMAGE_USER,{ bonus bNearAtkDef,getrandomoptinfo(ROA_VALUE); }

+ 1 - 1
doc/atcommands.txt

@@ -1360,7 +1360,7 @@ Affected files:
 -- atcommand: atcommand_athena.conf, groups.conf
 -- atcommand: atcommand_athena.conf, groups.conf
 -- battleconf: battle_athena.conf, battle_conf.txt
 -- battleconf: battle_athena.conf, battle_conf.txt
 -- instancedb: instance_db.txt
 -- instancedb: instance_db.txt
--- itemdb: item_db.txt, item_group_db.txt, item_trade.txt, item_noequip.txt, item_nouse.txt, item_combo_db.txt, item_avail.txt, item_stack.txt, item_delay.txt, item_buyingstore.txt, item_flag.txt
+-- itemdb: item_db.txt, item_group_db.txt, item_trade.txt, item_noequip.txt, item_nouse.txt, item_combo_db.txt, item_avail.txt, item_stack.txt, item_delay.txt, item_buyingstore.txt, item_flag.txt, item_randomopt_db.txt, item_randomopt_group.txt
 -- mobdb: mob_db.txt, mob_item_ratio.txt, mob_chat_db.txt, mob_avail.txt, mob_race2_db.txt, mob_branch.txt, mob_poring.txt, mob_boss.txt, mob_pouch.txt, mob_classchange.txt, pet_db.yml, homunculus_db.txt, homun_skill_tree.txt, exp_homun.txt, mercenary_db.txt, mercenary_skill_db.txt, elemental_db.txt, elemental_skill_db.txt
 -- mobdb: mob_db.txt, mob_item_ratio.txt, mob_chat_db.txt, mob_avail.txt, mob_race2_db.txt, mob_branch.txt, mob_poring.txt, mob_boss.txt, mob_pouch.txt, mob_classchange.txt, pet_db.yml, homunculus_db.txt, homun_skill_tree.txt, exp_homun.txt, mercenary_db.txt, mercenary_skill_db.txt, elemental_db.txt, elemental_skill_db.txt
 -- motd: motd.txt
 -- motd: motd.txt
 -- msgconf: atcommand_athena.conf
 -- msgconf: atcommand_athena.conf

+ 3 - 0
doc/item_bonus.txt

@@ -171,6 +171,7 @@ bonus2 bSkillAtk,sk,n;    		Increases damage of skill sk by n%
 bonus bShortAtkRate,n;			Increases damage of short ranged attacks by n%
 bonus bShortAtkRate,n;			Increases damage of short ranged attacks by n%
 bonus bLongAtkRate,n;     		Increases damage of long ranged attacks by n%
 bonus bLongAtkRate,n;     		Increases damage of long ranged attacks by n%
 bonus bCritAtkRate,n;     		Increases critical damage by +n%
 bonus bCritAtkRate,n;     		Increases critical damage by +n%
+bonus bCritDefRate,n;			Decreases critical damage received by n%
 bonus bCriticalDef,n;     		Decreases the chance of being hit by critical hits by n%
 bonus bCriticalDef,n;     		Decreases the chance of being hit by critical hits by n%
 bonus2 bWeaponAtk,w,n;    		Adds n ATK when weapon of type w is equipped
 bonus2 bWeaponAtk,w,n;    		Adds n ATK when weapon of type w is equipped
 bonus2 bWeaponDamageRate,w,n;	Adds n% damage to normal attacks when weapon of type w is equipped
 bonus2 bWeaponDamageRate,w,n;	Adds n% damage to normal attacks when weapon of type w is equipped
@@ -232,6 +233,7 @@ bonus2 bSubDefEle,e,x;    		+x% damage reduction from enemy with defense element
 bonus2 bAddRace,r,x;      		+x% physical damage against race r
 bonus2 bAddRace,r,x;      		+x% physical damage against race r
 bonus2 bMagicAddRace,r,x; 		+x% magical damage against race r
 bonus2 bMagicAddRace,r,x; 		+x% magical damage against race r
 bonus2 bSubRace,r,x;      		+x% damage reduction against race r
 bonus2 bSubRace,r,x;      		+x% damage reduction against race r
+bonus3 bSubRace,r,x,bf;    		+x% damage reduction against race r with trigger criteria bf 
 
 
 bonus2 bAddClass,c,x;     		+x% physical damage against class c
 bonus2 bAddClass,c,x;     		+x% physical damage against class c
 bonus2 bMagicAddClass,c,x;		+x% magical damage against class c
 bonus2 bMagicAddClass,c,x;		+x% magical damage against class c
@@ -240,6 +242,7 @@ bonus2 bSubClass,c,x;     		+x% damage reduction against class c
 bonus2 bAddSize,s,x;      		+x% physical damage against size s
 bonus2 bAddSize,s,x;      		+x% physical damage against size s
 bonus2 bMagicAddSize,s,x; 		+x% magical damage against size s
 bonus2 bMagicAddSize,s,x; 		+x% magical damage against size s
 bonus2 bSubSize,s,x;      		+x% damage reduction against size s
 bonus2 bSubSize,s,x;      		+x% damage reduction against size s
+bonus2 bMagicSubSize,s,x;      	+x% magic damage reduction against size s
 bonus bNoSizeFix;       		Ignores the size modifier when calculating damage
 bonus bNoSizeFix;       		Ignores the size modifier when calculating damage
 
 
 bonus2 bAddDamageClass,mid,x;     	+x% physical damage against monster mid
 bonus2 bAddDamageClass,mid,x;     	+x% physical damage against monster mid

+ 49 - 6
src/map/battle.cpp

@@ -698,8 +698,19 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li
 					cardfix = cardfix * (100 - ele_fix) / 100;
 					cardfix = cardfix * (100 - ele_fix) / 100;
 				}
 				}
 				cardfix = cardfix * (100 - tsd->subsize[sstatus->size] - tsd->subsize[SZ_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subsize[sstatus->size] - tsd->subsize[SZ_ALL]) / 100;
+				cardfix = cardfix * (100 - tsd->magic_subsize[sstatus->size] - tsd->magic_subsize[SZ_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
 				cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
-				cardfix = cardfix * (100 - tsd->subrace[sstatus->race] - tsd->subrace[RC_ALL]) / 100;
+				int race_fix = tsd->subrace[sstatus->race] - tsd->subrace[RC_ALL];
+				for (const auto &it : tsd->subrace3) {
+					if (it.race != sstatus->race)
+						continue;
+					if (!(((it.flag)&flag)&BF_WEAPONMASK &&
+						((it.flag)&flag)&BF_RANGEMASK &&
+						((it.flag)&flag)&BF_SKILLMASK))
+						continue;
+					race_fix += it.rate;
+				}
+				cardfix = cardfix * (100 - race_fix) / 100;
 				cardfix = cardfix * (100 - tsd->subclass[sstatus->class_] - tsd->subclass[CLASS_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subclass[sstatus->class_] - tsd->subclass[CLASS_ALL]) / 100;
 
 
 				for (const auto &it : tsd->add_mdef) {
 				for (const auto &it : tsd->add_mdef) {
@@ -898,7 +909,17 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li
 				}
 				}
 				cardfix = cardfix * (100 - tsd->subsize[sstatus->size] - tsd->subsize[SZ_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subsize[sstatus->size] - tsd->subsize[SZ_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
 				cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
-				cardfix = cardfix * (100 - tsd->subrace[sstatus->race] - tsd->subrace[RC_ALL]) / 100;
+				int race_fix = tsd->subrace[sstatus->race] - tsd->subrace[RC_ALL];
+				for (const auto &it : tsd->subrace3) {
+					if (it.race != sstatus->race)
+						continue;
+					if (!(((it.flag)&flag)&BF_WEAPONMASK &&
+						((it.flag)&flag)&BF_RANGEMASK &&
+						((it.flag)&flag)&BF_SKILLMASK))
+						continue;
+					race_fix += it.rate;
+				}
+				cardfix = cardfix * (100 - race_fix) / 100;
 				cardfix = cardfix * (100 - tsd->subclass[sstatus->class_] - tsd->subclass[CLASS_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subclass[sstatus->class_] - tsd->subclass[CLASS_ALL]) / 100;
 				for (const auto &it : tsd->add_def) {
 				for (const auto &it : tsd->add_def) {
 					if (it.id == s_class) {
 					if (it.id == s_class) {
@@ -935,9 +956,20 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li
 						ele_fix += tsd->subdefele[s_defele] + tsd->subdefele[ELE_ALL];
 						ele_fix += tsd->subdefele[s_defele] + tsd->subdefele[ELE_ALL];
 					cardfix = cardfix * (100 - ele_fix) / 100;
 					cardfix = cardfix * (100 - ele_fix) / 100;
 				}
 				}
+				int race_fix = tsd->subrace[sstatus->race] - tsd->subrace[RC_ALL];
+				for (const auto &it : tsd->subrace3) {
+					if (it.race != sstatus->race)
+						continue;
+					if (!(((it.flag)&flag)&BF_WEAPONMASK &&
+						((it.flag)&flag)&BF_RANGEMASK &&
+						((it.flag)&flag)&BF_SKILLMASK))
+						continue;
+					race_fix += it.rate;
+				}
+				cardfix = cardfix * (100 - race_fix) / 100;
+
 				cardfix = cardfix * (100 - tsd->subsize[sstatus->size] - tsd->subsize[SZ_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subsize[sstatus->size] - tsd->subsize[SZ_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
 				cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100;
-				cardfix = cardfix * (100 - tsd->subrace[sstatus->race] - tsd->subrace[RC_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subclass[sstatus->class_] - tsd->subclass[CLASS_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->subclass[sstatus->class_] - tsd->subclass[CLASS_ALL]) / 100;
 				cardfix = cardfix * (100 - tsd->bonus.misc_def_rate) / 100;
 				cardfix = cardfix * (100 - tsd->bonus.misc_def_rate) / 100;
 				if( flag&BF_SHORT )
 				if( flag&BF_SHORT )
@@ -3257,6 +3289,8 @@ static void battle_calc_skill_base_damage(struct Damage* wd, struct block_list *
 	struct status_data *sstatus = status_get_status_data(src);
 	struct status_data *sstatus = status_get_status_data(src);
 	struct status_data *tstatus = status_get_status_data(target);
 	struct status_data *tstatus = status_get_status_data(target);
 	struct map_session_data *sd = BL_CAST(BL_PC, src);
 	struct map_session_data *sd = BL_CAST(BL_PC, src);
+	struct map_session_data *tsd = BL_CAST(BL_PC, target);
+
 	uint16 i;
 	uint16 i;
 	std::bitset<NK_MAX> nk = battle_skill_get_damage_properties(skill_id, wd->miscflag);
 	std::bitset<NK_MAX> nk = battle_skill_get_damage_properties(skill_id, wd->miscflag);
 
 
@@ -3467,6 +3501,11 @@ static void battle_calc_skill_base_damage(struct Damage* wd, struct block_list *
 					}
 					}
 				}
 				}
 			}
 			}
+#ifndef RENEWAL
+			if(tsd != nullptr & tsd->bonus.crit_def_rate != 0 && !skill_id && is_attack_critical(wd, src, target, skill_id, skill_lv, false)) {
+				ATK_ADDRATE(wd->damage, wd->damage2, -tsd->bonus.crit_def_rate);
+			}
+#endif
 			break;
 			break;
 	} //End switch(skill_id)
 	} //End switch(skill_id)
 }
 }
@@ -5795,11 +5834,15 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 #ifdef RENEWAL
 #ifdef RENEWAL
 	if (is_attack_critical(&wd, src, target, skill_id, skill_lv, false)) {
 	if (is_attack_critical(&wd, src, target, skill_id, skill_lv, false)) {
 		if (sd) { //Check for player so we don't crash out, monsters don't have bonus crit rates [helvetica]
 		if (sd) { //Check for player so we don't crash out, monsters don't have bonus crit rates [helvetica]
-			wd.damage = (int)floor((float)((wd.damage * 140) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100);
+			wd.damage = (int64)floor((float)((wd.damage * 140) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100);
 			if (is_attack_left_handed(src, skill_id))
 			if (is_attack_left_handed(src, skill_id))
-				wd.damage2 = (int)floor((float)((wd.damage2 * 140) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100);
+				wd.damage2 = (int64)floor((float)((wd.damage2 * 140) / 100 * (100 + sd->bonus.crit_atk_rate)) / 100);
 		} else
 		} else
-			wd.damage = (int)floor((float)(wd.damage * 140) / 100);
+			wd.damage = (int64)floor((float)(wd.damage * 140) / 100);
+
+		if (tsd && tsd->bonus.crit_def_rate != 0) {
+			ATK_ADDRATE(wd.damage, wd.damage2, -tsd->bonus.crit_def_rate);
+		}
 	}
 	}
 #endif
 #endif
 
 

+ 1 - 1
src/map/map.hpp

@@ -505,7 +505,7 @@ enum _sp {
 	SP_STATE_NORECOVER_RACE, SP_CRITICAL_RANGEATK, SP_MAGIC_ADDRACE2, SP_IGNORE_MDEF_RACE2_RATE, // 2079-2082
 	SP_STATE_NORECOVER_RACE, SP_CRITICAL_RANGEATK, SP_MAGIC_ADDRACE2, SP_IGNORE_MDEF_RACE2_RATE, // 2079-2082
 	SP_WEAPON_ATK_RATE, SP_WEAPON_MATK_RATE, SP_DROP_ADDRACE, SP_DROP_ADDCLASS, SP_NO_MADO_FUEL, // 2083-2087
 	SP_WEAPON_ATK_RATE, SP_WEAPON_MATK_RATE, SP_DROP_ADDRACE, SP_DROP_ADDCLASS, SP_NO_MADO_FUEL, // 2083-2087
 	SP_IGNORE_DEF_CLASS_RATE, SP_REGEN_PERCENT_HP, SP_REGEN_PERCENT_SP, SP_SKILL_DELAY, SP_NO_WALK_DELAY, //2088-2093
 	SP_IGNORE_DEF_CLASS_RATE, SP_REGEN_PERCENT_HP, SP_REGEN_PERCENT_SP, SP_SKILL_DELAY, SP_NO_WALK_DELAY, //2088-2093
-	SP_LONG_SP_GAIN_VALUE, SP_LONG_HP_GAIN_VALUE, SP_SHORT_ATK_RATE // 2094-2096
+	SP_LONG_SP_GAIN_VALUE, SP_LONG_HP_GAIN_VALUE, SP_SHORT_ATK_RATE, SP_MAGIC_SUBSIZE, SP_CRIT_DEF_RATE // 2094-2098
 };
 };
 
 
 enum _look {
 enum _look {

+ 60 - 1
src/map/pc.cpp

@@ -2890,6 +2890,49 @@ static void pc_bonus_subele(struct map_session_data* sd, unsigned char ele, shor
 	sd->subele2.push_back(entry);
 	sd->subele2.push_back(entry);
 }
 }
 
 
+/**
+ * Adjust race damage to target when attacking
+ * @param sd: Player data
+ * @param race: Race to adjust
+ * @param rate: Success chance
+ * @param flag: Battle flag
+*/
+static void pc_bonus_subrace(struct map_session_data* sd, unsigned char race, short rate, short flag)
+{
+	if (sd->subrace3.size() == MAX_PC_BONUS) {
+		ShowWarning("pc_bonus_subrace: Reached max (%d) number of resist race damage bonuses per character!\n", MAX_PC_BONUS);
+		return;
+	}
+
+	if (!(flag&BF_RANGEMASK))
+		flag |= BF_SHORT | BF_LONG;
+	if (!(flag&BF_WEAPONMASK))
+		flag |= BF_WEAPON;
+	if (!(flag&BF_SKILLMASK)) {
+		if (flag&(BF_MAGIC | BF_MISC))
+			flag |= BF_SKILL;
+		if (flag&BF_WEAPON)
+			flag |= BF_NORMAL | BF_SKILL;
+	}
+
+	for (auto &it : sd->subrace3) {
+		if (it.race == race && it.flag == flag) {
+			it.rate = cap_value(it.rate + rate, -10000, 10000);
+			return;
+		}
+	}
+
+	struct s_addrace2 entry = {};
+
+	if (rate < -10000 || rate > 10000)
+		ShowWarning("pc_bonus_subrace: Item bonus rate %d exceeds -10000~10000 range, capping.\n", rate);
+
+	entry.race = race;
+	entry.rate = cap_value(rate, -10000, 10000);
+	entry.flag = flag;
+
+	sd->subrace3.push_back(entry);
+}
 /**
 /**
  * General item bonus for player
  * General item bonus for player
  * @param bonus: Bonus array
  * @param bonus: Bonus array
@@ -3469,6 +3512,10 @@ void pc_bonus(struct map_session_data *sd,int type,int val)
 			if(sd->state.lr_flag != 2)
 			if(sd->state.lr_flag != 2)
 				sd->bonus.crit_atk_rate += val;
 				sd->bonus.crit_atk_rate += val;
 			break;
 			break;
+		case SP_CRIT_DEF_RATE:
+			if(sd->state.lr_flag != 2)
+				sd->bonus.crit_def_rate += val;
+			break;
 		case SP_NO_REGEN:
 		case SP_NO_REGEN:
 			if(sd->state.lr_flag != 2)
 			if(sd->state.lr_flag != 2)
 				sd->regen.state.block|=val;
 				sd->regen.state.block|=val;
@@ -3924,6 +3971,11 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 		if(sd->state.lr_flag != 2)
 		if(sd->state.lr_flag != 2)
 			sd->subsize[type2]+=val;
 			sd->subsize[type2]+=val;
 		break;
 		break;
+	case SP_MAGIC_SUBSIZE: // bonus2 bMagicSubSize,s,x;
+		PC_BONUS_CHK_SIZE(type2,SP_MAGIC_SUBSIZE);
+		if(sd->state.lr_flag != 2)
+			sd->magic_subsize[type2]+=val;
+		break;
 	case SP_SUBRACE2: // bonus2 bSubRace2,mr,x;
 	case SP_SUBRACE2: // bonus2 bSubRace2,mr,x;
 		PC_BONUS_CHK_RACE2(type2,SP_SUBRACE2);
 		PC_BONUS_CHK_RACE2(type2,SP_SUBRACE2);
 		if(sd->state.lr_flag != 2)
 		if(sd->state.lr_flag != 2)
@@ -4281,7 +4333,13 @@ void pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val)
 		if (sd->state.lr_flag != 2)
 		if (sd->state.lr_flag != 2)
 			pc_bonus_subele(sd, (unsigned char)type2, type3, val);
 			pc_bonus_subele(sd, (unsigned char)type2, type3, val);
 		break;
 		break;
-		
+
+	case SP_SUBRACE: // bonus3 bSubRace,r,x,bf;
+		PC_BONUS_CHK_RACE(type2, SP_SUBRACE);
+		if (sd->state.lr_flag != 2)
+			pc_bonus_subrace(sd, (unsigned char)type2, type3, val);
+		break;
+
 	case SP_SP_VANISH_RACE_RATE: // bonus3 bSPVanishRaceRate,r,x,n;
 	case SP_SP_VANISH_RACE_RATE: // bonus3 bSPVanishRaceRate,r,x,n;
 		PC_BONUS_CHK_RACE(type2,SP_SP_VANISH_RACE_RATE);
 		PC_BONUS_CHK_RACE(type2,SP_SP_VANISH_RACE_RATE);
 		if(sd->state.lr_flag != 2) {
 		if(sd->state.lr_flag != 2) {
@@ -8731,6 +8789,7 @@ int64 pc_readparam(struct map_session_data* sd,int64 type)
 #else
 #else
 			val = sd->castrate; break;
 			val = sd->castrate; break;
 #endif
 #endif
+		case SP_CRIT_DEF_RATE: val = sd->bonus.crit_def_rate; break;
 		default:
 		default:
 			ShowError("pc_readparam: Attempt to read unknown parameter '%lld'.\n", type);
 			ShowError("pc_readparam: Attempt to read unknown parameter '%lld'.\n", type);
 			return -1;
 			return -1;

+ 10 - 0
src/map/pc.hpp

@@ -151,6 +151,12 @@ struct s_addele2 {
 	unsigned char ele;
 	unsigned char ele;
 };
 };
 
 
+/// AddRace bonus struct
+struct s_addrace2 {
+	short flag, rate;
+	unsigned char race;
+};
+
 struct weapon_data {
 struct weapon_data {
 	int atkmods[SZ_ALL];
 	int atkmods[SZ_ALL];
 	// all the variables except atkmods get zero'ed in each call of status_calc_pc
 	// all the variables except atkmods get zero'ed in each call of status_calc_pc
@@ -181,6 +187,7 @@ struct weapon_data {
 
 
 	std::vector<s_item_bonus> add_dmg;
 	std::vector<s_item_bonus> add_dmg;
 	std::vector<s_addele2> addele2;
 	std::vector<s_addele2> addele2;
+	std::vector<s_addrace2> addrace3;
 };
 };
 
 
 /// AutoSpell bonus struct
 /// AutoSpell bonus struct
@@ -440,6 +447,7 @@ struct map_session_data {
 	int magic_addclass[CLASS_MAX];
 	int magic_addclass[CLASS_MAX];
 	int magic_addsize[SZ_MAX];
 	int magic_addsize[SZ_MAX];
 	int magic_atk_ele[ELE_MAX];
 	int magic_atk_ele[ELE_MAX];
+	int magic_subsize[SZ_MAX];
 	int critaddrace[RC_MAX];
 	int critaddrace[RC_MAX];
 	int expaddrace[RC_MAX];
 	int expaddrace[RC_MAX];
 	int expaddclass[CLASS_MAX];
 	int expaddclass[CLASS_MAX];
@@ -462,6 +470,7 @@ struct map_session_data {
 	std::vector<s_add_drop> add_drop;
 	std::vector<s_add_drop> add_drop;
 	std::vector<s_addele2> subele2;
 	std::vector<s_addele2> subele2;
 	std::vector<s_vanish_bonus> sp_vanish, hp_vanish;
 	std::vector<s_vanish_bonus> sp_vanish, hp_vanish;
+	std::vector<s_addrace2> subrace3;
 	std::vector<s_autobonus> autobonus, autobonus2, autobonus3; //Auto script on attack, when attacked, on skill usage
 	std::vector<s_autobonus> autobonus, autobonus2, autobonus3; //Auto script on attack, when attacked, on skill usage
 
 
 	// zeroed structures start here
 	// zeroed structures start here
@@ -502,6 +511,7 @@ struct map_session_data {
 		int magic_damage_return; // AppleGirl Was Here
 		int magic_damage_return; // AppleGirl Was Here
 		int break_weapon_rate,break_armor_rate;
 		int break_weapon_rate,break_armor_rate;
 		int crit_atk_rate;
 		int crit_atk_rate;
+		int crit_def_rate;
 		int classchange; // [Valaris]
 		int classchange; // [Valaris]
 		int speed_rate, speed_add_rate, aspd_add;
 		int speed_rate, speed_add_rate, aspd_add;
 		int itemhealrate2; // [Epoque] Increase heal rate of all healing items.
 		int itemhealrate2; // [Epoque] Increase heal rate of all healing items.

+ 3 - 0
src/map/script_constants.hpp

@@ -753,6 +753,9 @@
 	export_constant2("bNoWalkDelay",SP_NO_WALK_DELAY);
 	export_constant2("bNoWalkDelay",SP_NO_WALK_DELAY);
 	export_constant2("bLongSPGainValue",SP_LONG_SP_GAIN_VALUE);
 	export_constant2("bLongSPGainValue",SP_LONG_SP_GAIN_VALUE);
 	export_constant2("bLongHPGainValue",SP_LONG_HP_GAIN_VALUE);
 	export_constant2("bLongHPGainValue",SP_LONG_HP_GAIN_VALUE);
+	export_constant2("bMagicSubSize",SP_MAGIC_SUBSIZE);
+	export_constant2("bCritDefRate",SP_CRIT_DEF_RATE);
+
 
 
 	/* equip indices */
 	/* equip indices */
 	export_constant(EQI_COMPOUND_ON);
 	export_constant(EQI_COMPOUND_ON);

+ 2 - 0
src/map/status.cpp

@@ -3832,6 +3832,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt)
 		+ sizeof(sd->magic_addclass)
 		+ sizeof(sd->magic_addclass)
 		+ sizeof(sd->magic_addsize)
 		+ sizeof(sd->magic_addsize)
 		+ sizeof(sd->magic_atk_ele)
 		+ sizeof(sd->magic_atk_ele)
+		+ sizeof(sd->magic_subsize)
 		+ sizeof(sd->critaddrace)
 		+ sizeof(sd->critaddrace)
 		+ sizeof(sd->expaddrace)
 		+ sizeof(sd->expaddrace)
 		+ sizeof(sd->expaddclass)
 		+ sizeof(sd->expaddclass)
@@ -3914,6 +3915,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt)
 	sd->add_drop.clear();
 	sd->add_drop.clear();
 	sd->itemhealrate.clear();
 	sd->itemhealrate.clear();
 	sd->subele2.clear();
 	sd->subele2.clear();
+	sd->subrace3.clear();
 	sd->skilldelay.clear();
 	sd->skilldelay.clear();
 	sd->sp_vanish.clear();
 	sd->sp_vanish.clear();
 	sd->hp_vanish.clear();
 	sd->hp_vanish.clear();