mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-06 04:23:47 +00:00
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:
@@ -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:
|
||||
|
||||
@@ -344,6 +344,9 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
|
||||
case SMART_TARGET_CLOSEST_FRIENDLY:
|
||||
case SMART_TARGET_STORED:
|
||||
case SMART_TARGET_FARTHEST:
|
||||
case SMART_TARGET_PLAYER_WITH_AURA:
|
||||
case SMART_TARGET_RANDOM_POINT:
|
||||
case SMART_TARGET_ROLE_SELECTION:
|
||||
break;
|
||||
default:
|
||||
sLog->outErrorDb("SmartAIMgr: Not handled target_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
@@ -396,7 +399,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (e.target.type < 0 || e.target.type >= SMART_TARGET_END)
|
||||
if (e.target.type < 0 || (e.target.type >= SMART_TARGET_TC_END && e.target.type < SMART_TARGET_AC_START) || e.target.type >= SMART_TARGET_AC_END)
|
||||
{
|
||||
sLog->outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has an invalid target type (%u), skipped.",
|
||||
e.entryOrGuid, e.event_id, e.GetTargetType());
|
||||
|
||||
@@ -1294,7 +1294,7 @@ enum SMARTAI_TARGETS
|
||||
SMART_TARGET_GAMEOBJECT_GUID = 14, // guid, entry
|
||||
SMART_TARGET_GAMEOBJECT_DISTANCE = 15, // entry(0any), maxDist
|
||||
SMART_TARGET_INVOKER_PARTY = 16, // invoker's party members
|
||||
SMART_TARGET_PLAYER_RANGE = 17, // min, max, maxCount (maxCount by pussywizard)
|
||||
SMART_TARGET_PLAYER_RANGE = 17, // min, max, maxCount (maxCount by pussywizard), set target.o to 1 if u want to search for all in range if min, max fails
|
||||
SMART_TARGET_PLAYER_DISTANCE = 18, // maxDist
|
||||
SMART_TARGET_CLOSEST_CREATURE = 19, // CreatureEntry(0any), maxDist, dead?
|
||||
SMART_TARGET_CLOSEST_GAMEOBJECT = 20, // entry(0any), maxDist
|
||||
@@ -1308,7 +1308,17 @@ enum SMARTAI_TARGETS
|
||||
SMART_TARGET_FARTHEST = 28, // maxDist, playerOnly, isInLos
|
||||
SMART_TARGET_VEHICLE_PASSENGER = 29, // TODO: NOT SUPPORTED YET
|
||||
|
||||
SMART_TARGET_END = 30
|
||||
SMART_TARGET_TC_END = 30, // placeholder
|
||||
|
||||
// AC-only SmartTargets:
|
||||
|
||||
SMART_TARGET_AC_START = 200, // placeholder
|
||||
|
||||
SMART_TARGET_PLAYER_WITH_AURA = 201, // spellId, negation, MaxDist, MinDist, set target.o to a number to random resize the list
|
||||
SMART_TARGET_RANDOM_POINT = 202, // range, amount (for summoning creature), self als middle (0/1) else use xyz
|
||||
SMART_TARGET_ROLE_SELECTION = 203, // Range Max, TargetMask (Tanks (1), Healer (2) Damage (4)), resize list
|
||||
|
||||
SMART_TARGET_AC_END = 204 // placeholder
|
||||
};
|
||||
|
||||
struct SmartTarget
|
||||
@@ -1359,6 +1369,13 @@ struct SmartTarget
|
||||
uint32 getFromHashMap; // Does not work in instances
|
||||
} unitGUID;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 maxDist;
|
||||
uint32 roleMask;
|
||||
uint32 resize;
|
||||
} roleSelection;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 creature;
|
||||
@@ -1432,6 +1449,21 @@ struct SmartTarget
|
||||
uint32 playerOnly;
|
||||
} closestFriendly;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 range;
|
||||
uint32 amount;
|
||||
uint32 self;
|
||||
} randomPoint;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 spellId;
|
||||
uint32 negation;
|
||||
uint32 distMax;
|
||||
uint32 distMin;
|
||||
} playerWithAura;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 param1;
|
||||
@@ -1442,6 +1474,13 @@ struct SmartTarget
|
||||
};
|
||||
};
|
||||
|
||||
enum SmartTargetRoleFlags
|
||||
{
|
||||
SMART_TARGET_ROLE_FLAG_TANKS = 0x001,
|
||||
SMART_TARGET_ROLE_FLAG_HEALERS = 0x002,
|
||||
SMART_TARGET_ROLE_FLAG_DAMAGERS = 0x004
|
||||
};
|
||||
|
||||
enum eSmartAI
|
||||
{
|
||||
SMART_EVENT_PARAM_COUNT = 4,
|
||||
|
||||
Reference in New Issue
Block a user