aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp34
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp9
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h9
-rw-r--r--src/server/game/Entities/Object/Object.cpp14
-rw-r--r--src/server/game/Entities/Object/Object.h1
8 files changed, 66 insertions, 9 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 9ab51c65463..066747b0610 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -869,9 +869,9 @@ void SmartAI::StopFollow(bool complete)
GetScript()->ProcessEventsFor(SMART_EVENT_FOLLOW_COMPLETED, player);
}
-void SmartAI::SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker)
+void SmartAI::SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker, uint32 startFromEventId)
{
- GetScript()->SetTimedActionList(e, entry, invoker);
+ GetScript()->SetTimedActionList(e, entry, invoker, startFromEventId);
}
void SmartAI::OnGameEvent(bool start, uint16 eventId)
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index c40fe78d179..6d0c766d650 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -71,7 +71,7 @@ class TC_GAME_API SmartAI : public CreatureAI
void WaypointReached(uint32 nodeId, uint32 pathId) override;
void WaypointPathEnded(uint32 nodeId, uint32 pathId) override;
- void SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker);
+ void SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker, uint32 startFromEventId = 0);
SmartScript* GetScript() { return &_script; }
// Called at reaching home after evade, InitializeAI(), EnterEvadeMode() for resetting variables
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 515c71b6a30..5968b4e8791 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -2522,6 +2522,26 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
break;
}
+ case SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER:
+ {
+ for (WorldObject* target : targets)
+ {
+ if (!IsPlayer(target))
+ continue;
+
+ ObjectGuid privateObjectOwner = target->GetGUID();
+ if (Creature* summon = GetBaseObject()->SummonPersonalClone((TempSummonType)e.action.becomePersonalClone.type, e.action.becomePersonalClone.duration, 0, 0, privateObjectOwner))
+ {
+ if (IsSmart(summon))
+ ENSURE_AI(SmartAI, summon->AI())->SetTimedActionList(e, e.entryOrGuid, target->ToUnit(), e.event_id + 1);
+
+ }
+ }
+
+ // action list will continue on personal clones
+ Trinity::Containers::EraseIf(mTimedActionList, [e](SmartScriptHolder const& script) { return script.event_id > e.event_id; });
+ break;
+ }
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry " SI64FMTD " SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
@@ -3936,17 +3956,20 @@ void SmartScript::OnUpdate(uint32 const diff)
if (!mTimedActionList.empty())
{
isProcessingTimedActionList = true;
- for (SmartScriptHolder& scriptholder : mTimedActionList)
+
+ for (size_t i = 0; i < mTimedActionList.size(); ++i)
{
- if (scriptholder.enableTimed)
+ SmartScriptHolder& scriptHolder = mTimedActionList[i];
+ if (scriptHolder.enableTimed)
{
- UpdateTimer(scriptholder, diff);
+ UpdateTimer(scriptHolder, diff);
needCleanup = false;
}
}
isProcessingTimedActionList = false;
}
+
if (needCleanup)
mTimedActionList.clear();
@@ -4188,7 +4211,7 @@ Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) co
return unit;
}
-void SmartScript::SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker)
+void SmartScript::SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker, uint32 startFromEventId)
{
//do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete
// any SmartScriptHolder contained like the "e" parameter passed to this function
@@ -4206,6 +4229,9 @@ void SmartScript::SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* i
mTimedActionList = sSmartScriptMgr->GetScript(entry, SMART_SCRIPT_TYPE_TIMED_ACTIONLIST);
if (mTimedActionList.empty())
return;
+
+ Trinity::Containers::EraseIf(mTimedActionList, [startFromEventId](SmartScriptHolder const& script) { return script.event_id < startFromEventId; });
+
mTimedActionListInvoker = invoker ? invoker->GetGUID() : ObjectGuid::Empty;
for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i)
{
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index e75d2bb48a3..55061ab40ef 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -91,7 +91,7 @@ class TC_GAME_API SmartScript
void OnReset();
void ResetBaseObject();
- void SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker);
+ void SetTimedActionList(SmartScriptHolder& e, uint32 entry, Unit* invoker, uint32 startFromEventId = 0);
Unit* GetLastInvoker(Unit* invoker = nullptr) const;
ObjectGuid mLastInvoker;
typedef std::unordered_map<uint32, uint32> CounterMap;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index d393b412958..40167bceb31 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1838,6 +1838,15 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_DESPAWN_SPAWNGROUP:
case SMART_ACTION_ADD_TO_STORED_TARGET_LIST:
break;
+ case SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER:
+ {
+ if (e.action.becomePersonalClone.type < TEMPSUMMON_TIMED_OR_DEAD_DESPAWN || e.action.becomePersonalClone.type > TEMPSUMMON_MANUAL_DESPAWN)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses incorrect TempSummonType %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.becomePersonalClone.type);
+ return false;
+ }
+ break;
+ }
default:
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry " SI64FMTD " SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
return false;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 0473febc762..87ea61dd5c4 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -613,7 +613,8 @@ enum SMART_ACTION
SMART_ACTION_SET_UNINTERACTIBLE = 146, // 0/1
SMART_ACTION_ACTIVATE_GAMEOBJECT = 147, // GameObjectActions
SMART_ACTION_ADD_TO_STORED_TARGET_LIST = 148, // varID
- SMART_ACTION_END = 149
+ SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER = 149, // summonType 1-8, duration in ms
+ SMART_ACTION_END = 150
};
enum class SmartActionSummonCreatureFlags
@@ -1241,6 +1242,12 @@ struct SmartAction
uint32 id;
} addToStoredTargets;
+ struct
+ {
+ uint32 type;
+ uint32 duration;
+ } becomePersonalClone;
+
//! Note for any new future actions
//! All parameters must have type uint32
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 4a89ecb2674..0587493d994 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1866,6 +1866,20 @@ TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, fl
return SummonCreature(id, { x,y,z,o }, despawnType, despawnTime, 0, 0, privateObjectOwner);
}
+TempSummon* WorldObject::SummonPersonalClone(TempSummonType despawnType, uint32 despawnTime, uint32 vehId, uint32 spellId, ObjectGuid privateObjectOwner)
+{
+ if (Map* map = FindMap())
+ {
+ if (TempSummon* summon = map->SummonCreature(GetEntry(), GetPosition(), nullptr, despawnTime, this, spellId, vehId, privateObjectOwner))
+ {
+ summon->SetTempSummonType(despawnType);
+ return summon;
+ }
+ }
+
+ return nullptr;
+}
+
GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, uint32 respawnTime, GOSummonType summonType)
{
if (!IsInWorld())
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index eac830cfedc..5187ebd25c5 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -571,6 +571,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
TempSummon* SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, uint32 despawnTime = 0, uint32 vehId = 0, uint32 spellId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty);
TempSummon* SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType, Milliseconds despawnTime, uint32 vehId = 0, uint32 spellId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty) { return SummonCreature(entry, pos, despawnType, uint32(despawnTime.count()), vehId, spellId, privateObjectOwner); }
TempSummon* SummonCreature(uint32 entry, float x, float y, float z, float o = 0, TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, uint32 despawnTime = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty);
+ TempSummon* SummonPersonalClone(TempSummonType despawnType = TEMPSUMMON_MANUAL_DESPAWN, uint32 despawnTime = 0, uint32 vehId = 0, uint32 spellId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty);
GameObject* SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, uint32 respawnTime /* s */, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN);
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, QuaternionData const& rot, uint32 respawnTime /* s */, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN);
Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = nullptr);