diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index b4b6725bb..5e13f3ed5 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -797,3 +797,152 @@ std::list HateList::GetHateListByDistance(int distance) } return hate_list; } + +#ifdef BOTS +Bot* HateList::GetRandomBotOnHateList(bool skip_mezzed) +{ + int count = list.size(); + if (count <= 0) { //If we don't have any entries it'll crash getting a random 0, -1 position. + return nullptr; + } + + if (count == 1) { //No need to do all that extra work if we only have one hate entry + if (*list.begin() && (*list.begin())->entity_on_hatelist->IsBot() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) { + return (*list.begin())->entity_on_hatelist->CastToBot(); + } + return nullptr; + } + + if (skip_mezzed) { + for (auto iter : list) { + if (iter->entity_on_hatelist->IsMezzed()) { + --count; + } + } + + if (count <= 0) { + return nullptr; + } + } + + int random = zone->random.Int(0, count - 1); + int counter = 0; + + for (auto iter : list) { + if (!iter->entity_on_hatelist->IsBot()) { + continue; + } + + if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) { + continue; + } + + if (counter < random) { + ++counter; + continue; + } + + return iter->entity_on_hatelist->CastToBot(); + } + + return nullptr; +} +#endif + +Client* HateList::GetRandomClientOnHateList(bool skip_mezzed) +{ + int count = list.size(); + if (count <= 0) { //If we don't have any entries it'll crash getting a random 0, -1 position. + return nullptr; + } + + if (count == 1) { //No need to do all that extra work if we only have one hate entry + if (*list.begin() && (*list.begin())->entity_on_hatelist->IsClient() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) { + return (*list.begin())->entity_on_hatelist->CastToClient(); + } + return nullptr; + } + + if (skip_mezzed) { + for (auto iter : list) { + if (iter->entity_on_hatelist->IsMezzed()) { + --count; + } + } + + if (count <= 0) { + return nullptr; + } + } + + int random = zone->random.Int(0, count - 1); + int counter = 0; + + for (auto iter : list) { + if (!iter->entity_on_hatelist->IsClient()) { + continue; + } + + if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) { + continue; + } + + if (counter < random) { + ++counter; + continue; + } + + return iter->entity_on_hatelist->CastToClient(); + } + + return nullptr; +} + +NPC* HateList::GetRandomNPCOnHateList(bool skip_mezzed) +{ + int count = list.size(); + if (count <= 0) { //If we don't have any entries it'll crash getting a random 0, -1 position. + return nullptr; + } + + if (count == 1) { //No need to do all that extra work if we only have one hate entry + if (*list.begin() && (*list.begin())->entity_on_hatelist->IsNPC() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) { + return (*list.begin())->entity_on_hatelist->CastToNPC(); + } + return nullptr; + } + + if (skip_mezzed) { + for (auto iter : list) { + if (iter->entity_on_hatelist->IsMezzed()) { + --count; + } + } + + if (count <= 0) { + return nullptr; + } + } + + int random = zone->random.Int(0, count - 1); + int counter = 0; + + for (auto iter : list) { + if (!iter->entity_on_hatelist->IsNPC()) { + continue; + } + + if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) { + continue; + } + + if (counter < random) { + ++counter; + continue; + } + + return iter->entity_on_hatelist->CastToNPC(); + } + + return nullptr; +} diff --git a/zone/hate_list.h b/zone/hate_list.h index 71c1f31cf..22971aa2e 100644 --- a/zone/hate_list.h +++ b/zone/hate_list.h @@ -49,6 +49,12 @@ public: Mob *GetEscapingEntOnHateList(); // returns first eligble entity Mob *GetEscapingEntOnHateList(Mob *center, float range = 0.0f, bool first = false); +#ifdef BOTS + Bot* GetRandomBotOnHateList(bool skip_mezzed = false); +#endif + Client* GetRandomClientOnHateList(bool skip_mezzed = false); + NPC* GetRandomNPCOnHateList(bool skip_mezzed = false); + bool IsEntOnHateList(Mob *mob); bool IsHateListEmpty(); bool RemoveEntFromHateList(Mob *ent); diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 3c2781c28..181a7dde5 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -5,9 +5,13 @@ #include "client.h" #include "npc.h" +#ifdef BOTS +#include "lua_bot.h" +#endif #include "lua_item.h" #include "lua_iteminst.h" #include "lua_mob.h" +#include "lua_npc.h" #include "lua_hate_list.h" #include "lua_client.h" #include "lua_stat_bonuses.h" @@ -2402,6 +2406,23 @@ void Lua_Mob::RemoveAllNimbusEffects() { self->RemoveAllNimbusEffects(); } +#ifdef BOTS +Lua_Bot Lua_Mob::GetHateRandomBot() { + Lua_Safe_Call_Class(Lua_Bot); + return Lua_Bot(self->GetHateRandomBot()); +} +#endif + +Lua_Client Lua_Mob::GetHateRandomClient() { + Lua_Safe_Call_Class(Lua_Client); + return Lua_Client(self->GetHateRandomClient()); +} + +Lua_NPC Lua_Mob::GetHateRandomNPC() { + Lua_Safe_Call_Class(Lua_NPC); + return Lua_NPC(self->GetHateRandomNPC()); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -2810,7 +2831,12 @@ luabind::scope lua_register_mob() { .def("GetLastName", &Lua_Mob::GetLastName) .def("CanClassEquipItem", &Lua_Mob::CanClassEquipItem) .def("CanRaceEquipItem", &Lua_Mob::CanRaceEquipItem) - .def("RemoveAllNimbusEffects", &Lua_Mob::RemoveAllNimbusEffects); + .def("RemoveAllNimbusEffects", &Lua_Mob::RemoveAllNimbusEffects) +#ifdef BOTS + .def("GetHateRandomBot", (Lua_Bot(Lua_Mob::*)(void))&Lua_Mob::GetHateRandomBot) +#endif + .def("GetHateRandomClient", (Lua_Client(Lua_Mob::*)(void))&Lua_Mob::GetHateRandomClient) + .def("GetHateRandomNPC", (Lua_NPC(Lua_Mob::*)(void))&Lua_Mob::GetHateRandomNPC); } luabind::scope lua_register_special_abilities() { diff --git a/zone/lua_mob.h b/zone/lua_mob.h index cd3e524cb..144d9dbb5 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -9,6 +9,11 @@ struct Lua_HateList; class Lua_Item; class Lua_ItemInst; class Lua_StatBonuses; +#ifdef BOTS +class Lua_Bot; +#endif +class Lua_NPC; +class Lua_Client; namespace luabind { struct scope; @@ -205,6 +210,11 @@ public: Lua_Mob GetHateTop(); Lua_Mob GetHateDamageTop(Lua_Mob other); Lua_Mob GetHateRandom(); +#ifdef BOTS + Lua_Bot GetHateRandomBot(); +#endif + Lua_Client GetHateRandomClient(); + Lua_NPC GetHateRandomNPC(); Lua_Mob GetHateClosest(); void AddToHateList(Lua_Mob other); void AddToHateList(Lua_Mob other, int hate); diff --git a/zone/mob.h b/zone/mob.h index 3d207ee26..c2e49f757 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -649,6 +649,11 @@ public: Mob* GetSecondaryHate(Mob *skip) { return hate_list.GetEntWithMostHateOnList(this, skip); } Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTopOnHateList(other);} Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();} + Client* GetHateRandomClient() { return hate_list.GetRandomClientOnHateList(); } + NPC* GetHateRandomNPC() { return hate_list.GetRandomNPCOnHateList(); } +#ifdef BOTS + Bot* GetHateRandomBot() { return hate_list.GetRandomBotOnHateList(); } +#endif Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();} Mob* GetHateClosest() { return hate_list.GetClosestEntOnHateList(this); } bool IsEngaged() { return(!hate_list.IsHateListEmpty()); } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index ff8bc48b9..4c32c5a87 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -6357,6 +6357,38 @@ XS(XS_Mob_ShieldAbility) { XSRETURN_EMPTY; } +XS(XS_Mob_GetHateRandomClient); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHateRandomClient) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetHateRandomClient(THIS)"); // @categories Hate and Aggro + { + Mob* THIS; + Client* RETVAL; + VALIDATE_THIS_IS_MOB; + RETVAL = THIS->GetHateRandomClient(); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Client", (void *) RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetHateRandomNPC); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHateRandomNPC) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetHateRandomNPC(THIS)"); // @categories Hate and Aggro + { + Mob* THIS; + NPC* RETVAL; + VALIDATE_THIS_IS_MOB; + RETVAL = THIS->GetHateRandomNPC(); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "NPC", (void *) RETVAL); + } + XSRETURN(1); +} + #ifdef BOTS XS(XS_Mob_CastToBot); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_CastToBot) @@ -6374,6 +6406,22 @@ XS(XS_Mob_CastToBot) } XSRETURN(1); } + +XS(XS_Mob_GetHateRandomBot); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHateRandomBot) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetHateRandomBot(THIS)"); // @categories Hate and Aggro + { + Mob* THIS; + Bot* RETVAL; + VALIDATE_THIS_IS_MOB; + RETVAL = THIS->GetHateRandomBot(); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Bot", (void *) RETVAL); + } + XSRETURN(1); +} #endif #ifdef __cplusplus @@ -6729,8 +6777,11 @@ XS(boot_Mob) { newXSproto(strcpy(buf, "RemoveAllNimbusEffects"), XS_Mob_RemoveAllNimbusEffects, file, "$"); newXSproto(strcpy(buf, "AddNimbusEffect"), XS_Mob_AddNimbusEffect, file, "$$"); newXSproto(strcpy(buf, "ShieldAbility"), XS_Mob_ShieldAbility, file, "$$$$$$$$"); + newXSproto(strcpy(buf, "GetHateRandomClient"), XS_Mob_GetHateRandomClient, file, "$"); + newXSproto(strcpy(buf, "GetHateRandomNPC"), XS_Mob_GetHateRandomNPC, file, "$"); #ifdef BOTS newXSproto(strcpy(buf, "CastToBot"), XS_Mob_CastToBot, file, "$"); + newXSproto(strcpy(buf, "GetHateRandomBot"), XS_Mob_GetHateRandomBot, file, "$"); #endif XSRETURN_YES; }