[Scripts] DBScripts-Engine: Implement new commands

* Add SCRIPT_COMMAND_MOVE_DYNAMIC to move to a random point or towards another unit

* Toggle GetRandomPoint function to be able to return a random point with min-distance or a given direction.
* Toggle MovementGenerator::GetResetPosition to be able to return a reasonable orientation for reset.

Ideas and requirement research by virusav!
Thanks to virusav and Grz3s for test-feedback! (c2603)
This commit is contained in:
schmoozerd 2015-03-23 22:52:33 +00:00 committed by Antz
parent beb3522e2a
commit 4819ec8ebc
10 changed files with 163 additions and 53 deletions

View File

@ -1 +1 @@
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

View File

@ -168,6 +168,13 @@ ID | Name | Parameters
34 | SCRIPT_COMMAND_TERMINATE_COND | `datalong` = condition_id, `datalong2` = fail-quest (if provided this quest will be failed for a player), `!(data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL)`: terminate when condition is true, `data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL`: terminate when condition is false
35 | SCRIPT_COMMAND_SEND_AI_EVENT_AROUND | resultingSource = Creature, resultingTarget = Unit, datalong = AIEventType - limited only to EventAI supported events, datalong2 = radius
36 | SCRIPT_COMMAND_TURN_TO | resultingSource = Creature, resultingTarget = Unit/none.
37 | SCRIPT_COMMAND_MOVE_DYNAMIC | Move resultingSource to a random point around resultingTarget or to resultingTarget
| * resultingSource = Creature, resultingTarget Worldobject.
| * datalong = 0: Move resultingSource towards resultingTarget
| * datalong != 0: Move resultingSource to a random point between datalong2..datalong around resultingTarget.
| orientation != 0: Obtain a random point around resultingTarget in direction of orientation
| * data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL Obtain a point in direction of resTarget->GetOrientation + orientation
| for resTarget == resSource and orientation == 0 this will mean resSource moving forward
TemporaryFactionFlags
---------------------

View File

@ -47,12 +47,11 @@ void HomeMovementGenerator<Creature>::_setTargetLocation(Creature& owner)
Movement::MoveSplineInit init(owner);
float x, y, z, o;
// at apply we can select more nice return points base at current movegen
if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner, x, y, z))
if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner, x, y, z, o))
{
owner.GetRespawnCoord(x, y, z, &o);
init.SetFacing(o);
}
init.SetFacing(o);
init.MoveTo(x, y, z, true);
init.SetWalk(false);
init.Launch();

View File

@ -59,7 +59,7 @@ class MovementGenerator
virtual void unitSpeedChanged() { }
// used by Evade code for select point to evade with expected restart default movement
virtual bool GetResetPosition(Unit&, float& /*x*/, float& /*y*/, float& /*z*/) const { return false; }
virtual bool GetResetPosition(Unit&, float& /*x*/, float& /*y*/, float& /*z*/, float& o) const { return false; }
// given destination unreachable? due to pathfinsing or other
virtual bool IsReachable() const { return true; }
@ -98,10 +98,10 @@ class MovementGeneratorMedium : public MovementGenerator
// u->AssertIsType<T>();
return (static_cast<D*>(this))->Update(*((T*)&u), time_diff);
}
bool GetResetPosition(Unit& u, float& x, float& y, float& z) const override
bool GetResetPosition(Unit& u, float& x, float& y, float& z, float& o) const override
{
// u->AssertIsType<T>();
return (static_cast<D const*>(this))->GetResetPosition(*((T*)&u), x, y, z);
return (static_cast<D const*>(this))->GetResetPosition(*((T*)&u), x, y, z, o);
}
public:
// Will not link if not overridden in the generators
@ -112,7 +112,7 @@ class MovementGeneratorMedium : public MovementGenerator
bool Update(T& u, const uint32& time_diff);
// not need always overwrites
bool GetResetPosition(T& /*u*/, float& /*x*/, float& /*y*/, float& /*z*/) const { return false; }
bool GetResetPosition(T& /*u*/, float& /*x*/, float& /*y*/, float& /*z*/, float& /*o*/) const { return false; }
};
struct SelectableMovement : public FactoryHolder<MovementGenerator, MovementGeneratorType>

View File

@ -254,32 +254,6 @@ bool WaypointMovementGenerator<Creature>::Update(Creature& creature, const uint3
return true;
}
void WaypointMovementGenerator<Creature>::MovementInform(Creature& creature)
{
if (creature.AI())
{ creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); }
}
bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z) const
{
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
{ return false; }
WaypointPath::const_iterator lastPoint = i_path->find(m_lastReachedWaypoint);
// Special case: Before the first waypoint is reached, m_lastReachedWaypoint is set to 0 (which may not be contained in i_path)
if (!m_lastReachedWaypoint && lastPoint == i_path->end())
{ return false; }
MANGOS_ASSERT(lastPoint != i_path->end());
const WaypointNode &waypoint = lastPoint->second;
x = waypoint.x;
y = waypoint.y;
z = waypoint.z;
return true;
}
bool WaypointMovementGenerator<Creature>::Stopped(Creature& u)
{
@ -295,6 +269,54 @@ bool WaypointMovementGenerator<Creature>::CanMove(int32 diff, Creature& u)
return i_nextMoveTime.Passed() && !u.hasUnitState(UNIT_STAT_WAYPOINT_PAUSED);
}
bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z, float& o) const
{
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
{ return false; }
WaypointPath::const_iterator lastPoint = i_path->find(m_lastReachedWaypoint);
// Special case: Before the first waypoint is reached, m_lastReachedWaypoint is set to 0 (which may not be contained in i_path)
if (!m_lastReachedWaypoint && lastPoint == i_path->end())
{ return false; }
MANGOS_ASSERT(lastPoint != i_path->end());
WaypointNode const* curWP = &(lastPoint->second);
x = curWP->x;
y = curWP->y;
z = curWP->z;
if (curWP->orientation != 100)
o = curWP->orientation;
else // Calculate the resulting angle based on positions between previous and current waypoint
{
WaypointNode const* prevWP;
if (lastPoint != i_path->begin()) // Not the first waypoint
{
--lastPoint;
prevWP = &(lastPoint->second);
}
else // Take the last waypoint (crbegin()) as previous
prevWP = &(i_path->rbegin()->second);
float dx = x - prevWP->x;
float dy = y - prevWP->y;
o = atan2(dy, dx); // returns value between -Pi..Pi
o = (o >= 0) ? o : 2 * M_PI_F + o;
}
return true;
}
void WaypointMovementGenerator<Creature>::MovementInform(Creature& creature)
{
if (creature.AI())
{ creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); }
}
void WaypointMovementGenerator<Creature>::AddToWaypointPauseTime(int32 waitTimeDiff)
{
if (!i_nextMoveTime.Passed())
@ -410,9 +432,12 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
}
}
bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z) const
bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z, float& o) const
{
const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
x = node.x; y = node.y; z = node.z;
x = node.x;
y = node.y;
z = node.z;
return true;
}

View File

@ -86,7 +86,7 @@ class WaypointMovementGenerator<Creature>
// now path movement implmementation
void LoadPath(Creature& c);
bool GetResetPosition(Creature&, float& x, float& y, float& z) const;
bool GetResetPosition(Creature&, float& /*x*/, float& /*y*/, float& /*z*/, float& /*o*/) const;
void AddToWaypointPauseTime(int32 waitTimeDiff);
@ -132,7 +132,7 @@ class FlightPathMovementGenerator
bool HasArrived() const { return (i_currentNode >= i_path->size()); }
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
bool GetResetPosition(Player&, float& x, float& y, float& z) const;
bool GetResetPosition(Player&, float& /*x*/, float& /*y*/, float& /*z*/, float& /*o*/) const;
};
#endif

View File

@ -1262,7 +1262,7 @@ bool WorldObject::isInBack(WorldObject const* target, float distance, float arc)
return IsWithinDist(target, distance) && !HasInArc(2 * M_PI_F - arc, target);
}
void WorldObject::GetRandomPoint(float x, float y, float z, float distance, float& rand_x, float& rand_y, float& rand_z) const
void WorldObject::GetRandomPoint(float x, float y, float z, float distance, float& rand_x, float& rand_y, float& rand_z, float minDist /*=0.0f*/, float const* ori /*=NULL*/) const
{
if (distance == 0)
{
@ -1273,8 +1273,17 @@ void WorldObject::GetRandomPoint(float x, float y, float z, float distance, floa
}
// angle to face `obj` to `this`
float angle = rand_norm_f() * 2 * M_PI_F;
float new_dist = rand_norm_f() * distance;
float angle;
if (!ori)
angle = rand_norm_f() * 2 * M_PI_F;
else
angle = *ori;
float new_dist;
if (minDist == 0.0f)
new_dist = rand_norm_f() * distance;
else
new_dist = minDist + rand_norm_f() * (distance - minDist);
rand_x = x + new_dist * cos(angle);
rand_y = y + new_dist * sin(angle);

View File

@ -540,7 +540,7 @@ class WorldObject : public Object
void UpdateGroundPositionZ(float x, float y, float& z) const;
void UpdateAllowedPositionZ(float x, float y, float& z) const;
void GetRandomPoint(float x, float y, float z, float distance, float& rand_x, float& rand_y, float& rand_z) const;
void GetRandomPoint(float x, float y, float z, float distance, float& rand_x, float& rand_y, float& rand_z, float minDist = 0.0f, float const* ori = NULL) const;
uint32 GetMapId() const { return m_mapId; }
uint32 GetInstanceId() const { return m_InstanceId; }

View File

@ -87,6 +87,10 @@ uint8 GetSpellStartDBScriptPriority(SpellEntry const* spellinfo, SpellEffectInde
if (spellinfo->Effect[effIdx] == SPELL_EFFECT_TRIGGER_SPELL && !sSpellStore.LookupEntry(spellinfo->EffectTriggerSpell[effIdx]))
{ return 5; }
// NonExisting trigger missile spells can also start DB-Spell-Scripts
if (spellinfo->Effect[effIdx] == SPELL_EFFECT_TRIGGER_MISSILE && !sSpellStore.LookupEntry(spellinfo->EffectTriggerSpell[effIdx]))
{ return 4; }
// Can not start script
return 0;
}
@ -678,6 +682,15 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
}
break;
}
case SCRIPT_COMMAND_MOVE_DYNAMIC: // 37
{
if (tmp.moveDynamic.maxDist < tmp.moveDynamic.minDist)
{
sLog.outErrorDb("Table `%s` has invalid min-dist (datalong2 = %u) less than max-dist (datalon = %u) in SCRIPT_COMMAND_MOVE_DYNAMIC for script id %u", tablename, tmp.moveDynamic.minDist, tmp.moveDynamic.maxDist, tmp.id);
continue;
}
break;
}
default:
{
sLog.outErrorDb("Table `%s` unknown command %u, skipping.", tablename, tmp.command);
@ -1065,6 +1078,15 @@ bool ScriptAction::LogIfNotGameObject(WorldObject* pWorldObject)
}
return false;
}
bool ScriptAction::LogIfNotPlayer(WorldObject* pWorldObject)
{
if (!pWorldObject || pWorldObject->GetTypeId() != TYPEID_PLAYER)
{
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-player, skipping.", m_table, m_script->id, m_script->command);
return true;
}
return false;
}
/// Helper to get a player if possible (target preferred)
Player* ScriptAction::GetPlayerTargetOrSourceAndLog(WorldObject* pSource, WorldObject* pTarget)
@ -1442,12 +1464,12 @@ bool ScriptAction::HandleScriptStep()
// Select Spell
uint32 spell = m_script->castSpell.spellId;
uint32 i = 0;
while (i < MAX_TEXT_ID && m_script->textId[i]) // Count which dataint fields are filled
++i;
if (i > 0)
if (uint32 rnd = urand(0, i)) // Random selection resulted in one of the dataint fields
spell = m_script->textId[rnd - 1];
uint32 filledCount = 0;
while (filledCount < MAX_TEXT_ID && m_script->textId[filledCount]) // Count which dataint fields are filled
++filledCount;
if (filledCount > 0)
if (uint32 randomField = urand(0, filledCount)) // Random selection resulted in one of the dataint fields
spell = m_script->textId[randomField - 1];
// TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
if (pSource && pSource->GetTypeId() == TYPEID_GAMEOBJECT)
@ -1824,6 +1846,39 @@ bool ScriptAction::HandleScriptStep()
((Unit*)pSource)->SetFacingTo(pSource->GetAngle(pTarget));
break;
}
case SCRIPT_COMMAND_MOVE_DYNAMIC: // 37
{
if (LogIfNotCreature(pSource))
return false;
if (LogIfNotUnit(pTarget))
return false;
float x, y, z;
if (m_script->moveDynamic.maxDist == 0) // Move to pTarget
{
if (pTarget == pSource)
{
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, _MOVE_DYNAMIC called with maxDist == 0, but resultingSource == resultingTarget (== %s)", m_table, m_script->id, pSource->GetGuidStr().c_str());
break;
}
pTarget->GetContactPoint(pSource, x, y, z);
}
else // Calculate position
{
float orientation;
if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL)
orientation = pSource->GetOrientation() + m_script->o + 2 * M_PI_F;
else
orientation = m_script->o;
pSource->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), m_script->moveDynamic.maxDist, x, y, z,
m_script->moveDynamic.minDist, (orientation == 0.0f ? NULL : &orientation));
z = std::max(z, pTarget->GetPositionZ());
pSource->UpdateAllowedPositionZ(x, y, z);
}
((Creature*)pSource)->GetMotionMaster()->MovePoint(1, x, y, z);
break;
}
default:
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u unknown command used.", m_table, m_script->id, m_script->command);
break;

View File

@ -111,6 +111,12 @@ enum ScriptCommand // resSource, resTar
// datalong = AIEventType
// datalong2 = radius
SCRIPT_COMMAND_TURN_TO = 36, // resSource = Unit, resTarget = Unit/none
SCRIPT_COMMAND_MOVE_DYNAMIC = 37, // resSource = Creature, resTarget Worldobject.
// datalong = 0: Move resSource towards resTarget
// datalong != 0: Move resSource to a random point between datalong2..datalong around resTarget.
// orientation != 0: Obtain a random point around resTarget in direction of orientation
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL Obtain a random point around resTarget in direction of resTarget->GetOrientation + orientation
// for resTarget == resSource and orientation == 0 this will mean resSource moving forward
};
#define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK, SCRIPT_COMMAND_EMOTE, SCRIPT_COMMAND_CAST_SPELL, SCRIPT_COMMAND_TERMINATE_SCRIPT
@ -339,17 +345,23 @@ struct ScriptInfo
uint32 radius; // datalong2
} sendAIEvent;
struct
{
uint32 data[2];
} raw;
struct // SCRIPT_COMMAND_TURN_TO (36)
{
uint32 targetId; // datalong
uint32 empty1; // datalong2
} turnTo;
struct // SCRIPT_COMMAND_MOVE_DYNAMIC (37)
{
uint32 maxDist; // datalong
uint32 minDist; // datalong2
} moveDynamic;
struct
{
uint32 data[2];
} raw;
};
// Buddy system (entry can be npc or go entry, depending on command)
@ -406,6 +418,8 @@ struct ScriptInfo
case SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL:
case SCRIPT_COMMAND_TERMINATE_SCRIPT:
case SCRIPT_COMMAND_TERMINATE_COND:
case SCRIPT_COMMAND_TURN_TO:
case SCRIPT_COMMAND_MOVE_DYNAMIC:
return true;
default:
return false;
@ -465,6 +479,7 @@ class ScriptAction
bool LogIfNotCreature(WorldObject* pWorldObject);
bool LogIfNotUnit(WorldObject* pWorldObject);
bool LogIfNotGameObject(WorldObject* pWorldObject);
bool LogIfNotPlayer(WorldObject* pWorldObject);
Player* GetPlayerTargetOrSourceAndLog(WorldObject* pSource, WorldObject* pTarget);
};