diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 53 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 37 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 43 |
3 files changed, 124 insertions, 9 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 16f9b43a8c1..251d47de473 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -2868,6 +2868,16 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); break; } + case SMART_EVENT_TARGET_HEALTH_PCT: + { + if (!me || !me->IsEngaged() || !me->GetVictim() || !me->EnsureVictim()->GetMaxHealth()) + return; + uint32 perc = (uint32)me->EnsureVictim()->GetHealthPct(); + if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) + return; + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->GetVictim()); + break; + } case SMART_EVENT_MANA_PCT: { if (!me || !me->IsEngaged() || !me->GetMaxPower(POWER_MANA)) @@ -2917,6 +2927,22 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessTimedAction(e, e.event.targetCasting.repeatMin, e.event.targetCasting.repeatMax, me->GetVictim()); break; } + case SMART_EVENT_FRIENDLY_HEALTH: + { + if (!me || !me->IsEngaged()) + return; + + Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealth.radius, e.event.friendlyHealth.hpDeficit); + if (!target || !target->IsInCombat()) + { + // if there are at least two same npcs, they will perform the same action immediately even if this is useless... + RecalcTimer(e, 1000, 3000); + return; + } + + ProcessTimedAction(e, e.event.friendlyHealth.repeatMin, e.event.friendlyHealth.repeatMax, target); + break; + } case SMART_EVENT_FRIENDLY_IS_CC: { if (!me || !me->IsEngaged()) @@ -2973,7 +2999,6 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui case SMART_EVENT_AGGRO: case SMART_EVENT_DEATH: case SMART_EVENT_EVADE: - case SMART_EVENT_RESPAWN: case SMART_EVENT_REACHED_HOME: case SMART_EVENT_CHARMED_TARGET: case SMART_EVENT_CORPSE_REMOVED: @@ -3015,6 +3040,18 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessAction(e, unit, var0, var1, bvar, spell, gob); break; + case SMART_EVENT_IS_BEHIND_TARGET: + { + if (!me) + return; + + if (Unit* victim = me->GetVictim()) + { + if (!victim->HasInArc(static_cast<float>(M_PI), me)) + ProcessTimedAction(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax, victim); + } + break; + } case SMART_EVENT_RECEIVE_EMOTE: if (e.event.emote.emote == var0) { @@ -3095,6 +3132,17 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui } break; } + case SMART_EVENT_RESPAWN: + { + if (!GetBaseObject()) + return; + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && GetBaseObject()->GetMapId() != e.event.respawn.map) + return; + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && GetBaseObject()->GetZoneId() != e.event.respawn.area) + return; + ProcessAction(e); + break; + } case SMART_EVENT_SUMMONED_UNIT: case SMART_EVENT_SUMMONED_UNIT_DIES: { @@ -3447,14 +3495,17 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) case SMART_EVENT_UPDATE_OOC: case SMART_EVENT_UPDATE_IC: case SMART_EVENT_HEALTH_PCT: + case SMART_EVENT_TARGET_HEALTH_PCT: case SMART_EVENT_MANA_PCT: case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: case SMART_EVENT_VICTIM_CASTING: + case SMART_EVENT_FRIENDLY_HEALTH: case SMART_EVENT_FRIENDLY_IS_CC: case SMART_EVENT_FRIENDLY_MISSING_BUFF: case SMART_EVENT_HAS_AURA: case SMART_EVENT_TARGET_BUFFED: + case SMART_EVENT_IS_BEHIND_TARGET: case SMART_EVENT_FRIENDLY_HEALTH_PCT: case SMART_EVENT_DISTANCE_CREATURE: case SMART_EVENT_DISTANCE_GAMEOBJECT: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index a766c4c26da..d00d483e8bf 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -311,9 +311,11 @@ void SmartAIMgr::LoadSmartAIFromDB() case SMART_EVENT_UPDATE_OOC: case SMART_EVENT_UPDATE_IC: case SMART_EVENT_HEALTH_PCT: + case SMART_EVENT_TARGET_HEALTH_PCT: case SMART_EVENT_MANA_PCT: case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: + case SMART_EVENT_FRIENDLY_HEALTH: case SMART_EVENT_FRIENDLY_HEALTH_PCT: case SMART_EVENT_FRIENDLY_MISSING_BUFF: case SMART_EVENT_HAS_AURA: @@ -326,6 +328,7 @@ void SmartAIMgr::LoadSmartAIFromDB() } break; case SMART_EVENT_VICTIM_CASTING: + case SMART_EVENT_IS_BEHIND_TARGET: if (temp.event.minMaxRepeat.min == 0 && temp.event.minMaxRepeat.max == 0 && !(temp.event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE) && temp.source_type != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST) { temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE; @@ -457,14 +460,17 @@ SmartScriptHolder& SmartAIMgr::FindLinkedEvent(SmartAIEventList& list, uint32 li case SMART_EVENT_IC_LOS: case SMART_EVENT_OOC_LOS: case SMART_EVENT_DISTANCE_CREATURE: + case SMART_EVENT_FRIENDLY_HEALTH: case SMART_EVENT_FRIENDLY_HEALTH_PCT: case SMART_EVENT_FRIENDLY_IS_CC: case SMART_EVENT_FRIENDLY_MISSING_BUFF: case SMART_EVENT_ACTION_DONE: + case SMART_EVENT_TARGET_HEALTH_PCT: case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: case SMART_EVENT_VICTIM_CASTING: case SMART_EVENT_TARGET_BUFFED: + case SMART_EVENT_IS_BEHIND_TARGET: case SMART_EVENT_INSTANCE_PLAYER_ENTER: case SMART_EVENT_TRANSPORT_ADDCREATURE: case SMART_EVENT_DATA_SET: @@ -706,8 +712,10 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e) case SMART_EVENT_SPELLHIT: return sizeof(SmartEvent::spellHit); case SMART_EVENT_RANGE: return sizeof(SmartEvent::minMaxRepeat); case SMART_EVENT_OOC_LOS: return sizeof(SmartEvent::los); - case SMART_EVENT_RESPAWN: return NO_PARAMS; + case SMART_EVENT_RESPAWN: return sizeof(SmartEvent::respawn); + case SMART_EVENT_TARGET_HEALTH_PCT: return sizeof(SmartEvent::minMaxRepeat); case SMART_EVENT_VICTIM_CASTING: return sizeof(SmartEvent::targetCasting); + case SMART_EVENT_FRIENDLY_HEALTH: return sizeof(SmartEvent::friendlyHealth); case SMART_EVENT_FRIENDLY_IS_CC: return sizeof(SmartEvent::friendlyCC); case SMART_EVENT_FRIENDLY_MISSING_BUFF: return sizeof(SmartEvent::missingBuff); case SMART_EVENT_SUMMONED_UNIT: return sizeof(SmartEvent::summoned); @@ -760,6 +768,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e) case SMART_EVENT_GOSSIP_HELLO: return sizeof(SmartEvent::gossipHello); case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS; case SMART_EVENT_EVENT_PHASE_CHANGE: return sizeof(SmartEvent::eventPhaseChange); + case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget); case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent); case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent); case SMART_EVENT_GO_LOOT_STATE_CHANGED: return sizeof(SmartEvent::goLootStateChanged); @@ -1094,6 +1103,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_EVENT_UPDATE_OOC: case SMART_EVENT_HEALTH_PCT: case SMART_EVENT_MANA_PCT: + case SMART_EVENT_TARGET_HEALTH_PCT: case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: case SMART_EVENT_DAMAGED: @@ -1137,6 +1147,25 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) TC_SAI_IS_BOOLEAN_VALID(e, e.event.los.playerOnly); break; + case SMART_EVENT_RESPAWN: + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map); + return false; + } + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area); + return false; + } + break; + case SMART_EVENT_FRIENDLY_HEALTH: + if (!NotNULL(e, e.event.friendlyHealth.radius)) + return false; + + if (!IsMinMaxValid(e, e.event.friendlyHealth.repeatMin, e.event.friendlyHealth.repeatMax)) + return false; + break; case SMART_EVENT_FRIENDLY_IS_CC: if (!IsMinMaxValid(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax)) return false; @@ -1265,6 +1294,12 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } break; } + case SMART_EVENT_IS_BEHIND_TARGET: + { + if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax)) + return false; + break; + } case SMART_EVENT_GAME_EVENT_START: case SMART_EVENT_GAME_EVENT_END: { diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 1fced264437..6e60dff91fb 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -109,10 +109,10 @@ enum SMART_EVENT SMART_EVENT_SPELLHIT = 8, // SpellID, School, CooldownMin, CooldownMax SMART_EVENT_RANGE = 9, // MinDist, MaxDist, RepeatMin, RepeatMax SMART_EVENT_OOC_LOS = 10, // HostilityMode, MaxRnage, CooldownMin, CooldownMax - SMART_EVENT_RESPAWN = 11, // NONE - SMART_EVENT_UNUSED_12 = 12, // do not reuse + SMART_EVENT_RESPAWN = 11, // type, MapId, ZoneId + SMART_EVENT_TARGET_HEALTH_PCT = 12, // HPMin%, HPMax%, RepeatMin, RepeatMax SMART_EVENT_VICTIM_CASTING = 13, // RepeatMin, RepeatMax, spellid - SMART_EVENT_UNUSED_14 = 14, // do not reuse + SMART_EVENT_FRIENDLY_HEALTH = 14, // HPDeficit, Radius, RepeatMin, RepeatMax SMART_EVENT_FRIENDLY_IS_CC = 15, // Radius, RepeatMin, RepeatMax SMART_EVENT_FRIENDLY_MISSING_BUFF = 16, // SpellId, Radius, RepeatMin, RepeatMax SMART_EVENT_SUMMONED_UNIT = 17, // CreatureId(0 all), CooldownMin, CooldownMax @@ -165,7 +165,7 @@ enum SMART_EVENT SMART_EVENT_GOSSIP_HELLO = 64, // noReportUse (for GOs) SMART_EVENT_FOLLOW_COMPLETED = 65, // none SMART_EVENT_EVENT_PHASE_CHANGE = 66, // event phase mask (<= SMART_EVENT_PHASE_ALL) - SMART_EVENT_UNUSED_67 = 67, // do not reuse + SMART_EVENT_IS_BEHIND_TARGET = 67, // cooldownMin, CooldownMax SMART_EVENT_GAME_EVENT_START = 68, // game_event.Entry SMART_EVENT_GAME_EVENT_END = 69, // game_event.Entry SMART_EVENT_GO_LOOT_STATE_CHANGED = 70, // go LootState @@ -231,6 +231,13 @@ struct SmartEvent struct { + uint32 type; + uint32 map; + uint32 area; + } respawn; + + struct + { uint32 repeatMin; uint32 repeatMax; } minMax; @@ -244,6 +251,14 @@ struct SmartEvent struct { + uint32 hpDeficit; + uint32 radius; + uint32 repeatMin; + uint32 repeatMax; + } friendlyHealth; + + struct + { uint32 radius; uint32 repeatMin; uint32 repeatMax; @@ -362,6 +377,12 @@ struct SmartEvent struct { + uint32 cooldownMin; + uint32 cooldownMax; + } behindTarget; + + struct + { uint32 gameEventId; } gameEvent; @@ -424,6 +445,14 @@ struct SmartEvent }; }; +enum SMART_SCRIPT_RESPAWN_CONDITION +{ + SMART_SCRIPT_RESPAWN_CONDITION_NONE = 0, + SMART_SCRIPT_RESPAWN_CONDITION_MAP = 1, + SMART_SCRIPT_RESPAWN_CONDITION_AREA = 2, + SMART_SCRIPT_RESPAWN_CONDITION_END = 3 +}; + enum SMART_ACTION { SMART_ACTION_NONE = 0, // No action @@ -1432,9 +1461,9 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_RANGE, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_OOC_LOS, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_RESPAWN, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, - {SMART_EVENT_UNUSED_12, 0 }, + {SMART_EVENT_TARGET_HEALTH_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_VICTIM_CASTING, SMART_SCRIPT_TYPE_MASK_CREATURE }, - {SMART_EVENT_UNUSED_14, 0 }, + {SMART_EVENT_FRIENDLY_HEALTH, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_FRIENDLY_IS_CC, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_FRIENDLY_MISSING_BUFF, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_SUMMONED_UNIT, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, @@ -1487,7 +1516,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_GOSSIP_HELLO, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, {SMART_EVENT_FOLLOW_COMPLETED, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_EVENT_PHASE_CHANGE, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, - {SMART_EVENT_UNUSED_67, 0 }, + {SMART_EVENT_IS_BEHIND_TARGET, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_GAME_EVENT_START, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, {SMART_EVENT_GAME_EVENT_END, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, {SMART_EVENT_GO_LOOT_STATE_CHANGED, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, |