diff --git a/common/version.h b/common/version.h index 108ce784b..4c86b26d7 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 9115 +#define CURRENT_BINARY_DATABASE_VERSION 9117 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9017 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 11dd1b315..1f95a513f 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -370,6 +370,7 @@ 9114|2017_07_22_aura.sql|SHOW TABLES LIKE 'auras'|empty| 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| # 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_01_NPC_Spells_Min_Max_HP.sql b/utils/sql/git/required/2018_02_01_NPC_Spells_Min_Max_HP.sql new file mode 100644 index 000000000..b0535e25f --- /dev/null +++ b/utils/sql/git/required/2018_02_01_NPC_Spells_Min_Max_HP.sql @@ -0,0 +1,2 @@ +ALTER TABLE `npc_spells_entries` ADD `min_hp` SMALLINT(5) DEFAULT '0'; +ALTER TABLE `npc_spells_entries` ADD `max_hp` SMALLINT(5) DEFAULT '0'; diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 164e4146c..a16d78361 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -420,7 +420,12 @@ void Lua_NPC::ModifyNPCStat(const char *stat, const char *value) { void Lua_NPC::AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust) { Lua_Safe_Call_Void(); - self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust); + self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, 0, 0); +} + +void Lua_NPC::AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust, int min_hp, int max_hp) { + Lua_Safe_Call_Void(); + self->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, min_hp, max_hp); } void Lua_NPC::RemoveAISpell(int spell_id) { @@ -585,6 +590,7 @@ luabind::scope lua_register_npc() { .def("SetSwarmTarget", (void(Lua_NPC::*)(int))&Lua_NPC::SetSwarmTarget) .def("ModifyNPCStat", (void(Lua_NPC::*)(const char*,const char*))&Lua_NPC::ModifyNPCStat) .def("AddAISpell", (void(Lua_NPC::*)(int,int,int,int,int,int))&Lua_NPC::AddAISpell) + .def("AddAISpell", (void(Lua_NPC::*)(int,int,int,int,int,int,int,int))&Lua_NPC::AddAISpell) .def("RemoveAISpell", (void(Lua_NPC::*)(int))&Lua_NPC::RemoveAISpell) .def("SetSpellFocusDMG", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusDMG) .def("SetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusHeal) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index cab47b5d6..972adee90 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -110,6 +110,7 @@ public: void SetSwarmTarget(int target); void ModifyNPCStat(const char *stat, const char *value); void AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust); + void AddAISpell(int priority, int spell_id, int type, int mana_cost, int recast_delay, int resist_adjust, int min_hp, int max_hp); void RemoveAISpell(int spell_id); void SetSpellFocusDMG(int focus); void SetSpellFocusHeal(int focus); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index bbda210fe..33970640c 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -91,6 +91,13 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates // we define an innate spell as a spell with priority 0 continue; } + + if (AIspells[i].min_hp != 0 && GetIntHPRatio() < AIspells[i].min_hp) + continue; + + if (AIspells[i].max_hp != 0 && GetIntHPRatio() > AIspells[i].max_hp) + continue; + if (iSpellTypes & AIspells[i].type) { // manacost has special values, -1 is no mana cost, -2 is instant cast (no mana) int32 mana_cost = AIspells[i].manacost; @@ -2421,7 +2428,7 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { if (GetLevel() >= e.minlevel && GetLevel() <= e.maxlevel && e.spellid > 0) { if (!IsSpellInList(spell_list, e.spellid)) { - AddSpellToNPCList(e.priority, e.spellid, e.type, e.manacost, e.recast_delay, e.resist_adjust); + AddSpellToNPCList(e.priority, e.spellid, e.type, e.manacost, e.recast_delay, e.resist_adjust, e.min_hp, e.max_hp); } } } @@ -2462,7 +2469,7 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { for (auto &e : spell_list->entries) { if (GetLevel() >= e.minlevel && GetLevel() <= e.maxlevel && e.spellid > 0) { - AddSpellToNPCList(e.priority, e.spellid, e.type, e.manacost, e.recast_delay, e.resist_adjust); + AddSpellToNPCList(e.priority, e.spellid, e.type, e.manacost, e.recast_delay, e.resist_adjust, e.min_hp, e.max_hp); } } @@ -2610,7 +2617,7 @@ bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID) { // adds a spell to the list, taking into account priority and resorting list as needed. void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, - int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust) + int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp) { if(!IsValidSpell(iSpellID)) @@ -2626,6 +2633,8 @@ void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, t.recast_delay = iRecastDelay; t.time_cancast = 0; t.resist_adjust = iResistAdjust; + t.min_hp = min_hp; + t.max_hp = max_hp; AIspells.push_back(t); @@ -2716,7 +2725,7 @@ DBnpcspells_Struct *ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) // pulling fixed values from an auto-increment field is dangerous... query = StringFormat( "SELECT spellid, type, minlevel, maxlevel, " - "manacost, recast_delay, priority, resist_adjust " + "manacost, recast_delay, priority, min_hp, max_hp, resist_adjust " #ifdef BOTS "FROM %s " "WHERE npc_spells_id=%d ORDER BY minlevel", @@ -2744,9 +2753,11 @@ DBnpcspells_Struct *ZoneDatabase::GetNPCSpells(uint32 iDBSpellsID) entry.manacost = atoi(row[4]); entry.recast_delay = atoi(row[5]); entry.priority = atoi(row[6]); + entry.min_hp = atoi(row[7]); + entry.max_hp = atoi(row[8]); - if (row[7]) - entry.resist_adjust = atoi(row[7]); + if (row[9]) + entry.resist_adjust = atoi(row[9]); else if (IsValidSpell(spell_id)) entry.resist_adjust = spells[spell_id].ResistDiff; diff --git a/zone/npc.h b/zone/npc.h index 181de06fa..8edff6245 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -61,6 +61,8 @@ struct AISpells_Struct { int32 recast_delay; int16 priority; int16 resist_adjust; + int8 min_hp; // >0 won't cast if HP is below + int8 max_hp; // >0 won't cast if HP is above }; struct AISpellsEffects_Struct { @@ -378,7 +380,7 @@ public: void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots uint32 GetAdventureTemplate() const { return adventure_template_id; } - void AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust); + void AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp); void AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base, int32 limit, int32 max); void RemoveSpellFromNPCList(int16 spell_id); Timer *GetRefaceTimer() const { return reface_timer; } diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index 18594e17a..eef7b1717 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -1993,7 +1993,7 @@ XS(XS_NPC_AddSpellToNPCList) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust); + THIS->AddSpellToNPCList(priority, spell_id, type, mana_cost, recast_delay, resist_adjust, 0, 0); } XSRETURN_EMPTY; } diff --git a/zone/zonedb.h b/zone/zonedb.h index 96604ce28..0a13c672e 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -48,13 +48,15 @@ struct wplist { #pragma pack(1) struct DBnpcspells_entries_Struct { int16 spellid; - uint32 type; uint8 minlevel; uint8 maxlevel; + uint32 type; int16 manacost; - int32 recast_delay; int16 priority; + int32 recast_delay; int16 resist_adjust; + int8 min_hp; + int8 max_hp; }; #pragma pack()