mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-17 19:05:42 +00:00
feat(Core/SAI): new Actions + Polar Coords System Offset Relocating (#2880)
This commit is contained in:
@@ -1822,6 +1822,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (!me)
|
||||
break;
|
||||
|
||||
if (e.action.orientation.random > 0)
|
||||
{
|
||||
float randomOri = frand(0.0f, 2 * M_PI);
|
||||
me->SetFacingTo(randomOri);
|
||||
if (e.action.orientation.quickChange)
|
||||
me->SetOrientation(randomOri);
|
||||
break;
|
||||
}
|
||||
|
||||
if (e.GetTargetType() == SMART_TARGET_SELF)
|
||||
{
|
||||
me->SetFacingTo((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation());
|
||||
@@ -3031,6 +3040,178 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
me->FindMap()->LoadGrid(e.target.x, e.target.y);
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_PLAYER_TALK:
|
||||
{
|
||||
ObjectList* targets = GetTargets(e, unit);
|
||||
char const* text = sObjectMgr->GetAcoreString(e.action.playerTalk.textId, DEFAULT_LOCALE);
|
||||
|
||||
if (targets)
|
||||
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
|
||||
if (IsPlayer(*itr))
|
||||
!e.action.playerTalk.flag ? (*itr)->ToPlayer()->Say(text, LANG_UNIVERSAL) : (*itr)->ToPlayer()->Yell(text, LANG_UNIVERSAL);
|
||||
|
||||
delete targets;
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_CUSTOM_CAST:
|
||||
{
|
||||
if (!me)
|
||||
break;
|
||||
|
||||
ObjectList* targets = GetTargets(e, unit);
|
||||
if (!targets)
|
||||
break;
|
||||
|
||||
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
|
||||
{
|
||||
if (IsUnit(*itr))
|
||||
{
|
||||
if (e.action.castCustom.flags & SMARTCAST_INTERRUPT_PREVIOUS)
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
if (e.action.castCustom.flags & SMARTCAST_COMBAT_MOVE)
|
||||
{
|
||||
// If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed
|
||||
// unless target is outside spell range, out of mana, or LOS.
|
||||
|
||||
bool _allowMove = false;
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.castCustom.spell);
|
||||
int32 mana = me->GetPower(POWER_MANA);
|
||||
|
||||
if (me->GetDistance((*itr)->ToUnit()) > spellInfo->GetMaxRange(true) ||
|
||||
me->GetDistance((*itr)->ToUnit()) < spellInfo->GetMinRange(true) ||
|
||||
!me->IsWithinLOSInMap((*itr)->ToUnit()) ||
|
||||
mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()))
|
||||
_allowMove = true;
|
||||
|
||||
CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove);
|
||||
}
|
||||
|
||||
if (!(e.action.castCustom.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.castCustom.spell))
|
||||
{
|
||||
CustomSpellValues values;
|
||||
if (e.action.castCustom.bp1)
|
||||
values.AddSpellMod(SPELLVALUE_BASE_POINT0, e.action.castCustom.bp1);
|
||||
if (e.action.castCustom.bp2)
|
||||
values.AddSpellMod(SPELLVALUE_BASE_POINT1, e.action.castCustom.bp2);
|
||||
if (e.action.castCustom.bp3)
|
||||
values.AddSpellMod(SPELLVALUE_BASE_POINT2, e.action.castCustom.bp3);
|
||||
me->CastCustomSpell(e.action.castCustom.spell, values, (*itr)->ToUnit(), (e.action.castCustom.flags & SMARTCAST_TRIGGERED) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete targets;
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_VORTEX_SUMMON:
|
||||
{
|
||||
if (!me)
|
||||
break;
|
||||
|
||||
ObjectList* targets = GetTargets(e, unit);
|
||||
if (!targets)
|
||||
break;
|
||||
|
||||
TempSummonType summon_type = (e.action.summonVortex.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN;
|
||||
|
||||
float a = static_cast<float>(e.action.summonVortex.a);
|
||||
float k = static_cast<float>(e.action.summonVortex.k) / 1000.0f;
|
||||
float r_max = static_cast<float>(e.action.summonVortex.r_max);
|
||||
float delta_phi = M_PI * static_cast<float>(e.action.summonVortex.phi_delta) / 180.0f;
|
||||
|
||||
// r(phi) = a * e ^ (k * phi)
|
||||
// r(phi + delta_phi) = a * e ^ (k * (phi + delta_phi))
|
||||
// r(phi + delta_phi) = a * e ^ (k * phi) * e ^ (k * delta_phi)
|
||||
// r(phi + delta_phi) = r(phi) * e ^ (k * delta_phi)
|
||||
float factor = std::exp(k * delta_phi);
|
||||
|
||||
// r(0) = a * e ^ (k * 0) = a * e ^ 0 = a * 1 = a
|
||||
float summonRadius = a;
|
||||
|
||||
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
|
||||
{
|
||||
// Offset by orientation, should not count into radius calculation,
|
||||
// but is needed for vortex direction (polar coordinates)
|
||||
float phi = (*itr)->GetOrientation();
|
||||
|
||||
do
|
||||
{
|
||||
Position summonPosition(**itr);
|
||||
summonPosition.RelocatePolarOffset(phi, summonRadius);
|
||||
|
||||
me->SummonCreature(e.action.summonVortex.summonEntry, summonPosition, summon_type, e.action.summonVortex.summonDuration);
|
||||
|
||||
phi += delta_phi;
|
||||
summonRadius *= factor;
|
||||
} while (summonRadius <= r_max);
|
||||
}
|
||||
|
||||
delete targets;
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_CONE_SUMMON:
|
||||
{
|
||||
if (!me)
|
||||
break;
|
||||
|
||||
TempSummonType spawnType = (e.action.coneSummon.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN;
|
||||
|
||||
float distInARow = static_cast<float>(e.action.coneSummon.distanceBetweenSummons);
|
||||
float coneAngle = static_cast<float>(e.action.coneSummon.coneAngle) * M_PI / 180.0f;
|
||||
|
||||
for (uint32 radius = 0; radius <= e.action.coneSummon.coneLength; radius += e.action.coneSummon.distanceBetweenRings)
|
||||
{
|
||||
float deltaAngle = 0.0f;
|
||||
if (radius > 0)
|
||||
deltaAngle = distInARow / radius;
|
||||
|
||||
uint32 count = 1;
|
||||
if (deltaAngle > 0)
|
||||
count += coneAngle / deltaAngle;
|
||||
|
||||
float currentAngle = -static_cast<float>(count) * deltaAngle / 2.0f;
|
||||
|
||||
if (e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_NONE)
|
||||
currentAngle += G3D::fuzzyGt(e.target.o, 0.0f) ? (e.target.o - me->GetOrientation()) : 0.0f;
|
||||
else if (ObjectList* targets = GetTargets(e, unit))
|
||||
{
|
||||
currentAngle += (me->GetAngle(targets->front()) - me->GetOrientation());
|
||||
delete targets;
|
||||
}
|
||||
|
||||
for (uint32 index = 0; index < count; ++index)
|
||||
{
|
||||
Position spawnPosition(*me);
|
||||
spawnPosition.RelocatePolarOffset(currentAngle, radius);
|
||||
currentAngle += deltaAngle;
|
||||
|
||||
me->SummonCreature(e.action.coneSummon.summonEntry, spawnPosition, spawnType, e.action.coneSummon.summonDuration);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_CU_ENCOUNTER_START:
|
||||
{
|
||||
ObjectList* targets = GetTargets(e, unit);
|
||||
if (!targets)
|
||||
break;
|
||||
|
||||
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
|
||||
{
|
||||
if (Player* playerTarget = (*itr)->ToPlayer())
|
||||
{
|
||||
playerTarget->RemoveArenaSpellCooldowns();
|
||||
playerTarget->RemoveAurasDueToSpell(57724); // Spell Shaman Debuff - Sated (Heroism)
|
||||
playerTarget->RemoveAurasDueToSpell(57723); // Spell Shaman Debuff - Exhaustion (Bloodlust)
|
||||
playerTarget->RemoveAurasDueToSpell(2825); // Bloodlust
|
||||
playerTarget->RemoveAurasDueToSpell(32182); // Heroism
|
||||
}
|
||||
}
|
||||
|
||||
delete targets;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sLog->outErrorDb("SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
@@ -4310,7 +4491,7 @@ void SmartScript::OnUpdate(uint32 const diff)
|
||||
void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTrigger const* at)
|
||||
{
|
||||
(void)at; // ensure that the variable is referenced even if extra logs are disabled in order to pass compiler checks
|
||||
|
||||
|
||||
if (e.empty())
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
|
||||
@@ -870,6 +870,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsSpellValid(e, e.action.crossCast.spell))
|
||||
return false;
|
||||
break;
|
||||
case SMART_ACTION_CUSTOM_CAST:
|
||||
if (!IsSpellValid(e, e.action.castCustom.spell))
|
||||
return false;
|
||||
break;
|
||||
case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS:
|
||||
case SMART_ACTION_CALL_GROUPEVENTHAPPENS:
|
||||
if (Quest const* qid = sObjectMgr->GetQuestTemplate(e.action.quest.quest))
|
||||
@@ -1208,6 +1212,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_STOP_MOTION:
|
||||
case SMART_ACTION_NO_ENVIRONMENT_UPDATE:
|
||||
case SMART_ACTION_ZONE_UNDER_ATTACK:
|
||||
case SMART_ACTION_CONE_SUMMON:
|
||||
case SMART_ACTION_VORTEX_SUMMON:
|
||||
case SMART_ACTION_PLAYER_TALK:
|
||||
case SMART_ACTION_CU_ENCOUNTER_START:
|
||||
break;
|
||||
default:
|
||||
sLog->outErrorDb("SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -457,7 +457,7 @@ enum SMART_ACTION
|
||||
SMART_ACTION_EVADE = 24, // No Params
|
||||
SMART_ACTION_FLEE_FOR_ASSIST = 25, // With Emote
|
||||
SMART_ACTION_CALL_GROUPEVENTHAPPENS = 26, // QuestID
|
||||
SMART_ACTION_COMBAT_STOP = 27, //
|
||||
SMART_ACTION_COMBAT_STOP = 27, //
|
||||
SMART_ACTION_REMOVEAURASFROMSPELL = 28, // Spellid (0 removes all auras), charges (0 removes aura)
|
||||
SMART_ACTION_FOLLOW = 29, // Distance (0 = default), Angle (0 = default), EndCreatureEntry, credit, creditType (0monsterkill, 1event)
|
||||
SMART_ACTION_RANDOM_PHASE = 30, // PhaseId1, PhaseId2, PhaseId3...
|
||||
@@ -496,7 +496,7 @@ enum SMART_ACTION
|
||||
SMART_ACTION_SET_COUNTER = 63, // id, value, reset (0/1)
|
||||
SMART_ACTION_STORE_TARGET_LIST = 64, // varID,
|
||||
SMART_ACTION_WP_RESUME = 65, // none
|
||||
SMART_ACTION_SET_ORIENTATION = 66, //
|
||||
SMART_ACTION_SET_ORIENTATION = 66, // quick change, random orientation? (0/1)
|
||||
SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance
|
||||
SMART_ACTION_PLAYMOVIE = 68, // entry
|
||||
SMART_ACTION_MOVE_TO_POS = 69, // PointId (optional x,y,z offset), transport, controlled, ContactDistance
|
||||
@@ -590,7 +590,13 @@ enum SMART_ACTION
|
||||
SMART_ACTION_MUSIC = 216, // SoundId, onlySelf, type
|
||||
SMART_ACTION_RANDOM_MUSIC = 217, // SoundId1, SoundId2, SoundId3, SoundId4, onlySelf, type
|
||||
|
||||
SMART_ACTION_AC_END = 218, // placeholder
|
||||
SMART_ACTION_CUSTOM_CAST = 218, // spellId, castflag, bp0, bp1, bp2
|
||||
SMART_ACTION_CONE_SUMMON = 219, // entry, duration (0 = perm), dist between rings, dist between earch summon in a row, length of cone, width of cone (angle)
|
||||
SMART_ACTION_PLAYER_TALK = 220, // acore_string.entry, yell? (0/1)
|
||||
SMART_ACTION_VORTEX_SUMMON = 221, // entry, duration (0 = perm), spiral scaling, spiral appearance, range max, phi_delta <-- yes confusing math, try it ingame and see, my lovely AC boys!
|
||||
SMART_ACTION_CU_ENCOUNTER_START = 222, // Resets cooldowns on all targets and removes Heroism debuff(s)
|
||||
|
||||
SMART_ACTION_AC_END = 223, // placeholder
|
||||
};
|
||||
|
||||
struct SmartAction
|
||||
@@ -1173,6 +1179,7 @@ struct SmartAction
|
||||
struct
|
||||
{
|
||||
uint32 quickChange;
|
||||
uint32 random;
|
||||
} orientation;
|
||||
|
||||
struct
|
||||
@@ -1181,6 +1188,38 @@ struct SmartAction
|
||||
uint32 movementExpired;
|
||||
} stopMotion;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 summonEntry;
|
||||
uint32 summonDuration;
|
||||
uint32 distanceBetweenRings;
|
||||
uint32 distanceBetweenSummons;
|
||||
uint32 coneLength;
|
||||
uint32 coneAngle;
|
||||
} coneSummon;
|
||||
|
||||
struct {
|
||||
uint32 textId;
|
||||
uint32 flag;
|
||||
} playerTalk;
|
||||
|
||||
struct {
|
||||
uint32 spell;
|
||||
uint32 flags;
|
||||
uint32 bp1;
|
||||
uint32 bp2;
|
||||
uint32 bp3;
|
||||
} castCustom;
|
||||
|
||||
struct {
|
||||
uint32 summonEntry;
|
||||
uint32 summonDuration;
|
||||
uint32 a;
|
||||
uint32 k;
|
||||
uint32 r_max;
|
||||
uint32 phi_delta;
|
||||
} summonVortex;
|
||||
|
||||
//! Note for any new future actions
|
||||
//! All parameters must have type uint32
|
||||
|
||||
|
||||
Reference in New Issue
Block a user