diff --git a/zone/embparser.cpp b/zone/embparser.cpp index c19ac6671..db37a58e7 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -977,6 +977,14 @@ void PerlembParser::MapFunctions() "package Expedition;" "&boot_Expedition;" +#ifdef BOTS + "package Bot;" + "our @ISA = qw(NPC);" // Bot inherits NPC + "&boot_Mob;" // load our Mob XS + "&boot_NPC;" // load our NPC XS + "&boot_Bot;" // load our Bot XS +#endif + #endif "package main;" "}" diff --git a/zone/embperl.cpp b/zone/embperl.cpp index b05a429a1..1300df0b2 100644 --- a/zone/embperl.cpp +++ b/zone/embperl.cpp @@ -39,6 +39,9 @@ EXTERN_C XS(boot_Object); EXTERN_C XS(boot_Doors); EXTERN_C XS(boot_PerlPacket); EXTERN_C XS(boot_Expedition); +#ifdef BOTS +EXTERN_C XS(boot_Bot); +#endif #endif #endif @@ -91,6 +94,11 @@ EXTERN_C void xs_init(pTHX) newXS(strcpy(buf, "Object::boot_Object"), boot_Object, file); newXS(strcpy(buf, "Doors::boot_Doors"), boot_Doors, file); newXS(strcpy(buf, "Expedition::boot_Expedition"), boot_Expedition, file); +#ifdef BOTS + newXS(strcpy(buf, "Bot::boot_Mob"), boot_Mob, file); + newXS(strcpy(buf, "Bot::boot_NPC"), boot_NPC, file); + newXS(strcpy(buf, "Bot::boot_Bot"), boot_Bot, file); +#endif ; #endif #endif diff --git a/zone/entity.cpp b/zone/entity.cpp index 5cc12dc72..81087da21 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4769,6 +4769,16 @@ void EntityList::GetClientList(std::list &c_list) } } +#ifdef BOTS +void EntityList::GetBotList(std::list &b_list) +{ + b_list.clear(); + for (auto bot_iterator : bot_list) { + b_list.push_back(bot_iterator); + } +} +#endif + void EntityList::GetCorpseList(std::list &c_list) { c_list.clear(); diff --git a/zone/entity.h b/zone/entity.h index b4855b42e..5eec26f35 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -514,6 +514,9 @@ public: inline const std::unordered_map &GetNPCList() { return npc_list; } inline const std::unordered_map &GetMercList() { return merc_list; } inline const std::unordered_map &GetClientList() { return client_list; } +#ifdef BOTS + inline const std::list &GetBotList() { return bot_list; } +#endif inline const std::unordered_map &GetCorpseList() { return corpse_list; } inline const std::unordered_map &GetObjectList() { return object_list; } inline const std::unordered_map &GetDoorsList() { return door_list; } @@ -593,6 +596,8 @@ private: void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff void ScanCloseClientMobs(std::unordered_map& close_mobs, Mob* scanning_mob); + + void GetBotList(std::list &b_list); private: std::list bot_list; #endif diff --git a/zone/lua_bot.cpp b/zone/lua_bot.cpp new file mode 100644 index 000000000..78bb7049c --- /dev/null +++ b/zone/lua_bot.cpp @@ -0,0 +1,13 @@ +#ifdef LUA_EQEMU + +#include "lua.hpp" +#include + +#include "bot.h" +#include "lua_bot.h" + +luabind::scope lua_register_bot() { + return luabind::class_("Bot").def(luabind::constructor<>()); +} + +#endif diff --git a/zone/lua_bot.h b/zone/lua_bot.h new file mode 100644 index 000000000..3e7d17631 --- /dev/null +++ b/zone/lua_bot.h @@ -0,0 +1,30 @@ +#ifndef EQEMU_LUA_BOT_H +#define EQEMU_LUA_BOT_H +#ifdef LUA_EQEMU + +#include "lua_mob.h" + +class Bot; +class Lua_Bot; + +namespace luabind { + struct scope; +} + +luabind::scope lua_register_bot(); + +class Lua_Bot : public Lua_Mob +{ + typedef Bot NativeType; +public: + Lua_Bot() { SetLuaPtrData(nullptr); } + Lua_Bot(Bot *d) { SetLuaPtrData(reinterpret_cast(d)); } + virtual ~Lua_Bot() { } + + operator Bot*() { + return reinterpret_cast(GetLuaPtrData()); + } +}; + +#endif +#endif diff --git a/zone/lua_entity.cpp b/zone/lua_entity.cpp index 725e78f5e..11ac06199 100644 --- a/zone/lua_entity.cpp +++ b/zone/lua_entity.cpp @@ -12,6 +12,10 @@ #include "lua_object.h" #include "lua_door.h" +#ifdef BOTS +#include "lua_bot.h" +#endif + bool Lua_Entity::IsClient() { Lua_Safe_Call_Bool(); return self->IsClient(); @@ -118,6 +122,14 @@ Lua_Door Lua_Entity::CastToDoor() { return Lua_Door(m); } +#ifdef BOTS +Lua_Bot Lua_Entity::CastToBot() { + void *d = GetLuaPtrData(); + Bot *b = reinterpret_cast(d); + return Lua_Bot(b); +} +#endif + luabind::scope lua_register_entity() { return luabind::class_("Entity") .def(luabind::constructor<>()) @@ -138,6 +150,9 @@ luabind::scope lua_register_entity() { .def("IsBot", &Lua_Entity::IsBot) .def("GetID", &Lua_Entity::GetID) .def("CastToClient", &Lua_Entity::CastToClient) +#ifdef BOTS + .def("CastToBot", &Lua_Entity::CastToBot) +#endif .def("CastToNPC", &Lua_Entity::CastToNPC) .def("CastToMob", &Lua_Entity::CastToMob) .def("CastToCorpse", &Lua_Entity::CastToCorpse) diff --git a/zone/lua_entity.h b/zone/lua_entity.h index b45208581..4954d13ff 100644 --- a/zone/lua_entity.h +++ b/zone/lua_entity.h @@ -6,6 +6,9 @@ class Entity; class Lua_Client; +#ifdef BOTS +class Lua_Bot; +#endif class Lua_NPC; class Lua_Mob; struct Lua_HateList; @@ -54,6 +57,9 @@ public: Lua_Corpse CastToCorpse(); Lua_Object CastToObject(); Lua_Door CastToDoor(); +#ifdef BOTS + Lua_Bot CastToBot(); +#endif }; #endif diff --git a/zone/lua_entity_list.cpp b/zone/lua_entity_list.cpp index e4f2b207d..9d6a812ed 100644 --- a/zone/lua_entity_list.cpp +++ b/zone/lua_entity_list.cpp @@ -17,6 +17,10 @@ #include "lua_raid.h" #include "lua_spawn.h" +#ifdef BOTS +#include "lua_bot.h" +#endif + struct Lua_Mob_List { std::vector entries; }; @@ -29,6 +33,12 @@ struct Lua_Client_List { std::vector entries; }; +#ifdef BOTS +struct Lua_Bot_List { + std::vector entries; +}; +#endif + struct Lua_Corpse_List { std::vector entries; }; @@ -345,6 +355,29 @@ Lua_Client_List Lua_EntityList::GetClientList() { return ret; } +#ifdef BOTS +Lua_Bot Lua_EntityList::GetBotByID(uint32 bot_id) { + Lua_Safe_Call_Class(Lua_Bot); + return Lua_Bot(self->GetBotByBotID(bot_id)); +} + +Lua_Bot Lua_EntityList::GetBotByName(std::string bot_name) { + Lua_Safe_Call_Class(Lua_Bot); + return Lua_Bot(self->GetBotByBotName(bot_name)); +} + +Lua_Bot_List Lua_EntityList::GetBotList() { + Lua_Safe_Call_Class(Lua_Bot_List); + Lua_Bot_List ret; + auto &bot_list = self->GetBotList(); + for (auto bot_iterator : bot_list) { + ret.entries.push_back(Lua_Bot(bot_iterator)); + } + + return ret; +} +#endif + Lua_Client_List Lua_EntityList::GetShuffledClientList() { Lua_Safe_Call_Class(Lua_Client_List); Lua_Client_List ret; @@ -502,6 +535,11 @@ luabind::scope lua_register_entity_list() { .def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float, float, float, float, Lua_Client))&Lua_EntityList::GetRandomClient) .def("GetMobList", (Lua_Mob_List(Lua_EntityList::*)(void))&Lua_EntityList::GetMobList) .def("GetClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetClientList) +#ifdef BOTS + .def("GetBotByID", (Lua_Bot(Lua_EntityList::*)(uint32))&Lua_EntityList::GetBotByID) + .def("GetBotByName", (Lua_Bot(Lua_EntityList::*)(std::string))&Lua_EntityList::GetBotByName) + .def("GetBotList", (Lua_Bot_List(Lua_EntityList::*)(void))&Lua_EntityList::GetBotList) +#endif .def("GetShuffledClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetShuffledClientList) .def("GetNPCList", (Lua_NPC_List(Lua_EntityList::*)(void))&Lua_EntityList::GetNPCList) .def("GetCorpseList", (Lua_Corpse_List(Lua_EntityList::*)(void))&Lua_EntityList::GetCorpseList) @@ -522,6 +560,13 @@ luabind::scope lua_register_client_list() { .def_readwrite("entries", &Lua_Client_List::entries, luabind::return_stl_iterator); } +#ifdef BOTS +luabind::scope lua_register_bot_list() { + return luabind::class_("BotList") + .def_readwrite("entries", &Lua_Bot_List::entries, luabind::return_stl_iterator); +} +#endif + luabind::scope lua_register_npc_list() { return luabind::class_("NPCList") .def_readwrite("entries", &Lua_NPC_List::entries, luabind::return_stl_iterator); diff --git a/zone/lua_entity_list.h b/zone/lua_entity_list.h index 04030e58e..4fa7b97b9 100644 --- a/zone/lua_entity_list.h +++ b/zone/lua_entity_list.h @@ -7,6 +7,9 @@ class EntityList; class Lua_Mob; class Lua_Client; +#ifdef BOTS +class Lua_Bot; +#endif class Lua_NPC; class Lua_Door; class Lua_Corpse; @@ -16,6 +19,9 @@ class Lua_Raid; class Lua_Spawn; struct Lua_Mob_List; struct Lua_Client_List; +#ifdef BOTS +struct Lua_Bot_List; +#endif struct Lua_NPC_List; struct Lua_Corpse_List; struct Lua_Object_List; @@ -35,6 +41,10 @@ luabind::scope lua_register_object_list(); luabind::scope lua_register_door_list(); luabind::scope lua_register_spawn_list(); +#ifdef BOTS +luabind::scope lua_register_bot_list(); +#endif + class Lua_EntityList : public Lua_Ptr { typedef EntityList NativeType; @@ -110,6 +120,11 @@ public: Lua_Spawn_List GetSpawnList(); void SignalAllClients(int signal); void ChannelMessage(Lua_Mob from, int channel_num, int language, const char *message); +#ifdef BOTS + Lua_Bot GetBotByID(uint32 bot_id); + Lua_Bot GetBotByName(std::string bot_name); + Lua_Bot_List GetBotList(); +#endif }; #endif diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 59b10d4bf..1fc0fc47a 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -40,6 +40,10 @@ #include "lua_encounter.h" #include "lua_stat_bonuses.h" +#ifdef BOTS +#include "lua_bot.h" +#endif + const char *LuaEvents[_LargestEventID] = { "event_say", "event_trade", @@ -1090,6 +1094,9 @@ void LuaParser::MapFunctions(lua_State *L) { lua_register_special_abilities(), lua_register_npc(), lua_register_client(), +#ifdef BOTS + lua_register_bot(), +#endif lua_register_inventory(), lua_register_inventory_where(), lua_register_iteminst(), @@ -1101,6 +1108,9 @@ void LuaParser::MapFunctions(lua_State *L) { lua_register_entity_list(), lua_register_mob_list(), lua_register_client_list(), +#ifdef BOTS + lua_register_bot_list(), +#endif lua_register_npc_list(), lua_register_corpse_list(), lua_register_object_list(), diff --git a/zone/perl_bot.cpp b/zone/perl_bot.cpp new file mode 100644 index 000000000..d78c82d52 --- /dev/null +++ b/zone/perl_bot.cpp @@ -0,0 +1,84 @@ +/* EQEMu: Everquest Server Emulator +Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY except by those people which sell it, which +are required to give you total support for your newly bought product; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "../common/features.h" +#ifdef EMBPERL_XS_CLASSES +#include "../common/global_define.h" +#include "embperl.h" + +#ifdef seed +#undef seed +#endif + +#include "bot.h" + +#ifdef THIS +#undef THIS +#endif + +#define VALIDATE_THIS_IS_BOT \ + do { \ + if (sv_derived_from(ST(0), "Bot")) { \ + IV tmp = SvIV((SV*)SvRV(ST(0))); \ + THIS = INT2PTR(Bot*, tmp); \ + } else { \ + Perl_croak(aTHX_ "THIS is not of type Bot"); \ + } \ + if (THIS == nullptr) { \ + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); \ + } \ + } while (0); + +XS(XS_Bot_GetOwner); +XS(XS_Bot_GetOwner) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Bot::GetOwner(THIS)"); // @categories Script Utility, Bot + { + Bot* THIS; + Mob* bot_owner; + VALIDATE_THIS_IS_BOT; + bot_owner = THIS->GetBotOwner(); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Mob", (void*)bot_owner); + } + XSRETURN(1); +} + +#ifdef __cplusplus +extern "C" +#endif + +XS(boot_Bot); +XS(boot_Bot) +{ + dXSARGS; + char file[256]; + strncpy(file, __FILE__, 256); + file[255] = 0; + + if (items != 1) + fprintf(stderr, "boot_Bot does not take any arguments."); + + char buf[128]; + XS_VERSION_BOOTCHECK; + + newXSproto(strcpy(buf, "GetOwner"), XS_Bot_GetOwner, file, "$"); + + XSRETURN_YES; +} + +#endif //EMBPERL_XS_CLASSES \ No newline at end of file diff --git a/zone/perl_entity.cpp b/zone/perl_entity.cpp index c2b3d6a32..ec1e855cd 100644 --- a/zone/perl_entity.cpp +++ b/zone/perl_entity.cpp @@ -1310,6 +1310,64 @@ XS(XS_EntityList_GetClientList) { XSRETURN(num_clients); } +#ifdef BOTS +XS(XS_EntityList_GetBotByID); +XS(XS_EntityList_GetBotByID) { + dXSARGS; + int bot_count = 0; + if (items != 2) + Perl_croak(aTHX_ "Usage: EntityList::GetBotByID(THIS, uint32 bot_id)"); // @categories Script Utility, Bot + { + EntityList* THIS; + Bot* RETVAL; + uint32 bot_id = (uint32) SvUV(ST(1)); + VALIDATE_THIS_IS_ENTITY; + RETVAL = THIS->GetBotByBotID(bot_id); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Bot", (void *) RETVAL); + } + XSRETURN(1); +} + +XS(XS_EntityList_GetBotByName); +XS(XS_EntityList_GetBotByName) { + dXSARGS; + int bot_count = 0; + if (items != 2) + Perl_croak(aTHX_ "Usage: EntityList::GetBotByName(THIS, string bot_name)"); // @categories Script Utility, Bot + { + EntityList* THIS; + Bot* RETVAL; + std::string bot_name = (std::string) SvPV_nolen(ST(1)); + VALIDATE_THIS_IS_ENTITY; + RETVAL = THIS->GetBotByBotName(bot_name); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Bot", (void *) RETVAL); + } + XSRETURN(1); +} + +XS(XS_EntityList_GetBotList); +XS(XS_EntityList_GetBotList) { + dXSARGS; + int bot_count = 0; + if (items != 1) + Perl_croak(aTHX_ "Usage: EntityList::GetBotList(THIS)"); // @categories Script Utility, Bot + { + EntityList *THIS; + VALIDATE_THIS_IS_ENTITY; + auto current_bot_list = THIS->GetBotList(); + for (auto bot_iterator : current_bot_list) { + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Bot", (void *)bot_iterator); + XPUSHs(ST(0)); + bot_count++; + } + } + XSRETURN(bot_count); +} +#endif + XS(XS_EntityList_GetNPCList); /* prototype to pass -Wmissing-prototypes */ XS(XS_EntityList_GetNPCList) { dXSARGS; @@ -1517,6 +1575,11 @@ XS(boot_EntityList) { newXSproto(strcpy(buf, "GetObjectList"), XS_EntityList_GetObjectList, file, "$"); newXSproto(strcpy(buf, "GetDoorsList"), XS_EntityList_GetDoorsList, file, "$"); newXSproto(strcpy(buf, "SignalAllClients"), XS_EntityList_SignalAllClients, file, "$$"); +#ifdef BOTS + newXSproto(strcpy(buf, "GetBotByID"), XS_EntityList_GetBotByID, file, "$$"); + newXSproto(strcpy(buf, "GetBotByName"), XS_EntityList_GetBotByName, file, "$$"); + newXSproto(strcpy(buf, "GetBotList"), XS_EntityList_GetBotList, file, "$"); +#endif XSRETURN_YES; } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index fb4606d27..28830ef2b 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -42,6 +42,10 @@ typedef const char Const_char; #include "client.h" #include "../common/spdat.h" +#ifdef BOTS +#include "bot.h" +#endif + #ifdef THIS /* this macro seems to leak out on some systems */ #undef THIS #endif @@ -6253,6 +6257,25 @@ XS(XS_Mob_GetLastName) { XSRETURN(1); } +#ifdef BOTS +XS(XS_Mob_CastToBot); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_CastToBot) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::CastToBot(THIS)"); + { + Mob* THIS; + Bot* RETVAL; + VALIDATE_THIS_IS_MOB; + RETVAL = THIS->CastToBot(); + ST(0) = sv_newmortal(); + sv_setref_pv(ST(0), "Bot", (void*)RETVAL); + } + XSRETURN(1); +} +#endif + #ifdef __cplusplus extern "C" #endif @@ -6602,6 +6625,9 @@ XS(boot_Mob) { newXSproto(strcpy(buf, "GetHateClosest"), XS_Mob_GetHateClosest, file, "$"); newXSproto(strcpy(buf, "GetHateListByDistance"), XS_Mob_GetHateListByDistance, file, "$;$"); newXSproto(strcpy(buf, "GetLastName"), XS_Mob_GetLastName, file, "$"); +#ifdef BOTS + newXSproto(strcpy(buf, "CastToBot"), XS_Mob_CastToBot, file, "$"); +#endif XSRETURN_YES; }