/* /\/\ __ _ _ __ __ _ ___ / _\ ___ _ __(_)_ __ | |_
* / \ / _` | '_ \ / _` |/ _ \\ \ / __| '__| | '_ \| __|
* / /\/\ \ (_| | | | | (_| | (_) |\ \ (__| | | | |_) | |_
* \/ \/\__,_|_| |_|\__, |\___/\__/\___|_| |_| .__/ \__|
* |___/ |_|
* 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 <http://www.mangoscript.org>
*
* 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, Unit, WorldObject, Object>("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;
}