2 * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "TemporarySummon.h"
20 #include "CreatureAI.h"
21 #include "DB2Structure.h"
24 #include "ObjectAccessor.h"
28 TempSummon::TempSummon(SummonPropertiesEntry
const* properties
, Unit
* owner
, bool isWorldObject
) :
29 Creature(isWorldObject
), m_Properties(properties
), m_type(TEMPSUMMON_MANUAL_DESPAWN
),
30 m_timer(0), m_lifetime(0), m_visibleBySummonerOnly(false)
33 m_summonerGUID
= owner
->GetGUID();
35 m_unitTypeMask
|= UNIT_MASK_SUMMON
;
38 Unit
* TempSummon::GetSummoner() const
40 return !m_summonerGUID
.IsEmpty() ? ObjectAccessor::GetUnit(*this, m_summonerGUID
) : NULL
;
43 Creature
* TempSummon::GetSummonerCreatureBase() const
45 return !m_summonerGUID
.IsEmpty() ? ObjectAccessor::GetCreature(*this, m_summonerGUID
) : NULL
;
48 void TempSummon::Update(uint32 diff
)
50 Creature::Update(diff
);
52 if (m_deathState
== DEAD
)
59 case TEMPSUMMON_MANUAL_DESPAWN
:
61 case TEMPSUMMON_TIMED_DESPAWN
:
72 case TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
:
84 else if (m_timer
!= m_lifetime
)
90 case TEMPSUMMON_CORPSE_TIMED_DESPAWN
:
92 if (m_deathState
== CORPSE
)
104 case TEMPSUMMON_CORPSE_DESPAWN
:
106 // if m_deathState is DEAD, CORPSE was skipped
107 if (m_deathState
== CORPSE
|| m_deathState
== DEAD
)
115 case TEMPSUMMON_DEAD_DESPAWN
:
117 if (m_deathState
== DEAD
)
124 case TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN
:
126 // if m_deathState is DEAD, CORPSE was skipped
127 if (m_deathState
== CORPSE
|| m_deathState
== DEAD
)
143 else if (m_timer
!= m_lifetime
)
144 m_timer
= m_lifetime
;
147 case TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
:
149 // if m_deathState is DEAD, CORPSE was skipped
150 if (m_deathState
== DEAD
)
156 if (!IsInCombat() && IsAlive())
166 else if (m_timer
!= m_lifetime
)
167 m_timer
= m_lifetime
;
172 TC_LOG_ERROR("entities.unit", "Temporary summoned creature (entry: %u) have unknown type %u of ", GetEntry(), m_type
);
177 void TempSummon::InitStats(uint32 duration
)
182 m_lifetime
= duration
;
184 if (m_type
== TEMPSUMMON_MANUAL_DESPAWN
)
185 m_type
= (duration
== 0) ? TEMPSUMMON_DEAD_DESPAWN
: TEMPSUMMON_TIMED_DESPAWN
;
187 Unit
* owner
= GetSummoner();
189 if (owner
&& IsTrigger() && m_spells
[0])
191 setFaction(owner
->getFaction());
192 SetLevel(owner
->getLevel());
193 if (owner
->GetTypeId() == TYPEID_PLAYER
)
194 m_ControlledByPlayer
= true;
202 int32 slot
= m_Properties
->Slot
;
205 if (!owner
->m_SummonSlot
[slot
].IsEmpty() && owner
->m_SummonSlot
[slot
] != GetGUID())
207 Creature
* oldSummon
= GetMap()->GetCreature(owner
->m_SummonSlot
[slot
]);
208 if (oldSummon
&& oldSummon
->IsSummon())
209 oldSummon
->ToTempSummon()->UnSummon();
211 owner
->m_SummonSlot
[slot
] = GetGUID();
215 if (m_Properties
->Faction
)
216 setFaction(m_Properties
->Faction
);
217 else if (IsVehicle() && owner
) // properties should be vehicle
218 setFaction(owner
->getFaction());
221 void TempSummon::InitSummon()
223 Unit
* owner
= GetSummoner();
226 if (owner
->GetTypeId() == TYPEID_UNIT
&& owner
->ToCreature()->IsAIEnabled
)
227 owner
->ToCreature()->AI()->JustSummoned(this);
229 AI()->IsSummonedBy(owner
);
233 void TempSummon::UpdateObjectVisibilityOnCreate()
235 WorldObject::UpdateObjectVisibility(true);
238 void TempSummon::SetTempSummonType(TempSummonType type
)
243 void TempSummon::UnSummon(uint32 msTime
)
247 ForcedUnsummonDelayEvent
* pEvent
= new ForcedUnsummonDelayEvent(*this);
249 m_Events
.AddEvent(pEvent
, m_Events
.CalculateTime(msTime
));
256 ToPet()->Remove(PET_SAVE_NOT_IN_SLOT
);
257 ASSERT(!IsInWorld());
261 Unit
* owner
= GetSummoner();
262 if (owner
&& owner
->GetTypeId() == TYPEID_UNIT
&& owner
->ToCreature()->IsAIEnabled
)
263 owner
->ToCreature()->AI()->SummonedCreatureDespawn(this);
265 AddObjectToRemoveList();
268 bool ForcedUnsummonDelayEvent::Execute(uint64
/*e_time*/, uint32
/*p_time*/)
274 void TempSummon::RemoveFromWorld()
281 int32 slot
= m_Properties
->Slot
;
283 if (Unit
* owner
= GetSummoner())
284 if (owner
->m_SummonSlot
[slot
] == GetGUID())
285 owner
->m_SummonSlot
[slot
].Clear();
288 //if (GetOwnerGUID())
289 // TC_LOG_ERROR("entities.unit", "Unit %u has owner guid when removed from world", GetEntry());
291 Creature::RemoveFromWorld();
294 Minion::Minion(SummonPropertiesEntry
const* properties
, Unit
* owner
, bool isWorldObject
)
295 : TempSummon(properties
, owner
, isWorldObject
), m_owner(owner
)
298 m_unitTypeMask
|= UNIT_MASK_MINION
;
299 m_followAngle
= PET_FOLLOW_ANGLE
;
300 /// @todo: Find correct way
304 void Minion::InitStats(uint32 duration
)
306 TempSummon::InitStats(duration
);
308 SetReactState(REACT_PASSIVE
);
310 SetCreatorGUID(GetOwner()->GetGUID());
311 setFaction(GetOwner()->getFaction());
313 GetOwner()->SetMinion(this, true);
316 void Minion::RemoveFromWorld()
321 GetOwner()->SetMinion(this, false);
322 TempSummon::RemoveFromWorld();
325 bool Minion::IsGuardianPet() const
327 return IsPet() || (m_Properties
&& m_Properties
->Control
== SUMMON_CATEGORY_PET
);
330 Guardian::Guardian(SummonPropertiesEntry
const* properties
, Unit
* owner
, bool isWorldObject
) : Minion(properties
, owner
, isWorldObject
)
331 , m_bonusSpellDamage(0)
333 memset(m_statFromOwner
, 0, sizeof(float)*MAX_STATS
);
334 m_unitTypeMask
|= UNIT_MASK_GUARDIAN
;
335 if (properties
&& (properties
->Title
== SUMMON_TYPE_PET
|| properties
->Control
== SUMMON_CATEGORY_PET
))
337 m_unitTypeMask
|= UNIT_MASK_CONTROLABLE_GUARDIAN
;
342 void Guardian::InitStats(uint32 duration
)
344 Minion::InitStats(duration
);
346 InitStatsForLevel(GetOwner()->getLevel());
348 if (GetOwner()->GetTypeId() == TYPEID_PLAYER
&& HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN
))
349 m_charmInfo
->InitCharmCreateSpells();
351 SetReactState(REACT_AGGRESSIVE
);
354 void Guardian::InitSummon()
356 TempSummon::InitSummon();
358 if (GetOwner()->GetTypeId() == TYPEID_PLAYER
359 && GetOwner()->GetMinionGUID() == GetGUID()
360 && !GetOwner()->GetCharmGUID())
362 GetOwner()->ToPlayer()->CharmSpellInitialize();
366 Puppet::Puppet(SummonPropertiesEntry
const* properties
, Unit
* owner
)
367 : Minion(properties
, owner
, false) //maybe true?
369 ASSERT(m_owner
->GetTypeId() == TYPEID_PLAYER
);
370 m_unitTypeMask
|= UNIT_MASK_PUPPET
;
373 void Puppet::InitStats(uint32 duration
)
375 Minion::InitStats(duration
);
376 SetLevel(GetOwner()->getLevel());
377 SetReactState(REACT_PASSIVE
);
380 void Puppet::InitSummon()
382 Minion::InitSummon();
383 if (!SetCharmedBy(GetOwner(), CHARM_TYPE_POSSESS
))
387 void Puppet::Update(uint32 time
)
389 Minion::Update(time
);
390 //check if caster is channelling?
396 /// @todo why long distance .die does not remove it
401 void Puppet::RemoveFromWorld()
406 RemoveCharmedBy(NULL
);
407 Minion::RemoveFromWorld();