From f720e5158582857c998bb22e46f4ffe74b64ea20 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 4 Feb 2018 16:30:16 -0500 Subject: [PATCH] Implement NPC Charm Stats These combat stats an NPC will change to while charmed --- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../git/required/2018_02_04_Charm_Stats.sql | 7 +++ zone/npc.cpp | 57 +++++++++++++++++++ zone/npc.h | 21 +++++++ zone/spell_effects.cpp | 2 + zone/zonedb.cpp | 17 +++++- zone/zonedump.h | 7 +++ 8 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 utils/sql/git/required/2018_02_04_Charm_Stats.sql diff --git a/common/version.h b/common/version.h index ddff10b59..a79766ec3 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9117 +#define CURRENT_BINARY_DATABASE_VERSION 9118 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9018 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 1f95a513f..8463d979f 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -371,6 +371,7 @@ 9115|2017_10_28_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'triggered_number'|empty| 9116|2017_12_16_GroundSpawn_Respawn_Timer.sql|SHOW COLUMNS FROM `ground_spawns` WHERE Field = 'respawn_timer' AND Type = 'int(11) unsigned'|empty| 9117|2018_02_01_NPC_Spells_Min_Max_HP.sql|SHOW COLUMNS FROM `npc_spells_entries` LIKE 'min_hp'|empty| +9118|2018_02_04_Charm_Stats.sql|SHOW COLUMNS FROM `npc_types` LIKE 'charm_ac'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_02_04_Charm_Stats.sql b/utils/sql/git/required/2018_02_04_Charm_Stats.sql new file mode 100644 index 000000000..3a9164f40 --- /dev/null +++ b/utils/sql/git/required/2018_02_04_Charm_Stats.sql @@ -0,0 +1,7 @@ +ALTER TABLE `npc_types` ADD `charm_ac` SMALLINT(5) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_min_dmg` INT(10) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_max_dmg` INT(10) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_attack_delay` TINYINT(3) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_accuracy_rating` MEDIUMINT(9) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_avoidance_rating` MEDIUMINT(9) DEFAULT '0'; +ALTER TABLE `npc_types` ADD `charm_atk` MEDIUMINT(9) DEFAULT '0'; diff --git a/zone/npc.cpp b/zone/npc.cpp index c13841358..de494bb05 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -208,6 +208,24 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if avoidance_rating = d->avoidance_rating; ATK = d->ATK; + // used for when switch back to charm + default_ac = d->AC; + default_min_dmg = min_dmg; + default_max_dmg = max_dmg; + default_attack_delay = d->attack_delay; + default_accuracy_rating = d->accuracy_rating; + default_avoidance_rating = d->avoidance_rating; + default_atk = d->ATK; + + // used for when getting charmed, if 0, doesn't swap + charm_ac = d->charm_ac; + charm_min_dmg = d->charm_min_dmg; + charm_max_dmg = d->charm_max_dmg; + charm_attack_delay = d->charm_attack_delay; + charm_accuracy_rating = d->charm_accuracy_rating; + charm_avoidance_rating = d->charm_avoidance_rating; + charm_atk = d->charm_atk; + CalcMaxMana(); SetMana(GetMaxMana()); @@ -2636,3 +2654,42 @@ void NPC::DepopSwarmPets() } } } + +void NPC::ModifyStatsOnCharm(bool bRemoved) +{ + if (bRemoved) { + if (charm_ac) + AC = default_ac; + if (charm_attack_delay) + attack_delay = default_attack_delay; + if (charm_accuracy_rating) + accuracy_rating = default_accuracy_rating; + if (charm_avoidance_rating) + avoidance_rating = default_avoidance_rating; + if (charm_atk) + ATK = default_atk; + if (charm_min_dmg || charm_max_dmg) { + base_damage = round((default_max_dmg - default_min_dmg) / 1.9); + min_damage = default_min_dmg - round(base_damage / 10.0); + } + } else { + if (charm_ac) + AC = charm_ac; + if (charm_attack_delay) + attack_delay = charm_attack_delay; + if (charm_accuracy_rating) + accuracy_rating = charm_accuracy_rating; + if (charm_avoidance_rating) + avoidance_rating = charm_avoidance_rating; + if (charm_atk) + ATK = charm_atk; + if (charm_min_dmg || charm_max_dmg) { + base_damage = round((charm_max_dmg - charm_min_dmg) / 1.9); + min_damage = charm_min_dmg - round(base_damage / 10.0); + } + } + // the rest of the stats aren't cached, so lets just do these two instead of full CalcBonuses() + SetAttackTimer(); + CalcAC(); +} + diff --git a/zone/npc.h b/zone/npc.h index 8edff6245..0ff7f3b03 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -282,6 +282,8 @@ public: int32 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; } inline const char* GetAmmoIDfile() const { return ammo_idfile; } + void ModifyStatsOnCharm(bool bRemoved); + //waypoint crap int GetMaxWp() const { return max_wp; } void DisplayWaypointInfo(Client *to); @@ -482,6 +484,25 @@ protected: int32 SpellFocusDMG; int32 SpellFocusHeal; + // stats to switch back to after charm wears off + // could probably pick a better name, but these probably aren't taken so ... + int default_ac; + int default_min_dmg; + int default_max_dmg; + int default_attack_delay; + int default_accuracy_rating; + int default_avoidance_rating; + int default_atk; + + // when charmed, switch to these + int charm_ac; + int charm_min_dmg; + int charm_max_dmg; + int charm_attack_delay; + int charm_accuracy_rating; + int charm_avoidance_rating; + int charm_atk; + //pet crap: uint16 pet_spell_id; bool taunting; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 67104a234..5ebde5d05 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -790,6 +790,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove CastToClient()->AI_Start(); } else if(IsNPC()) { CastToNPC()->SetPetSpellID(0); //not a pet spell. + CastToNPC()->ModifyStatsOnCharm(false); } bool bBreak = false; @@ -3966,6 +3967,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) if(IsNPC()) { CastToNPC()->RestoreGuardSpotCharm(); + CastToNPC()->ModifyStatsOnCharm(true); } SendAppearancePacket(AT_Pet, 0, true, true); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 1de044973..75ca99ac8 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1962,7 +1962,14 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load "npc_types.feettexture, " "npc_types.ignore_despawn, " "npc_types.show_name, " - "npc_types.untargetable " + "npc_types.untargetable, " + "npc_types.charm_ac, " + "npc_types.charm_min_dmg, " + "npc_types.charm_max_dmg, " + "npc_types.charm_attack_delay, " + "npc_types.charm_accuracy_rating, " + "npc_types.charm_avoidance_rating, " + "npc_types.charm_atk " "FROM npc_types %s", where_condition.c_str() ); @@ -2141,6 +2148,14 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load temp_npctype_data->show_name = atoi(row[98]) != 0 ? true : false; temp_npctype_data->untargetable = atoi(row[99]) != 0 ? true : false; + temp_npctype_data->charm_ac = atoi(row[100]); + temp_npctype_data->charm_min_dmg = atoi(row[101]); + temp_npctype_data->charm_max_dmg = atoi(row[102]); + temp_npctype_data->charm_attack_delay = atoi(row[103]) * 100; // TODO: fix DB + temp_npctype_data->charm_accuracy_rating = atoi(row[104]); + temp_npctype_data->charm_avoidance_rating = atoi(row[105]); + temp_npctype_data->charm_atk = atoi(row[106]); + // If NPC with duplicate NPC id already in table, // free item we attempted to add. if (zone->npctable.find(temp_npctype_data->npc_id) != zone->npctable.end()) { diff --git a/zone/zonedump.h b/zone/zonedump.h index d305e4105..636978475 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -89,6 +89,13 @@ struct NPCType EQEmu::TintProfile armor_tint; uint32 min_dmg; uint32 max_dmg; + uint32 charm_ac; + uint32 charm_min_dmg; + uint32 charm_max_dmg; + int charm_attack_delay; + int charm_accuracy_rating; + int charm_avoidance_rating; + int charm_atk; int16 attack_count; char special_abilities[512]; uint16 d_melee_texture1;