feat(Core/AI): CU_SAI - Custom Target Options (#2879)

NEW:
* SMART_TARGET_PLAYER_WITH_AURA (spellid, negation?, distMax, distMin) - if target.O is set it will resize the list of targets to target.o
* SMART_TARGET_RANDOM_POINT (range, amount (for summon creature), self (creature is middle else use xyz) (ONLY USED FOR SUMMON CREATURE OR MOVE/JUMP TO POS ACTIONS FOR NOW)

MODIFIED:
* SMART_ACTION_SUMMON_CREATURE now possible to spawn multiple creatures with SMART_TARGET_RANDOM_POINT
* SMART_ACTION_MOVE_TO_POS/JUMP_TO_POS now possible to move to a random point with SMART_TARGET_RANDOM_POINT
* SMART_TARGET_PLAYER_RANGE no longer targets GMs or dead targets and when target.o is >0 it will try all possible targets in max instead of min-maxing


Co-authored-by: Francesco Borzì <borzifrancesco@gmail.com>
This commit is contained in:
P-Kito
2020-04-18 16:59:52 +02:00
committed by GitHub
parent 63c86a9a14
commit 2514f8fc9a
7 changed files with 1033 additions and 677 deletions

View File

@@ -1547,6 +1547,28 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!summoner)
break;
if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT)
{
float range = (float)e.target.randomPoint.range;
Position randomPoint;
Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
for (uint32 i = 0; i < e.target.randomPoint.amount; i++)
{
if (e.target.randomPoint.self > 0)
me->GetRandomPoint(me->GetPosition(), range, randomPoint);
else
me->GetRandomPoint(srcPos, range, randomPoint);
if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, randomPoint, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration))
{
if (unit && e.action.summonCreature.attackInvoker)
summon->AI()->AttackStart(unit);
else if (me && e.action.summonCreature.attackScriptOwner)
summon->AI()->AttackStart(me);
}
}
break;
}
if (targets)
{
float x, y, z, o;
@@ -1896,6 +1918,28 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
WorldObject* target = NULL;
if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT)
{
if (me)
{
float range = (float)e.target.randomPoint.range;
Position randomPoint;
Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
me->GetRandomPoint(srcPos, range, randomPoint);
me->GetMotionMaster()->MovePoint(
e.action.MoveToPos.pointId,
randomPoint.m_positionX,
randomPoint.m_positionY,
randomPoint.m_positionZ,
true,
true,
e.action.MoveToPos.controlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE
);
}
break;
}
/*if (e.GetTargetType() == SMART_TARGET_CREATURE_RANGE || e.GetTargetType() == SMART_TARGET_CREATURE_GUID ||
e.GetTargetType() == SMART_TARGET_CREATURE_DISTANCE || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_RANGE ||
e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE ||
@@ -2456,6 +2500,20 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_JUMP_TO_POS:
{
if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT)
{
if (me)
{
float range = (float)e.target.randomPoint.range;
Position randomPoint;
Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
me->GetRandomPoint(srcPos, range, randomPoint);
me->GetMotionMaster()->MoveJump(randomPoint, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
}
break;
}
ObjectList* targets = GetTargets(e, unit);
if (!targets)
break;
@@ -3614,17 +3672,23 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
}
case SMART_TARGET_PLAYER_RANGE:
{
uint32 count = 0;
// will always return a valid pointer, even if empty list
ObjectList* units = GetWorldObjectsInDist((float)e.target.playerRange.maxDist);
if (!units->empty() && GetBaseObject())
{
for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr)
if (IsPlayer(*itr) && GetBaseObject()->IsInRange(*itr, (float)e.target.playerRange.minDist, (float)e.target.playerRange.maxDist))
{
if (IsPlayer(*itr) && GetBaseObject()->IsInRange(*itr, (float)e.target.playerRange.minDist, (float)e.target.playerRange.maxDist) && (*itr)->ToPlayer()->IsAlive() && !(*itr)->ToPlayer()->IsGameMaster())
l->push_back(*itr);
if (e.target.playerRange.maxCount && ++count >= e.target.playerRange.maxCount)
break;
}
// If Orientation is also set and we didnt find targets, try it with all the range
if (l->empty() && e.target.o > 0)
for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr)
if (IsPlayer(*itr) && baseObject->IsInRange(*itr, 0.0f, float(e.target.playerRange.maxDist)) && (*itr)->ToPlayer()->IsAlive() && !(*itr)->ToPlayer()->IsGameMaster())
l->push_back(*itr);
if (e.target.playerRange.maxCount > 0)
acore::Containers::RandomResizeList(*l, e.target.playerRange.maxCount);
}
delete units;
break;
@@ -3732,6 +3796,64 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
break;
}
case SMART_TARGET_PLAYER_WITH_AURA:
{
// will always return a valid pointer, even if empty list
ObjectList* units = GetWorldObjectsInDist(e.target.z ? e.target.z : float(e.target.playerWithAura.distMax));
for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr)
if (IsPlayer(*itr) && (*itr)->ToPlayer()->IsAlive() && !(*itr)->ToPlayer()->IsGameMaster())
if (GetBaseObject()->IsInRange(*itr, (float)e.target.playerWithAura.distMin, (float)e.target.playerWithAura.distMax))
if (bool(e.target.playerWithAura.negation) != (*itr)->ToPlayer()->HasAura(e.target.playerWithAura.spellId))
l->push_back(*itr);
if (e.target.o > 0)
acore::Containers::RandomResizeList(*l, e.target.o);
delete units;
break;
}
case SMART_TARGET_ROLE_SELECTION:
{
// will always return a valid pointer, even if empty list
ObjectList* units = GetWorldObjectsInDist(float(e.target.roleSelection.maxDist));
// 1 = Tanks, 2 = Healer, 4 = Damage
uint32 roleMask = e.target.roleSelection.roleMask;
for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr)
if (Player* targetPlayer = (*itr)->ToPlayer())
if (targetPlayer->IsAlive() && !targetPlayer->IsGameMaster())
{
if (roleMask & SMART_TARGET_ROLE_FLAG_TANKS)
{
if (targetPlayer->HasTankSpec())
{
l->push_back(*itr);
continue;
}
}
if (roleMask & SMART_TARGET_ROLE_FLAG_HEALERS)
{
if (targetPlayer->HasHealSpec())
{
l->push_back(*itr);
continue;
}
}
if (roleMask & SMART_TARGET_ROLE_FLAG_DAMAGERS)
{
if (targetPlayer->HasCasterSpec() || targetPlayer->HasMeleeSpec())
{
l->push_back(*itr);
continue;
}
}
}
if (e.target.roleSelection.resize > 0)
acore::Containers::RandomResizeList(*l, e.target.roleSelection.resize);
delete units;
break;
}
case SMART_TARGET_NONE:
case SMART_TARGET_POSITION:
default: