diff --git a/src/ElunaLuaEngine_SC.cpp b/src/ElunaLuaEngine_SC.cpp index 301607b..cd8e2d6 100644 --- a/src/ElunaLuaEngine_SC.cpp +++ b/src/ElunaLuaEngine_SC.cpp @@ -807,6 +807,11 @@ public: { sEluna->OnBattlegroundDesertion(player, type); } + + void OnCreatureKilledByPet(Player* player, Creature* killed) override + { + sEluna->OnCreatureKilledByPet(player, killed); + } }; class Eluna_ServerScript : public ServerScript diff --git a/src/LuaEngine/Hooks.h b/src/LuaEngine/Hooks.h index f368317..a5fd28b 100644 --- a/src/LuaEngine/Hooks.h +++ b/src/LuaEngine/Hooks.h @@ -219,6 +219,7 @@ namespace Hooks PLAYER_EVENT_ON_CAN_GROUP_INVITE = 55, // (event, player, memberName) - Can return false to prevent inviting PLAYER_EVENT_ON_GROUP_ROLL_REWARD_ITEM = 56, // (event, player, item, count, voteType, roll) PLAYER_EVENT_ON_BG_DESERTION = 57, // (event, player, type) + PLAYER_EVENT_ON_PET_KILL = 58, // (event, player, killer) PLAYER_EVENT_COUNT }; diff --git a/src/LuaEngine/LuaEngine.h b/src/LuaEngine/LuaEngine.h index 6955356..af0a5d5 100644 --- a/src/LuaEngine/LuaEngine.h +++ b/src/LuaEngine/LuaEngine.h @@ -490,6 +490,7 @@ public: bool OnCanGroupInvite(Player* player, std::string& memberName); void OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll); void OnBattlegroundDesertion(Player* player, const BattlegroundDesertionType type); + void OnCreatureKilledByPet(Player* player, Creature* killed); #ifndef CLASSIC #ifndef TBC diff --git a/src/LuaEngine/LuaFunctions.cpp b/src/LuaEngine/LuaFunctions.cpp index ec34249..a2ecfc0 100644 --- a/src/LuaEngine/LuaFunctions.cpp +++ b/src/LuaEngine/LuaFunctions.cpp @@ -353,6 +353,7 @@ ElunaRegister UnitMethods[] = { "SetStandState", &LuaUnit::SetStandState }, { "SetInCombatWith", &LuaUnit::SetInCombatWith }, { "ModifyPower", &LuaUnit::ModifyPower }, + { "SetImmuneTo", &LuaUnit::SetImmuneTo }, // Boolean { "IsAlive", &LuaUnit::IsAlive }, @@ -401,6 +402,7 @@ ElunaRegister UnitMethods[] = #endif // Other + { "HandleStatModifier", &LuaUnit::HandleStatModifier }, { "AddAura", &LuaUnit::AddAura }, { "RemoveAura", &LuaUnit::RemoveAura }, { "RemoveAllAuras", &LuaUnit::RemoveAllAuras }, @@ -472,6 +474,7 @@ ElunaRegister PlayerMethods[] = { "GetGuild", &LuaPlayer::GetGuild }, { "GetAccountId", &LuaPlayer::GetAccountId }, { "GetAccountName", &LuaPlayer::GetAccountName }, + { "GetCompletedQuestsCount", &LuaPlayer::GetCompletedQuestsCount }, #if defined (TBC) || defined (WOTLK) { "GetArenaPoints", &LuaPlayer::GetArenaPoints }, { "GetHonorPoints", &LuaPlayer::GetHonorPoints }, @@ -492,6 +495,8 @@ ElunaRegister PlayerMethods[] = { "GetRestBonus", &LuaPlayer::GetRestBonus }, #ifdef WOTLK { "GetPhaseMaskForSpawn", &LuaPlayer::GetPhaseMaskForSpawn }, + { "GetAchievementPoints", &LuaPlayer::GetAchievementPoints }, + { "GetCompletedAchievementsCount", &LuaPlayer::GetCompletedAchievementsCount }, #endif { "GetReqKillOrCastCurrentCount", &LuaPlayer::GetReqKillOrCastCurrentCount }, { "GetQuestStatus", &LuaPlayer::GetQuestStatus }, @@ -568,6 +573,7 @@ ElunaRegister PlayerMethods[] = { "SetRankPoints", &LuaPlayer::SetRankPoints }, { "SetHonorLastWeekStandingPos", &LuaPlayer::SetHonorLastWeekStandingPos }, #endif + { "SetSpellPower", &LuaPlayer::SetSpellPower }, { "SetLifetimeKills", &LuaPlayer::SetLifetimeKills }, { "SetGameMaster", &LuaPlayer::SetGameMaster }, { "SetGMChat", &LuaPlayer::SetGMChat }, @@ -593,6 +599,10 @@ ElunaRegister PlayerMethods[] = #endif // Boolean + { "HasTankSpec", &LuaPlayer::HasTankSpec }, + { "HasMeleeSpec", &LuaPlayer::HasMeleeSpec }, + { "HasCasterSpec", &LuaPlayer::HasCasterSpec }, + { "HasHealSpec", &LuaPlayer::HasHealSpec }, { "IsInGroup", &LuaPlayer::IsInGroup }, { "IsInGuild", &LuaPlayer::IsInGuild }, { "IsGM", &LuaPlayer::IsGM }, @@ -1102,6 +1112,7 @@ ElunaRegister SpellMethods[] = { "GetEntry", &LuaSpell::GetEntry }, { "GetDuration", &LuaSpell::GetDuration }, { "GetPowerCost", &LuaSpell::GetPowerCost }, + { "GetReagentCost", &LuaSpell::GetReagentCost }, { "GetTargetDest", &LuaSpell::GetTargetDest }, { "GetTarget", &LuaSpell::GetTarget }, diff --git a/src/LuaEngine/PlayerHooks.cpp b/src/LuaEngine/PlayerHooks.cpp index 6d30434..e437a2a 100644 --- a/src/LuaEngine/PlayerHooks.cpp +++ b/src/LuaEngine/PlayerHooks.cpp @@ -698,3 +698,11 @@ void Eluna::OnBattlegroundDesertion(Player* player, const BattlegroundDesertionT Push(type); CallAllFunctions(PlayerEventBindings, key); } + +void Eluna::OnCreatureKilledByPet(Player* player, Creature* killed) +{ + START_HOOK(PLAYER_EVENT_ON_PET_KILL); + Push(player); + Push(killed); + CallAllFunctions(PlayerEventBindings, key); +} diff --git a/src/LuaEngine/PlayerMethods.h b/src/LuaEngine/PlayerMethods.h index c7737c6..b6684f4 100644 --- a/src/LuaEngine/PlayerMethods.h +++ b/src/LuaEngine/PlayerMethods.h @@ -405,6 +405,50 @@ namespace LuaPlayer } #endif + /** + * Returns `true` if the [Player] has a Tank Specialization, `false` otherwise. + * + * @return bool HasTankSpec + */ + int HasTankSpec(lua_State* L, Player* player) + { + Eluna::Push(L, player->HasTankSpec()); + return 1; + } + + /** + * Returns `true` if the [Player] has a Melee Specialization, `false` otherwise. + * + * @return bool HasMeleeSpec + */ + int HasMeleeSpec(lua_State* L, Player* player) + { + Eluna::Push(L, player->HasMeleeSpec()); + return 1; + } + + /** + * Returns `true` if the [Player] has a Caster Specialization, `false` otherwise. + * + * @return bool HasCasterSpec + */ + int HasCasterSpec(lua_State* L, Player* player) + { + Eluna::Push(L, player->HasCasterSpec()); + return 1; + } + + /** + * Returns `true` if the [Player] has a Heal Specialization, `false` otherwise. + * + * @return bool HasHealSpec + */ + int HasHealSpec(lua_State* L, Player* player) + { + Eluna::Push(L, player->HasHealSpec()); + return 1; + } + /** * Returns `true` if the [Player] is in a [Group], `false` otherwise. * @@ -859,6 +903,51 @@ namespace LuaPlayer Eluna::Push(L, player->GetPhaseMaskForSpawn()); return 1; } + + /** + * Returns the [Player]s current amount of Achievement Points + * + * @return uint32 achievementPoints + */ + int GetAchievementPoints(lua_State* L, Player* player) + { + uint32 count = 0; + const CompletedAchievementMap& completedAchievements = player->GetAchievementMgr()->GetCompletedAchievements(); + for (auto& pair : completedAchievements) + { + AchievementEntry const* achievement = sAchievementStore.LookupEntry(pair.first); + if (achievement) + { + count += achievement->points; + } + } + + Eluna::Push(L, count); + return 1; + } + + /** + * Returns the [Player]s current amount of Achievements Completed + * + * @return uint32 achievementsCount + */ + int GetCompletedAchievementsCount(lua_State* L, Player* player) + { + uint32 count = 0; + bool countFeatsOfStrength = Eluna::CHECKVAL(L, 2, false); + const CompletedAchievementMap& completedAchievements = player->GetAchievementMgr()->GetCompletedAchievements(); + for (auto& pair : completedAchievements) + { + AchievementEntry const* achievement = sAchievementStore.LookupEntry(pair.first); + if (achievement && (achievement->categoryId != 81 || countFeatsOfStrength)) + { + count++; + } + } + + Eluna::Push(L, count); + return 1; + } #endif #if defined(TBC) || defined (WOTLK) @@ -1687,6 +1776,19 @@ namespace LuaPlayer return 1; } + /** + * Returns the [Player]s completed quest count + * + * @return int32 questcount + */ + int GetCompletedQuestsCount(lua_State* L, Player* player) + { + uint32 count = player->GetRewardedQuestCount(); + + Eluna::Push(L, count); + return 1; + } + /** * Returns the [Player]s [Corpse] object * @@ -4267,6 +4369,21 @@ namespace LuaPlayer return 1; } + /** + * The [Player] sets the spell power + * + * @param int value : The spell power value to set + * @param bool apply = false : Whether the spell power should be applied or removed + */ + int SetSpellPower(lua_State* L, Player* player) + { + int value = Eluna::CHECKVAL(L, 2); + bool apply = Eluna::CHECKVAL(L, 3, false); + + player->ApplySpellPowerBonus(value, apply); + return 0; + } + /*int BindToInstance(lua_State* L, Player* player) { player->BindToInstance(); diff --git a/src/LuaEngine/SpellMethods.h b/src/LuaEngine/SpellMethods.h index 2036c00..3c5d025 100644 --- a/src/LuaEngine/SpellMethods.h +++ b/src/LuaEngine/SpellMethods.h @@ -69,6 +69,30 @@ namespace LuaSpell return 1; } + /** + * Returns the reagents needed for the [Spell]. + * + * @return table reagents : a table containing the [ItemTemplate]s and amount of reagents needed for the [Spell] + */ + int GetReagentCost(lua_State* L, Spell* spell) + { + auto spellInfo = spell->GetSpellInfo(); + auto reagents = spellInfo->Reagent; + auto reagentCounts = spellInfo->ReagentCount; + lua_newtable(L); + for (auto i = 0; i < MAX_SPELL_REAGENTS; ++i) + { + if (reagents[i] <= 0) + continue; + auto reagent = eObjectMgr->GetItemTemplate(reagents[i]); + auto count = reagentCounts[i]; + Eluna::Push(L, reagent); + Eluna::Push(L, count); + lua_settable(L, -3); + } + return 1; + } + /** * Returns the spell duration of the [Spell]. * diff --git a/src/LuaEngine/UnitMethods.h b/src/LuaEngine/UnitMethods.h index 50e467b..38c948a 100644 --- a/src/LuaEngine/UnitMethods.h +++ b/src/LuaEngine/UnitMethods.h @@ -12,6 +12,77 @@ */ namespace LuaUnit { + /** + * Sets a mechanic immunity for the [Unit]. + * + *
+    *   MECHANIC_NONE             = 0,
+    *   MECHANIC_CHARM            = 1,
+    *   MECHANIC_DISORIENTED      = 2,
+    *   MECHANIC_DISARM           = 3,
+    *   MECHANIC_DISTRACT         = 4,
+    *   MECHANIC_FEAR             = 5,
+    *   MECHANIC_GRIP             = 6,
+    *   MECHANIC_ROOT             = 7,
+    *   MECHANIC_SLOW_ATTACK      = 8,
+    *   MECHANIC_SILENCE          = 9,
+    *   MECHANIC_SLEEP            = 10,
+    *   MECHANIC_SNARE            = 11,
+    *   MECHANIC_STUN             = 12,
+    *   MECHANIC_FREEZE           = 13,
+    *   MECHANIC_KNOCKOUT         = 14,
+    *   MECHANIC_BLEED            = 15,
+    *   MECHANIC_BANDAGE          = 16,
+    *   MECHANIC_POLYMORPH        = 17,
+    *   MECHANIC_BANISH           = 18,
+    *   MECHANIC_SHIELD           = 19,
+    *   MECHANIC_SHACKLE          = 20,
+    *   MECHANIC_MOUNT            = 21,
+    *   MECHANIC_INFECTED         = 22,
+    *   MECHANIC_TURN             = 23,
+    *   MECHANIC_HORROR           = 24,
+    *   MECHANIC_INVULNERABILITY  = 25,
+    *   MECHANIC_INTERRUPT        = 26,
+    *   MECHANIC_DAZE             = 27,
+    *   MECHANIC_DISCOVERY        = 28,
+    *   MECHANIC_IMMUNE_SHIELD    = 29,     // Divine (Blessing) Shield/Protection and Ice Block
+    *   MECHANIC_SAPPED           = 30,
+    *   MECHANIC_ENRAGED          = 31
+    * 
+ * + * @param int32 immunity : new value for the immunity mask + * @param bool apply = true : if true, the immunity is applied, otherwise it is removed + */ + int SetImmuneTo(lua_State* L, Unit* unit) + { + int32 immunity = Eluna::CHECKVAL(L, 2); + bool apply = Eluna::CHECKVAL(L, 3, true); + + unit->ApplySpellImmune(0, 5, immunity, apply); + return 0; + } + + /** + * The [Unit] modifies a specific stat + * + * @param int32 stat : The stat to modify + * @param int8 type : The type of modifier to apply + * @param float value : The value to apply to the stat + * @param bool apply = false : Whether the modifier should be applied or removed + * @return bool : Whether the stat modification was successful + */ + int HandleStatModifier(lua_State* L, Unit* unit) + { + int32 stat = Eluna::CHECKVAL(L, 2); + int8 type = Eluna::CHECKVAL(L, 3); + + float value = Eluna::CHECKVAL(L, 4); + bool apply = Eluna::CHECKVAL(L, 5, false); + + Eluna::Push(L, unit->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + stat), (UnitModifierType)type, value, apply)); + return 1; + } + /** * The [Unit] tries to attack a given target * @@ -1696,7 +1767,7 @@ namespace LuaUnit unit->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); for (Unit::ControlSet::iterator itr = unit->m_Controlled.begin(); itr != unit->m_Controlled.end(); ++itr) (*itr)->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - } + } else { unit->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); @@ -2293,20 +2364,20 @@ namespace LuaUnit bool delayed = Eluna::CHECKVAL(L, 3, true); switch (spellType) { - case 0: - spellType = CURRENT_MELEE_SPELL; - break; - case 1: - spellType = CURRENT_GENERIC_SPELL; - break; - case 2: - spellType = CURRENT_CHANNELED_SPELL; - break; - case 3: - spellType = CURRENT_AUTOREPEAT_SPELL; - break; - default: - return luaL_argerror(L, 2, "valid CurrentSpellTypes expected"); + case 0: + spellType = CURRENT_MELEE_SPELL; + break; + case 1: + spellType = CURRENT_GENERIC_SPELL; + break; + case 2: + spellType = CURRENT_CHANNELED_SPELL; + break; + case 3: + spellType = CURRENT_AUTOREPEAT_SPELL; + break; + default: + return luaL_argerror(L, 2, "valid CurrentSpellTypes expected"); } unit->InterruptSpell((CurrentSpellTypes)spellType, delayed); @@ -2564,12 +2635,12 @@ namespace LuaUnit return 0; } - /** - * Modifies threat in pct to the [Unit] from the victim - * - * @param [Unit] victim : [Unit] that caused the threat - * @param int32 percent : threat amount in pct - */ + /** + * Modifies threat in pct to the [Unit] from the victim + * + * @param [Unit] victim : [Unit] that caused the threat + * @param int32 percent : threat amount in pct + */ int ModifyThreatPct(lua_State* L, Unit* unit) { Unit* victim = Eluna::CHECKOBJ(L, 2);