From a7f4954fbebccf1eea1618c58153577045dc4972 Mon Sep 17 00:00:00 2001 From: Rochet2 Date: Sat, 22 Nov 2014 17:16:41 +0200 Subject: [PATCH] Eluna implement functions from #121, implement hidden file ignoring closes #122, enhance documentation in places, change requiring some now only allowing unique filenames --- CreatureMethods.h | 27 ++++- ElunaIncludes.h | 2 +- GlobalMethods.h | 242 ++++++++++++++++++++++++++++++------- ItemMethods.h | 40 +++--- LuaEngine.cpp | 50 +++++++- LuaFunctions.cpp | 17 ++- PlayerMethods.h | 32 +++-- UnitMethods.h | 281 +++++++++++++++++++++++++++++++++++-------- WorldObjectMethods.h | 29 +++++ docs/DOC_GEN.md | 22 ++++ 10 files changed, 617 insertions(+), 125 deletions(-) diff --git a/CreatureMethods.h b/CreatureMethods.h index 0942f82..b9a2d45 100644 --- a/CreatureMethods.h +++ b/CreatureMethods.h @@ -898,7 +898,32 @@ namespace LuaCreature } /** - * Sets whether the [Creature] can be aggroed by movement or not. + * Equips given [Item]s to the [Unit]. Using 0 removes the equipped [Item] + * + * @param uint32 main_hand : main hand [Item]'s entry + * @param uint32 off_hand : off hand [Item]'s entry + * @param uint32 ranged : ranged [Item]'s entry + */ + int SetEquipmentSlots(lua_State* L, Creature* creature) + { + uint32 main_hand = Eluna::CHECKVAL(L, 2); + uint32 off_hand = Eluna::CHECKVAL(L, 3); + uint32 ranged = Eluna::CHECKVAL(L, 4); + +#ifdef TRINITY + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, main_hand); + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, off_hand); + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, ranged); +#else + creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, main_hand); + creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, off_hand); + creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, ranged); +#endif + return 0; + } + + /** + * Sets whether the [Creature] can be aggroed. * * @param bool allow = true : `true` to allow aggro, `false` to disable aggro */ diff --git a/ElunaIncludes.h b/ElunaIncludes.h index 389cd04..9781e6a 100644 --- a/ElunaIncludes.h +++ b/ElunaIncludes.h @@ -98,7 +98,7 @@ typedef ThreatContainer::StorageType ThreatList; #define eAccountMgr (&sAccountMgr) #define eObjectAccessor (&sObjectAccessor) #define SERVER_MSG_STRING SERVER_MSG_CUSTOM -#define MAX_LOCALES MAX_LOCALE +#define TOTAL_LOCALES MAX_LOCALE #define DIALOG_STATUS_SCRIPTED_NO_STATUS DIALOG_STATUS_UNDEFINED #define TARGETICONCOUNT TARGET_ICON_COUNT #define MAX_TALENT_SPECS MAX_TALENT_SPEC_COUNT diff --git a/GlobalMethods.h b/GlobalMethods.h index 7e2f1fb..00ea40d 100644 --- a/GlobalMethods.h +++ b/GlobalMethods.h @@ -359,10 +359,10 @@ namespace LuaGlobalFunctions } /** - * Returns an [Item]'s chat link + * Returns an item chat link for given entry * *
-     * enum Locales
+     * enum LocaleConstant
      * {
      *     LOCALE_enUS = 0,
      *     LOCALE_koKR = 1,
@@ -376,15 +376,15 @@ namespace LuaGlobalFunctions
      * };
      * 
* - * @param uint32 entry : entry ID of the [Item] - * @param int32 loc_idx = 0 : locale index, default is enUS + * @param uint32 entry : entry ID of an [Item] + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the [Item] name in * @return string itemLink */ int GetItemLink(lua_State* L) { uint32 entry = Eluna::CHECKVAL(L, 1); - int loc_idx = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); - if (loc_idx < 0 || loc_idx >= MAX_LOCALES) + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) return luaL_argerror(L, 2, "valid LocaleConstant expected"); const ItemTemplate* temp = eObjectMgr->GetItemTemplate(entry); @@ -393,7 +393,7 @@ namespace LuaGlobalFunctions std::string name = temp->Name1; if (ItemLocale const* il = eObjectMgr->GetItemLocale(entry)) - ObjectMgr::GetLocaleString(il->Name, loc_idx, name); + ObjectMgr::GetLocaleString(il->Name, locale, name); std::ostringstream oss; oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec << @@ -441,20 +441,35 @@ namespace LuaGlobalFunctions /** * Returns the area's or zone's name * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * * @param uint32 areaOrZoneId : area ID or zone ID - * @param uint32 locale_idx = 0 : locale to return the name in + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the name in * @return string areaOrZoneName */ int GetAreaName(lua_State* L) { uint32 areaOrZoneId = Eluna::CHECKVAL(L, 1); - int locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); - if (locale < 0 || locale >= MAX_LOCALES) - return luaL_argerror(L, 2, "Invalid locale specified"); + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaOrZoneId); if (!areaEntry) - return luaL_argerror(L, 1, "Invalid Area or Zone ID"); + return luaL_argerror(L, 1, "valid Area or Zone ID expected"); Eluna::Push(L, areaEntry->area_name[locale]); return 1; @@ -1681,6 +1696,7 @@ namespace LuaGlobalFunctions /** * Sends mail to a [Player] + * There can be several item entry-amount pairs at the end of the function. There can be maximum of 12 different items. * *
      * enum MailStationery
@@ -1698,11 +1714,13 @@ namespace LuaGlobalFunctions
      * @param string subject : title (subject) of the mail
      * @param string text : contents of the mail
      * @param uint32 receiverGUIDLow : low GUID of the receiver
-     * @param uint32 senderGUIDLow = 0 : low GUID of the sender, this is optional
-     * @param uint32 stationary = MAIL_STATIONERY_DEFAULT : type of mail that is being sent as, refer to MailStationery above, this is optional
-     * @param uint32 delay = 0 : mail send delay in milliseconds, this is optional
-     * @param uint32 money = 0 : money to send, this is optional
-     * @param uint32 cod = 0 : cod money amount, this is optional
+     * @param uint32 senderGUIDLow = 0 : low GUID of the sender
+     * @param uint32 stationary = MAIL_STATIONERY_DEFAULT : type of mail that is being sent as, refer to MailStationery above
+     * @param uint32 delay = 0 : mail send delay in milliseconds
+     * @param uint32 money = 0 : money to send
+     * @param uint32 cod = 0 : cod money amount
+     * @param uint32 entry = 0 : entry of an [Item] to send with mail
+     * @param uint32 amount = 0 : amount of the [Item] to send with mail
      */
     int SendMail(lua_State* L)
     {
@@ -1778,12 +1796,11 @@ namespace LuaGlobalFunctions
     }
 
     /**
-     * Returns result
-     * Documentation will need to be changed
+     * Returns the result of bitwise and: a & b
      *
      * @param uint32 a
      * @param uint32 b
-     * @return uint32 val
+     * @return uint32 result
      */
     int bit_and(lua_State* L)
     {
@@ -1794,12 +1811,11 @@ namespace LuaGlobalFunctions
     }
 
     /**
-     * Returns result
-     * Documentation will need to be changed
+     * Returns the result of bitwise or: a | b
      *
      * @param uint32 a
      * @param uint32 b
-     * @return uint32 val
+     * @return uint32 result
      */
     int bit_or(lua_State* L)
     {
@@ -1810,12 +1826,11 @@ namespace LuaGlobalFunctions
     }
 
     /**
-     * Returns result
-     * Documentation will need to be changed
+     * Returns the result of bitwise left shift: a << b
      *
      * @param uint32 a
      * @param uint32 b
-     * @return uint32 val
+     * @return uint32 result
      */
     int bit_lshift(lua_State* L)
     {
@@ -1826,12 +1841,11 @@ namespace LuaGlobalFunctions
     }
 
     /**
-     * Returns result
-     * Documentation will need to be changed
+     * Returns the result of bitwise right shift: a >> b
      *
      * @param uint32 a
      * @param uint32 b
-     * @return uint32 val
+     * @return uint32 result
      */
     int bit_rshift(lua_State* L)
     {
@@ -1842,12 +1856,11 @@ namespace LuaGlobalFunctions
     }
 
     /**
-     * Returns result
-     * Documentation will need to be changed
+     * Returns the result of bitwise xor: a ^ b
      *
      * @param uint32 a
      * @param uint32 b
-     * @return uint32 val
+     * @return uint32 result
      */
     int bit_xor(lua_State* L)
     {
@@ -1858,11 +1871,10 @@ namespace LuaGlobalFunctions
     }
 
     /**
-     * Returns result
-     * Documentation will need to be changed
+     * Returns the result of bitwise not: ~a
      *
      * @param uint32 a
-     * @return uint32 val
+     * @return uint32 result
      */
     int bit_not(lua_State* L)
     {
@@ -1871,16 +1883,24 @@ namespace LuaGlobalFunctions
         return 1;
     }
 
-    // AddTaxiPath(pathTable, mountA, mountH[, price, pathId])
     /**
-     * Adds a taxi path to a specified map, also returns pathId
+     * Adds a taxi path to a specified map, returns the used pathId
+     * Related function: [Player:StartTaxi]
      *
-     * @param table waypoints : waypoint table, goes by map, x, y, and z
+     * 
+     * -- Execute on startup
+     * local pathTable = {{mapid, x, y, z}, {mapid, x, y, z}}
+     * local path = AddTaxiPath(pathTable, 28135, 28135)
+     * -- Execute when the player should fly
+     * player:StartTaxi(path)
+     * 
+ * + * @param table waypoints : table containing waypoints: {map, x, y, z[, actionFlag, delay]} * @param uint32 mountA : alliance [Creature] entry * @param uint32 mountH : horde [Creature] entry - * @param uint32 price = 0 : price of the taxi path, this is optional - * @param uint32 pathId = 0 : path Id of the taxi path, this is optional - * @return uint32 pathId + * @param uint32 price = 0 : price of the taxi path + * @param uint32 pathId = 0 : path Id of the taxi path + * @return uint32 actualPathId */ int AddTaxiPath(lua_State* L) { @@ -1927,8 +1947,8 @@ namespace LuaGlobalFunctions entry->y = Eluna::CHECKVAL(L, start + 2); entry->z = Eluna::CHECKVAL(L, start + 3); // optional - entry->actionFlag = Eluna::CHECKVAL(L, start + 4); - entry->delay = Eluna::CHECKVAL(L, start + 5); + entry->actionFlag = Eluna::CHECKVAL(L, start + 4, 0); + entry->delay = Eluna::CHECKVAL(L, start + 5, 0); nodes.push_back(*entry); @@ -2097,5 +2117,141 @@ namespace LuaGlobalFunctions #endif return 0; } + + /** + * Returns true if the bag and slot is a valid inventory position, otherwise false + * + *
+     * Possible and most commonly used combinations:
+     *
+     * bag = 255
+     * slots 0-18 equipment
+     * slots 19-22 equipped bag slots
+     * slots 23-38 backpack
+     * slots 39-66 bank main slots
+     * slots 67-74 bank bag slots
+     * slots 86-117 keyring
+     *
+     * bag = 19-22
+     * slots 0-35 for equipped bags
+     *
+     * bag = 67-74
+     * slots 0-35 for bank bags
+     * 
+ * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isInventoryPos + */ + int IsInventoryPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsInventoryPos(bag, slot)); + return 1; + } + + /** + * Returns true if the bag and slot is a valid equipment position, otherwise false + * + *
+     * Possible and most commonly used combinations:
+     *
+     * bag = 255
+     * slots 0-18 equipment
+     * slots 19-22 equipped bag slots
+     * slots 23-38 backpack
+     * slots 39-66 bank main slots
+     * slots 67-74 bank bag slots
+     * slots 86-117 keyring
+     *
+     * bag = 19-22
+     * slots 0-35 for equipped bags
+     *
+     * bag = 67-74
+     * slots 0-35 for bank bags
+     * 
+ * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isEquipmentPosition + */ + int IsEquipmentPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsEquipmentPos(bag, slot)); + return 1; + } + + /** + * Returns true if the bag and slot is a valid bank position, otherwise false + * + *
+     * Possible and most commonly used combinations:
+     *
+     * bag = 255
+     * slots 0-18 equipment
+     * slots 19-22 equipped bag slots
+     * slots 23-38 backpack
+     * slots 39-66 bank main slots
+     * slots 67-74 bank bag slots
+     * slots 86-117 keyring
+     *
+     * bag = 19-22
+     * slots 0-35 for equipped bags
+     *
+     * bag = 67-74
+     * slots 0-35 for bank bags
+     * 
+ * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isBankPosition + */ + int IsBankPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsBankPos(bag, slot)); + return 1; + } + + /** + * Returns true if the bag and slot is a valid bag position, otherwise false + * + *
+     * Possible and most commonly used combinations:
+     *
+     * bag = 255
+     * slots 0-18 equipment
+     * slots 19-22 equipped bag slots
+     * slots 23-38 backpack
+     * slots 39-66 bank main slots
+     * slots 67-74 bank bag slots
+     * slots 86-117 keyring
+     *
+     * bag = 19-22
+     * slots 0-35 for equipped bags
+     *
+     * bag = 67-74
+     * slots 0-35 for bank bags
+     * 
+ * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return bool isBagPosition + */ + int IsBagPos(lua_State* L) + { + uint8 bag = Eluna::CHECKVAL(L, 1); + uint8 slot = Eluna::CHECKVAL(L, 2); + + Eluna::Push(L, Player::IsBagPos((bag << 8) + slot)); + return 1; + } } #endif diff --git a/ItemMethods.h b/ItemMethods.h index 892ff27..58b3ad1 100644 --- a/ItemMethods.h +++ b/ItemMethods.h @@ -145,26 +145,38 @@ namespace LuaItem */ /* GETTERS */ + + /** + * Returns the chat link of the [Item] + * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the [Item]'s name in + * @return string itemLink + */ int GetItemLink(lua_State* L, Item* item) { - // LOCALE_enUS = 0, - // LOCALE_koKR = 1, - // LOCALE_frFR = 2, - // LOCALE_deDE = 3, - // LOCALE_zhCN = 4, - // LOCALE_zhTW = 5, - // LOCALE_esES = 6, - // LOCALE_esMX = 7, - // LOCALE_ruRU = 8 - - int loc_idx = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); - if (loc_idx < 0 || loc_idx >= MAX_LOCALES) + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) return luaL_argerror(L, 2, "valid LocaleConstant expected"); const ItemTemplate* temp = item->GetTemplate(); std::string name = temp->Name1; if (ItemLocale const* il = eObjectMgr->GetItemLocale(temp->ItemId)) - ObjectMgr::GetLocaleString(il->Name, loc_idx, name); + ObjectMgr::GetLocaleString(il->Name, locale, name); #ifndef CLASSIC if (int32 itemRandPropId = item->GetItemRandomPropertyId()) @@ -192,7 +204,7 @@ namespace LuaItem //if (!test.empty()) //{ name += ' '; - name += suffix[(name != temp->Name1) ? loc_idx : DEFAULT_LOCALE]; + name += suffix[(name != temp->Name1) ? locale : DEFAULT_LOCALE]; /*}*/ } } diff --git a/LuaEngine.cpp b/LuaEngine.cpp index 3fff1f3..abad273 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -126,6 +126,8 @@ playerGossipBindings(new EntryBind("GossipEvents (player) lua_getglobal(L, "package"); lua_pushstring(L, lua_requirepath.c_str()); lua_setfield(L, -2, "path"); + lua_pushstring(L, ""); // erase cpath + lua_setfield(L, -2, "cpath"); lua_pop(L, 1); // Replace this with map insert if making multithread version @@ -206,14 +208,27 @@ void Eluna::GetScripts(std::string path) if (boost::filesystem::exists(someDir) && boost::filesystem::is_directory(someDir)) { lua_requirepath += - path + "/?" + - ";" + path + "/?.lua" + - ";" + path + "/?.dll" + ";"; + path + "/?;" + + path + "/?.lua;" + + path + "/?.dll;" + + path + "/?.so;"; for (boost::filesystem::directory_iterator dir_iter(someDir); dir_iter != end_iter; ++dir_iter) { std::string fullpath = dir_iter->path().generic_string(); + // Check if file is hidden +#ifdef WIN32 + DWORD dwAttrib = GetFileAttributes(fullpath.c_str()); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_HIDDEN)) + continue; +#endif +#ifdef UNIX + const char* name = dir_iter->path().filename().generic_string().c_str(); + if (name != ".." || name != "." || name[0] == '.') + continue; +#endif + // load subfolder if (boost::filesystem::is_directory(dir_iter->status())) { @@ -235,9 +250,10 @@ void Eluna::GetScripts(std::string path) return; lua_requirepath += - path + "?" + - ";" + path + "?.lua" + - ";" + path + "?.dll" + ";"; + path + "/?;" + + path + "/?.lua;" + + path + "/?.dll;" + + path + "/?.so;"; ACE_DIRENT *directory = 0; while ((directory = dir.read())) @@ -248,6 +264,18 @@ void Eluna::GetScripts(std::string path) std::string fullpath = path + "/" + directory->d_name; + // Check if file is hidden +#ifdef WIN32 + DWORD dwAttrib = GetFileAttributes(fullpath.c_str()); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_HIDDEN)) + continue; +#endif +#ifdef UNIX + const char* name = directory->d_name.c_str(); + if (name != ".." || name != "." || name[0] == '.') + continue; +#endif + ACE_stat stat_buf; if (ACE_OS::lstat(fullpath.c_str(), &stat_buf) == -1) continue; @@ -282,11 +310,21 @@ void Eluna::RunScripts() scripts.insert(scripts.end(), lua_extensions.begin(), lua_extensions.end()); scripts.insert(scripts.end(), lua_scripts.begin(), lua_scripts.end()); + UNORDERED_MAP loaded; // filename, path + lua_getglobal(L, "package"); luaL_getsubtable(L, -1, "loaded"); int modules = lua_gettop(L); for (ScriptList::const_iterator it = scripts.begin(); it != scripts.end(); ++it) { + // Check that no duplicate names exist + if (loaded.find(it->filename) != loaded.end()) + { + ELUNA_LOG_ERROR("[Eluna]: Error loading `%s`. File with same name already loaded from `%s`, rename either file", it->filepath.c_str(), loaded[it->filename].c_str()); + continue; + } + loaded[it->filename] = it->filepath; + lua_getfield(L, modules, it->filename.c_str()); if (!lua_isnoneornil(L, -1)) { diff --git a/LuaFunctions.cpp b/LuaFunctions.cpp index 4f11036..659ba1e 100644 --- a/LuaFunctions.cpp +++ b/LuaFunctions.cpp @@ -86,6 +86,12 @@ void RegisterGlobals(lua_State* L) lua_register(L, "GetItemLink", &LuaGlobalFunctions::GetItemLink); lua_register(L, "GetMapById", &LuaGlobalFunctions::GetMapById); + // Boolean + lua_register(L, "IsInventoryPos", &LuaGlobalFunctions::IsInventoryPos); + lua_register(L, "IsEquipmentPos", &LuaGlobalFunctions::IsEquipmentPos); + lua_register(L, "IsBankPos", &LuaGlobalFunctions::IsBankPos); + lua_register(L, "IsBagPos", &LuaGlobalFunctions::IsBagPos); + // Other lua_register(L, "ReloadEluna", &LuaGlobalFunctions::ReloadEluna); lua_register(L, "SendWorldMessage", &LuaGlobalFunctions::SendWorldMessage); @@ -189,6 +195,9 @@ ElunaRegister WorldObjectMethods[] = { "GetRelativePoint", &LuaWorldObject::GetRelativePoint }, // :GetRelativePoint(dist, rad) - Returns the x, y and z of a point dist away from worldobject. { "GetAngle", &LuaWorldObject::GetAngle }, // :GetAngle(WorldObject or x, y) - Returns angle between world object and target or x and y coords. + // Boolean + { "IsWithinLoS", &LuaWorldObject::IsWithinLoS }, + // Other { "SummonGameObject", &LuaWorldObject::SummonGameObject }, // :SummonGameObject(entry, x, y, z, o[, respawnDelay]) - Spawns an object to location. Returns the object or nil { "SpawnCreature", &LuaWorldObject::SpawnCreature }, // :SpawnCreature(entry, x, y, z, o[, spawnType, despawnDelay]) - Spawns a creature to location that despawns after given time (0 for infinite). Returns the creature or nil @@ -216,7 +225,8 @@ ElunaRegister UnitMethods[] = { "GetGender", &LuaUnit::GetGender }, // :GetGender() - returns the gender where male = 0 female = 1 { "GetRace", &LuaUnit::GetRace }, // :GetRace() { "GetClass", &LuaUnit::GetClass }, // :GetClass() - { "GetClassAsString", &LuaUnit::GetClassAsString }, // :GetClassAsString() + { "GetRaceAsString", &LuaUnit::GetRaceAsString }, // :GetRaceAsString([locale]) + { "GetClassAsString", &LuaUnit::GetClassAsString }, // :GetClassAsString([locale]) { "GetAura", &LuaUnit::GetAura }, // :GetAura(spellID) - returns aura object { "GetCombatTime", &LuaUnit::GetCombatTime }, // :GetCombatTime() - Returns how long the unit has been in combat { "GetFaction", &LuaUnit::GetFaction }, // :GetFaction() - Returns the unit's factionId @@ -239,6 +249,7 @@ ElunaRegister UnitMethods[] = { "GetControllerGUIDS", &LuaUnit::GetControllerGUIDS }, // :GetControllerGUIDS() - Returns the charmer, owner or unit's own GUID { "GetStandState", &LuaUnit::GetStandState }, // :GetStandState() - Returns the unit's stand state { "GetVictim", &LuaUnit::GetVictim }, // :GetVictim() - Returns creature's current target + { "GetSpeed", &LuaUnit::GetSpeed }, // :GetSpeed(movementType) - Returns the unit's speed { "GetStat", &LuaUnit::GetStat }, // :GetStat(stat) { "GetBaseSpellPower", &LuaUnit::GetBaseSpellPower }, // :GetBaseSpellPower() #if (!defined(TBC) && !defined(CLASSIC)) @@ -324,7 +335,6 @@ ElunaRegister UnitMethods[] = { "IsWithinDistInMap", &LuaUnit::IsWithinDistInMap }, // :IsWithinDistInMap(worldObject, radius) - Returns if the unit is within distance in map of the worldObject { "IsInAccessiblePlaceFor", &LuaUnit::IsInAccessiblePlaceFor }, // :IsInAccessiblePlaceFor(creature) - Returns if the unit is in an accessible place for the specified creature { "IsVendor", &LuaUnit::IsVendor }, // :IsVendor() - Returns if the unit is a vendor or not - { "IsWithinLoS", &LuaUnit::IsWithinLoS }, // :IsWithinLoS(x, y, z) { "IsRooted", &LuaUnit::IsRooted }, // :IsRooted() { "IsFullHealth", &LuaUnit::IsFullHealth }, // :IsFullHealth() - Returns if the unit is full health { "HasAura", &LuaUnit::HasAura }, // :HasAura(spellId) - Returns true if the unit has the aura from the spell @@ -411,7 +421,7 @@ ElunaRegister PlayerMethods[] = { "GetPlayerIP", &LuaPlayer::GetPlayerIP }, // :GetPlayerIP() - Returns the player's IP Address { "GetLevelPlayedTime", &LuaPlayer::GetLevelPlayedTime }, // :GetLevelPlayedTime() - Returns the player's played time at that level { "GetTotalPlayedTime", &LuaPlayer::GetTotalPlayedTime }, // :GetTotalPlayedTime() - Returns the total played time of that player - { "GetItemByPos", &LuaPlayer::GetItemByPos }, // :GetItemByPos(bag, slot) - Returns item in given slot in a bag (bag: 19-22 slot : 0-35) or inventory (bag: -1 slot : 0-38) + { "GetItemByPos", &LuaPlayer::GetItemByPos }, // :GetItemByPos(bag, slot) - Returns item in given slot in a bag (bag: 19-22 slot: 0-35) or inventory (bag: 255 slot : 0-38) { "GetReputation", &LuaPlayer::GetReputation }, // :GetReputation(faction) - Gets player's reputation with given faction { "GetItemByEntry", &LuaPlayer::GetItemByEntry }, // :GetItemByEntry(entry) - Gets an item if the player has it { "GetEquippedItemBySlot", &LuaPlayer::GetEquippedItemBySlot }, // :GetEquippedItemBySlot(slotId) - Returns equipped item by slot @@ -753,6 +763,7 @@ ElunaRegister CreatureMethods[] = { "SetDeathState", &LuaCreature::SetDeathState }, { "SetWalk", &LuaCreature::SetWalk }, { "SetHomePosition", &LuaCreature::SetHomePosition }, + { "SetEquipmentSlots", &LuaCreature::SetEquipmentSlots }, // Booleans { "IsWorldBoss", &LuaCreature::IsWorldBoss }, diff --git a/PlayerMethods.h b/PlayerMethods.h index 01b5267..cc3dd17 100644 --- a/PlayerMethods.h +++ b/PlayerMethods.h @@ -834,15 +834,33 @@ namespace LuaPlayer return 1; } + /** + * Returns an item in given bag on given slot. + * + *
+     * Possible and most commonly used combinations:
+     *
+     * bag = 255
+     * slots 0-18 equipment
+     * slots 19-22 equipped bag slots
+     * slots 23-38 backpack
+     * slots 39-66 bank main slots
+     * slots 67-74 bank bag slots
+     * slots 86-117 keyring
+     *
+     * bag = 19-22
+     * slots 0-35 for equipped bags
+     *
+     * bag = 67-74
+     * slots 0-35 for bank bags
+     * 
+ * + * @param uint8 bag : the bag the [Item] is in, you can get this with [Item:GetBagSlot] + * @param uint8 slot : the slot the [Item] is in within the bag, you can get this with [Item:GetSlot] + * @return [Item] item : [Item] or nil + */ int GetItemByPos(lua_State* L, Player* player) { - /* - bag = -1 for inventory and backpack, 19-22 other bags - slots 0-18 equipment - slots 19-22 bags - slots 23-38 backpack - slots 0-35 other bags - */ uint8 bag = Eluna::CHECKVAL(L, 2); uint8 slot = Eluna::CHECKVAL(L, 3); diff --git a/UnitMethods.h b/UnitMethods.h index 12621bb..8f522c6 100644 --- a/UnitMethods.h +++ b/UnitMethods.h @@ -37,16 +37,6 @@ namespace LuaUnit return 1; } - int IsWithinLoS(lua_State* L, Unit* unit) - { - float x = Eluna::CHECKVAL(L, 2); - float y = Eluna::CHECKVAL(L, 3); - float z = Eluna::CHECKVAL(L, 4); - - Eluna::Push(L, unit->IsWithinLOS(x, y, z)); - return 1; - } - int IsRooted(lua_State* L, Unit* unit) { #ifdef TRINITY @@ -514,11 +504,28 @@ namespace LuaUnit return 1; } + /** + * Returns the currently casted [Spell] of given type or nil + * + *
+     * enum CurrentSpellTypes
+     * {
+     *     CURRENT_MELEE_SPELL             = 0,
+     *     CURRENT_GENERIC_SPELL           = 1,
+     *     CURRENT_CHANNELED_SPELL         = 2,
+     *     CURRENT_AUTOREPEAT_SPELL        = 3
+     * };
+     * 
+ * + * @param [CurrentSpellTypes] spellType + * @return [Spell] castedSpell + */ int GetCurrentSpell(lua_State* L, Unit* unit) { uint32 type = Eluna::CHECKVAL(L, 2); if (type >= CURRENT_MAX_SPELL) return luaL_argerror(L, 2, "valid CurrentSpellTypes expected"); + Eluna::Push(L, unit->GetCurrentSpell(type)); return 1; } @@ -651,47 +658,73 @@ namespace LuaUnit return 1; } + /** + * Returns the [Unit]'s class' name in given or default locale or nil. + * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * + * @param [LocaleConstant] locale = DEFAULT_LOCALE + * @return string className : class name or nil + */ int GetClassAsString(lua_State* L, Unit* unit) { - const char* str = NULL; - switch (unit->getClass()) - { - case 1: - str = "Warrior"; - break; - case 2: - str = "Paladin"; - break; - case 3: - str = "Hunter"; - break; - case 4: - str = "Rogue"; - break; - case 5: - str = "Priest"; - break; - case 6: - str = "Death Knight"; - break; - case 7: - str = "Shaman"; - break; - case 8: - str = "Mage"; - break; - case 9: - str = "Warlock"; - break; - case 11: - str = "Druid"; - break; - default: - str = NULL; - break; - } + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); - Eluna::Push(L, str); + const ChrClassesEntry* entry = sChrClassesStore.LookupEntry(unit->getClass()); + if (!entry) + return 1; + + Eluna::Push(L, entry->name[locale]); + return 1; + } + + /** + * Returns the [Unit]'s race's name in given or default locale or nil. + * + *
+     * enum LocaleConstant
+     * {
+     *     LOCALE_enUS = 0,
+     *     LOCALE_koKR = 1,
+     *     LOCALE_frFR = 2,
+     *     LOCALE_deDE = 3,
+     *     LOCALE_zhCN = 4,
+     *     LOCALE_zhTW = 5,
+     *     LOCALE_esES = 6,
+     *     LOCALE_esMX = 7,
+     *     LOCALE_ruRU = 8
+     * };
+     * 
+ * + * @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the race name in + * @return string raceName : race name or nil + */ + int GetRaceAsString(lua_State* L, Unit* unit) + { + uint8 locale = Eluna::CHECKVAL(L, 2, DEFAULT_LOCALE); + if (locale >= TOTAL_LOCALES) + return luaL_argerror(L, 2, "valid LocaleConstant expected"); + + const ChrRacesEntry* entry = sChrRacesStore.LookupEntry(unit->getRace()); + if (!entry) + return 1; + + Eluna::Push(L, entry->name[locale]); return 1; } @@ -812,6 +845,41 @@ namespace LuaUnit } #endif + /** + * Returns the [Unit]'s speed of given [UnitMoveType]. + * + *
+     * enum UnitMoveType
+     * {
+     *     MOVE_WALK           = 0,
+     *     MOVE_RUN            = 1,
+     *     MOVE_RUN_BACK       = 2,
+     *     MOVE_SWIM           = 3,
+     *     MOVE_SWIM_BACK      = 4,
+     *     MOVE_TURN_RATE      = 5,
+     *     MOVE_FLIGHT         = 6,
+     *     MOVE_FLIGHT_BACK    = 7,
+     *     MOVE_PITCH_RATE     = 8
+     * };
+     * 
+ * + * @param [UnitMoveType] type + * @return float speed + */ + int GetSpeed(lua_State* L, Unit* unit) + { + uint32 type = Eluna::CHECKVAL(L, 2); + if (type >= MAX_MOVE_TYPE) + return luaL_argerror(L, 2, "valid UnitMoveType expected"); + +#ifndef TRINITY + Eluna::Push(L, unit->GetSpeedRate((UnitMoveType)type)); +#else + Eluna::Push(L, unit->GetSpeed((UnitMoveType)type)); +#endif + return 1; + } + /* SETTERS */ int SetOwnerGUID(lua_State* L, Unit* unit) { @@ -851,6 +919,29 @@ namespace LuaUnit return 0; } + /** + * Sets the [Unit]'s speed of given [UnitMoveType] to given rate. + * If forced, packets sent to clients forcing the visual change. + * + *
+     * enum UnitMoveType
+     * {
+     *     MOVE_WALK           = 0,
+     *     MOVE_RUN            = 1,
+     *     MOVE_RUN_BACK       = 2,
+     *     MOVE_SWIM           = 3,
+     *     MOVE_SWIM_BACK      = 4,
+     *     MOVE_TURN_RATE      = 5,
+     *     MOVE_FLIGHT         = 6,
+     *     MOVE_FLIGHT_BACK    = 7,
+     *     MOVE_PITCH_RATE     = 8
+     * };
+     * 
+ * + * @param [UnitMoveType] type + * @param float rate + * @param bool forced = false + */ int SetSpeed(lua_State* L, Unit* unit) { uint32 type = Eluna::CHECKVAL(L, 2); @@ -1569,16 +1660,100 @@ namespace LuaUnit return 1; } + /** + * Makes the [Unit] damage the target [Unit] + * + *
+     * enum SpellSchools
+     * {
+     *     SPELL_SCHOOL_NORMAL  = 0,
+     *     SPELL_SCHOOL_HOLY    = 1,
+     *     SPELL_SCHOOL_FIRE    = 2,
+     *     SPELL_SCHOOL_NATURE  = 3,
+     *     SPELL_SCHOOL_FROST   = 4,
+     *     SPELL_SCHOOL_SHADOW  = 5,
+     *     SPELL_SCHOOL_ARCANE  = 6,
+     *     MAX_SPELL_SCHOOL     = 7
+     * };
+     * 
+ * + * @param [Unit] target : [Unit] to damage + * @param uint32 damage : amount to damage + * @param bool durabilityloss = true : if false, the damage does not do durability damage + * @param [SpellSchools] school = MAX_SPELL_SCHOOL : school the damage is done in or MAX_SPELL_SCHOOL for direct damage + * @param uint32 spell = 0 : spell that inflicts the damage + */ int DealDamage(lua_State* L, Unit* unit) { Unit* target = Eluna::CHECKOBJ(L, 2); - uint32 amount = Eluna::CHECKVAL(L, 3); + uint32 damage = Eluna::CHECKVAL(L, 3); bool durabilityloss = Eluna::CHECKVAL(L, 4, true); + uint32 school = Eluna::CHECKVAL(L, 5, MAX_SPELL_SCHOOL); + uint32 spell = Eluna::CHECKVAL(L, 6, 0); + if (school > MAX_SPELL_SCHOOL) + return luaL_argerror(L, 6, "valid SpellSchool expected"); - unit->DealDamage(target, amount, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, durabilityloss); + // flat melee damage without resistence/etc reduction + if (school == MAX_SPELL_SCHOOL) + { + unit->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, durabilityloss); +#ifdef TRINITY + unit->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); +#else + unit->SendAttackStateUpdate(HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); +#endif + return 0; + } + + SpellSchoolMask schoolmask = SpellSchoolMask(1 << school); + +#ifdef TRINITY + if (Unit::IsDamageReducedByArmor(schoolmask)) + damage = unit->CalcArmorReducedDamage(target, damage, NULL, BASE_ATTACK); +#else + if (schoolmask & SPELL_SCHOOL_MASK_NORMAL) + damage = unit->CalcArmorReducedDamage(target, damage); +#endif + + // melee damage by specific school + if (!spell) + { + uint32 absorb = 0; + uint32 resist = 0; +#ifdef TRINITY + unit->CalcAbsorbResist(target, schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); +#else + target->CalculateDamageAbsorbAndResist(unit, schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); +#endif + + if (damage <= absorb + resist) + damage = 0; + else + damage -= absorb + resist; + + unit->DealDamageMods(target, damage, &absorb); + unit->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); +#ifdef TRINITY + unit->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_HIT, 0); +#else + unit->SendAttackStateUpdate(HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0); +#endif + return 0; + } + + // non-melee damage + unit->SpellNonMeleeDamageLog(target, spell, damage); return 0; } + /** + * Makes the [Unit] heal the target [Unit] with given spell + * + * @param [Unit] target : [Unit] to heal + * @param uint32 spell : spell that causes the healing + * @param uint32 amount : amount to heal + * @param bool critical = false : if true, heal is logged as critical + */ int DealHeal(lua_State* L, Unit* unit) { Unit* target = Eluna::CHECKOBJ(L, 2); @@ -1596,6 +1771,12 @@ namespace LuaUnit return 0; } + /** + * Makes the [Unit] kill the target [Unit] + * + * @param [Unit] target : [Unit] to kill + * @param bool durLoss = true : when true, the target's items suffer durability loss + */ int Kill(lua_State* L, Unit* unit) { Unit* target = Eluna::CHECKOBJ(L, 2); diff --git a/WorldObjectMethods.h b/WorldObjectMethods.h index 0de745f..79544c6 100644 --- a/WorldObjectMethods.h +++ b/WorldObjectMethods.h @@ -658,5 +658,34 @@ namespace LuaWorldObject obj->elunaEvents->RemoveEvents(); return 0; } + + /** + * Returns true if the given [WorldObject] or coordinates are in the [WorldObject]'s line of sight + * + * @proto isInLoS = (worldobject) + * @proto isInLoS = (x, y, z) + * + * @param [WorldObject] worldobject + * @param float x + * @param float y + * @param float z + * @return bool isInLoS + */ + int IsWithinLoS(lua_State* L, WorldObject* obj) + { + WorldObject* target = Eluna::CHECKOBJ(L, 2, false); + + if (target) + Eluna::Push(L, obj->IsWithinLOSInMap(target)); + else + { + float x = Eluna::CHECKVAL(L, 2); + float y = Eluna::CHECKVAL(L, 3); + float z = Eluna::CHECKVAL(L, 4); + Eluna::Push(L, obj->IsWithinLOS(x, y, z)); + } + + return 1; + } }; #endif diff --git a/docs/DOC_GEN.md b/docs/DOC_GEN.md index 8cebe06..bfedec3 100644 --- a/docs/DOC_GEN.md +++ b/docs/DOC_GEN.md @@ -110,3 +110,25 @@ codeblock *italic* **bold** + +###Types +Here are some examples of possible types and most commonly used ones +``` +string +uint32 +uint16 +uint8 +int32 +int16 +int8 +double +float +[EnumName] +[Player] +[Creature] +[GameObject] +[Item] +[Unit] +[WorldObject] +[Object] +```