Aller au contenu

Photo

Invisible fencing trigger for use with livestock


  • Veuillez vous connecter pour répondre
15 réponses à ce sujet

#1
rjshae

rjshae
  • Members
  • 4 497 messages
I'm using the following brief script to keep ambiently-wandering livestock contained in their pens, despite openings in the fence. Perhaps you may find it useful?

// ww_invisible_fence
/*
	  This is the On Enter script for a Trigger blueprint that
	  causes a non-controlled animal to 'back off' upon entry.
  It can be used, for example, to cover an opening to a
  fenced-in area where the livestock have been given
	  'X2_L_SPAWN_USE_AMBIENT = 1' variable settings.
*/
// RJH 30jun13

void main()
{
  object oTarget = GetEnteringObject();
	  if ( ! GetIsObjectValid( oTarget ) )
		  return; // Invalid object
	
  // Check if the creature is of type Animal
	  if ( GetRacialType( oTarget ) != RACIAL_TYPE_ANIMAL )
		    return;
	
  // Check if creature is player-controlled
	  object oControl = GetControlledCharacter( oTarget );
  if ( oControl != OBJECT_INVALID )
		    return;
	
  	// Get current creature location information
	  location locCreature = GetLocation( oTarget );

  // Compute a 'back off' vector
  float facAway = GetFacingFromLocation( locCreature ) + 180.0f;
  vector vAwayNorm = VectorNormalize( AngleToVector( facAway ) );
	  float fScale = 0.5;
	  vector vAway = Vector( fScale * vAwayNorm.x, fScale * vAwayNorm.y, fScale * vAwayNorm.z );
	  vector vPos = GetPositionFromLocation( locCreature );
	
	  // Stop the current movement
	  AssignCommand( oTarget, ClearAllActions() );
	
  // Compute the new destination
	  object oArea = GetAreaFromLocation( locCreature );
  location locTurnAway = Location( oArea, vPos + vAway, facAway );
	  location locSafeTurnAway = CalcSafeLocation( oTarget, locTurnAway, 0.4f, TRUE, FALSE );
	
  // Order creature away after a brief pause
	  AssignCommand( oTarget, ActionWait( 0.2f ) );
  DelayCommand( 0.2f, AssignCommand( oTarget, ActionMoveToLocation( locSafeTurnAway ) ) );
}

Modifié par rjshae, 23 octobre 2013 - 03:34 .


#2
kevL

kevL
  • Members
  • 4 070 messages
neat!

#3
rjshae

rjshae
  • Members
  • 4 497 messages
Thanks. During subsequent testing the animals sometimes got caught inside the area when it is fairly small in size and located near several unwalkable barriers. It's an odd scripting behavior that I haven't quite figured out yet. Ah, my goof. :whistle:

Modifié par rjshae, 30 juin 2013 - 10:20 .


#4
MasterChanger

MasterChanger
  • Members
  • 686 messages
Are you intending these pens to be reachable by creatures that don't start off in the pens? What I'm getting at is: is there a reason to not just use walkmesh cutters to enclose the pens?

Of course, I am always happy to see new uses of movement commands to make AI more elegant, so this is nice work nonetheless.

#5
rjshae

rjshae
  • Members
  • 4 497 messages
Yes, I prefer to allow the party to be able to go pretty much wherever they want, even if there is nothing interesting to find. The world feels more explorable that way. In this case I have several farms with large outer fences that I want the PCs and their associated creatures to be able to enter and leave.

#6
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
It's also useful for when you want fences or other barriers to be walkable, like a low wooden fence or even a rail around a cow pasture.

Additionally, you could use the code without the fences, to keep wildlife restricted to particular sections of an area.

#7
Dann-J

Dann-J
  • Members
  • 3 161 messages
I use a slightly different approach. I use quite a few wandering 'eye candy' domestic animals with a custom HB script that does two things; randomly has them play one of three sounds stored on them as local strings (pigs grunt, horses neigh, dogs bark, etc), and check to see how far away from a home waypoint they are. If they have a valid home waypoint that matches their tag structure, and they're greater than a specified distance away from it, they turn and walk back towards it. Otherwise they wander randomly.

#8
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 598 messages
My contribution to this was made back in December 2007. I use a trigger with a waypoint and two scripts, one for entering the trigger and one for exiting the trigger. I used these in my Silverwand Sample Campaign to control passive farm animals. In combination with a custom OnPerception script (bb_c2_default2) this also allowed me to restrict randomly walking hostiles to specific areas until they perceive the party. Here are the two trigger scripts.

// bb_onenter_fence
// by Brendan Bellina
// Dec 2007

// Use as the onEnter script of a trigger, coupled with the onExit script
// bb_onexit_fence, to allow a creature(s) to walk around randomly within a
// restricted area defined by the trigger.

// Set variable num_creature_types on the trigger to indicate the number of different
// types of creatures within it, and use variables fencedCreature_1, fencedCreature_2, etc
// to record the tag of each type.

// Create a waypoint and position it inside the trigger and set variable fencedWaypoint on the
// trigger with the tag of the waypoint.

// If the creature(s) is hostile then set its OnPerception script to bb_c2_default2
// so that the random walking will cease when it perceives a PC.

// The creature(s) should have variable X2_L_SPAWN_USE_AMBIENT set to 1.
// Some creatures do not have any ambience anyway. For them use the script bb_randomwalker_sp.

// Note: Once a hostile creature perceives a PC it can enter the trigger without
// starting to randomly walk, because at that point it is in combat.

void main()
{
object oPC = GetEnteringObject();
int nCreatureTypes = GetLocalInt(OBJECT_SELF,"num_creature_types");
if (nCreatureTypes == 0)
nCreatureTypes = 1;
int i = 1;
int found = 0;
while ( !found && i <= nCreatureTypes )
{
string sVar = "fencedCreature_" + IntToString(i++);
string sFencedCreature = GetLocalString(OBJECT_SELF, sVar);
if (GetTag(oPC) == sFencedCreature)
{
found = 1;
if (!GetIsInCombat(oPC)
&& !IsInConversation(oPC))
{
AssignCommand (oPC, ClearAllActions());
AssignCommand (oPC, ActionRandomWalk());
}
}
}
}

And the exit script:
// bb_onexit_fence
// by Brendan Bellina
// Dec 2007

// Use as the onExit script of a trigger, coupled with the onEnter script
// bb_onenter_fence, to allow a creature(s) to walk around randomly within a
// restricted area defined by the trigger.

// Set variable num_creature_types on the trigger to indicate the number of different
// types of creatures within it, and use variables fencedCreature_1, fencedCreature_2, etc
// to record the tag of each type.

// Create a waypoint and position it inside the trigger and set variable fencedWaypoint on the
// trigger with the tag of the waypoint.

// If the creature(s) is hostile then set its OnPerception script to bb_c2_default2
// so that the random walking will cease when it perceives a PC.

// The creature(s) should have variable X2_L_SPAWN_USE_AMBIENT set to 1.
// Some creatures do not have any ambience anyway. For them use the script bb_randomwalker_sp.

// Note: Once a hostile creature perceives a PC it can exit the trigger, because
// at that point it will be in combat.

void main()
{
object oPC = GetExitingObject();
string sFencedWaypoint = GetLocalString(OBJECT_SELF, "fencedWaypoint");
int nCreatureTypes = GetLocalInt(OBJECT_SELF,"num_creature_types");
if (nCreatureTypes == 0)
nCreatureTypes = 1;
int i = 1;
int found = 0;
while ( !found && i <= nCreatureTypes )
{
string sVar = "fencedCreature_" + IntToString(i++);
string sFencedCreature = GetLocalString(OBJECT_SELF, sVar);
if (GetTag(oPC) == sFencedCreature)
{
found = 1;
if (!GetIsInCombat(oPC)
&& !IsInConversation(oPC))
{
AssignCommand (oPC, ClearAllActions());
AssignCommand (oPC, ActionForceMoveToObject(GetWaypointByTag(sFencedWaypoint)));
}
}
}
}

Regards

#9
rjshae

rjshae
  • Members
  • 4 497 messages
^^^ Yes, that should work. My only concern is that it becomes a nuisance to try and select anything in the toolset inside a trigger region.

After expanding the invisible fence code to allow it to get a racial type from a variable on the trigger, I ended up adding a SetFacing call because it looked silly for a human to keep backing away like that.
:)

#10
MarshallV

MarshallV
  • Members
  • 43 messages
 This AI can limit NPCs/Monsters to home points as well as a few other things.  Since these videos, and with Kamal's permission, it has incorporated elements of his commoner AI as well.  

http://www.youtube.c...0707723B71A48F9

Download HERE

Modifié par MarshallV_ForgotMyAccount, 10 juillet 2013 - 09:19 .


#11
PJ156

PJ156
  • Members
  • 2 985 messages
Lol ... my cows stand still.

Note to self, must learn to script.

Thanks for posting this guys I am going to think about where I might usefully use this.

PJ

#12
rjshae

rjshae
  • Members
  • 4 497 messages
It does seem like the animations for many of the animals are too lethargic compared to the movement rates in their blueprints. Watching chickens skate across the ground is odd; I usually have to set them to 'slow' movement. Plus when the larger animals such as horses end up next to fences, the body often intersects with the fence parts. Widening the walkmesh cutter helps with that a little.

#13
rjshae

rjshae
  • Members
  • 4 497 messages
The original script above turned out to be susceptible to collisions that would negate the back-off action. A mix of methods worked better.

#14
Dann-J

Dann-J
  • Members
  • 3 161 messages
This is the heartbeat script I use on eye-candy creatures. It keeps them from wandering too far from a home waypoint (if they have one), and allows then to make random animal sounds.


// Heartbeat script for randomly wandering eye-candy creatures
//
// If you want to restrict the creatures to a certain area,
// create a waypoint with a tag of WP_[tag of creature]
// If you don't set a local float called 'Range' on the creatures,
// the default wander distance from the home waypoint is 10 metres.
//
// The script also has a chance to play one of three random sounds.
// Store local strings on the creature for up to three possible sounds.
// (Sound1, Sound2, Sound3)

#include "hench_i0_ai"

void main()
{
object oAreaPC = GetArea(GetFirstPC());
object oAreaMe = GetArea(OBJECT_SELF);

if (oAreaPC != oAreaMe) return;//Abort script if player not in the same area

// If current action is ACTION_MOVETOPOINT, abort script
if (GetCurrentAction(OBJECT_SELF) == 0) return;

object oPC = GetFirstPC(FALSE);
string oTag = GetTag(OBJECT_SELF);
string WPname = "WP_"+oTag;
object WPhome = GetWaypointByTag(WPname);
float fRoamDistance = GetLocalFloat(OBJECT_SELF, "Range");

if (fRoamDistance == 0.0) fRoamDistance = 10.0; // How far to roam from home waypoint

// Walk back to within 1m of home waypoint if they wander too far away
if (GetDistanceToObject(WPhome) > fRoamDistance && GetIsObjectValid(WPhome))
{
ClearAllActions(TRUE);
ActionMoveToObject(WPhome, FALSE, 1.0);
return;
}

// Determine random sound
string sSound1 = GetLocalString(OBJECT_SELF, "Sound1");
string sSound2 = GetLocalString(OBJECT_SELF, "Sound2");
string sSound3 = GetLocalString(OBJECT_SELF, "Sound3");

int iRandom = d6(1);// 50% chance no sound
string sSound;

switch(iRandom)
{
case 1:
sSound = sSound1;
break;
case 2:
sSound = sSound2;
break;
case 3:
sSound = sSound3;
break;
}//end switch

if (sSound != "")
{
ClearAllActions(FALSE);
PlaySound(sSound);
}

// Otherwise wander or follow waypoints
if (GetWalkCondition(NW_WALK_FLAG_CONSTANT))
{
WalkWayPoints();
}//end if
else
{
if(!IsInConversation(OBJECT_SELF) && GetCurrentAction(OBJECT_SELF) != 3)
{
if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) ||
GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN))
{
PlayMobileAmbientAnimations();
}
else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS))
{
PlayImmobileAmbientAnimations();
}
}//end if
}//end else
}

#15
bealzebub

bealzebub
  • Members
  • 352 messages
...copy ...paste ...compile... Thanks Dann!

#16
Dann-J

Dann-J
  • Members
  • 3 161 messages
The advantage of having each creature determine its own boundaries via their HB script is that if you want the entire herd to move somewhere specific, you can just destroy the old waypoint and spawn another one with the same tag elsewhere (or just change the tags of two existing waypoints). Then they all wander towards it in their own good time, and start confining themselves to the new location.