diff --git a/doc/EventAI.md b/doc/EventAI.md index 239d7ea01..dd0bb9213 100644 --- a/doc/EventAI.md +++ b/doc/EventAI.md @@ -1,57 +1,50 @@ -mangos EventAI scripting -======================== -**Last Updated**: September 25, 2013 +=========================================================================== +MaNGOS EventAI (Creature_AI) Documentation: (Last Updated: August 22, 2012) +=========================================================================== -*mangos* provides a simple scripting feature through a set of event-based -commands from within the database. - -Introduction ------------- -Enhancing creatures with dynamic features instead of just a few spells can be -achieved without knowing any programming language, and only requires basic -[SQL][1] knowledge, and a database editor of your choice. - -*EventAI* scripts are based on in-game events, and attached to specific creature -templates, which means they are valid for every spawn of a creature. - -Database documentation ----------------------- -All scripts and related information are stored within the database tables -`creature_ai_scripts`, `creature_ai_summons` and `creature_ai_texts`. +EventAI allows users to create new creature scripts entirely within the database. For the AI to be used, you must first make sure to set AIname for each creature that should use this AI. +UPDATE creature_template SET AIName = 'EventAI' WHERE entry IN (...); - UPDATE creature_template SET AIName = 'EventAI' WHERE entry IN (...); -Basic Structure of creature_ai_scripts +========================================= +Basic Structure of EventAI ========================================= -Field_Name | Description -------------------------------| ----------- -id | This value is merely an incrementing counter of the current Event number. Required for sql queries. (ACID Standards: CreatureID+Additional 2 digit Increment Starting with 01) -creature_id | Creature ID which should trigger this event (This is entry value from `creature_template` table). -event_type | The type of event you want to script. (see "Event Types" below for different values) -event_inverse_phase_mask | Mask with phases this event should NOT trigger in [^1] -event_chance | Percentage chance of triggering the event (1 - 100) -event_flags | Event Flags (Used to select Repeatable or Dungeon Heroic Mode)... See "Event Flags" Below For Defined Values -event_param1 | Variables for the event (depends on event_type) -event_param2 | Variables for the event (depends on event_type) -event_param3 | Variables for the event (depends on event_type) -event_param4 | Variables for the event (depends on event_type) -action1_type | Action #1 to take when the Event occurs (see "Action types" below) -action1_param1 | Variables used by Action1 (depends on action_type) -action1_param2 | Variables used by Action1 (depends on action_type) -action1_param3 | Variables used by Action1 (depends on action_type) -action2_type | Action #2 to take when the Event occurs (see "Action types" below) -action2_param1 | Variables used by Action1 (depends on action_type) -action2_param2 | Variables used by Action1 (depends on action_type) -action2_param3 | Variables used by Action1 (depends on action_type) -action3_type | Action #3 to take when the Event occurs (see "Action types" below) -action3_param1 | Variables used by Action1 (depends on action_type) -action3_param2 | Variables used by Action1 (depends on action_type) -action3_param3 | Variables used by Action1 (depends on action_type) +EventAI follows a basic IF (Event) then DO (Action) format. +Below is the list of current fields of the creature_ai_scripts table. -All parameters are signed 32-bit values (+/- 2147483647). Time values are always in milliseconds. +Field_Name Description +------------------------------------------- +id This value is merely an incrementing counter of the current Event number. Required for sql queries. (ACID Standards: CreatureID+Additional 2 digit Incriment Starting with 01) +creature_id Creature ID which should trigger this event (This is entry value from `creature_template` table). + +event_type The type of event you want to script. (see "Event Types" below for different values) +event_inverse_phase_mask Mask with phases this event should NOT trigger in* (See footnote for more details on using any other value then 0) +event_chance Percentage chance of triggering the event (1 - 100) +event_flags Event Flags (Used to select Repeatable or Dungeon/Raid Difficulty Level)... See "Event Flags" Below For Defined Values +event_param1 Variables for the event (depends on event_type) +event_param2 Variables for the event (depends on event_type) +event_param3 Variables for the event (depends on event_type) +event_param4 Variables for the event (depends on event_type) + +action1_type Action #1 to take when the Event occurs (see "Action types" below) +action1_param1 Variables used by Action1 (depends on action_type) +action1_param2 Variables used by Action1 (depends on action_type) +action1_param3 Variables used by Action1 (depends on action_type) + +action2_type Action #2 to take when the Event occurs (see "Action types" below) +action2_param1 Variables used by Action1 (depends on action_type) +action2_param2 Variables used by Action1 (depends on action_type) +action2_param3 Variables used by Action1 (depends on action_type) + +action3_type Action #3 to take when the Event occurs (see "Action types" below) +action3_param1 Variables used by Action1 (depends on action_type) +action3_param2 Variables used by Action1 (depends on action_type) +action3_param3 Variables used by Action1 (depends on action_type) + +All params are signed 32-bit values (+/- 2147483647). Time values are always in milliseconds. In case of a percentage value, use value/100 (ie. param = 500 then that means 500%, -50 = -50%) [*] Phase mask is a bitmask of phases which shouldn't trigger this event. (ie. Phase mask of value 12 (binary 1100) results in triggering this event in phases 0, 1 and all others with exception for phases 2 and 3 (counting from 0). @@ -60,664 +53,735 @@ In case of a percentage value, use value/100 (ie. param = 500 then that means 50 ========================================= Event Types -=========== +========================================= + This is the list of available Event Types EventAI is able to handle. -Each event type has its own specific interpretation of the parameters that accompany it. -Parameters are always read in the ascending order (from Param1 to Param3). +Each event type has its own specific interpretation of the params that accompany it. +Params are always read in the ascending order (from Param1 to Param3). NOTE: Events will not repeat until the creature exits combat or unless EFLAG_REPEATABLE value is set in Event Flags. Some events such as EVENT_T_AGGRO, EVENT_T_DEATH, EVENT_T_SPAWNED, and EVENT_T_EVADE cannot repeat even if EFLAG_REPEATABLE value is set. -# | Internal Name | Event Param Usage (Param1, Param2, Param3, Param4) | Description ----| ----------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- -0 | EVENT_T_TIMER_IN_COMBAT | InitialMin, InitialMax, RepeatMin, RepeatMax | Expires at first between (Param1) and (Param2) and then will repeat between every (Param3) and (Param4), EXPIRES ONLY IN COMBAT. -1 | EVENT_T_TIMER_OOC | InitialMin, InitialMax, RepeatMin, RepeatMax | Expires at first between (Param1) and (Param2) and then will repeat between every (Param3) and (Param4), EXPIRES ONLY OUT OF COMBAT BUT NOT DURING EVADE. -2 | EVENT_T_HP | HPMax%, HPMin%, RepeatMin, RepeatMax | Expires when the NPC's HP% is between (Param1) and (Param2). Will repeat between every (Param3) and (Param4) If Event Conditions Are Still Met. -3 | EVENT_T_MANA | ManaMax%, ManaMin%, RepeatMin, RepeatMax | Expires when the NPC's Mana% is between (Param1) and (Param2). Will repeat between every (Param3) and (Param4) If Event Conditions Are Still Met. -4 | EVENT_T_AGGRO | NONE | Expires ONLY upon the NPC's INITIAL Aggro at the Start of Combat (Does NOT Repeat) and Only Resets on Spawn or Evade. -5 | EVENT_T_KILL | RepeatMin, RepeatMax | Expires upon Killing a Player. Will Repeat Check between (Param1) and (Param2). This Event Will Not Trigger Again Until Repeat Timer Expires -6 | EVENT_T_DEATH | NONE | Expires on the NPC's Death. (This Triggers At The Moment The NPC Dies) -7 | EVENT_T_EVADE | NONE | Expires at the moment the Creature EnterEvadeMode() and Exits Combat. -8 | EVENT_T_SPELLHIT | SpellID, Schoolmask, RepeatMin, RepeatMax | Expires upon Spell Hit of the NPC. When (param1) is set, it is the specific Spell ID used as the trigger. With (param2) specified, the expiration is limited to specific spell schools (-1 for all) and Spell ID value is ignored. Will repeat Event Conditions Check between every (Param3) and (Param4). Only A Spell ID or Spell School may be Specified but NOT both. -9 | EVENT_T_RANGE | MinDist, MaxDist, RepeatMin, RepeatMax | Expires when the Highest Threat Target Distance is Greater than (Param1) and Less than (Param2). Will repeat between every (Param3) and (Param4) if Event Conditions Are Still Met. -10 | EVENT_T_OOC_LOS | Hostile-or-Not, MaxAllowedRange, RepeatMin, RepeatMax | Expires when a unit moves within distance (MaxAllowedRange) of the NPC. If (Param1) is 0 it will expire only when unit is hostile, If (Param1) is 1 it will expire only when unit is friendly. This depends generally on faction relations. Will repeat every (Param3) and (Param4). Does NOT expire when the NPC is in combat. -11 | EVENT_T_SPAWNED | NONE | Expires on initial spawn and respawn of the NPC (Useful for setting Ranged Movement/Summoning Pets/Applying Buffs). -12 | EVENT_T_TARGET_HP | HPMax%, HPMin%, RepeatMin, RepeatMax | Expires when current target's HP% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4)If Event Conditions Are Still Met. -13 | EVENT_T_TARGET_CASTING | RepeatMin, RepeatatMax | Expires when the current target is casting a spell. Will repeat every (Param1) and (Param2) If Event Conditions Are Still Met. -14 | EVENT_T_FRIENDLY_HP | HPDeficit, Radius, RepeatMin, RepeatMax | Expires when a friendly unit in (Radius) has at least (Param1) HP points missing. Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. -15 | EVENT_T_FRIENDLY_IS_CC | DispelType, Radius, RepeatMin, RepeatMax | Expires when a friendly unit is crowd controlled within the given Radius (Param2). Will repeat every (Param3) and (Param4). -16 | EVENT_T_FRIENDLY_MISSING_BUFF | SpellId, Radius, RepeatMin, RepeatMax | Expires when a friendly unit is missing aura(s) given by a spell (Param1) within Radius (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. -17 | EVENT_T_SUMMONED_UNIT | CreatureId, RepeatMin, RepeatMax | Expires after creature with entry = (Param1) is spawned (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). -18 | EVENT_T_TARGET_MANA | ManaMax%, ManaMin%, RepeatMin, RepeatMax | Expires when current target's Mana% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. -21 | EVENT_T_REACHED_HOME | NONE | Expires when a creature reaches it's home (spawn) location after evade. This is commonly used for NPC's who Stealth once reaching their Spawn Location -22 | EVENT_T_RECEIVE_EMOTE | EmoteId, Condition, CondValue1, CondValue2 | Expires when a creature receives an emote with emote text id ("enum TextEmotes" from SharedDefines.h in Mangos Source) in (Param1). Conditions can be defined (Param2) with optional values (Param3,Param4), see (enum ConditionType) in ObjectMgr.h (Mangos Source). -23 | EVENT_T_AURA | SpellID, AmountInStack, RepeatMin, RepeatMax | Expires when a creature has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. -24 | EVENT_T_TARGET_BUFFED | SpellID, AmountInStack, RepeatMin, RepeatMax | Expires when a target unit has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. -25 | EVENT_T_SUMMONED_JUST_DIED | CreatureId, RepeatMin, RepeatMax | Expires after creature with entry = (Param1) is die (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). -26 | EVENT_T_SUMMONED_JUST_DESPAWN | CreatureId, RepeatMin, RepeatMax | Expires before creature with entry = (Param1) is despawn (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). -27 | EVENT_T_MISSING_AURA | SpellID, AmountInStack, RepeatMin, RepeatMax | Expires when a creature not has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4). -28 | EVENT_T_TARGET_MISSING_AURA | SpellID, AmountInStack, RepeatMin, RepeatMax | Expires when a target unit not has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4). -29 | EVENT_T_TIMER_GENERIC | InitialMin, InitialMax, RepeatMin, RepeatMax | Expires at first between (Param1) and (Param2) and then will repeat between every (Param3) and (Param4). -30 | EVENT_T_RECEIVE_AI_EVENT | AIEventType, Sender-Entry, unused, unused | Expires when the creature receives an AIEvent of type (Param1), sent by creature (Param2 != 0). If (Param2 = 0) then sent by any creature +# Internal Name Event Param Usage (Param1, Param2, Param3, Param4) Description +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +0 EVENT_T_TIMER_IN_COMBAT InitialMin, InitialMax, RepeatMin, RepeatMax Expires at first between (Param1) and (Param2) and then will repeat between every (Param3) and (Param4), EXPIRES ONLY IN COMBAT. +1 EVENT_T_TIMER_OOC InitialMin, InitialMax, RepeatMin, RepeatMax Expires at first between (Param1) and (Param2) and then will repeat between every (Param3) and (Param4), EXPIRES ONLY OUT OF COMBAT BUT NOT DURING EVADE. +2 EVENT_T_HP HPMax%, HPMin%, RepeatMin, RepeatMax Expires when the NPC's HP% is between (Param1) and (Param2). Will repeat between every (Param3) and (Param4) If Event Conditions Are Still Met. +3 EVENT_T_MANA ManaMax%, ManaMin%, RepeatMin, RepeatMax Expires when the NPC's Mana% is between (Param1) and (Param2). Will repeat between every (Param3) and (Param4) If Event Conditions Are Still Met. +4 EVENT_T_AGGRO NONE Expires ONLY upon the NPC's INITIAL Aggro at the Start of Combat (Does NOT Repeat) and Only Resets on Spawn or Evade. +5 EVENT_T_KILL RepeatMin, RepeatMax Expires upon Killing a Player. Will Repeat Check between (Param1) and (Param2). This Event Will Not Trigger Again Until Repeat Timer Expires +6 EVENT_T_DEATH NONE Expires on the NPC's Death. (This Triggers At The Moment The NPC Dies) +7 EVENT_T_EVADE NONE Expires at the moment the Creature EnterEvadeMode() and Exits Combat. +8 EVENT_T_SPELLHIT SpellID, Schoolmask, RepeatMin, RepeatMax Expires upon Spell Hit of the NPC. When (param1) is set, it is the specific Spell ID used as the trigger. With (param2) specified, the expiration is limited to specific spell schools (-1 for all) and Spell ID value is ignored. Will repeat Event Conditions Check between every (Param3) and (Param4). Only A Spell ID or Spell School may be Specified but NOT both. +9 EVENT_T_RANGE MinDist, MaxDist, RepeatMin, RepeatMax Expires when the Highest Threat Target Distance is Greater than (Param1) and Less than (Param2). Will repeat between every (Param3) and (Param4) if Event Conditions Are Still Met. +10 EVENT_T_OOC_LOS Hostile-or-Not, MaxAllowedRange, RepeatMin, RepeatMax Expires when a unit moves within distance (MaxAllowedRange) of the NPC. If (Param1) is 0 it will expire only when unit is hostile, If (Param1) is 1 it will expire only when unit is friendly. This depends generally on faction relations. Will repeat every (Param3) and (Param4). Does NOT expire when the NPC is in combat. +11 EVENT_T_SPAWNED NONE Expires on initial spawn and respawn of the NPC (Useful for setting Ranged Movement/Summoning Pets/Applying Buffs). +12 EVENT_T_TARGET_HP HPMax%, HPMin%, RepeatMin, RepeatMax Expires when current target's HP% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4)If Event Conditions Are Still Met. +13 EVENT_T_TARGET_CASTING RepeatMin, RepeatatMax Expires when the current target is casting a spell. Will repeat every (Param1) and (Param2) If Event Conditions Are Still Met. +14 EVENT_T_FRIENDLY_HP HPDeficit, Radius, RepeatMin, RepeatMax Expires when a friendly unit in (Radius) has at least (Param1) HP points missing. Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. +15 EVENT_T_FRIENDLY_IS_CC DispelType, Radius, RepeatMin, RepeatMax Expires when a friendly unit is crowd controlled within the given Radius (Param2). Will repeat every (Param3) and (Param4). +16 EVENT_T_FRIENDLY_MISSING_BUFF SpellId, Radius, RepeatMin, RepeatMax Expires when a friendly unit is missing aura(s) given by a spell (Param1) within Radius (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. +17 EVENT_T_SUMMONED_UNIT CreatureId, RepeatMin, RepeatMax Expires after creature with entry = (Param1) is spawned (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). +18 EVENT_T_TARGET_MANA ManaMax%, ManaMin%, RepeatMin, RepeatMax Expires when current target's Mana% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. +21 EVENT_T_REACHED_HOME NONE Expires when a creature reaches it's home (spawn) location after evade. This is commonly used for NPC's who Stealth once reaching their Spawn Location +22 EVENT_T_RECEIVE_EMOTE EmoteId, Condition, CondValue1, CondValue2 Expires when a creature receives an emote with emote text id ("enum TextEmotes" from SharedDefines.h in Mangos Source) in (Param1). Conditions can be defined (Param2) with optional values (Param3,Param4), see (enum ConditionType) in ObjectMgr.h (Mangos Source). +23 EVENT_T_AURA SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a creature has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. +24 EVENT_T_TARGET_BUFFED SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a target unit has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. +25 EVENT_T_SUMMONED_JUST_DIED CreatureId, RepeatMin, RepeatMax Expires after creature with entry = (Param1) is die (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). +26 EVENT_T_SUMMONED_JUST_DESPAWN CreatureId, RepeatMin, RepeatMax Expires before creature with entry = (Param1) is despawn (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). +27 EVENT_T_MISSING_AURA SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a creature not has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4). +28 EVENT_T_TARGET_MISSING_AURA SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a target unit not has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4). +29 EVENT_T_TIMER_GENERIC InitialMin, InitialMax, RepeatMin, RepeatMax Expires at first between (Param1) and (Param2) and then will repeat between every (Param3) and (Param4). +30 EVENT_T_RECEIVE_AI_EVENT AIEventType, Sender-Entry, unused, unused Expires when the creature receives an AIEvent of type (Param1), sent by creature (Param2 != 0). If (Param2 = 0) then sent by any creature +31 EVENT_T_ENERGY EnergyMax%, EnergyMin%, RepeatMin, RepeatMax Expires when the NPC's Energy% is between (Param1) and (Param2). Will repeat between every (Param3) and (Param4) If Event Conditions Are Still Met. +========================================= Action Types -============ +========================================= + This is a list of action types that EventAI is able to handle. -Each event type has it's own specific interpretation of it's parameters, just like Events. +Each event type has it's own specific interpretation of it's params, just like Events. For all ACTION_T_RANDOM Actions, When a Particular Param is selected for the Event... The SAME Param # is selected for all 3 actions when Event is triggered. -# | Internal name | Param usage | Description --- | ------------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- -0 | ACTION_T_NONE | No Action | Does nothing. -1 | ACTION_T_TEXT | -TextId1, -TextId2, -TextId3 | Displays the specified -TextId. When -TextId2 and -TextId3 are specified, the selection will be Randomized between 1,2 or 3. Text ID's are defined, along with other options for the text, in creature_ai_texts table. Below is detailed Text Information. All text ID values for EventAI MUST be negative. -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 | Sets either model from creature_template.entry (Param1) OR explicit modelId (Param2) for the NPC. If (Param1) AND (Param2) are both 0, NPC will demorph and revert to the default model (as specified in creature_template). -4 | ACTION_T_SOUND | SoundId | NPC Plays a specified Sound ID. -5 | ACTION_T_EMOTE | EmoteId | NPC Does a specified Emote ID. -6 | UNUSED | UNUSED | UNUSED -7 | UNUSED | UNUSED | UNUSED -8 | UNUSED | UNUSED | UNUSED -9 | ACTION_T_RANDOM_SOUND | SoundId1, SoundId2, SoundId3 | NPC Plays a Random Sound ID (Random Selects Param1, Param2 or Param3) [^2] -10 | ACTION_T_RANDOM_EMOTE | EmoteId1, EmoteId2, EmoteId3 | NPC Emotes a Random Emote ID (Random Selects Param1, Param2 or Param3) [^2] -11 | ACTION_T_CAST | SpellId, Target, CastFlags | Casts spell (Param1) on a target (Param2) using cast flags (Param3) --> Specified Below -12 | ACTION_T_SUMMON | CreatureID, Target, Duration | Summons a Creature ID (Param1) for (Param3) duration after Evade (In MS) and orders it to attack (Param2) target (specified below). Spawns on top of NPC who summons it. -13 | ACTION_T_THREAT_SINGLE_PCT | Threat%, Target | Modifies a threat by (Param1) percent on a target (Param2). -14 | ACTION_T_THREAT_ALL_PCT | Threat% | Modifies a threat by (Param1) on all targets in the threat list (using -100% here will result in full aggro dump). -15 | ACTION_T_QUEST_EVENT | QuestID, Target | Calls AreaExploredOrEventHappens with (Param1) for a target in (Param2). -16 | ACTION_T_QUEST_CASTCREATUREGO | CreatureID, SpellId, Target | Sends CastCreatureOrGo for a creature specified by CreatureId (Param1) with provided spell id (Param2) for a target in (Param3). -17 | ACTION_T_SET_UNIT_FIELD | Field_Number, Value, Target | Sets a unit field (Param1) to provided value (Param2) on a target in (Param3). -18 | ACTION_T_SET_UNIT_FLAG | Flags, Target | Sets flag (flags can be used together to modify multiple flags at once) on a target (Param2). -19 | ACTION_T_REMOVE_UNIT_FLAG | Flags, Target | Removes flag on a target (Param2). -20 | ACTION_T_AUTO_ATTACK | AllowAutoAttack | Stop melee attack when (Param1) is zero, otherwise continue attacking / allow melee attack. -21 | ACTION_T_COMBAT_MOVEMENT | AllowCombatMovement | Stop combat based movement when (Param1) is zero, otherwise continue/allow combat based movement (targeted movement generator). -22 | ACTION_T_SET_PHASE | Phase | Sets the current phase to (Param1). -23 | ACTION_T_INC_PHASE | Value | Increments the phase by (Param1). May be negative to decrement, but should not be zero. -24 | ACTION_T_EVADE | No parameters | Forces the creature to evade, wiping all threat and dropping combat. -25 | ACTION_T_FLEE_FOR_ASSIST | No parameters | Causes the creature to flee for assistance (often at low health). -26 | ACTION_T_QUEST_EVENT_ALL | QuestId | Calls GroupEventHappens with (Param1). Only used if it's _expected_ event should call quest completion for all players in a current party. -27 | ACTION_T_CASTCREATUREGO_ALL | QuestId, SpellId | Calls CastedCreatureOrGo for all players on the threat list with quest id specified in (Param1) and spell id in (Param2). -28 | ACTION_T_REMOVEAURASFROMSPELL | Target, Spellid | Removes all auras on a target (Param1) caused by a spell (Param2). -29 | ACTION_T_RANGED_MOVEMENT | Distance, Angle | Changes the movement generator to a ranged type. (note: default melee type can still be set by using 0 as angle and 0 as distance). -30 | ACTION_T_RANDOM_PHASE | PhaseId1, PhaseId2, PhaseId3 | Sets a phase to a specified id(s) [^2] -31 | ACTION_T_RANDOM_PHASE_RANGE | PhaseMin, PhaseMax | Sets a phase to a random id (Phase = PhaseMin + rnd % PhaseMin-PhaseMax). PhaseMax must be greater than PhaseMin. -32 | ACTION_T_SUMMON_ID | CreatureID, Target, SummonID | Summons a creature (Param1) to attack target (Param2) at location specified by EventAI_Summons (Param3). -33 | ACTION_T_KILLED_MONSTER | CreatureID, Target | Calls KilledMonster (Param1) for a target (Param2). -34 | ACTION_T_SET_INST_DATA | Field, Data | Calls ScriptedInstance::SetData with field (Param1) and data (Param2). -35 | ACTION_T_SET_INST_DATA64 | Field, Target | Calls ScriptedInstance::SetData64 with field (Param1) and target's GUID (Param2). -36 | ACTION_T_UPDATE_TEMPLATE | TemplateId, Team | Changes a creature's template to (Param1) with team = Alliance or Horde when (Param2) is either false or true respectively. -37 | ACTION_T_DIE | No parameters | Kills the creature -38 | ACTION_T_ZONE_COMBAT_PULSE | No parameters | Puts all players within an instance into combat with the creature. Only works when a creature is already in combat. Doesn't work outside instances. -39 | ACTION_T_CALL_FOR_HELP | Radius | Call any friendly out-of-combat creatures in a radius (Param1) to attack current creature's target. -40 | ACTION_T_SET_SHEATH | Sheath | Sets sheath state for a creature (0 = no weapon, 1 = melee weapon, 2 = ranged weapon). -41 | ACTION_T_FORCE_DESPAWN | Delay | Despawns the creature, if delay = 0 immediate otherwise will despawn after delay time set in Param1 (in ms). -42 | ACTION_T_SET_INVINCIBILITY_HP_LEVEL | HP_Level, HP_Percent | Set min. health level for creature that can be set at damage as flat value or percent from max health -43 | ACTION_T_MOUNT_TO_ENTRY_OR_MODEL | CreatureEntry, ModelId | Set mount model from creature_template.entry (Param1) OR explicit modelId (Param2). If (Param1) AND (Param2) are both 0, unmount. -44 | ACTION_T_CHANCED_TEXT | Chance, -TextId1, -TextId2 | Displays by Chance (1..100) the specified -TextId. When -TextId2 is specified, the selection will be randomized. Text types are defined, along with other options for the text, in a table below. Param2 and Param3 needs to be negative. -45 | ACTION_T_THROW_AI_EVENT | EventType, Radius | Throws an AIEvent of type (Param1) to nearby friendly Npcs in range of (Param2) -46 | ACTION_T_SET_THROW_MASK | EventTypeMask | Marks for which AIEvents the npc will throw AIEvents on its own. -47 ACTION_T_SUMMON_UNIQUE CreatureID, Target, SummonID Only summons a creature when not already spawned (Param1) to attack target (Param2) at location specified by EventAI_Summons (Param3). Preventing multiple spawns of unique creatures. -48 ACTION_T_EMOTE_TARGET EmoteId, TargetGuid NPC faces to creature (Param2) and does a specified emote id (Param1). +# Internal name Param usage Description +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +0 ACTION_T_NONE No Action Does nothing. +1 ACTION_T_TEXT -TextId1, -TextId2, -TextId3 Displays the specified -TextId. When -TextId2 and -TextId3 are specified, the selection will be Randomized between 1,2 or 3. Text ID's are defined, along with other options for the text, in creature_ai_texts table. Below is detailed Text Information. All text ID values for EventAI MUST be negative. +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 Sets either model from creature_template.entry (Param1) OR explicit modelId (Param2) for the NPC. If (Param1) AND (Param2) are both 0, NPC will demorph and revert to the default model (as specified in creature_template). +4 ACTION_T_SOUND SoundId NPC Plays a specified Sound ID. +5 ACTION_T_EMOTE EmoteId NPC Does a specified Emote ID. +6 UNUSED UNUSED UNUSED +7 UNUSED UNUSED UNUSED +8 UNUSED UNUSED UNUSED +9 ACTION_T_RANDOM_SOUND SoundId1, SoundId2, SoundId3 NPC Plays a Random Sound ID (Random Selects Param1, Param2 or Param3) * +10 ACTION_T_RANDOM_EMOTE EmoteId1, EmoteId2, EmoteId3 NPC Emotes a Random Emote ID (Random Selects Param1, Param2 or Param3) * +11 ACTION_T_CAST SpellId, Target, CastFlags Casts spell (Param1) on a target (Param2) using cast flags (Param3) --> Specified Below +12 ACTION_T_SUMMON CreatureID, Target, Duration Summons a Creature ID (Param1) for (Param3) duration after Evade (In MS) and orders it to attack (Param2) target (specified below). Spawns on top of NPC who summons it. +13 ACTION_T_THREAT_SINGLE_PCT Threat%, Target Modifies a threat by (Param1) percent on a target (Param2). +14 ACTION_T_THREAT_ALL_PCT Threat% Modifies a threat by (Param1) on all targets in the threat list (using -100% here will result in full aggro dump). +15 ACTION_T_QUEST_EVENT QuestID, Target Calls AreaExploredOrEventHappens with (Param1) for a target in (Param2). +16 ACTION_T_QUEST_CASTCREATUREGO CreatureID, SpellId, Target Sends CastCreatureOrGo for a creature specified by CreatureId (Param1) with provided spell id (Param2) for a target in (Param3). +17 ACTION_T_SET_UNIT_FIELD Field_Number, Value, Target Sets a unit field (Param1) to provided value (Param2) on a target in (Param3). +18 ACTION_T_SET_UNIT_FLAG Flags, Target Sets flag (flags can be used together to modify multiple flags at once) on a target (Param2). +19 ACTION_T_REMOVE_UNIT_FLAG Flags, Target Removes flag on a target (Param2). +20 ACTION_T_AUTO_ATTACK AllowAutoAttack Stop melee attack when (Param1) is zero, otherwise continue attacking / allow melee attack. +21 ACTION_T_COMBAT_MOVEMENT AllowCombatMovement Stop combat based movement when (Param1) is zero, otherwise continue/allow combat based movement (targeted movement generator). +22 ACTION_T_SET_PHASE Phase Sets the current phase to (Param1). +23 ACTION_T_INC_PHASE Value Increments the phase by (Param1). May be negative to decrement, but should not be zero. +24 ACTION_T_EVADE No Params Forces the creature to evade, wiping all threat and dropping combat. +25 ACTION_T_FLEE_FOR_ASSIST No Params Causes the creature to flee for assistence (often at low health). +26 ACTION_T_QUEST_EVENT_ALL QuestId Calls GroupEventHappens with (Param1). Only used if it's _expected_ event should call quest completion for all players in a current party. +27 ACTION_T_CASTCREATUREGO_ALL QuestId, SpellId Calls CastedCreatureOrGo for all players on the threat list with quest id specified in (Param1) and spell id in (Param2). +28 ACTION_T_REMOVEAURASFROMSPELL Target, Spellid Removes all auras on a target (Param1) caused by a spell (Param2). +29 ACTION_T_RANGED_MOVEMENT Distance, Angle Changes the movement generator to a ranged type. (note: default melee type can still be set by using 0 as angle and 0 as distance). +30 ACTION_T_RANDOM_PHASE PhaseId1, PhaseId2, PhaseId3 Sets a phase to a specified id(s)* +31 ACTION_T_RANDOM_PHASE_RANGE PhaseMin, PhaseMax Sets a phase to a random id (Phase = PhaseMin + rnd % PhaseMin-PhaseMax). PhaseMax must be greater than PhaseMin. +32 ACTION_T_SUMMON CreatureID, Target, SummonID Summons a creature (Param1) to attack target (Param2) at location specified by EventAI_Summons (Param3). +33 ACTION_T_KILLED_MONSTER CreatureID, Target Calls KilledMonster (Param1) for a target (Param2). +34 ACTION_T_SET_INST_DATA Field, Data Calls ScriptedInstance::SetData with field (Param1) and data (Param2). +35 ACTION_T_SET_INST_DATA64 Field, Target Calls ScriptedInstance::SetData64 with field (Param1) and target's GUID (Param2). +36 ACTION_T_UPDATE_TEMPLATE TemplateId, Team Changes a creature's template to (Param1) with team = Alliance or Horde when (Param2) is either false or true respectively. +37 ACTION_T_DIE No Params Kills the creature +38 ACTION_T_ZONE_COMBAT_PULSE No Params Puts all players within an instance into combat with the creature. Only works when a creature is already in combat. Doesn't work outside instances. +39 ACTION_T_CALL_FOR_HELP Radius Call any friendly out-of-combat creatures in a radius (Param1) to attack current creature's target. +40 ACTION_T_SET_SHEATH Sheath Sets sheath state for a creature (0 = no weapon, 1 = melee weapon, 2 = ranged weapon). +41 ACTION_T_FORCE_DESPAWN Delay Despawns the creature, if delay = 0 immediate otherwise will despawn after delay time set in Param1 (in ms). +42 ACTION_T_SET_INVINCIBILITY_HP_LEVEL HP_Level, HP_Percent Set min. health level for creature that can be set at damage as flat value or percent from max health +43 ACTION_T_MOUNT_TO_ENTRY_OR_MODEL CreatureEntry, ModelId Set mount model from creature_template.entry (Param1) OR explicit modelId (Param2). If (Param1) AND (Param2) are both 0, unmount. +44 ACTION_T_CHANCED_TEXT Chance, -TextId1, -TextId2 Displays by Chance (1..100) the specified -TextId. When -TextId2 is specified, the selection will be randomized. Text types are defined, along with other options for the text, in a table below. Param2 and Param3 needs to be negative. +45 ACTION_T_THROW_AI_EVENT EventType, Radius Throws an AIEvent of type (Param1) to nearby friendly Npcs in range of (Param2) +46 ACTION_T_SET_THROW_MASK EventTypeMask Marks for which AIEvents the npc will throw AIEvents on its own. +47 ACTION_T_SET_STAND_STATE StandState Set the unit stand state (Param1) of the current creature. +48 ACTION_T_CHANGE_MOVEMENT MovementType, WanderDistance Change the unit movement type (Param1). If the movement type is Random Movement (1), the WanderDistance (Param2) must be provided. +49 ACTION_T_DYNAMIC_MOVEMENT EnableDynamicMovement Enable dynamic movement behavior (1 = on; 0 = off) * = Use -1 where the param is expected to do nothing. Random constant is generated for each event, so if you have a random yell and a random sound, they will be linked up with each other (ie. param2 with param2). ============================================== Event Types: Expanded and Detailed Information ----------------------------------------------- -* COMBAT ONLY - Means that this event will only trigger during combat. -* OUT OF COMBAT ONLY - Means that this event will only trigger while out of combat. -* BOTH - This event can trigger both in and out of combat. +============================================== +Note: +COMBAT ONLY - Means that this event will only trigger durring combat. +OUT OF COMBAT ONLY - Means that this event will only trigger while out of combat. +BOTH - This event can trigger both in and out of combat. -Events that do not have labels on them are events that are directly involved with the in and out of combat state. +Events that do not have lables on them are events that are directly involved with the in and out of combat state. -0 = EVENT_T_TIMER_IN_COMBAT ---------------------------- -* Parameter 1: InitialMin - Minimum Time used to calculate Random Initial Expire -* Parameter 2: InitialMax - Maximum Time used to calculate Random Initial Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +------------------ +0 = EVENT_T_TIMER_IN_COMBAT: +------------------ +Parameter 1: InitialMin - Minumum Time used to calculate Random Initial Expire +Parameter 2: InitialMax - Maximum Time used to calculate Random Initial Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire COMBAT ONLY - Expires first between (Param1) and (Param2) and then between every (Param3) and (Param4) from then on. -This is commonly used for spells that repeat cast during combat (Simulates Spell Cool-down). +This is commonly used for spells that repeat cast during combat (Simulates Spell Cooldown). -1 = EVENT_T_TIMER_OOC ---------------------- -* Parameter 1: InitialMin - Minimum Time used to calculate Random Initial Event Expire -* Parameter 2: InitialMax - Maximum Time used to calculate Random Initial Event Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire +---------------------- +1 = EVENT_T_TIMER_OOC: +---------------------- +Parameter 1: InitialMin - Minimum Time used to calculate Random Initial Event Expire +Parameter 2: InitialMax - Maximum Time used to calculate Random Initial Event Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire OUT OF COMBAT ONLY (Not while evading) - Expires first between (Param1) and (Param2) and then between every (Param3) and (Param4) from then on. This is commonly used for events that occur and repeat outside of combat like random NPC Say or Random Emotes. -2 = EVENT_T_HP --------------- -* Parameter 1: HPMax% - Maximum HP% That will trigger this Event to Expire -* Parameter 2: HPMin% - Minimum HP% That will trigger this Event to Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire +--------------- +2 = EVENT_T_HP: +--------------- +Parameter 1: HPMax% - Maximum HP% That will trigger this Event to Expire +Parameter 2: HPMin% - Minimum HP% That will trigger this Event to Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire BOTH - Expires when HP is between (Param1) and (Param2). Will repeat every (Param3) and (Param4). This is commonly used for events that occur at a specific HP% Range (Such as Heal/Enrage Spells or NPC's that Flee). NOTE: For Repeat Events the Repeat Timer ONLY Re-Check's Event Conditions to see If HP% Is Between Max and Min. If it is then Event will Expire again. -3 = EVENT_T_MANA ----------------- -* Parameter 1: ManaMax% - Maximum Mana% That will trigger this Event to Expire -* Parameter 2: ManaMin% - Minimum Mana% That will trigger this Event to Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire +----------------- +3 = EVENT_T_MANA: +----------------- +Parameter 1: ManaMax% - Maximum Mana% That will trigger this Event to Expire +Parameter 2: ManaMin% - Minimum Mana% That will trigger this Event to Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire BOTH - Expires once Mana% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4). This is commonly used for events where an NPC low on Mana will do something (Such as stop casting spells and switch to melee). -4 = EVENT_T_AGGRO ------------------ -**COMBAT ONLY** - This Event Expires upon Initial Aggro (This Event does not occur again until NPC either Evades/Re-spawns and then Enters Combat Again). +------------------ +4 = EVENT_T_AGGRO: +------------------ +COMBAT ONLY - This Event Expires upon Initial Aggro (This Event does not occur again until NPC either Evades/Respawns and then Enters Combat Again). -5 = EVENT_T_KILL ----------------- -* Parameter 1: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire -* Parameter 2: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire +----------------- +5 = EVENT_T_KILL: +----------------- +Parameter 1: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire +Parameter 2: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire COMBAT ONLY - Expires upon killing a player. Will repeat every (Param1) and (Param2). This Event Expires upon killing a player. It is commonly used for NPC's who yell or do something after killing a player. Normally use a short repeating timer is advisable. -NOTE: For Repeat Events the Repeat Timer ONLY Re-Check's Event Conditions to see If another Player Kill has occurred. So After Repeat Min/Max Player Kill Event can occur again. +NOTE: For Repeat Events the Repeat Timer ONLY Re-Check's Event Conditions to see If another Player Kill has occured. So After Repeat Min/Max Player Kill Event can occur again. -6 = EVENT_T_DEATH ------------------ +------------------ +6 = EVENT_T_DEATH: +------------------ BOTH - This Event Expires upon Death of the Scripted NPC. This is normally only used in combat though. This is commonly used for NPC's who have a Yell or Spell Cast when they Die. -7 = EVENT_T_EVADE ------------------ +------------------ +7 = EVENT_T_EVADE: +------------------ COMBAT ONLY - This Event Expires when the Scripted NPC Evades Combat (EnterEvadeMode). This is commonly used for NPC's who use phases, allows you to reset their phase to 0 on evade to prevent possible strange behavior on Re-Aggro. -8 = EVENT_T_SPELLHIT --------------------- -* Parameter 1: SpellID - The Spell ID that will trigger the Event to occur (NOTE: If you use Spell School as the trigger ALWAYS set this value to 0) -* Parameter 2: School - Spell School to trigger the Event (NOTE: If you use a SpellID then ALWAYS set this value to -1) - *See Below for Spell School Bit mask Values* -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire +--------------------- +8 = EVENT_T_SPELLHIT: +--------------------- +Parameter 1: SpellID - The Spell ID that will trigger the Event to occur (NOTE: If you use Spell School as the trigger ALWAYS set this value to 0) +Parameter 2: School - Spell School to trigger the Event (NOTE: If you use a SpellID then ALWAYS set this value to -1) - *See Below for Spell School Bitmask Values* +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire -BOTH - Expires on Spell-hit. If (param1) is set it will only expire on that SPECIFIC Spell OR If (param2) is set it will only expire on Spells of that School. Will repeat every (Param3) and (Param4). +BOTH - Expires on Spellhit. If (param1) is set it will only expire on that SPECIFIC Spell OR If (param2) is set it will only expire on Spells of that School. Will repeat every (Param3) and (Param4). This Event is commonly used for NPC's who can do special things when you cast a spell (Or specific spell) on them. -NOTE: For Repeat Events the Repeat Timer ONLY Re-Check's Event Conditions to see If another Spell-hit has occurred. So After Repeat Min/Max expires Spell-hit Event can occur again. +NOTE: For Repeat Events the Repeat Timer ONLY Re-Check's Event Conditions to see If another Spellhit has occured. So After Repeat Min/Max expires Spellhit Event can occur again. -Name | School | School Bit mask Values ---------------------| ------ | --------------- -SPELL_SCHOOL_NORMAL | 0 | 1 -SPELL_SCHOOL_HOLY | 1 | 2 -SPELL_SCHOOL_FIRE | 2 | 4 -SPELL_SCHOOL_NATURE | 3 | 8 -SPELL_SCHOOL_FROST | 4 | 16 -SPELL_SCHOOL_SHADOW | 5 | 32 -SPELL_SCHOOL_ARCANE | 6 | 64 +(Name ==> School ==> School Bitmask Values) +------------------------------------------- +SPELL_SCHOOL_NORMAL = 0 ==> 1 +SPELL_SCHOOL_HOLY = 1 ==> 2 +SPELL_SCHOOL_FIRE = 2 ==> 4 +SPELL_SCHOOL_NATURE = 3 ==> 8 +SPELL_SCHOOL_FROST = 4 ==> 16 +SPELL_SCHOOL_SHADOW = 5 ==> 32 +SPELL_SCHOOL_ARCANE = 6 ==> 64 +Use These Bitmask Values For Schoolmask (Param2) or Any Combinations Of These School Bitmasks for Multiple Schools. -Use These Bit mask Values For Schoolmask (Param2) or Any Combinations Of These School Bit masks for Multiple Schools. - -9 = EVENT_T_RANGE ------------------ -* Parameter 1: MinDist - This Distance is the Minimum Distance between the NPC and it's target to allow this Event to Expire -* Parameter 2: MaxDist - This Distance is the Maximum Distance between the NPC and it's target to allow this Event to Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +------------------ +9 = EVENT_T_RANGE: +------------------ +Parameter 1: MinDist - This Distance is the Minimum Distance between the NPC and it's target to allow this Event to Expire +Parameter 2: MaxDist - This Distance is the Maximum Distance between the NPC and it's target to allow this Event to Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire COMBAT ONLY - Expires when the highest threat target distance is greater than (Param1) and less than (Param2). Will repeat every (Param3) and (Param4). -This Event is commonly used for NPC's who have Ranged Combat and will Throw/Shoot between a certain distance. +This Event is commonly used for NPC's who have Ranged Combat and will Throw/Shoot between a certian distance. -10 = EVENT_T_OOC_LOS --------------------- -* Parameter 1: Hostile-or-Not - This will expire if Unit are hostile. If Param1=1 it will only expire if Unit are not Hostile(generally determined by faction) -* Parameter 2: MaxAllowedRange - Expires when a Unit moves within this distance to creature -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +--------------------- +10 = EVENT_T_OOC_LOS: +--------------------- +Parameter 1: Hostile-or-Not - This will expire if Unit are hostile. If Param1=1 it will only expire if Unit are not Hostile(generally determined by faction) +Parameter 2: MaxAllowedRange - Expires when a Unit moves within this distance to creature +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire OUT OF COMBAT ONLY This Event is commonly used for NPC's who do something or say something to you when you walk past them Out of Combat. -11 = EVENT_T_SPAWNED --------------------- +--------------------- +11 = EVENT_T_SPAWNED: +--------------------- Expires at initial spawn and at creature respawn. This Event is commonly used for setting ranged movement type or Summoning a Pet on Spawn - -* Parameter 1: 0: works always, 1: works on map in Parameter 2, 2: works on zone/sub-zone in Parameter 2 -* Parameter 2: depends on Parameter 1: for 1 it is map ID, for 2 it is area ID to check +Parameter 1: 0: works always, 1: works on map in Parameter 2, 2: works on zone/subzone in Parameter 2 +Parameter 2: depends on Parameter 1: for 1 it is map ID, for 2 it is area ID to check BOTH - Expires in or out of combat when the NPC Spawns This Event is commonly used for NPC's who cast a spell or do something special when they spawn. This event is not repeatable so it is a one time event on Spawn. -12 = EVENT_T_TARGET_HP ----------------------- -* Parameter 1: HPMax% - Maximum HP% That this Event will Expire -* Parameter 2: HPMin% - Minimum HP% That this Event will Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +----------------------- +12 = EVENT_T_TARGET_HP: +----------------------- +Parameter 1: HPMax% - Maximum HP% That this Event will Expire +Parameter 2: HPMin% - Minimum HP% That this Event will Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire COMBAT ONLY - Expires when Current NPC's Target's HP is between (Param1) and (Param2). Will repeat every (Param3) and (Param4). This Event is commonly used for NPC's who have a special ability (Like Execute) that only casts when a Player HP is low. -13 = EVENT_T_TARGET_CASTING ---------------------------- -* Parameter 1: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 2: RepeatMax - Maximum Time used to calculate Random Repeat Expire +---------------------------- +13 = EVENT_T_TARGET_CASTING: +---------------------------- +Parameter 1: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 2: RepeatMax - Maximum Time used to calculate Random Repeat Expire COMBAT ONLY - Expires when the current target is casting a spell. Will repeat every (Param1) and (Param2). This event is commonly used for NPC's who will cast a counter spell when their target starts to cast a spell. -14 = EVENT_T_FRIENDLY_HP ------------------------- -* Parameter 1: HPDeficit - This is the Amount of HP Missing from Full HP to trigger this event (You would need to calculate the amount of HP the event happens and subtract that from Full HP Value to get this number) -* Parameter 2: Radius - This is the Range in Yards the NPC will scan for nearby Friendlies (Faction is Friendly To) for the missing amount of HP in Param1. -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +------------------------- +14 = EVENT_T_FRIENDLY_HP: +------------------------- +Parameter 1: HPDeficit - This is the Amount of HP Missing from Full HP to trigger this event (You would need to calculate the amount of HP the event happens and subtract that from Full HP Value to get this number) +Parameter 2: Radius - This is the Range in Yards the NPC will scan for nearby Friendlies (Faction is Friendly To) for the missing amount of HP in Param1. +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire COMBAT ONLY - Expires when a friendly unit in radius(param2) has at least (param1) hp missing. Will repeat every (Param3) and (Param4). This is commonly used when an NPC in Combat will heal a nearby Friendly NPC in Combat with a Heal/Renew Spell. -15 = EVENT_T_FRIENDLY_IS_CC ---------------------------- -* Parameter 1: DispelType - Dispel Type to trigger the event - *See Below for Dispel Bit mask Values* -* Parameter 2: Radius - This is the Range in Yards the NPC will scan for nearby Friendlies being Crowd Controlled -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +---------------------------- +15 = EVENT_T_FRIENDLY_IS_CC: +---------------------------- +Parameter 1: DispelType - Dispel Type to trigger the event - *See Below for Dispel Bitmask Values* +Parameter 2: Radius - This is the Range in Yards the NPC will scan for nearby Friendlies being Crowd Controlled +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire COMBAT ONLY - Expires when a friendly unit is Crowd controlled within the given radius (param2). Will repeat every (Param3) and (Param4). -This is commonly used for NPC's who can come to the rescue of other Friendly NPC's if being Crowd Controlled +This is commonly used for NPC's who can come to the resule of other Friendly NPC's if being Crowd Controlled -16 = EVENT_T_FRIENDLY_MISSING_BUFF ----------------------------------- -* Parameter 1: SpellId - This is the SpellID That the Aura Check will look for (If it is missing this Aura) -* Parameter 2: Radius - This is the Range in Yards the NPC will scan for nearby Friendlies (Faction is Friendly To) for the missing Aura. -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +----------------------------------- +16 = EVENT_T_FRIENDLY_MISSING_BUFF: +----------------------------------- +Parameter 1: SpellId - This is the SpellID That the Aura Check will look for (If it is missing this Aura) +Parameter 2: Radius - This is the Range in Yards the NPC will scan for nearby Friendlies (Faction is Friendly To) for the missing Aura. +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire BOTH - Expires when a friendly unit is missing aura's given by spell (param1) within radius (param2). Will repeat every (Param3) and (Param4). This is commonly used for NPC's who watch friendly units for a debuff to end so they can recast it on them again. -17 = EVENT_T_SUMMONED_UNIT --------------------------- -* Parameter 1: CreatureId - The CreatureID that the NPC is watching to spawn to trigger this event -* Parameter 2: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 3: RepeatMax - Maximum Time used to calculate Random Repeat Expire +--------------------------- +17 = EVENT_T_SUMMONED_UNIT: +--------------------------- +Parameter 1: CreatureId - The CreatureID that the NPC is watching to spawn to trigger this event +Parameter 2: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 3: RepeatMax - Maximum Time used to calculate Random Repeat Expire BOTH - Expires after creature with entry(Param1) is spawned or for all spawns if param1 = 0. Will repeat every (Param2) and (Param3) . This is commonly used for NPC's who will do something special once another NPC is summoned. Usually used is Complex Scripts or Special Events. -21 = EVENT_T_REACHED_HOME -------------------------- +--------------------------- +21 = EVENT_T_REACHED_HOME: +--------------------------- Expires only when creature has returned to it's home location after Evade. Out of combat event. Most commonly used to cast spells that can not be casted in EVENT_T_EVADE and other effects that does not fit in while still running back to spawn/home location. -22 = EVENT_T_RECEIVE_EMOTE --------------------------- -* Parameter 1: EmoteId - Valid text emote ID from Mangos source (SharedDefines.h - enum TextEmotes) -* Parameter 2: Condition - Conditions based on /src/game/ObjectMgr.h - enum ConditionType -* Parameter 3: CondValue1 - -* Parameter 4: CondValue2 - +--------------------------- +22 = EVENT_T_RECEIVE_EMOTE: +--------------------------- +Parameter 1: EmoteId - Valid text emote ID from Mangos source (SharedDefines.h - enum TextEmotes) +Parameter 2: Condition - Conditions based on /src/game/ObjectMgr.h - enum ConditionType +Parameter 3: CondValue1 - +Parameter 4: CondValue2 - Expires only when creature receive emote from player. Valid text emote id's are in Mangos source (SharedDefines.h - enum TextEmotes) Event does not require any conditions to process, however many are expected to have condition. -23 = EVENT_T_AURA ------------------ -* Parameter 1: SpellId - This is the SpellID That the Aura Check will look for -* Parameter 2: Amount - This is the amount of SpellID's auras at creature required for event expire. -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +--------------------------- +23 = EVENT_T_AURA : +--------------------------- +Parameter 1: SpellId - This is the SpellID That the Aura Check will look for +Parameter 2: Amount - This is the amount of SpellID's auras at creature required for event expire. +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire -24 = EVENT_T_TARGET_BUFFED --------------------------- -* Parameter 1: SpellId - This is the SpellID That the Aura Check will look for -* Parameter 2: Amount - This is the amount of SpellID's auras at target unit required for event expire. -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +--------------------------- +24 = EVENT_T_TARGET_BUFFED: +--------------------------- +Parameter 1: SpellId - This is the SpellID That the Aura Check will look for +Parameter 2: Amount - This is the amount of SpellID's auras at target unit required for event expire. +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire EventAI use conditions from available in Mangos (enum ConditionType) +Current implemented conditions: +CONDITION_NONE (0) 0 0 +CONDITION_AURA (1) spell_id effindex +CONDITION_ITEM (2) item_id count +CONDITION_ITEM_EQUIPPED (3) item_id count +CONDITION_ZONEID (4) zone_id 0 +CONDITION_REPUTATION_RANK (5) faction_id min_rank +CONDITION_TEAM (6) player_team 0 (469-Alliance / 67-Horde) +CONDITION_SKILL (7) skill_id min_skill_value +CONDITION_QUESTREWARDED (8) quest_id 0, if quest are rewarded +CONDITION_QUESTTAKEN (9) quest_id 0, while quest active(incomplete) +CONDITION_ACTIVE_EVENT (12) event_id 0, note this is id from dbc, also defined in Mangos source(enum HolidayIds) NOT id of game_event in database -**Current implemented conditions** - -Condition | Object | Value ------------------------------ | ----------- | ---------------------------------- -CONDITION_NONE (0) | 0 | 0 -CONDITION_AURA (1) | spell_id | effindex -CONDITION_ITEM (2) | item_id | count -CONDITION_ITEM_EQUIPPED (3) | item_id | count -CONDITION_ZONEID (4) | zone_id | 0 -CONDITION_REPUTATION_RANK (5) | faction_id | min_rank -CONDITION_TEAM (6) | player_team | 0 (469-Alliance / 67-Horde) -CONDITION_SKILL (7) | skill_id | min_skill_value -CONDITION_QUESTREWARDED (8) | quest_id | 0, if quest are rewarded -CONDITION_QUESTTAKEN (9) | quest_id | 0, while quest active(incomplete) -CONDITION_ACTIVE_EVENT (12) | event_id | 0, note this is id from dbc, also defined in Mangos source(enum HolidayIds) NOT id of game_event in database - -25 = EVENT_T_SUMMONED_JUST_DIED -------------------------------- -* Parameter 1: CreatureId - The CreatureID that the NPC is watching die to trigger this event -* Parameter 2: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 3: RepeatMax - Maximum Time used to calculate Random Repeat Expire +-------------------------------- +25 = EVENT_T_SUMMONED_JUST_DIED: +-------------------------------- +Parameter 1: CreatureId - The CreatureID that the NPC is watching die to trigger this event +Parameter 2: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 3: RepeatMax - Maximum Time used to calculate Random Repeat Expire BOTH - Expires after creature with entry(Param1) is die or for all spawns if param1 = 0. Will repeat every (Param2) and (Param3) . This is commonly used for NPC's who will do something special once another NPC is die. Usually used is Complex Scripts or Special Events. -26 = EVENT_T_SUMMONED_JUST_DESPAWN ----------------------------------- -* Parameter 1: CreatureId - The CreatureID that the NPC is watching despawn to trigger this event -* Parameter 2: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 3: RepeatMax - Maximum Time used to calculate Random Repeat Expire +----------------------------------- +26 = EVENT_T_SUMMONED_JUST_DESPAWN: +----------------------------------- +Parameter 1: CreatureId - The CreatureID that the NPC is watching despawn to trigger this event +Parameter 2: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 3: RepeatMax - Maximum Time used to calculate Random Repeat Expire BOTH - Expires before creature with entry(Param1) is despawned or for all spawns if param1 = 0. Will repeat every (Param2) and (Param3) . This is commonly used for NPC's who will do something special once another NPC is despawn. Usually used is Complex Scripts or Special Events. NOTE: called before despawn happens, so summoned creature still in world at expire moment. -27 = EVENT_T_MISSING_BUFF -------------------------- -* Parameter 1: SpellId - This is the SpellID That the Aura Check will look for to be missing -* Parameter 2: Amount - This is the amount or less of SpellID's auras at creature required for event expire. -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire - -28 = EVENT_T_TARGET_MISSING_AURA --------------------------------- -* Parameter 1: SpellId - This is the SpellID That the Aura Check will look for to be missing -* Parameter 2: Amount - This is the amount or less of SpellID's auras at creature required for event expire. -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire - -29 = EVENT_T_TIMER_GENERIC -------------------------- -* Parameter 1: InitialMin - Minimum Time used to calculate Random Initial Expire -* Parameter 2: InitialMax - Maximum Time used to calculate Random Initial Expire -* Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire -* Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire +27 = EVENT_T_MISSING_BUFF: +-------------------------- +Parameter 1: SpellId - This is the SpellID That the Aura Check will look for to be missing +Parameter 2: Amount - This is the amount or less of SpellID's auras at creature required for event expire. +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire + +--------------------------------- +28 = EVENT_T_TARGET_MISSING_AURA: +--------------------------------- +Parameter 1: SpellId - This is the SpellID That the Aura Check will look for to be missing +Parameter 2: Amount - This is the amount or less of SpellID's auras at creature required for event expire. +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire + +--------------------------- +29 = EVENT_T_TIMER_GENERIC: +--------------------------- +Parameter 1: InitialMin - Minumum Time used to calculate Random Initial Expire +Parameter 2: InitialMax - Maximum Time used to calculate Random Initial Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire IN COMBAT and OUT OF COMBAT - Expires first between (Param1) and (Param2) and then between every (Param3) and (Param4) from then on. -30 = EVENT_T_RECEIVE_AI_EVENT ------------------------------ -* Parameter 1: AIEventType - Only expire when an AIEvent of this type is received. Supported types see CreatureAI.h enum AIEventType -* Parameter 2: Sender-Entry - If != 0 then only expire when the AIEvent is received from a creature of this entry +------------------------------ +30 = EVENT_T_RECEIVE_AI_EVENT: +------------------------------ +Parameter 1: AIEventType - Only expire when an AIEvent of this type is received. Supported types see CreatureAI.h enum AIEventType +Parameter 2: Sender-Entry - If != 0 then only expire when the AIEvent is received from a creature of this entry Note: This is the only EVENT where the target-type TARGET_T_EVENT_SENDER (10) is defined -Action types -============ +----------------- +31 = EVENT_T_ENERGY: +----------------- +Parameter 1: EnergyMax% - Maximum Energy% That will trigger this Event to Expire +Parameter 2: EnergyMin% - Minimum Energy% That will trigger this Event to Expire +Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Event Expire +Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Event Expire + +BOTH - Expires once Energy% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4). +This is commonly used for events where an NPC low on Energy will do something (Such as stop casting spells and switch to melee). + +========================================= +Action Types +========================================= -1 = ACTION_T_TEXT ------------------ -* Parameter 1: The entry of the text that the NPC should use from eventai_texts table. Optionally a entry from other tables can be used (such as custom_texts). +1 = ACTION_T_TEXT: +------------------ +Parameter 1: The entry of the text that the NPC should use from eventai_texts table. Optionally a entry from other tables can be used (such as custom_texts). Entry are required to be negative and exist in a *_texts-table. The type text to be displayed are defined in the texts-table itself (Say, Yell, Whisper, Emote Text, Boss Whisper, Boss Emote) Other options are also to be defined in the texts-table, such as a sound to be heard with the text and the language used in output (common, dwarvish, etc). In case this entry has a localized version of the text, the localized text will be displayed in client that support this locale. -* Parameter 2: Optional. TextId can be defined in addition. The same apply to this as explained above, however eventAI will randomize between the two. -* Parameter 3: Optional, if Parameter 2 exist. In this case, eventAI will randomize between three. + +Parameter 2: Optional. TextId can be defined in addition. The same apply to this as explained above, however eventAI will randomize between the two. +Parameter 3: Optional, if Parameter 2 exist. In this case, eventAI will randomize between three. 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: +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 ------------------------------------- -* Parameter 1: Creature entry from creature_template. Action will then change to the model this creature are using. -* Parameter 2: If parameter 1 is 0, then this modelId will be used (in case parameter 1 exist, parameter 2 will not be used) +3 = ACTION_T_MORPH_TO_ENTRY_OR_MODEL: +------------------------------------- +Parameter 1: Creature entry from creature_template. Action will then change to the model this creature are using. +Parameter 2: If parameter 1 is 0, then this modelId will be used (in case parameter 1 exist, parameter 2 will not be used) If both parameter 1 and 2 is 0, the creature will DeMorph, and use it's default model. -4 = ACTION_T_SOUND ------------------- -* Parameter 1: The Sound ID to be played. (Sound IDs are contained in the DBC files.) +4 = ACTION_T_SOUND: +------------------- +Parameter 1: The Sound ID to be played. (Sound IDs are contained in the DBC files.) The creature will play the specified sound. This is commonly used for Bosses who Yell and then also have a Voice for the same thing. -5 = ACTION_T_EMOTE ------------------- -* Parameter 1: The Emote ID that the creature should perform. (Emote IDs are also contained in the DBC but they can be found in the mangos source as well). +5 = ACTION_T_EMOTE: +------------------- +Parameter 1: The Emote ID that the creature should perform. (Emote IDs are also contained in the DBC but they can be found in the mangos source as well). The creature will perform a visual emote. Unlike a text emote, a visual emote is one where the creature will actually move or perform a gesture. -This is commonly used for NPC's who may perform a special action (Salute, Roar, etc...). Not all player emotes work for creature models. +This is commonly used for NPC's who may perform a special action (Salute, Roar, ect...). Not all player emotes work for creature models. -6 = ACTION_T_RANDOM_SAY +------------------------ +6 = ACTION_T_RANDOM_SAY: ------------------------ UNUSED Can be reused to create new action type -7 = ACTION_T_RANDOM_YELL +------------------------- +7 = ACTION_T_RANDOM_YELL: ------------------------- UNUSED Can be reused to create new action type -8 = ACTION_T_RANDOM_TEXTEMOTE +------------------------------ +8 = ACTION_T_RANDOM_TEXTEMOTE: ------------------------------ UNUSED Can be reused to create new action type -9 = ACTION_T_RANDOM_SOUND -------------------------- -* Parameter 1: The Sound ID to be played as Random Choice #1. -* Parameter 2: The Sound ID to be played as Random Choice #2. -* Parameter 3: The Sound ID to be played as Random Choice #3. +9 = ACTION_T_RANDOM_SOUND: +-------------------------- +Parameter 1: The Sound ID to be played as Random Choice #1. +Parameter 2: The Sound ID to be played as Random Choice #2. +Parameter 3: The Sound ID to be played as Random Choice #3. Similar to the ACTION_T_SOUND action, it will choose at random a sound to play. -10 = ACTION_T_RANDOM_EMOTE --------------------------- -* Parameter 1: The Emote ID to be played as Random Choice #1. -* Parameter 2: The Emote ID to be played as Random Choice #2. -* Parameter 3: The Emote ID to be played as Random Choice #3. +10 = ACTION_T_RANDOM_EMOTE: +--------------------------- +Parameter 1: The Emote ID to be played as Random Choice #1. +Parameter 2: The Emote ID to be played as Random Choice #2. +Parameter 3: The Emote ID to be played as Random Choice #3. Similar to the ACTION_T_EMOTE action, it will choose at random an Emote to Visually Perform. -11 = ACTION_T_CAST ------------------- -* Parameter 1: SpellId - The Spell ID to use for the NPC to cast. The value used in this field needs to be a valid Spell ID. -* Parameter 2: Target - The Target Type defining who the creature should cast the spell at. The value in this field needs to be a valid Target Type as specified in the reference tables below. -* Parameter 3: CastFlags - See Table Below for Cast Flag Bit mask Values. If you are unsure what to set this value at leave it at 0. +11 = ACTION_T_CAST: +------------------- +Parameter 1: SpellId - The Spell ID to use for the NPC to cast. The value used in this field needs to be a valid Spell ID. +Parameter 2: Target - The Target Type defining who the creature should cast the spell at. The value in this field needs to be a valid Target Type as specified in the reference tables below. +Parameter 3: CastFlags - See Table Below for Cast Flag Bitmask Values. If you are unsure what to set this value at leave it at 0. The creature will cast a spell specified by a spell ID on a target specified by the target type. If the spell is normal cast, random target types will select only targets within LOS and in spell range This is commonly used for NPC's who cast spells. -12 = ACTION_T_SUMMON --------------------- -* Parameter 1: CreatureID - The Creature Template ID to be Summoned. The value here needs to be a valid Creature Template ID. -* Parameter 2: Target - The Target Type defining who the Summoned creature will attack once spawned. The value in this field needs to be a valid Target Type as specified in the reference tables below. -* Parameter 3: Duration - The duration until the summoned creature should be unsummoned AFTER Combat ends. The value in this field is in milliseconds or 0. - -The NPC will Summon another cast flag 0 will work for you creature at the same spot as itself that will attack the specified target. - -*NOTE*: Almost all Creature Summons have proper Summon Spells that should be used when possible. This Action is a powerful last resort option only to be used if nothing else works. -*NOTE*: Using Target Type 0 will cause the Summoned creature to not attack anyone. -*NOTE*: If Duration is set at 0, then the summoned creature will not despawn until it has died. +12 = ACTION_T_SUMMON: +--------------------- +Parameter 1: CreatureID - The Creature Template ID to be Summoned. The value here needs to be a valid Creature Template ID. +Parameter 2: Target - The Target Type defining who the Summoned creature will attack once spawned. The value in this field needs to be a valid Target Type as specified in the reference tables below. +Parameter 3: Duration - The duration until the summoned creature should be unsummoned AFTER Combat ends. The value in this field is in milliseconds or 0. +The NPC will Summon another cast flag 0 will work for you treature at the same spot as itself that will attack the specified target. +NOTE: Almost all Creature Summons have proper Summon Spells that should be used when possible. This Action is a powerful last resort option only to be used if nothing else works. +NOTE: Using Target Type 0 will cause the Summoned creature to not attack anyone. +NOTE: If Duration is set at 0, then the summoned creature will not despawn until it has died. This is used as a manual way to force an NPC to Summon. NOTE: THIS ONLY WORKS IN COMBAT -13 = ACTION_T_THREAT_SINGLE_PCT -------------------------------- -* Parameter 1: Threat% - Threat percent that should be modified. The value in this field can range from -100 to +100. If it is negative, threat will be taken away and if positive, threat will be added. -* Parameter 2: Target - The Target Type defining on whom the threat change should occur. The value in this field needs to be a valid target type as specified in the reference tables below. +13 = ACTION_T_THREAT_SINGLE_PCT: +-------------------------------- +Parameter 1: Threat% - Threat percent that should be modified. The value in this field can range from -100 to +100. If it is negative, threat will be taken away and if positive, threat will be added. +Parameter 2: Target - The Target Type defining on whom the threat change should occur. The value in this field needs to be a valid target type as specified in the reference tables below. This action will modify the threat of a target in the creature's threat list by the specified percent. This is commonly used to allow an NPC to adjust the Threat to a single player. -14 = ACTION_T_THREAT_ALL_PCT ----------------------------- -* Parameter 1: Threat% - The percent that should be used in modifying everyone's threat in the creature's threat list. The value here can range from -100 to +100. +14 = ACTION_T_THREAT_ALL_PCT: +----------------------------- +Parameter 1: Threat% - The percent that should be used in modifying everyone's threat in the creature's threat list. The value here can range from -100 to +100. This action will modify the threat for everyone in the creature's threat list by the specified percent. - NOTE: Using -100 will cause the creature to reset everyone's threat to 0 so that everyone has the same amount of threat. It will NOT remove anyone from the threat list. - This is commonly used to allow an NPC to drop threat for all players to zero. -15 = ACTION_T_QUEST_EVENT -------------------------- -* Parameter 1: QuestID - The Quest Template ID. The value here must be a valid quest template ID. Furthermore, the quest should have SpecialFlags | 2 as it would need to be completed by an external event which is the activation of this action. -* Parameter 2: Target - The Target Type defining whom the quest should be completed for. The value in this field needs to be a valid target type as specified in the reference tables below. +15 = ACTION_T_QUEST_EVENT: +-------------------------- +Parameter 1: QuestID - The Quest Template ID. The value here must be a valid quest template ID. Furthermore, the quest should have SpecialFlags | 2 as it would need to be completed by an external event which is the activation of this action. +Parameter 2: Target - The Target Type defining whom the quest should be completed for. The value in this field needs to be a valid target type as specified in the reference tables below. This action will satisfy the external completion requirement for the quest for the specified target defined by the target type. NOTE: This action can only be used with player targets so it must be ensured that the target type will point to a player. This is commonly used for Quests where only ONE player will gain credit for the quest. -16 = ACTION_T_CASTCREATUREGO ----------------------------- -* Parameter 1: CreatureID - The Creature Template ID to be Summoned. The value here needs to be a valid Creature Template ID. -* Parameter 2: SpellID - The Spell ID to use to simulate the cast. The value used in this field needs to be a valid Spell ID. -* Parameter 3: Target - The Target Type defining whom the quest credit should be given to. The value in this field needs to be a valid target type as specified in the reference tables below. +16 = ACTION_T_CASTCREATUREGO: +----------------------------- +Parameter 1: CreatureID - The Creature Template ID to be Summoned. The value here needs to be a valid Creature Template ID. +Parameter 2: SpellID - The Spell ID to use to simulate the cast. The value used in this field needs to be a valid Spell ID. +Parameter 3: Target - The Target Type defining whom the quest credit should be given to. The value in this field needs to be a valid target type as specified in the reference tables below. This action will call CastedCreatureOrGO() function for the player. It can be used to give quest credit for casting a spell on the creature. This is commonly used for NPC's who have a special requirement to have a Spell cast on them to complete a quest. -17 = ACTION_T_SET_UNIT_FIELD ----------------------------- -* Parameter 1: Field_Number - The index of the Field Number to be changed. Use (http://wiki.udbforums.org/index.php/Character_data) for a list of indexes and what they control. Creatures only contain the OBJECT_FIELD_* and UNIT_FIELD_* fields. They do not contain the PLAYER_FIELD_* fields. -* Parameter 2: Value - The new value to be put in the field. -* Parameter 3: Target - The Target Type defining for whom the unit field should be changed. The value in this field needs to be a valid target type as specified in the reference tables below. +17 = ACTION_T_SET_UNIT_FIELD: +----------------------------- +Parameter 1: Field_Number - The index of the Field Number to be changed. Use (http://wiki.udbforums.org/index.php/Character_data) for a list of indeces and what they control. Creatures only contain the OBJECT_FIELD_* and UNIT_FIELD_* fields. They do not contain the PLAYER_FIELD_* fields. +Parameter 2: Value - The new value to be put in the field. +Parameter 3: Target - The Target Type defining for whom the unit field should be changed. The value in this field needs to be a valid target type as specified in the reference tables below. -When activated, this action can change the target's unit field values. More information on the field value indexes can be found at (http://wiki.udbforums.org/index.php/Character_data) +When activated, this action can change the target's unit field values. More information on the field value indeces can be found at (http://wiki.udbforums.org/index.php/Character_data) -18 = ACTION_T_SET_UNIT_FLAG ---------------------------- -* Parameter 1: Flags - The flag(s) to be set. Multiple flags can be set by using bitwise-OR on them (adding them together). -* Parameter 2: Target - The Target Type defining for whom the flags should be changed. The value in this field needs to be a valid Target Type as specified in the reference tables below. +18 = ACTION_T_SET_UNIT_FLAG: +---------------------------- +Parameter 1: Flags - The flag(s) to be set. Multiple flags can be set by using bitwise-OR on them (adding them together). +Parameter 2: Target - The Target Type defining for whom the flags should be changed. The value in this field needs to be a valid Target Type as specified in the reference tables below. When activated, this action changes the target's flags by adding (turning on) more flags. For example, this action can make the creature unattackable/unselectable if the right flags are used. -19 = ACTION_T_REMOVE_UNIT_FLAG ------------------------------- -* Parameter 1: Flags - The flag(s) to be removed. Multiple flags can be set by using bitwise-OR on them (adding them together). -* Parameter 2: Target - The target type defining for whom the flags should be changed. The value in this field needs to be a valid Target Type as specified in the reference tables below. +19 = ACTION_T_REMOVE_UNIT_FLAG: +------------------------------- +Parameter 1: Flags - The flag(s) to be removed. Multiple flags can be set by using bitwise-OR on them (adding them together). +Parameter 2: Target - The target type defining for whom the flags should be changed. The value in this field needs to be a valid Target Type as specified in the reference tables below. When activated, this action changes the target's flags by removing (turning off) flags. For example, this action can make the creature normal after it was unattackable/unselectable if the right flags are used. -20 = ACTION_T_AUTO_ATTACK -------------------------- -* Parameter 1: AllowAutoAttack - If zero, then the creature will stop its melee attacks. If non-zero, then the creature will either continue its melee attacks (the action would then have no effect) or it will start its melee attacks on the target with the top threat if its melee attacks were previously stopped. +20 = ACTION_T_AUTO_ATTACK: +-------------------------- +Parameter 1: AllowAutoAttack - If zero, then the creature will stop its melee attacks. If non-zero, then the creature will either continue its melee attacks (the action would then have no effect) or it will start its melee attacks on the target with the top threat if its melee attacks were previously stopped. This action controls whether or not the creature should stop or start the auto melee attack. NOTE: The ACID Dev Team has conformed to using either 0 or 1 for the Param values (0 = Stop Melee, 1 = Start Melee). This is commonly used in combination with EVENT_T_RANGE and ACTION_T_COMBAT_MOVEMENT for Ranged Combat for Mages and Spell Casters. -21 = ACTION_T_COMBAT_MOVEMENT ------------------------------ -* Parameter 1: If zero, then the creature will stop moving towards its victim (if its victim gets out of melee range) and will be stationary. If non-zero, then the creature will either continue to follow its victim (the action would have no effect) or it will start to follow the target with the top threat if its movement was disabled before. -* Parameter 2: If non-zero, then stop melee combat state (if param1=0) or start melee combat state (if param1!=0) and creature in combat with selected target. +21 = ACTION_T_COMBAT_MOVEMENT: +------------------------------ +Parameter 1: If zero, then the creature will stop moving towards its victim (if its victim gets out of melee range) and will be stationary. If non-zero, then the creature will either continue to follow its victim (the action would have no effect) or it will start to follow the target with the top threat if its movement was disabled before. +Parameter 2: If non-zero, then stop melee combat state (if param1=0) or start melee combat state (if param1!=0) and creature in combat with selected target. This action controls whether or not the creature will always move towards its target. NOTE: The ACID Dev Team has conformed to using either 0 or 1 for the Param values. (0 = Stop Movement, 1 = Start Movement) -This is commonly used with EVENT_T_RANGE and ACTION_T_AUTO_ATTACK for NPC's who engage in Ranged Combat (Either Spells or Ranged Attacks) -Parameter 2 specially used for ranged combat proper client side visual show ranged weapon in proper state. +This is commonly used with EVENT_T_RANGE and ACTION_T_AUTO_ATTACK for NPC's who engage in Ranged Comabt (Either Spells or Ranged Attacks) +Parameter 2 specialy used for ranged combat proper client side visual show ranged weapon in proper state. -22 = ACTION_T_SET_PHASE ------------------------ -* Parameter 1: The new phase to set the creature in. This number must be an integer between 0 and 31. Numbers outside of that range will result in an error. +22 = ACTION_T_SET_PHASE: +------------------------ +Parameter 1: The new phase to set the creature in. This number must be an integer between 0 and 31. Numbers outside of that range will result in an error. When activated, this action sets the creature's event to the specified value. NOTE: The creature's current Phase is NOT reset at creature evade. You must manually set the phase back to 0 at EVENT_T_RESET. NOTE: The value used for the Param is the actual Phase Number (Not The Event_Inverse_Phase_Mask) This is commonly used for complex scripts with several phases and you need to switch to a different phase. -23 = ACTION_T_INC_PHASE ------------------------ -* Parameter 1: Value - The number of phases to increase or decrease. Use negative values to decrease the current phase. +23 = ACTION_T_INC_PHASE: +------------------------ +Parameter 1: Value - The number of phases to increase or decrease. Use negative values to decrease the current phase. When activated, this action will increase (or decrease) the current creature's phase. NOTE: After increasing or decreasing the phase by this action, the current phase must NOT be lower than 0 or exceed 31. This can be used instead of ACTION_T_SET_PHASE to change phases in scripts. Just a user friendly option for changing phases. -24 = ACTION_T_EVADE +-------------------- +24 = ACTION_T_EVADE: -------------------- When activated, the creature will immediately exit out of combat, clear its threat list, and move back to its spawn point. Basically, this action will reset the whole encounter. NOTE: All Param Values Are 0 for this Action. -25 = ACTION_T_FLEE +------------------- +25 = ACTION_T_FLEE: ------------------- When activated, the creature will flee from combat for assistance from nearby NPC's if possible. NOTE: All Param Values Are 0 for this Action. -26 = ACTION_T_QUEST_EVENT_ALL ------------------------------ -* Parameter 1: QuestId - The quest ID to finish for everyone. +26 = ACTION_T_QUEST_EVENT_ALL: +------------------------------ +Parameter 1: QuestId - The quest ID to finish for everyone. This action does the same thing as the ACTION_T_QUEST_EVENT does but it does it for all players in the creature's threat list. NOTE: If a player is not in the NPC's threat list for whatever reason, he/she won't get the quest completed. -27 = ACTION_T_CASTCREATUREGO_ALL --------------------------------- -* Parameter 1: QuestId - The quest template ID. -* Parameter 2: SpellId - The spell ID used to simulate the cast. +27 = ACTION_T_CASTCREATUREGO_ALL: +--------------------------------- +Parameter 1: QuestId - The quest template ID. +Parameter 2: SpellId - The spell ID used to simulate the cast. This action does the same thing as the ACTION_T_CASTCREATUREGO does but it does it for all players in the creature's threat list. NOTE: If a player is not in its threat list for whatever reason, he/she won't receive the cast emulation. -28 = ACTION_T_REMOVEAURASFROMSPELL ----------------------------------- -* Parameter 1: Target - The target type defining for whom the unit field should be changed. The value in this field needs to be a valid target type as specified in the reference tables below. -* Parameter 2: SpellId - The spell ID whose auras will be removed. +28 = ACTION_T_REMOVEAURASFROMSPELL: +----------------------------------- +Parameter 1: Target - The target type defining for whom the unit field should be changed. The value in this field needs to be a valid target type as specified in the reference tables below. +Parameter 2: SpellId - The spell ID whose auras will be removed. This action will remove all auras from a specific spell from the target. This is commonly used for NPC's who have an OOC Aura that is removed at combat start or a similar idea (Like Stealth or Shape Shift) -29 = ACTION_T_RANGED_MOVEMENT ------------------------------ -* Parameter 1: Distance - The distance the mob should keep between it and its target. -* Parameter 2: Angle - The angle the mob should use. +29 = ACTION_T_RANGED_MOVEMENT: +------------------------------ +Parameter 1: Distance - The distance the mob should keep between it and its target. +Parameter 2: Angle - The angle the mob should use. This action changes the movement type generator to ranged type using the specified values for angle and distance. NOTE: Specifying zero angle and distance will make it just melee instead. This is commonly used for NPC's who always attack at range and you can specify the distance they will maintain from the target. -30 = ACTION_T_RANDOM_PHASE --------------------------- -* Parameter 1: PhaseId1 - A possible random phase choice. -* Parameter 2: PhaseId2 - A possible random phase choice. -* Parameter 3: PhaseId3 - A possible random phase choice. +30 = ACTION_T_RANDOM_PHASE: +--------------------------- +Parameter 1: PhaseId1 - A possible random phase choice. +Parameter 2: PhaseId2 - A possible random phase choice. +Parameter 3: PhaseId3 - A possible random phase choice. Randomly sets the phase to one from the three parameter choices. NOTE: Use -1 to specify that if this param is picked to do nothing. Random is constant between actions within an event. So if you have a random Yell and a random Sound they will match up (ex: param2 with param2) NOTE 2: PLEASE NOTE THAT EACH OF THE PARAM VALUES ARE ACTUAL PHASE NUMBERS NOT THE INVERSE PHASE MASK VALUE. -This is commonly used for Spell casting NPC's who on Aggro may select at random a school of spells to use for the fight. Use this if you have up to 3 phases used, otherwise use Action 31 for more then 3 phases. +This is commonly used for Spellcasting NPC's who on Aggro may select at random a school of spells to use for the fight. Use this if you have up to 3 phases used, otherwise use Action 31 for more then 3 phases. -31 = ACTION_T_RANDOM_PHASE_RANGE --------------------------------- -* Parameter 1: PhaseMin - The minimum of the phase range. -* Parameter 2: PhaseMax - The maximum of the phase range. The number here must be greater than PhaseMin. +31 = ACTION_T_RANDOM_PHASE_RANGE: +--------------------------------- +Parameter 1: PhaseMin - The minimum of the phase range. +Parameter 2: PhaseMax - The maximum of the phase range. The number here must be greater than PhaseMin. Randomly sets the phase between a range of phases controlled by the parameters. Sets the phase to a random id (Phase = PhaseMin + rnd % PhaseMin-PhaseMax). NOTE: PhaseMax must be greater than PhaseMin. NOTE 2: PLEASE NOTE THAT EACH OF THE PARAM VALUES ARE ACTUAL PHASE NUMBERS NOT THE INVERSE PHASE MASK VALUE. -This is commonly used for Spell casting NPC's who on Aggro may select at random a school of spells to use for the fight. Use this if you have MORE then 3 phases used, otherwise use Action 30. +This is commonly used for Spellcasting NPC's who on Aggro may select at random a school of spells to use for the fight. Use this if you have MORE then 3 phases used, otherwise use Action 30. -32 = ACTION_T_SUMMON --------------------- -* Parameter 1: CreatureID - The creature template ID to be summoned. The value here needs to be a valid creature template ID. -* Parameter 2: Target - The target type defining who the summoned creature will attack. The value in this field needs to be a valid target type as specified in the reference tables below. NOTE: Using target type 0 will cause the summoned creature to not attack anyone. -* Parameter 3: SummonID - The summon ID from the creature_ai_summons table controlling the position (and spawn time) where the summoned mob should be spawned at. +32 = ACTION_T_SUMMON: +--------------------- +Parameter 1: CreatureID - The creature template ID to be summoned. The value here needs to be a valid creature template ID. +Parameter 2: Target - The target type defining who the summoned creature will attack. The value in this field needs to be a valid target type as specified in the reference tables below. NOTE: Using target type 0 will cause the summoned creature to not attack anyone. +Parameter 3: SummonID - The summon ID from the creature_ai_summons table controlling the position (and spawntime) where the summoned mob should be spawned at. Summons creature (param1) to attack target (param2) at location specified by creature_ai_summons (param3). NOTE: Param3 Value is the ID Value used for the entry used in creature_ai_summons for this action. You MUST have an creature_ai_summons entry to use this action. This is commonly used for NPC's who need to Summon a creature at a specific location. (Normally used for complex events) -33 = ACTION_T_KILLED_MONSTER ----------------------------- -* Parameter 1: CreatureID - The creature template ID. The value here must be a valid creature template ID. -* Parameter 2: Target - The target type defining whom the quest kill count should be given to. The value in this field needs to be a valid target type as specified in the reference tables below. +33 = ACTION_T_KILLED_MONSTER: +----------------------------- +Parameter 1: CreatureID - The creature template ID. The value here must be a valid creature template ID. +Parameter 2: Target - The target type defining whom the quest kill count should be given to. The value in this field needs to be a valid target type as specified in the reference tables below. -When activated, this action will call KilledMonster() function for the player. It can be used to give creature credit for killing a creature. In general if the quest is set to be accomplished on different creatures (e.g. "Credit" templates). +When activated, this action will call KilledMonster() function for the player. It can be used to give creature credit for killing a creature. In general if the quest is set to be accompished on different creatures (e.g. "Credit" templates). NOTE: It can be ANY creature including certain quest specific triggers This is commonly used for giving the player Quest Credits for NPC kills (Many NPC's may use the same CreatureID for the Kill Credit) -34 = ACTION_T_SET_INST_DATA ---------------------------- -* Parameter 1: Field - The field to change in the instance script. Again, this field needs to be a valid field that has been already defined in the instance's script. -* Parameter 2: Data - The value to put at that field index. +34 = ACTION_T_SET_INST_DATA: +---------------------------- +Parameter 1: Field - The field to change in the instance script. Again, this field needs to be a valid field that has been already defined in the instance's script. +Parameter 2: Data - The value to put at that field index. Sets data for the instance. Note that this will only work when the creature is inside an instantiable zone that has a valid script (ScriptedInstance) assigned. This is commonly used to link an EventAI script with a existing Script Library C++ Script. You make make things happen like opening doors on specific events that happen. @@ -725,175 +789,182 @@ This is commonly used to link an EventAI script with a existing Script Library C Field Values: These are located in there SD2 Instance File (Example: blackrock_depths.h) And Are Clearly Defined For Specific Events Scripted In The Instance. -Name | Value ------------ | ----- -NOT_STARTED | 0 -IN_PROGRESS | 1 -FAIL | 2 -DONE | 3 -SPECIAL | 4 +Data Values: +NOT_STARTED = 0 +IN_PROGRESS = 1 +FAIL = 2 +DONE = 3 +SPECIAL = 4 -35 = ACTION_T_SET_INST_DATA64 ------------------------------ -* Parameter 1: Field - The field to change in the instance script. Again, this field needs to be a valid field that has been already defined in the instance's script. -* Parameter 2: Target - The target type to use to get the GUID that will be stored at the field index. The value in this field needs to be a valid target type as specified in the reference tables below. +35 = ACTION_T_SET_INST_DATA64: +------------------------------ +Parameter 1: Field - The field to change in the instance script. Again, this field needs to be a valid field that has been already defined in the instance's script. +Parameter 2: Target - The target type to use to get the GUID that will be stored at the field index. The value in this field needs to be a valid target type as specified in the reference tables below. Sets GUID (64 bits) data for the instance based on the target. Note that this will only work when the creature is inside an instantiable zone that has a valid script (ScriptedInstance) assigned. Calls ScriptedInstance::SetData64 with field (param1) and data (param2) target's GUID. -36 = ACTION_T_UPDATE_TEMPLATE ------------------------------ -* Parameter 1: TemplateId - The creature template ID. The value here must be a valid creature template ID. -* Parameter 2: Team - Use model_id from team : Alliance(0) or Horde (1). +36 = ACTION_T_UPDATE_TEMPLATE: +------------------------------ +Parameter 1: TemplateId - The creature template ID. The value here must be a valid creature template ID. +Parameter 2: Team - Use model_id from team : Alliance(0) or Horde (1). This function temporarily changes creature entry to new entry, display is changed, loot is changed, but AI is not changed. At respawn creature will be reverted to original entry. Changes the creature to a new creature template of (param1) with team = Alliance if (param2) = false or Horde if (param2) = true -37 = ACTION_T_DIE +------------------ +37 = ACTION_T_DIE: ------------------ Kills the creature - This is commonly used if you need to Instakill the creature for one reason or another. -38 = ACTION_T_ZONE_COMBAT_PULSE +-------------------------------- +38 = ACTION_T_ZONE_COMBAT_PULSE: -------------------------------- Places all players within the instance into combat with the creature. Only works in combat and only works inside of instances. -39 = ACTION_T_CALL_FOR_HELP ---------------------------- -* Parameter 1: Radius - All friendly (not only same faction) creatures will go to help +39 = ACTION_T_CALL_FOR_HELP: +---------------------------- +Parameter 1: Radius - All friendly (not only same faction) creatures will go to help Call any friendly creatures (if its not in combat/etc) in radius attack creature target. Mostly used when call to help more wide that normal aggro radius or auto-used call for assistance, and need apply at some event. -40 ACTION_T_SET_SHEATH ------------------------- -* Parameter 1: Set Sheath State - -Value | Name | Description ------ | -------------------- | ---------------------------------------------- -0 | SHEATH_STATE_UNARMED | Set No Weapon Displayed (Not Usually Used By Creatures) -1 | SHEATH_STATE_MELEE | Set Melee Weapon Displayed -2 | SHEATH_STATE_RANGED | Set Ranged Weapon Displayed +40 ACTION_T_SET_SHEATH: +------------------------- +Parameter 1: Set Sheath State +0 = SHEATH_STATE_UNARMED Set No Weapon Displayed (Not Usually Used By Creatures) +1 = SHEATH_STATE_MELEE Set Melee Weapon Displayed +2 = SHEATH_STATE_RANGED Set Ranged Weapon Displayed Set Sheath State For NPC. Note: SHEATH_STATE_RANGED case work in combat state only if combat not start as melee commands. -This possible setup by set at event AI start (single used EVENT_T_TIMER_OOC or set ACTION_T_COMBAT_MOVEMENT 0 for creature that preferred ranged attack) +This possible setup by set at event AI start (single used EVENT_T_TIMER_OOC or set ACTION_T_COMBAT_MOVEMENT 0 for creature that prefered ranged attack) -41 ACTION_T_FORCE_DESPAWN +---------------------------- +41 ACTION_T_FORCE_DESPAWN: ---------------------------- Despawns The NPC with optional delay time (Works In or Out of Combat) +Parameter 1: Delay - Sets delay time until Despawn occurs after triggering the action. Time is in (ms). -* Parameter 1: `Delay` - Sets delay time until Despawn occurs after triggering the action. Time is in (ms). - -42 ACTION_T_SET_INVINCIBILITY_HP_LEVEL ----------------------------------------- -* Parameter 1: Minimum Health Level That NPC Can Reach (NPC Will Not Go Below This Value). -* Parameter 2: Sets Format of Parameter 1 Value. - 0 = Sets Parameter 1 as an exact HP value, - 1 = Sets Parameter 1 as a HP Percent (0..100) of the creature's max health - -NOTE: To cancel invincible You Need To Set Script For Either 0% HP or 0 HP So Then NPC Can Be Killed Again - -43 ACTION_T_MOUNT_TO_ENTRY_OR_MODEL +42 ACTION_T_SET_INVINCIBILITY_HP_LEVEL: ----------------------------------------- -* Parameter 1, Optional: Set mount model from creature_template.entry -* Parameter 2, Optional: Set mount model by explicit modelId +Parameter 1: Minimum Health Level That NPC Can Reach (NPC Will Not Go Below This Value). +Parameter 2: Sets Format of Paramater 1 Value +0 = Sets Paramater 1 as an exact HP value +1 = Sets Paramater 1 as a HP Percent (0..100) of the creature's max health + +NOTE: To Cancel Invincible You Need To Set Script For Either 0% HP or 0 HP So Then NPC Can Be Killed Again + +----------------------------------------- +43 ACTION_T_MOUNT_TO_ENTRY_OR_MODEL: +----------------------------------------- +Parameter 1, Optional: Set mount model from creature_template.entry +Parameter 2, Optional: Set mount model by explicit modelId If (Param1) AND (Param2) are both 0, unmount. -44 = ACTION_T_CHANCED_TEXT --------------------------- -* Parameter 1: Chance with which a text will be displayed (must be between 1 and 99) -* Parameter 2: The entry of the text that the NPC should use from eventai_texts table. Optionally a entry from other tables can be used (such as custom_texts). - Entry are required to be negative and exist in a *_texts-table. The type text to be displayed are defined in the texts-table itself (Say, Yell, Whisper, Emote Text, Boss Whisper, Boss Emote) - Other options are also to be defined in the texts-table, such as a sound to be heard with the text and the language used in output (common, dwarvish, etc). - In case this entry has a localized version of the text, the localized text will be displayed in client that support this locale. -* Parameter 3: Optional TextId can be defined in addition. The same apply to this as explained above, however eventAI will randomize between the two. +44 = ACTION_T_CHANCED_TEXT: +--------------------------- +Parameter 1: Chance with which a text will be displayed (must be between 1 and 99) + +Parameter 2: The entry of the text that the NPC should use from eventai_texts table. Optionally a entry from other tables can be used (such as custom_texts). + Entry are required to be negative and exist in a *_texts-table. The type text to be displayed are defined in the texts-table itself (Say, Yell, Whisper, Emote Text, Boss Whisper, Boss Emote) + Other options are also to be defined in the texts-table, such as a sound to be heard with the text and the language used in output (common, dwarvish, etc). + In case this entry has a localized version of the text, the localized text will be displayed in client that support this locale. + +Parameter 3: Optional TextId can be defined in addition. The same apply to this as explained above, however eventAI will randomize between the two. Also remark that the chance also depends on the chance of the event. And remark that a chance of 100 is useless and in this case ACTION_T_TEXT should be used. Read at bottom for documentation of creature_ai_texts-table. -45 = ACTION_T_THROW_AI_EVENT ----------------------------- -* Parameter 1: `EventType` - What AIEvent to throw, supported types see CreatureAI.h enum AIEventType -* Parameter 2: `Radius` - Throw the AIEvent to nearby friendly creatures within this range +45 = ACTION_T_THROW_AI_EVENT: +----------------------------- +Parameter 1: EventType - What AIEvent to throw, supported types see CreatureAI.h enum AIEventType +Parameter 2: Radius - Throw the AIEvent to nearby friendly creatures within this range -46 = ACTION_T_SET_THROW_MASK ----------------------------- -* Parameter 1: `EventTypeMask` - Which AIEvents to throw, supported types see CreatureAI.h enum AIEventType (mask-value is 2^type) +46 = ACTION_T_SET_THROW_MASK: +----------------------------- +Parameter 1: EventTypeMask - Which AIEvents to throw, supported types see CreatureAI.h enum AIEventType (mask-value is 2^type) This action sets which AIEvents a npc will throw automatically. - -Mask name | Value | Involed creatures | Source --------------------------- | ----------------- | ------------------------------------------- | ----------------------------------- -AI_EVENT_JUST_DIED | MaskValue: 0x01 | Sender = Killed Npc, Invoker = Killer | Sent when npc dies -AI_EVENT_CRITICAL_HEALTH | MaskValue: 0x02 | Sender = Hurt Npc, Invoker = DamageDealer | Sent when damaged below 10% health -AI_EVENT_LOST_HEALTH | MaskValue: 0x04 | Sender = Hurt Npc, Invoker = DamageDealer | Sent when damaged below 50% health -AI_EVENT_LOST_SOME_HEALTH | MaskValue: 0x08 | Sender = Hurt Npc, Invoker = DamageDealer | Sent when damaged below 90% health -AI_EVENT_GOT_FULL_HEALTH | MaskValue: 0x10 | Sender = Healed Npc, Invoker = Healer | Sent when healed to full health +Currently supported are: + AI_EVENT_JUST_DIED | MaskValue: 0x01 | Sender = Killed Npc, Invoker = Killer | Sent when npc dies + AI_EVENT_CRITICAL_HEALTH | MaskValue: 0x02 | Sender = Hurt Npc, Invoker = DamageDealer | Sent when damaged below 10% health + AI_EVENT_LOST_HEALTH | MaskValue: 0x04 | Sender = Hurt Npc, Invoker = DamageDealer | Sent when damaged below 50% health + AI_EVENT_LOST_SOME_HEALTH | MaskValue: 0x08 | Sender = Hurt Npc, Invoker = DamageDealer | Sent when damaged below 90% health + AI_EVENT_GOT_FULL_HEALTH | MaskValue: 0x10 | Sender = Healed Npc, Invoker = Healer | Sent when healed to full health So if you want an npc to throw AIEvents automatically on death and on critical health, you would set its EventTypeMask to 0x03 ------------------------------ -47 = ACTION_T_SUMMON_UNIQUE ------------------------------ -* Parameter 1: CreatureID - The creature template ID to be summoned. The value here needs to be a valid creature template ID. -* Parameter 2: Target - The target type defining who the summoned creature will attack. The value in this field needs to be a valid target type as specified in the reference tables below. NOTE: Using target type 0 will cause the summoned creature to not attack anyone. -* Parameter 3: SummonID - The summon ID from the creature_ai_summons table controlling the position (and spawn time) where the summoned mob should be spawned at. +------------------------------ +47 = ACTION_T_SET_STAND_STATE: +------------------------------ +Parameter 1: StandState - Stand state id to be used by the creature as defined in Unit.h file in the core. -Only summons a creature when not already spawned (Param1) to attack target (Param2) at location specified by EventAI_Summons (Param3). Preventing multiple spawns of unique creatures. +------------------------------ +48 = ACTION_T_CHANGE_MOVEMENT: +------------------------------ +Parameter 1: MovementType - Movement type id to be used by the creature. Can be 0 = Idle, 1 = Random, 2 = Waypoint. +Parameter 2: WanderDistance - Wander distance to be used in case the movement type is 1 (Random). ------------------------------ -48 = ACTION_T_EMOTE_TARGET ------------------------------ -Parameter 1: The Emote ID that the creature should perform. (Emote IDs are also contained in the DBC but they can be found in the mangos source as well). -Parameter 2: Creature guid, to which emote dealer will performed. +------------------------------- +49 = ACTION_T_DYNAMIC_MOVEMENT: +------------------------------- +Parameter 1: EnableDynamicMovement - Enable dynamic movement behavior. 1 = on / 0 = off. -The creature will perform a visual emote. Unlike a text emote, a visual emote is one where the creature will actually move or perform a gesture. -This is commonly used for NPC's who may perform a special action (Salute, Roar, ect...). Not all player emotes work for creature models. - -Target types ------------- +========================================= +Target Types +========================================= Below is the list of current Target types that EventAI can handle. Target types are used by certain actions and may effect actions differently -# | Internal Name | Description --- | -------------------------------------- | ----------- -0 | TARGET_T_SELF | Self Cast -1 | TARGET_T_HOSTILE | Current Target (ie: Highest Aggro) -2 | TARGET_T_HOSTILE_SECOND_AGGRO | Second Highest Aggro (Generally used for Cleaves and some special attacks) -3 | TARGET_T_HOSTILE_LAST_AGGRO | Dead Last on Aggro (no idea what this could be used for) -4 | TARGET_T_HOSTILE_RANDOM | Random Target on The Threat List -5 | TARGET_T_HOSTILE_RANDOM_NOT_TOP | Any Random Target Except Top Threat -6 | TARGET_T_ACTION_INVOKER | Unit Who Caused This Event to Occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT) -7 | TARGET_T_ACTION_INVOKER_OWNER | Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT) -8 | TARGET_T_HOSTILE_RANDOM_PLAYER | Random Player on The Threat List -9 | TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER | Any Random Player Except Top Threat -10 | TARGET_T_EVENT_SENDER | Creature who sent a received AIEvent - only triggered by EVENT_T_RECEIVE_AI_EVENT +# Internal Name Description +--------------------------------------------------- +0 TARGET_T_SELF Self Cast +1 TARGET_T_HOSTILE Current Target (ie: Highest Aggro) +2 TARGET_T_HOSTILE_SECOND_AGGRO Second Highest Aggro (Generaly used for Cleaves and some special attacks) +3 TARGET_T_HOSTILE_LAST_AGGRO Dead Last on Aggro (no idea what this could be used for) +4 TARGET_T_HOSTILE_RANDOM Random Target on The Threat List +5 TARGET_T_HOSTILE_RANDOM_NOT_TOP Any Random Target Except Top Threat +6 TARGET_T_ACTION_INVOKER Unit Who Caused This Event to Occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT) +7 TARGET_T_ACTION_INVOKER_OWNER Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT) +8 TARGET_T_HOSTILE_RANDOM_PLAYER Random Player on The Threat List +9 TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER Any Random Player Except Top Threat +10 TARGET_T_EVENT_SENDER Creature who sent a received AIEvent - only triggered by EVENT_T_RECEIVE_AI_EVENT -Cast flags ----------- +========================================= +Cast Flags +========================================= Below is the list of current Cast Flags that EventAI's spell casting can handle. Cast flags are handled bitwise. Bit 0 is Interrupt Previous, bit 1 is triggered, etc. So for example the number "3" (11 in Binary, selecting first 2 options) would mean that this cast has both CAST_INTURRUPT_PREVIOUS and CAST_TRIGGERED. Another example: the number "5" (101 in Binary, selecting first and third options) would mean that this cast has CAST_INTURRUPT_PREVIOUS and CAST_FORCE_CAST. -# | Decimal | Internal Name | Description -- | ------- | ----------------------- | ----------- -0 | 1 | CAST_INTURRUPT_PREVIOUS | Interrupts any previous spell casting (basically makes sure that this spell goes off) -1 | 2 | CAST_TRIGGERED | Forces the spell to be instant cast and require no mana/reagents. -2 | 4 | CAST_FORCE_CAST | Forces spell to cast even if the target is possibly out of range or the creature is possibly out of mana -3 | 8 | CAST_NO_MELEE_IF_OOM | Prevents creature from entering melee if out of mana or out of range -4 | 16 | CAST_FORCE_TARGET_SELF | Forces the target to cast this spell on itself -5 | 32 | CAST_AURA_NOT_PRESENT | Only casts the spell on the target if the target does not have the aura from that spell on itself already. +# Decimal Internal Name Description +-------------------------------------------------------------- +0 1 CAST_INTURRUPT_PREVIOUS Interrupts any previous spell casting (basicaly makes sure that this spell goes off) +1 2 CAST_TRIGGERED Forces the spell to be instant cast and require no mana/reagents. +2 4 CAST_FORCE_CAST Forces spell to cast even if the target is possibly out of range or the creature is possibly out of mana +3 8 CAST_NO_MELEE_IF_OOM Prevents creature from entering melee if out of mana or out of range +4 16 CAST_FORCE_TARGET_SELF Forces the target to cast this spell on itself +5 32 CAST_AURA_NOT_PRESENT Only casts the spell on the target if the target does not have the aura from that spell on itself already. NOTE: You can add the numbers in the decimal column to combine flags. For example if you wanted to use CAST_NO_MELEE_IF_OOM(8) and CAST_TRIGGERED(2) you would simply use 10 in the cast flags field (8 + 2 = 10). -Event flags ------------ +========================================= +Event Flags +========================================= Below is the list of current Event Flags that EventAI can handle. Event flags are handled bitwise. # Decimal Internal Name Description diff --git a/src/game/BattleGround/BattleGround.cpp b/src/game/BattleGround/BattleGround.cpp index b9ab03a4c..020a3b87d 100644 --- a/src/game/BattleGround/BattleGround.cpp +++ b/src/game/BattleGround/BattleGround.cpp @@ -53,6 +53,9 @@ namespace MaNGOS { char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx); + ObjectGuid sourceGuid = i_source ? i_source->GetObjectGuid() : ObjectGuid(); + std::string sourceName = i_source ? i_source->GetName() : ""; + if (i_args) { // we need copy va_list before use or original va_list will corrupted @@ -63,26 +66,12 @@ namespace MaNGOS vsnprintf(str, 2048, text, ap); va_end(ap); - do_helper(data, &str[0]); + ChatHandler::BuildChatPacket(data, i_msgtype, &str[0], LANG_UNIVERSAL, CHAT_TAG_NONE, sourceGuid, sourceName.c_str()); } else - do_helper(data, text); + ChatHandler::BuildChatPacket(data, i_msgtype, text, LANG_UNIVERSAL, CHAT_TAG_NONE, sourceGuid, sourceName.c_str(), sourceGuid, sourceName.c_str()); } private: - void do_helper(WorldPacket& data, char const* text) - { - ObjectGuid targetGuid = i_source ? i_source ->GetObjectGuid() : ObjectGuid(); - - data << uint8(i_msgtype); - data << uint32(LANG_UNIVERSAL); - data << ObjectGuid(targetGuid); // there 0 for BG messages - data << uint32(0); // can be chat msg group or something - data << ObjectGuid(targetGuid); - data << uint32(strlen(text) + 1); - data << text; - data << uint8(i_source ? i_source->GetChatTag() : uint8(CHAT_TAG_NONE)); - } - ChatMsg i_msgtype; int32 i_textId; Player const* i_source; @@ -91,8 +80,8 @@ namespace MaNGOS class BattleGroundYellBuilder { - public: - BattleGroundYellBuilder(uint32 language, int32 textId, Creature const* source, va_list* args = NULL) + public: + BattleGroundYellBuilder(Language language, int32 textId, Creature const* source, va_list* args = nullptr) : i_language(language), i_textId(textId), i_source(source), i_args(args) {} void operator()(WorldPacket& data, int32 loc_idx) { @@ -108,28 +97,13 @@ namespace MaNGOS vsnprintf(str, 2048, text, ap); va_end(ap); - do_helper(data, &str[0]); + ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, &str[0], i_language, CHAT_TAG_NONE, i_source->GetObjectGuid(), i_source->GetName()); } else - do_helper(data, text); + ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, text, i_language, CHAT_TAG_NONE, i_source->GetObjectGuid(), i_source->GetName()); } private: - void do_helper(WorldPacket& data, char const* text) - { - // copyied from BuildMonsterChat - data << uint8(CHAT_MSG_MONSTER_YELL); - data << uint32(i_language); - data << ObjectGuid(i_source->GetObjectGuid()); - data << uint32(0); // 2.1.0 - data << uint32(strlen(i_source->GetName()) + 1); - data << i_source->GetName(); - data << ObjectGuid(); // Unit Target - isn't important for bgs - data << uint32(strlen(text) + 1); - data << text; - data << uint8(0); // ChatTag - for bgs allways 0? - } - - uint32 i_language; + Language i_language; int32 i_textId; Creature const* i_source; va_list* i_args; @@ -150,19 +124,16 @@ namespace MaNGOS char str [2048]; snprintf(str, 2048, text, arg1str, arg2str); - ObjectGuid targetGuid = i_source ? i_source ->GetObjectGuid() : ObjectGuid(); - - data << uint8(i_msgtype); - data << uint32(LANG_UNIVERSAL); - data << ObjectGuid(targetGuid); // there 0 for BG messages - data << uint32(0); // can be chat msg group or something - data << ObjectGuid(targetGuid); - data << uint32(strlen(str) + 1); - data << str; - data << uint8(i_source ? i_source->GetChatTag() : uint8(CHAT_TAG_NONE)); + ObjectGuid guid; + char const* pName = nullptr; + if (i_source) + { + guid = i_source->GetObjectGuid(); + pName = i_source->GetName(); + } + ChatHandler::BuildChatPacket(data, i_msgtype, str, LANG_UNIVERSAL, CHAT_TAG_NONE, ObjectGuid(), nullptr, guid, pName); } private: - ChatMsg i_msgtype; int32 i_textId; Player const* i_source; @@ -1589,7 +1560,7 @@ void BattleGround::SendYellToAll(int32 entry, uint32 language, ObjectGuid guid) Creature* source = GetBgMap()->GetCreature(guid); if (!source) return; - MaNGOS::BattleGroundYellBuilder bg_builder(language, entry, source); + MaNGOS::BattleGroundYellBuilder bg_builder(Language(language), entry, source); MaNGOS::LocalizedPacketDo bg_do(bg_builder); BroadcastWorker(bg_do); } diff --git a/src/game/BattleGround/BattleGroundEY.cpp b/src/game/BattleGround/BattleGroundEY.cpp index 2f97bd95b..b65b0f3bb 100644 --- a/src/game/BattleGround/BattleGroundEY.cpp +++ b/src/game/BattleGround/BattleGroundEY.cpp @@ -178,19 +178,19 @@ void BattleGroundEY::HandleGameObjectCreate(GameObject* go) { case GO_CAPTURE_POINT_BLOOD_ELF_TOWER: m_towers[NODE_BLOOD_ELF_TOWER] = go->GetObjectGuid(); - go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); + go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false); break; case GO_CAPTURE_POINT_FEL_REAVER_RUINS: m_towers[NODE_FEL_REAVER_RUINS] = go->GetObjectGuid(); - go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); + go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false); break; case GO_CAPTURE_POINT_MAGE_TOWER: m_towers[NODE_MAGE_TOWER] = go->GetObjectGuid(); - go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); + go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false); break; case GO_CAPTURE_POINT_DRAENEI_RUINS: m_towers[NODE_DRAENEI_RUINS] = go->GetObjectGuid(); - go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); + go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false); break; } } diff --git a/src/game/ChatCommands/Level1.cpp b/src/game/ChatCommands/Level1.cpp index 001e1f8d3..916a8b9b9 100644 --- a/src/game/ChatCommands/Level1.cpp +++ b/src/game/ChatCommands/Level1.cpp @@ -58,7 +58,7 @@ bool ChatHandler::HandleNpcSayCommand(char* args) return false; } - pCreature->MonsterSay(args, LANG_UNIVERSAL); + pCreature->MonsterSay(args, LANG_UNIVERSAL, m_session->GetPlayer()); return true; } @@ -76,7 +76,7 @@ bool ChatHandler::HandleNpcYellCommand(char* args) return false; } - pCreature->MonsterYell(args, LANG_UNIVERSAL); + pCreature->MonsterYell(args, LANG_UNIVERSAL, m_session->GetPlayer()); return true; } @@ -96,7 +96,7 @@ bool ChatHandler::HandleNpcTextEmoteCommand(char* args) return false; } - pCreature->MonsterTextEmote(args, NULL); + pCreature->MonsterTextEmote(args, m_session->GetPlayer()); return true; } @@ -909,9 +909,9 @@ bool ChatHandler::HandleModifyFactionCommand(char* args) { uint32 factionid = chr->getFaction(); uint32 flag = chr->GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 npcflag = chr->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 NpcFlags = chr->GetUInt32Value(UNIT_NPC_FLAGS); uint32 dyflag = chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS); - PSendSysMessage(LANG_CURRENT_FACTION, chr->GetGUIDLow(), factionid, flag, npcflag, dyflag); + PSendSysMessage(LANG_CURRENT_FACTION, chr->GetGUIDLow(), factionid, flag, NpcFlags, dyflag); } return true; } @@ -938,19 +938,19 @@ bool ChatHandler::HandleModifyFactionCommand(char* args) if (!ExtractOptUInt32(&args, flag, chr->GetUInt32Value(UNIT_FIELD_FLAGS))) return false; - uint32 npcflag; - if (!ExtractOptUInt32(&args, npcflag, chr->GetUInt32Value(UNIT_NPC_FLAGS))) + uint32 NpcFlags; + if (!ExtractOptUInt32(&args, NpcFlags, chr->GetUInt32Value(UNIT_NPC_FLAGS))) return false; uint32 dyflag; if (!ExtractOptUInt32(&args, dyflag, chr->GetUInt32Value(UNIT_DYNAMIC_FLAGS))) return false; - PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(), factionid, flag, npcflag, dyflag); + PSendSysMessage(LANG_YOU_CHANGE_FACTION, chr->GetGUIDLow(), factionid, flag, NpcFlags, dyflag); chr->setFaction(factionid); chr->SetUInt32Value(UNIT_FIELD_FLAGS, flag); - chr->SetUInt32Value(UNIT_NPC_FLAGS, npcflag); + chr->SetUInt32Value(UNIT_NPC_FLAGS, NpcFlags); chr->SetUInt32Value(UNIT_DYNAMIC_FLAGS, dyflag); return true; diff --git a/src/game/ChatCommands/Level2.cpp b/src/game/ChatCommands/Level2.cpp index 6f74994d0..9f689ed88 100644 --- a/src/game/ChatCommands/Level2.cpp +++ b/src/game/ChatCommands/Level2.cpp @@ -1878,7 +1878,7 @@ bool ChatHandler::HandleNpcChangeLevelCommand(char* args) return true; } -// set npcflag of creature +// set NpcFlags of creature bool ChatHandler::HandleNpcFlagCommand(char* args) { if (!*args) @@ -1897,7 +1897,7 @@ bool ChatHandler::HandleNpcFlagCommand(char* args) pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); - WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); + WorldDatabase.PExecuteLog("UPDATE creature_template SET NpcFlags = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); SendSysMessage(LANG_VALUE_SAVED_REJOIN); diff --git a/src/game/ChatCommands/Level3.cpp b/src/game/ChatCommands/Level3.cpp index df4d644e9..712b1e580 100644 --- a/src/game/ChatCommands/Level3.cpp +++ b/src/game/ChatCommands/Level3.cpp @@ -1137,6 +1137,14 @@ bool ChatHandler::HandleReloadMailLevelRewardCommand(char* /*args*/) return true; } +bool ChatHandler::HandleReloadCreaturesStatsCommand(char* /*args*/) +{ + sLog.outString("Re-Loading stats data..."); + sObjectMgr.LoadCreatureClassLvlStats(); + SendGlobalSysMessage("DB table `creature_template_classlevelstats` reloaded."); + return true; +} + bool ChatHandler::HandleLoadScriptsCommand(char* args) { if (!*args) @@ -2472,7 +2480,7 @@ bool ChatHandler::HandleLearnAllMyPetTalentsCommand(char* /*args*/) return false; } - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family); if (!pet_family) { SendSysMessage(LANG_WRONG_PET_TYPE); @@ -4338,7 +4346,7 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/) } uint32 faction = target->getFaction(); - uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 NpcFlagss = target->GetUInt32Value(UNIT_NPC_FLAGS); uint32 displayid = target->GetDisplayId(); uint32 nativeid = target->GetNativeDisplayId(); uint32 Entry = target->GetEntry(); @@ -4358,25 +4366,25 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/) break; if (diff < MAX_DIFFICULTY) - PSendSysMessage(LANG_NPCINFO_CHAR_DIFFICULTY, target->GetGuidStr().c_str(), faction, npcflags, + PSendSysMessage(LANG_NPCINFO_CHAR_DIFFICULTY, target->GetGuidStr().c_str(), faction, NpcFlagss, Entry, target->GetCreatureInfo()->Entry, diff, displayid, nativeid); else - PSendSysMessage(LANG_NPCINFO_CHAR, target->GetGuidStr().c_str(), faction, npcflags, Entry, displayid, nativeid); + PSendSysMessage(LANG_NPCINFO_CHAR, target->GetGuidStr().c_str(), faction, NpcFlagss, Entry, displayid, nativeid); PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str()); - PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid, cInfo->pickpocketLootId, cInfo->SkinLootId); + PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->LootId, cInfo->PickpocketLootId, cInfo->SkinningLootId); PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); - if ((npcflags & UNIT_NPC_FLAG_VENDOR)) + if ((NpcFlagss & UNIT_NPC_FLAG_VENDOR)) { SendSysMessage(LANG_NPCINFO_VENDOR); } - if ((npcflags & UNIT_NPC_FLAG_TRAINER)) + if ((NpcFlagss & UNIT_NPC_FLAG_TRAINER)) { SendSysMessage(LANG_NPCINFO_TRAINER); } diff --git a/src/game/ChatCommands/debugcmds.cpp b/src/game/ChatCommands/debugcmds.cpp index ed7d77515..39fd07e95 100644 --- a/src/game/ChatCommands/debugcmds.cpp +++ b/src/game/ChatCommands/debugcmds.cpp @@ -313,7 +313,7 @@ bool ChatHandler::HandleDebugSendChatMsgCommand(char* args) return false; WorldPacket data; - ChatHandler::FillMessageData(&data, m_session, type, 0, "chan", m_session->GetPlayer()->GetObjectGuid(), msg, m_session->GetPlayer()); + ChatHandler::BuildChatPacket(data, ChatMsg(type), msg, LANG_UNIVERSAL, CHAT_TAG_NONE, m_session->GetPlayer()->GetObjectGuid(), m_session->GetPlayerName()); m_session->SendPacket(&data); return true; } diff --git a/src/game/MotionGenerators/RandomMovementGenerator.cpp b/src/game/MotionGenerators/RandomMovementGenerator.cpp index 13ac7867d..542d6c86b 100644 --- a/src/game/MotionGenerators/RandomMovementGenerator.cpp +++ b/src/game/MotionGenerators/RandomMovementGenerator.cpp @@ -46,13 +46,42 @@ RandomMovementGenerator::RandomMovementGenerator(const Creature& creat template<> void RandomMovementGenerator::_setRandomLocation(Creature& creature) +{ + float destX = i_x; + float destY = i_y; + float destZ = i_z; + + creature.addUnitState(UNIT_STAT_ROAMING_MOVE); + + // check if new random position is assigned, GetReachableRandomPosition may fail + if (creature.GetMap()->GetReachableRandomPosition(&creature, destX, destY, destZ, i_radius)) + { + Movement::MoveSplineInit init(creature); + init.MoveTo(destX, destY, destZ, true); + init.SetWalk(true); + init.Launch(); + if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK)) + i_nextMoveTime.Reset(50); + else + i_nextMoveTime.Reset(urand(3000, 10000)); // Keep a short wait time + } + else + i_nextMoveTime.Reset(50); // Retry later + return; +} + +/* +void RandomMovementGenerator::_setRandomLocation(Creature& creature) { const float angle = rand_norm_f() * (M_PI_F * 2.0f); const float range = rand_norm_f() * i_radius; - float destX = i_x + range * cos(angle); - float destY = i_y + range * sin(angle); - float destZ = i_z + frand(-1, 1) * i_verticalZ; + float destX = i_x; + float destY = i_y; + float destZ = i_z; + // float destX = i_x + range * cos(angle); + // float destY = i_y + range * sin(angle); + // float destZ = i_z + frand(-1, 1) * i_verticalZ; creature.UpdateAllowedPositionZ(destX, destY, destZ); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); @@ -67,6 +96,7 @@ void RandomMovementGenerator::_setRandomLocation(Creature& creature) else i_nextMoveTime.Reset(urand(500, 10000)); } +*/ template<> void RandomMovementGenerator::Initialize(Creature& creature) diff --git a/src/game/MotionGenerators/RandomMovementGenerator.h b/src/game/MotionGenerators/RandomMovementGenerator.h index 685f38172..d8671487d 100644 --- a/src/game/MotionGenerators/RandomMovementGenerator.h +++ b/src/game/MotionGenerators/RandomMovementGenerator.h @@ -27,6 +27,9 @@ #include "MovementGenerator.h" +// define chance for creature to not stop after reaching a waypoint +#define MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK 30 + template class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator > diff --git a/src/game/MotionGenerators/WaypointMovementGenerator.cpp b/src/game/MotionGenerators/WaypointMovementGenerator.cpp index 928ec7262..30f883c90 100644 --- a/src/game/MotionGenerators/WaypointMovementGenerator.cpp +++ b/src/game/MotionGenerators/WaypointMovementGenerator.cpp @@ -142,6 +142,7 @@ void WaypointMovementGenerator::OnArrived(Creature& creature) if (behavior->textid[0]) { + int32 textId = behavior->textid[0]; // Not only one text is set if (behavior->textid[1]) { @@ -153,10 +154,13 @@ void WaypointMovementGenerator::OnArrived(Creature& creature) break; } - creature.MonsterSay(behavior->textid[rand() % i], LANG_UNIVERSAL); + textId = behavior->textid[urand(0, i - 1)]; } + + if (MangosStringLocale const* textData = sObjectMgr.GetMangosStringLocale(textId)) + creature.MonsterText(textData, nullptr); else - creature.MonsterSay(behavior->textid[0], LANG_UNIVERSAL); + sLog.outErrorDb("%s reached waypoint %u, attempted to do text %i, but required text-data could not be found", creature.GetGuidStr().c_str(), i_currentNode, textId); } } diff --git a/src/game/Object/AuctionHouseMgr.cpp b/src/game/Object/AuctionHouseMgr.cpp index 2b25f6274..0aa492468 100644 --- a/src/game/Object/AuctionHouseMgr.cpp +++ b/src/game/Object/AuctionHouseMgr.cpp @@ -846,8 +846,24 @@ void WorldSession::BuildListAuctionItems(std::vector const& aucti if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; - if (usable != 0x00 && _player->CanUseItem(item) != EQUIP_ERR_OK) - continue; + if (usable != 0x00) + { + if (_player->CanUseItem(item) != EQUIP_ERR_OK) + continue; + + if (proto->Class == ITEM_CLASS_RECIPE) + { + if (SpellEntry const* spell = sSpellStore.LookupEntry(proto->Spells[0].SpellId)) + { + SpellEffectEntry const* spellEff = spell->GetSpellEffect(EFFECT_INDEX_0); + if (!spellEff) + continue; + + if (_player->HasSpell(spellEff->EffectTriggerSpell)) + continue; + } + } + } std::string name = proto->Name1; sObjectMgr.GetItemLocaleStrings(proto->ItemId, loc_idx, &name); diff --git a/src/game/Object/Creature.cpp b/src/game/Object/Creature.cpp index 7b1ca1f98..796024cea 100644 --- a/src/game/Object/Creature.cpp +++ b/src/game/Object/Creature.cpp @@ -165,7 +165,7 @@ Creature::Creature(CreatureSubtype subtype) : Unit(), lootForPickPocketed(false), lootForBody(false), lootForSkin(false), m_groupLootTimer(0), m_groupLootId(0), m_lootMoney(0), m_lootGroupRecipientId(0), - m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(5.0f), + m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_aggroDelay(0), m_respawnradius(5.0f), 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), @@ -310,7 +310,7 @@ bool Creature::InitEntry(uint32 Entry, CreatureData const* data /*=NULL*/, GameE SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); // known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE - SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); + SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->UnitClass)); uint32 display_id = ChooseDisplayId(GetCreatureInfo(), data, eventData); if (!display_id) // Cancel load if no display id @@ -374,28 +374,26 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*= if (!InitEntry(Entry, data, eventData)) return false; - m_regenHealth = GetCreatureInfo()->RegenHealth; - // creatures always have melee weapon ready if any SetSheath(SHEATH_STATE_MELEE); - SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f, 100.0f); + SelectLevel(GetCreatureInfo(), preserveHPAndPower ? GetHealthPercent() : 100.0f); if (team == HORDE) setFaction(GetCreatureInfo()->FactionHorde); else setFaction(GetCreatureInfo()->FactionAlliance); - SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->npcflag); + SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->NpcFlags); - uint32 attackTimer = GetCreatureInfo()->baseattacktime; + uint32 attackTimer = GetCreatureInfo()->MeleeBaseAttackTime; SetAttackTime(BASE_ATTACK, attackTimer); SetAttackTime(OFF_ATTACK, attackTimer - attackTimer / 4); - SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->rangeattacktime); + SetAttackTime(RANGED_ATTACK, GetCreatureInfo()->RangedBaseAttackTime); - uint32 unitFlags = GetCreatureInfo()->unit_flags; - uint32 unitFlags2 = GetCreatureInfo()->unit_flags2; + uint32 unitFlags = GetCreatureInfo()->UnitFlags; + uint32 unitFlags2 = GetCreatureInfo()->UnitFlags2; // we may need to append or remove additional flags if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT)) @@ -406,15 +404,15 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData* data /*= // preserve all current dynamic flags if exist uint32 dynFlags = GetUInt32Value(UNIT_DYNAMIC_FLAGS); - SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynFlags ? dynFlags : GetCreatureInfo()->dynamicflags); + SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynFlags ? dynFlags : GetCreatureInfo()->DynamicFlags); - SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor)); - SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1)); - SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2)); - SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->resistance3)); - SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->resistance4)); - SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->resistance5)); - SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->resistance6)); + SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->Armor)); + SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->ResistanceHoly)); + SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->ResistanceFire)); + SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(GetCreatureInfo()->ResistanceNature)); + SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(GetCreatureInfo()->ResistanceFrost)); + SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(GetCreatureInfo()->ResistanceShadow)); + SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(GetCreatureInfo()->ResistanceArcane)); SetCanModifyStats(true); UpdateAllStats(); @@ -518,6 +516,7 @@ void Creature::Update(uint32 update_diff, uint32 diff) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Respawning..."); m_respawnTime = 0; + m_aggroDelay = sWorld.getConfig(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY); lootForPickPocketed = false; lootForBody = false; lootForSkin = false; @@ -535,6 +534,7 @@ void Creature::Update(uint32 update_diff, uint32 diff) CreatureInfo const* cinfo = GetCreatureInfo(); SelectLevel(cinfo); + UpdateAllStats(); // to be sure stats is correct regarding level of the creature SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); if (m_IsDeadByDefault) { @@ -584,6 +584,11 @@ void Creature::Update(uint32 update_diff, uint32 diff) } case ALIVE: { + if (m_aggroDelay <= update_diff) + m_aggroDelay = 0; + else + m_aggroDelay -= update_diff; + if (m_IsDeadByDefault) { if (m_corpseDecayTimer <= update_diff) @@ -819,7 +824,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const return false; // pet trainers not have spells in fact now - if (GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS) + if (GetCreatureInfo()->TrainerType != TRAINER_TYPE_PETS) { TrainerSpellData const* cSpells = GetTrainerSpells(); TrainerSpellData const* tSpells = GetTrainerTemplateSpells(); @@ -833,15 +838,15 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const } } - switch (GetCreatureInfo()->trainer_type) + switch (GetCreatureInfo()->TrainerType) { case TRAINER_TYPE_CLASS: - if (pPlayer->getClass() != GetCreatureInfo()->trainer_class) + if (pPlayer->getClass() != GetCreatureInfo()->TrainerClass) { if (msg) { pPlayer->PlayerTalkClass->ClearMenus(); - switch (GetCreatureInfo()->trainer_class) + switch (GetCreatureInfo()->TrainerClass) { case CLASS_DRUID: pPlayer->PlayerTalkClass->SendGossipMenu(4913, GetObjectGuid()); break; case CLASS_HUNTER: pPlayer->PlayerTalkClass->SendGossipMenu(10090, GetObjectGuid()); break; @@ -869,7 +874,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const } break; case TRAINER_TYPE_MOUNTS: - if (GetCreatureInfo()->trainer_race && pPlayer->getRace() != GetCreatureInfo()->trainer_race) + if (GetCreatureInfo()->TrainerRace && pPlayer->getRace() != GetCreatureInfo()->TrainerRace) { // Allowed to train if exalted if (FactionTemplateEntry const* faction_template = getFactionTemplateEntry()) @@ -881,7 +886,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const if (msg) { pPlayer->PlayerTalkClass->ClearMenus(); - switch (GetCreatureInfo()->trainer_class) + switch (GetCreatureInfo()->TrainerClass) { case RACE_DWARF: pPlayer->PlayerTalkClass->SendGossipMenu(5865, GetObjectGuid()); break; case RACE_GNOME: pPlayer->PlayerTalkClass->SendGossipMenu(4881, GetObjectGuid()); break; @@ -899,7 +904,7 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const } break; case TRAINER_TYPE_TRADESKILLS: - if (GetCreatureInfo()->trainer_spell && !pPlayer->HasSpell(GetCreatureInfo()->trainer_spell)) + if (GetCreatureInfo()->TrainerSpell && !pPlayer->HasSpell(GetCreatureInfo()->TrainerSpell)) { if (msg) { @@ -953,8 +958,8 @@ bool Creature::CanInteractWithBattleMaster(Player* pPlayer, bool msg) const bool Creature::CanTrainAndResetTalentsOf(Player* pPlayer) const { return pPlayer->getLevel() >= 10 - && GetCreatureInfo()->trainer_type == TRAINER_TYPE_CLASS - && pPlayer->getClass() == GetCreatureInfo()->trainer_class; + && GetCreatureInfo()->TrainerType == TRAINER_TYPE_CLASS + && pPlayer->getClass() == GetCreatureInfo()->TrainerType; } void Creature::PrepareBodyLootState() @@ -965,9 +970,9 @@ void Creature::PrepareBodyLootState() if (!lootForBody) { // have normal loot - if (GetCreatureInfo()->maxgold > 0 || GetCreatureInfo()->lootid || + if (GetCreatureInfo()->MaxLootGold > 0 || GetCreatureInfo()->LootId || // ... or can have skinning after - (GetCreatureInfo()->SkinLootId && sWorld.getConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW))) + (GetCreatureInfo()->SkinningLootId && sWorld.getConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW))) { SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); return; @@ -977,7 +982,7 @@ void Creature::PrepareBodyLootState() lootForBody = true; // pass this loot mode // if not have normal loot allow skinning if need - if (!lootForSkin && GetCreatureInfo()->SkinLootId) + if (!lootForSkin && GetCreatureInfo()->SkinningLootId) { RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); @@ -1162,25 +1167,59 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) WorldDatabase.CommitTransaction(); } -void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float percentMana) + +void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 100.0f*/) { - uint32 rank = IsPet() ? 0 : cinfo->Rank; + uint32 rank = IsPet() ? 0 : cinfo->Rank; // TODO :: IsPet probably not needed here // level - uint32 minlevel = std::min(cinfo->maxlevel, cinfo->minlevel); - uint32 maxlevel = std::max(cinfo->maxlevel, cinfo->minlevel); + uint32 const minlevel = cinfo->MinLevel; + uint32 const maxlevel = cinfo->MaxLevel; uint32 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel); SetLevel(level); - float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel); + ////////////////////////////////////////////////////////////////////////// + // Calculate level dependend stats + ////////////////////////////////////////////////////////////////////////// + + uint32 health; + uint32 mana; + + if (CreatureClassLvlStats const* cCLS = sObjectMgr.GetCreatureClassLvlStats(level, cinfo->UnitClass, cinfo->Expansion)) + { + // Use Creature Stats to calculate stat values + + // health + health = cCLS->BaseHealth * cinfo->HealthMultiplier; + + // mana + mana = cCLS->BaseMana * cinfo->PowerMultiplier; + } + else + { + // Use old style to calculate stat values + float rellevel = maxlevel == minlevel ? 0 : (float(level - minlevel)) / (maxlevel - minlevel); + + // health + uint32 minhealth = std::min(cinfo->MaxLevelHealth, cinfo->MinLevelHealth); + uint32 maxhealth = std::max(cinfo->MaxLevelHealth, cinfo->MinLevelHealth); + health = uint32(minhealth + uint32(rellevel * (maxhealth - minhealth))); + + // mana + uint32 minmana = std::min(cinfo->MaxLevelMana, cinfo->MinLevelMana); + uint32 maxmana = std::max(cinfo->MaxLevelMana, cinfo->MinLevelMana); + mana = minmana + uint32(rellevel * (maxmana - minmana)); + } + + health *= _GetHealthMod(rank); // Apply custom config settting + if (health < 1) + health = 1; + + ////////////////////////////////////////////////////////////////////////// + // Set values + ////////////////////////////////////////////////////////////////////////// // health - float healthmod = _GetHealthMod(rank); - - uint32 minhealth = std::min(cinfo->maxhealth, cinfo->minhealth); - uint32 maxhealth = std::max(cinfo->maxhealth, cinfo->minhealth); - uint32 health = uint32(healthmod * (minhealth + uint32(rellevel * (maxhealth - minhealth)))); - SetCreateHealth(health); SetMaxHealth(health); @@ -1189,33 +1228,51 @@ void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth, float else SetHealthPercent(percentHealth); - // mana - uint32 minmana = std::min(cinfo->maxmana, cinfo->minmana); - uint32 maxmana = std::max(cinfo->maxmana, cinfo->minmana); - uint32 mana = minmana + uint32(rellevel * (maxmana - minmana)); - - SetCreateMana(mana); - SetMaxPower(POWER_MANA, mana); // MAX Mana - SetPower(POWER_MANA, mana); - - // TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc) - SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health)); - SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, float(mana)); + + // all power types + for (int i = POWER_MANA; i <= POWER_RUNIC_POWER; ++i) + { + uint32 maxValue = 0; + + switch (i) + { + case POWER_MANA: maxValue = mana; break; + case POWER_RAGE: maxValue = 0; break; + case POWER_FOCUS: maxValue = POWER_FOCUS_DEFAULT; break; + case POWER_ENERGY: maxValue = POWER_ENERGY_DEFAULT * cinfo->PowerMultiplier; break; + case POWER_RUNE: maxValue = 0; break; + case POWER_RUNIC_POWER: maxValue = 0; break; + } + + uint32 value = maxValue; + + // For non regenerating powers set 0 + if ((i == POWER_ENERGY || i == POWER_MANA) && !IsRegeneratingPower()) + value = 0; + + // Mana requires an extra field to be set + if (i == POWER_MANA) + SetCreateMana(value); + + SetMaxPower(Powers(i), maxValue); + SetPower(Powers(i), value); + SetModifierValue(UnitMods(UNIT_MOD_POWER_START + i), BASE_VALUE, float(value)); + } // damage float damagemod = _GetDamageMod(rank); - SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); - SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod); - SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); - SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); + SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->MinMeleeDmg * damagemod); + SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->MaxMeleeDmg * damagemod); - SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->minrangedmg * damagemod); - SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->maxrangedmg * damagemod); + SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->MinRangedDmg * damagemod); + SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->MaxRangedDmg * damagemod); - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod); + SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->MeleeAttackPower * damagemod); } float Creature::_GetHealthMod(int32 Rank) @@ -1370,7 +1427,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map* map) SetHealth(m_deathState == ALIVE ? curhealth : 0); SetPower(POWER_MANA, data->curmana); - SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); + SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool)); // checked at creature_template loading m_defaultMovementType = MovementGeneratorType(data->movementType); @@ -1561,7 +1618,7 @@ void Creature::SetDeathState(DeathState s) if (GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_RESPAWN) ClearTemporaryFaction(); - SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool)); + SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->DamageSchool)); // Dynamic flags may be adjusted by spells. Clear them // first and let spell from *addon apply where needed. @@ -1570,7 +1627,7 @@ void Creature::SetDeathState(DeathState s) // Flags after LoadCreatureAddon. Any spell in *addon // will not be able to adjust these. - SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->npcflag); + SetUInt32Value(UNIT_NPC_FLAGS, GetCreatureInfo()->NpcFlags); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); SetWalk(true, true); @@ -1634,7 +1691,7 @@ bool Creature::IsImmuneToSpellEffect(SpellEntry const* spellInfo, SpellEffectInd return true; // Taunt immunity special flag check - if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NOT_TAUNTABLE) + if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NOT_TAUNTABLE) { // Taunt aura apply check if (spellEffect->Effect == SPELL_EFFECT_APPLY_AURA) @@ -1775,7 +1832,7 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const if (pl->isGameMaster()) return true; - if (GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INVISIBLE) + if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INVISIBLE) return false; // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0 @@ -1822,6 +1879,10 @@ void Creature::CallAssistance() if (!m_AlreadyCallAssistance && getVictim() && !IsCharmed()) { SetNoCallAssistance(true); + + if (GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CALL_ASSIST) + return; + AI()->SendAIEventAround(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); } } @@ -1888,6 +1949,12 @@ bool Creature::CanInitiateAttack() if (isPassiveToHostile()) return false; + if (m_aggroDelay != 0) + return false; + + if (!CanAttackByItself()) + return false; + return true; } @@ -2350,8 +2417,8 @@ VendorItemData const* Creature::GetVendorItems() const VendorItemData const* Creature::GetVendorTemplateItems() const { - uint32 vendorId = GetCreatureInfo()->vendorId; - return vendorId ? sObjectMgr.GetNpcVendorTemplateItemList(vendorId) : NULL; + uint32 VendorTemplateId = GetCreatureInfo()->VendorTemplateId; + return VendorTemplateId ? sObjectMgr.GetNpcVendorTemplateItemList(VendorTemplateId) : NULL; } uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem) @@ -2428,8 +2495,8 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us TrainerSpellData const* Creature::GetTrainerTemplateSpells() const { - uint32 trainerId = GetCreatureInfo()->trainerId; - return trainerId ? sObjectMgr.GetNpcTrainerTemplateSpells(trainerId) : NULL; + uint32 TrainerTemplateId = GetCreatureInfo()->TrainerTemplateId; + return TrainerTemplateId ? sObjectMgr.GetNpcTrainerTemplateSpells(TrainerTemplateId) : NULL; } TrainerSpellData const* Creature::GetTrainerSpells() const @@ -2469,11 +2536,11 @@ void Creature::ClearTemporaryFaction() // Reset to original faction setFaction(GetCreatureInfo()->FactionAlliance); // Reset UNIT_FLAG_NON_ATTACKABLE, UNIT_FLAG_OOC_NOT_ATTACKABLE or UNIT_FLAG_PASSIVE flags - if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_NON_ATTACKABLE && GetCreatureInfo()->unit_flags & UNIT_FLAG_NON_ATTACKABLE) + if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_NON_ATTACKABLE && GetCreatureInfo()->UnitFlags & UNIT_FLAG_NON_ATTACKABLE) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK && GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !IsInCombat()) + if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK && GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !IsInCombat()) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_PASSIVE && GetCreatureInfo()->unit_flags & UNIT_FLAG_PASSIVE) + if (m_temporaryFactionFlags & TEMPFACTION_TOGGLE_PASSIVE && GetCreatureInfo()->UnitFlags & UNIT_FLAG_PASSIVE) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); m_temporaryFactionFlags = TEMPFACTION_NONE; diff --git a/src/game/Object/Creature.h b/src/game/Object/Creature.h index 8d2e54421..a49fcd444 100644 --- a/src/game/Object/Creature.h +++ b/src/game/Object/Creature.h @@ -49,17 +49,23 @@ struct GameEventCreatureData; enum CreatureFlagsExtra { - CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group - CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) - CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry - CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry - CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block - CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks - CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP - CREATURE_FLAG_EXTRA_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures) - CREATURE_FLAG_EXTRA_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me - CREATURE_FLAG_EXTRA_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro - CREATURE_FLAG_EXTRA_GUARD = 0x00000400, // creature is a guard + CREATURE_EXTRA_FLAG_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group + CREATURE_EXTRA_FLAG_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility) + CREATURE_EXTRA_FLAG_NO_PARRY = 0x00000004, // creature can't parry + CREATURE_EXTRA_FLAG_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry + CREATURE_EXTRA_FLAG_NO_BLOCK = 0x00000010, // creature can't block + CREATURE_EXTRA_FLAG_NO_CRUSH = 0x00000020, // creature can't do crush attacks + CREATURE_EXTRA_FLAG_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP + CREATURE_EXTRA_FLAG_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures) + CREATURE_EXTRA_FLAG_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me + CREATURE_EXTRA_FLAG_AGGRO_ZONE = 0x00000200, // creature sets itself in combat with zone on aggro + CREATURE_EXTRA_FLAG_GUARD = 0x00000400, // creature is a guard + CREATURE_EXTRA_FLAG_NO_CALL_ASSIST = 0x00000800, // creature shouldn't call for assistance on aggro + CREATURE_EXTRA_FLAG_ACTIVE = 0x00001000, // creature is active object. Grid of this creature will be loaded and creature set as active + CREATURE_EXTRA_FLAG_MMAP_FORCE_ENABLE = 0x00002000, // creature is forced to use MMaps + CREATURE_EXTRA_FLAG_MMAP_FORCE_DISABLE = 0x00004000, // creature is forced to NOT use MMaps + CREATURE_EXTRA_FLAG_WALK_IN_WATER = 0x00008000, // creature is forced to walk in water even it can swim + CREATURE_EXTRA_FLAG_HAVE_NO_SWIM_ANIMATION = 0x00010000, // we have to not set "swim" animation or creature will have "no animation" }; // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform @@ -72,8 +78,124 @@ enum CreatureFlagsExtra #define MAX_KILL_CREDIT 2 #define MAX_CREATURE_MODEL 4 + // from `creature_template` table struct CreatureInfo +{ + uint32 Entry; + char* Name; + char* SubName; + char* IconName; + uint32 MinLevel; + uint32 MaxLevel; + uint32 DifficultyEntry[MAX_DIFFICULTY - 1]; + uint32 ModelId[MAX_CREATURE_MODEL]; + uint32 FactionAlliance; + uint32 FactionHorde; + float Scale; + uint32 Family; // enum CreatureFamily values (optional) + uint32 CreatureType; // enum CreatureType values + uint32 InhabitType; + uint32 RegenerateStats; + bool RacialLeader; + uint32 NpcFlags; + uint32 UnitFlags; // enum UnitFlags mask values + uint32 UnitFlags2; // enum UnitFlags2 mask values + uint32 DynamicFlags; + uint32 ExtraFlags; + uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values + float SpeedWalk; + float SpeedRun; + uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures. + uint32 Rank; + int32 Expansion; // creature expansion, important for stats, CAN BE -1 as marker for some invalid cases. + float HealthMultiplier; + float PowerMultiplier; + float DamageMultiplier; + float DamageVariance; + float ArmorMultiplier; + float ExperienceMultiplier; + uint32 MinLevelHealth; + uint32 MaxLevelHealth; + uint32 MinLevelMana; + uint32 MaxLevelMana; + float MinMeleeDmg; + float MaxMeleeDmg; + float MinRangedDmg; + float MaxRangedDmg; + uint32 Armor; + uint32 MeleeAttackPower; + uint32 RangedAttackPower; + uint32 MeleeBaseAttackTime; + uint32 RangedBaseAttackTime; + uint32 DamageSchool; + uint32 MinLootGold; + uint32 MaxLootGold; + uint32 LootId; + uint32 PickpocketLootId; + uint32 SkinningLootId; + uint32 KillCredit[MAX_KILL_CREDIT]; + uint32 QuestItems[6]; + uint32 MechanicImmuneMask; + int32 ResistanceHoly; + int32 ResistanceFire; + int32 ResistanceNature; + int32 ResistanceFrost; + int32 ResistanceShadow; + int32 ResistanceArcane; + uint32 PetSpellDataId; + uint32 MovementType; + uint32 MovementTemplateId; + uint32 TrainerType; + uint32 TrainerSpell; + uint32 TrainerClass; + uint32 TrainerRace; + uint32 TrainerTemplateId; + uint32 VendorTemplateId; + uint32 EquipmentTemplateId; + uint32 VehicleTemplateId; + uint32 GossipMenuId; + char const* AIName; + + // helpers + HighGuid GetHighGuid() const + { + return VehicleTemplateId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT; + } + + ObjectGuid GetObjectGuid(uint32 lowguid) const { return ObjectGuid(GetHighGuid(), Entry, lowguid); } + + SkillType GetRequiredLootSkill() const + { + if (CreatureTypeFlags & CREATURE_TYPEFLAGS_HERBLOOT) + return SKILL_HERBALISM; + else if (CreatureTypeFlags & CREATURE_TYPEFLAGS_MININGLOOT) + return SKILL_MINING; + else if (CreatureTypeFlags & CREATURE_TYPEFLAGS_ENGINEERLOOT) + return SKILL_ENGINEERING; + else + return SKILL_SKINNING; // normal case + } + + bool IsExotic() const + { + return (CreatureTypeFlags & CREATURE_TYPEFLAGS_EXOTIC); + } + + bool isTameable(bool exotic) const + { + if (CreatureType != CREATURE_TYPE_BEAST || Family == 0 || (CreatureTypeFlags & CREATURE_TYPEFLAGS_TAMEABLE) == 0) + return false; + + // if can tame exotic then can tame any temable + return exotic || !IsExotic(); + } +}; + + +// from `creature_template` table +/* +struct CreatureInfo { uint32 Entry; uint32 DifficultyEntry[MAX_DIFFICULTY - 1]; @@ -83,16 +205,16 @@ struct CreatureInfo char* SubName; char* IconName; uint32 GossipMenuId; - uint32 minlevel; - uint32 maxlevel; - uint32 minhealth; + uint32 MinLevel; + uint32 MaxLevel; + uint32 MinLevelHealth; uint32 maxhealth; - uint32 minmana; + uint32 MinLevelMana; uint32 maxmana; uint32 armor; uint32 FactionAlliance; uint32 FactionHorde; - uint32 npcflag; + uint32 NpcFlags; float speed_walk; float speed_run; float Scale; @@ -102,25 +224,25 @@ struct CreatureInfo uint32 dmgschool; uint32 attackpower; float dmg_multiplier; - uint32 baseattacktime; - uint32 rangeattacktime; - uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures. - uint32 unit_flags; // enum UnitFlags mask values - uint32 unit_flags2; // enum UnitFlags2 mask values + uint32 MeleeAttackPower; + uint32 RangedAttackPower; + uint32 UnitClass; // enum Classes. Note only 4 classes are known for creatures. + uint32 UnitFlags; // enum UnitFlags mask values + uint32 UnitFlags2; // enum UnitFlags2 mask values uint32 dynamicflags; uint32 family; // enum CreatureFamily values (optional) - uint32 trainer_type; + uint32 TrainerType; uint32 trainer_spell; - uint32 trainer_class; + uint32 TrainerClass; uint32 trainer_race; float minrangedmg; float maxrangedmg; uint32 rangedattackpower; uint32 type; // enum CreatureType values uint32 CreatureTypeFlags; // enum CreatureTypeFlags mask values - uint32 lootid; + uint32 Lootid; uint32 pickpocketLootId; - uint32 SkinLootId; + uint32 SkinningLootId; int32 resistance1; int32 resistance2; int32 resistance3; @@ -128,7 +250,7 @@ struct CreatureInfo int32 resistance5; int32 resistance6; uint32 PetSpellDataId; - uint32 mingold; + uint32 MinLootGold; uint32 maxgold; char const* AIName; uint32 MovementType; @@ -141,8 +263,8 @@ struct CreatureInfo bool RegenHealth; uint32 VehicleTemplateId; uint32 EquipmentTemplateId; - uint32 trainerId; - uint32 vendorId; + uint32 TrainerTemplateId; + uint32 VendorTemplateId; uint32 MechanicImmuneMask; uint32 ExtraFlags; @@ -179,7 +301,7 @@ struct CreatureInfo // if can tame exotic then can tame any temable return exotic || !IsExotic(); } -}; +}; */ struct CreatureTemplateSpells { @@ -330,6 +452,12 @@ enum SelectFlags SELECT_FLAG_NOT_IN_MELEE_RANGE = 0x080, }; +enum RegenStatsFlags +{ + REGEN_FLAG_HEALTH = 0x001, + REGEN_FLAG_POWER = 0x002, +}; + // Vendors enum @@ -501,7 +629,7 @@ class Creature : public Unit bool Create(uint32 guidlow, CreatureCreatePos& cPos, CreatureInfo const* cinfo, Team team = TEAM_NONE, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL); bool LoadCreatureAddon(bool reload); - void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f, float percentMana = 100.0f); + void SelectLevel(const CreatureInfo* cinfo, float percentHealth = 100.0f); void LoadEquipment(uint32 equip_entry, bool force = false); bool HasStaticDBSpawnData() const; // listed in `creature` table and have fixed in DB guid @@ -523,12 +651,14 @@ class Creature : public Unit void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } uint32 GetCorpseDelay() const { return m_corpseDelay; } bool IsRacialLeader() const { return GetCreatureInfo()->RacialLeader; } - bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_CIVILIAN; } - bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_GUARD; } + bool IsCivilian() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_CIVILIAN; } + bool IsGuard() const { return GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_GUARD; } bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; } - virtual bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } - bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || HasAuraType(SPELL_AURA_FLY); } + bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } + bool IsSwimming() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_SWIMMING))); } + bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_FLY_ANIM) || m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_LEVITATING | MOVEFLAG_CAN_FLY)); } + bool IsFlying() const { return (m_movementInfo.HasMovementFlag((MovementFlags)(MOVEFLAG_FLYING | MOVEFLAG_LEVITATING))); } bool IsTrainerOf(Player* player, bool msg) const; bool CanInteractWithBattleMaster(Player* player, bool msg) const; @@ -745,7 +875,8 @@ class Creature : public Unit bool HasInvolvedQuest(uint32 quest_id) const override; GridReference& GetGridRef() { return m_gridRef; } - bool IsRegeneratingHealth() { return m_regenHealth; } + bool IsRegeneratingHealth() { return GetCreatureInfo()->RegenerateStats & REGEN_FLAG_HEALTH; } + bool IsRegeneratingPower() { return GetCreatureInfo()->RegenerateStats & REGEN_FLAG_POWER; } virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; } virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const { @@ -802,6 +933,7 @@ class Creature : public Unit time_t m_respawnTime; // (secs) time of next respawn uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance + uint32 m_aggroDelay; // (msecs)delay between respawn and aggro due to movement float m_respawnradius; CreatureSubtype m_subtype; // set in Creatures subclasses for fast it detect without dynamic_cast use diff --git a/src/game/Object/CreatureEventAI.cpp b/src/game/Object/CreatureEventAI.cpp index 9f0734437..79b694a23 100644 --- a/src/game/Object/CreatureEventAI.cpp +++ b/src/game/Object/CreatureEventAI.cpp @@ -732,7 +732,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; case ACTION_T_COMBAT_MOVEMENT: // ignore no affect case - if (m_isCombatMovement == (action.combat_movement.state != 0)) + if (m_isCombatMovement == (action.combat_movement.state != 0) || m_creature->IsNonMeleeSpellCasted(false)) return; SetCombatMovement(action.combat_movement.state != 0, true); @@ -966,63 +966,38 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 m_throwAIEventMask = action.setThrowMask.eventTypeMask; break; } - case ACTION_T_SUMMON_UNIQUE: + case ACTION_T_SET_STAND_STATE: { - Creature* pCreature = NULL; - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_creature, action.summon_unique.creatureId, true, false, 100, true); - MaNGOS::CreatureLastSearcher searcher(pCreature, u_check); - Cell::VisitGridObjects(m_creature, searcher, 100); - WorldObject* pSpawn = NULL; - pSpawn = pCreature; - - if (!pSpawn) - { - Unit* target = GetTargetByType(action.summon_unique.target, pActionInvoker, pAIEventSender, reportTargetError); - - if (!target && reportTargetError) - sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SUMMON_UNIQUE(%u), target-type %u", EventId, action.type, action.summon_unique.target); - - CreatureEventAI_Summon_Map::const_iterator i = sEventAIMgr.GetCreatureEventAISummonMap().find(action.summon_unique.spawnId); - if (i == sEventAIMgr.GetCreatureEventAISummonMap().end()) - { - sLog.outErrorEventAI("Failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", action.summon_unique.creatureId, action.summon_unique.spawnId, EventId, m_creature->GetEntry()); - return; - } - - Creature* pCreature = NULL; - if ((*i).second.SpawnTimeSecs) - pCreature = m_creature->SummonCreature(action.summon_unique.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs); - else - pCreature = m_creature->SummonCreature(action.summon_unique.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OOC_DESPAWN, 0); - - if (!pCreature) - sLog.outErrorEventAI("Failed to spawn creature %u. EventId %d.Creature %d", action.summon_unique.creatureId, EventId, m_creature->GetEntry()); - else if (action.summon_unique.target != TARGET_T_SELF && target) - pCreature->AI()->AttackStart(target); - - break; - } - - if (pSpawn) - { - return; - } + m_creature->SetStandState(action.setStandState.standState); + break; } - case ACTION_T_EMOTE_TARGET: + case ACTION_T_CHANGE_MOVEMENT: { - Unit* pCreature = m_creature->GetMap()->GetCreature(ObjectGuid(HIGHGUID_UNIT, action.emoteTarget.targetGuid)); - if (!pCreature) + switch (action.changeMovement.movementType) { - sLog.outErrorEventAI("Event %d. Cannot find creature by guid %d", EventId, action.emoteTarget.targetGuid); - return; + case IDLE_MOTION_TYPE: + m_creature->GetMotionMaster()->MoveIdle(); + break; + case RANDOM_MOTION_TYPE: + m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), float(action.changeMovement.wanderDistance)); + break; + case WAYPOINT_MOTION_TYPE: + m_creature->GetMotionMaster()->MoveWaypoint(); + break; } + break; + } + case ACTION_T_DYNAMIC_MOVEMENT: + { + if (action.dynamicMovement.state && m_DynamicMovement || !action.dynamicMovement.state && !m_DynamicMovement) + break; - - m_creature->SetFacingToObject(pCreature); - m_creature->HandleEmote(action.emoteTarget.emoteId); + m_DynamicMovement = action.dynamicMovement.state; + SetCombatMovement(!m_DynamicMovement, true); break; } default: + sLog.outError("CreatureEventAi::ProcessAction(): action(%u) not implemented", static_cast(action.type)); break; } } diff --git a/src/game/Object/CreatureEventAI.h b/src/game/Object/CreatureEventAI.h index f710409d7..2c304c027 100644 --- a/src/game/Object/CreatureEventAI.h +++ b/src/game/Object/CreatureEventAI.h @@ -121,10 +121,12 @@ enum EventAI_ActionType ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health) ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount) ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values. - ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused + ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused ACTION_T_SET_THROW_MASK = 46, // EventTypeMask, unused, unused - ACTION_T_SUMMON_UNIQUE = 47, // CreatureId, Target, SpawnId - ACTION_T_EMOTE_TARGET = 48, // EmoteId, TargetGuid + ACTION_T_SET_STAND_STATE = 47, // StandState, unused, unused + ACTION_T_CHANGE_MOVEMENT = 48, // MovementType, WanderDistance, unused + ACTION_T_DYNAMIC_MOVEMENT = 49, // EnableDynamicMovement (1 = on; 0 = off) + ACTION_T_END, }; @@ -173,7 +175,7 @@ enum SpawnedEventMode struct CreatureEventAI_Action { - EventAI_ActionType type: 16; + EventAI_ActionType type : 16; union { // ACTION_T_TEXT = 1 @@ -384,7 +386,6 @@ struct CreatureEventAI_Action uint32 creatureId; // set one from fields (or 0 for both to dismount) uint32 modelId; } mount; - // ACTION_T_CHANCED_TEXT = 44 struct { @@ -405,19 +406,27 @@ struct CreatureEventAI_Action uint32 unused1; uint32 unused2; } setThrowMask; - // ACTION_T_SUMMON_UNIQUE = 47 + // ACTION_T_SET_STAND_STATE = 47 struct { - uint32 creatureId; - uint32 target; - uint32 spawnId; - } summon_unique; - // ACTION_T_EMOTE_TARGET = 48 + uint32 standState; + uint32 unused1; + uint32 unused2; + } setStandState; + // ACTION_T_CHANGE_MOVEMENT = 48 struct { - uint32 emoteId; - uint32 targetGuid; - } emoteTarget; + uint32 movementType; + uint32 wanderDistance; + uint32 unused1; + } changeMovement; + // ACTION_T_DYNAMIC_MOVEMENT = 49 + struct + { + uint32 state; // bool: 1 = on; 0 = off + uint32 unused1; + uint32 unused2; + } dynamicMovement; // RAW struct { @@ -672,6 +681,8 @@ class CreatureEventAI : public CreatureAI uint8 m_Phase; // Current phase, max 32 phases bool m_MeleeEnabled; // If we allow melee auto attack + bool m_DynamicMovement; // Core will control creatures movement if this is enabled + bool m_HasOOCLoSEvent; // Cache if a OOC-LoS Event exists uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask diff --git a/src/game/Object/CreatureEventAIMgr.cpp b/src/game/Object/CreatureEventAIMgr.cpp index f889a85fc..6c82bde0d 100644 --- a/src/game/Object/CreatureEventAIMgr.cpp +++ b/src/game/Object/CreatureEventAIMgr.cpp @@ -873,6 +873,21 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() continue; } break; + case ACTION_T_SET_STAND_STATE: + if (action.setStandState.standState >= MAX_UNIT_STAND_STATE) + { + sLog.outErrorEventAI("Event %u Action %u uses invalid unit stand state %u (must be smaller than %u)", i, j + 1, action.setStandState.standState, MAX_UNIT_STAND_STATE); + continue; + } + break; + case ACTION_T_CHANGE_MOVEMENT: + if (action.changeMovement.movementType >= MAX_DB_MOTION_TYPE) + { + sLog.outErrorEventAI("Event %u Action %u uses invalid movement type %u (must be smaller than %u)", i, j + 1, action.changeMovement.movementType, MAX_DB_MOTION_TYPE); + continue; + } + break; + default: sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type); break; diff --git a/src/game/Object/Formulas.h b/src/game/Object/Formulas.h index 7be483fd7..5ecdc7a4f 100644 --- a/src/game/Object/Formulas.h +++ b/src/game/Object/Formulas.h @@ -119,7 +119,7 @@ namespace MaNGOS { if (u->GetTypeId() == TYPEID_UNIT && ( ((Creature*)u)->IsTotem() || ((Creature*)u)->IsPet() || - (((Creature*)u)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) + (((Creature*)u)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_XP_AT_KILL))) return 0; uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(), pl->GetZoneId())); diff --git a/src/game/Object/GameObject.cpp b/src/game/Object/GameObject.cpp index 4451dda73..58415db44 100644 --- a/src/game/Object/GameObject.cpp +++ b/src/game/Object/GameObject.cpp @@ -2048,30 +2048,27 @@ bool GameObject::HasStaticDBSpawnData() const return sObjectMgr.GetGOData(GetGUIDLow()) != NULL; } -void GameObject::SetCapturePointSlider(float value) +void GameObject::SetCapturePointSlider(float value, bool isLocked) { GameObjectInfo const* info = GetGOInfo(); + m_captureSlider = value; + // only activate non-locked capture point - if (value >= 0) - { - m_captureSlider = value; - { SetLootState(GO_ACTIVATED); } - } - else - m_captureSlider = -value; + if (!isLocked) + SetLootState(GO_ACTIVATED); // set the state of the capture point based on the slider value if ((int)m_captureSlider == CAPTURE_SLIDER_ALLIANCE) - { m_captureState = CAPTURE_STATE_WIN_ALLIANCE; } + m_captureState = CAPTURE_STATE_WIN_ALLIANCE; else if ((int)m_captureSlider == CAPTURE_SLIDER_HORDE) - { m_captureState = CAPTURE_STATE_WIN_HORDE; } + m_captureState = CAPTURE_STATE_WIN_HORDE; else if (m_captureSlider > CAPTURE_SLIDER_MIDDLE + info->capturePoint.neutralPercent * 0.5f) - { m_captureState = CAPTURE_STATE_PROGRESS_ALLIANCE; } + m_captureState = CAPTURE_STATE_PROGRESS_ALLIANCE; else if (m_captureSlider < CAPTURE_SLIDER_MIDDLE - info->capturePoint.neutralPercent * 0.5f) - { m_captureState = CAPTURE_STATE_PROGRESS_HORDE; } + m_captureState = CAPTURE_STATE_PROGRESS_HORDE; else - { m_captureState = CAPTURE_STATE_NEUTRAL; } + m_captureState = CAPTURE_STATE_NEUTRAL; } void GameObject::TickCapturePoint() diff --git a/src/game/Object/GameObject.h b/src/game/Object/GameObject.h index 7dd8115bb..ee29180b5 100644 --- a/src/game/Object/GameObject.h +++ b/src/game/Object/GameObject.h @@ -622,11 +622,11 @@ enum CapturePointState CAPTURE_STATE_WIN_HORDE }; -enum CapturePointSlider +enum CapturePointSliderValue { - CAPTURE_SLIDER_ALLIANCE = 100, // full alliance - CAPTURE_SLIDER_HORDE = 0, // full horde - CAPTURE_SLIDER_MIDDLE = 50 // middle + CAPTURE_SLIDER_ALLIANCE = 100, // full alliance + CAPTURE_SLIDER_HORDE = 0, // full horde + CAPTURE_SLIDER_MIDDLE = 50 // middle }; class Unit; @@ -796,8 +796,10 @@ class GameObject : public WorldObject GameObject* LookupFishingHoleAround(float range); - void SetCapturePointSlider(float value); - float GetCapturePointSlider() const { return m_captureSlider; } + void SetCapturePointSlider(float value, bool isLocked); + float GetCapturePointSliderValue() const { return m_captureSlider; } + + float GetInteractionDistance(); uint32 GetScriptId(); diff --git a/src/game/Object/Guild.cpp b/src/game/Object/Guild.cpp index f513274fc..56e5ea633 100644 --- a/src/game/Object/Guild.cpp +++ b/src/game/Object/Guild.cpp @@ -583,7 +583,7 @@ void Guild::BroadcastToGuild(WorldSession* session, const std::string& msg, uint if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK)) { WorldPacket data; - ChatHandler::FillMessageData(&data, session, CHAT_MSG_GUILD, language, msg.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_GUILD, msg.c_str(), Language(language), session->GetPlayer()->GetChatTag(), session->GetPlayer()->GetObjectGuid(), session->GetPlayer()->GetName()); for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) { @@ -600,7 +600,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg, if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_GCHATSPEAK)) { WorldPacket data; - ChatHandler::FillMessageData(&data, session,CHAT_MSG_GUILD, CHAT_MSG_ADDON, NULL, ObjectGuid(), msg.c_str(), NULL, prefix.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_GUILD, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str()); for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) { @@ -614,18 +614,22 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, const std::string& msg, void Guild::BroadcastToOfficers(WorldSession* session, const std::string& msg, uint32 language) { - if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_OFFCHATSPEAK)) + if (!session) + return; + + Player* player = session->GetPlayer(); + if (!player || !HasRankRight(player->GetRank(), GR_RIGHT_OFFCHATSPEAK)) + return; + + for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - WorldPacket data; - ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, msg.c_str()); + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_OFFICER, msg.c_str(), Language(language), player->GetChatTag(), player->GetObjectGuid(), player->GetName()); - Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first)); + Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first)); - if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetObjectGuid())) - pl->GetSession()->SendPacket(&data); - } + if (pl && pl->GetSession() && HasRankRight(pl->GetRank(), GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(player->GetObjectGuid())) + pl->GetSession()->SendPacket(&data); } } @@ -636,7 +640,7 @@ void Guild::BroadcastAddonToOfficers(WorldSession* session, const std::string& m for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) { WorldPacket data; - ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, CHAT_MSG_ADDON, NULL, ObjectGuid(), msg.c_str(), NULL, prefix.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_OFFICER, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str()); Player* pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first)); diff --git a/src/game/Object/LootMgr.cpp b/src/game/Object/LootMgr.cpp index 98d793b6d..a64b580eb 100644 --- a/src/game/Object/LootMgr.cpp +++ b/src/game/Object/LootMgr.cpp @@ -47,11 +47,11 @@ static eConfigFloatValues const qualityToRate[MAX_ITEM_QUALITY] = LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true); LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true); LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true); -LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject lootid", true); +LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject Lootid", true); LootStore LootTemplates_Item("item_loot_template", "item entry with ITEM_FLAG_LOOTABLE", true); LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false); LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true); -LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true); +LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket Lootid", true); LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true); LootStore LootTemplates_Reference("reference_loot_template", "reference id", false); LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); @@ -1271,12 +1271,12 @@ void LoadLootTemplates_Creature() { if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) { - if (uint32 lootid = cInfo->lootid) + if (uint32 Lootid = cInfo->LootId) { - if (ids_set.find(lootid) == ids_set.end()) - LootTemplates_Creature.ReportNotExistedId(lootid); + if (ids_set.find(Lootid) == ids_set.end()) + LootTemplates_Creature.ReportNotExistedId(Lootid); else - ids_setUsed.insert(lootid); + ids_setUsed.insert(Lootid); } } } @@ -1301,12 +1301,12 @@ void LoadLootTemplates_Disenchant() { if (ItemPrototype const* proto = sItemStorage.LookupEntry(i)) { - if (uint32 lootid = proto->DisenchantID) + if (uint32 Lootid = proto->DisenchantID) { - if (ids_set.find(lootid) == ids_set.end()) - LootTemplates_Disenchant.ReportNotExistedId(lootid); + if (ids_set.find(Lootid) == ids_set.end()) + LootTemplates_Disenchant.ReportNotExistedId(Lootid); else - ids_setUsed.insert(lootid); + ids_setUsed.insert(Lootid); } } } @@ -1344,12 +1344,12 @@ void LoadLootTemplates_Gameobject() // remove real entries and check existence loot for (SQLStorageBase::SQLSIterator itr = sGOStorage.getDataBegin(); itr < sGOStorage.getDataEnd(); ++itr) { - if (uint32 lootid = itr->GetLootId()) + if (uint32 Lootid = itr->GetLootId()) { - if (ids_set.find(lootid) == ids_set.end()) - LootTemplates_Gameobject.ReportNotExistedId(lootid); + if (ids_set.find(Lootid) == ids_set.end()) + LootTemplates_Gameobject.ReportNotExistedId(Lootid); else - ids_setUsed.insert(lootid); + ids_setUsed.insert(Lootid); } } for (LootIdSet::const_iterator itr = ids_setUsed.begin(); itr != ids_setUsed.end(); ++itr) @@ -1419,12 +1419,12 @@ void LoadLootTemplates_Pickpocketing() { if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) { - if (uint32 lootid = cInfo->pickpocketLootId) + if (uint32 Lootid = cInfo->PickpocketLootId) { - if (ids_set.find(lootid) == ids_set.end()) - LootTemplates_Pickpocketing.ReportNotExistedId(lootid); + if (ids_set.find(Lootid) == ids_set.end()) + LootTemplates_Pickpocketing.ReportNotExistedId(Lootid); else - ids_setUsed.insert(lootid); + ids_setUsed.insert(Lootid); } } } @@ -1485,12 +1485,12 @@ void LoadLootTemplates_Skinning() { if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) { - if (uint32 lootid = cInfo->SkinLootId) + if (uint32 Lootid = cInfo->SkinningLootId) { - if (ids_set.find(lootid) == ids_set.end()) - LootTemplates_Skinning.ReportNotExistedId(lootid); + if (ids_set.find(Lootid) == ids_set.end()) + LootTemplates_Skinning.ReportNotExistedId(Lootid); else - ids_setUsed.insert(lootid); + ids_setUsed.insert(Lootid); } } } diff --git a/src/game/Object/Object.cpp b/src/game/Object/Object.cpp index 06b56e981..dc33c3577 100644 --- a/src/game/Object/Object.cpp +++ b/src/game/Object/Object.cpp @@ -49,6 +49,7 @@ #include "TemporarySummon.h" #include "movement/packet_builder.h" #include "CreatureLinkingMgr.h" +#include "Chat.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #include "ElunaEventMgr.h" @@ -1550,22 +1551,24 @@ bool WorldObject::IsPositionValid() const void WorldObject::MonsterSay(const char* text, uint32 language, Unit const* target) const { WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_SAY, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); + ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_SAY, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(), + target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true); } void WorldObject::MonsterYell(const char* text, uint32 language, Unit const* target) const { WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_YELL, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); + ChatHandler::BuildChatPacket(data, CHAT_MSG_MONSTER_YELL, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(), + target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true); } void WorldObject::MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote) const { WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildMonsterChat(&data, GetObjectGuid(), IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, - GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); + ChatHandler::BuildChatPacket(data, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(), + target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); SendMessageToSetInRange(&data, sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true); } @@ -1575,8 +1578,8 @@ void WorldObject::MonsterWhisper(const char* text, Unit const* target, bool IsBo { return; } WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, - GetName(), target->GetObjectGuid(), target->GetName()); + ChatHandler::BuildChatPacket(data, IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, CHAT_TAG_NONE, GetObjectGuid(), GetName(), + target->GetObjectGuid(), target->GetName()); ((Player*)target)->GetSession()->SendPacket(&data); } @@ -1584,102 +1587,87 @@ namespace MaNGOS { class MonsterChatBuilder { - public: - MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target) - : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) {} + public: + MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, MangosStringLocale const* textData, Language language, Unit const* target) + : i_object(obj), i_msgtype(msgtype), i_textData(textData), i_language(language), i_target(target) {} void operator()(WorldPacket& data, int32 loc_idx) { - char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx); + char const* text = nullptr; + if ((int32)i_textData->Content.size() > loc_idx + 1 && !i_textData->Content[loc_idx + 1].empty()) + text = i_textData->Content[loc_idx + 1].c_str(); + else + text = i_textData->Content[0].c_str(); - WorldObject::BuildMonsterChat(&data, i_object.GetObjectGuid(), i_msgtype, text, i_language, i_object.GetNameForLocaleIdx(loc_idx), i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); + ChatHandler::BuildChatPacket(data, i_msgtype, text, i_language, CHAT_TAG_NONE, i_object.GetObjectGuid(), i_object.GetNameForLocaleIdx(loc_idx), + i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); } private: WorldObject const& i_object; ChatMsg i_msgtype; - int32 i_textId; - uint32 i_language; + MangosStringLocale const* i_textData; + Language i_language; Unit const* i_target; }; } // namespace MaNGOS -void WorldObject::MonsterSay(int32 textId, uint32 language, Unit const* target) const +/// Helper function to create localized around a source +void _DoLocalizedTextAround(WorldObject const* source, MangosStringLocale const* textData, ChatMsg msgtype, Language language, Unit const* target, float range) { - float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY); - MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId, language, target); + MaNGOS::MonsterChatBuilder say_build(*source, msgtype, textData, language, target); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::CameraDistWorker > say_worker(this, range, say_do); - Cell::VisitWorldObjects(this, say_worker, range); + MaNGOS::CameraDistWorker > say_worker(source, range, say_do); + Cell::VisitWorldObjects(source, say_worker, range); } -void WorldObject::MonsterYell(int32 textId, uint32 language, Unit const* target) const +/// Function that sends a text associated to a MangosString +void WorldObject::MonsterText(MangosStringLocale const* textData, Unit const* target) const { - float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL); - MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target); - MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::CameraDistWorker > say_worker(this, range, say_do); - Cell::VisitWorldObjects(this, say_worker, range); -} + MANGOS_ASSERT(textData); -void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const -{ - MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target); - MaNGOS::LocalizedPacketDo say_do(say_build); - - uint32 zoneid = GetZoneId(); - - Map::PlayerList const& pList = GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - if (itr->getSource()->GetZoneId() == zoneid) - say_do(itr->getSource()); -} - -void WorldObject::MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote) const -{ - float range = sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE); - - MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId, LANG_UNIVERSAL, target); - MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::CameraDistWorker > say_worker(this, range, say_do); - Cell::VisitWorldObjects(this, say_worker, range); -} - -void WorldObject::MonsterWhisper(int32 textId, Unit const* target, bool IsBossWhisper) const -{ - if (!target || target->GetTypeId() != TYPEID_PLAYER) - return; - - uint32 loc_idx = ((Player*)target)->GetSession()->GetSessionDbLocaleIndex(); - char const* text = sObjectMgr.GetMangosString(textId, loc_idx); - - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildMonsterChat(&data, GetObjectGuid(), IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, text, LANG_UNIVERSAL, - GetNameForLocaleIdx(loc_idx), target->GetObjectGuid(), ""); - - ((Player*)target)->GetSession()->SendPacket(&data); -} - -void WorldObject::BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName) -{ - *data << uint8(msgtype); - *data << uint32(language); - *data << ObjectGuid(senderGuid); - *data << uint32(0); // 2.1.0 - *data << uint32(strlen(name) + 1); - *data << name; - *data << ObjectGuid(targetGuid); // Unit Target - if (targetGuid && !targetGuid.IsPlayer()) + switch (textData->Type) { - *data << uint32(strlen(targetName) + 1); // target name length - *data << targetName; // target name - } - *data << uint32(strlen(text) + 1); - *data << text; - *data << uint8(0); // ChatTag - if (msgtype == CHAT_MSG_RAID_BOSS_EMOTE || msgtype == CHAT_MSG_RAID_BOSS_WHISPER) - { - *data << float(0.0f); - *data << uint8(0); + case CHAT_TYPE_SAY: + _DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_SAY, textData->LanguageId, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY)); + break; + case CHAT_TYPE_YELL: + _DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_YELL, textData->LanguageId, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL)); + break; + case CHAT_TYPE_TEXT_EMOTE: + _DoLocalizedTextAround(this, textData, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE)); + break; + case CHAT_TYPE_BOSS_EMOTE: + _DoLocalizedTextAround(this, textData, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, target, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL)); + break; + case CHAT_TYPE_WHISPER: + { + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return; + MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_WHISPER, textData, LANG_UNIVERSAL, target); + MaNGOS::LocalizedPacketDo say_do(say_build); + say_do((Player*)target); + break; + } + case CHAT_TYPE_BOSS_WHISPER: + { + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return; + MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_RAID_BOSS_WHISPER, textData, LANG_UNIVERSAL, target); + MaNGOS::LocalizedPacketDo say_do(say_build); + say_do((Player*)target); + break; + } + case CHAT_TYPE_ZONE_YELL: + { + MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textData, textData->LanguageId, target); + MaNGOS::LocalizedPacketDo say_do(say_build); + uint32 zoneid = GetZoneId(); + Map::PlayerList const& pList = GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) + if (itr->getSource()->GetZoneId() == zoneid) + say_do(itr->getSource()); + break; + } } } diff --git a/src/game/Object/Object.h b/src/game/Object/Object.h index 492f81911..cae69f0c7 100644 --- a/src/game/Object/Object.h +++ b/src/game/Object/Object.h @@ -601,16 +601,13 @@ class WorldObject : public Object virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const; void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const; - void MonsterSay(const char* text, uint32 language, Unit const* target = NULL) const; - void MonsterYell(const char* text, uint32 language, Unit const* target = NULL) const; + void MonsterSay(const char* text, uint32 language, Unit const* target = nullptr) const; + void MonsterYell(const char* text, uint32 language, Unit const* target = nullptr) const; void MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote = false) const; void MonsterWhisper(const char* text, Unit const* target, bool IsBossWhisper = false) const; - void MonsterSay(int32 textId, uint32 language, Unit const* target = NULL) const; - void MonsterYell(int32 textId, uint32 language, Unit const* target = NULL) const; - void MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote = false) const; - void MonsterWhisper(int32 textId, Unit const* receiver, bool IsBossWhisper = false) const; + void MonsterText(MangosStringLocale const* textData, Unit const* target) const; + void MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const; - static void BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName); void PlayDistanceSound(uint32 sound_id, Player const* target = NULL) const; void PlayDirectSound(uint32 sound_id, Player const* target = NULL) const; diff --git a/src/game/Object/ObjectMgr.cpp b/src/game/Object/ObjectMgr.cpp index 4df6f63e5..2dfecf3aa 100644 --- a/src/game/Object/ObjectMgr.cpp +++ b/src/game/Object/ObjectMgr.cpp @@ -527,38 +527,38 @@ void ObjectMgr::LoadCreatureTemplates() if (!ok2) continue; - if (cInfo->unit_class != difficultyInfo->unit_class) + if (cInfo->UnitClass != difficultyInfo->UnitFlags) { - sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).", - i, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class); + sLog.outErrorDb("Creature (Entry: %u, class %u) has different `UnitClass` in difficulty %u mode (Entry: %u, class %u).", + i, cInfo->UnitClass, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->UnitClass); continue; } - if (cInfo->npcflag != difficultyInfo->npcflag) + if (cInfo->NpcFlags != difficultyInfo->NpcFlags) { - sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); + sLog.outErrorDb("Creature (Entry: %u) has different `NpcFlags` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_class != difficultyInfo->trainer_class) + if (cInfo->TrainerClass != difficultyInfo->TrainerClass) { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); + sLog.outErrorDb("Creature (Entry: %u) has different `TrainerClass` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_race != difficultyInfo->trainer_race) + if (cInfo->TrainerRace != difficultyInfo->TrainerRace) { sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_type != difficultyInfo->trainer_type) + if (cInfo->TrainerType != difficultyInfo->TrainerType) { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); + sLog.outErrorDb("Creature (Entry: %u) has different `TrainerType` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_spell != difficultyInfo->trainer_spell) + if (cInfo->TrainerSpell != difficultyInfo->TrainerSpell) { sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; @@ -630,56 +630,89 @@ void ObjectMgr::LoadCreatureTemplates() if (!displayScaleEntry) sLog.outErrorDb("Creature (Entry: %u) has nonexistent modelid in modelid_1/modelid_2/modelid_3/modelid_4", cInfo->Entry); - if (!cInfo->minlevel) + if (!cInfo->MinLevel) { sLog.outErrorDb("Creature (Entry: %u) has invalid minlevel, set to 1", cInfo->Entry); - const_cast(cInfo)->minlevel = 1; + const_cast(cInfo)->MinLevel = 1; } - if (cInfo->minlevel > cInfo->maxlevel) + if (cInfo->MinLevel > cInfo->MaxLevel) { sLog.outErrorDb("Creature (Entry: %u) has invalid maxlevel, set to minlevel", cInfo->Entry); - const_cast(cInfo)->maxlevel = cInfo->minlevel; + const_cast(cInfo)->MaxLevel = cInfo->MinLevel; } - // use below code for 0-checks for unit_class - if (!cInfo->unit_class) - ERROR_DB_STRICT_LOG("Creature (Entry: %u) not has proper unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class); - else if (((1 << (cInfo->unit_class - 1)) & CLASSMASK_ALL_CREATURES) == 0) - sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class); - - if (cInfo->dmgschool >= MAX_SPELL_SCHOOL) + if (cInfo->MinLevel > DEFAULT_MAX_CREATURE_LEVEL) { - sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`", cInfo->Entry, cInfo->dmgschool); - const_cast(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; + sLog.outErrorDb("Creature (Entry: %u) `MinLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL)); + const_cast(cInfo)->MinLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL); } - if (cInfo->baseattacktime == 0) - const_cast(cInfo)->baseattacktime = BASE_ATTACK_TIME; + if (cInfo->MaxLevel > DEFAULT_MAX_CREATURE_LEVEL) + { + sLog.outErrorDb("Creature (Entry: %u) `MaxLevel` exceeds maximum allowed value of '%u'", cInfo->Entry, uint32(DEFAULT_MAX_CREATURE_LEVEL)); + const_cast(cInfo)->MaxLevel = uint32(DEFAULT_MAX_CREATURE_LEVEL); + } - if (cInfo->rangeattacktime == 0) - const_cast(cInfo)->rangeattacktime = BASE_ATTACK_TIME; + if (cInfo->Expansion > MAX_EXPANSION) + { + sLog.outErrorDb("Creature (Entry: %u) `Expansion(%u)` is not correct", cInfo->Entry, uint32(MAX_EXPANSION)); + const_cast(cInfo)->Expansion = -1; + } - if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK) + if (!cInfo->UnitClass || (((1 << (cInfo->UnitClass - 1)) & CLASSMASK_ALL_CREATURES) == 0)) + { + ERROR_DB_STRICT_LOG("Creature (Entry: %u) does not have proper `UnitClass` (%u) in creature_template", cInfo->Entry, cInfo->UnitClass); + // Mark NPC as having improper data by his expansion + const_cast(cInfo)->Expansion = -1; + } + + if (!sLog.HasLogFilter(LOG_FILTER_DB_STRICTED_CHECK) && cInfo->Expansion >= 0) // TODO - Remove the DB_STRICTED_CHECK after a while + { + // check if ClassLevel data are available for all possible level of that creature + for (uint32 level = cInfo->MinLevel; level <= cInfo->MaxLevel; ++level) + { + if (!GetCreatureClassLvlStats(level, cInfo->UnitClass, cInfo->Expansion)) + { + sLog.outErrorDb("Creature (Entry: %u), level(%u) has no data in `creature_template_classlevelstats`", cInfo->Entry, level); + // Deactivate using ClassLevelStats for this NPC + const_cast(cInfo)->Expansion = -1; + } + } + } + + if (cInfo->DamageSchool >= MAX_SPELL_SCHOOL) + { + sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `DamageSchool`", cInfo->Entry, cInfo->DamageSchool); + const_cast(cInfo)->DamageSchool = SPELL_SCHOOL_NORMAL; + } + + if (cInfo->MeleeAttackPower == 0) + const_cast(cInfo)->MeleeAttackPower = BASE_ATTACK_TIME; + + if (cInfo->RangedAttackPower == 0) + const_cast(cInfo)->RangedAttackPower = BASE_ATTACK_TIME; + + if (cInfo->NpcFlags & UNIT_NPC_FLAG_SPELLCLICK) { sLog.outDebug("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, but it is expected to be set in run-time based at `npc_spellclick_spells` contents.", cInfo->Entry, UNIT_NPC_FLAG_SPELLCLICK); - const_cast(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK; + const_cast(cInfo)->NpcFlags &= ~UNIT_NPC_FLAG_SPELLCLICK; } - if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) - sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->trainer_type); + if ((cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER) && cInfo->TrainerType >= MAX_TRAINER_TYPE) + sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u", cInfo->Entry, cInfo->TrainerType); - if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type)) + if (cInfo->CreatureType && !sCreatureTypeStore.LookupEntry(cInfo->CreatureType)) { - sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->type); - const_cast(cInfo)->type = CREATURE_TYPE_HUMANOID; + sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`", cInfo->Entry, cInfo->CreatureType); + const_cast(cInfo)->CreatureType = CREATURE_TYPE_HUMANOID; } // must exist or used hidden but used in data horse case - if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM) + if (cInfo->Family && !sCreatureFamilyStore.LookupEntry(cInfo->Family) && cInfo->Family != CREATURE_FAMILY_HORSE_CUSTOM) { - sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`", cInfo->Entry, cInfo->family); - const_cast(cInfo)->family = 0; + sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `Family`", cInfo->Entry, cInfo->Family); + const_cast(cInfo)->Family = 0; } if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE) @@ -716,10 +749,10 @@ void ObjectMgr::LoadCreatureTemplates() } } - if (cInfo->vendorId > 0) + if (cInfo->VendorTemplateId > 0) { - if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR)) - sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with vendor_id %u but not have flag UNIT_NPC_FLAG_VENDOR (%u), vendor items will ignored.", cInfo->Entry, cInfo->vendorId, UNIT_NPC_FLAG_VENDOR); + if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR)) + sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with vendor_id %u but not have flag UNIT_NPC_FLAG_VENDOR (%u), vendor items will ignored.", cInfo->Entry, cInfo->VendorTemplateId, UNIT_NPC_FLAG_VENDOR); } /// if not set custom creature Scale then load Scale from CreatureDisplayInfo.dbc @@ -948,6 +981,19 @@ void ObjectMgr::LoadCreatureClassLvlStats() sLog.outString(">> Loaded %u creature class level stats definitions.", DataCount); } +CreatureClassLvlStats const* ObjectMgr::GetCreatureClassLvlStats(uint32 level, uint32 unitClass, int32 expansion) const +{ + if (expansion < 0) + return nullptr; + + CreatureClassLvlStats const* cCLS = &m_creatureClassLvlStats[level][classToIndex[unitClass]][expansion]; + + if (cCLS->BaseHealth != 0 && cCLS->BaseDamage > 0.1f) + return cCLS; + + return nullptr; +} + void ObjectMgr::LoadEquipmentTemplates() { sEquipmentStorage.Load(); @@ -1401,30 +1447,30 @@ void ObjectMgr::LoadCreatures() } } - if (cInfo->RegenHealth && data.curhealth < cInfo->minhealth) + if (cInfo->RegenerateStats & REGEN_FLAG_HEALTH && data.curhealth < cInfo->MinLevelHealth) { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.", guid, data.id, data.curhealth, cInfo->minhealth); - data.curhealth = cInfo->minhealth; + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`MinLevelHealth`=%u.", guid, data.id, data.curhealth, cInfo->MinLevelHealth); + data.curhealth = cInfo->MinLevelHealth; } - if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND) { if (!mapEntry || !mapEntry->IsDungeon()) - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_FLAG_EXTRA_INSTANCE_BIND (%u) but creature are not in instance.", - guid, data.id, CREATURE_FLAG_EXTRA_INSTANCE_BIND); + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_EXTRA_FLAG_INSTANCE_BIND (%u) but creature are not in instance.", + guid, data.id, CREATURE_EXTRA_FLAG_INSTANCE_BIND); } - if (cInfo->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE) + if (cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE) { if (!mapEntry || !mapEntry->IsDungeon()) - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_FLAG_EXTRA_AGGRO_ZONE (%u) but creature are not in instance.", - guid, data.id, CREATURE_FLAG_EXTRA_AGGRO_ZONE); + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`ExtraFlags` including CREATURE_EXTRA_FLAG_AGGRO_ZONE (%u) but creature are not in instance.", + guid, data.id, CREATURE_EXTRA_FLAG_AGGRO_ZONE); } - if (data.curmana < cInfo->minmana) + if (data.curmana < cInfo->MinLevelMana) { - sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.", guid, data.id, data.curmana, cInfo->minmana); - data.curmana = cInfo->minmana; + sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`MinLevelMana`=%u.", guid, data.id, data.curmana, cInfo->MinLevelMana); + data.curmana = cInfo->MinLevelMana; } if (data.spawndist < 0.0f) @@ -6601,7 +6647,7 @@ std::string ObjectMgr::GeneratePetName(uint32 entry) if (list0.empty() || list1.empty()) { CreatureInfo const* cinfo = GetCreatureTemplate(entry); - char const* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); + char const* petname = GetPetName(cinfo->Family, sWorld.GetDefaultDbcLocale()); if (!petname) petname = cinfo->Name; return std::string(petname); @@ -7340,7 +7386,7 @@ void ObjectMgr::LoadNPCSpellClickSpells() mSpellClickInfoMap.insert(SpellClickInfoMap::value_type(npc_entry, info)); // mark creature template as spell clickable - const_cast(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; + const_cast(cInfo)->NpcFlags |= UNIT_NPC_FLAG_SPELLCLICK; ++count; } @@ -7544,8 +7590,8 @@ void ObjectMgr::LoadCreatureQuestRelations() CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); if (!cInfo) sLog.outErrorDb("Table `creature_questrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second); - else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) - sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); + else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER)) + sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); } } @@ -7558,8 +7604,8 @@ void ObjectMgr::LoadCreatureInvolvedRelations() CreatureInfo const* cInfo = GetCreatureTemplate(itr->first); if (!cInfo) sLog.outErrorDb("Table `creature_involvedrelation` have data for nonexistent creature entry (%u) and existing quest %u", itr->first, itr->second); - else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER)) - sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); + else if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_QUESTGIVER)) + sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but NpcFlags does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second); } } @@ -7997,10 +8043,10 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min // Load additional string content if necessary if (extra_content) { - data.SoundId = fields[10].GetUInt32(); - data.Type = fields[11].GetUInt32(); - data.LanguageId = (Language)fields[12].GetUInt32(); - data.Emote = fields[13].GetUInt32(); + data.SoundId = fields[10].GetUInt32(); + data.Type = fields[11].GetUInt32(); + data.LanguageId = Language(fields[12].GetUInt32()); + data.Emote = fields[13].GetUInt32(); if (data.SoundId && !sSoundEntriesStore.LookupEntry(data.SoundId)) { @@ -8010,7 +8056,7 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min if (!GetLanguageDescByID(data.LanguageId)) { - _DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, data.LanguageId); + _DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, uint32(data.LanguageId)); data.LanguageId = LANG_UNIVERSAL; } @@ -9237,7 +9283,7 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates) continue; } - if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER)) + if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_TRAINER)) { if (skip_trainers.find(entry) == skip_trainers.end()) { @@ -9247,11 +9293,11 @@ void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates) continue; } - if (TrainerSpellData const* tSpells = cInfo->trainerId ? GetNpcTrainerTemplateSpells(cInfo->trainerId) : NULL) + if (TrainerSpellData const* tSpells = cInfo->TrainerTemplateId ? GetNpcTrainerTemplateSpells(cInfo->TrainerTemplateId) : NULL) { if (tSpells->spellList.find(spell) != tSpells->spellList.end()) { - sLog.outErrorDb("Table `%s` (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell, cInfo->trainerId); + sLog.outErrorDb("Table `%s` (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell, cInfo->TrainerTemplateId); continue; } } @@ -9349,12 +9395,12 @@ void ObjectMgr::LoadTrainerTemplates() { if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) { - if (cInfo->trainerId) + if (cInfo->TrainerTemplateId) { - if (m_mCacheTrainerTemplateSpellMap.find(cInfo->trainerId) != m_mCacheTrainerTemplateSpellMap.end()) - trainer_ids.erase(cInfo->trainerId); + if (m_mCacheTrainerTemplateSpellMap.find(cInfo->TrainerTemplateId) != m_mCacheTrainerTemplateSpellMap.end()) + trainer_ids.erase(cInfo->TrainerTemplateId); else - sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->trainerId); + sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->TrainerTemplateId); } } } @@ -9433,12 +9479,12 @@ void ObjectMgr::LoadVendorTemplates() { if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry(i)) { - if (cInfo->vendorId) + if (cInfo->VendorTemplateId) { - if (m_mCacheVendorTemplateItemMap.find(cInfo->vendorId) != m_mCacheVendorTemplateItemMap.end()) - vendor_ids.erase(cInfo->vendorId); + if (m_mCacheVendorTemplateItemMap.find(cInfo->VendorTemplateId) != m_mCacheVendorTemplateItemMap.end()) + vendor_ids.erase(cInfo->VendorTemplateId); else - sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->vendorId); + sLog.outErrorDb("Creature (Entry: %u) has vendor_id = %u for nonexistent vendor template", cInfo->Entry, cInfo->VendorTemplateId); } } } @@ -9593,7 +9639,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set& gossipScriptSet) m_mGossipMenuItemsMap.clear(); QueryResult* result = WorldDatabase.Query( - "SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, " + "SELECT menu_id, id, option_icon, option_text, option_id, npc_option_NpcFlags, " "action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text, " "condition_id " "FROM gossip_menu_option ORDER BY menu_id, id"); @@ -9654,7 +9700,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set& gossipScriptSet) gMenuItem.option_icon = fields[2].GetUInt8(); gMenuItem.option_text = fields[3].GetCppString(); gMenuItem.option_id = fields[4].GetUInt32(); - gMenuItem.npc_option_npcflag = fields[5].GetUInt32(); + gMenuItem.npc_option_NpcFlags = fields[5].GetUInt32(); gMenuItem.action_menu_id = fields[6].GetInt32(); gMenuItem.action_poi_id = fields[7].GetUInt32(); gMenuItem.action_script_id = fields[8].GetUInt32(); @@ -9693,7 +9739,7 @@ void ObjectMgr::LoadGossipMenuItems(std::set& gossipScriptSet) if (gMenuItem.option_id >= GOSSIP_OPTION_MAX) sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_id); - if (gMenuItem.menu_id && gMenuItem.npc_option_npcflag) + if (gMenuItem.menu_id && gMenuItem.npc_option_NpcFlags) { bool found_menu_uses = false; bool found_flags_uses = false; @@ -9706,12 +9752,12 @@ void ObjectMgr::LoadGossipMenuItems(std::set& gossipScriptSet) found_menu_uses = true; // some from creatures with gossip menu can use gossip option base at npc_flags - if (gMenuItem.npc_option_npcflag & cInfo->npcflag) + if (gMenuItem.npc_option_NpcFlags & cInfo->NpcFlags) found_flags_uses = true; } if (found_menu_uses && !found_flags_uses) - sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_npcflag` = %u but creatures using this menu does not have corresponding`npcflag`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_npcflag); + sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has `npc_option_NpcFlags` = %u but creatures using this menu does not have corresponding`NpcFlags`. Option will not accessible in game.", gMenuItem.menu_id, gMenuItem.id, gMenuItem.npc_option_NpcFlags); } if (gMenuItem.action_poi_id && !GetPointOfInterest(gMenuItem.action_poi_id)) @@ -9820,7 +9866,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 return false; } - if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR)) + if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR)) { if (!skip_vendors || skip_vendors->count(vendor_entry) == 0) { @@ -9923,12 +9969,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 } else { - if (!cInfo->vendorId) + if (!cInfo->VendorTemplateId) sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u, ignoring", tableName, item_id, idStr, vendor_entry); else sLog.outErrorDb("Table `%s` has duplicate items %u for %s %u (or possible in vendor template %u), ignoring", - tableName, item_id, idStr, vendor_entry, cInfo->vendorId); + tableName, item_id, idStr, vendor_entry, cInfo->VendorTemplateId); } return false; } @@ -9974,7 +10020,7 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 return false; } - if (!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR)) + if (!(cInfo->NpcFlags & UNIT_NPC_FLAG_VENDOR)) { if (!skip_vendors || skip_vendors->count(vendor_entry) == 0) { @@ -10111,12 +10157,12 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, item_id, type == VENDOR_ITEM_TYPE_CURRENCY, ExtendedCost); else { - if (!cInfo->vendorId) + if (!cInfo->VendorTemplateId) sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u, ignoring", tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry); else sLog.outErrorDb("Table `%s` has duplicate %s %u (with extended cost %u) for %s %u (or possible in vendor template %u), ignoring", - tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->vendorId); + tableName, nameStr, item_id, ExtendedCost, idStr, vendor_entry, cInfo->VendorTemplateId); } return false; } @@ -10366,47 +10412,13 @@ bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL* } } - switch (data->Type) + if ((data->Type == CHAT_TYPE_WHISPER || data->Type == CHAT_TYPE_BOSS_WHISPER) && (!target || target->GetTypeId() != TYPEID_PLAYER)) { - case CHAT_TYPE_SAY: - source->MonsterSay(entry, data->LanguageId, target); - break; - case CHAT_TYPE_YELL: - source->MonsterYell(entry, data->LanguageId, target); - break; - case CHAT_TYPE_TEXT_EMOTE: - source->MonsterTextEmote(entry, target); - break; - case CHAT_TYPE_BOSS_EMOTE: - source->MonsterTextEmote(entry, target, true); - break; - case CHAT_TYPE_WHISPER: - { - if (target && target->GetTypeId() == TYPEID_PLAYER) - source->MonsterWhisper(entry, target); - else - { - _DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry); - return false; - } - break; - } - case CHAT_TYPE_BOSS_WHISPER: - { - if (target && target->GetTypeId() == TYPEID_PLAYER) - source->MonsterWhisper(entry, target, true); - else - { - _DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry); - return false; - } - break; - } - case CHAT_TYPE_ZONE_YELL: - source->MonsterYellToZone(entry, data->LanguageId, target); - break; + _DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry); + return false; } + source->MonsterText(data, target); return true; } diff --git a/src/game/Object/ObjectMgr.h b/src/game/Object/ObjectMgr.h index 20ce46970..1c397adfc 100644 --- a/src/game/Object/ObjectMgr.h +++ b/src/game/Object/ObjectMgr.h @@ -132,7 +132,7 @@ typedef UNORDERED_MAP < uint32/*(mapid,spawnMode) pair*/, CellObjectGuidsMap > M #define MIN_MANGOS_STRING_ID 1 // 'mangos_string' #define MAX_MANGOS_STRING_ID 2000000000 #define MIN_DB_SCRIPT_STRING_ID MAX_MANGOS_STRING_ID // 'db_script_string' -#define MAX_DB_SCRIPT_STRING_ID 2000010000 +#define MAX_DB_SCRIPT_STRING_ID 2001000000 #define MIN_CREATURE_AI_TEXT_STRING_ID (-1) // 'creature_ai_texts' #define MAX_CREATURE_AI_TEXT_STRING_ID (-1000000) // Anything below MAX_CREATURE_AI_TEXT_STRING_ID is handled by the external script lib @@ -283,7 +283,7 @@ struct GossipMenuItems uint8 option_icon; std::string option_text; uint32 option_id; - uint32 npc_option_npcflag; + uint32 npc_option_NpcFlags; int32 action_menu_id; uint32 action_poi_id; uint32 action_script_id; @@ -1191,6 +1191,19 @@ class ObjectMgr QuestRelationsMap& GetCreatureQuestRelationsMap() { return m_CreatureQuestRelations; } uint32 GetModelForRace(uint32 sourceModelId, uint32 racemask); + /** + * \brief: Data returned is used to compute health, mana, armor, damage of creatures. May be nullptr. + * \param uint32 level creature level + * \param uint32 unitClass creature class, related to CLASSMASK_ALL_CREATURES + * \param uint32 expansion creature expansion (we could have creature exp = 0 for wotlk as well as exp = 1 or exp = 2) + * \return: CreatureClassLvlStats const* or nullptr + * + * Description: GetCreatureClassLvlStats give fast access to creature stats data. + * FullName: ObjectMgr::GetCreatureClassLvlStats + * Access: public + * Qualifier: const + **/ + CreatureClassLvlStats const* GetCreatureClassLvlStats(uint32 level, uint32 unitClass, int32 expansion) const; void LoadHotfixData(); HotfixData const& GetHotfixData() const { return m_hotfixData; } diff --git a/src/game/Object/Pet.cpp b/src/game/Object/Pet.cpp index 9c7b3a157..5c805b2e2 100644 --- a/src/game/Object/Pet.cpp +++ b/src/game/Object/Pet.cpp @@ -180,7 +180,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c // reget for sure use real creature info selected for Pet at load/creating CreatureInfo const* cinfo = GetCreatureInfo(); - if (cinfo->type == CREATURE_TYPE_CRITTER) + if (cinfo->CreatureType == CREATURE_TYPE_CRITTER) { AIM_Initialize(); pos.GetMap()->Add((Creature*)this); @@ -817,7 +817,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) return false; } - if (cinfo->type == CREATURE_TYPE_CRITTER) + if (cinfo->CreatureType == CREATURE_TYPE_CRITTER) { setPetType(MINI_PET); return true; @@ -830,12 +830,12 @@ bool Pet::CreateBaseAtCreature(Creature* creature) SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, sObjectMgr.GetXPForPetLevel(creature->getLevel())); SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); - if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) + if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family)) SetName(cFamily->Name[sWorld.GetDefaultDbcLocale()]); else SetName(creature->GetNameForLocaleIdx(sObjectMgr.GetDBCLocaleIndex())); - if (cinfo->type == CREATURE_TYPE_BEAST) + if (cinfo->CreatureType == CREATURE_TYPE_BEAST) { SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_WARRIOR); SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_NONE); @@ -889,7 +889,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) SetLevel(petlevel); - SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); + SetMeleeDamageSchool(SpellSchools(cinfo->DamageSchool)); SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50)); @@ -899,7 +899,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0); - CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family); + CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->Family); if (cFamily && cFamily->minScale > 0.0f && getPetType() == HUNTER_PET) { float Scale; @@ -919,12 +919,12 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) if (getPetType() != HUNTER_PET) { - createResistance[SPELL_SCHOOL_HOLY] = cinfo->resistance1; - createResistance[SPELL_SCHOOL_FIRE] = cinfo->resistance2; - createResistance[SPELL_SCHOOL_NATURE] = cinfo->resistance3; - createResistance[SPELL_SCHOOL_FROST] = cinfo->resistance4; - createResistance[SPELL_SCHOOL_SHADOW] = cinfo->resistance5; - createResistance[SPELL_SCHOOL_ARCANE] = cinfo->resistance6; + createResistance[SPELL_SCHOOL_HOLY] = cinfo->ResistanceHoly; + createResistance[SPELL_SCHOOL_FIRE] = cinfo->ResistanceFire; + createResistance[SPELL_SCHOOL_NATURE] = cinfo->ResistanceNature; + createResistance[SPELL_SCHOOL_FROST] = cinfo->ResistanceFrost; + createResistance[SPELL_SCHOOL_SHADOW] = cinfo->ResistanceShadow; + createResistance[SPELL_SCHOOL_ARCANE] = cinfo->ResistanceArcane; } switch (getPetType()) @@ -985,8 +985,8 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) sLog.outErrorDb("Summoned pet (Entry: %u) not have pet stats data in DB", cinfo->Entry); // remove elite bonuses included in DB values - SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel)); - SetCreateMana(uint32(((float(cinfo->maxmana) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel)); + SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel)); + SetCreateMana(uint32(((float(cinfo->MaxLevelMana) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel)); SetCreateStat(STAT_STRENGTH, 22); SetCreateStat(STAT_AGILITY, 22); @@ -1024,7 +1024,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel, Unit* owner) sLog.outErrorDb("Hunter pet levelstats missing in DB"); // remove elite bonuses included in DB values - SetCreateHealth(uint32(((float(cinfo->maxhealth) / cinfo->maxlevel) / (1 + 2 * cinfo->Rank)) * petlevel)); + SetCreateHealth(uint32(((float(cinfo->MaxLevelHealth) / cinfo->MaxLevel) / (1 + 2 * cinfo->Rank)) * petlevel)); SetCreateStat(STAT_STRENGTH, 22); SetCreateStat(STAT_AGILITY, 22); @@ -1074,7 +1074,7 @@ bool Pet::HaveInDiet(ItemPrototype const* item) const if (!cInfo) return false; - CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family); + CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family); if (!cFamily) return false; @@ -1563,7 +1563,7 @@ void Pet::InitLevelupSpellsForLevel() { uint32 level = getLevel(); - if (PetLevelupSpellSet const* levelupSpells = GetCreatureInfo()->family ? sSpellMgr.GetPetLevelupSpellList(GetCreatureInfo()->family) : NULL) + if (PetLevelupSpellSet const* levelupSpells = GetCreatureInfo()->Family ? sSpellMgr.GetPetLevelupSpellList(GetCreatureInfo()->Family) : NULL) { // PetLevelupSpellSet ordered by levels, process in reversed order for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr) @@ -1702,7 +1702,7 @@ bool Pet::resetTalents(bool no_cost) if (!ci) return false; // Check pet talent type - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family); if (!pet_family || pet_family->petTalentType < 0) return false; @@ -1961,9 +1961,9 @@ bool Pet::IsPermanentPetFor(Player* owner) // oddly enough, Mage's Water Elemental is still treated as temporary pet with Glyph of Eternal Water // i.e. does not unsummon at mounting, gets dismissed at teleport etc. case CLASS_WARLOCK: - return GetCreatureInfo()->type == CREATURE_TYPE_DEMON; + return GetCreatureInfo()->CreatureType == CREATURE_TYPE_DEMON; case CLASS_DEATH_KNIGHT: - return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD; + return GetCreatureInfo()->CreatureType == CREATURE_TYPE_UNDEAD; default: return false; } @@ -2012,7 +2012,7 @@ void Pet::LearnPetPassives() if (!cInfo) return; - CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family); + CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->Family); if (!cFamily) return; diff --git a/src/game/Object/Pet.h b/src/game/Object/Pet.h index d163a677b..2a5fa12bd 100644 --- a/src/game/Object/Pet.h +++ b/src/game/Object/Pet.h @@ -168,7 +168,7 @@ class Pet : public Creature return m_autospells[pos]; } - bool CanSwim() const override + bool CanSwim() const { Unit const* owner = GetOwner(); if (owner) diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index d9665d17b..ad82f52e3 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -1526,7 +1526,7 @@ bool Player::BuildEnumData(QueryResult* result, ByteBuffer* data, ByteBuffer* bu { petDisplayId = fields[17].GetUInt32(); petLevel = fields[18].GetUInt32(); - petFamily = cInfo->family; + petFamily = cInfo->Family; } } @@ -1644,9 +1644,9 @@ void Player::ToggleDND() ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); } -uint8 Player::GetChatTag() const +ChatTagFlags Player::GetChatTag() const { - uint8 tag = CHAT_TAG_NONE; + ChatTagFlags tag = CHAT_TAG_NONE; if (isAFK()) tag |= CHAT_TAG_AFK; @@ -2291,7 +2291,7 @@ void Player::RegenerateHealth(uint32 diff) ModifyHealth(int32(addvalue)); } -Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) +Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask) { // some basic checks if (!guid || !IsInWorld() || IsTaxiFlying()) @@ -2307,10 +2307,10 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) return NULL; // appropriate npc type - if (npcflagmask && !unit->HasFlag(UNIT_NPC_FLAGS, npcflagmask)) + if (NpcFlagsmask && !unit->HasFlag(UNIT_NPC_FLAGS, NpcFlagsmask)) return NULL; - if (npcflagmask == UNIT_NPC_FLAG_STABLEMASTER) + if (NpcFlagsmask == UNIT_NPC_FLAG_STABLEMASTER) { if (getClass() != CLASS_HUNTER) return NULL; @@ -5047,7 +5047,7 @@ void Player::CleanupChannels() { Channel* ch = *m_channels.begin(); m_channels.erase(m_channels.begin()); // remove from player's channel list - ch->Leave(GetObjectGuid(), false); // not send to client, not remove from player's channel list + ch->Leave(this, false); // not send to client, not remove from player's channel list if (ChannelMgr* cMgr = channelMgr(GetTeam())) cMgr->LeftChannel(ch->GetName()); // deleted channel if empty } @@ -5091,13 +5091,13 @@ void Player::UpdateLocalChannels(uint32 newZone) if ((*i) != new_channel) { - new_channel->Join(GetObjectGuid(), ""); // will output Changed Channel: N. Name + new_channel->Join(this, ""); // will output Changed Channel: N. Name // leave old channel - (*i)->Leave(GetObjectGuid(), false); // not send leave channel, it already replaced at client + (*i)->Leave(this, false); // not send leave channel, it already replaced at client std::string name = (*i)->GetName(); // store name, (*i)erase in LeftChannel LeftChannel(*i); // remove from player's channel list - cMgr->LeftChannel(name); // delete if empty + cMgr->LeftChannel(name); // delete if empty // delete if empty } } DEBUG_LOG("Player: channels cleaned up!"); @@ -5109,7 +5109,7 @@ void Player::LeaveLFGChannel() { if ((*i)->IsLFG()) { - (*i)->Leave(GetObjectGuid()); + (*i)->Leave(this); break; } } @@ -8120,7 +8120,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) // generate loot only if ready for open and spawned in world if (go->getLootState() == GO_READY && go->isSpawned()) { - uint32 lootid = go->GetGOInfo()->GetLootId(); + uint32 Lootid = go->GetGOInfo()->GetLootId(); if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) { if (BattleGround* bg = GetBattleGround()) @@ -8149,11 +8149,11 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) loot->FillLoot(zone, LootTemplates_Fishing, this, true); break; default: - if (!lootid) + if (!Lootid) break; DEBUG_LOG(" send normal GO loot"); - loot->FillLoot(lootid, LootTemplates_Gameobject, this, false); + loot->FillLoot(Lootid, LootTemplates_Gameobject, this, false); loot->generateMoneyLoot(go->GetGOInfo()->MinMoneyLoot, go->GetGOInfo()->MaxMoneyLoot); if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules) @@ -8313,8 +8313,8 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) creature->lootForPickPocketed = true; loot->clear(); - if (uint32 lootid = creature->GetCreatureInfo()->pickpocketLootId) - loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, false); + if (uint32 Lootid = creature->GetCreatureInfo()->PickpocketLootId) + loot->FillLoot(Lootid, LootTemplates_Pickpocketing, this, false); // Generate extra money for pick pocket loot const uint32 a = urand(0, creature->getLevel() / 2); @@ -8344,10 +8344,10 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) creature->lootForBody = true; loot->clear(); - if (uint32 lootid = creature->GetCreatureInfo()->lootid) - loot->FillLoot(lootid, LootTemplates_Creature, recipient, false); + if (uint32 Lootid = creature->GetCreatureInfo()->LootId) + loot->FillLoot(Lootid, LootTemplates_Creature, recipient, false); - loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold, creature->GetCreatureInfo()->maxgold); + loot->generateMoneyLoot(creature->GetCreatureInfo()->MinLootGold, creature->GetCreatureInfo()->MaxLootGold); if (Group* group = creature->GetGroupLootRecipient()) { @@ -8378,7 +8378,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) { creature->lootForSkin = true; loot->clear(); - loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, this, false); + loot->FillLoot(creature->GetCreatureInfo()->SkinningLootId, LootTemplates_Skinning, this, false); // let reopen skinning loot if will closed. if (!loot->empty()) @@ -8474,302 +8474,6 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value) GetSession()->SendPacket(&data); } -static WorldStatePair AV_world_states[] = -{ - { 0x7ae, 0x1 }, // 1966 7 snowfall n - { 0x532, 0x1 }, // 1330 8 frostwolfhut hc - { 0x531, 0x0 }, // 1329 9 frostwolfhut ac - { 0x52e, 0x0 }, // 1326 10 stormpike firstaid a_a - { 0x571, 0x0 }, // 1393 11 east frostwolf tower horde assaulted -unused - { 0x570, 0x0 }, // 1392 12 west frostwolf tower horde assaulted - unused - { 0x567, 0x1 }, // 1383 13 frostwolfe c - { 0x566, 0x1 }, // 1382 14 frostwolfw c - { 0x550, 0x1 }, // 1360 15 irondeep (N) ally - { 0x544, 0x0 }, // 1348 16 ice grave a_a - { 0x536, 0x0 }, // 1334 17 stormpike grave h_c - { 0x535, 0x1 }, // 1333 18 stormpike grave a_c - { 0x518, 0x0 }, // 1304 19 stoneheart grave a_a - { 0x517, 0x0 }, // 1303 20 stoneheart grave h_a - { 0x574, 0x0 }, // 1396 21 unk - { 0x573, 0x0 }, // 1395 22 iceblood tower horde assaulted -unused - { 0x572, 0x0 }, // 1394 23 towerpoint horde assaulted - unused - { 0x56f, 0x0 }, // 1391 24 unk - { 0x56e, 0x0 }, // 1390 25 iceblood a - { 0x56d, 0x0 }, // 1389 26 towerp a - { 0x56c, 0x0 }, // 1388 27 frostwolfe a - { 0x56b, 0x0 }, // 1387 28 froswolfw a - { 0x56a, 0x1 }, // 1386 29 unk - { 0x569, 0x1 }, // 1385 30 iceblood c - { 0x568, 0x1 }, // 1384 31 towerp c - { 0x565, 0x0 }, // 1381 32 stoneh tower a - { 0x564, 0x0 }, // 1380 33 icewing tower a - { 0x563, 0x0 }, // 1379 34 dunn a - { 0x562, 0x0 }, // 1378 35 duns a - { 0x561, 0x0 }, // 1377 36 stoneheart bunker alliance assaulted - unused - { 0x560, 0x0 }, // 1376 37 icewing bunker alliance assaulted - unused - { 0x55f, 0x0 }, // 1375 38 dunbaldar south alliance assaulted - unused - { 0x55e, 0x0 }, // 1374 39 dunbaldar north alliance assaulted - unused - { 0x55d, 0x0 }, // 1373 40 stone tower d - { 0x3c6, 0x0 }, // 966 41 unk - { 0x3c4, 0x0 }, // 964 42 unk - { 0x3c2, 0x0 }, // 962 43 unk - { 0x516, 0x1 }, // 1302 44 stoneheart grave a_c - { 0x515, 0x0 }, // 1301 45 stonheart grave h_c - { 0x3b6, 0x0 }, // 950 46 unk - { 0x55c, 0x0 }, // 1372 47 icewing tower d - { 0x55b, 0x0 }, // 1371 48 dunn d - { 0x55a, 0x0 }, // 1370 49 duns d - { 0x559, 0x0 }, // 1369 50 unk - { 0x558, 0x0 }, // 1368 51 iceblood d - { 0x557, 0x0 }, // 1367 52 towerp d - { 0x556, 0x0 }, // 1366 53 frostwolfe d - { 0x555, 0x0 }, // 1365 54 frostwolfw d - { 0x554, 0x1 }, // 1364 55 stoneh tower c - { 0x553, 0x1 }, // 1363 56 icewing tower c - { 0x552, 0x1 }, // 1362 57 dunn c - { 0x551, 0x1 }, // 1361 58 duns c - { 0x54f, 0x0 }, // 1359 59 irondeep (N) horde - { 0x54e, 0x0 }, // 1358 60 irondeep (N) ally - { 0x54d, 0x1 }, // 1357 61 mine (S) neutral - { 0x54c, 0x0 }, // 1356 62 mine (S) horde - { 0x54b, 0x0 }, // 1355 63 mine (S) ally - { 0x545, 0x0 }, // 1349 64 iceblood h_a - { 0x543, 0x1 }, // 1347 65 iceblod h_c - { 0x542, 0x0 }, // 1346 66 iceblood a_c - { 0x540, 0x0 }, // 1344 67 snowfall h_a - { 0x53f, 0x0 }, // 1343 68 snowfall a_a - { 0x53e, 0x0 }, // 1342 69 snowfall h_c - { 0x53d, 0x0 }, // 1341 70 snowfall a_c - { 0x53c, 0x0 }, // 1340 71 frostwolf g h_a - { 0x53b, 0x0 }, // 1339 72 frostwolf g a_a - { 0x53a, 0x1 }, // 1338 73 frostwolf g h_c - { 0x539, 0x0 }, // l33t 74 frostwolf g a_c - { 0x538, 0x0 }, // 1336 75 stormpike grave h_a - { 0x537, 0x0 }, // 1335 76 stormpike grave a_a - { 0x534, 0x0 }, // 1332 77 frostwolf hut h_a - { 0x533, 0x0 }, // 1331 78 frostwolf hut a_a - { 0x530, 0x0 }, // 1328 79 stormpike first aid h_a - { 0x52f, 0x0 }, // 1327 80 stormpike first aid h_c - { 0x52d, 0x1 }, // 1325 81 stormpike first aid a_c - { 0x0, 0x0 } -}; - -static WorldStatePair WS_world_states[] = -{ - { 0x62d, 0x0 }, // 1581 7 alliance flag captures - { 0x62e, 0x0 }, // 1582 8 horde flag captures - { 0x609, 0x0 }, // 1545 9 unk, set to 1 on alliance flag pickup... - { 0x60a, 0x0 }, // 1546 10 unk, set to 1 on horde flag pickup, after drop it's -1 - { 0x60b, 0x2 }, // 1547 11 unk - { 0x641, 0x3 }, // 1601 12 unk (max flag captures?) - { 0x922, 0x1 }, // 2338 13 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) - { 0x923, 0x1 }, // 2339 14 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing) - { 0x1097, 0x1 }, // 4247 15 show time limit? - { 0x1098, 0x19 }, // 4248 16 time remaining in minutes - { 0x0, 0x0 } -}; - -static WorldStatePair AB_world_states[] = -{ - { 0x6e7, 0x0 }, // 1767 7 stables alliance - { 0x6e8, 0x0 }, // 1768 8 stables horde - { 0x6e9, 0x0 }, // 1769 9 unk, ST? - { 0x6ea, 0x0 }, // 1770 10 stables (show/hide) - { 0x6ec, 0x0 }, // 1772 11 farm (0 - horde controlled, 1 - alliance controlled) - { 0x6ed, 0x0 }, // 1773 12 farm (show/hide) - { 0x6ee, 0x0 }, // 1774 13 farm color - { 0x6ef, 0x0 }, // 1775 14 gold mine color, may be FM? - { 0x6f0, 0x0 }, // 1776 15 alliance resources - { 0x6f1, 0x0 }, // 1777 16 horde resources - { 0x6f2, 0x0 }, // 1778 17 horde bases - { 0x6f3, 0x0 }, // 1779 18 alliance bases - { 0x6f4, 0x7d0 }, // 1780 19 max resources (2000) - { 0x6f6, 0x0 }, // 1782 20 blacksmith color - { 0x6f7, 0x0 }, // 1783 21 blacksmith (show/hide) - { 0x6f8, 0x0 }, // 1784 22 unk, bs? - { 0x6f9, 0x0 }, // 1785 23 unk, bs? - { 0x6fb, 0x0 }, // 1787 24 gold mine (0 - horde contr, 1 - alliance contr) - { 0x6fc, 0x0 }, // 1788 25 gold mine (0 - conflict, 1 - horde) - { 0x6fd, 0x0 }, // 1789 26 gold mine (1 - show/0 - hide) - { 0x6fe, 0x0 }, // 1790 27 gold mine color - { 0x700, 0x0 }, // 1792 28 gold mine color, wtf?, may be LM? - { 0x701, 0x0 }, // 1793 29 lumber mill color (0 - conflict, 1 - horde contr) - { 0x702, 0x0 }, // 1794 30 lumber mill (show/hide) - { 0x703, 0x0 }, // 1795 31 lumber mill color color - { 0x732, 0x1 }, // 1842 32 stables (1 - uncontrolled) - { 0x733, 0x1 }, // 1843 33 gold mine (1 - uncontrolled) - { 0x734, 0x1 }, // 1844 34 lumber mill (1 - uncontrolled) - { 0x735, 0x1 }, // 1845 35 farm (1 - uncontrolled) - { 0x736, 0x1 }, // 1846 36 blacksmith (1 - uncontrolled) - { 0x745, 0x2 }, // 1861 37 unk - { 0x7a3, 0x708 }, // 1955 38 warning limit (1800) - { 0x0, 0x0 } -}; - -static WorldStatePair EY_world_states[] = -{ - { 2753, 0 }, // WORLD_STATE_EY_TOWER_COUNT_HORDE - { 2752, 0 }, // WORLD_STATE_EY_TOWER_COUNT_ALLIANCE - { 2733, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_HORDE - { 2732, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_ALLIANCE - { 2731, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_DRAENEI_RUINS_NEUTRAL - { 2730, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_ALLIANCE - { 2729, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_HORDE - { 2728, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_MAGE_TOWER_NEUTRAL - { 2727, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_HORDE - { 2726, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_ALLIANCE - { 2725, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_FEL_REAVER_NEUTRAL - { 2724, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_HORDE - { 2723, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_ALLIANCE - { 2722, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_BLOOD_ELF_NEUTRAL - { 2757, WORLD_STATE_REMOVE }, // WORLD_STATE_EY_NETHERSTORM_FLAG_READY - { 2770, 1 }, // WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_HORDE - { 2769, 1 }, // WORLD_STATE_EY_NETHERSTORM_FLAG_STATE_ALLIANCE - { 2750, 0 }, // WORLD_STATE_EY_RESOURCES_HORDE - { 2749, 0 }, // WORLD_STATE_EY_RESOURCES_ALLIANCE - { 2565, 0x8e }, // global unk -- TODO: move to global world state - { 3085, 0x17b } // global unk -- TODO: move to global world state -}; - -static WorldStatePair SI_world_states[] = // Silithus -{ - { 2313, 0 }, // WORLD_STATE_SI_GATHERED_A - { 2314, 0 }, // WORLD_STATE_SI_GATHERED_H - { 2317, 0 } // WORLD_STATE_SI_SILITHYST_MAX -}; - -static WorldStatePair EP_world_states[] = // Eastern Plaguelands -{ - { 2327, 0 }, // WORLD_STATE_EP_TOWER_COUNT_ALLIANCE - { 2328, 0 }, // WORLD_STATE_EP_TOWER_COUNT_HORDE - { 2355, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_NEUTRAL - { 2374, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_CONTEST_ALLIANCE - { 2375, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_CONTEST_HORDE - { 2376, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_PROGRESS_ALLIANCE - { 2377, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_PROGRESS_HORDE - { 2378, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_ALLIANCE - { 2379, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_CROWNGUARD_HORDE - { 2354, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_ALLIANCE - { 2356, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_HORDE - { 2357, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_PROGRESS_ALLIANCE - { 2358, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_PROGRESS_HORDE - { 2359, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_CONTEST_ALLIANCE - { 2360, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_CONTEST_HORDE - { 2361, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_EASTWALL_NEUTRAL - { 2352, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_NEUTRAL - { 2362, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_CONTEST_ALLIANCE - { 2363, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_CONTEST_HORDE - { 2364, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_PROGRESS_ALLIANCE - { 2365, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_PROGRESS_HORDE - { 2372, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_ALLIANCE - { 2373, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_NORTHPASS_HORDE - { 2353, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_NEUTRAL - { 2366, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_CONTEST_ALLIANCE - { 2367, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_CONTEST_HORDE - not in dbc! sent for consistency's sake, and to match field count - { 2368, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_PROGRESS_ALLIANCE - { 2369, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_PROGRESS_HORDE - { 2370, WORLD_STATE_REMOVE }, // WORLD_STATE_EP_PLAGUEWOOD_ALLIANCE - { 2371, WORLD_STATE_REMOVE } // WORLD_STATE_EP_PLAGUEWOOD_HORDE -}; - -static WorldStatePair HP_world_states[] = // Hellfire Peninsula -{ - { 2490, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_TOWER_DISPLAY_A - { 2489, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_TOWER_DISPLAY_H - { 2485, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_NEUTRAL - { 2484, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_HORDE - { 2483, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_BROKEN_HILL_ALLIANCE - { 2482, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_NEUTRAL - { 2481, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_HORDE - { 2480, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_OVERLOOK_ALLIANCE - { 2478, 0 }, // WORLD_STATE_HP_TOWER_COUNT_HORDE - { 2476, 0 }, // WORLD_STATE_HP_TOWER_COUNT_ALLIANCE - { 2472, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_STADIUM_NEUTRAL - { 2471, WORLD_STATE_REMOVE }, // WORLD_STATE_HP_STADIUM_ALLIANCE - { 2470, WORLD_STATE_REMOVE } // WORLD_STATE_HP_STADIUM_HORDE -}; - -static WorldStatePair TF_world_states[] = // Terokkar Forest -{ - { 2622, 0 }, // WORLD_STATE_TF_TOWER_COUNT_H - { 2621, 0 }, // WORLD_STATE_TF_TOWER_COUNT_A - { 2620, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_TOWERS_CONTROLLED - { 2695, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_HORDE - { 2694, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_ALLIANCE - { 2693, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_NEUTRAL - { 2692, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_HORDE - { 2691, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_TOWER_ALLIANCE - { 2690, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_NEUTRAL - { 2689, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_HORDE - { 2688, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_EAST_TOWER_ALLIANCE - { 2686, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_NEUTRAL - { 2685, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_HORDE - { 2684, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_NORTH_TOWER_ALLIANCE - { 2683, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_ALLIANCE - { 2682, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_HORDE - { 2681, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_WEST_TOWER_NEUTRAL - { 2512, 0 }, // WORLD_STATE_TF_TIME_MIN_FIRST_DIGIT - { 2510, 0 }, // WORLD_STATE_TF_TIME_MIN_SECOND_DIGIT - { 2509, 0 }, // WORLD_STATE_TF_TIME_HOURS - { 2508, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_LOCKED_NEUTRAL - { 2696, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_SOUTH_EAST_TOWER_NEUTRAL - { 2768, WORLD_STATE_REMOVE }, // WORLD_STATE_TF_LOCKED_HORDE - { 2767, WORLD_STATE_REMOVE } // WORLD_STATE_TF_LOCKED_ALLIANCE -}; - -static WorldStatePair ZM_world_states[] = // Zangarmarsh -{ - { 2653, 0x1 }, // WORLD_STATE_ZM_UNK - { 2652, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_NEUTRAL - { 2651, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_HORDE - { 2650, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_ALLIANCE - { 2649, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_HORDE - { 2648, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_ALLIANCE - { 2647, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_GRAVEYARD_NEUTRAL - { 2646, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_NEUTRAL - { 2645, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_HORDE - { 2644, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_ALLIANCE - { 2560, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_NEUTRAL - { 2559, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_HORDE - { 2558, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_EAST_UI_ALLIANCE - { 2557, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_NEUTRAL - { 2556, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_HORDE - { 2555, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_BEACON_WEST_UI_ALLIANCE - { 2658, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_READY_HORDE - { 2657, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_NOT_READY_HORDE - { 2656, WORLD_STATE_REMOVE }, // WORLD_STATE_ZM_FLAG_NOT_READY_ALLIANCE - { 2655, WORLD_STATE_REMOVE } // WORLD_STATE_ZM_FLAG_READY_ALLIANCE -}; - -static WorldStatePair NA_world_states[] = -{ - { 2503, 0 }, // WORLD_STATE_NA_GUARDS_HORDE - { 2502, 0 }, // WORLD_STATE_NA_GUARDS_ALLIANCE - { 2493, 0 }, // WORLD_STATE_NA_GUARDS_MAX - { 2491, 0 }, // WORLD_STATE_NA_GUARDS_LEFT - { 2762, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_NEUTRAL_H - { 2662, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_NEUTRAL_A - { 2663, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_H - { 2664, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_NORTH_A - { 2760, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_NEUTRAL_H - { 2670, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_NEUTRAL_A - { 2668, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_H - { 2669, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_SOUTH_A - { 2761, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_NEUTRAL_H - { 2667, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_NEUTRAL_A - { 2665, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_H - { 2666, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_WEST_A - { 2763, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_NEUTRAL_H - { 2659, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_NEUTRAL_A - { 2660, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_H - { 2661, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_WYVERN_EAST_A - { 2671, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL - { 2676, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL_A - { 2677, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_NEUTRAL_H - { 2672, WORLD_STATE_REMOVE }, // WORLD_STATE_NA_HALAA_HORDE - { 2673, WORLD_STATE_REMOVE } // WORLD_STATE_NA_HALAA_ALLIANCE -}; - void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) { // data depends on zoneid/mapid... @@ -8787,136 +8491,53 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) size_t count_pos = data.wpos(); data << uint16(0); // count of uint64 blocks, placeholder - // common fields - FillInitialWorldState(data, count, 0x8d8, 0x0); // 2264 1 - FillInitialWorldState(data, count, 0x8d7, 0x0); // 2263 2 - FillInitialWorldState(data, count, 0x8d6, 0x0); // 2262 3 - FillInitialWorldState(data, count, 0x8d5, 0x0); // 2261 4 - FillInitialWorldState(data, count, 0x8d4, 0x0); // 2260 5 - FillInitialWorldState(data, count, 0x8d3, 0x0); // 2259 6 - // 3191 7 Current arena season + // Current arena season FillInitialWorldState(data, count, 0xC77, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_ID)); - // 3901 8 Previous arena season + // Previous arena season FillInitialWorldState(data, count, 0xF3D, sWorld.getConfig(CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID)); - FillInitialWorldState(data, count, 0xED9, 1); // 3801 9 0 - Battle for Wintergrasp in progress, 1 - otherwise - // 4354 10 Time when next Battle for Wintergrasp starts - FillInitialWorldState(data, count, 0x1102, uint32(time(NULL) + 9000)); - - if (mapid == 530) // Outland - { - FillInitialWorldState(data, count, 0x9bf, 0x0); // 2495 - FillInitialWorldState(data, count, 0x9bd, 0xF); // 2493 - FillInitialWorldState(data, count, 0x9bb, 0xF); // 2491 - } + // 0 - Battle for Wintergrasp in progress, 1 - otherwise + FillInitialWorldState(data, count, 0xED9, 1); + // Time when next Battle for Wintergrasp starts + FillInitialWorldState(data, count, 0x1102, uint32(time(nullptr) + 9000)); switch (zoneid) { - case 1: // Dun Morogh - case 11: // Wetlands - case 12: // Elwynn Forest - case 38: // Loch Modan - case 40: // Westfall - case 51: // Searing Gorge - case 1519: // Stormwind City - case 1537: // Ironforge - case 2257: // Deeprun Tram - case 3703: // Shattrath City - break; case 139: // Eastern Plaguelands - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) - outdoorPvP->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, EP_world_states); - break; case 1377: // Silithus + case 3483: // Hellfire Peninsula + case 3518: // Nagrand + case 3519: // Terokkar Forest + case 3521: // Zangarmarsh if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) outdoorPvP->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, SI_world_states); break; case 2597: // AV if (bg && bg->GetTypeID() == BATTLEGROUND_AV) bg->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, AV_world_states); break; case 3277: // WS if (bg && bg->GetTypeID() == BATTLEGROUND_WS) bg->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, WS_world_states); break; case 3358: // AB if (bg && bg->GetTypeID() == BATTLEGROUND_AB) bg->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, AB_world_states); break; case 3820: // EY if (bg && bg->GetTypeID() == BATTLEGROUND_EY) bg->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, EY_world_states); - break; - case 3483: // Hellfire Peninsula - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) - outdoorPvP->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, HP_world_states); - break; - case 3518: // Nagrand - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) - outdoorPvP->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, NA_world_states); - break; - case 3519: // Terokkar Forest - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) - outdoorPvP->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, TF_world_states); - break; - case 3521: // Zangarmarsh - if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(zoneid)) - outdoorPvP->FillInitialWorldStates(data, count); - else - FillInitialWorldState(data, count, ZM_world_states); break; case 3698: // Nagrand Arena if (bg && bg->GetTypeID() == BATTLEGROUND_NA) bg->FillInitialWorldStates(data, count); - else - { - FillInitialWorldState(data, count, 0xa0f, 0x0); // 2575 7 - FillInitialWorldState(data, count, 0xa10, 0x0); // 2576 8 - FillInitialWorldState(data, count, 0xa11, 0x0); // 2577 9 show - } break; case 3702: // Blade's Edge Arena if (bg && bg->GetTypeID() == BATTLEGROUND_BE) bg->FillInitialWorldStates(data, count); - else - { - FillInitialWorldState(data, count, 0x9f0, 0x0); // 2544 7 gold - FillInitialWorldState(data, count, 0x9f1, 0x0); // 2545 8 green - FillInitialWorldState(data, count, 0x9f3, 0x0); // 2547 9 show - } break; case 3968: // Ruins of Lordaeron if (bg && bg->GetTypeID() == BATTLEGROUND_RL) bg->FillInitialWorldStates(data, count); - else - { - FillInitialWorldState(data, count, 0xbb8, 0x0); // 3000 7 gold - FillInitialWorldState(data, count, 0xbb9, 0x0); // 3001 8 green - FillInitialWorldState(data, count, 0xbba, 0x0); // 3002 9 show - } - break; - default: - FillInitialWorldState(data, count, 0x914, 0x0); // 2324 7 - FillInitialWorldState(data, count, 0x913, 0x0); // 2323 8 - FillInitialWorldState(data, count, 0x912, 0x0); // 2322 9 - FillInitialWorldState(data, count, 0x915, 0x0); // 2325 10 break; } @@ -13093,9 +12714,9 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId) { Creature* pCreature = (Creature*)pSource; - uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); + uint32 NpcFlagss = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); - if (!(itr->second.npc_option_npcflag & npcflags)) + if (!(itr->second.npc_option_NpcFlags & NpcFlagss)) continue; switch (itr->second.option_id) @@ -13126,7 +12747,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId) case GOSSIP_OPTION_TRAINER: // pet trainers not have spells in fact now /* FIXME: gossip menu with single unlearn pet talents option not show by some reason - if (pCreature->GetCreatureInfo()->trainer_type == TRAINER_TYPE_PETS) + if (pCreature->GetCreatureInfo()->TrainerType == TRAINER_TYPE_PETS) hasMenuItem = false; else */ if (!pCreature->IsTrainerOf(this, false)) @@ -13137,7 +12758,7 @@ void Player::PrepareGossipMenu(WorldObject* pSource, uint32 menuId) hasMenuItem = false; break; case GOSSIP_OPTION_UNLEARNPETSKILLS: - if (pCreature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->trainer_class != CLASS_HUNTER) + if (pCreature->GetCreatureInfo()->TrainerType != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->TrainerClass != CLASS_HUNTER) hasMenuItem = false; else if (Pet* pet = GetPet()) { @@ -18660,39 +18281,24 @@ void Player::RemovePet(PetSaveMode mode) pet->Unsummon(mode, this); } -void Player::BuildPlayerChat(WorldPacket* data, uint8 msgtype, const std::string& text, uint32 language, const char* addonPrefix) const -{ - *data << uint8(msgtype); - *data << uint32(language); - *data << GetObjectGuid(); - *data << uint32(0); // constant unknown time 4.3.4 - if (addonPrefix) - *data << addonPrefix; - else - *data << GetObjectGuid(); - *data << uint32(text.length() + 1); - *data << text; - *data << uint8(GetChatTag()); -} - void Player::Say(const std::string& text, const uint32 language) { - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_SAY, text, language); + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName()); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true); } void Player::Yell(const std::string& text, const uint32 language) { - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_YELL, text, language); + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName()); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true); } void Player::TextEmote(const std::string& text) { - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_EMOTE, text, LANG_UNIVERSAL); + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, text.c_str(), LANG_UNIVERSAL, GetChatTag(), GetObjectGuid(), GetName()); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true, !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT)); } @@ -18700,12 +18306,12 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv { Player* rPlayer = sObjectMgr.GetPlayer(receiver); - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_WHISPER, text, language); + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, text.c_str(), Language(language), GetChatTag(), GetObjectGuid(), GetName()); rPlayer->GetSession()->SendPacket(&data); - data.Initialize(SMSG_MESSAGECHAT, 200); - rPlayer->BuildPlayerChat(&data, CHAT_MSG_WHISPER_INFORM, text, language); + data.clear(); + ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER_INFORM, text.c_str(), Language(language), CHAT_TAG_NONE, rPlayer->GetObjectGuid()); GetSession()->SendPacket(&data); if (!isAcceptWhispers()) @@ -18721,17 +18327,6 @@ void Player::Whisper(const std::string& text, uint32 language, ObjectGuid receiv ChatHandler(this).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName(), rPlayer->autoReplyMsg.c_str()); } -void Player::WhisperAddon(const std::string& text, const std::string& prefix, ObjectGuid receiver) -{ - Player* rPlayer = sObjectMgr.GetPlayer(receiver); - - std::string _text(text); - - WorldPacket data(SMSG_MESSAGECHAT, 200); - BuildPlayerChat(&data, CHAT_MSG_WHISPER, _text, LANG_UNIVERSAL, prefix.c_str()); - rPlayer->GetSession()->SendPacket(&data); -} - void Player::PetSpellInitialize() { Pet* pet = GetPet(); @@ -18745,7 +18340,7 @@ void Player::PetSpellInitialize() WorldPacket data(SMSG_PET_SPELLS, 8 + 2 + 4 + 4 + 4 * MAX_UNIT_ACTION_BAR_INDEX + 1 + 1); data << pet->GetObjectGuid(); - data << uint16(pet->GetCreatureInfo()->family); // creature family (required for pet talents) + data << uint16(pet->GetCreatureInfo()->Family); // creature family (required for pet talents) data << uint32(0); data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); @@ -18862,7 +18457,7 @@ void Player::CharmSpellInitialize() { CreatureInfo const* cinfo = ((Creature*)charm)->GetCreatureInfo(); - if (cinfo && cinfo->type == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK) + if (cinfo && cinfo->CreatureType == CREATURE_TYPE_DEMON && getClass() == CLASS_WARLOCK) { for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) { @@ -21486,7 +21081,7 @@ bool Player::isHonorOrXPTarget(Unit* pVictim) const { if (((Creature*)pVictim)->IsTotem() || ((Creature*)pVictim)->IsPet() || - ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) + ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_XP_AT_KILL) return false; } return true; @@ -22808,7 +22403,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa if (!ci) return; - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family); if (!pet_family) return; @@ -23033,7 +22628,7 @@ void Player::BuildPetTalentsInfoData(WorldPacket* data) if (!ci) return; - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); + CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->Family); if (!pet_family || pet_family->petTalentType < 0) return; diff --git a/src/game/Object/Player.h b/src/game/Object/Player.h index cbbb81b0a..ab41b6c3d 100644 --- a/src/game/Object/Player.h +++ b/src/game/Object/Player.h @@ -43,6 +43,7 @@ #include "ReputationMgr.h" #include "BattleGround.h" #include "SharedDefines.h" +#include "Chat.h" #include #include @@ -1111,20 +1112,15 @@ class Player : public Unit void SendInitialPacketsAfterAddToMap(); void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); - Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask); + Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 NpcFlagsmask); GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const; void ToggleAFK(); void ToggleDND(); - bool isAFK() const - { - return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); - } - bool isDND() const - { - return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); - } - uint8 GetChatTag() const; + bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); } + bool isDND() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); } + ChatTagFlags GetChatTag() const; + std::string autoReplyMsg; uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, uint32 newskintone); @@ -1219,8 +1215,6 @@ class Player : public Unit void Yell(const std::string& text, const uint32 language); void TextEmote(const std::string& text); void Whisper(const std::string& text, const uint32 language, ObjectGuid receiver); - void WhisperAddon(const std::string& text, const std::string& prefix, ObjectGuid receiver); - void BuildPlayerChat(WorldPacket* data, uint8 msgtype, const std::string& text, uint32 language, const char* addonPrefix = NULL) const; /*********************************************************/ /*** STORAGE SYSTEM ***/ diff --git a/src/game/Object/SpellMgr.cpp b/src/game/Object/SpellMgr.cpp index 4324d5b07..b59aefa7a 100644 --- a/src/game/Object/SpellMgr.cpp +++ b/src/game/Object/SpellMgr.cpp @@ -757,10 +757,16 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex) case 18153: // Kodo Kombobulator case 32312: // Move 1 case 37388: // Move 2 + case 45863: // Cosmetic - Incinerate to Random Target case 49634: // Sergeant's Flare case 54530: // Opening - case 56099: // Throw Ice + case 56099: // Throw Ice + case 58533: // Return to Stormwind + case 58552: // Return to Orgrimmar case 62105: // To'kini's Blowgun + case 63745: // Sara's Blessing + case 63747: // Sara's Fervor + case 64402: // Rocket Strike return true; default: break; @@ -2220,6 +2226,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 64417) || (spellInfo_2->Id == 62169 && spellInfo_1->Id == 64417)) return false; + + // Auto Grow and Healthy Spore Visual + if ((spellInfo_1->Id == 62559 && spellInfo_2->Id == 62538) || + (spellInfo_2->Id == 62559 && spellInfo_1->Id == 62538)) + return false; break; } case SPELLFAMILY_MAGE: @@ -3523,9 +3534,9 @@ void SpellMgr::LoadSpellScriptTarget() } if (const CreatureInfo* cInfo = sCreatureStorage.LookupEntry(itr->targetEntry)) { - if (itr->spellId == 30427 && !cInfo->SkinLootId) + if (itr->spellId == 30427 && !cInfo->SkinningLootId) { - sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!", cInfo->Entry); + sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinLootid. Gas extraction will not work!", cInfo->Entry); sSpellScriptTargetStorage.EraseEntry(itr->spellId); continue; } @@ -3710,7 +3721,7 @@ bool SpellMgr::LoadPetDefaultSpells_helper(CreatureInfo const* cInfo, PetDefault return false; // remove duplicates with levelupSpells if any - if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? GetPetLevelupSpellList(cInfo->family) : NULL) + if (PetLevelupSpellSet const* levelupSpells = cInfo->Family ? GetPetLevelupSpellList(cInfo->Family) : NULL) { for (int j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) { diff --git a/src/game/Object/StatSystem.cpp b/src/game/Object/StatSystem.cpp index f79a6cb4d..d87e23bf7 100644 --- a/src/game/Object/StatSystem.cpp +++ b/src/game/Object/StatSystem.cpp @@ -883,12 +883,12 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) UnitMods unitMod = (attType == BASE_ATTACK ? UNIT_MOD_DAMAGE_MAINHAND : UNIT_MOD_DAMAGE_OFFHAND); /* difference in AP between current attack power and base value from DB */ - float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower; + float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->MeleeAttackPower; float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f); float base_pct = GetModifierValue(unitMod, BASE_PCT); float total_value = GetModifierValue(unitMod, TOTAL_VALUE); float total_pct = GetModifierValue(unitMod, TOTAL_PCT); - float dmg_multiplier = GetCreatureInfo()->dmg_multiplier; + float dmg_multiplier = GetCreatureInfo()->DamageMultiplier; float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index b5ab0498c..f0b2b2f15 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -902,48 +902,11 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa return 0; } - // no xp,health if type 8 /critters/ - if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER) - { - // TODO: fix this part - // Critter may not die of damage taken, instead expect it to run away (no fighting back) - // If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat. - // It is unclear how it should work for other cases. - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies"); - - ((Creature*)pVictim)->SetLootRecipient(this); - - JustKilledCreature((Creature*)pVictim, NULL); - pVictim->SetHealth(0); - - return damage; - } - DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamageStart"); uint32 health = pVictim->GetHealth(); DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "deal dmg:%d to health:%d ", damage, health); - // duel ends when player has 1 or less hp - bool duel_hasEnded = false; - if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1)) - { - // prevent kill only if killed in duel and killed by opponent or opponent controlled creature - if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid()) - damage = health - 1; - - duel_hasEnded = true; - } - // Get in CombatState - if (pVictim != this && damagetype != DOT) - { - SetInCombatWith(pVictim); - pVictim->SetInCombatWith(this); - - if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) - SetContestedPvP(attackedPlayer); - } - // Rage from Damage made (only from direct weapon damage) if (cleanDamage && damagetype == DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (GetPowerType() == POWER_RAGE)) { @@ -978,6 +941,70 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa } } + // no xp,health if type 8 /critters/ + if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetCreatureType() == CREATURE_TYPE_CRITTER) + { + // TODO: fix this part + // Critter may not die of damage taken, instead expect it to run away (no fighting back) + // If (this) is TYPEID_PLAYER, (this) will enter combat w/victim, but after some time, automatically leave combat. + // It is unclear how it should work for other cases. + DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "DealDamage critter, critter dies"); + + ((Creature*)pVictim)->SetLootRecipient(this); + + JustKilledCreature((Creature*)pVictim, nullptr); + pVictim->SetHealth(0); + + return damage; + } + + // share damage by auras + AuraList const& vShareDamageAuras = pVictim->GetAurasByType(SPELL_AURA_SHARE_DAMAGE_PCT); + for (AuraList::const_iterator itr = vShareDamageAuras.begin(); itr != vShareDamageAuras.end(); ++itr) + { + if (!spellProto) + break; + + SpellEffectEntry const* spellEffect = spellProto->GetSpellEffect(EFFECT_INDEX_0); + + // if damage is done by another shared aura, then skip to avoid circular reference (aura 300 is only applied on effect_idx_0 + if (spellEffect && spellEffect->Effect == SPELL_EFFECT_APPLY_AURA && + spellEffect->EffectApplyAuraName == SPELL_AURA_SHARE_DAMAGE_PCT) + break; + + if (Unit* shareTarget = (*itr)->GetCaster()) + { + if (shareTarget != pVictim && ((*itr)->GetMiscValue() & damageSchoolMask)) + { + SpellEntry const* shareSpell = (*itr)->GetSpellProto(); + uint32 shareDamage = uint32(damage*(*itr)->GetModifier()->m_amount / 100.0f); + DealDamageMods(shareTarget, shareDamage, nullptr); + DealDamage(shareTarget, shareDamage, 0, damagetype, GetSpellSchoolMask(shareSpell), shareSpell, false); + } + } + } + + // duel ends when player has 1 or less hp + bool duel_hasEnded = false; + if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health - 1)) + { + // prevent kill only if killed in duel and killed by opponent or opponent controlled creature + if (((Player*)pVictim)->duel->opponent == this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid()) + damage = health - 1; + + duel_hasEnded = true; + } + + // Get in CombatState + if (pVictim != this && damagetype != DOT) + { + SetInCombatWith(pVictim); + pVictim->SetInCombatWith(this); + + if (Player* attackedPlayer = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) + SetContestedPvP(attackedPlayer); + } + if (GetTypeId() == TYPEID_PLAYER && this != pVictim) { Player* killer = ((Player*)this); @@ -1208,11 +1235,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa pVictim->AttackedBy(this); } - if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE) - { - if (!spellProto || !(spellProto->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DIRECT_DAMAGE)) - pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE); - } if (pVictim->GetTypeId() != TYPEID_PLAYER) { float threat = damage * sSpellMgr.GetSpellThreatMultiplier(spellProto); @@ -1245,21 +1267,6 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa } } - // TODO: Store auras by interrupt flag to speed this up. - SpellAuraHolderMap& vAuras = pVictim->GetSpellAuraHolderMap(); - for (SpellAuraHolderMap::const_iterator i = vAuras.begin(), next; i != vAuras.end(); i = next) - { - const SpellEntry* se = i->second->GetSpellProto(); - next = i; ++next; - if (spellProto && spellProto->Id == se->Id) // Not drop auras added by self - continue; - if (!se->GetProcFlags() && (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE)) - { - pVictim->RemoveAurasDueToSpell(i->second->GetId()); - next = vAuras.begin(); - } - } - if (damagetype != NODAMAGE && damage && pVictim->GetTypeId() == TYPEID_PLAYER) { if (damagetype != DOT) @@ -1426,7 +1433,7 @@ void Unit::JustKilledCreature(Creature* victim, Player* responsiblePlayer) { if (m->IsRaidOrHeroicDungeon()) { - if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + if (victim->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_INSTANCE_BIND) { ((DungeonMap*)m)->PermBindAllPlayers(creditedPlayer); } } else @@ -1779,7 +1786,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) } // TODO for melee need create structure as in -void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType) +void Unit::CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/) { damageInfo->attacker = this; damageInfo->target = pVictim; @@ -1836,7 +1843,7 @@ void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* da damageInfo->cleanDamage = 0; return; } - damage += CalculateDamage(damageInfo->attackType, false); + uint32 damage = CalculateDamage(damageInfo->attackType, false); // Add melee damage bonus damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType); damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType); @@ -2909,7 +2916,7 @@ void Unit::AttackerStateUpdate(Unit* pVictim, WeaponAttackType attType, bool ext pVictim = SelectMagnetTarget(pVictim); CalcDamageInfo damageInfo; - CalculateMeleeDamage(pVictim, 0, &damageInfo, attType); + CalculateMeleeDamage(pVictim, &damageInfo, attType); // Send log damage message to client DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb); SendAttackStateUpdate(&damageInfo); @@ -3028,7 +3035,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT else parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25; - if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_PARRY))) + if (parry_chance > 0 && (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_PARRY))) { parry_chance -= skillBonus; @@ -3066,7 +3073,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT // check if attack comes from behind, nobody can parry or block if attacker is behind if (!from_behind) { - if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_BLOCK)) + if (pVictim->GetTypeId() == TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK)) { tmp = block_chance; if ((tmp > 0) // check if unit _can_ block @@ -3092,7 +3099,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* pVictim, WeaponAttackT if (GetLevelForTarget(pVictim) >= pVictim->GetLevelForTarget(this) + 4 && // can be from by creature (if can) or from controlled player that considered as creature ((GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->IsPet() && - !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_CRUSH)) || + !(((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_CRUSH)) || GetTypeId() == TYPEID_PLAYER && GetCharmerOrOwnerGuid())) { // when their weapon skill is 15 or more above victim's defense skill @@ -3226,7 +3233,7 @@ bool Unit::IsSpellBlocked(Unit* pCaster, SpellEntry const* spellEntry, WeaponAtt // Check creatures ExtraFlags for disable block if (GetTypeId() == TYPEID_UNIT) { - if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_NO_BLOCK) + if (((Creature*)this)->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_NO_BLOCK) return false; } @@ -3363,7 +3370,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* pVictim, SpellEntry const* spell) if (pVictim->GetTypeId() == TYPEID_UNIT) { uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->ExtraFlags; - if (flagEx & CREATURE_FLAG_EXTRA_NO_PARRY) + if (flagEx & CREATURE_EXTRA_FLAG_NO_PARRY) canParry = false; } // Ignore combat result aura @@ -6225,6 +6232,26 @@ bool Unit::isAttackingPlayer() const return CheckAllControlledUnits(IsAttackingPlayerHelper(), CONTROLLED_PET | CONTROLLED_TOTEMS | CONTROLLED_GUARDIANS | CONTROLLED_CHARM); } +bool Unit::CanAttackByItself() const +{ + if (!IsVehicle()) + return true; + + for (uint8 i = 0; i < MAX_VEHICLE_SEAT; ++i) + { + if (uint32 seatId = m_vehicleInfo->GetVehicleEntry()->m_seatID[i]) + { + if (VehicleSeatEntry const* seatEntry = sVehicleSeatStore.LookupEntry(seatId)) + { + if (seatEntry->m_flags & SEAT_FLAG_CAN_CONTROL) + return false; + } + } + } + + return true; +} + void Unit::RemoveAllAttackers() { while (!m_attackers.empty()) @@ -8431,7 +8458,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) { pCreature->AI()->EnterCombat(enemy); } // Some bosses are set into combat with zone - if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_FLAG_EXTRA_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer()) + if (GetMap()->IsDungeon() && (pCreature->GetCreatureInfo()->ExtraFlags & CREATURE_EXTRA_FLAG_AGGRO_ZONE) && enemy && enemy->IsControlledByPlayer()) { pCreature->SetInCombatWithZone(); } if (InstanceData* mapInstance = GetInstanceData()) @@ -8466,7 +8493,7 @@ void Unit::ClearInCombat() if (GetTypeId() == TYPEID_UNIT) { Creature* cThis = static_cast(this); - if (cThis->GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK)) + if (cThis->GetCreatureInfo()->UnitFlags & UNIT_FLAG_OOC_NOT_ATTACKABLE && !(cThis->GetTemporaryFactionFlags() & TEMPFACTION_TOGGLE_OOC_NOT_ATTACK)) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); clearUnitState(UNIT_STAT_ATTACK_PLAYER); @@ -8968,10 +8995,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio, bool ignore switch (mtype) { case MOVE_RUN: - speed *= ((Creature*)this)->GetCreatureInfo()->speed_run; + speed *= ((Creature*)this)->GetCreatureInfo()->SpeedRun; break; case MOVE_WALK: - speed *= ((Creature*)this)->GetCreatureInfo()->speed_walk; + speed *= ((Creature*)this)->GetCreatureInfo()->SpeedWalk; break; default: break; @@ -9900,7 +9927,7 @@ uint32 Unit::GetCreatureType() const return CREATURE_TYPE_HUMANOID; } else - return ((Creature*)this)->GetCreatureInfo()->type; + return ((Creature*)this)->GetCreatureInfo()->CreatureType; } /*####################################### @@ -10816,76 +10843,91 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag, if (itr->second->IsDeleted()) continue; - SpellProcEventEntry const* spellProcEvent = NULL; + SpellProcEventEntry const* spellProcEvent = nullptr; + // check if that aura is triggered by proc event (then it will be managed by proc handler) if (!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, spellProcEvent)) + { + // spell seem not managed by proc system, although some case need to be handled + + // only process damage case on victim + if (!isVictim || !(procFlag & PROC_FLAG_TAKEN_ANY_DAMAGE)) + continue; + + const SpellEntry* se = itr->second->GetSpellProto(); + + // check if the aura is interruptible by damage and if its not just added by this spell (spell who is responsible for this damage is procSpell) + if (se->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_DAMAGE && (!procSpell || procSpell->Id != se->Id)) + { + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "ProcDamageAndSpell: Added Spell %u to 'remove aura due to spell' list! Reason: Damage received.", se->Id); + removedSpells.push_back(se->Id); + } continue; + } itr->second->SetInUse(true); // prevent holder deletion procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second)); } - // Nothing found - if (procTriggered.empty()) - return; - - // Handle effects proceed this time - for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr) + if (!procTriggered.empty()) { - // Some auras can be deleted in function called in this loop (except first, ofc) - SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder; - if (triggeredByHolder->IsDeleted()) - continue; - - SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent; - bool useCharges = triggeredByHolder->GetAuraCharges() > 0; - bool procSuccess = true; - bool anyAuraProc = false; - - // For players set spell cooldown if need - uint32 cooldown = 0; - if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown) - cooldown = spellProcEvent->cooldown; - - for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + // Handle effects proceed this time + for (ProcTriggeredList::const_iterator itr = procTriggered.begin(); itr != procTriggered.end(); ++itr) { - Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i)); - if (!triggeredByAura) + // Some auras can be deleted in function called in this loop (except first, ofc) + SpellAuraHolder* triggeredByHolder = itr->triggeredByHolder; + if (triggeredByHolder->IsDeleted()) continue; - SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i)); - if (!spellEffect) - continue; + SpellProcEventEntry const* spellProcEvent = itr->spellProcEvent; + bool useCharges = triggeredByHolder->GetAuraCharges() > 0; + bool procSuccess = true; + bool anyAuraProc = false; - if (procSpell) + // For players set spell cooldown if need + uint32 cooldown = 0; + if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown) + cooldown = spellProcEvent->cooldown; + + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) { - if (spellProcEvent) - { - if (spellProcEvent->spellFamilyMask[i]) - { - if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) - continue; + Aura* triggeredByAura = triggeredByHolder->GetAuraByEffectIndex(SpellEffectIndex(i)); + if (!triggeredByAura) + continue; - // don't allow proc from cast end for non modifier spells - // unless they have proc ex defined for that - if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell)) + SpellEffectEntry const* spellEffect = triggeredByHolder->GetSpellProto()->GetSpellEffect(SpellEffectIndex(i)); + if (!spellEffect) + continue; + + if (procSpell) + { + if (spellProcEvent) + { + if (spellProcEvent->spellFamilyMask[i]) { - if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE) + if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) + continue; + + // don't allow proc from cast end for non modifier spells + // unless they have proc ex defined for that + if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), procSpell)) + { + if (useCharges && procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE) + continue; + } + else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END) continue; } - else if (spellProcEvent->procEx == PROC_EX_NONE && procExtra == PROC_EX_CAST_END) + // don't check dbc FamilyFlags if schoolMask exists + else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask)) continue; } - // don't check dbc FamilyFlags if schoolMask exists - else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask)) + else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true)) continue; } - else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true)) - continue; - } - SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown); - switch (procResult) - { + SpellAuraProcResult procResult = (*this.*AuraProcHandler[spellEffect->EffectApplyAuraName])(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown); + switch (procResult) + { case SPELL_AURA_PROC_CANT_TRIGGER: continue; case SPELL_AURA_PROC_FAILED: @@ -10893,20 +10935,21 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* pTarget, uint32 procFlag, break; case SPELL_AURA_PROC_OK: break; + } + + anyAuraProc = true; } - anyAuraProc = true; - } + // Remove charge (aura can be removed by triggers) + if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted()) + { + // If last charge dropped add spell to remove list + if (triggeredByHolder->DropAuraCharge()) + removedSpells.push_back(triggeredByHolder->GetId()); + } - // Remove charge (aura can be removed by triggers) - if (useCharges && procSuccess && anyAuraProc && !triggeredByHolder->IsDeleted()) - { - // If last charge dropped add spell to remove list - if (triggeredByHolder->DropAuraCharge()) - removedSpells.push_back(triggeredByHolder->GetId()); + triggeredByHolder->SetInUse(false); } - - triggeredByHolder->SetInUse(false); } if (!removedSpells.empty()) diff --git a/src/game/Object/Unit.h b/src/game/Object/Unit.h index 04801a42f..7aad62d6e 100644 --- a/src/game/Object/Unit.h +++ b/src/game/Object/Unit.h @@ -1253,6 +1253,18 @@ enum IgnoreUnitState #define REGEN_TIME_PRECISE 500 // Used in Spell::CheckPower for precise regeneration in spell cast time #define REGEN_TIME_HOLY_POWER 10000 // This determines how often holy power regen is processed +// Power type values defines +enum PowerDefaults +{ + POWER_RAGE_DEFAULT = 1000, + POWER_FOCUS_DEFAULT = 100, + POWER_ENERGY_DEFAULT = 100, + POWER_RUNE_DEFAULT = 8, + POWER_RUNIC_POWER_DEFAULT = 1000, + POWER_HOLY_POWER_DEFAULT = 3, + POWER_SOUL_SHARDS_DEFAULT = 3, +}; + struct SpellProcEventEntry; // used only privately #define MAX_OBJECT_SLOT 5 @@ -1492,6 +1504,11 @@ class Unit : public WorldObject * @return true if you and/or your pets/minions etc are attacking a player. */ bool isAttackingPlayer() const; + /** + * Checks if wa vehicle is allowed to attack other units by itself. + * @return true if vehicle can attack itself. + */ + bool CanAttackByItself() const; /** * @return The victim that you are currently attacking */ @@ -2120,7 +2137,7 @@ class Unit : public WorldObject * @param damageInfo this is filled with data about what kind of damage that was done * @param attackType type of attack, base/off/ranged */ - void CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); + void CalculateMeleeDamage(Unit* pVictim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); /** * Deals melee damage, if the attack was parried we reduce the victims time until next hit * instead of the weapons normal time by 20 or 60%. diff --git a/src/game/OutdoorPvP/OutdoorPvP.cpp b/src/game/OutdoorPvP/OutdoorPvP.cpp index 40e64cbff..9245fe9f4 100644 --- a/src/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/game/OutdoorPvP/OutdoorPvP.cpp @@ -79,14 +79,24 @@ void OutdoorPvP::HandleGameObjectCreate(GameObject* go) { // set initial data and activate capture points if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT) - go->SetCapturePointSlider(sOutdoorPvPMgr.GetCapturePointSliderValue(go->GetEntry(), CAPTURE_SLIDER_MIDDLE)); + { + CapturePointSliderMap const* capturePoints = sOutdoorPvPMgr.GetCapturePointSliderMap(); + CapturePointSliderMap::const_iterator itr = capturePoints->find(go->GetEntry()); + if (itr != capturePoints->end()) + go->SetCapturePointSlider(itr->second.Value, itr->second.IsLocked); + else + go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false); + } } void OutdoorPvP::HandleGameObjectRemove(GameObject* go) { // save capture point slider value (negative value if locked) if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT) - sOutdoorPvPMgr.SetCapturePointSlider(go->GetEntry(), go->getLootState() == GO_ACTIVATED ? go->GetCapturePointSlider() : -go->GetCapturePointSlider()); + { + CapturePointSlider value(go->GetCapturePointSliderValue(), go->getLootState() != GO_ACTIVATED); + sOutdoorPvPMgr.SetCapturePointSlider(go->GetEntry(), value); + } } /** diff --git a/src/game/OutdoorPvP/OutdoorPvP.h b/src/game/OutdoorPvP/OutdoorPvP.h index a5a246e41..3e4c5dd69 100644 --- a/src/game/OutdoorPvP/OutdoorPvP.h +++ b/src/game/OutdoorPvP/OutdoorPvP.h @@ -48,7 +48,7 @@ enum CapturePointAnimations CAPTURE_ANIM_NEUTRAL = 2 }; -typedef std::map < ObjectGuid /*playerGuid*/, bool /*isMainZone*/ > GuidZoneMap; +typedef std::map GuidZoneMap; class OutdoorPvP { @@ -65,7 +65,7 @@ class OutdoorPvP virtual bool HandleEvent(uint32 /*eventId*/, GameObject* /*go*/) { return false; } // handle capture objective complete - virtual void HandleObjectiveComplete(uint32 /*eventId*/, std::list /*players*/, Team /*team*/) {} + virtual void HandleObjectiveComplete(uint32 /*eventId*/, const std::list& /*players*/, Team /*team*/) {} // Called when a creature is created virtual void HandleCreatureCreate(Creature* /*creature*/) {} diff --git a/src/game/OutdoorPvP/OutdoorPvPEP.cpp b/src/game/OutdoorPvP/OutdoorPvPEP.cpp index 79b9ec15f..9536a3f57 100644 --- a/src/game/OutdoorPvP/OutdoorPvPEP.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPEP.cpp @@ -148,38 +148,38 @@ void OutdoorPvPEP::HandleGameObjectCreate(GameObject* go) } } -void OutdoorPvPEP::HandleObjectiveComplete(uint32 eventId, std::list players, Team team) +void OutdoorPvPEP::HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) { uint32 credit = 0; switch (eventId) { - case EVENT_CROWNGUARD_PROGRESS_ALLIANCE: - case EVENT_CROWNGUARD_PROGRESS_HORDE: - credit = NPC_CROWNGUARD_TOWER_QUEST_DOODAD; - break; - case EVENT_EASTWALL_PROGRESS_ALLIANCE: - case EVENT_EASTWALL_PROGRESS_HORDE: - credit = NPC_EASTWALL_TOWER_QUEST_DOODAD; - break; - case EVENT_NORTHPASS_PROGRESS_ALLIANCE: - case EVENT_NORTHPASS_PROGRESS_HORDE: - credit = NPC_NORTHPASS_TOWER_QUEST_DOODAD; - break; - case EVENT_PLAGUEWOOD_PROGRESS_ALLIANCE: - case EVENT_PLAGUEWOOD_PROGRESS_HORDE: - credit = NPC_PLAGUEWOOD_TOWER_QUEST_DOODAD; - break; - default: - return; + case EVENT_CROWNGUARD_PROGRESS_ALLIANCE: + case EVENT_CROWNGUARD_PROGRESS_HORDE: + credit = NPC_CROWNGUARD_TOWER_QUEST_DOODAD; + break; + case EVENT_EASTWALL_PROGRESS_ALLIANCE: + case EVENT_EASTWALL_PROGRESS_HORDE: + credit = NPC_EASTWALL_TOWER_QUEST_DOODAD; + break; + case EVENT_NORTHPASS_PROGRESS_ALLIANCE: + case EVENT_NORTHPASS_PROGRESS_HORDE: + credit = NPC_NORTHPASS_TOWER_QUEST_DOODAD; + break; + case EVENT_PLAGUEWOOD_PROGRESS_ALLIANCE: + case EVENT_PLAGUEWOOD_PROGRESS_HORDE: + credit = NPC_PLAGUEWOOD_TOWER_QUEST_DOODAD; + break; + default: + return; } - for (std::list::iterator itr = players.begin(); itr != players.end(); ++itr) + for (std::list::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if ((*itr) && (*itr)->GetTeam() == team) { (*itr)->KilledMonsterCredit(credit); - (*itr)->RewardHonor(NULL, 1, HONOR_REWARD_PLAGUELANDS); + (*itr)->RewardHonor(nullptr, 1, HONOR_REWARD_PLAGUELANDS); } } } diff --git a/src/game/OutdoorPvP/OutdoorPvPEP.h b/src/game/OutdoorPvP/OutdoorPvPEP.h index e5e6b83af..881f99f4b 100644 --- a/src/game/OutdoorPvP/OutdoorPvPEP.h +++ b/src/game/OutdoorPvP/OutdoorPvPEP.h @@ -238,7 +238,7 @@ class OutdoorPvPEP : public OutdoorPvP void SendRemoveWorldStates(Player* player) override; bool HandleEvent(uint32 eventId, GameObject* go) override; - void HandleObjectiveComplete(uint32 eventId, std::list players, Team team) override; + void HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) override; void HandleCreatureCreate(Creature* creature) override; void HandleGameObjectCreate(GameObject* go) override; diff --git a/src/game/OutdoorPvP/OutdoorPvPGH.cpp b/src/game/OutdoorPvP/OutdoorPvPGH.cpp index 159558bd3..8d865c322 100644 --- a/src/game/OutdoorPvP/OutdoorPvPGH.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPGH.cpp @@ -143,16 +143,22 @@ void OutdoorPvPGH::LockLighthouse(const WorldObject* objRef) if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) go->SetLootState(GO_JUST_DEACTIVATED); else + { // if grid is unloaded, changing the saved slider value is enough - sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, m_zoneOwner == ALLIANCE ? -CAPTURE_SLIDER_ALLIANCE : -CAPTURE_SLIDER_HORDE); + CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, true); + sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, value); + } } // Handle Lighthouse unlock when the commander is killed void OutdoorPvPGH::UnlockLighthouse(const WorldObject* objRef) { if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) - go->SetCapturePointSlider(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); + go->SetLootState(GO_ACTIVATED); else - // if grid is unloaded, resetting the saved slider value is enough - sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); + { + // if grid is unloaded, changing the saved slider value is enough + CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, false); + sOutdoorPvPMgr.SetCapturePointSlider(GO_VENTURE_BAY_LIGHTHOUSE, value); + } } diff --git a/src/game/OutdoorPvP/OutdoorPvPHP.cpp b/src/game/OutdoorPvP/OutdoorPvPHP.cpp index d9312a88e..bd3ba39ec 100644 --- a/src/game/OutdoorPvP/OutdoorPvPHP.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPHP.cpp @@ -114,7 +114,7 @@ void OutdoorPvPHP::HandleGameObjectCreate(GameObject* go) } } -void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, std::list players, Team team) +void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) { uint32 credit = 0; @@ -136,12 +136,12 @@ void OutdoorPvPHP::HandleObjectiveComplete(uint32 eventId, std::list pl return; } - for (std::list::iterator itr = players.begin(); itr != players.end(); ++itr) + for (std::list::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if ((*itr) && (*itr)->GetTeam() == team) { (*itr)->KilledMonsterCredit(credit); - (*itr)->RewardHonor(NULL, 1, HONOR_REWARD_HELLFIRE); + (*itr)->RewardHonor(nullptr, 1, HONOR_REWARD_HELLFIRE); } } } diff --git a/src/game/OutdoorPvP/OutdoorPvPHP.h b/src/game/OutdoorPvP/OutdoorPvPHP.h index 7c44ed350..0a85de924 100644 --- a/src/game/OutdoorPvP/OutdoorPvPHP.h +++ b/src/game/OutdoorPvP/OutdoorPvPHP.h @@ -159,7 +159,7 @@ class OutdoorPvPHP : public OutdoorPvP void SendRemoveWorldStates(Player* player) override; bool HandleEvent(uint32 eventId, GameObject* go) override; - void HandleObjectiveComplete(uint32 eventId, std::list players, Team team) override; + void HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) override; void HandleGameObjectCreate(GameObject* go) override; void HandlePlayerKillInsideArea(Player* player) override; diff --git a/src/game/OutdoorPvP/OutdoorPvPMgr.cpp b/src/game/OutdoorPvP/OutdoorPvPMgr.cpp index 4f8126049..13adf6a99 100644 --- a/src/game/OutdoorPvP/OutdoorPvPMgr.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPMgr.cpp @@ -167,19 +167,3 @@ void OutdoorPvPMgr::Update(uint32 diff) m_updateTimer.Reset(); } - -/** - Function that gets the capture point slider value - - @param capture point entry - @param default value being returned if no saved value for the capture point was found - */ -float OutdoorPvPMgr::GetCapturePointSliderValue(uint32 entry, float defaultValue) -{ - CapturePointSliderMap::const_iterator itr = m_capturePointSlider.find(entry); - if (itr != m_capturePointSlider.end()) - return itr->second; - - // return default value if we can't find any - return defaultValue; -} diff --git a/src/game/OutdoorPvP/OutdoorPvPMgr.h b/src/game/OutdoorPvP/OutdoorPvPMgr.h index 8832a001c..58ccc42bd 100644 --- a/src/game/OutdoorPvP/OutdoorPvPMgr.h +++ b/src/game/OutdoorPvP/OutdoorPvPMgr.h @@ -79,11 +79,22 @@ enum OutdoorPvPZones ZONE_ID_GRIZZLY_HILLS = 394 }; +struct CapturePointSlider +{ + CapturePointSlider() : Value(0.0f), IsLocked(false) {} + CapturePointSlider(float value, bool isLocked) : Value(value), IsLocked(isLocked) {} + + float Value; + bool IsLocked; +}; + class Player; class GameObject; class Creature; class OutdoorPvP; +typedef std::map CapturePointSliderMap; + class OutdoorPvPMgr { public: @@ -104,23 +115,21 @@ class OutdoorPvPMgr void Update(uint32 diff); - // Save and load capture point slider values - float GetCapturePointSliderValue(uint32 entry, float defaultValue); - void SetCapturePointSlider(uint32 entry, float value) { m_capturePointSlider[entry] = value; } + // Save and load capture point slider + CapturePointSliderMap const* GetCapturePointSliderMap() const { return &m_capturePointSlider; } + void SetCapturePointSlider(uint32 entry, CapturePointSlider value) { m_capturePointSlider[entry] = value; } - private: - // return assigned outdoor pvp script - OutdoorPvP* GetScriptOfAffectedZone(uint32 zoneId); +private: + // return assigned outdoor pvp script + OutdoorPvP* GetScriptOfAffectedZone(uint32 zoneId); - // contains all outdoor pvp scripts - OutdoorPvP* m_scripts[MAX_OPVP_ID]; + // contains all outdoor pvp scripts + OutdoorPvP* m_scripts[MAX_OPVP_ID]; - typedef std::map CapturePointSliderMap; + CapturePointSliderMap m_capturePointSlider; - CapturePointSliderMap m_capturePointSlider; - - // update interval - ShortIntervalTimer m_updateTimer; + // update interval + ShortIntervalTimer m_updateTimer; }; #define sOutdoorPvPMgr MaNGOS::Singleton::Instance() diff --git a/src/game/OutdoorPvP/OutdoorPvPNA.cpp b/src/game/OutdoorPvP/OutdoorPvPNA.cpp index c868700b6..ef737d184 100644 --- a/src/game/OutdoorPvP/OutdoorPvPNA.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPNA.cpp @@ -85,11 +85,11 @@ void OutdoorPvPNA::HandlePlayerLeaveZone(Player* player, bool isMainZone) OutdoorPvP::HandlePlayerLeaveZone(player, isMainZone); } -void OutdoorPvPNA::HandleObjectiveComplete(uint32 eventId, std::list players, Team team) +void OutdoorPvPNA::HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) { if (eventId == EVENT_HALAA_BANNER_WIN_ALLIANCE || eventId == EVENT_HALAA_BANNER_WIN_HORDE) { - for (std::list::iterator itr = players.begin(); itr != players.end(); ++itr) + for (std::list::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if ((*itr) && (*itr)->GetTeam() == team) (*itr)->KilledMonsterCredit(NPC_HALAA_COMBATANT); @@ -550,16 +550,22 @@ void OutdoorPvPNA::LockHalaa(const WorldObject* objRef) if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) go->SetLootState(GO_JUST_DEACTIVATED); else + { // if grid is unloaded, changing the saved slider value is enough - sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, m_zoneOwner == ALLIANCE ? -CAPTURE_SLIDER_ALLIANCE : -CAPTURE_SLIDER_HORDE); + CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, true); + sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, value); + } } // Unlock Halaa when all the soldiers are killed void OutdoorPvPNA::UnlockHalaa(const WorldObject* objRef) { if (GameObject* go = objRef->GetMap()->GetGameObject(m_capturePoint)) - go->SetCapturePointSlider(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); + go->SetLootState(GO_ACTIVATED); else - // if grid is unloaded, resetting the saved slider value is enough - sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE); + { + // if grid is unloaded, changing the saved slider value is enough + CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, false); + sOutdoorPvPMgr.SetCapturePointSlider(GO_HALAA_BANNER, value); + } } diff --git a/src/game/OutdoorPvP/OutdoorPvPNA.h b/src/game/OutdoorPvP/OutdoorPvPNA.h index 08bec4495..ef59f4659 100644 --- a/src/game/OutdoorPvP/OutdoorPvPNA.h +++ b/src/game/OutdoorPvP/OutdoorPvPNA.h @@ -168,7 +168,7 @@ class OutdoorPvPNA : public OutdoorPvP void SendRemoveWorldStates(Player* player) override; bool HandleEvent(uint32 eventId, GameObject* go) override; - void HandleObjectiveComplete(uint32 eventId, std::list players, Team team) override; + void HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) override; void HandleCreatureCreate(Creature* creature) override; void HandleGameObjectCreate(GameObject* go) override; diff --git a/src/game/OutdoorPvP/OutdoorPvPTF.cpp b/src/game/OutdoorPvP/OutdoorPvPTF.cpp index 24e947052..1ce721450 100644 --- a/src/game/OutdoorPvP/OutdoorPvPTF.cpp +++ b/src/game/OutdoorPvP/OutdoorPvPTF.cpp @@ -118,7 +118,7 @@ void OutdoorPvPTF::HandleGameObjectCreate(GameObject* go) } } -void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, std::list players, Team team) +void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) { for (uint8 i = 0; i < MAX_TF_TOWERS; ++i) { @@ -126,7 +126,7 @@ void OutdoorPvPTF::HandleObjectiveComplete(uint32 eventId, std::list pl { if (terokkarTowerEvents[i][j].eventEntry == eventId) { - for (std::list::iterator itr = players.begin(); itr != players.end(); ++itr) + for (std::list::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if ((*itr) && (*itr)->GetTeam() == team) (*itr)->AreaExploredOrEventHappens(team == ALLIANCE ? QUEST_SPIRITS_OF_AUCHINDOUM_ALLIANCE : QUEST_SPIRITS_OF_AUCHINDOUM_HORDE); @@ -351,8 +351,11 @@ void OutdoorPvPTF::LockTowers(const WorldObject* objRef) if (GameObject* go = objRef->GetMap()->GetGameObject(m_towerBanners[i])) go->SetLootState(GO_JUST_DEACTIVATED); else + { // if grid is unloaded, changing the saved slider value is enough - sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], m_zoneOwner == ALLIANCE ? -CAPTURE_SLIDER_ALLIANCE : -CAPTURE_SLIDER_HORDE); + CapturePointSlider value(m_zoneOwner == ALLIANCE ? CAPTURE_SLIDER_ALLIANCE : CAPTURE_SLIDER_HORDE, true); + sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], value); + } } } @@ -363,12 +366,15 @@ void OutdoorPvPTF::ResetTowers(const WorldObject* objRef) { if (GameObject* go = objRef->GetMap()->GetGameObject(m_towerBanners[i])) { - go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE); + go->SetCapturePointSlider(CAPTURE_SLIDER_MIDDLE, false); // visual update needed because banner still has artkit from previous owner SetBannerVisual(go, CAPTURE_ARTKIT_NEUTRAL, CAPTURE_ANIM_NEUTRAL); } else - // if grid is unloaded, resetting the saved slider value is enough - sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], CAPTURE_SLIDER_MIDDLE); + { + // if grid is unloaded, changing the saved slider value is enough + CapturePointSlider value(CAPTURE_SLIDER_MIDDLE, false); + sOutdoorPvPMgr.SetCapturePointSlider(terokkarTowers[i], value); + } } } diff --git a/src/game/OutdoorPvP/OutdoorPvPTF.h b/src/game/OutdoorPvP/OutdoorPvPTF.h index 3e7317053..72fea1837 100644 --- a/src/game/OutdoorPvP/OutdoorPvPTF.h +++ b/src/game/OutdoorPvP/OutdoorPvPTF.h @@ -169,7 +169,7 @@ class OutdoorPvPTF : public OutdoorPvP void SendRemoveWorldStates(Player* player) override; bool HandleEvent(uint32 eventId, GameObject* go) override; - void HandleObjectiveComplete(uint32 eventId, std::list players, Team team) override; + void HandleObjectiveComplete(uint32 eventId, const std::list& players, Team team) override; void HandleGameObjectCreate(GameObject* go) override; void Update(uint32 diff) override; diff --git a/src/game/Server/SharedDefines.h b/src/game/Server/SharedDefines.h index 5c41e0699..2bb5f86c6 100644 --- a/src/game/Server/SharedDefines.h +++ b/src/game/Server/SharedDefines.h @@ -3779,7 +3779,7 @@ enum MaxLevel static const MaxLevel maxLevelForExpansion[MAX_EXPANSION + 1] = { MAX_LEVEL_CLASSIC, MAX_LEVEL_TBC, MAX_LEVEL_WOTLK, MAX_LEVEL_CATACLYSM }; // Max creature level (included some bosses and elite) -#define DEFAULT_MAX_CREATURE_LEVEL 85 +#define DEFAULT_MAX_CREATURE_LEVEL 90 // This spell is used for general boarding serverside #define SPELL_RIDE_VEHICLE_HARDCODED 46598 diff --git a/src/game/Tools/Language.h b/src/game/Tools/Language.h index 6d09489ce..557e015f3 100644 --- a/src/game/Tools/Language.h +++ b/src/game/Tools/Language.h @@ -1042,7 +1042,7 @@ enum MangosStrings // Use for custom patches 11000-11999 // NOT RESERVED IDS 12000-1999999999 - // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) - // For other tables maybe 2000010000-2147483647 (max index) + // `db_script_string` table index 2000000000-2000999999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) + // For other tables maybe 2001000000-2147483647 (max index) }; #endif diff --git a/src/game/WorldHandlers/AccountMgr.cpp b/src/game/WorldHandlers/AccountMgr.cpp index e544a4255..96577512d 100644 --- a/src/game/WorldHandlers/AccountMgr.cpp +++ b/src/game/WorldHandlers/AccountMgr.cpp @@ -246,12 +246,13 @@ bool AccountMgr::CheckPassword(uint32 accid, std::string passwd) bool AccountMgr::normalizeString(std::string& utf8str) { wchar_t wstr_buf[MAX_ACCOUNT_STR + 1]; - size_t wstr_len = MAX_ACCOUNT_STR; + if (!Utf8toWStr(utf8str, wstr_buf, wstr_len)) return false; - std::transform(&wstr_buf[0], wstr_buf + wstr_len, &wstr_buf[0], wcharToUpperOnlyLatin); + for (uint32 i = 0; i <= wstr_len; ++i) + wstr_buf[i] = wcharToUpperOnlyLatin(wstr_buf[i]); return WStrToUtf8(wstr_buf, wstr_len, utf8str); } diff --git a/src/game/WorldHandlers/AchievementMgr.cpp b/src/game/WorldHandlers/AchievementMgr.cpp index 69eaadb78..969b47252 100644 --- a/src/game/WorldHandlers/AchievementMgr.cpp +++ b/src/game/WorldHandlers/AchievementMgr.cpp @@ -47,6 +47,7 @@ #include "Map.h" #include "InstanceData.h" #include "DBCStructure.h" +#include "Chat.h" #include "Policies/Singleton.h" @@ -63,15 +64,8 @@ namespace MaNGOS { char const* text = sObjectMgr.GetMangosString(i_textId, loc_idx); - data << uint8(i_msgtype); - data << uint32(LANG_UNIVERSAL); - data << i_player.GetObjectGuid(); - data << uint32(5); - data << i_player.GetObjectGuid(); - data << uint32(strlen(text) + 1); - data << text; - data << uint8(0); - data << uint32(i_achievementId); + ChatHandler::BuildChatPacket(data, i_msgtype, text, LANG_UNIVERSAL, i_player.GetChatTag(), i_player.GetObjectGuid(), nullptr, i_player.GetObjectGuid(), nullptr, nullptr, + i_achievementId); } private: diff --git a/src/game/WorldHandlers/Channel.cpp b/src/game/WorldHandlers/Channel.cpp index 1b7cb833d..40e780789 100644 --- a/src/game/WorldHandlers/Channel.cpp +++ b/src/game/WorldHandlers/Channel.cpp @@ -57,627 +57,644 @@ Channel::Channel(const std::string& name, uint32 channel_id) } } -void Channel::Join(ObjectGuid p, const char* pass) +void Channel::Join(Player* player, const char* password) { - WorldPacket data; - if (IsOn(p)) - { - if (!IsConstant()) // non send error message for built-in channels - { - MakePlayerAlreadyMember(&data, p); - SendToOne(&data, p); - } - return; - } + ObjectGuid guid = player->GetObjectGuid(); - if (IsBanned(p)) - { - MakeBanned(&data); - SendToOne(&data, p); - return; - } + WorldPacket data; + if (IsOn(guid)) + { + if (!IsConstant()) // non send error message for built-in channels + { + MakePlayerAlreadyMember(&data, guid); + SendToOne(&data, guid); + } + return; + } - if (m_password.length() > 0 && strcmp(pass, m_password.c_str())) - { - MakeWrongPassword(&data); - SendToOne(&data, p); - return; - } + if (IsBanned(guid)) + { + MakeBanned(&data); + SendToOne(&data, guid); + return; + } - Player* plr = sObjectMgr.GetPlayer(p); + if (m_password.length() > 0 && strcmp(password, m_password.c_str())) + { + MakeWrongPassword(&data); + SendToOne(&data, guid); + return; + } - if (plr) - { - if (HasFlag(CHANNEL_FLAG_LFG) && sWorld.getConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL) && plr->GetSession()->GetSecurity() == SEC_PLAYER) - { - MakeNotInLfg(&data); - SendToOne(&data, p); - return; - } + if (HasFlag(CHANNEL_FLAG_LFG) && sWorld.getConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL) && player->GetSession()->GetSecurity() == SEC_PLAYER) + { + MakeNotInLfg(&data); + SendToOne(&data, guid); + return; + } - if (plr->GetGuildId() && (GetFlags() == 0x38)) - return; + if (player->GetGuildId() && (GetFlags() == 0x38)) + return; - plr->JoinedChannel(this); - } + // join channel + player->JoinedChannel(this); - if (m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL))) - { - MakeJoined(&data, p); - SendToAll(&data); - } + if (m_announce && (player->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL))) + { + MakeJoined(&data, guid); + SendToAll(&data); + } - data.clear(); + data.clear(); - PlayerInfo& pinfo = m_players[p]; - pinfo.player = p; - pinfo.flags = 0; + PlayerInfo& pinfo = m_players[guid]; + pinfo.player = guid; + pinfo.flags = MEMBER_FLAG_NONE; - MakeYouJoined(&data); - SendToOne(&data, p); + MakeYouJoined(&data); + SendToOne(&data, guid); - JoinNotify(p); + JoinNotify(guid); - // if no owner first logged will become - if (!IsConstant() && !m_ownerGuid) - { - SetOwner(p, (m_players.size() > 1 ? true : false)); - m_players[p].SetModerator(true); - } + // if no owner first logged will become + if (!IsConstant() && !m_ownerGuid) + { + SetOwner(guid, (m_players.size() > 1 ? true : false)); + m_players[guid].SetModerator(true); + } } -void Channel::Leave(ObjectGuid p, bool send) +void Channel::Leave(Player* player, bool send) { - if (!IsOn(p)) - { - if (send) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - } - else - { - Player* plr = sObjectMgr.GetPlayer(p); + ObjectGuid guid = player->GetObjectGuid(); - if (send) - { - WorldPacket data; - MakeYouLeft(&data); - SendToOne(&data, p); - if (plr) - plr->LeftChannel(this); - data.clear(); - } + if (!IsOn(guid)) + { + if (send) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + } + return; + } - bool changeowner = m_players[p].IsOwner(); + // leave channel + if (send) + { + WorldPacket data; + MakeYouLeft(&data); + SendToOne(&data, guid); + player->LeftChannel(this); + data.clear(); + } - m_players.erase(p); - if (m_announce && (!plr || plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL))) - { - WorldPacket data; - MakeLeft(&data, p); - SendToAll(&data); - } + bool changeowner = m_players[guid].IsOwner(); - LeaveNotify(p); + m_players.erase(guid); + if (m_announce && (player->GetSession()->GetSecurity() < SEC_GAMEMASTER || !sWorld.getConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL))) + { + WorldPacket data; + MakeLeft(&data, guid); + SendToAll(&data); + } - if (changeowner) - { - ObjectGuid newowner = !m_players.empty() ? m_players.begin()->second.player : ObjectGuid(); - SetOwner(newowner); - } - } + LeaveNotify(guid); + + if (changeowner) + { + ObjectGuid newowner = !m_players.empty() ? m_players.begin()->second.player : ObjectGuid(); + SetOwner(newowner); + } } -void Channel::KickOrBan(ObjectGuid good, const char* badname, bool ban) +void Channel::KickOrBan(Player* player, const char* targetName, bool ban) { - AccountTypes sec = SEC_PLAYER; - Player* gplr = sObjectMgr.GetPlayer(good); - if (gplr) - sec = gplr->GetSession()->GetSecurity(); + ObjectGuid guid = player->GetObjectGuid(); - if (!IsOn(good)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, good); - } - else if (!m_players[good].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, good); - } - else - { - Player* bad = sObjectMgr.GetPlayer(badname); - if (bad == NULL || !IsOn(bad->GetObjectGuid())) - { - WorldPacket data; - MakePlayerNotFound(&data, badname); - SendToOne(&data, good); - } - else if (sec < SEC_GAMEMASTER && bad->GetObjectGuid() == m_ownerGuid && good != m_ownerGuid) - { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, good); - } - else - { - bool changeowner = (m_ownerGuid == bad->GetObjectGuid()); + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } - WorldPacket data; + if (!m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } - if (ban && !IsBanned(bad->GetObjectGuid())) - { - m_banned.insert(bad->GetObjectGuid()); - MakePlayerBanned(&data, bad->GetObjectGuid(), good); - } - else - MakePlayerKicked(&data, bad->GetObjectGuid(), good); + Player* target = sObjectMgr.GetPlayer(targetName); + if (!target) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } - SendToAll(&data); - m_players.erase(bad->GetObjectGuid()); - bad->LeftChannel(this); + ObjectGuid targetGuid = target->GetObjectGuid(); + if (!IsOn(targetGuid)) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } - if (changeowner) - { - ObjectGuid newowner = !m_players.empty() ? good : ObjectGuid(); - SetOwner(newowner); - } - } - } + bool changeowner = m_ownerGuid == targetGuid; + + if (player->GetSession()->GetSecurity() < SEC_GAMEMASTER && changeowner && guid != m_ownerGuid) + { + WorldPacket data; + MakeNotOwner(&data); + SendToOne(&data, guid); + return; + } + + // kick or ban player + WorldPacket data; + + if (ban && !IsBanned(targetGuid)) + { + m_banned.insert(targetGuid); + MakePlayerBanned(&data, targetGuid, guid); + } + else + MakePlayerKicked(&data, targetGuid, guid); + + SendToAll(&data); + m_players.erase(targetGuid); + target->LeftChannel(this); + + if (changeowner) + { + ObjectGuid newowner = !m_players.empty() ? guid : ObjectGuid(); + SetOwner(newowner); + } } -void Channel::UnBan(ObjectGuid good, const char* badname) +void Channel::UnBan(Player* player, const char* targetName) { - uint32 sec = 0; - Player* gplr = sObjectMgr.GetPlayer(good); - if (gplr) - sec = gplr->GetSession()->GetSecurity(); + ObjectGuid guid = player->GetObjectGuid(); - if (!IsOn(good)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, good); - } - else if (!m_players[good].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, good); - } - else - { - Player* bad = sObjectMgr.GetPlayer(badname); - if (bad == NULL || !IsBanned(bad->GetObjectGuid())) - { - WorldPacket data; - MakePlayerNotFound(&data, badname); - SendToOne(&data, good); - } - else - { - m_banned.erase(bad->GetObjectGuid()); + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } - WorldPacket data; - MakePlayerUnbanned(&data, bad->GetObjectGuid(), good); - SendToAll(&data); - } - } + if (!m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } + + Player* target = sObjectMgr.GetPlayer(targetName); + if (!target) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } + + ObjectGuid targetGuid = target->GetObjectGuid(); + if (!IsBanned(targetGuid)) + { + WorldPacket data; + MakePlayerNotBanned(&data, targetName); + SendToOne(&data, guid); + return; + } + + // unban player + m_banned.erase(targetGuid); + + WorldPacket data; + MakePlayerUnbanned(&data, targetGuid, guid); + SendToAll(&data); } -void Channel::Password(ObjectGuid p, const char* pass) +void Channel::Password(Player* player, const char* password) { - uint32 sec = 0; - Player* plr = sObjectMgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); + ObjectGuid guid = player->GetObjectGuid(); - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!m_players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - m_password = pass; + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } - WorldPacket data; - MakePasswordChanged(&data, p); - SendToAll(&data); - } + if (!m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } + + // set channel password + m_password = password; + + WorldPacket data; + MakePasswordChanged(&data, guid); + SendToAll(&data); } -void Channel::SetMode(ObjectGuid p, const char* p2n, bool mod, bool set) +void Channel::SetMode(Player* player, const char* targetName, bool moderator, bool set) { - Player* plr = sObjectMgr.GetPlayer(p); - if (!plr) - return; + ObjectGuid guid = player->GetObjectGuid(); - uint32 sec = plr->GetSession()->GetSecurity(); + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!m_players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - Player* newp = sObjectMgr.GetPlayer(p2n); - if (!newp) - { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, p); - return; - } + if (!m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } - PlayerInfo inf = m_players[newp->GetObjectGuid()]; - if (p == m_ownerGuid && newp->GetObjectGuid() == m_ownerGuid && mod) - return; + Player* target = sObjectMgr.GetPlayer(targetName); + if (!target) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } - if (!IsOn(newp->GetObjectGuid())) - { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, p); - return; - } + ObjectGuid targetGuid = target->GetObjectGuid(); + if (moderator && guid == m_ownerGuid && targetGuid == m_ownerGuid) + return; - // allow make moderator from another team only if both is GMs - // at this moment this only way to show channel post for GM from another team - if ((plr->GetSession()->GetSecurity() < SEC_GAMEMASTER || newp->GetSession()->GetSecurity() < SEC_GAMEMASTER) && - plr->GetTeam() != newp->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - { - WorldPacket data; - MakePlayerNotFound(&data, p2n); - SendToOne(&data, p); - return; - } + if (!IsOn(targetGuid)) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } - if (m_ownerGuid == newp->GetObjectGuid() && m_ownerGuid != p) - { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, p); - return; - } + // allow make moderator from another team only if both is GMs + // at this moment this only way to show channel post for GM from another team + if ((player->GetSession()->GetSecurity() < SEC_GAMEMASTER || target->GetSession()->GetSecurity() < SEC_GAMEMASTER) && + player->GetTeam() != target->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } - if (mod) - SetModerator(newp->GetObjectGuid(), set); - else - SetMute(newp->GetObjectGuid(), set); - } -} + if (m_ownerGuid == targetGuid && m_ownerGuid != guid) + { + WorldPacket data; + MakeNotOwner(&data); + SendToOne(&data, guid); + return; + } -void Channel::SetOwner(ObjectGuid p, const char* newname) -{ - Player* plr = sObjectMgr.GetPlayer(p); - if (!plr) - return; - - uint32 sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - return; - } - - if (sec < SEC_GAMEMASTER && p != m_ownerGuid) - { - WorldPacket data; - MakeNotOwner(&data); - SendToOne(&data, p); - return; - } - - Player* newp = sObjectMgr.GetPlayer(newname); - if (newp == NULL || !IsOn(newp->GetObjectGuid())) - { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, p); - return; - } - - if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, p); - return; - } - - m_players[newp->GetObjectGuid()].SetModerator(true); - SetOwner(newp->GetObjectGuid()); -} - -void Channel::SendWhoOwner(ObjectGuid p) -{ - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else - { - WorldPacket data; - MakeChannelOwner(&data); - SendToOne(&data, p); - } -} - -void Channel::List(Player* player) -{ - ObjectGuid p = player->GetObjectGuid(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else - { - WorldPacket data(SMSG_CHANNEL_LIST, 1 + (GetName().size() + 1) + 1 + 4 + m_players.size() * (8 + 1)); - data << uint8(1); // channel type? - data << GetName(); // channel name - data << uint8(GetFlags()); // channel flags? - - size_t pos = data.wpos(); - data << uint32(0); // size of list, placeholder - - AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST); - - uint32 count = 0; - for (PlayerList::const_iterator i = m_players.begin(); i != m_players.end(); ++i) - { - Player* plr = sObjectMgr.GetPlayer(i->first); - - // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters - // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (plr && (player->GetSession()->GetSecurity() > SEC_PLAYER || plr->GetSession()->GetSecurity() <= gmLevelInWhoList) && - plr->IsVisibleGloballyFor(player)) - { - data << ObjectGuid(i->first); - data << uint8(i->second.flags); // flags seems to be changed... - ++count; - } - } - - data.put(pos, count); - - SendToOne(&data, p); - } -} - -void Channel::Announce(ObjectGuid p) -{ - uint32 sec = 0; - Player* plr = sObjectMgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!m_players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - m_announce = !m_announce; - - WorldPacket data; - if (m_announce) - MakeAnnouncementsOn(&data, p); - else - MakeAnnouncementsOff(&data, p); - SendToAll(&data); - } -} - -void Channel::Moderate(ObjectGuid p) -{ - uint32 sec = 0; - Player* plr = sObjectMgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (!m_players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - m_moderate = !m_moderate; - - WorldPacket data; - if (m_moderate) - MakeModerationOn(&data, p); - else - MakeModerationOff(&data, p); - SendToAll(&data); - } -} - -void Channel::Say(ObjectGuid p, const char* what, uint32 lang) -{ - if (!what) - return; - if (sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - lang = LANG_UNIVERSAL; - - uint32 sec = 0; - Player* plr = sObjectMgr.GetPlayer(p); - if (plr) - sec = plr->GetSession()->GetSecurity(); - - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - } - else if (m_players[p].IsMuted()) - { - WorldPacket data; - MakeMuted(&data); - SendToOne(&data, p); - } - else if (m_moderate && !m_players[p].IsModerator() && sec < SEC_GAMEMASTER) - { - WorldPacket data; - MakeNotModerator(&data); - SendToOne(&data, p); - } - else - { - uint32 messageLength = strlen(what) + 1; - - WorldPacket data(SMSG_MESSAGECHAT, 1 + 4 + 8 + 4 + m_name.size() + 1 + 8 + 4 + messageLength + 1); - data << uint8(CHAT_MSG_CHANNEL); - data << uint32(lang); - data << ObjectGuid(p); // 2.1.0 - data << uint32(0); // 2.1.0 - data << m_name; - data << ObjectGuid(p); - data << uint32(messageLength); - data << what; - data << uint8(plr ? plr->GetChatTag() : uint8(CHAT_TAG_NONE)); - - SendToAll(&data, !m_players[p].IsModerator() ? p : ObjectGuid()); - } -} - -void Channel::Invite(ObjectGuid p, const char* newname) -{ - if (!IsOn(p)) - { - WorldPacket data; - MakeNotMember(&data); - SendToOne(&data, p); - return; - } - - Player* newp = sObjectMgr.GetPlayer(newname); - if (!newp) - { - WorldPacket data; - MakePlayerNotFound(&data, newname); - SendToOne(&data, p); - return; - } - - Player* plr = sObjectMgr.GetPlayer(p); - if (!plr) - return; - - if (newp->GetTeam() != plr->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - { - WorldPacket data; - MakeInviteWrongFaction(&data); - SendToOne(&data, p); - return; - } - - if (IsOn(newp->GetObjectGuid())) - { - WorldPacket data; - MakePlayerAlreadyMember(&data, newp->GetObjectGuid()); - SendToOne(&data, p); - return; - } - - WorldPacket data; - if (!newp->GetSocial()->HasIgnore(p)) - { - MakeInvite(&data, p); - SendToOne(&data, newp->GetObjectGuid()); - data.clear(); - } - MakePlayerInvited(&data, newp->GetName()); - SendToOne(&data, p); + // set channel moderator + if (moderator) + SetModerator(targetGuid, set); + else + SetMute(targetGuid, set); } void Channel::SetOwner(ObjectGuid guid, bool exclaim) { - if (m_ownerGuid) - { - // [] will re-add player after it possible removed - PlayerList::iterator p_itr = m_players.find(m_ownerGuid); - if (p_itr != m_players.end()) - p_itr->second.SetOwner(false); - } + if (m_ownerGuid) + { + // [] will re-add player after it possible removed + PlayerList::iterator p_itr = m_players.find(m_ownerGuid); + if (p_itr != m_players.end()) + p_itr->second.SetOwner(false); + } - m_ownerGuid = guid; + m_ownerGuid = guid; - if (m_ownerGuid) - { - uint8 oldFlag = GetPlayerFlags(m_ownerGuid); - m_players[m_ownerGuid].SetOwner(true); + if (m_ownerGuid) + { + uint8 oldFlag = GetPlayerFlags(m_ownerGuid); + m_players[m_ownerGuid].SetOwner(true); - WorldPacket data; - MakeModeChange(&data, m_ownerGuid, oldFlag); - SendToAll(&data); + WorldPacket data; + MakeModeChange(&data, m_ownerGuid, oldFlag); + SendToAll(&data); - if (exclaim) - { - MakeOwnerChanged(&data, m_ownerGuid); - SendToAll(&data); - } - } + if (exclaim) + { + MakeOwnerChanged(&data, m_ownerGuid); + SendToAll(&data); + } + } } -void Channel::SendToAll(WorldPacket* data, ObjectGuid p) +void Channel::SetOwner(Player* player, const char* targetName) { - for (PlayerList::const_iterator i = m_players.begin(); i != m_players.end(); ++i) - if (Player* plr = sObjectMgr.GetPlayer(i->first)) - if (!p || !plr->GetSocial()->HasIgnore(p)) - plr->GetSession()->SendPacket(data); + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + if (player->GetSession()->GetSecurity() < SEC_GAMEMASTER && guid != m_ownerGuid) + { + WorldPacket data; + MakeNotOwner(&data); + SendToOne(&data, guid); + return; + } + + Player* target = sObjectMgr.GetPlayer(targetName); + if (!target) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } + + ObjectGuid targetGuid = target->GetObjectGuid(); + if (!IsOn(targetGuid)) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } + + if (target->GetTeam() != player->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } + + // set channel owner + m_players[targetGuid].SetModerator(true); + SetOwner(targetGuid); +} + +void Channel::SendWhoOwner(Player* player) +{ + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + // send channel owner + WorldPacket data; + MakeChannelOwner(&data); + SendToOne(&data, guid); +} + +void Channel::List(Player* player) +{ + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + // list players in channel + WorldPacket data(SMSG_CHANNEL_LIST, 1 + (GetName().size() + 1) + 1 + 4 + m_players.size() * (8 + 1)); + data << uint8(1); // channel type? + data << GetName(); // channel name + data << uint8(GetFlags()); // channel flags? + + size_t pos = data.wpos(); + data << uint32(0); // size of list, placeholder + + AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST); + + uint32 count = 0; + for (PlayerList::const_iterator i = m_players.begin(); i != m_players.end(); ++i) + { + Player* plr = sObjectMgr.GetPlayer(i->first); + + // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters + // MODERATOR, GAME MASTER, ADMINISTRATOR can see all + if (plr && (player->GetSession()->GetSecurity() > SEC_PLAYER || plr->GetSession()->GetSecurity() <= gmLevelInWhoList) && + plr->IsVisibleGloballyFor(player)) + { + data << ObjectGuid(i->first); + data << uint8(i->second.flags); // flags seems to be changed... + ++count; + } + } + + data.put(pos, count); + + SendToOne(&data, guid); +} + +void Channel::Announce(Player* player) +{ + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + if (!m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } + + // toggle channel announcement + m_announce = !m_announce; + + WorldPacket data; + if (m_announce) + MakeAnnouncementsOn(&data, guid); + else + MakeAnnouncementsOff(&data, guid); + + SendToAll(&data); +} + +void Channel::Moderate(Player* player) +{ + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + if (!m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } + + // toggle channel moderation + m_moderate = !m_moderate; + + WorldPacket data; + if (m_moderate) + MakeModerationOn(&data, guid); + else + MakeModerationOff(&data, guid); + + SendToAll(&data); +} + +void Channel::Say(Player* player, const char* text, uint32 lang) +{ + if (!text) + return; + + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + if (m_players[guid].IsMuted()) + { + WorldPacket data; + MakeMuted(&data); + SendToOne(&data, guid); + return; + } + + if (m_moderate && !m_players[guid].IsModerator() && player->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + WorldPacket data; + MakeNotModerator(&data); + SendToOne(&data, guid); + return; + } + + // send channel message + if (sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + lang = LANG_UNIVERSAL; + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_CHANNEL, text, Language(lang), player->GetChatTag(), guid, player->GetName(), ObjectGuid(), "", m_name.c_str()); + SendToAll(&data, !m_players[guid].IsModerator() ? guid : ObjectGuid()); +} + +void Channel::Invite(Player* player, const char* targetName) +{ + ObjectGuid guid = player->GetObjectGuid(); + + if (!IsOn(guid)) + { + WorldPacket data; + MakeNotMember(&data); + SendToOne(&data, guid); + return; + } + + Player* target = sObjectMgr.GetPlayer(targetName); + if (!target) + { + WorldPacket data; + MakePlayerNotFound(&data, targetName); + SendToOne(&data, guid); + return; + } + + ObjectGuid targetGuid = target->GetObjectGuid(); + if (IsOn(targetGuid)) + { + WorldPacket data; + MakePlayerAlreadyMember(&data, targetGuid); + SendToOne(&data, guid); + return; + } + + if (IsBanned(targetGuid)) + { + WorldPacket data; + MakePlayerInviteBanned(&data, targetName); + SendToOne(&data, guid); + return; + } + + if (target->GetTeam() != player->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + { + WorldPacket data; + MakeInviteWrongFaction(&data); + SendToOne(&data, guid); + return; + } + + // invite player + WorldPacket data; + if (!target->GetSocial()->HasIgnore(guid)) + { + MakeInvite(&data, guid); + SendToOne(&data, targetGuid); + data.clear(); + } + + MakePlayerInvited(&data, targetName); + SendToOne(&data, guid); +} + +void Channel::SendToAll(WorldPacket* data, ObjectGuid guid) +{ + for (PlayerList::const_iterator i = m_players.begin(); i != m_players.end(); ++i) + if (Player* plr = sObjectMgr.GetPlayer(i->first)) + if (!guid || !plr->GetSocial()->HasIgnore(guid)) + plr->GetSession()->SendPacket(data); } void Channel::SendToOne(WorldPacket* data, ObjectGuid who) { - if (Player* plr = ObjectMgr::GetPlayer(who)) - plr->GetSession()->SendPacket(data); + if (Player* plr = ObjectMgr::GetPlayer(who)) + plr->GetSession()->SendPacket(data); } void Channel::Voice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) @@ -688,289 +705,252 @@ void Channel::DeVoice(ObjectGuid /*guid1*/, ObjectGuid /*guid2*/) { } -// done void Channel::MakeNotifyPacket(WorldPacket* data, uint8 notify_type) { - data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + m_name.size() + 1); - *data << uint8(notify_type); - *data << m_name; + data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + m_name.size() + 1); + *data << uint8(notify_type); + *data << m_name; } -// done 0x00 void Channel::MakeJoined(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_JOINED_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_JOINED_NOTICE); + *data << ObjectGuid(guid); } -// done 0x01 void Channel::MakeLeft(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_LEFT_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_LEFT_NOTICE); + *data << ObjectGuid(guid); } -// done 0x02 void Channel::MakeYouJoined(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE); - *data << uint8(GetFlags()); - *data << uint32(GetChannelId()); - *data << uint32(0); + MakeNotifyPacket(data, CHAT_YOU_JOINED_NOTICE); + *data << uint8(GetFlags()); + *data << uint32(GetChannelId()); + *data << uint32(0); } -// done 0x03 void Channel::MakeYouLeft(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE); - *data << uint32(GetChannelId()); - *data << uint8(0); // can be 0x00 and 0x01 + MakeNotifyPacket(data, CHAT_YOU_LEFT_NOTICE); + *data << uint32(GetChannelId()); + *data << uint8(0); // can be 0x00 and 0x01 } -// done 0x04 void Channel::MakeWrongPassword(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE); + MakeNotifyPacket(data, CHAT_WRONG_PASSWORD_NOTICE); } -// done 0x05 void Channel::MakeNotMember(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE); + MakeNotifyPacket(data, CHAT_NOT_MEMBER_NOTICE); } -// done 0x06 void Channel::MakeNotModerator(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE); + MakeNotifyPacket(data, CHAT_NOT_MODERATOR_NOTICE); } -// done 0x07 void Channel::MakePasswordChanged(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_PASSWORD_CHANGED_NOTICE); + *data << ObjectGuid(guid); } -// done 0x08 void Channel::MakeOwnerChanged(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_OWNER_CHANGED_NOTICE); + *data << ObjectGuid(guid); } -// done 0x09 void Channel::MakePlayerNotFound(WorldPacket* data, const std::string& name) { - MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE); - *data << name; + MakeNotifyPacket(data, CHAT_PLAYER_NOT_FOUND_NOTICE); + *data << name; } -// done 0x0A void Channel::MakeNotOwner(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE); + MakeNotifyPacket(data, CHAT_NOT_OWNER_NOTICE); } -// done 0x0B void Channel::MakeChannelOwner(WorldPacket* data) { - std::string name = ""; + std::string name = ""; - if (!sObjectMgr.GetPlayerNameByGUID(m_ownerGuid, name) || name.empty()) - name = "PLAYER_NOT_FOUND"; + if (!sObjectMgr.GetPlayerNameByGUID(m_ownerGuid, name) || name.empty()) + name = "PLAYER_NOT_FOUND"; - MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE); - *data << ((IsConstant() || !m_ownerGuid) ? "Nobody" : name); + MakeNotifyPacket(data, CHAT_CHANNEL_OWNER_NOTICE); + *data << ((IsConstant() || !m_ownerGuid) ? "Nobody" : name); } -// done 0x0C void Channel::MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags) { - MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE); - *data << ObjectGuid(guid); - *data << uint8(oldflags); - *data << uint8(GetPlayerFlags(guid)); + MakeNotifyPacket(data, CHAT_MODE_CHANGE_NOTICE); + *data << ObjectGuid(guid); + *data << uint8(oldflags); + *data << uint8(GetPlayerFlags(guid)); } -// done 0x0D void Channel::MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_ON_NOTICE); + *data << ObjectGuid(guid); } -// done 0x0E void Channel::MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_ANNOUNCEMENTS_OFF_NOTICE); + *data << ObjectGuid(guid); } -// done 0x0F void Channel::MakeModerationOn(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE); + *data << ObjectGuid(guid); } -// done 0x10 void Channel::MakeModerationOff(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE); + *data << ObjectGuid(guid); } -// done 0x11 void Channel::MakeMuted(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_MUTED_NOTICE); + MakeNotifyPacket(data, CHAT_MUTED_NOTICE); } -// done 0x12 -void Channel::MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good) +void Channel::MakePlayerKicked(WorldPacket* data, ObjectGuid target, ObjectGuid source) { - MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE); - *data << ObjectGuid(bad); - *data << ObjectGuid(good); + MakeNotifyPacket(data, CHAT_PLAYER_KICKED_NOTICE); + *data << ObjectGuid(target); + *data << ObjectGuid(source); } -// done 0x13 void Channel::MakeBanned(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_BANNED_NOTICE); + MakeNotifyPacket(data, CHAT_BANNED_NOTICE); } -// done 0x14 -void Channel::MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) +void Channel::MakePlayerBanned(WorldPacket* data, ObjectGuid target, ObjectGuid source) { - MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE); - *data << ObjectGuid(bad); - *data << ObjectGuid(good); + MakeNotifyPacket(data, CHAT_PLAYER_BANNED_NOTICE); + *data << ObjectGuid(target); + *data << ObjectGuid(source); } -// done 0x15 -void Channel::MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good) +void Channel::MakePlayerUnbanned(WorldPacket* data, ObjectGuid target, ObjectGuid source) { - MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE); - *data << ObjectGuid(bad); - *data << ObjectGuid(good); + MakeNotifyPacket(data, CHAT_PLAYER_UNBANNED_NOTICE); + *data << ObjectGuid(target); + *data << ObjectGuid(source); } -// done 0x16 -void Channel::MakePlayerNotBanned(WorldPacket* data, ObjectGuid guid) +void Channel::MakePlayerNotBanned(WorldPacket* data, const std::string& name) { - MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE); - *data << ObjectGuid(guid); // should be string!! + MakeNotifyPacket(data, CHAT_PLAYER_NOT_BANNED_NOTICE); + *data << name; } -// done 0x17 void Channel::MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_PLAYER_ALREADY_MEMBER_NOTICE); + *data << ObjectGuid(guid); } -// done 0x18 void Channel::MakeInvite(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_INVITE_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_INVITE_NOTICE); + *data << ObjectGuid(guid); } -// done 0x19 void Channel::MakeInviteWrongFaction(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE); + MakeNotifyPacket(data, CHAT_INVITE_WRONG_FACTION_NOTICE); } -// done 0x1A void Channel::MakeWrongFaction(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE); + MakeNotifyPacket(data, CHAT_WRONG_FACTION_NOTICE); } -// done 0x1B void Channel::MakeInvalidName(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE); + MakeNotifyPacket(data, CHAT_INVALID_NAME_NOTICE); } -// done 0x1C void Channel::MakeNotModerated(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE); + MakeNotifyPacket(data, CHAT_NOT_MODERATED_NOTICE); } -// done 0x1D void Channel::MakePlayerInvited(WorldPacket* data, const std::string& name) { - MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE); - *data << name; + MakeNotifyPacket(data, CHAT_PLAYER_INVITED_NOTICE); + *data << name; } -// done 0x1E -void Channel::MakePlayerInviteBanned(WorldPacket* data, ObjectGuid guid) +void Channel::MakePlayerInviteBanned(WorldPacket* data, const std::string& name) { - MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE); - *data << ObjectGuid(guid); // should be string!! + MakeNotifyPacket(data, CHAT_PLAYER_INVITE_BANNED_NOTICE); + *data << name; } -// done 0x1F void Channel::MakeThrottled(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE); + MakeNotifyPacket(data, CHAT_THROTTLED_NOTICE); } -// done 0x20 void Channel::MakeNotInArea(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE); + MakeNotifyPacket(data, CHAT_NOT_IN_AREA_NOTICE); } -// done 0x21 void Channel::MakeNotInLfg(WorldPacket* data) { - MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE); + MakeNotifyPacket(data, CHAT_NOT_IN_LFG_NOTICE); } -// done 0x22 void Channel::MakeVoiceOn(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_VOICE_ON_NOTICE); + *data << ObjectGuid(guid); } -// done 0x23 void Channel::MakeVoiceOff(WorldPacket* data, ObjectGuid guid) { - MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE); - *data << ObjectGuid(guid); + MakeNotifyPacket(data, CHAT_VOICE_OFF_NOTICE); + *data << ObjectGuid(guid); } void Channel::JoinNotify(ObjectGuid guid) { - WorldPacket data; + WorldPacket data; - if (IsConstant()) - data.Initialize(SMSG_USERLIST_ADD, 8 + 1 + 1 + 4 + GetName().size() + 1); - else - data.Initialize(SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size() + 1); + if (IsConstant()) + data.Initialize(SMSG_USERLIST_ADD, 8 + 1 + 1 + 4 + GetName().size() + 1); + else + data.Initialize(SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size() + 1); - data << ObjectGuid(guid); - data << uint8(GetPlayerFlags(guid)); - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); - SendToAll(&data); + data << ObjectGuid(guid); + data << uint8(GetPlayerFlags(guid)); + data << uint8(GetFlags()); + data << uint32(GetNumPlayers()); + data << GetName(); + SendToAll(&data); } void Channel::LeaveNotify(ObjectGuid guid) { - WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size() + 1); - data << ObjectGuid(guid); - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); - SendToAll(&data); + WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size() + 1); + data << ObjectGuid(guid); + data << uint8(GetFlags()); + data << uint32(GetNumPlayers()); + data << GetName(); + SendToAll(&data); } diff --git a/src/game/WorldHandlers/Channel.h b/src/game/WorldHandlers/Channel.h index 9ed370f60..1f5b2fc79 100644 --- a/src/game/WorldHandlers/Channel.h +++ b/src/game/WorldHandlers/Channel.h @@ -39,9 +39,9 @@ enum ChatNotify { CHAT_JOINED_NOTICE = 0x00, //+ "%s joined channel."; CHAT_LEFT_NOTICE = 0x01, //+ "%s left channel."; - // CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel."; + // CHAT_SUSPENDED_NOTICE = 0x01, // "%s left channel."; CHAT_YOU_JOINED_NOTICE = 0x02, //+ "Joined Channel: [%s]"; -- You joined - // CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]"; + // CHAT_YOU_CHANGED_NOTICE = 0x02, // "Changed Channel: [%s]"; CHAT_YOU_LEFT_NOTICE = 0x03, //+ "Left Channel: [%s]"; -- You left CHAT_WRONG_PASSWORD_NOTICE = 0x04, //+ "Wrong password for %s."; CHAT_NOT_MEMBER_NOTICE = 0x05, //+ "Not on channel %s."; @@ -63,7 +63,7 @@ enum ChatNotify CHAT_PLAYER_UNBANNED_NOTICE = 0x15, //? "[%s] Player %s unbanned by %s."; CHAT_PLAYER_NOT_BANNED_NOTICE = 0x16, //+ "[%s] Player %s is not banned."; CHAT_PLAYER_ALREADY_MEMBER_NOTICE = 0x17, //+ "[%s] Player %s is already on the channel."; - CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'."; + CHAT_INVITE_NOTICE = 0x18, //+ "%2$s has invited you to join the channel '%1$s'."; CHAT_INVITE_WRONG_FACTION_NOTICE = 0x19, //+ "Target is in the wrong alliance for %s."; CHAT_WRONG_FACTION_NOTICE = 0x1A, //+ "Wrong alliance for %s."; CHAT_INVALID_NAME_NOTICE = 0x1B, //+ "Invalid channel name"; @@ -75,215 +75,215 @@ enum ChatNotify CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels. CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s."; CHAT_VOICE_OFF_NOTICE = 0x23 //+ "[%s] Channel voice disabled by %s."; - // 0x24 enable voice? + // 0x24 enable voice? }; class Channel { - enum ChannelFlags - { - CHANNEL_FLAG_NONE = 0x00, - CHANNEL_FLAG_CUSTOM = 0x01, - // 0x02 - CHANNEL_FLAG_TRADE = 0x04, - CHANNEL_FLAG_NOT_LFG = 0x08, - CHANNEL_FLAG_GENERAL = 0x10, - CHANNEL_FLAG_CITY = 0x20, - CHANNEL_FLAG_LFG = 0x40, - CHANNEL_FLAG_VOICE = 0x80 - // General 0x18 = 0x10 | 0x08 - // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04 - // LocalDefence 0x18 = 0x10 | 0x08 - // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08 - // LookingForGroup 0x50 = 0x40 | 0x10 - }; + enum ChannelFlags + { + CHANNEL_FLAG_NONE = 0x00, + CHANNEL_FLAG_CUSTOM = 0x01, + // 0x02 + CHANNEL_FLAG_TRADE = 0x04, + CHANNEL_FLAG_NOT_LFG = 0x08, + CHANNEL_FLAG_GENERAL = 0x10, + CHANNEL_FLAG_CITY = 0x20, + CHANNEL_FLAG_LFG = 0x40, + CHANNEL_FLAG_VOICE = 0x80 + // General 0x18 = 0x10 | 0x08 + // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04 + // LocalDefence 0x18 = 0x10 | 0x08 + // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08 + // LookingForGroup 0x50 = 0x40 | 0x10 + }; - enum ChannelDBCFlags - { - CHANNEL_DBC_FLAG_NONE = 0x00000, - CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG - CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment - CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense - CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade - CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment - CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment - CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense - CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment - CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup - }; + enum ChannelDBCFlags + { + CHANNEL_DBC_FLAG_NONE = 0x00000, + CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG + CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment + CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense + CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade + CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment + CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment + CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense + CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment + CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup + }; - enum ChannelMemberFlags - { - MEMBER_FLAG_NONE = 0x00, - MEMBER_FLAG_OWNER = 0x01, - MEMBER_FLAG_MODERATOR = 0x02, - MEMBER_FLAG_VOICED = 0x04, - MEMBER_FLAG_MUTED = 0x08, - MEMBER_FLAG_CUSTOM = 0x10, - MEMBER_FLAG_MIC_MUTED = 0x20, - // 0x40 - // 0x80 - }; + enum ChannelMemberFlags + { + MEMBER_FLAG_NONE = 0x00, + MEMBER_FLAG_OWNER = 0x01, + MEMBER_FLAG_MODERATOR = 0x02, + MEMBER_FLAG_VOICED = 0x04, + MEMBER_FLAG_MUTED = 0x08, + MEMBER_FLAG_CUSTOM = 0x10, + MEMBER_FLAG_MIC_MUTED = 0x20, + // 0x40 + // 0x80 + }; - struct PlayerInfo - { - ObjectGuid player; - uint8 flags; + struct PlayerInfo + { + ObjectGuid player; + uint8 flags; - bool HasFlag(uint8 flag) { return flags & flag; } - void SetFlag(uint8 flag) { if (!HasFlag(flag)) flags |= flag; } - bool IsOwner() { return flags & MEMBER_FLAG_OWNER; } - void SetOwner(bool state) - { - if (state) flags |= MEMBER_FLAG_OWNER; - else flags &= ~MEMBER_FLAG_OWNER; - } - bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; } - void SetModerator(bool state) - { - if (state) flags |= MEMBER_FLAG_MODERATOR; - else flags &= ~MEMBER_FLAG_MODERATOR; - } - bool IsMuted() { return flags & MEMBER_FLAG_MUTED; } - void SetMuted(bool state) - { - if (state) flags |= MEMBER_FLAG_MUTED; - else flags &= ~MEMBER_FLAG_MUTED; - } - }; + bool HasFlag(uint8 flag) { return flags & flag; } + void SetFlag(uint8 flag) { if (!HasFlag(flag)) flags |= flag; } + bool IsOwner() { return flags & MEMBER_FLAG_OWNER; } + void SetOwner(bool state) + { + if (state) flags |= MEMBER_FLAG_OWNER; + else flags &= ~MEMBER_FLAG_OWNER; + } + bool IsModerator() { return flags & MEMBER_FLAG_MODERATOR; } + void SetModerator(bool state) + { + if (state) flags |= MEMBER_FLAG_MODERATOR; + else flags &= ~MEMBER_FLAG_MODERATOR; + } + bool IsMuted() { return flags & MEMBER_FLAG_MUTED; } + void SetMuted(bool state) + { + if (state) flags |= MEMBER_FLAG_MUTED; + else flags &= ~MEMBER_FLAG_MUTED; + } + }; - public: - Channel(const std::string& name, uint32 channel_id); - std::string GetName() const { return m_name; } - uint32 GetChannelId() const { return m_channelId; } - bool IsConstant() const { return m_channelId != 0; } - bool IsAnnounce() const { return m_announce; } - bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; } - std::string GetPassword() const { return m_password; } - void SetPassword(const std::string& npassword) { m_password = npassword; } - void SetAnnounce(bool nannounce) { m_announce = nannounce; } - uint32 GetNumPlayers() const { return m_players.size(); } - uint8 GetFlags() const { return m_flags; } - bool HasFlag(uint8 flag) { return m_flags & flag; } +public: + Channel(const std::string& name, uint32 channel_id); + std::string GetName() const { return m_name; } + uint32 GetChannelId() const { return m_channelId; } + bool IsConstant() const { return m_channelId != 0; } + bool IsAnnounce() const { return m_announce; } + bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; } + std::string GetPassword() const { return m_password; } + void SetPassword(const std::string& npassword) { m_password = npassword; } + void SetAnnounce(bool nannounce) { m_announce = nannounce; } + uint32 GetNumPlayers() const { return m_players.size(); } + uint8 GetFlags() const { return m_flags; } + bool HasFlag(uint8 flag) { return m_flags & flag; } - void Join(ObjectGuid p, const char* pass); - void Leave(ObjectGuid p, bool send = true); - void KickOrBan(ObjectGuid good, const char* badname, bool ban); - void Kick(ObjectGuid good, const char* badname) { KickOrBan(good, badname, false); } - void Ban(ObjectGuid good, const char* badname) { KickOrBan(good, badname, true); } - void UnBan(ObjectGuid good, const char* badname); - void Password(ObjectGuid p, const char* pass); - void SetMode(ObjectGuid p, const char* p2n, bool mod, bool set); - void SetOwner(ObjectGuid p, bool exclaim = true); - void SetOwner(ObjectGuid p, const char* newname); - void SendWhoOwner(ObjectGuid p); - void SetModerator(ObjectGuid p, const char* newname) { SetMode(p, newname, true, true); } - void UnsetModerator(ObjectGuid p, const char* newname) { SetMode(p, newname, true, false); } - void SetMute(ObjectGuid p, const char* newname) { SetMode(p, newname, false, true); } - void UnsetMute(ObjectGuid p, const char* newname) { SetMode(p, newname, false, false); } - void List(Player* p); - void Announce(ObjectGuid p); - void Moderate(ObjectGuid p); - void Say(ObjectGuid p, const char* what, uint32 lang); - void Invite(ObjectGuid p, const char* newp); - void Voice(ObjectGuid guid1, ObjectGuid guid2); - void DeVoice(ObjectGuid guid1, ObjectGuid guid2); - void JoinNotify(ObjectGuid guid); // invisible notify - void LeaveNotify(ObjectGuid guid); // invisible notify + void Join(Player* player, const char* password); + void Leave(Player* player, bool send = true); + void KickOrBan(Player* player, const char* targetName, bool ban); + void Kick(Player* player, const char* targetName) { KickOrBan(player, targetName, false); } + void Ban(Player* player, const char* targetName) { KickOrBan(player, targetName, true); } + void UnBan(Player* player, const char* targetName); + void Password(Player* player, const char* password); + void SetMode(Player* player, const char* targetName, bool moderator, bool set); + void SetOwner(ObjectGuid guid, bool exclaim = true); + void SetOwner(Player* player, const char* targetName); + void SendWhoOwner(Player* player); + void SetModerator(Player* player, const char* targetName) { SetMode(player, targetName, true, true); } + void UnsetModerator(Player* player, const char* targetName) { SetMode(player, targetName, true, false); } + void SetMute(Player* player, const char* targetName) { SetMode(player, targetName, false, true); } + void UnsetMute(Player* player, const char* targetName) { SetMode(player, targetName, false, false); } + void List(Player* player); + void Announce(Player* player); + void Moderate(Player* player); + void Say(Player* player, const char* text, uint32 lang); + void Invite(Player* player, const char* targetName); + void Voice(ObjectGuid guid1, ObjectGuid guid2); + void DeVoice(ObjectGuid guid1, ObjectGuid guid2); + void JoinNotify(ObjectGuid guid); // invisible notify + void LeaveNotify(ObjectGuid guid); // invisible notify - private: - // initial packet data (notify type and channel name) - void MakeNotifyPacket(WorldPacket* data, uint8 notify_type); - // type specific packet data - void MakeJoined(WorldPacket* data, ObjectGuid guid); //+ 0x00 - void MakeLeft(WorldPacket* data, ObjectGuid guid); //+ 0x01 - void MakeYouJoined(WorldPacket* data); //+ 0x02 - void MakeYouLeft(WorldPacket* data); //+ 0x03 - void MakeWrongPassword(WorldPacket* data); //? 0x04 - void MakeNotMember(WorldPacket* data); //? 0x05 - void MakeNotModerator(WorldPacket* data); //? 0x06 - void MakePasswordChanged(WorldPacket* data, ObjectGuid guid); //+ 0x07 - void MakeOwnerChanged(WorldPacket* data, ObjectGuid guid); //? 0x08 - void MakePlayerNotFound(WorldPacket* data, const std::string& name); //+ 0x09 - void MakeNotOwner(WorldPacket* data); //? 0x0A - void MakeChannelOwner(WorldPacket* data); //? 0x0B - void MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags);//+ 0x0C - void MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid); //+ 0x0D - void MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid); //+ 0x0E - void MakeModerationOn(WorldPacket* data, ObjectGuid guid); //+ 0x0F - void MakeModerationOff(WorldPacket* data, ObjectGuid guid); //+ 0x10 - void MakeMuted(WorldPacket* data); //? 0x11 - void MakePlayerKicked(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x12 - void MakeBanned(WorldPacket* data); //? 0x13 - void MakePlayerBanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x14 - void MakePlayerUnbanned(WorldPacket* data, ObjectGuid bad, ObjectGuid good);//? 0x15 - void MakePlayerNotBanned(WorldPacket* data, ObjectGuid guid); //? 0x16 - void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17 - void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18 - void MakeInviteWrongFaction(WorldPacket* data); //? 0x19 - void MakeWrongFaction(WorldPacket* data); //? 0x1A - void MakeInvalidName(WorldPacket* data); //? 0x1B - void MakeNotModerated(WorldPacket* data); //? 0x1C - void MakePlayerInvited(WorldPacket* data, const std::string& name); //+ 0x1D - void MakePlayerInviteBanned(WorldPacket* data, ObjectGuid guid); //? 0x1E - void MakeThrottled(WorldPacket* data); //? 0x1F - void MakeNotInArea(WorldPacket* data); //? 0x20 - void MakeNotInLfg(WorldPacket* data); //? 0x21 - void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22 - void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23 +private: + // initial packet data (notify type and channel name) + void MakeNotifyPacket(WorldPacket* data, uint8 notify_type); + // type specific packet data + void MakeJoined(WorldPacket* data, ObjectGuid guid); //+ 0x00 + void MakeLeft(WorldPacket* data, ObjectGuid guid); //+ 0x01 + void MakeYouJoined(WorldPacket* data); //+ 0x02 + void MakeYouLeft(WorldPacket* data); //+ 0x03 + void MakeWrongPassword(WorldPacket* data); //? 0x04 + void MakeNotMember(WorldPacket* data); //? 0x05 + void MakeNotModerator(WorldPacket* data); //? 0x06 + void MakePasswordChanged(WorldPacket* data, ObjectGuid guid); //+ 0x07 + void MakeOwnerChanged(WorldPacket* data, ObjectGuid guid); //? 0x08 + void MakePlayerNotFound(WorldPacket* data, const std::string& name); //+ 0x09 + void MakeNotOwner(WorldPacket* data); //? 0x0A + void MakeChannelOwner(WorldPacket* data); //? 0x0B + void MakeModeChange(WorldPacket* data, ObjectGuid guid, uint8 oldflags);//+ 0x0C + void MakeAnnouncementsOn(WorldPacket* data, ObjectGuid guid); //+ 0x0D + void MakeAnnouncementsOff(WorldPacket* data, ObjectGuid guid); //+ 0x0E + void MakeModerationOn(WorldPacket* data, ObjectGuid guid); //+ 0x0F + void MakeModerationOff(WorldPacket* data, ObjectGuid guid); //+ 0x10 + void MakeMuted(WorldPacket* data); //? 0x11 + void MakePlayerKicked(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x12 + void MakeBanned(WorldPacket* data); //? 0x13 + void MakePlayerBanned(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x14 + void MakePlayerUnbanned(WorldPacket* data, ObjectGuid target, ObjectGuid source);//? 0x15 + void MakePlayerNotBanned(WorldPacket* data, const std::string& name); //? 0x16 + void MakePlayerAlreadyMember(WorldPacket* data, ObjectGuid guid); //+ 0x17 + void MakeInvite(WorldPacket* data, ObjectGuid guid); //? 0x18 + void MakeInviteWrongFaction(WorldPacket* data); //? 0x19 + void MakeWrongFaction(WorldPacket* data); //? 0x1A + void MakeInvalidName(WorldPacket* data); //? 0x1B + void MakeNotModerated(WorldPacket* data); //? 0x1C + void MakePlayerInvited(WorldPacket* data, const std::string& name); //+ 0x1D + void MakePlayerInviteBanned(WorldPacket* data, const std::string& name);//? 0x1E + void MakeThrottled(WorldPacket* data); //? 0x1F + void MakeNotInArea(WorldPacket* data); //? 0x20 + void MakeNotInLfg(WorldPacket* data); //? 0x21 + void MakeVoiceOn(WorldPacket* data, ObjectGuid guid); //+ 0x22 + void MakeVoiceOff(WorldPacket* data, ObjectGuid guid); //+ 0x23 - void SendToAll(WorldPacket* data, ObjectGuid p = ObjectGuid()); - void SendToOne(WorldPacket* data, ObjectGuid who); + void SendToAll(WorldPacket* data, ObjectGuid guid = ObjectGuid()); + void SendToOne(WorldPacket* data, ObjectGuid who); - bool IsOn(ObjectGuid who) const { return m_players.find(who) != m_players.end(); } - bool IsBanned(ObjectGuid guid) const { return m_banned.find(guid) != m_banned.end(); } + bool IsOn(ObjectGuid who) const { return m_players.find(who) != m_players.end(); } + bool IsBanned(ObjectGuid guid) const { return m_banned.find(guid) != m_banned.end(); } - uint8 GetPlayerFlags(ObjectGuid p) const - { - PlayerList::const_iterator p_itr = m_players.find(p); - if (p_itr == m_players.end()) - return 0; + uint8 GetPlayerFlags(ObjectGuid guid) const + { + PlayerList::const_iterator p_itr = m_players.find(guid); + if (p_itr == m_players.end()) + return 0; - return p_itr->second.flags; - } + return p_itr->second.flags; + } - void SetModerator(ObjectGuid p, bool set) - { - if (m_players[p].IsModerator() != set) - { - uint8 oldFlag = GetPlayerFlags(p); - m_players[p].SetModerator(set); + void SetModerator(ObjectGuid guid, bool set) + { + if (m_players[guid].IsModerator() != set) + { + uint8 oldFlag = GetPlayerFlags(guid); + m_players[guid].SetModerator(set); - WorldPacket data; - MakeModeChange(&data, p, oldFlag); - SendToAll(&data); - } - } + WorldPacket data; + MakeModeChange(&data, guid, oldFlag); + SendToAll(&data); + } + } - void SetMute(ObjectGuid p, bool set) - { - if (m_players[p].IsMuted() != set) - { - uint8 oldFlag = GetPlayerFlags(p); - m_players[p].SetMuted(set); + void SetMute(ObjectGuid guid, bool set) + { + if (m_players[guid].IsMuted() != set) + { + uint8 oldFlag = GetPlayerFlags(guid); + m_players[guid].SetMuted(set); - WorldPacket data; - MakeModeChange(&data, p, oldFlag); - SendToAll(&data); - } - } + WorldPacket data; + MakeModeChange(&data, guid, oldFlag); + SendToAll(&data); + } + } - private: - bool m_announce; - bool m_moderate; - std::string m_name; - std::string m_password; - uint8 m_flags; - uint32 m_channelId; - ObjectGuid m_ownerGuid; +private: + bool m_announce; + bool m_moderate; + std::string m_name; + std::string m_password; + uint8 m_flags; + uint32 m_channelId; + ObjectGuid m_ownerGuid; - typedef std::map PlayerList; - PlayerList m_players; - GuidSet m_banned; + typedef std::map PlayerList; + PlayerList m_players; + GuidSet m_banned; }; #endif diff --git a/src/game/WorldHandlers/ChannelHandler.cpp b/src/game/WorldHandlers/ChannelHandler.cpp index 7b95e837e..4c1442943 100644 --- a/src/game/WorldHandlers/ChannelHandler.cpp +++ b/src/game/WorldHandlers/ChannelHandler.cpp @@ -45,14 +45,15 @@ void WorldSession::HandleJoinChannelOpcode(WorldPacket& recvPacket) return; if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetJoinChannel(channelname, channel_id)) // channel id seems to be useless but must be checked for LFG - chn->Join(_player->GetObjectGuid(), pass.c_str()); + if (Channel* chn = cMgr->GetJoinChannel(channelname, channel_id)) + chn->Join(_player, pass.c_str()); } void WorldSession::HandleLeaveChannelOpcode(WorldPacket& recvPacket) { DEBUG_LOG("WORLD: Received opcode %s (%u, 0x%X)", recvPacket.GetOpcodeName(), recvPacket.GetOpcode(), recvPacket.GetOpcode()); // recvPacket.hexlike(); + uint32 unk; std::string channelname; recvPacket >> unk; // channel id? @@ -64,7 +65,7 @@ void WorldSession::HandleLeaveChannelOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) { if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Leave(_player->GetObjectGuid(), true); + chn->Leave(_player, true); cMgr->LeftChannel(channelname); } } @@ -94,7 +95,7 @@ void WorldSession::HandleChannelPasswordOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Password(_player->GetObjectGuid(), pass.c_str()); + chn->Password(_player, pass.c_str()); } void WorldSession::HandleChannelSetOwnerOpcode(WorldPacket& recvPacket) @@ -126,7 +127,7 @@ void WorldSession::HandleChannelOwnerOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SendWhoOwner(_player->GetObjectGuid()); + chn->SendWhoOwner(_player); } void WorldSession::HandleChannelModeratorOpcode(WorldPacket& recvPacket) @@ -146,7 +147,7 @@ void WorldSession::HandleChannelModeratorOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SetModerator(_player->GetObjectGuid(), otp.c_str()); + chn->SetModerator(_player, otp.c_str()); } void WorldSession::HandleChannelUnmoderatorOpcode(WorldPacket& recvPacket) @@ -156,17 +157,17 @@ void WorldSession::HandleChannelUnmoderatorOpcode(WorldPacket& recvPacket) uint32 channelLen, nameLen; std::string channelname, otp; - nameLen = recvPacket.ReadBits(7); channelLen = recvPacket.ReadBits(8); - channelname = recvPacket.ReadString(channelLen); + nameLen = recvPacket.ReadBits(7); otp = recvPacket.ReadString(nameLen); + channelname = recvPacket.ReadString(channelLen); if (!normalizePlayerName(otp)) return; if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->UnsetModerator(_player->GetObjectGuid(), otp.c_str()); + chn->UnsetMute(_player, otp.c_str()); } void WorldSession::HandleChannelMuteOpcode(WorldPacket& recvPacket) @@ -176,17 +177,17 @@ void WorldSession::HandleChannelMuteOpcode(WorldPacket& recvPacket) uint32 channelLen, nameLen; std::string channelname, otp; - channelLen = recvPacket.ReadBits(8); nameLen = recvPacket.ReadBits(7); - channelname = recvPacket.ReadString(channelLen); + channelLen = recvPacket.ReadBits(8); otp = recvPacket.ReadString(nameLen); + channelname = recvPacket.ReadString(channelLen); if (!normalizePlayerName(otp)) return; if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SetMute(_player->GetObjectGuid(), otp.c_str()); + chn->Invite(_player, otp.c_str()); } void WorldSession::HandleChannelUnmuteOpcode(WorldPacket& recvPacket) @@ -206,7 +207,7 @@ void WorldSession::HandleChannelUnmuteOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->UnsetMute(_player->GetObjectGuid(), otp.c_str()); + chn->UnsetMute(_player, otp.c_str()); } void WorldSession::HandleChannelInviteOpcode(WorldPacket& recvPacket) @@ -226,7 +227,7 @@ void WorldSession::HandleChannelInviteOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Invite(_player->GetObjectGuid(), otp.c_str()); + chn->Invite(_player, otp.c_str()); } void WorldSession::HandleChannelKickOpcode(WorldPacket& recvPacket) @@ -246,7 +247,7 @@ void WorldSession::HandleChannelKickOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Kick(_player->GetObjectGuid(), otp.c_str()); + chn->Kick(_player, otp.c_str()); } void WorldSession::HandleChannelBanOpcode(WorldPacket& recvPacket) @@ -266,7 +267,7 @@ void WorldSession::HandleChannelBanOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Ban(_player->GetObjectGuid(), otp.c_str()); + chn->Ban(_player, otp.c_str()); } void WorldSession::HandleChannelUnbanOpcode(WorldPacket& recvPacket) @@ -286,7 +287,7 @@ void WorldSession::HandleChannelUnbanOpcode(WorldPacket& recvPacket) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->UnBan(_player->GetObjectGuid(), otp.c_str()); + chn->UnBan(_player, otp.c_str()); } void WorldSession::HandleChannelAnnouncementsOpcode(WorldPacket& recvPacket) @@ -296,7 +297,7 @@ void WorldSession::HandleChannelAnnouncementsOpcode(WorldPacket& recvPacket) std::string channelname = recvPacket.ReadString(recvPacket.ReadBits(8)); if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Announce(_player->GetObjectGuid()); + chn->Announce(_player); } void WorldSession::HandleChannelModerateOpcode(WorldPacket& recvPacket) @@ -307,7 +308,7 @@ void WorldSession::HandleChannelModerateOpcode(WorldPacket& recvPacket) recvPacket >> channelname; if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Moderate(_player->GetObjectGuid()); + chn->Moderate(_player); } void WorldSession::HandleChannelDisplayListQueryOpcode(WorldPacket& recvPacket) diff --git a/src/game/WorldHandlers/Chat.cpp b/src/game/WorldHandlers/Chat.cpp index e0177b7f9..14c6ef026 100644 --- a/src/game/WorldHandlers/Chat.cpp +++ b/src/game/WorldHandlers/Chat.cpp @@ -536,7 +536,8 @@ ChatCommand* ChatHandler::getCommandTable() { "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL }, { "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL }, { "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL }, - { "creature_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL }, + { "creature_battleground", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadBattleEventCommand, "", NULL }, + { "creature_template_classlevelstats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreaturesStatsCommand, "", nullptr }, { "creature_involvedrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestInvRelationsCommand, "", NULL }, { "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, { "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, @@ -985,7 +986,7 @@ void ChatHandler::SendSysMessage(const char* str) while (char* line = LineFromMessage(pos)) { - FillSystemMessageData(&data, line); + ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, m_session->GetPlayer()->GetObjectGuid()); m_session->SendPacket(&data); } @@ -1000,10 +1001,11 @@ void ChatHandler::SendGlobalSysMessage(const char* str) // need copy to prevent corruption by strtok call in LineFromMessage original string char* buf = mangos_strdup(str); char* pos = buf; + ObjectGuid guid = m_session ? m_session->GetPlayer()->GetObjectGuid() : ObjectGuid(); while (char* line = LineFromMessage(pos)) { - FillSystemMessageData(&data, line); + ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, line, LANG_UNIVERSAL, CHAT_TAG_NONE, guid); sWorld.SendGlobalMessage(&data); } @@ -2095,99 +2097,6 @@ bool ChatHandler::isValidChatMessage(const char* message) return validSequence == validSequenceIterator; } -// Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored) -void ChatHandler::FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* channelName, ObjectGuid targetGuid, const char* message, Unit* speaker, const char* addonPrefix /*= NULL*/) -{ - uint32 messageLength = (message ? strlen(message) : 0) + 1; - - data->Initialize(SMSG_MESSAGECHAT, 100); // guess size - *data << uint8(type); - if ((type != CHAT_MSG_CHANNEL && type != CHAT_MSG_WHISPER) || language == LANG_ADDON) - *data << uint32(language); - else - *data << uint32(LANG_UNIVERSAL); - - switch (type) - { - case CHAT_MSG_SAY: - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - case CHAT_MSG_RAID: - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - case CHAT_MSG_YELL: - case CHAT_MSG_WHISPER: - case CHAT_MSG_CHANNEL: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - case CHAT_MSG_BG_SYSTEM_NEUTRAL: - case CHAT_MSG_BG_SYSTEM_ALLIANCE: - case CHAT_MSG_BG_SYSTEM_HORDE: - case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_BATTLEGROUND_LEADER: - targetGuid = session ? session->GetPlayer()->GetObjectGuid() : ObjectGuid(); - break; - case CHAT_MSG_MONSTER_SAY: - case CHAT_MSG_MONSTER_PARTY: - case CHAT_MSG_MONSTER_YELL: - case CHAT_MSG_MONSTER_WHISPER: - case CHAT_MSG_MONSTER_EMOTE: - case CHAT_MSG_RAID_BOSS_WHISPER: - case CHAT_MSG_RAID_BOSS_EMOTE: - case CHAT_MSG_BATTLENET: - { - *data << ObjectGuid(speaker->GetObjectGuid()); - *data << uint32(0); // 2.1.0 - *data << uint32(strlen(speaker->GetName()) + 1); - *data << speaker->GetName(); - ObjectGuid listener_guid; - *data << listener_guid; - if (listener_guid && !listener_guid.IsPlayer()) - { - *data << uint32(1); // string listener_name_length - *data << uint8(0); // string listener_name - } - *data << uint32(messageLength); - *data << message; - *data << uint8(0); - - if (type == CHAT_MSG_RAID_BOSS_WHISPER || type == CHAT_MSG_RAID_BOSS_EMOTE) - { - *data << float(0.0f); // Added in 4.2.0, unk - *data << uint8(0); // Added in 4.2.0, unk - } - return; - } - default: - if (type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_IGNORED && type != CHAT_MSG_DND && type != CHAT_MSG_AFK) - targetGuid.Clear(); // only for CHAT_MSG_WHISPER_INFORM used original value target_guid - break; - } - - *data << ObjectGuid(targetGuid); // there 0 for BG messages - *data << uint32(0); // can be chat msg group or something - - if (type == CHAT_MSG_CHANNEL) - { - MANGOS_ASSERT(channelName); - *data << channelName; - *data << ObjectGuid(targetGuid); - } - else if (type == CHAT_MSG_ADDON) - { - MANGOS_ASSERT(addonPrefix); - *data << addonPrefix; - } - else - *data << ObjectGuid(targetGuid); - *data << uint32(messageLength); - *data << message; - if (session != 0 && type != CHAT_MSG_WHISPER_INFORM && type != CHAT_MSG_DND && type != CHAT_MSG_AFK) - *data << uint8(session->GetPlayer()->GetChatTag()); - else - *data << uint8(0); -} - Player* ChatHandler::getSelectedPlayer() { if (!m_session) @@ -3717,11 +3626,12 @@ void ChatHandler::LogCommand(char const* fullcmd) } void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const* message, Language language /*= LANG_UNIVERSAL*/, ChatTagFlags chatTag /*= CHAT_TAG_NONE*/, - ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= NULL*/, - ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* targetName /*= NULL*/, - char const* channelName /*= NULL*/) + ObjectGuid const& senderGuid /*= ObjectGuid()*/, char const* senderName /*= nullptr*/, + ObjectGuid const& targetGuid /*= ObjectGuid()*/, char const* targetName /*= nullptr*/, + char const* channelName /*= nullptr*/, uint32 achievementId /*= 0*/, const char* addonPrefix /*= nullptr*/) { bool isGM = chatTag & CHAT_TAG_GM; + bool isAchievement = false; data.Initialize(isGM ? SMSG_GM_MESSAGECHAT : SMSG_MESSAGECHAT); data << uint8(msgtype); @@ -3731,60 +3641,76 @@ void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const switch (msgtype) { - case CHAT_MSG_MONSTER_SAY: - case CHAT_MSG_MONSTER_PARTY: - case CHAT_MSG_MONSTER_YELL: - case CHAT_MSG_MONSTER_WHISPER: - case CHAT_MSG_RAID_BOSS_WHISPER: - case CHAT_MSG_RAID_BOSS_EMOTE: - case CHAT_MSG_MONSTER_EMOTE: - MANGOS_ASSERT(senderName); - data << uint32(strlen(senderName) + 1); - data << senderName; - data << ObjectGuid(targetGuid); // Unit Target - if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet()) - { - data << uint32(strlen(targetName) + 1); // target name length - data << targetName; // target name - } - MANGOS_ASSERT(message); - data << uint32(strlen(message) + 1); - data << message; - data << uint8(chatTag); - break; - case CHAT_MSG_BG_SYSTEM_NEUTRAL: - case CHAT_MSG_BG_SYSTEM_ALLIANCE: - case CHAT_MSG_BG_SYSTEM_HORDE: - data << ObjectGuid(targetGuid); // Unit Target - if (targetGuid && !targetGuid.IsPlayer()) - { - MANGOS_ASSERT(targetName); - data << uint32(strlen(targetName) + 1); // target name length - data << targetName; // target name - } - MANGOS_ASSERT(message); - data << uint32(strlen(message) + 1); - data << message; - data << uint8(chatTag); - break; - default: - if (msgtype == CHAT_MSG_CHANNEL) - { - MANGOS_ASSERT(channelName); - data << channelName; - } - data << ObjectGuid(targetGuid); - MANGOS_ASSERT(message); - data << uint32(strlen(message) + 1); - data << message; - data << uint8(chatTag); - if (isGM) - { + case CHAT_MSG_MONSTER_SAY: + case CHAT_MSG_MONSTER_PARTY: + case CHAT_MSG_MONSTER_YELL: + case CHAT_MSG_MONSTER_WHISPER: + case CHAT_MSG_MONSTER_EMOTE: + case CHAT_MSG_RAID_BOSS_WHISPER: + case CHAT_MSG_RAID_BOSS_EMOTE: + case CHAT_MSG_BATTLENET: + case CHAT_MSG_WHISPER_FOREIGN: MANGOS_ASSERT(senderName); data << uint32(strlen(senderName) + 1); data << senderName; - } - break; + data << ObjectGuid(targetGuid); // Unit Target + if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet() && (msgtype != CHAT_MSG_WHISPER_FOREIGN)) + { + data << uint32(strlen(targetName) + 1); // target name length + data << targetName; // target name + } + break; + case CHAT_MSG_BG_SYSTEM_NEUTRAL: + case CHAT_MSG_BG_SYSTEM_ALLIANCE: + case CHAT_MSG_BG_SYSTEM_HORDE: + data << ObjectGuid(targetGuid); // Unit Target + if (targetGuid && !targetGuid.IsPlayer()) + { + MANGOS_ASSERT(targetName); + data << uint32(strlen(targetName) + 1); // target name length + data << targetName; // target name + } + break; + case CHAT_MSG_ACHIEVEMENT: + case CHAT_MSG_GUILD_ACHIEVEMENT: + data << ObjectGuid(targetGuid); // Unit Target + isAchievement = true; + break; + default: + if (isGM) + { + MANGOS_ASSERT(senderName); + data << uint32(strlen(senderName) + 1); + data << senderName; + } + + if (msgtype == CHAT_MSG_CHANNEL) + { + MANGOS_ASSERT(channelName); + data << channelName; + data << ObjectGuid(targetGuid); + } + else if (msgtype == CHAT_MSG_ADDON) + { + MANGOS_ASSERT(addonPrefix); + data << addonPrefix; + } + else + data << ObjectGuid(targetGuid); + break; + } + MANGOS_ASSERT(message); + data << uint32(strlen(message) + 1); + data << message; + data << uint8(chatTag); + + if (isAchievement) + data << uint32(achievementId); + + if (msgtype == CHAT_MSG_RAID_BOSS_WHISPER || msgtype == CHAT_MSG_RAID_BOSS_EMOTE) + { + data << float(0.0f); // Added in 4.2.0, unk + data << uint8(0); // Added in 4.2.0, unk } } diff --git a/src/game/WorldHandlers/Chat.h b/src/game/WorldHandlers/Chat.h index 4ac1f98a2..3be9aeaed 100644 --- a/src/game/WorldHandlers/Chat.h +++ b/src/game/WorldHandlers/Chat.h @@ -71,12 +71,12 @@ enum ChatCommandSearchResult enum PlayerChatTag { - CHAT_TAG_NONE = 0, - CHAT_TAG_AFK = 1, - CHAT_TAG_DND = 2, - CHAT_TAG_GM = 3, - CHAT_TAG_COM = 4, // Commentator - CHAT_TAG_DEV = 5, // Developer + CHAT_TAG_NONE = 0x00, + CHAT_TAG_AFK = 0x01, + CHAT_TAG_DND = 0x02, + CHAT_TAG_GM = 0x04, + CHAT_TAG_COM = 0x08, // Commentator + CHAT_TAG_DEV = 0x10, // Developer }; typedef uint32 ChatTagFlags; @@ -87,23 +87,6 @@ class ChatHandler explicit ChatHandler(Player* player); ~ChatHandler(); - static void FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* channelName, ObjectGuid targetGuid, const char* message, Unit* speaker, const char* addonPrefix = NULL); - - static void FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, ObjectGuid targetGuid, const char* message) - { - FillMessageData(data, session, type, language, NULL, targetGuid, message, NULL); - } - - static void FillMessageData(WorldPacket* data, WorldSession* session, uint8 type, uint32 language, const char* message) - { - FillMessageData(data, session, type, language, NULL, ObjectGuid(), message, NULL); - } - - void FillSystemMessageData(WorldPacket* data, const char* message) - { - FillMessageData(data, m_session, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, ObjectGuid(), message); - } - static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = NULL; return start; } // function with different implementation for chat/console @@ -140,12 +123,13 @@ class ChatHandler * \param ObjectGuid const& targetGuid : Often null, but needed for type *MONSTER* or *BATTLENET or *BATTLEGROUND* or *ACHIEVEMENT * \param char const* targetName : Often null, but needed for type *MONSTER* or *BATTLENET or *BATTLEGROUND* * \param char const* channelName : Required only for CHAT_MSG_CHANNEL + * \param uint32 achievementId : Required only for *ACHIEVEMENT + * \param const char* addonPrefix : Required only for *CHAT_MSG_ADDON **/ - static void BuildChatPacket( - WorldPacket& data, ChatMsg msgtype, char const* message, Language language = LANG_UNIVERSAL, ChatTagFlags chatTag = CHAT_TAG_NONE, + static void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, char const* message, Language language = LANG_UNIVERSAL, ChatTagFlags chatTag = CHAT_TAG_NONE, ObjectGuid const& senderGuid = ObjectGuid(), char const* senderName = NULL, ObjectGuid const& targetGuid = ObjectGuid(), char const* targetName = NULL, - char const* channelName = NULL); + char const* channelName = NULL, uint32 achievementId = 0, const char* addonPrefix = NULL); protected: explicit ChatHandler() : m_session(NULL) {} // for CLI subclass @@ -450,6 +434,7 @@ class ChatHandler bool HandleReloadAreaTriggerTavernCommand(char* args); bool HandleReloadAreaTriggerTeleportCommand(char* args); bool HandleReloadBattleEventCommand(char* args); + bool HandleReloadCreaturesStatsCommand(char* args); bool HandleReloadCommandCommand(char* args); bool HandleReloadConditionsCommand(char* args); bool HandleReloadCreatureQuestRelationsCommand(char* args); diff --git a/src/game/WorldHandlers/ChatHandler.cpp b/src/game/WorldHandlers/ChatHandler.cpp index 1f3576525..8102e1858 100644 --- a/src/game/WorldHandlers/ChatHandler.cpp +++ b/src/game/WorldHandlers/ChatHandler.cpp @@ -286,7 +286,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) return; WorldPacket data; - ChatHandler::FillMessageData(&data, this, type, lang, msg.c_str()); + ChatHandler::BuildChatPacket(data, ChatMsg(type), msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetObjectGuid())); break; @@ -364,7 +364,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) } WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, msg.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); } break; case CHAT_MSG_RAID_LEADER: @@ -394,7 +394,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) } WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, msg.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_LEADER, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); } break; @@ -416,7 +416,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) WorldPacket data; // in battleground, raid warning is sent only to players in battleground - code is ok - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, msg.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_WARNING, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); } break; @@ -437,7 +437,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) return; WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, msg.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); } break; @@ -458,7 +458,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) return; WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, msg.c_str()); + ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND_LEADER, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); } break; @@ -478,7 +478,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) if (Channel* chn = cMgr->GetChannel(channel, _player)) - chn->Say(_player->GetObjectGuid(), msg.c_str(), lang); + chn->Say(_player, msg.c_str(), lang); } break; case CHAT_MSG_AFK: @@ -539,7 +539,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data) { - uint32 type; + ChatMsg type; switch (recv_data.GetOpcode()) { @@ -573,7 +573,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data) return; WorldPacket data; - ChatHandler::FillMessageData(&data, this, type, LANG_ADDON, "", ObjectGuid(), msg.c_str(), NULL); + ChatHandler::BuildChatPacket(data, type, msg.c_str(), LANG_ADDON); group->BroadcastPacket(&data, false); break; } @@ -618,7 +618,9 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data) if (!receiver) break; - _player->WhisperAddon(msg, prefix, receiver->GetObjectGuid()); + WorldPacket data; + ChatHandler::BuildChatPacket(data, type, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, ObjectGuid(), NULL, receiver->GetObjectGuid(), targetName.c_str(), NULL, 0, prefix.c_str()); + _player->GetSession()->SendPacket(&data); break; } // Messages sent to "RAID" while in a party will get delivered to "PARTY" @@ -635,7 +637,7 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recv_data) break; WorldPacket data; - ChatHandler::FillMessageData(&data, this, type, LANG_ADDON, "", ObjectGuid(), msg.c_str(), NULL, prefix.c_str()); + ChatHandler::BuildChatPacket(data, type, msg.c_str(), LANG_ADDON, CHAT_TAG_NONE, ObjectGuid(), NULL, ObjectGuid(), NULL, NULL, 0, prefix.c_str()); group->BroadcastPacket(&data, false, group->GetMemberGroup(_player->GetObjectGuid())); break; } @@ -768,7 +770,7 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data) return; WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetObjectGuid(), GetPlayer()->GetName(), NULL); + ChatHandler::BuildChatPacket(data, CHAT_MSG_IGNORED, _player->GetName(), LANG_UNIVERSAL, CHAT_TAG_NONE, _player->GetObjectGuid()); player->GetSession()->SendPacket(&data); } diff --git a/src/game/WorldHandlers/GossipDef.h b/src/game/WorldHandlers/GossipDef.h index 5f683c8c5..ec56fb5f3 100644 --- a/src/game/WorldHandlers/GossipDef.h +++ b/src/game/WorldHandlers/GossipDef.h @@ -32,8 +32,8 @@ class WorldSession; -#define GOSSIP_MAX_MENU_ITEMS 64 // client supported items unknown, but provided number must be enough -#define DEFAULT_GOSSIP_MESSAGE 0xffffff +#define GOSSIP_MAX_MENU_ITEMS 32 // client supports showing max 32 items +#define DEFAULT_GOSSIP_MESSAGE 0xffffff enum Gossip_Option { diff --git a/src/game/WorldHandlers/GridNotifiersImpl.h b/src/game/WorldHandlers/GridNotifiersImpl.h index 4ce746e23..40ec22ba9 100644 --- a/src/game/WorldHandlers/GridNotifiersImpl.h +++ b/src/game/WorldHandlers/GridNotifiersImpl.h @@ -657,7 +657,7 @@ void MaNGOS::LocalizedPacketDo::operator()(Player* p) if (i_data_cache.size() < cache_idx + 1) i_data_cache.resize(cache_idx + 1); - data = new WorldPacket(SMSG_MESSAGECHAT, 200); + data = new WorldPacket(); i_builder(*data, loc_idx); diff --git a/src/game/WorldHandlers/Map.cpp b/src/game/WorldHandlers/Map.cpp index 52ea6d908..343201056 100644 --- a/src/game/WorldHandlers/Map.cpp +++ b/src/game/WorldHandlers/Map.cpp @@ -45,6 +45,7 @@ #include "BattleGround/BattleGroundMgr.h" #include "Weather.h" #include "Calendar.h" +#include "Chat.h" #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ @@ -1970,8 +1971,8 @@ uint32 Map::GenerateLocalLowGuid(HighGuid guidhigh) */ class StaticMonsterChatBuilder { - public: - StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid = 0) +public: + StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, Language language, Unit const* target, uint32 senderLowGuid = 0) : i_cInfo(cInfo), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) { // 0 lowguid not used in core, but accepted fine in this case by client @@ -1984,7 +1985,8 @@ class StaticMonsterChatBuilder char const* nameForLocale = i_cInfo->Name; sObjectMgr.GetCreatureLocaleStrings(i_cInfo->Entry, loc_idx, &nameForLocale); - WorldObject::BuildMonsterChat(&data, i_senderGuid, i_msgtype, text, i_language, nameForLocale, i_target ? i_target->GetObjectGuid() : ObjectGuid(), i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); + ChatHandler::BuildChatPacket(data, i_msgtype, text, i_language, CHAT_TAG_NONE, i_senderGuid, nameForLocale, i_target ? i_target->GetObjectGuid() : ObjectGuid(), + i_target ? i_target->GetNameForLocaleIdx(loc_idx) : ""); } private: @@ -1992,7 +1994,7 @@ class StaticMonsterChatBuilder CreatureInfo const* i_cInfo; ChatMsg i_msgtype; int32 i_textId; - uint32 i_language; + Language i_language; Unit const* i_target; }; @@ -2126,3 +2128,178 @@ bool Map::ContainsGameObjectModel(const GameObjectModel& mdl) const { return m_dyn_tree.contains(mdl); } +// This will generate a random point to all directions in water for the provided point in radius range. +bool Map::GetRandomPointUnderWater(uint32 phaseMask, float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status) +{ + const float angle = rand_norm_f() * (M_PI_F * 2.0f); + const float range = rand_norm_f() * radius; + + float i_x = x + range * cos(angle); + float i_y = y + range * sin(angle); + + // get real ground of new point + // the code consider cylinder instead of sphere for possible z + float ground = GetHeight(phaseMask, i_x, i_y, z); + if (ground > INVALID_HEIGHT) // GetHeight can fail + { + float min_z = z - 0.7f * radius; // 0.7 to have a bit a "flat" cylinder, TODO which value looks nicest + if (min_z < ground) + min_z = ground + 0.5f; // Get some space to prevent under map + + float liquidLevel = liquid_status.level - 2.0f; // just to make the generated point is in water and not on surface or a bit above + + // if not enough space to fit the creature better is to return from here + if (min_z > liquidLevel) + return false; + + float max_z = std::max(z + 0.7f * radius, min_z); + max_z = std::min(max_z, liquidLevel); + x = i_x; + y = i_y; + z = min_z + rand_norm_f() * (max_z - min_z); + return true; + } + return false; +} + +// This will generate a random point to all directions in air for the provided point in radius range. +bool Map::GetRandomPointInTheAir(uint32 phaseMask, float& x, float& y, float& z, float radius) +{ + const float angle = rand_norm_f() * (M_PI_F * 2.0f); + const float range = rand_norm_f() * radius; + + float i_x = x + range * cos(angle); + float i_y = y + range * sin(angle); + + // get real ground of new point + // the code consider cylinder instead of sphere for possible z + float ground = GetHeight(phaseMask, i_x, i_y, z); + if (ground > INVALID_HEIGHT) // GetHeight can fail + { + float min_z = z - 0.7f * radius; // 0.7 to have a bit a "flat" cylinder, TODO which value looks nicest + if (min_z < ground) + min_z = ground + 2.5f; // Get some space to prevent landing + float max_z = std::max(z + 0.7f * radius, min_z); + x = i_x; + y = i_y; + z = min_z + rand_norm_f() * (max_z - min_z); + return true; + } + return false; +} + +// supposed to be used for not big radius, usually less than 20.0f +bool Map::GetReachableRandomPointOnGround(uint32 phaseMask, float& x, float& y, float& z, float radius) +{ + // Generate a random range and direction for the new point + const float angle = rand_norm_f() * (M_PI_F * 2.0f); + const float range = rand_norm_f() * radius; + + float i_x = x + range * cos(angle); + float i_y = y + range * sin(angle); + float i_z = z + 1.0f; + + GetHitPosition(x, y, z + 1.0f, i_x, i_y, i_z, phaseMask, -0.5f); + i_z = z; // reset i_z to z value to avoid too much difference from original point before GetHeightInRange + // commented out, as this function has not been defined anywhere (previous cores or other repos) +// if (!GetHeightInRange(phaseMask, i_x, i_y, i_z)) // GetHeight can fail +// return false; + + // here we have a valid position but the point can have a big Z in some case + // next code will check angle from 2 points + // c + // /| + // / | + // b/__|a + + // project vector to get only positive value + float ab = fabs(x - i_x); + float ac = fabs(z - i_z); + + // slope represented by c angle (in radian) + float slope = 0; + const float MAX_SLOPE_IN_RADIAN = 50.0f / 180.0f * M_PI_F; // 50(degree) max seem best value for walkable slope + + // check ab vector to avoid divide by 0 + if (ab > 0.0f) + { + // compute c angle and convert it from radian to degree + slope = atan(ac / ab); + if (slope < MAX_SLOPE_IN_RADIAN) + { + x = i_x; + y = i_y; + z = i_z; + return true; + } + } + + return false; +} + +// Get random point by handling different situation depending of if the unit is flying/swimming/walking +bool Map::GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius) +{ + + float i_x = x; + float i_y = y; + float i_z = z; + + bool newDestAssigned = false; // used to check if new random destination is found + + bool isFlying = false; + bool isSwimming = true; + switch (unit->GetTypeId()) + { + case TYPEID_PLAYER: + isFlying = static_cast(unit)->IsFlying(); + break; + case TYPEID_UNIT: + isFlying = static_cast(unit)->IsFlying(); + isSwimming = static_cast(unit)->IsSwimming(); + break; + default: + sLog.outError("Map::GetReachableRandomPosition> Unsupported unit type is passed!"); + return false; + } + + if (radius < 0.1f) + { + sLog.outError("Map::GetReachableRandomPosition> Unsupported unit type is passed!"); + return false; + } + + if (isFlying) + { + newDestAssigned = GetRandomPointInTheAir(unit->GetPhaseMask(), i_x, i_y, i_z, radius); + /*if (newDestAssigned) + sLog.outString("Generating air random point for %s", GetGuidStr().c_str());*/ + } + else + { + GridMapLiquidData liquid_status; + GridMapLiquidStatus res = m_TerrainData->getLiquidStatus(i_x, i_y, i_z, MAP_ALL_LIQUIDS, &liquid_status); + if (isSwimming && (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER))) + { + newDestAssigned = GetRandomPointUnderWater(unit->GetPhaseMask(), i_x, i_y, i_z, radius, liquid_status); + /*if (newDestAssigned) + sLog.outString("Generating swim random point for %s", GetGuidStr().c_str());*/ + } + else + { + newDestAssigned = GetReachableRandomPointOnGround(unit->GetPhaseMask(), i_x, i_y, i_z, radius); + /*if (newDestAssigned) + sLog.outString("Generating ground random point for %s", GetGuidStr().c_str());*/ + } + } + + if (newDestAssigned) + { + x = i_x; + y = i_y; + z = i_z; + return true; + } + + return false; +} diff --git a/src/game/WorldHandlers/Map.h b/src/game/WorldHandlers/Map.h index 1c8abbdb1..d2b4efb65 100644 --- a/src/game/WorldHandlers/Map.h +++ b/src/game/WorldHandlers/Map.h @@ -309,9 +309,9 @@ class Map : public GridRefManager // Random on map generation bool GetReachableRandomPosition(Unit* unit, float& x, float& y, float& z, float radius); - bool GetReachableRandomPointOnGround(float& x, float& y, float& z, float radius); - bool GetRandomPointInTheAir(float& x, float& y, float& z, float radius); - bool GetRandomPointUnderWater(float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status); + bool GetReachableRandomPointOnGround(uint32 phaseMask, float& x, float& y, float& z, float radius); + bool GetRandomPointInTheAir(uint32 phaseMask, float& x, float& y, float& z, float radius); + bool GetRandomPointUnderWater(uint32 phaseMask, float& x, float& y, float& z, float radius, GridMapLiquidData& liquid_status); private: void LoadMapAndVMap(int gx, int gy); diff --git a/src/game/WorldHandlers/MiscHandler.cpp b/src/game/WorldHandlers/MiscHandler.cpp index 1656ce646..f3782a614 100644 --- a/src/game/WorldHandlers/MiscHandler.cpp +++ b/src/game/WorldHandlers/MiscHandler.cpp @@ -1565,7 +1565,7 @@ void WorldSession::HandleRequestHotfix(WorldPacket& recv_data) count = recv_data.ReadBits(23); std::vector guids; - guids.reserve(count); + guids.resize(count); for (uint32 i = 0; i < count; ++i) recv_data.ReadGuidMask<0, 4, 7, 2, 5, 3, 6, 1>(guids[i]); diff --git a/src/game/WorldHandlers/NPCHandler.cpp b/src/game/WorldHandlers/NPCHandler.cpp index 688608031..f18e6c19d 100644 --- a/src/game/WorldHandlers/NPCHandler.cpp +++ b/src/game/WorldHandlers/NPCHandler.cpp @@ -178,12 +178,12 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) } uint32 maxcount = (cSpells ? cSpells->spellList.size() : 0) + (tSpells ? tSpells->spellList.size() : 0); - uint32 trainer_type = cSpells && cSpells->trainerType ? cSpells->trainerType : (tSpells ? tSpells->trainerType : 0); + uint32 TrainerType = cSpells && cSpells->trainerType ? cSpells->trainerType : (tSpells ? tSpells->trainerType : 0); WorldPacket data(SMSG_TRAINER_LIST, 8 + 4 + 4 + maxcount * 38 + strTitle.size() + 1); data << ObjectGuid(guid); - data << uint32(trainer_type); - data << uint32(ci->trainerId); + data << uint32(TrainerType); + data << uint32(ci->TrainerTemplateId); size_t count_pos = data.wpos(); data << uint32(maxcount); @@ -243,9 +243,9 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recv_data) { ObjectGuid guid; - uint32 spellId = 0, trainerId = 0; + uint32 spellId = 0, TrainerTemplateId = 0; - recv_data >> guid >> trainerId >> spellId; + recv_data >> guid >> TrainerTemplateId >> spellId; DEBUG_LOG("WORLD: Received opcode CMSG_TRAINER_BUY_SPELL Trainer: %s, learn spell id is: %u", guid.GetString().c_str(), spellId); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); diff --git a/src/game/WorldHandlers/QueryHandler.cpp b/src/game/WorldHandlers/QueryHandler.cpp index a29b0f78e..e9d2777ce 100644 --- a/src/game/WorldHandlers/QueryHandler.cpp +++ b/src/game/WorldHandlers/QueryHandler.cpp @@ -182,8 +182,8 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recv_data) data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 data << uint32(ci->CreatureTypeFlags); // flags data << uint32(0); // unk - data << uint32(ci->type); // CreatureType.dbc - data << uint32(ci->family); // CreatureFamily.dbc + data << uint32(ci->CreatureType); // CreatureType.dbc + data << uint32(ci->Family); // CreatureFamily.dbc data << uint32(ci->Rank); // Creature Rank (elite, boss, etc) data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit @@ -191,12 +191,12 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recv_data) for (int i = 0; i < MAX_CREATURE_MODEL; ++i) data << uint32(ci->ModelId[i]); - data << float(ci->healthModifier); // health modifier - data << float(ci->powerModifier); // power modifier + data << float(ci->HealthMultiplier); // health modifier + data << float(ci->PowerMultiplier); // power modifier data << uint8(ci->RacialLeader); for (uint32 i = 0; i < 6; ++i) - data << uint32(ci->questItems[i]); // itemId[6], quest drop - data << uint32(ci->movementId); // CreatureMovementInfo.dbc + data << uint32(ci->QuestItems[i]); // itemId[6], quest drop + data << uint32(ci->MovementTemplateId); // CreatureMovementInfo.dbc data << uint32(0); //unk SendPacket(&data); DEBUG_LOG("WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); diff --git a/src/game/WorldHandlers/ScriptMgr.cpp b/src/game/WorldHandlers/ScriptMgr.cpp index b41b72941..f4ccc5a0c 100644 --- a/src/game/WorldHandlers/ScriptMgr.cpp +++ b/src/game/WorldHandlers/ScriptMgr.cpp @@ -1226,7 +1226,7 @@ bool ScriptAction::HandleScriptStep() for (int i = 0; i < MAX_TEXT_ID; ++i) { if (!m_script->textId[i]) - { break; } + break; emotes.push_back(uint32(m_script->textId[i])); } diff --git a/src/game/WorldHandlers/Spell.cpp b/src/game/WorldHandlers/Spell.cpp index 9ec2c7694..ac0428242 100644 --- a/src/game/WorldHandlers/Spell.cpp +++ b/src/game/WorldHandlers/Spell.cpp @@ -3384,7 +3384,7 @@ void Spell::cast(bool skipCheck) // Hand of Reckoning else if (m_spellInfo->Id == 62124) { - if (m_targets.getUnitTarget() && m_targets.getUnitTarget()->getVictim() != m_caster) + if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetTargetGuid() != m_caster->GetObjectGuid()) AddPrecastSpell(67485); // Hand of Rekoning (no typos in name ;) ) } // Divine Shield, Divine Protection or Hand of Protection @@ -7972,6 +7972,7 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r case 44869: // Spectral Blast (SWP, Kalecgos) case 45391: // Summon Demonic Vapor (SWP, Felmyst) case 45785: // Sinister Reflection Clone (SWP, Kil'jaeden) + case 45863: // Cosmetic - Incinerate to Random Target (Borean Tundra) case 45892: // Sinister Reflection (SWP, Kil'jaeden) case 45976: // Open Portal (SWP, M'uru) case 46372: // Ice Spear Target Picker (Slave Pens, Ahune) @@ -8000,15 +8001,15 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r case 62797: // Storm Cloud (Ulduar, Hodir) case 63018: // Searing Light (Ulduar, XT-002) case 63024: // Gravity Bomb (Ulduar, XT-002) - case 63387: // Rapid Burst case 63545: // Icicle (Ulduar, Hodir) case 63795: // Psychosis (Ulduar, Yogg-Saron) case 63820: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Scrap Bots, hits npc 33856 case 64218: // Overcharge (VoA, Emalon) case 64234: // Gravity Bomb (h) (Ulduar, XT-002) + case 64402: // Rocket Strike (Ulduar, Mimiron) case 64425: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Assault Bots, hits npc 33856 - case 64531: // Rapid Burst (h) case 64543: // Melt Ice (Ulduar, Hodir) + case 64623: // Frost Bomb (Ulduar, Mimiron) case 65121: // Searing Light (h) (Ulduar, XT-002) case 65301: // Psychosis (Ulduar, Yogg-Saron) case 65872: // Pursuing Spikes (ToCrusader, Anub'arak) diff --git a/src/game/WorldHandlers/SpellAuraDefines.h b/src/game/WorldHandlers/SpellAuraDefines.h index c2518d23c..922575da6 100644 --- a/src/game/WorldHandlers/SpellAuraDefines.h +++ b/src/game/WorldHandlers/SpellAuraDefines.h @@ -448,7 +448,7 @@ enum AuraType SPELL_AURA_297 = 297, SPELL_AURA_298 = 298, SPELL_AURA_299 = 299, - SPELL_AURA_300 = 300, + SPELL_AURA_SHARE_DAMAGE_PCT = 300, SPELL_AURA_HEAL_ABSORB = 301, SPELL_AURA_302 = 302, SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE = 303, diff --git a/src/game/WorldHandlers/SpellAuras.cpp b/src/game/WorldHandlers/SpellAuras.cpp index 8bf9a11fc..dd1170b5d 100644 --- a/src/game/WorldHandlers/SpellAuras.cpp +++ b/src/game/WorldHandlers/SpellAuras.cpp @@ -1457,15 +1457,15 @@ void Aura::TriggerSpell() // move loot to player inventory and despawn target if (caster->GetTypeId() == TYPEID_PLAYER && triggerTarget->GetTypeId() == TYPEID_UNIT && - ((Creature*)triggerTarget)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD) + ((Creature*)triggerTarget)->GetCreatureInfo()->CreatureType == CREATURE_TYPE_GAS_CLOUD) { Player* player = (Player*)caster; Creature* creature = (Creature*)triggerTarget; - // missing lootid has been reported on startup - just return - if (!creature->GetCreatureInfo()->SkinLootId) + // missing Lootid has been reported on startup - just return + if (!creature->GetCreatureInfo()->SkinningLootId) return; - player->AutoStoreLoot(creature, creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true); + player->AutoStoreLoot(creature, creature->GetCreatureInfo()->SkinningLootId, LootTemplates_Skinning, true); creature->ForcedDespawn(); } @@ -2378,9 +2378,14 @@ void Aura::HandleAuraDummy(bool apply, bool Real) case 54729: // Winged Steed of the Ebon Blade Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 54726, 54727, 0); return; - case 58600: // Restricted Flight Area - target->MonsterWhisper(LANG_NO_FLY_ZONE, target, true); + case 58600: // Restricted Flight Area + { + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return; + const char* text = sObjectMgr.GetMangosString(LANG_NO_FLY_ZONE, ((Player*)target)->GetSession()->GetSessionDbLocaleIndex()); + target->MonsterWhisper(text, target, true); return; + } case 61187: // Twilight Shift (single target) case 61190: // Twilight Shift (many targets) target->RemoveAurasDueToSpell(57620); @@ -2936,18 +2941,18 @@ void Aura::HandleAuraDummy(bool apply, bool Real) return; } - case 64398: // Summon Scrap Bot (Ulduar, Mimiron) - for Scrap Bots - case 64426: // Summon Scrap Bot (Ulduar, Mimiron) - for Assault Bots - case 64621: // Summon Fire Bot (Ulduar, Mimiron) + case 62483: // Stonebark's Essence Channel + case 62484: // Ironbranch's Essence Channel + case 62485: // Brightleaf's Essence Channel + case 65587: // Brightleaf's Essence Channel (h) + case 65588: // Ironbranch's Essence Channel (h) + case 65589: // Stonebark's Essence Channel (h) { - uint32 triggerSpell = 0; - switch (GetId()) + if (Unit* caster = GetCaster()) { - case 64398: triggerSpell = 63819; break; - case 64426: triggerSpell = 64427; break; - case 64621: triggerSpell = 64622; break; + if (m_removeMode == AURA_REMOVE_BY_EXPIRE) + caster->CastSpell(caster, 62467, true); } - target->CastSpell(target, triggerSpell, false); return; } case 68839: // Corrupt Soul @@ -4487,15 +4492,15 @@ void Aura::HandleModCharm(bool apply, bool Real) if (caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK) { CreatureInfo const* cinfo = ((Creature*)target)->GetCreatureInfo(); - if (cinfo && cinfo->type == CREATURE_TYPE_DEMON) + if (cinfo && cinfo->CreatureType == CREATURE_TYPE_DEMON) { // creature with pet number expected have class set if (target->GetByteValue(UNIT_FIELD_BYTES_0, 1) == 0) { - if (cinfo->unit_class == 0) - sLog.outErrorDb("Creature (Entry: %u) have unit_class = 0 but used in charmed spell, that will be result client crash.", cinfo->Entry); + if (cinfo->UnitClass == 0) + sLog.outErrorDb("Creature (Entry: %u) have UnitClass = 0 but used in charmed spell, that will be result client crash.", cinfo->Entry); else - sLog.outError("Creature (Entry: %u) have unit_class = %u but at charming have class 0!!! that will be result client crash.", cinfo->Entry, cinfo->unit_class); + sLog.outError("Creature (Entry: %u) have UnitClass = %u but at charming have class 0!!! that will be result client crash.", cinfo->Entry, cinfo->UnitClass); target->SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_MAGE); } @@ -4533,10 +4538,10 @@ void Aura::HandleModCharm(bool apply, bool Real) target->setFaction(cinfo->FactionAlliance); // restore UNIT_FIELD_BYTES_0 - if (cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON) + if (cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->CreatureType == CREATURE_TYPE_DEMON) { // DB must have proper class set in field at loading, not req. restore, including workaround case at apply - // m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class); + // m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->UnitClass); if (target->GetCharmInfo()) { target->GetCharmInfo()->SetPetNumber(0, true); } @@ -4947,13 +4952,8 @@ void Aura::HandleAuraModRoot(bool apply, bool Real) if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST) { target->ModifyAuraState(AURA_STATE_FROZEN, apply); } - target->addUnitState(UNIT_STAT_ROOT); target->SetTargetGuid(ObjectGuid()); - // Save last orientation - if (target->getVictim()) - target->SetOrientation(target->GetAngle(target->getVictim())); - if (target->GetTypeId() == TYPEID_PLAYER) { target->SetRoot(true); @@ -4991,18 +4991,14 @@ void Aura::HandleAuraModRoot(bool apply, bool Real) // Real remove called after current aura remove from lists, check if other similar auras active if (target->HasAuraType(SPELL_AURA_MOD_ROOT)) - { return; } + { + return; + } target->clearUnitState(UNIT_STAT_ROOT); - if (!target->hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect - { - if (target->getVictim() && target->IsAlive()) - target->SetTargetGuid(target->getVictim()->GetObjectGuid()); - - if (target->GetTypeId() == TYPEID_PLAYER) - target->SetRoot(false); - } + if (!target->hasUnitState(UNIT_STAT_STUNNED) && (target->GetTypeId() == TYPEID_PLAYER)) // prevent allow move if have also stun effect + target->SetRoot(false); } } @@ -7027,7 +7023,7 @@ void Aura::HandleAuraEmpathy(bool apply, bool /*Real*/) return; CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(GetTarget()->GetEntry()); - if (ci && ci->type == CREATURE_TYPE_BEAST) + if (ci && ci->CreatureType == CREATURE_TYPE_BEAST) GetTarget()->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply); } @@ -8346,6 +8342,14 @@ void Aura::PeriodicDummyTick() target->CastSpell(target, 63536, true, NULL, this); return; } + case 63382: // Rapid Burst + { + if (GetAuraTicks() % 2) + target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 64019 : 64532, true); + else + target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 63387 : 64531, true); + return; + } case 64217: // Overcharged { if (GetHolder()->GetStackAmount() >= 10) @@ -8826,7 +8830,7 @@ void Aura::HandleAuraMirrorImage(bool apply, bool Real) const CreatureModelInfo* minfo = sObjectMgr.GetCreatureModelInfo(pCreature->GetNativeDisplayId()); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); - pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class); + pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->UnitClass); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, 0); diff --git a/src/game/WorldHandlers/SpellEffects.cpp b/src/game/WorldHandlers/SpellEffects.cpp index 79555ade4..b0dd31e90 100644 --- a/src/game/WorldHandlers/SpellEffects.cpp +++ b/src/game/WorldHandlers/SpellEffects.cpp @@ -1542,6 +1542,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) unitTarget->CastSpell(unitTarget, spell_id, true); return; } + case 41283: // Abyssal Toss + { + if (!unitTarget) + return; + + m_caster->SummonCreature(23416, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + return; + } case 41333: // Empyreal Equivalency { if (!unitTarget) @@ -2738,6 +2746,31 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); return; } + case 62217: // Unstable Energy + case 62922: // Unstable Energy (h) + { + if (!unitTarget) + return; + + unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue()); + return; + } + case 62262: // Brightleaf Flux + { + if (!unitTarget) + return; + + if (unitTarget->HasAura(62239)) + unitTarget->RemoveAurasDueToSpell(62239); + else + { + uint32 stackAmount = urand(1, GetSpellStore()->LookupEntry(62239)->GetStackAmount()); + + for (uint8 i = 0; i < stackAmount; ++i) + unitTarget->CastSpell(unitTarget, 62239, true); + } + return; + } case 62278: // Lightning Orb Charger { if (!unitTarget) @@ -2747,6 +2780,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) unitTarget->CastSpell(unitTarget, 62279, true); return; } + case 62652: // Tidal Wave + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 62653 : 62935, true); + return; + } case 62797: // Storm Cloud { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) @@ -2764,6 +2805,15 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true); return; } + case 63027: // Proximity Mines + { + if (!unitTarget) + return; + + for (uint8 i = 0; i < 15; ++i) + unitTarget->CastSpell(unitTarget, 65347, true); + return; + } case 63499: // Dispel Magic { if (!unitTarget) @@ -2779,6 +2829,22 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true); } + case 63667: // Napalm Shell + { + if (!unitTarget) + return; + + m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 63666 : 65026, true); + return; + } + case 63681: // Rocket Strike + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + m_caster->CastSpell(unitTarget, 63036, true); + return; + } case 63820: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Scrap Bots case 64425: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Assault Bots case 64620: // Summon Fire Bot Trigger (Ulduar - Mimiron) for Fire Bots @@ -2801,6 +2867,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) m_caster->SetFacingTo(frand(0, M_PI_F * 2)); return; } + case 64402: // Rocket Strike + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 63681, true); + return; + } case 64489: // Feral Rush { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) @@ -2818,6 +2892,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) m_caster->CastSpell(m_caster, 64540, true); return; } + case 64623: // Frost Bomb + { + if (!unitTarget) + return; + + m_caster->CastSpell(unitTarget, 64627, true); + return; + } case 64673: // Feral Rush (h) { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) @@ -2826,6 +2908,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) m_caster->CastSpell(unitTarget, 64674, true); return; } + case 64841: // Rapid Burst + { + if (!unitTarget) + return; + + unitTarget->CastSpell(m_caster, 63382, false); + return; + } case 64981: // Summon Random Vanquished Tentacle { uint32 spell_id = 0; @@ -2840,6 +2930,16 @@ void Spell::EffectDummy(SpellEffectEntry const* effect) m_caster->CastSpell(m_caster, spell_id, true); return; } + case 65346: // Proximity Mine + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + m_caster->CastSpell(m_caster, m_caster->GetMap()->IsRegularDifficulty() ? 66351 : 63009, true); + m_caster->RemoveAurasDueToSpell(65345); + m_caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + return; + } case 66390: // Read Last Rites { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER) @@ -5279,7 +5379,7 @@ void Spell::EffectSummonType(SpellEffectEntry const* effect) return; // FIXME: not all totems and similar cases selected by this check... - if (cInfo->type == CREATURE_TYPE_TOTEM) + if (cInfo->CreatureType == CREATURE_TYPE_TOTEM) summonResult = DoSummonTotem(effect); else summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level); @@ -5468,7 +5568,7 @@ bool Spell::DoSummonCritter(CreatureSummonPositions& list, SummonPropertiesEntry critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter... // critter->InitLevelupSpellsForLevel(); // none? critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp - critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->npcflag); + critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->NpcFlags); // some mini-pets have quests // set timer for unsummon if (m_duration > 0) @@ -5538,7 +5638,7 @@ bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntr // spawnCreature->SetName(""); // generated by client spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid()); spawnCreature->SetPowerType(POWER_MANA); - spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->npcflag); + spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, spawnCreature->GetCreatureInfo()->NpcFlags); spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid()); @@ -7597,6 +7697,23 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect) unitTarget->CastSpell(unitTarget, triggeredSpell[urand(0, 3)], true); return; } + case 44323: // Hawk Hunting + case 44407: // Hawk Hunting + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + // check target entry specific to each spell + if (m_spellInfo->Id == 44323 && unitTarget->GetEntry() != 24746) + return; + if (m_spellInfo->Id == 44407 && unitTarget->GetEntry() != 24747) + return; + + unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true); + // despawn delay depends on the distance between caster and target + ((Creature*)unitTarget)->ForcedDespawn(100 * unitTarget->GetDistance2d(m_caster)); + return; + } case 44364: // Rock Falcon Primer { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) @@ -7771,6 +7888,14 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect) unitTarget->CastSpell(unitTarget, 45259, true); return; } + case 45625: // Arcane Chains: Character Force Cast + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true); + return; + } case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) @@ -7855,7 +7980,7 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect) } else { - m_caster->SetUInt32Value(UNIT_NPC_FLAGS, cTemplate->npcflag); + m_caster->SetUInt32Value(UNIT_NPC_FLAGS, cTemplate->NpcFlags); ((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0); ((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0); @@ -8643,6 +8768,28 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect) unitTarget->CastSpell(m_caster, 64909, true); return; } + case 62282: // Iron Roots + case 62440: // Strengthened Iron Roots + case 63598: // Iron Roots (h) + case 63601: // Strengthened Iron Roots (h) + { + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !((Creature*)unitTarget)->IsTemporarySummon()) + return; + + uint32 ownerAura = 0; + + switch (m_spellInfo->Id) + { + case 62282: ownerAura = 62283; break; + case 62440: ownerAura = 62438; break; + case 63598: ownerAura = 62930; break; + case 63601: ownerAura = 62861; break; + }; + + if (Unit* summoner = unitTarget->GetMap()->GetUnit(((TemporarySummon*)unitTarget)->GetSummonerGuid())) + summoner->RemoveAurasDueToSpell(ownerAura); + return; + } case 62381: // Chill { if (!unitTarget) @@ -8685,18 +8832,6 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect) unitTarget->RemoveAuraHolderFromStack(spellId, numStacks); return; } - case 62678: // Summon Allies of Nature - { - const uint32 randSpells[] = - { - 62685, // Summon Wave - 1 Mob - 62686, // Summon Wave - 3 Mob - 62688, // Summon Wave - 10 Mob - }; - - m_caster->CastSpell(m_caster, randSpells[urand(0, countof(randSpells) - 1)], true); - return; - } case 62688: // Summon Wave - 10 Mob { uint32 spellId = effect->CalculateSimpleValue(); diff --git a/src/game/WorldHandlers/UnitAuraProcHandler.cpp b/src/game/WorldHandlers/UnitAuraProcHandler.cpp index c545b689e..074b2dcba 100644 --- a/src/game/WorldHandlers/UnitAuraProcHandler.cpp +++ b/src/game/WorldHandlers/UnitAuraProcHandler.cpp @@ -1214,6 +1214,13 @@ SpellAuraProcResult Unit::HandleDummyAuraProc(Unit* pVictim, uint32 damage, Aura basepoints[0] = damage * 15 / 100; break; } + // Fingers of Frost + case 74396: + { + // Remove only single aura from stack and remove holder if its last stack + RemoveAuraHolderFromStack(74396); + return SPELL_AURA_PROC_OK; + } } break; } @@ -3111,6 +3118,12 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d (((Creature*)pVictim)->GetCreatureInfo()->MechanicImmuneMask & (1 << (MECHANIC_STUN - 1))) == 0) return SPELL_AURA_PROC_FAILED; } + else if (auraSpellInfo->SpellIconID == 2947) // Fingers of Frost + { + // proc chance for spells in basepoints + if (!roll_chance_i(triggerAmount)) + return SPELL_AURA_PROC_FAILED; + } break; } case SPELLFAMILY_WARRIOR: diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 089207871..907c971e0 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -779,6 +779,7 @@ void World::LoadConfigSettings(bool reload) setConfigMinMax(CONFIG_FLOAT_GHOST_RUN_SPEED_BG, "Death.Ghost.RunSpeed.Battleground", 1.0f, 0.1f, 10.0f); setConfig(CONFIG_FLOAT_THREAT_RADIUS, "ThreatRadius", 100.0f); + setConfigMin(CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY, "CreatureRespawnAggroDelay", 5000, 0); // always use declined names in the russian client if (getConfig(CONFIG_UINT32_REALM_ZONE) == REALM_ZONE_RUSSIAN) @@ -812,7 +813,7 @@ void World::LoadConfigSettings(bool reload) setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "Network.KickOnBadPacket", false); - setConfig(CONFIG_BOOL_PLAYER_COMMANDS, "PlayerCommands", false); + setConfig(CONFIG_BOOL_PLAYER_COMMANDS, "PlayerCommands", true); if (int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0)) { @@ -1782,19 +1783,7 @@ namespace MaNGOS while (char* line = lineFromMessage(pos)) { WorldPacket* data = new WorldPacket(); - - uint32 lineLength = (line ? strlen(line) : 0) + 1; - - data->Initialize(SMSG_MESSAGECHAT, 100);// guess size - *data << uint8(CHAT_MSG_SYSTEM); - *data << uint32(LANG_UNIVERSAL); - *data << uint64(0); - *data << uint32(0); // can be chat msg group or something - *data << uint64(0); - *data << uint32(lineLength); - *data << line; - *data << uint8(0); - + ChatHandler::BuildChatPacket(*data, CHAT_MSG_SYSTEM, line); data_list.push_back(data); } } diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index ecc1e74b3..3b3919626 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -217,6 +217,7 @@ enum eConfigUInt32Values CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE, CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT, CONFIG_UINT32_MIN_LEVEL_FOR_RAID, + CONFIG_UINT32_CREATURE_RESPAWN_AGGRO_DELAY, CONFIG_UINT32_RANDOM_BG_RESET_HOUR, // Warden CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY, diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index 615b6ab76..4b578e113 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -785,6 +785,11 @@ SD2ErrorLogFile = "scriptdev2-errors.log" # You can bypass this setting by typing "/script SetAllowLowLevelRaid(true/false)" command in chat # Default: 10 # +# PlayerCommands +# Should player chat be parsed for GM commands. +# Default: 1 (parse commands) +# 0 (ignore commands) +# ################################################################################ GameType = 1 @@ -856,6 +861,7 @@ WaitAtStartupError = 10 PlayerCommands = 0 Motd = "Welcome to Mangos Three." Raid.MinLevel = 10 +PlayerCommands = 1 ################################################################################ # PLAYER INTERACTION @@ -1008,6 +1014,7 @@ TalentsInspecting = 1 ThreatRadius = 100 Rate.Creature.Aggro = 1 +CreatureRespawnAggroDelay = 5000 CreatureFamilyFleeAssistanceRadius = 30 CreatureFamilyAssistanceRadius = 10 CreatureFamilyAssistanceDelay = 1500 diff --git a/src/modules/SD3/base/escort_ai.cpp b/src/modules/SD3/base/escort_ai.cpp index b4a069951..f64ac70da 100644 --- a/src/modules/SD3/base/escort_ai.cpp +++ b/src/modules/SD3/base/escort_ai.cpp @@ -144,7 +144,7 @@ bool npc_escortAI::AssistPlayerInCombat(Unit* pWho) return false; } - // unit state prevents (similar check is done in CanInitiateAttack which also include checking unit_flags. We skip those here) + // unit state prevents (similar check is done in CanInitiateAttack which also include checking UnitFlags. We skip those here) if (m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED)) { return false; @@ -629,7 +629,7 @@ void npc_escortAI::Start(bool bRun, const Player* pPlayer, const Quest* pQuest, debug_log("SD3: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle."); } - // disable npcflags + // disable NpcFlagss m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); debug_log("SD3: EscortAI started with " SIZEFMTD " waypoints. Run = %d, PlayerGuid = %s", WaypointList.size(), m_bIsRunning, m_playerGuid.GetString().c_str()); diff --git a/src/modules/SD3/base/follower_ai.cpp b/src/modules/SD3/base/follower_ai.cpp index 0dc514726..00aa14aea 100644 --- a/src/modules/SD3/base/follower_ai.cpp +++ b/src/modules/SD3/base/follower_ai.cpp @@ -82,7 +82,7 @@ bool FollowerAI::AssistPlayerInCombat(Unit* pWho) return false; } - // unit state prevents (similar check is done in CanInitiateAttack which also include checking unit_flags. We skip those here) + // unit state prevents (similar check is done in CanInitiateAttack which also include checking UnitFlags. We skip those here) if (m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED)) { return false; diff --git a/src/modules/SD3/scripts/kalimdor/felwood.cpp b/src/modules/SD3/scripts/kalimdor/felwood.cpp index ab2fd368d..3d7afe03e 100644 --- a/src/modules/SD3/scripts/kalimdor/felwood.cpp +++ b/src/modules/SD3/scripts/kalimdor/felwood.cpp @@ -92,7 +92,7 @@ struct npc_kitten : public CreatureScript void MoveInLineOfSight(Unit* pWho) override { - // should not have npcflag by default, so set when expected + // should not have NpcFlags by default, so set when expected if (!m_creature->getVictim() && !m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && HasFollowState(STATE_FOLLOW_INPROGRESS) && pWho->GetEntry() == NPC_WINNA) { if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) diff --git a/src/modules/SD3/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp b/src/modules/SD3/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp index d619816e9..74358588c 100644 --- a/src/modules/SD3/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp +++ b/src/modules/SD3/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp @@ -86,7 +86,7 @@ struct boss_moam : public CreatureScript m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana); #endif #if defined (CATA) - m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->maxmana);// TODO MaxLevelHealth); + m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana);// TODO MaxLevelHealth); #endif } diff --git a/src/modules/SD3/scripts/outland/nagrand.cpp b/src/modules/SD3/scripts/outland/nagrand.cpp index c81f85c74..4c3c77a22 100644 --- a/src/modules/SD3/scripts/outland/nagrand.cpp +++ b/src/modules/SD3/scripts/outland/nagrand.cpp @@ -102,7 +102,7 @@ struct mob_lump : public CreatureScript m_creature->DeleteThreatList(); m_creature->CombatStop(true); - // should get unit_flags UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE at faction change, but unclear why/for what reason, skipped (no flags expected as default) + // should get UnitFlags UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE at faction change, but unclear why/for what reason, skipped (no flags expected as default) m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME); m_creature->SetStandState(UNIT_STAND_STATE_SIT); diff --git a/src/modules/SD3/scripts/world/npcs_special.cpp b/src/modules/SD3/scripts/world/npcs_special.cpp index fe9ebcd9e..55d35c8a1 100644 --- a/src/modules/SD3/scripts/world/npcs_special.cpp +++ b/src/modules/SD3/scripts/world/npcs_special.cpp @@ -1213,9 +1213,9 @@ struct npc_guardian : public CreatureScript # npc_innkeeper #########*/ -// Script applied to all innkeepers by npcflag. +// Script applied to all innkeepers by NpcFlags. // Are there any known innkeepers that does not hape the options in the below? -// (remember gossipHello is not called unless npcflag|1 is present) +// (remember gossipHello is not called unless NpcFlags|1 is present) enum { diff --git a/src/shared/Utilities/ProgressBar.cpp b/src/shared/Utilities/ProgressBar.cpp index d11c6a1f9..95e115474 100644 --- a/src/shared/Utilities/ProgressBar.cpp +++ b/src/shared/Utilities/ProgressBar.cpp @@ -41,18 +41,6 @@ BarGoLink::BarGoLink(int row_count) init(row_count); } -BarGoLink::BarGoLink(uint32 row_count) -{ - MANGOS_ASSERT(row_count < (uint32)ACE_INT32_MAX); - init((int)row_count); -} - -BarGoLink::BarGoLink(uint64 row_count) -{ - MANGOS_ASSERT(row_count < (uint64)ACE_INT32_MAX); - init((int)row_count); -} - BarGoLink::~BarGoLink() { if (!m_showOutput) diff --git a/src/shared/Utilities/ProgressBar.h b/src/shared/Utilities/ProgressBar.h index e9249c3b0..55713ebfc 100644 --- a/src/shared/Utilities/ProgressBar.h +++ b/src/shared/Utilities/ProgressBar.h @@ -40,8 +40,6 @@ class BarGoLink * @param row_count */ explicit BarGoLink(int row_count); - explicit BarGoLink(uint32 row_count); // row_count < ACE_INT32_MAX - explicit BarGoLink(uint64 row_count); // row_count < ACE_INT64_MAX /** * @brief *