/* /\/\ __ _ _ __ __ _ ___ / _\ ___ _ __(_)_ __ | |_ * / \ / _` | '_ \ / _` |/ _ \\ \ / __| '__| | '_ \| __| * / /\/\ \ (_| | | | | (_| | (_) |\ \ (__| | | | |_) | |_ * \/ \/\__,_|_| |_|\__, |\___/\__/\___|_| |_| .__/ \__| * |___/ |_| * A WHOLE NEW WORLD * MangoScript - Bringing a whole new world to MaNGOS * * Lua_Creature.cpp - Exports Creature related functions to LUA * * (c) Copyright 2006-2007 by the MangoScript Team * * 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; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; 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 * * $Id: Lua_Creature.cpp 136 2007-02-26 01:51:38Z andrejkw $ */ #include "luainc.h" #include "Lua_Creature.h" #include "WorldPacket.h" #include "Player.h" #include "Creature.h" #include "GossipDef.h" #include "SpellAuras.h" #include "DynamicObject.h" #include "Lua_uint64.h" #include "Lua_AI.h" #include "ObjectMgr.h" #include "MapManager.h" #include "Chat.h" #include "CppScriptMgr.h" const char* lb_Creature_GetScriptName(Creature* m_creature) { return m_creature->GetCreatureInfo()->ScriptName; } uint32 lb_Creature_QUEST_DIALOG_STATUS(Creature* m_creature, Player *pPlayer, uint32 defstatus) { return m_creature->getDialogStatus(pPlayer, defstatus); } void lb_Creature_MonsterSay(Creature* m_creature, char const *text, uint32 language) { m_creature->MonsterSay(text, language, m_creature->GetGUID()); } LuaAI_Proxy* lb_Creature_GetLuaAI(Creature* m_creature) { debug_log("lb_Creature_GetLuaAI"); if (isRegistered_LuaAI(m_creature)) return ((LuaAI*)&m_creature->AI())->m_proxy; error_log("[Lua] : AI : WARNING : Trying to get LuaAI of creature that doesn't have such"); return NULL; } void lb_Creature_reachWithSpellAttack(Creature* cr , Unit* target ) { if(!target) return; const SpellEntry* spellinfo = cr->reachWithSpellAttack(target); if (spellinfo) cr->CastSpell(target, spellinfo, true); } void lb_Ressurect(Creature* m_creature, bool goToRespawn) { if (!m_creature || m_creature->isAlive() || !m_creature->IsInWorld()) return; CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(m_creature->GetEntry()); switch (m_creature->getDeathState()) { case DEAD: { DEBUG_LOG("Respawning..."); m_creature->SelectLevel(cinfo); m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); m_creature->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); m_creature->SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); m_creature->SetHealth(m_creature->GetMaxHealth()); m_creature->setDeathState( ALIVE ); m_creature->clearUnitState(UNIT_STAT_ALL_STATE); (*m_creature)->Clear(); MapManager::Instance().GetMap(m_creature->GetMapId())->Add(m_creature); /*WE ARE AWREADY MOVED TO RESS PLACE ... SO goToRespawn IS USELESS FOR HERE*/ } break; case CORPSE: { ObjectAccessor::Instance().RemoveCreatureCorpseFromPlayerView(m_creature); m_creature->loot.clear(); m_creature->setDeathState(DEAD); m_creature->SelectLevel(cinfo); m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); m_creature->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); m_creature->SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); m_creature->SetHealth(m_creature->GetMaxHealth()); m_creature->setDeathState(ALIVE); m_creature->clearUnitState(UNIT_STAT_ALL_STATE); if (goToRespawn) { float x, y, z; m_creature->GetRespawnCoord(x, y, z); MapManager::Instance().GetMap(m_creature->GetMapId())->CreatureRelocation(m_creature, x, y, z, m_creature->GetOrientation()); } } break; default: break; } } void lb_Creature_MoveTo(Creature* m_creature, const float& X, const float& Y, const float& Z, bool Run, const uint32& Time) { float dx = X - m_creature->GetPositionX(); float dy = Y - m_creature->GetPositionY(); float orientation = (float)atan2((double)dy, (double)dx); m_creature->SendMoveToPacket(X, Y, Z, Run, Time); MapManager::Instance().GetMap(m_creature->GetMapId())->CreatureRelocation(m_creature, X, Y, Z, orientation); } bool lb_Creature_DoCast(Creature* m_creature, Unit* Victim, uint32 spellId) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) { sLog.outError("WORLD: unknown spell id %i\n", spellId); return false; } //No triggered spells for now Spell *spell = new Spell(m_creature, spellInfo, false, 0); WPAssert(spell); SpellCastTargets targets; targets.setUnitTarget(Victim); spell->m_CastItem = NULL; uint8 castresult = spell->CanCast(); spell->prepare(&targets); m_creature->m_canMove = false; return (castresult == 0); } void lb_Creature_DoYell(Creature* m_creature, char const* text, uint32 language, Unit* target) { WorldPacket data(30 + strlen(text) + strlen(m_creature->GetCreatureInfo()->Name) + 2);//30 bytes + text size + name size + 2(nulls at end of string) data.SetOpcode(SMSG_MESSAGECHAT); data << (uint8)CHAT_MSG_MONSTER_YELL; data << language; data << (uint64)m_creature->GetGUID(); data << (uint32)(strlen(m_creature->GetCreatureInfo()->Name) + 1); data << m_creature->GetCreatureInfo()->Name; if (target) data << uint64(target->GetGUID()); else data << uint64(m_creature->GetGUID()); data << uint32(strlen(text)+1); data << text; data << uint8(0); m_creature->SendMessageToSet(&data, false); } SpellEntry const* lb_Creature_SelectSpell(Creature* m_creature, Unit* Target, uint32 School, uint32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) { //No target so we can't cast if (!Target) return false; //Silenced so we can't cast if (m_creature->m_silenced) return false; //Using the extended script system we first create a list of viable spells SpellEntry const* Spell[4]; Spell[0] = 0; Spell[1] = 0; Spell[2] = 0; Spell[3] = 0; uint32 SpellCount = 0; SpellEntry const* TempSpell; SpellRangeEntry const* TempRange; //Check if each spell is viable(set it to null if not) for (uint32 i = 0; i < 4; i++) { TempSpell = sSpellStore.LookupEntry(m_creature->m_spells[i]); //This spell doesn't exist if (!TempSpell) continue; //Check for school if specified if (School && TempSpell->School != School) continue; //Check for spell mechanic if specified if (Mechanic && TempSpell->Mechanic != Mechanic) continue; //Check the spell targets if specified if (Targets) { bool bSkipThisSpell = true; switch (Targets) { //Spell targets self case SELECT_TARGET_SELF: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_SELF) bSkipThisSpell = false; break; //Spell targets a single enemy case SELECT_TARGET_SINGLE_ENEMY: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_ENEMY || TempSpell->EffectImplicitTargetA[i] == TARGET_CURRENT_SELECTED_ENEMY) bSkipThisSpell = false; break; //Spell targets AoE at enemy case SELECT_TARGET_AOE_ENEMY: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMIES_AROUND_CASTER || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) bSkipThisSpell = false; break; //Spell targets an enemy case SELECT_TARGET_ANY_ENEMY: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_ENEMY || TempSpell->EffectImplicitTargetA[i] == TARGET_CURRENT_SELECTED_ENEMY || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMIES_AROUND_CASTER || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) bSkipThisSpell = false; break; //Spell targets a single friend(or self) case SELECT_TARGET_SINGLE_FRIEND: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_SELF || TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND || TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_PARTY || TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND_2) bSkipThisSpell = false; break; //Spell targets aoe friends case SELECT_TARGET_AOE_FRIEND: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_PARTY_AROUND_CASTER || TempSpell->EffectImplicitTargetA[i] == TARGET_AREAEFFECT_PARTY) bSkipThisSpell = false; break; //Spell targets any friend(or self) case SELECT_TARGET_ANY_FRIEND: for (uint32 i = 0; i < 3; i++) if (TempSpell->EffectImplicitTargetA[i] == TARGET_SELF || TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND || TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_PARTY || TempSpell->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND_2 || TempSpell->EffectImplicitTargetA[i] == TARGET_ALL_PARTY_AROUND_CASTER || TempSpell->EffectImplicitTargetA[i] == TARGET_AREAEFFECT_PARTY) bSkipThisSpell = false; break; } if (bSkipThisSpell) continue; } //Make sure that the spell uses the requested amount of power if (PowerCostMin) if (TempSpell->manaCost < PowerCostMin) continue; if (PowerCostMax) if (TempSpell->manaCost > PowerCostMax) continue; //Continue if we don't have the mana to actually cast this spell if (TempSpell->manaCost > m_creature->GetPower((Powers)TempSpell->powerType)) continue; //Get the Range TempRange = sSpellRangeStore.LookupEntry(TempSpell->rangeIndex); //Spell has invalid range store so we can't use it if (!TempRange) continue; //Check if the spell meets our range requirements if (RangeMin) if (TempRange->maxRange < RangeMin) continue; if (RangeMax) if (TempRange->maxRange > RangeMax) continue; //Check if our target is in range if (m_creature->GetDistanceSq(Target) < TempRange->minRange * TempRange->minRange || m_creature->GetDistanceSq(Target) > TempRange->maxRange * TempRange->maxRange) continue; //Check the type of spell if we are looking for a specific spell type if (Effects) { bool bSkipThisSpell = true; switch (Effects) { //Make sure that this spell includes a damage effect case SELECT_EFFECT_DAMAGE: for (uint32 j = 0; j < 3; j++) if (TempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || TempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || TempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || TempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH) bSkipThisSpell = false; break; //Make sure that this spell includes a healing effect case SELECT_EFFECT_HEALING: for (uint32 j = 0; j < 3; j++) if (TempSpell->Effect[j] == SPELL_EFFECT_HEAL || TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || TempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL) bSkipThisSpell = false; break; //Make sure that this spell applies an aura case SELECT_EFFECT_AURA: for (uint32 j = 0; j < 3; j++) if (TempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA) bSkipThisSpell = false; break; default: bSkipThisSpell = false; break; } if (bSkipThisSpell) continue; } //All good so lets add it to the spell list Spell[SpellCount] = TempSpell; SpellCount++; } //We got our usable spells so now lets randomly pick one if (!SpellCount) return NULL; return Spell[rand()%SpellCount]; } int lb_Export_Creature(lua_State* L) { using namespace luabind; module(L) [ def("Ressurect", lb_Ressurect) ]; module(L) [ class_("Creature") .def("GetLuaAI", &lb_Creature_GetLuaAI) .def("DoYell", &lb_Creature_DoYell) .def("DoCast", &lb_Creature_DoCast) .def("MoveTo", &lb_Creature_MoveTo) .def("SelectSpell", &lb_Creature_SelectSpell) .def("reachWithSpellAttack", &lb_Creature_reachWithSpellAttack) .def("GetScriptName", &lb_Creature_GetScriptName) .def("QUEST_DIALOG_STATUS", &lb_Creature_QUEST_DIALOG_STATUS) /* from Creature.h */ .def("isPet", &Creature::isPet) .def("isTotem", &Creature::isTotem) .def("isCivilian", &Creature::isCivilian) .def("isCanSwimOrFly", &Creature::isCanSwimOrFly) .def("isCanWalkOrFly", &Creature::isCanWalkOrFly) .def("isCanTrainingOf", &Creature::isCanTrainingOf) .def("isCanTrainingAndResetTalentsOf", &Creature::isCanTrainingAndResetTalentsOf) .def("isElite", &Creature::isElite) .def("GetOwner", &Creature::GetOwner) /*.def("setMoveRandomFlag", &Creature::setMoveRandomFlag)*/ .def("setMoveRunFlag", &Creature::setMoveRunFlag) /*.def("getMoveRandomFlag", &Creature::getMoveRandomFlag)*/ .def("getMoveRunFlag", &Creature::getMoveRunFlag) .def("IsStopped", &Creature::IsStopped) .def("StopMoving", &Creature::StopMoving) .def("GetBlockValue", &Creature::GetBlockValue) .def("GetItemCount", (uint32 (Creature::*)(uint32) const)&Creature::GetItemCount) .def("GetItemCount", (uint8 (Creature::*)(void) const)&Creature::GetItemCount) .def("GetItemId", &Creature::GetItemId) .def("GetMaxItemCount", &Creature::GetMaxItemCount) .def("GetItemIncrTime", &Creature::GetItemIncrTime) .def("GetItemLastIncr", &Creature::GetItemLastIncr) .def("SetItemCount", &Creature::SetItemCount) .def("SetItemLastIncr", &Creature::SetItemLastIncr) .def("AddItem", &Creature::AddItem) .def("GetTrainerSpellsSize", &Creature::GetTrainerSpellsSize) .def("getDialogStatus", &Creature::getDialogStatus) .def("prepareGossipMenu", &Creature::prepareGossipMenu) .def("sendPreparedGossip", &Creature::sendPreparedGossip) .def("OnGossipSelect", &Creature::OnGossipSelect) .def("OnPoiSelect", &Creature::OnPoiSelect) .def("GetGossipTextId", &Creature::GetGossipTextId) .def("GetNpcTextId", &Creature::GetNpcTextId) .def("LoadGossipOptions", &Creature::LoadGossipOptions) .def("GetGossipTitle", &Creature::GetGossipTitle) .def("GetGossipCount", &Creature::GetGossipCount) .def("addGossipOption", &Creature::addGossipOption) .def("setEmoteState", &Creature::setEmoteState) .def("setDeathState", &Creature::setDeathState) .def("Say", &Creature::Say) .def("MonsterSay", &lb_Creature_MonsterSay) .def("getloyalty", &Creature::getloyalty) .def("getUsedTrainPoint", &Creature::getUsedTrainPoint) /*.def("GivePetLevel",&Creature::GivePetLevel)*/ .def("GetDefaultMovementType", &Creature::GetDefaultMovementType) .def("SetDefaultMovementType", &Creature::SetDefaultMovementType) ]; return 0; }