diff --git a/doc/EventAI.txt b/doc/EventAI.txt index 07d07bea5..8e011394c 100644 --- a/doc/EventAI.txt +++ b/doc/EventAI.txt @@ -105,7 +105,7 @@ For all ACTION_T_RANDOM, When a Particular Param is selected for the Event... Th ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 0 ACTION_T_NONE No Action Does nothing. 1 ACTION_T_TEXT -TextId1, -TextId2, -TextId3 Simply displays the specified -TextId. When -TextId2 and -TextId3 are specified, the selection will be randomized. Text types are defined, along with other options for the text, in a table below. All values needs to be negative. -2 ACTION_T_SET_FACTION FactionId Changes faction for a creature. When param1 is zero, creature will revert to it's default faction. +2 ACTION_T_SET_FACTION FactionId, Flags Changes faction for a creature. When param1 is zero, creature will revert to it's default faction. Flags will determine when faction is restored to default (evade, respawn etc) 3 ACTION_T_MORPH_TO_ENTRY_OR_MODEL CreatureEntry, ModelId Set either model from creature_template.entry (Param1) OR explicit modelId (Param2). If (Param1) AND (Param2) are both 0, demorph and revert to the default model. 4 ACTION_T_SOUND SoundId Plays a sound 5 ACTION_T_EMOTE EmoteId Does an emote @@ -430,6 +430,11 @@ Read at bottom for documentation of creature_ai_texts-table. 2 = ACTION_T_SET_FACTION: ------------------ Parameter 1: FactionId from Faction.dbc OR 0. Changes faction for creature. If 0, creature will revert to it's default faction if previously changed. +Parameter 2: When Parameter 1 is not 0, flags can be used to restore default faction at certain events. Current supported, from enum TemporaryFactionFlags: + TEMPFACTION_NONE = 0x00, // A persistent faction change and will require manual change to default/another faction when changed once + TEMPFACTION_RESTORE_RESPAWN = 0x01, // Default faction will be restored at respawn + TEMPFACTION_RESTORE_COMBAT_STOP = 0x02, // ... at CombatStop() (happens at creature death, at evade or custom scripte among others) + TEMPFACTION_RESTORE_REACH_HOME = 0x04, // ... at reaching home in home movement (evade), if not already done at CombatStop() ----------------------- 3 = ACTION_T_MORPH_TO_ENTRY_OR_MODEL: diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 66a2f2d1a..0630f734b 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -190,6 +190,11 @@ spell_scripts * datalong=factionId OR 0 to restore original faction from creature_template * datalong2=creature entry * datalong3=search radius + * data_flags = enum TemporaryFactionFlags + TEMPFACTION_NONE = 0x00, // When no flag is used in temporary faction change, faction will be persistent. It will then require manual change back to default/another faction when changed once + TEMPFACTION_RESTORE_RESPAWN = 0x01, // Default faction will be restored at respawn + TEMPFACTION_RESTORE_COMBAT_STOP = 0x02, // ... at CombatStop() (happens at creature death, at evade or custom scripte among others) + TEMPFACTION_RESTORE_REACH_HOME = 0x04, // ... at reaching home in home movement (evade), if not already done at CombatStop() 23 SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL source=worldobject, target=creature * datalong=creature entry/modelid (depend on data_flags) OR 0 to demorph diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index c20bb2583..365e76df0 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -155,7 +155,7 @@ m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), -m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), +m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_temporaryFactionFlags(TEMPFACTION_NONE), m_creatureInfo(NULL), m_splineFlags(SPLINEFLAG_WALKMODE) { m_regenTimer = 200; @@ -1477,7 +1477,12 @@ void Creature::SetDeathState(DeathState s) RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); AddSplineFlag(SPLINEFLAG_WALKMODE); SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); + + if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN) + ClearTemporaryFaction(); + Unit::SetDeathState(ALIVE); + clearUnitState(UNIT_STAT_ALL_STATE); i_motionMaster.Clear(); SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); @@ -2316,6 +2321,24 @@ const char* Creature::GetNameForLocaleIdx(int32 loc_idx) const return GetName(); } +void Creature::SetFactionTemporary(uint32 factionId, uint32 tempFactionFlags) +{ + m_temporaryFactionFlags = tempFactionFlags; + setFaction(factionId); +} + +void Creature::ClearTemporaryFaction() +{ + // No restore if creature is charmed/possessed. + // For later we may consider extend to restore to charmer faction where charmer is creature. + // This can also be done by update any pet/charmed of creature at any faction change to charmer. + if (isCharmed()) + return; + + m_temporaryFactionFlags = TEMPFACTION_NONE; + setFaction(GetCreatureInfo()->faction_A); +} + void Creature::SetActiveObjectState( bool on ) { if(m_isActiveObject==on) diff --git a/src/game/Creature.h b/src/game/Creature.h index a6d941dc7..7cd3497c9 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -422,6 +422,15 @@ enum CreatureSubtype CREATURE_SUBTYPE_TEMPORARY_SUMMON, // new TemporarySummon }; +enum TemporaryFactionFlags // Used at real faction changes +{ + TEMPFACTION_NONE = 0x00, // When no flag is used in temporary faction change, faction will be persistent. It will then require manual change back to default/another faction when changed once + TEMPFACTION_RESTORE_RESPAWN = 0x01, // Default faction will be restored at respawn + TEMPFACTION_RESTORE_COMBAT_STOP = 0x02, // ... at CombatStop() (happens at creature death, at evade or custom scripte among others) + TEMPFACTION_RESTORE_REACH_HOME = 0x04, // ... at reaching home in home movement (evade), if not already done at CombatStop() + TEMPFACTION_ALL, +}; + class MANGOS_DLL_SPEC Creature : public Unit { CreatureAI *i_AI; @@ -681,6 +690,10 @@ class MANGOS_DLL_SPEC Creature : public Unit void SetActiveObjectState(bool on); + void SetFactionTemporary(uint32 factionId, uint32 tempFactionFlags = TEMPFACTION_ALL); + void ClearTemporaryFaction(); + uint32 GetTemporaryFactionFlags() { return m_temporaryFactionFlags; } + void SendAreaSpiritHealerQueryOpcode(Player *pl); void SetVirtualItem(VirtualItemSlot slot, uint32 item_id) { SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + slot, item_id); } @@ -719,11 +732,13 @@ class MANGOS_DLL_SPEC Creature : public Unit Cell m_currentCell; // store current cell where creature listed uint32 m_equipmentId; + // below fields has potential for optimization bool m_AlreadyCallAssistance; bool m_AlreadySearchedAssistance; bool m_regenHealth; bool m_AI_locked; bool m_isDeadByDefault; + uint32 m_temporaryFactionFlags; // used for real faction changes (not auras etc) SpellSchoolMask m_meleeDamageSchoolMask; uint32 m_originalEntry; diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index b11a77309..2cfc7bea8 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -457,16 +457,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 case ACTION_T_SET_FACTION: { if (action.set_faction.factionId) - m_creature->setFaction(action.set_faction.factionId); - else - { - if (CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(m_creature->GetEntry())) - { - //if no id provided, assume reset and then use default - if (m_creature->getFaction() != ci->faction_A) - m_creature->setFaction(ci->faction_A); - } - } + m_creature->SetFactionTemporary(action.set_faction.factionId, action.set_faction.factionFlags); + else // no id provided, assume reset and then use default + m_creature->ClearTemporaryFaction(); + break; } case ACTION_T_MORPH_TO_ENTRY_OR_MODEL: diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index f8c41ccc1..d1a33f4d3 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -187,7 +187,8 @@ struct CreatureEventAI_Action // ACTION_T_SET_FACTION = 2 struct { - uint32 factionId; // faction or 0 for default) + uint32 factionId; // faction id or 0 to restore default faction + uint32 factionFlags; // flags will restore default faction at evade and/or respawn } set_faction; // ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3 struct diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp index b8997d550..1cbf03966 100644 --- a/src/game/HomeMovementGenerator.cpp +++ b/src/game/HomeMovementGenerator.cpp @@ -80,6 +80,9 @@ HomeMovementGenerator::Update(Creature &owner, const uint32& time_diff } } + if (owner.GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_REACH_HOME) + owner.ClearTemporaryFaction(); + owner.LoadCreatureAddon(true); owner.AI()->JustReachedHome(); return false; diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 747088e62..38222307b 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -2683,9 +2683,9 @@ void Map::ScriptsProcess() } if (step.script->faction.factionId) - pOwner->setFaction(step.script->faction.factionId); + pOwner->SetFactionTemporary(step.script->faction.factionId, step.script->faction.flags); else - pOwner->setFaction(pOwner->GetCreatureInfo()->faction_A); + pOwner->ClearTemporaryFaction(); break; } diff --git a/src/game/ScriptMgr.h b/src/game/ScriptMgr.h index 2115ff1ac..a67d9350f 100644 --- a/src/game/ScriptMgr.h +++ b/src/game/ScriptMgr.h @@ -246,6 +246,8 @@ struct ScriptInfo uint32 factionId; // datalong uint32 creatureEntry; // datalong2 uint32 searchRadius; // datalong3 + uint32 empty1; // datalong4 + uint32 flags; // data_flags } faction; struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (23) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 5bbcfa2c9..e45c38e75 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -5713,8 +5713,15 @@ void Unit::CombatStop(bool includingCast) AttackStop(); RemoveAllAttackers(); + if( GetTypeId()==TYPEID_PLAYER ) ((Player*)this)->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel + else if (GetTypeId() == TYPEID_UNIT) + { + if (((Creature*)this)->GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_COMBAT_STOP) + ((Creature*)this)->ClearTemporaryFaction(); + } + ClearInCombat(); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index f339b1e5f..d45543772 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11315" + #define REVISION_NR "11316" #endif // __REVISION_NR_H__