diff --git a/common/spdat.h b/common/spdat.h index 416f63561..c7c6027c6 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -607,7 +607,7 @@ typedef enum { #define SE_LimitSpellGroup 385 // implemented - Limits to spell group(ie type 3 reuse reduction augs that are class specific and thus all share s SG) #define SE_CastOnCurer 386 // implemented - Casts a spell on the person curing #define SE_CastOnCure 387 // implemented - Casts a spell on the cured person -//#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) +#define SE_SummonCorpseZone 388 // implemented - summons a corpse from any zone(nec AA) #define SE_FcTimerRefresh 389 // implemented - Refresh spell icons //#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. #define SE_LimitManaMax 391 // implemented diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c29c28e20..871cc0ced 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1812,6 +1812,43 @@ XS(XS__summonallplayercorpses) { XSRETURN(1); } +XS(XS__getplayercorpsecount); +XS(XS__getplayercorpsecount) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::getplayercorpsecount(uint32 char_id)"); + + uint32 RETVAL; + dXSTARG; + + uint32 char_id = (int) SvIV(ST(0)); + + RETVAL = quest_manager.getplayercorpsecount(char_id); + XSprePUSH; + PUSHu((IV) RETVAL); + + XSRETURN(1); +} + +XS(XS__getplayercorpsecountbyzoneid); +XS(XS__getplayercorpsecountbyzoneid) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: quest::getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id)"); + + uint32 RETVAL; + dXSTARG; + + uint32 char_id = (int) SvIV(ST(0)); + uint32 zone_id = (int)SvIV(ST(1)); + + RETVAL = quest_manager.getplayercorpsecountbyzoneid(char_id, zone_id); + XSprePUSH; + PUSHu((IV) RETVAL); + + XSRETURN(1); +} + XS(XS__getplayerburiedcorpsecount); XS(XS__getplayerburiedcorpsecount) { dXSARGS; @@ -3907,6 +3944,8 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); + newXS(strcpy(buf, "getplayercorpsecount"), XS__getplayercorpsecount, file); + newXS(strcpy(buf, "getplayercorpsecountbyzoneid"), XS__getplayercorpsecountbyzoneid, file); newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file); newXS(strcpy(buf, "givecash"), XS__givecash, file); newXS(strcpy(buf, "gmmove"), XS__gmmove, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index ff0c6b10a..0d1086ad1 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -549,6 +549,14 @@ void lua_summon_all_player_corpses(uint32 char_id, float x, float y, float z, fl quest_manager.summonallplayercorpses(char_id, glm::vec4(x, y, z, h)); } +int lua_get_player_corpse_count(uint32 char_id) { + return database.CountCharacterCorpses(char_id); +} + +int lua_get_player_corpse_count_by_zone_id(uint32 char_id, uint32 zone_id) { + return database.CountCharacterCorpsesByZoneID(char_id, zone_id); +} + int lua_get_player_buried_corpse_count(uint32 char_id) { return quest_manager.getplayerburiedcorpsecount(char_id); } @@ -1663,6 +1671,8 @@ luabind::scope lua_register_general() { luabind::def("toggle_spawn_event", &lua_toggle_spawn_event), luabind::def("summon_buried_player_corpse", &lua_summon_buried_player_corpse), luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses), + luabind::def("get_player_corpse_count", &lua_get_player_corpse_count), + luabind::def("get_player_corpse_count_by_zone_id", &lua_get_player_corpse_count_by_zone_id), luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count), luabind::def("bury_player_corpse", &lua_bury_player_corpse), luabind::def("task_selector", &lua_task_selector), diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 69e55a57f..bea136e28 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -1910,6 +1910,21 @@ bool QuestManager::summonallplayercorpses(uint32 char_id, const glm::vec4& posit return true; } +int QuestManager::getplayercorpsecount(uint32 char_id) { + if (char_id > 0) { + return database.CountCharacterCorpses(char_id); + } + return 0; + +} + +int QuestManager::getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id) { + if (char_id > 0 && zone_id > 0) { + return database.CountCharacterCorpsesByZoneID(char_id, zone_id); + } + return 0; +} + uint32 QuestManager::getplayerburiedcorpsecount(uint32 char_id) { uint32 Result = 0; diff --git a/zone/questmgr.h b/zone/questmgr.h index 1b9ea9c4d..5ad551c43 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -172,6 +172,8 @@ public: bool summonburiedplayercorpse(uint32 char_id, const glm::vec4& position); bool summonallplayercorpses(uint32 char_id, const glm::vec4& position); uint32 getplayerburiedcorpsecount(uint32 char_id); + int getplayercorpsecount(uint32 char_id); + int getplayercorpsecountbyzoneid(uint32 char_id, uint32 zone_id); bool buryplayercorpse(uint32 char_id); void forcedooropen(uint32 doorid, bool altmode); void forcedoorclose(uint32 doorid, bool altmode); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 0f29c38ce..693222e9f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1820,6 +1820,58 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove break; } + case SE_SummonCorpseZone: + { + if (IsClient()) { + Client* client_target = this->CastToClient(); + if (client_target->IsGrouped()) { + Group* group = client_target->GetGroup(); + if (!group->IsGroupMember(caster)) { + if (caster != this) { + caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); + break; + } + } + } else if (caster) { + if (caster->IsRaidGrouped()) { + Raid *raid = caster->GetRaid(); + uint32 group_id = raid->GetGroup(caster->GetName()); + if (group_id > 0 && group_id < MAX_RAID_GROUPS) { + if (raid->GetGroup(client_target->GetName()) != group_id) { + caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); + break; + } + } + } else { + if (caster != this) { + caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); + break; + } + } + } + + if (client_target) { + if (database.CountCharacterCorpses(client_target->CharacterID()) == 0) { + if (caster == this) { + Message(Chat::Yellow, "You have no corpses to summon."); + } else { + caster->Message(Chat::Yellow, "%s has no corpses to summon.", client_target->GetCleanName()); + } + } else { + if (caster == this) { + Message(Chat::Spells, "Summoning your corpses."); + } else { + caster->MessageString(Chat::Spells, SUMMONING_CORPSE_ZONE, client_target->GetCleanName()); + } + client_target->SummonAllCorpses(client_target->GetPosition()); + } + } else { + MessageString(Chat::Spells, TARGET_NOT_FOUND); + LogError("[{}] attempted to cast spell id [{}] with spell effect SE_SummonCorpseZone, but could not cast target into a Client object", GetCleanName(), spell_id); + } + } + break; + } case SE_AddMeleeProc: case SE_WeaponProc: { diff --git a/zone/string_ids.h b/zone/string_ids.h index acab3df22..0948d13a8 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -65,6 +65,7 @@ #define SILENCED_STRING 207 //You *CANNOT* cast spells, you have been silenced! #define CANNOT_AFFECT_PC 210 //That spell can not affect this target PC. #define SPELL_NEED_TAR 214 //You must first select a target for this spell! +#define SUMMON_ONLY_GROUP_CORPSE 215 //You must first target a living group member whose corpse you wish to summon. #define ONLY_ON_CORPSES 221 //This spell only works on corpses. #define CANT_DRAIN_SELF 224 //You can't drain yourself! #define CORPSE_NOT_VALID 230 //This corpse is not valid. @@ -169,6 +170,7 @@ #define PVP_ON 552 //You are now player kill and follow the ways of Discord. #define GENERIC_STRINGID_SAY 554 //%1 says '%T2' #define CANNOT_WAKE 555 //%1 tells you, 'I am unable to wake %2, master.' +#define SUMMONING_CORPSE_ZONE 596 //Summoning %1's corpse(s). #define PET_HOLD_SET_ON 698 //The pet hold mode has been set to on. #define PET_HOLD_SET_OFF 699 //The pet hold mode has been set to off. #define PET_FOCUS_SET_ON 700 //The pet focus mode has been set to on. diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index dc2e29cad..d5346877d 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -4707,6 +4707,47 @@ bool ZoneDatabase::SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zone_id return (CorpseCount > 0); } +int ZoneDatabase::CountCharacterCorpses(uint32 char_id) { + std::string query = fmt::format( + SQL( + SELECT + COUNT(*) + FROM + character_corpses + WHERE + charid = '{}' + ), + char_id + ); + auto results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + return atoi(row[0]); + } + return 0; +} + +int ZoneDatabase::CountCharacterCorpsesByZoneID(uint32 char_id, uint32 zone_id) { + std::string query = fmt::format( + SQL( + SELECT + COUNT(*) + FROM + character_corpses + WHERE + charid = '{}' + AND + zone_id = '{}' + ), + char_id, + zone_id + ); + auto results = QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + return atoi(row[0]); + } + return 0; +} + bool ZoneDatabase::UnburyCharacterCorpse(uint32 db_id, uint32 new_zone_id, uint16 new_instance_id, const glm::vec4& position) { std::string query = StringFormat("UPDATE `character_corpses` " "SET `is_buried` = 0, `zone_id` = %u, `instance_id` = %u, " diff --git a/zone/zonedb.h b/zone/zonedb.h index e93a40713..f28ac5ec4 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -356,6 +356,8 @@ public: bool DeleteCharacterCorpse(uint32 dbid); bool SummonAllCharacterCorpses(uint32 char_id, uint32 dest_zoneid, uint16 dest_instanceid, const glm::vec4& position); bool SummonAllGraveyardCorpses(uint32 cur_zoneid, uint32 dest_zoneid, uint16 dest_instanceid, const glm::vec4& position); + int CountCharacterCorpses(uint32 char_id); + int CountCharacterCorpsesByZoneID(uint32 char_id, uint32 zone_id); bool UnburyCharacterCorpse(uint32 dbid, uint32 new_zoneid, uint16 dest_instanceid, const glm::vec4& position); bool LoadCharacterCorpses(uint32 iZoneID, uint16 iInstanceID); bool DeleteGraveyard(uint32 zone_id, uint32 graveyard_id);