From b372b02e9cc21ceeb42a428177d992998aed2eec Mon Sep 17 00:00:00 2001
From: Emistry Haoyan <equinox1991@gmail.com>
Date: Tue, 23 Jul 2019 22:24:57 +0800
Subject: Update mob_db - DamageTakenRate field

- adjust the damage taken by monster. (default = `100 = 1x`)
- ref: https://github.com/idathena/trunk/commit/e267d2e2dada6196b479a6f2f35e9d25291ef22b
---
 src/map/battle.c | 12 ++++++++++++
 src/map/mob.c    |  7 +++++++
 src/map/mob.h    |  2 ++
 src/map/script.c |  9 +++++++++
 src/map/script.h |  1 +
 src/map/skill.c  | 12 ++++++++++++
 6 files changed, 43 insertions(+)

(limited to 'src/map')

diff --git a/src/map/battle.c b/src/map/battle.c
index c40c3afac..75ce2b894 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -6321,6 +6321,18 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_
 	if (sd && sd->state.arrow_atk) //Consume arrow.
 		battle->consume_ammo(sd, 0, 0);
 
+	if (target->type == BL_MOB) {
+		struct mob_data *md = BL_CAST(BL_MOB, target);
+		if (md != NULL) {
+			if (md->db->dmg_taken_rate != 100) {
+				if (wd.damage > 0)
+					wd.damage = apply_percentrate64(wd.damage, md->db->dmg_taken_rate, 100);
+				if (wd.damage2 > 0)
+					wd.damage2 = apply_percentrate64(wd.damage2, md->db->dmg_taken_rate, 100);
+			}
+		}
+	}
+
 	damage = wd.damage + wd.damage2;
 	if( damage > 0 && src != target ) {
 		if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rnd()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 ){
diff --git a/src/map/mob.c b/src/map/mob.c
index 8511f8523..73f739264 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -4604,6 +4604,7 @@ static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *sou
 	 * AttackMotion: attack motion
 	 * DamageMotion: damage motion
 	 * MvpExp: mvp experience
+	 * DamageTakenRate: damage taken rate
 	 * MvpDrops: {
 	 *     AegisName: chance
 	 *     ...
@@ -4837,6 +4838,12 @@ static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *sou
 		}
 	}
 
+	if (mob->lookup_const(mobt, "DamageTakenRate", &i32) && i32 >= 0) {
+		md.dmg_taken_rate = cap_value(i32, 1, INT_MAX);
+	} else if (!inherit) {
+		md.dmg_taken_rate = 100;
+	}
+
 	mob->read_db_additional_fields(&md, mobt, n, source);
 
 	return mob->db_validate_entry(&md, n, source);
diff --git a/src/map/mob.h b/src/map/mob.h
index b63efd272..a86215470 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -206,6 +206,7 @@ struct mob_db {
 	unsigned int option;
 	int summonper[MAX_RANDOMMONSTER];
 	int maxskill;
+	int dmg_taken_rate;
 	struct mob_skill skill[MAX_MOBSKILL];
 	struct spawn_info spawn[10];
 	struct hplugin_data_store *hdata; ///< HPM Plugin Data Store
@@ -244,6 +245,7 @@ struct mob_data {
 		unsigned int dmg;
 		unsigned int flag : 2; //0: Normal. 1: Homunc exp. 2: Pet exp
 	} dmglog[DAMAGELOG_SIZE];
+	int dmg_taken_rate;
 	struct spawn_data *spawn; //Spawn data.
 	int spawn_timer; //Required for Convex Mirror
 	struct item *lootitem;
diff --git a/src/map/script.c b/src/map/script.c
index c1e210d27..8c1d69794 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -18580,6 +18580,7 @@ static BUILDIN(getmonsterinfo)
 		case 20: script_pushint(st,monster->status.def_ele); break;
 		case 21: script_pushint(st,monster->status.mode); break;
 		case 22: script_pushint(st,monster->mexp); break;
+		case 23: script_pushint(st, monster->dmg_taken_rate); break;
 		default: script_pushint(st,-1); //wrong Index
 	}
 	return true;
@@ -19137,6 +19138,9 @@ static BUILDIN(setunitdata)
 		script_pushint(st, 1);
 		return true;
 	}
+	case UDT_DAMAGE_TAKEN_RATE:
+		setunitdata_check_bounds(4, 1, INT_MAX);
+		break;
 	default:
 		break;
 	}
@@ -19311,6 +19315,9 @@ static BUILDIN(setunitdata)
 		case UDT_DMOTION:
 			md->status.dmotion = (unsigned short) val;
 			break;
+		case UDT_DAMAGE_TAKEN_RATE:
+			md->dmg_taken_rate = (int) val;
+			break;
 		default:
 			ShowWarning("buildin_setunitdata: Invalid data type '%s' for mob unit.\n", udtype);
 			script_pushint(st, 0);
@@ -20158,6 +20165,7 @@ static BUILDIN(getunitdata)
 		case UDT_AMOTION:     script_pushint(st, md->status.amotion); break;
 		case UDT_ADELAY:      script_pushint(st, md->status.adelay); break;
 		case UDT_DMOTION:     script_pushint(st, md->status.dmotion); break;
+		case UDT_DAMAGE_TAKEN_RATE: script_pushint(st, md->dmg_taken_rate); break;
 		default:
 			ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mob unit.\n", udtype);
 			script_pushint(st, -1);
@@ -26890,6 +26898,7 @@ static void script_hardcoded_constants(void)
 	script->set_constant("UDT_ROBE", UDT_ROBE, false, false);
 	script->set_constant("UDT_BODY2", UDT_BODY2, false, false);
 	script->set_constant("UDT_GROUP", UDT_GROUP, false, false);
+	script->set_constant("UDT_DAMAGE_TAKEN_RATE", UDT_DAMAGE_TAKEN_RATE, false, false);
 
 	script->constdb_comment("getguildonline types");
 	script->set_constant("GUILD_ONLINE_ALL", GUILD_ONLINE_ALL, false, false);
diff --git a/src/map/script.h b/src/map/script.h
index 62950ba8d..84a8e3b6e 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -434,6 +434,7 @@ enum script_unit_data_types {
 	UDT_ROBE,
 	UDT_BODY2,
 	UDT_GROUP,
+	UDT_DAMAGE_TAKEN_RATE,
 	UDT_MAX
 };
 
diff --git a/src/map/skill.c b/src/map/skill.c
index a259829ef..af61c887c 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -2906,6 +2906,18 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li
 		}
 	}
 
+	if (bl->type == BL_MOB) {
+		struct mob_data *md = BL_CAST(BL_MOB, bl);
+		if (md != NULL) {
+			if (md->db->dmg_taken_rate != 100) {
+				if (dmg.damage > 0)
+					dmg.damage = apply_percentrate64(dmg.damage, md->db->dmg_taken_rate, 100);
+				if (dmg.damage2 > 0)
+					dmg.damage2 = apply_percentrate64(dmg.damage2, md->db->dmg_taken_rate, 100);
+			}
+		}
+	}
+
 	damage = dmg.damage + dmg.damage2;
 
 	if( (skill_id == AL_INCAGI || skill_id == AL_BLESSING ||
-- 
cgit v1.2.3-70-g09d2