Enemy soldier scripting

Topics regarding Scripting with Reality Factory
User avatar
Kamazy
Posts: 146
Joined: Wed Jul 20, 2005 2:59 pm
Location: Everywhere And Nowhere

Enemy soldier scripting

Post by Kamazy »

Hey all i'm wondering if enemys can hear footsteps and gun fire cuz my can't.
And how can i make an enemy take cover after seeing me or run for the alarm.
The patroling and guarding are easy but he cant hear me or see dead friends and press the alarm.
how can i make a alarm like triger. maybe make them go to a script point them another pawn trigers the alarm.
And how can a pawn drop a weapon then he dies.
Image
User avatar
ZenBudha
Posts: 285
Joined: Wed Aug 17, 2005 6:06 am
Contact:

Post by ZenBudha »

The pawn doesn't drop his weapon. A weapon of X type is spawned at the dead pawns location. If you get what I mean.

For hearing you are probably going to have to set up some AI sound stuff for the pawn to check for. Perhaps by attaching an invisible pawn to the player that checks speed, and produces an amount of noise in an attribute.

Then the pawns can check the noise level and if it's >X they will alert to the sound. Same thing with gunfire.

For alarms and such you just need to script in the extra actions for when they spot the player. Instead of just attacking the player have them move to a point like in front of the alarm, and then tell them what trigger to activate.

For detecting dead pawns perhaps have the pawns also check their fellow pawns health attribute. If it = 0 then have them react however you want. Like having them go to them and check if they're dead, and then running for the alarm, or calling for backup, etc.
User avatar
Kamazy
Posts: 146
Joined: Wed Jul 20, 2005 2:59 pm
Location: Everywhere And Nowhere

Post by Kamazy »

That sound good but i'm still a novice scripter a sample script would be great thanks.
Image
User avatar
Kamazy
Posts: 146
Joined: Wed Jul 20, 2005 2:59 pm
Location: Everywhere And Nowhere

Post by Kamazy »

That sound good but i'm still a novice scripter a sample script would be great thanks. Any way my new project is much simpler that what i was doing in the begining. my new project won't need this features. I'm just starting with game making and think i simple but fun game should be the first one i make. When i get better i will make better games.
Image
Johnny Nobody

Post by Johnny Nobody »

Hi, I'm a beginner with realityfactory and I have a problem with adding enemies.

I managed to make the default monster (Xanibot3) appear but all it does is stand there breathing. How do I make it attack the player and patrol?

I downloaded the genericmonster.s and the perfectai.s but I do not know how to use them in the RFEditPro program.

Any help will be appreciated, thanks.
User avatar
Microman171
Posts: 167
Joined: Sat Jul 09, 2005 3:45 am
Location: New Zealand

Post by Microman171 »

I would find that useful because I want the xanibot to shoot me and kill me instead of just terminating the game
(\/)
(Oo)
(><)

Help this bunny in his world domination by putting him in your sig.
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Re: Enemy soldier scripting

Post by incenseman2003 »

I have searched high and low for the way to make a pawn patrol and then attack when it sees the player.

I have spent many hours trying to get the pawn in my game to do it.

Considering the age of this post I am suprised that no one has just posted the answer.

The manual is very unclear on how it is done. I have followed it to the letter and have not been able to get it to work. I have also opened the demo that came with RF that has patroling robots in it. I set my pawn and script points just like the demo. The pawn just stands there and is indestructable.

Is there any one that knows how to make this happen using the genericmonster.s?

If so, Will they please just post the answer in detail here?
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
User avatar
vrageprogrammer
Posts: 566
Joined: Wed Oct 31, 2007 2:59 pm
Location: On top of a tree
Contact:

Re: Enemy soldier scripting

Post by vrageprogrammer »

incenseman2003 wrote:I have searched high and low for the way to make a pawn patrol and then attack when it sees the player.

I have spent many hours trying to get the pawn in my game to do it.

Considering the age of this post I am suprised that no one has just posted the answer.

The manual is very unclear on how it is done. I have followed it to the letter and have not been able to get it to work. I have also opened the demo that came with RF that has patroling robots in it. I set my pawn and script points just like the demo. The pawn just stands there and is indestructable.

Is there any one that knows how to make this happen using the genericmonster.s?

If so, Will they please just post the answer in detail here?

get in to the scripts>Sample folder.

Use genericai.s

make 2 Script points and in each Script point, make it run 'Setup'

Viola!
It was not Possible to determine the dimensions of the image....
User avatar
darksmaster923
Posts: 1857
Joined: Wed Jan 03, 2007 10:32 pm
Location: Huntington Beach, California, USA

Re: Enemy soldier scripting

Post by darksmaster923 »

did you give the pawn a spawn point? you have to give a scriptpoint a szentityname and use that for the pawns spawnpoint entry
Herp derp.
User avatar
bernie
RF Moderator
Posts: 1249
Joined: Tue Nov 15, 2005 10:07 am
Location: Ireland

Re: Enemy soldier scripting

Post by bernie »

Search the forum for the perfectai script its up here somewhere. It's probably on hike1's website, download it and use that it's much better.
Set Patrol [false] (you don't need script points for an ambush type pawn) and away you go.

EDIT: here it is:

{
// Perfect AI
// by Peter Coleman
// monster will fire missiles or melee if close enough
// Changes to ai-run and Check-Any-Attack


SCALE [1] // scale of actor
GROUP [soldier] // name of monster group
BOXWIDTH [25] // width and depth of bounding box
HOSTILEPLAYER [true] // hostile to player
HOSTILEDIFFERENT [false] // hostile to different Pawn group
HOSTILESAME [false] // hostile to same Pawn group
HEALTHATTRIBUTE [health] // name of health attribute
CONATTRIBUTE [conciousness]
CON [10]
HEALTH [50] // initial amount of health
SIGHTDIST [200] // max distance monster can see at idle
ALERTSIGHTDIST [150] // max distance monster can see when alert
FOV [360] // field of view in degrees
ATTACKFOV [360] // attacking field of view
YAWSPEED [360] // speed of rotation in deg/sec
DAMAGEATTRIBUTE [health] // attribute damaged by attack
ALERTTRIGGER [AlertG] // name of alert trigger

// define the type of monster this will be

ATTACKTYPE [melee] // type of attack - melee or missile
PATROL [true] // false - ambush or true - patrol
PC [0] // make any visible point the next point

// idling and turning

STAND [Idle] // idle animation
TURNL [Idle] // turn left animation
TURNR [Idle] // turn right animation

// when in pain

PAIN [Injury] // pain animations
PAIN1 [Injury]
PAIN2 [Injury]
PAIN3 [Injury]
PAINPERCENT [50] // percentage of time pain is shown
PAINSOUND [pl_pain2.wav] // sounds played when in pain
PAINSOUND1 [injury1.wav]
PAINSOUND2 [injury1.wav]
PAINSOUND3 [injury1.wav]

// when dying

DIE [Die] // dying animations
DIE1 [Die]
DIE2 [Die]
DIE3 [Die]
DIEHOLD [false] // time corpse still appears
DIEFADE [false] // fadeout time of corpse
DIESOUND [deathyell.wav] // sounds played when dying
DIESOUND1 [die1.wav]
DIESOUND2 [die1.wav]
DIESOUND3 [deathyell.wav]

// when running to attack

RUN [Run] // running animation
RUNSPEED [200] // average run speed
RUNSOUNDDELAY [2] // delay between making sounds when running to attack
RUNSOUND [breath.wav] // sound played while running to attack

// when walking while patroling

WALK [Walk] // walking animation
WALKSPEED [100] // average walking speed
WALKSOUND [breath.wav] // walking sound

// the projectile attack mode

MISSILEATTACK [Run]//[crouch_shoot_xm4_blend1] // missile attacking animations
MISSILEATTACK1 [Run]//[ref_shoot_xm4_blend1]
MISSILEATTACK2 [Run]//[crouch_shoot_xm4_blend1]
SHOOTUP [Run]//[ref_shoot_xm4_blend2]
SHOOTDOWN [Run]//[ref_shoot_xm4_blend1]
FIREDELAY [0.3] // delay after animation starts before projectile launch
FIREDELAY1 [0.3]
FIREDELAY2 [0.3]
MISSILESOUND [shoot1.wav] // sounds played when shooting
MISSILESOUND1 [shoot1.wav]
MISSILESOUND2 [shoot1.wav]
MISSILERANGE [1]//[700] // max distance to start missile attack
PROJECTILE [PlasmaBullet] // projectile name
FIREBONE [Bip01 R Finger1] // projectile launch bone
OFFSETX [0] // launch offsets
OFFSETY [0]
OFFSETZ [0]
ATTACKDELAY [0.3] // time between shots
SKILL [5] // skill level 1 to 10

// the melee attack mode

MELEEATTACK [Punch] // melee attacking animations
MELEEATTACK1 [Slash1]
MELEEATTACK2 [Slash2]
MELEESOUND [uuh.wav] // sounds played when melee attacking
MELEESOUND1 [uuh.wav]
MELEESOUND2 [uuh.wav]
MELEERANGE [35] // max distance to start melee attack
//MAXMELEERANGE [100] // max distance for melee mode
MINMELEEDAMAGE [10] // minimum amount of damage per melee attack
MAXMELEEDAMAGE [10] // maximum amount of damage per melee attack
MELEEDELAY [2] // number of seconds between melee damages
MELEEDAMAGESOUND [melee2.wav] // sound played when damage is done

// search for enemy

LOSTTIME [10] // time to search for enemy before giving up
POINTRADIUS [20] // radius from point when considered there

// obstacle avoidance forces for jumping

FORCEUP [65] // obstacle avoidance jump speed
FORCEFORWARD [20] // obstacle avoidance forward speed
FORCESIDE [20] // obstacle avoidance sideways speed

// local variables - do not change


RUNFUNC [monster_run_start] // monster run to attack function
MISSILEFUNC [monster_missile_start] // monster missile function
MELEEFUNC [monster_melee_start] // monster melee function
LOSTFUNC [monster_lost_target_start] // monster lost target function

AS_NONE [0]
AS_MELEE [1]
AS_MISSILE [2]
AS_STRAIGHT [3]
attack_delay [0]
melee_time [0]
lost_time [0]
back_up [false]
back_time [0]
left_time [0]
back_flag [false]
fire_delay [0]
skill_time [0]
attack_state [0]
run_sound_time [0]
missile_sound [NULL]
door_check [TRUE] // always check first to see if obstacle is a door
LENGTH [0] //Length of time to delay at script point do not change -- is set elsewhere

// spawn pawn and do setup work

Spawn[ ()
{
Console(true); // false = console off
Scale(SCALE); // scale the actor
if(BOXWIDTH > 0)
{
BoxWidth(BOXWIDTH*SCALE); // set bounding box width/depth
}
AttributeOrder(HEALTHATTRIBUTE, HEALTH, "Death"); // give monster health
HostilePlayer(HOSTILEPLAYER); // set who monster is hostile to
HostileSame(HOSTILESAME);
HostileDifferent(HOSTILEDIFFERENT);
SetFOV(360,"Bip01 Head"); // set field of view
SetGroup(GROUP); // assign a group to belong to
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AvoidOrder("Avoidance"); // avoid obstacles
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
SetWeapon("Mp5k2"); // give the monster a big gun
RotateToPoint(STAND, YAWSPEED, false, ""); // go to point if any specified
MoveToPoint(WALK, WALKSPEED*SCALE, WALKSOUND);
if(PATROL = true)
{
NewOrder("Patrol");
}
else
{
NewOrder("Idle");
}
} ]

// avoid objects when doing a MoveToPoint

Avoidance[ ()
{

if(door_check=true)
{
MoveBackward(WALK, WALKSPEED*SCALE, (WALKSPEED/2)*SCALE, ""); // if it's a door try again
door_check=false; // if it wasn't a door try other ways
Return();
}
if(random(1,10)<3) // backup and move sideways sometimes
{
MoveBackward(WALK, WALKSPEED*SCALE, (WALKSPEED/2)*SCALE, "");
MoveRight(WALK, WALKSPEED*SCALE, (WALKSPEED/2)*SCALE, "");
}
else
{
Jump(RUN, FORCEUP*SCALE, true, "");
if(random(1,10)<6)
{
Move("", FORCEFORWARD*SCALE, (FORCEFORWARD/2)*SCALE, 0, 90, 0, "");
}
else
{
Move("", FORCEFORWARD*SCALE, (FORCEFORWARD/2)*SCALE, 0, -90, 0, "");
}
}
Return();
} ]

// idle in place waiting for something to happen

Idle[ ()
{
PlayAnimation(STAND, true, "");
RestartOrder();
} ]



// walk the beat from point to point

Patrol[ ()
{

NextPoint();

LENGTH=random(10,40); // Set delay time between 10 and 40 secs

if(self.point_name="Start")
{

Delay("Idle",LENGTH,""); // Wait at start for BETWEEN 10 & 40 secs

}

LENGTH=random(5,20); // Set delay time between 5 and 20 secs

if(self.point_name="sp3")
{

Delay("Idle",LENGTH,""); // Wait at sp3 BETWEEN 5 & 20 secs

}
RotateMoveToPoint(WALK, YAWSPEED, WALKSPEED*SCALE, false, WALKSOUND);
MoveToPoint(WALK, WALKSPEED*SCALE, WALKSOUND);
door_check=true; // ready to check for doors again
RestartOrder();
//}

} ]

// show pain at idle then trigger to alert

IdlePain[ ()
{

NewOrder("FoundTarget");
} ]

// start shifting from idle to alert

IdleToAlert[ ()
{
NewOrder("FoundTarget");
} ]

// look around at alert looking for enemy

Alert[ ()
{
NewOrder("FoundTarget");
} ]

// show pain at alert

AlertPain[ ()
{
NewOrder("FoundTarget");
} ]

// timed out at alert

AlertToIdle[ ()
{
NewOrder("FoundTarget");
} ]

// found a target to attack

FoundTarget[ ()
{
SetFOV(360,"Bip01 Head"); // set field of view
LowLevel(RUNFUNC); // attack functions are low level
} ]

// lost target while attacking so go back to idle again

LostTarget[ ()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
FindPointOrder("Patrol"); // do point stuff
if(PATROL = true)
{
NewOrder("Patrol");
}
else
{
NewOrder("Idle");
}
} ]

// you died




Death[ ()
{
SetNoCollision(); // remove bounding box so there are no collisions with corpse
FadeOut(10,0);
Remove =(true); // remove actor
RemoveWeapon(true); // remove the current weapon actor.
return 0;
}]

// Low level attack routines

// Start of run to attack

monster_run_start[ ()
{
TargetPlayer();
UpdateEnemyVis(true); //always aware of player position
UpdateTarget();
Animate(RUN); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "monster_run"; // go to run attack routine
self.ideal_yaw = enemy_yaw; // set direction to run
self.yaw_speed = YAWSPEED; // set rotation speed
back_up = false; // initialize obstacle avoidance
attack_state = AS_NONE; // not attacking yet
melee_time = time;
run_sound_time = time;
} ]

// run to enemy to attack

monster_run[ ()
{
self.ThinkTime = 0;
if(self.health<=0)
{
self.think = "death_biz"; // dead
return 0;
}
if((self.in_pain = true) and (random(1,100)<PAINPERCENT))
{
self.think = "monster_run_pain_start"; // in pain
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy is gone or dead
return 0;
}
if(enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
return 0;
}
if(run_sound_time < time)
{
if(random(1,10)>7)
{
run_sound_time = time + RUNSOUNDDELAY;
PlaySound(RUNSOUND);
}
}
ai_run(random((RUNSPEED-2)*SCALE,(RUNSPEED+2)*SCALE)); // run toward enemy
} ]

// start of pain while running

monster_run_pain_start[ ()
{
switch(random(1,4)) // play one of 4 pain animations
{
case 1
{
Animate(PAIN);
PlaySound("pl_pain2.wav", 500);
}
case 2
{
Animate(PAIN1);
PlaySound("pl_pain2.wav", 500);
}
case 3
{
Animate(PAIN2);
PlaySound("pl_pain2.wav", 500);
}
case 4
{
Animate(PAIN3);
PlaySound("pl_pain2.wav", 500);
}
}
SetHoldAtEnd(true); // set to stop at animation end
self.ThinkTime = 0;
self.think = "monster_run_pain";
} ]

// wait for animation to stop

monster_run_pain[ ()
{
self.ThinkTime = 0;
if(self.animate_at_end = true) // wait for end of animation
{
self.think = "monster_run_start"; // start running again
SetHoldAtEnd(false); // remove animation stop
self.ThinkTime = 0;
}
} ]

// start of lost sight of enemy routine

monster_lost_target_start[ ()
{
Animate(RUN); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "monster_lost_target";
run_sound_time = time + RUNSOUNDDELAY;
} ]

// go to last known location of enemy

monster_lost_target[ ()
{
self.ThinkTime = 0;
if(lost_time<time)
{
HighLevel("LostTarget"); // timed out while looking
return 0;
}
self.ThinkTime = 0;
if(self.health<=0)
{
self.think = "death_biz"; // dead
return 0;
}
if((self.in_pain = true) and (random(1,100)<PAINPERCENT))
{
self.think = "monster_lost_pain_start"; // in pain
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy died or was removed
return 0;
}
if(enemy_vis = true)
{
PlaySound("overhere_a.wav", 500);
self.think = "monster_run_start"; // seen again so run to attack
self.ThinkTime = 0;
return 0;
}
if(run_sound_time < time)
{
if(random(1,10)>7)
{
run_sound_time = time + RUNSOUNDDELAY;
PlaySound(RUNSOUND);
}
}
if((enemy_range>POINTRADIUS) and (RUNSPEED > 0)) // get close to last known location
{
walk_movetogoal(random((RUNSPEED-2)*SCALE,(RUNSPEED+2)*SCALE));
}
else
{
HighLevel("LostTarget"); // can't find at last known location
return 0;
}
} ]

// start of showing pain while searching

monster_lost_pain_start[ ()
{
switch(random(1,4)) // play one of 4 pain animations
{
case 1
{
Animate(PAIN);
PlaySound("pl_pain2.wav", 500);
}
case 2
{
Animate(PAIN1);
PlaySound("pl_pain2.wav", 500);
}
case 3
{
Animate(PAIN2);
PlaySound("pl_pain2.wav", 500);
}
case 4
{
Animate(PAIN3);
PlaySound("pl_pain2.wav", 500);
}
}
SetHoldAtEnd(true); // set to stop at end
self.ThinkTime = 0;
self.think = "monster_lost_pain";
} ]

// wait till animation is done

monster_lost_pain[ ()
{
self.ThinkTime = 0;
if(self.animate_at_end = true) // animation done
{
self.think = "monster_lost_target_start"; // go back to finding target
SetHoldAtEnd(false); // remove stop at end
self.ThinkTime = 0;
}
} ]

CheckForPoints[()
{
self.ThinkTime=0; // Process every frame
if(self.point_vis)
{
// point is visible - go to high level for nav and targetting
HighLevel("LostTarget");
return 0;
}
else
{
// Point not visible - cycle points
PC=PC+1; // Increment point counter variable
if(PC > 15)
{
// Point count has exceeded max - set to 0. (Max 110)
PC=1;
}
NextPoint();
}
}]

// start of missile attack

monster_missile_start[ ()
{
switch(random(1,3)) // play one of 3 missile animations
{
case 1
{
Animate(MISSILEATTACK);
fire_delay = time + FIREDELAY; // set firing delay
PlaySound("shotfire.wav", 500);
}
case 2
{
Animate(MISSILEATTACK1);
fire_delay = time + FIREDELAY1; // set firing delay
PlaySound("shotfire.wav", 500);
}
case 3
{
Animate(MISSILEATTACK2);
fire_delay = time + FIREDELAY2; // set firing delay
PlaySound("shotfire.wav", 500);
}
}
TargetPlayer();
UpdateEnemyVis(true); //always aware of player position
UpdateTarget();
self.ideal_yaw = enemy_yaw; // set direction to run
SetHoldAtEnd(true);
self.ThinkTime = 0.3;
self.think = "monster_missile";
skill_time = time + (SKILL*0.1); // calculate next update time
attack_delay = time + ATTACKDELAY; // delay until next shot
} ]

// attack target with projectile

monster_missile[ ()
{
self.ThinkTime = 0.3;
if(self.health<=0)
{
self.think = "death_biz";
return 0;
}
if((self.in_pain = true) and (random(1,100)<PAINPERCENT))
{
self.think = "monster_missile_pain_start"; // in pain
SetHoldAtEnd(false);
return 0;
}
exist = EnemyExist(DAMAGEATTRIBUTE);
if(exist < 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead but body remains
return 0;
}
if(enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
SetHoldAtEnd(false);
return 0;
}
if(self.player_Y>self.current_Y)
{
Animate(SHOOTUP);
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
PlaySound("shotfire.wav", 500);
SetHoldAtEnd(false);
self.ThinkTime = 0.3;
}
if(self.player_Y<self.current_Y)
{
Animate(SHOOTDOWN);
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
PlaySound("shotfire.wav", 500);
SetHoldAtEnd(false);
self.ThinkTime = 0.3;
}
if(enemy_range>MISSILERANGE)
{
Animate(MISSILEATTACK);
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
fire_delay = time + FIREDELAY; // set firing delay
PlaySound("shotfire.wav", 500);
self.think = RUNFUNC; // too far away so run toward
SetHoldAtEnd(false);
return 0;
}
if(skill_time<time) // update according to skill level
{
UpdateTarget(); // update target location
skill_time = time + (SKILL*0);
ai_face(); // face enemy while attacking
}

if(fire_delay<time) // delay after animation starts before firing
{
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
fire_delay = time + 1000; // set delay well ahead so it is ignored
PlaySound("shotfire.wav", 500);
}
if(self.animate_at_end = true)
{
if(attack_delay < time)
{
//self.think = RUNFUNC; // no
self.think = "monster_missile_start";
SetHoldAtEnd(false);
self.ThinkTime = 0;
}
}
} ]

death_biz[ ()
{
Animate(DIE);
PlaySound("deathyell.wav", 500);
SetHoldAtEnd(true); // set to stop at end
self.ThinkTime = 0.1;
//self.think = "Death";
HighLevel("Death");
return 0;
} ]

// start of showing pain

monster_missile_pain_start[ ()
{
switch(random(1,4)) // play one of 4 pain animations
{
case 1
{
Animate(PAIN);
PlaySound("pl_pain2.wav", 500);
}
case 2
{
Animate(PAIN1);
PlaySound("pl_pain2.wav", 500);
}
case 3
{
Animate(PAIN2);
PlaySound("pl_pain2.wav", 500);
}
case 4
{
Animate(PAIN3);
PlaySound("pl_pain2.wav", 500);
}
}
SetHoldAtEnd(true); // set to stop at end
self.ThinkTime = 0;
self.think = "monster_missile_pain";
} ]

// wait until animation is done

monster_missile_pain[ ()
{
self.ThinkTime = 0;
if(self.animate_at_end = true) // animation is done
{
self.think = "monster_missile_start"; // go back to missile attack
SetHoldAtEnd(false);
self.ThinkTime = 0;
}
} ]

// start of melee attack

monster_melee_start[ ()
{
switch(random(1,3)) // play one of 3 melee animations
{
case 1
{
Animate(MELEEATTACK);
}
case 2
{
Animate(MELEEATTACK1);
}
case 3
{
Animate(MELEEATTACK2);
}
}
SetHoldAtEnd(true); // set to stop at end
self.ThinkTime = 0.1;
self.think = "monster_melee";
} ]

// melee attack

monster_melee[ ()
{
self.ThinkTime = 0;
if(self.health<=0)
{
PlaySound("deathyell.wav", 500);
self.think = "death_biz"; // in pain
return 0;
}
if((self.in_pain = true) and (random(1,100)<PAINPERCENT))
{
SetHoldAtEnd(false);
self.think = "monster_melee_pain_start"; // in pain
return 0.1;
}
exist = EnemyExist(DAMAGEATTRIBUTE); // see if target is around
if(exist < 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 2)
{
SetHoldAtEnd(false);
HighLevel("DeadTarget"); // enemy is dead but body remains
return 0;
}
if(enemy_vis = false)
{
SetHoldAtEnd(false);
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
return 0;
}
if(enemy_range>(MELEERANGE*SCALE))
{
SetHoldAtEnd(false);
self.think = RUNFUNC; // too far away so run toward
return 0;
}
ai_face(); // face enemy while attacking
if(self.animate_at_end = true) // animation is done
{
SetHoldAtEnd(false);
switch(random(1,3)) // play one of 3 melee animations
{
case 1
{
Animate(MELEEATTACK);
}
case 2
{
Animate(MELEEATTACK1);
}
case 3
{
Animate(MELEEATTACK2);
}
}
SetHoldAtEnd(true); // set to stop at end
}
if(time>melee_time) // if time then damage
{
damage = random(MINMELEEDAMAGE, MAXMELEEDAMAGE); // get damage amount
Damage(damage, DAMAGEATTRIBUTE); // damage target
melee_time = time + MELEEDELAY; // reset time until next damage
}
} ]

// start of showing pain

monster_melee_pain_start[ ()
{
switch(random(1,4)) // play one of 4 pain animations
{
case 1
{
Animate(PAIN);
PlaySound("pl_pain2.wav", 500);
}
case 2
{
Animate(PAIN1);
PlaySound("pl_pain2.wav", 500);
}
case 3
{
Animate(PAIN2);
PlaySound("pl_pain2.wav", 500);
}
case 4
{
Animate(PAIN3);
PlaySound("pl_pain2.wav", 500);
}
}
SetHoldAtEnd(true); // set to stop at end
self.ThinkTime = 0.1;
self.think = "monster_melee_pain";
} ]

// wait until animation is done

monster_melee_pain[ ()
{
self.ThinkTime = 0.1;
if(self.animate_at_end = true) // animation is done
{
self.think = "monster_melee_start"; // go back to melee attack
SetHoldAtEnd(false);
self.ThinkTime = 0.1;
melee_time = time + MELEEDELAY; // reset attack deley
}
} ]

// basic AI routines

// run toward enemy and see if you are ready to attack

ai_run[ (dist)
{
if (attack_state = AS_MELEE) // do melee attack
{
ai_run_melee();
}
if (attack_state = AS_MISSILE) // do missile attack
{
ai_run_missile();
}

attack_state = AS_NONE;

if (CheckAnyAttack()) // check if you can start the actual attack
{
return 0;
}
if(RUNSPEED > 0)
{
walk_movetogoal(dist); // else move toward the enemy
}
} ]

// check if ready to do actual attacking

CheckAnyAttack[ ()
{
if(enemy_range<MELEERANGE)
{
if(enemy_range<(MELEERANGE*SCALE)) // inside melee range
{
attack_state = AS_MELEE; // do a melee attack
return true;
}
return false;
}

if(enemy_range<MISSILERANGE)
{
if(attack_delay>time)
{
return false;
}
if(enemy_range<MISSILERANGE)
{
attack_state = AS_MISSILE; // do a missile attack
return true;
}
}
return false;
} ]

// missile attack setup

ai_run_missile[ ()
{
ai_face();
if(FacingIdeal()) // got close enough
{
self.think = MISSILEFUNC; // start missile attack
attack_state = AS_STRAIGHT;
UpdateTarget();
skill_time = time + (SKILL*0.1);
}
} ]

// melee attack setup

ai_run_melee[ ()
{
ai_face(); // turn to face target
if(FacingIdeal()) // got close enough
{
self.think = MELEEFUNC; // start melee attack
self.attack_state = AS_STRAIGHT;
}
} ]

// face enemy

ai_face[ ()
{
self.ideal_yaw = enemy_yaw;
ChangeYaw(); // rotate to face enemy
} ]

// use walkmove to naviagte to enemy

walk_movetogoal[ (dist)
{
if(IsFalling = true)
{
return 0; // don't move while falling
}
if(dist < 0)
{
return 0;
}
if(back_up = false)
{
ai_face(); // turn to face enemy
if(FacingIdeal())
{
if(walkmove(self.current_yaw, dist) = true)
{
return 0; // can move in current direction
}
else
{
if(random(1,10)<3) // backup and move sideways
{
back_up = true;
back_time = time + 0.5;
back_flag = false;
return 0;
}
else
{
ForceUp(FORCEUP*SCALE); // jump up, forward and to side
ForceForward(FORCEFORWARD*SCALE);
if(random(1,10)<6)
{
ForceRight(FORCESIDE*SCALE);
}
else
{
ForceLeft(FORCESIDE*SCALE);
}
}
}
}
}
else
{
if(back_flag = false) // go backward 1/2 sec
{
if(back_time > time)
{
walkmove((self.current_yaw-(180*0.0174532925199433)), dist);
return 0;
}
else
{
back_time = time + 0.5;
back_flag = true;
}
}
if(back_time > time) // go sideways 1/2 sec
{
walkmove((self.current_yaw-(90*0.0174532925199433)), dist);
return 0;
}
back_up = false;
}
} ]

// check if nearly facing enemy

FacingIdeal[ ()
{
selfangle = self.current_yaw/0.0174532925199433; // your direction in degrees
idealangle = self.ideal_yaw/0.0174532925199433; // his direction in degrees
delta = selfangle - idealangle; // difference in directions
if (delta > -20 and delta < 20) // within 20 degrees is close enough
{
return true;
}
return false;
} ]

}// End script
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Re: Enemy soldier scripting

Post by incenseman2003 »

vrageprogrammer wrote:[get in to the scripts>Sample folder.

Use genericai.s

make 2 Script points and in each Script point, make it run 'Setup'

Viola!
vrageprogrammer, Thanks I will give that a try. I don't know why I didnt think of that myself.

darksmaster923 wrote:did you give the pawn a spawn point? you have to give a scriptpoint a szentityname and use that for the pawns spawnpoint entry

darksmaster923, I did just what the manual said. I followed it to the letter. Pawn would still not work.

bernie wrote:Search the forum for the perfectai script its up here somewhere. It's probably on hike1's website, download it and use that it's much better.
Set Patrol [false] (you don't need script points for an ambush type pawn) and away you go.

bernie, I have used the perfectai.s and think that it works great for more intrcate things. It is however a lot of work just to get what I want in this instance. Thanks a ton though for the reply.
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Re: Enemy soldier scripting

Post by incenseman2003 »

I did as vrageprogrammer suggested and it didn't work.

Pawn Settings:
Angle - 0 0 0
ChangeMaterial - Blank
ConvoOrder - Blank
ConvoScriptOrder - Blank
HideFromRadar - False
origin - -1520 -126 -1376
PawnType - virgil2
ScriptName - genericai.s
SpawnOrder - Spawn (I also tried "setup" and "Setup")
SpawnPoint - ScriptPoint1
SpawnTrigger - Blank
szEntityName - virgil2

Pawn.ini:
[virgil2]
actorname - virgil.act
actoration - -90 180 0
actorscale - 1
fillcollor - 255 255 255
ambientcolor - 255 255 255
subjecttogravity - True
boundingboxeanimation - Idle
shadowsize - 30

ScriptPoint1:
Angle - 0 0 0
NextOrder - setup (I also tried "Spawn")
NextPoint - ScriptPoint2
origin - -1398 -225 -1449
szEntityName - ScriptPoint1

ScriptPoint2:
Angle - 0 0 0
NextOrder - setup (I also tried "Spawn")
NextPoint - ScriptPoint1
origin - -840 -225 -1432
szEntityName - ScriptPoint2

Pawn does not patrol.
Pawn shoots once when it sees player and causes no damage then just stands there.
Pawn can be killed.

I have also tried the following in the genericai.s file:
Setting "MAXPOINTS" to the same number of ScriptPoints that in the level.

Setting "NewPoint" to the name of the first ScriptPoint.

Nothing that I have tried has gotten the pawn to patrol and then shoot at the player when it sees the player.

It appears that there may be some important information that has not been mentioned yet.

Even though I have set up the pawn and the ScriptPoints up the same way that the robots in the the example level are set up it does not work.
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
User avatar
darksmaster923
Posts: 1857
Joined: Wed Jan 03, 2007 10:32 pm
Location: Huntington Beach, California, USA

Re: Enemy soldier scripting

Post by darksmaster923 »

does the script have orders to follow the scriptpoints?
Herp derp.
User avatar
vrageprogrammer
Posts: 566
Joined: Wed Oct 31, 2007 2:59 pm
Location: On top of a tree
Contact:

Re: Enemy soldier scripting

Post by vrageprogrammer »

incenseman2003 wrote: ScriptPoint2:
Angle - 0 0 0
NextOrder - setup (I also tried "Spawn")
NextPoint - ScriptPoint1
origin - -840 -225 -1432
szEntityName - ScriptPoint2
2 things:

1.Check pawn rotation - I had this error once
2."NextOrder - setup (I also tried "Spawn")"

try Patrol
It was not Possible to determine the dimensions of the image....
User avatar
bernie
RF Moderator
Posts: 1249
Joined: Tue Nov 15, 2005 10:07 am
Location: Ireland

Re: Enemy soldier scripting

Post by bernie »

If you use perfectai script Next Order would be FindPointOrder;
Look for something similar in genericai.

Pointsetup maybe?

Personally I would always use perfectai because it covers all situations much better than genericai. It's much easier to adapt to your own needs I think.
Post Reply