/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* 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, see .
*/
#ifndef ACORE_SMARTSCRIPT_H
#define ACORE_SMARTSCRIPT_H
#include "Creature.h"
#include "GridNotifiers.h"
#include "SmartScriptMgr.h"
#include "Spell.h"
#include "Unit.h"
#include
class SmartScript
{
struct SmartScriptFrame
{
SmartScriptHolder& holder;
Unit* unit;
uint32 var0;
uint32 var1;
bool bvar;
SpellInfo const* spell;
GameObject* gob;
};
public:
SmartScript();
~SmartScript();
void OnInitialize(WorldObject* obj, AreaTrigger const* at = nullptr);
void GetScript();
void FillScript(SmartAIEventList e, WorldObject* obj, AreaTrigger const* at);
void ProcessEventsFor(SMART_EVENT e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
void ProcessEvent(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
bool CheckTimer(SmartScriptHolder const& e) const;
static void RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max);
void UpdateTimer(SmartScriptHolder& e, uint32 const diff);
static void InitTimer(SmartScriptHolder& e);
void ProcessAction(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr);
void GetTargets(ObjectVector& targets, SmartScriptHolder const& e, WorldObject* invoker = nullptr) const;
void GetWorldObjectsInDist(ObjectVector& objects, float dist) const;
void InstallTemplate(SmartScriptHolder const& e);
static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask);
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask);
void SetPathId(uint32 id) { mPathId = id; }
uint32 GetPathId() const { return mPathId; }
WorldObject* GetBaseObject() const
{
WorldObject* obj = nullptr;
if (me)
obj = me;
else if (go)
obj = go;
return obj;
}
static bool IsUnit(WorldObject* obj);
static bool IsPlayer(WorldObject* obj);
static bool IsCreature(WorldObject* obj);
static bool IsCharmedCreature(WorldObject* obj);
static bool IsGameObject(WorldObject* obj);
void OnUpdate(const uint32 diff);
void OnMoveInLineOfSight(Unit* who);
Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) const;
Unit* DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, uint32 maxHpPct) const;
void DoFindFriendlyCC(std::vector& creatures, float range) const;
void DoFindFriendlyMissingBuff(std::vector& creatures, float range, uint32 spellid) const;
Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly) const;
bool IsSmart(Creature* c, bool silent = false) const;
bool IsSmart(GameObject* g, bool silent = false) const;
bool IsSmart(bool silent = false) const;
void StoreTargetList(ObjectVector const& targets, uint32 id)
{
// insert or replace
_storedTargets.erase(id);
_storedTargets.emplace(id, ObjectGuidVector(targets));
}
ObjectVector const* GetStoredTargetVector(uint32 id, WorldObject const& ref) const
{
auto itr = _storedTargets.find(id);
if (itr != _storedTargets.end())
return itr->second.GetObjectVector(ref);
return nullptr;
}
void StoreCounter(uint32 id, uint32 value, uint32 reset, uint32 subtract)
{
CounterMap::iterator itr = mCounterList.find(id);
if (itr != mCounterList.end())
{
if (!reset && !subtract)
{
itr->second += value;
}
else if (subtract)
{
itr->second -= value;
}
else
{
itr->second = value;
}
}
else
{
mCounterList.insert(std::make_pair(id, value));
}
ProcessEventsFor(SMART_EVENT_COUNTER_SET, nullptr, id);
}
uint32 GetCounterValue(uint32 id)
{
CounterMap::iterator itr = mCounterList.find(id);
if (itr != mCounterList.end())
return itr->second;
return 0;
}
GameObject* FindGameObjectNear(WorldObject* searchObject, ObjectGuid::LowType guid) const
{
auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
if (bounds.first == bounds.second)
return nullptr;
return bounds.first->second;
}
Creature* FindCreatureNear(WorldObject* searchObject, ObjectGuid::LowType guid) const
{
auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid);
if (bounds.first == bounds.second)
return nullptr;
auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
{
return pair.second->IsAlive();
});
return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
}
void OnReset();
void ResetBaseObject()
{
WorldObject* lookupRoot = me;
if (!lookupRoot)
lookupRoot = go;
if (lookupRoot)
{
if (meOrigGUID)
{
if (Creature* m = ObjectAccessor::GetCreature(*lookupRoot, meOrigGUID))
{
me = m;
go = nullptr;
}
}
if (goOrigGUID)
{
if (GameObject* o = ObjectAccessor::GetGameObject(*lookupRoot, goOrigGUID))
{
me = nullptr;
go = o;
}
}
}
goOrigGUID.Clear();
meOrigGUID.Clear();
}
//TIMED_ACTIONLIST (script type 9 aka script9)
void SetScript9(SmartScriptHolder& e, uint32 entry);
WorldObject* GetLastInvoker(WorldObject* invoker = nullptr) const;
ObjectGuid mLastInvoker;
typedef std::unordered_map CounterMap;
CounterMap mCounterList;
bool AllowPhaseReset() const { return _allowPhaseReset; }
void SetPhaseReset(bool allow) { _allowPhaseReset = allow; }
void AddCreatureSummon(ObjectGuid const& guid);
void RemoveCreatureSummon(ObjectGuid const& guid);
private:
void IncPhase(uint32 p);
void DecPhase(uint32 p);
void SetPhase(uint32 p);
bool IsInPhase(uint32 p) const;
void SortEvents(SmartAIEventList& events);
void RaisePriority(SmartScriptHolder& e);
void RetryLater(SmartScriptHolder& e, bool ignoreChanceRoll = false);
SmartAIEventList mEvents;
SmartAIEventList mInstallEvents;
SmartAIEventList mTimedActionList;
bool isProcessingTimedActionList;
Creature* me;
ObjectGuid meOrigGUID;
GameObject* go;
ObjectGuid goOrigGUID;
AreaTrigger const* trigger;
SmartScriptType mScriptType;
uint32 mEventPhase;
std::unordered_map mStoredDecimals;
uint32 mPathId;
SmartAIEventStoredList mStoredEvents;
std::list mRemIDs;
uint32 mTextTimer;
uint32 mLastTextID;
uint32 mTalkerEntry;
bool mUseTextTimer;
uint32 mCurrentPriority;
bool mEventSortingRequired;
// Xinef: misc
bool _allowPhaseReset;
ObjectVectorMap _storedTargets;
SMARTAI_TEMPLATE mTemplate;
void InstallEvents();
void RemoveStoredEvent (uint32 id)
{
if (!mStoredEvents.empty())
{
for (SmartAIEventStoredList::iterator i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
{
if (i->event_id == id)
{
mStoredEvents.erase(i);
return;
}
}
}
}
std::optional> FindLinkedEvent(uint32 link)
{
if (!mEvents.empty())
{
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
{
if (i->event_id == link)
{
return std::ref(*i);
}
}
}
return std::nullopt;
}
GuidUnorderedSet _summonList;
std::deque executionStack;
};
#endif