Thursday 28 April 2011

Coding up animations

One of the things that it will be useful for an NPC to do is run animations.

Consider:

A human player walks down a street past a bot-spawning prim. A script in this prim detects the human player and boots up the decision tree which cascades through the criteria until the decision is taken to spawn an NPC in an angry hostile state with the goal of attacking the human interloper.

So the bot spawns, moves forward into range and then needs to attack. One of the things it should do when attacking (in order to make the experience enjoyable for the human player) is play a reasonable animation which is relevant to the attack.

So... it's necessary to code in some kind of animations to the bot. One of the things we'll need to do is make sure that it's only bots that can be animated or else the potential for griefing would be astronomical. We obviously don't want the ability to script any other player to perform a random animation without their permission, so we need a permissions check built in to make sure that it is in fact a bot and not a human player. That's easy enough to do though.

So the next piece is the actual animation code. Currently that's sitting in the OSSL_API.cs, which I think is not the right place for the code for bots because to run it you need the threat level to be high. Animating a bot is not a high threat level even though animating another human character against their will might be. Any case, I'm going to see if I can't hack up something from the code and put it into the bot code. The following are the two relevant functions, startanimation and stopanimation:

public void osAvatarPlayAnimation(string avatar, string animation)
{
ScriptProtection.CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarPlayAnimation", m_host, "OSSL");

UUID avatarID = (UUID)avatar;


if (World.Entities.ContainsKey((UUID)avatar) && World.Entities[avatarID] is ScenePresence)
{
ScenePresence target = (ScenePresence)World.Entities[avatarID];
if (target != null)
{
UUID animID=UUID.Zero;
lock (m_host.TaskInventory)
{
foreach (KeyValuePair inv in m_host.TaskInventory)
{
if (inv.Value.Name == animation)
{
if (inv.Value.Type == (int)AssetType.Animation)
animID = inv.Value.AssetID;
continue;
}
}
}
if (animID == UUID.Zero)
target.Animator.AddAnimation(animation, m_host.UUID);
else
target.Animator.AddAnimation(animID, m_host.UUID);
}
}
}

public void osAvatarStopAnimation(string avatar, string animation)
{
ScriptProtection.CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarStopAnimation", m_host, "OSSL");

UUID avatarID = (UUID)avatar;


if (World.Entities.ContainsKey(avatarID) && World.Entities[avatarID] is ScenePresence)
{
ScenePresence target = (ScenePresence)World.Entities[avatarID];
if (target != null)
{
UUID animID=UUID.Zero;
lock (m_host.TaskInventory)
{
foreach (KeyValuePair inv in m_host.TaskInventory)
{
if (inv.Value.Name == animation)
{
if (inv.Value.Type == (int)AssetType.Animation)
animID = inv.Value.AssetID;
continue;
}
}
}

if (animID == UUID.Zero)
target.Animator.RemoveAnimation(animation);
else
target.Animator.RemoveAnimation(animID);
}
}
}

No comments:

Post a Comment