Need help with Making pawns attack pawns.

Topics regarding Scripting with Reality Factory
Post Reply
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Need help with Making pawns attack pawns.

Post by incenseman2003 »

I have seen this posted before but cannot find the posts now. When I did read them I didnt see any detailed answer that stated that it worked.

I have tried the following to get a robot pawn to attack the pawn group called robot. It didnt work. Can some please tell me why?

{

IDLE [idle] // idle animation
WALK [walk] // walk animation
DIE [die] // die animation
SHOOT [shoot] // shoot animation
MISC1 [slump] // misc1 animation

GROUP [friendly_robot]
HOSTILEPLAYER [false] // hostile to player
HOSTILESAME [false] // hostile to same Pawn group
TargetGroup [false] // hostile to a certain group, true or false doesnt work
HostileDifferent [true] // hostile to different group, true or false doesnt work

HEALTHATTRIBUTE [enemy_health] // name of pawns health attribute
HEALTH [100] // initial pawn health
DAMAGEATTRIBUTE [health] // attribute damaged by attack

ALERTTRIGGER [AlertG] // name of alert trigger
DIEHOLD [15] // time corpse still appears
DIEFADE [10] // fadeout time of corpse

FOV [360] // field of view
SIGHTDIST [700] // max distance pawn can see at idle
ALERTSIGHTDIST [900] // max distance pawn can see when alert
YAWSPEED [90]
WALKSPEED [50]

SHOOTRANGE [300] // max distance to start missile attack
PROJECTILE [10mm_shell] // projectile name
FIREBONE [Joint15] // projectile launch bone
OFFSETX [0] // launch offsets
OFFSETY [0]
OFFSETZ [25]
ATTACKDELAY [0.5] // time between shots
FIREDELAY [0.1] // delay after animation starts before projectile launch
SKILL [5] // skill level 1 to 10

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

RUNFUNC [run_start] // monster run to attack function
SHOOTFUNC [shoot_start] // monster missile function
LOSTFUNC [lost_target_start] // monster lost target function

AS_NONE [0]
AS_SHOOT [2]
AS_STRAIGHT [3]
attack_delay [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]

Spawn[ ()
{
//Console(true);
SetFOV(FOV); // set field of view
BoxWidth(40);
SetGroup(GROUP);
HostilePlayer(HOSTILEPLAYER);
HostileSame(HOSTILESAME);
TargetGroup(robot); //added by me, didnt work
HostileDifferent(robot); //added by me, didnt work
// setup orders
AttributeOrder(HEALTHATTRIBUTE, HEALTH, "Death"); // give monster health
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AvoidOrder("Avoidance"); // avoid obstacles
AddPainOrder("PainToAlert", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered

RotateToPoint(IDLE, YAWSPEED, false, ""); // go to point if any specified
MoveToPoint(WALK, WALKSPEED, ""); // move to starting point
NewOrder("Patrol");

} ]

Idle[ ()
{
// just look around a bit
Rotate(IDLE, YAWSPEED, 0, 100, 0, "");
Delay(IDLE, random(3,5), "");
Rotate(IDLE, YAWSPEED, 0, -200, 0, "");
Delay(IDLE, random(3,5), "");
Align();
NewOrder("Patrol"); // continue to patrol
} ]

Avoidance[()
{
// backup and move sideways sometimes
MoveBackward(WALK, WALKSPEED, (WALKSPEED/2), "");

if(random(1,10)<6)
{
MoveRight(WALK, WALKSPEED, (WALKSPEED/2), "");
}
else
{
MoveLeft(WALK, WALKSPEED, (WALKSPEED/2), "");
}
Return();
}]

Patrol[ ()
{
// patroling from point to point, looking for special orders in each script point (i.e. "Idle")
NextPoint();
NextOrder();
RotateMoveToPoint(WALK, YAWSPEED, WALKSPEED, false, "");
MoveToPoint(WALK, WALKSPEED, "");
RestartOrder();
}]

PainToAlert[()
{
SetEventState(ALERTTRIGGER, true); // set trigger to go to alert
Return();
}]

IdleToAlert[()
{
FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // increase viewing

distance
AddTimerOrder(1, LOSTTIME, "AlertToIdle"); // go to idle after 10

secs
SetEventState(ALERTTRIGGER, false); // turn off alert

trigger
NewOrder("Alert");
}]

Alert[()
{
// just look around a bit
Rotate(IDLE, YAWSPEED, 0, 150, 0, "");
Delay(IDLE, random(3,5), "");
Rotate(IDLE, YAWSPEED, 0, -150, 0, "");
Delay(IDLE, random(3,5), "");
RestartOrder();
}]

AlertToIdle[()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // decrease viewing distance
AddPainOrder("PainToAlert", 100); // go to alert when pain
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Idle");
}]

FoundTarget[()
{
DelTimerOrder(1); // get rid of alert timer
LowLevel(RUNFUNC); // attack functions are low level
}]

LostTarget[ ()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("PainToAlert", 100); // trigger alert when pain
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
FindPointOrder("Patrol");
NewOrder("Idle");
} ]

Death[()
{
DelTimerOrder(1); // remove alert timer
AddPainOrder("PainToAlert", 0); // remove pain order
FindTargetOrder(0, "FoundTarget", DAMAGEATTRIBUTE); // remove target finding
DelTriggerOrder("IdleToAlert"); // remove alert trigger
SetNoCollision(); // remove bounding box so there are no

collisions with corpse
AnimateStop(DIE, DIEHOLD, "");
FadeOut(DIEFADE, 0); // fade out corpse
Remove(true); // remove actor
}]

// Low level routines

run_start[ ()
{
Animate(WALK); // play animation
self.ThinkTime = 0; // start thinking on next frame
self.ideal_yaw = self.enemy_yaw; // set direction to run
self.yaw_speed = YAWSPEED; // set rotation speed
back_up = false; // initialize obsticle avoidance
attack_state = AS_NONE; // not attacking yet
self.think = "run_to_attack"; // go to run attack routine
} ]

run_to_attack[ ()
{
self.ThinkTime = 0.05;
if(self.health<=0)
{
HighLevel("Death"); // dead
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy is gone or dead
return 0;
}
if(self.enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = self.time + LOSTTIME;
return 0;
}
ai_run(random(WALKSPEED-2, WALKSPEED+2)); // run toward enemy

} ]

// start of lost sight of enemy routine
lost_target_start[()
{
Animate(WALK); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "lost_target";
}]

// go to last known location of enemy
lost_target[()
{
self.ThinkTime = 0.1;
if(lost_time<self.time)
{
HighLevel("LostTarget"); // timed out while looking
return 0;
}
if(self.health<=0)
{
HighLevel("Death"); // died
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy died or was removed
return 0;
}
if(self.enemy_vis = true)
{
self.think = "run_start"; // seen again so run to attack
self.ThinkTime = 0;
return 0;
}
if(self.enemy_range>POINTRADIUS) // get close to last known location
{
walk_movetogoal(random(WALKSPEED-2, WALKSPEED+2));
}
else
{
HighLevel("LostTarget"); // can't find at last known location
return 0;
}
}]

// start of shoot attack

shoot_start[()
{
Animate(SHOOT); // play shoot attack animation
SetHoldAtEnd(true);
self.ThinkTime = 0;
fire_delay = self.time + FIREDELAY; // set firing delay
UpdateTarget(); // update target location
skill_time = self.time + (SKILL*0.1); // calculate next update time
attack_delay = self.time + ATTACKDELAY; // delay until next shot
self.think = "shooting";
}]

// attack target with projectile

shooting[()
{
self.ThinkTime = 0.1;
if(self.health<=0)
{
SetHoldAtEnd(false);
HighLevel("Death"); // dead
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(self.enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = self.time + LOSTTIME;
SetHoldAtEnd(false);
return 0;
}
if(self.enemy_range>SHOOTRANGE)
{
self.think = RUNFUNC; // too far away so run toward
SetHoldAtEnd(false);
return 0;
}
if(skill_time<self.time) // update according to skill level
{
UpdateTarget(); // update target location
skill_time = self.time + (SKILL*0.1);
ai_face(); // face enemy while attacking
}
if(fire_delay<self.time) // delay after animation starts before firing
{
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
fire_delay = self.time + 1000; // set delay well ahead so it is ignored
}

// wait until animation is done before attacking again
// hold animation at end until attack delay is over
if(self.animate_at_end = true)
{
if(attack_delay < self.time)
{
self.think = "shoot_start"; // go back to missile attack
SetHoldAtEnd(false);
self.ThinkTime = 0.1;
}
}
}]

// basic AI routines

ai_run[(dist)
{
if (attack_state = AS_SHOOT) // do shoot attack
{
ai_run_shoot();
return 0;
}
if (CheckAnyAttack()) // check if you can start the actual attack
{
return 0;
}
walk_movetogoal(dist); // else move toward the enemy
}]

// shoot attack setup

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

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

// use walkmove to naviagte to enemy

walk_movetogoal[(dist)
{
if(self.IsFalling = true)
{
return 0; // don't move while falling
}
if(back_up = false)
{
ai_face(); // turn to face enemy
if(FacingIdeal())
{
yaw = self.current_yaw;
if(NearestPoint(10, 500))
{
yaw = GetYawToPoint();
self.ideal_yaw = yaw;
ChangeYaw();
}
if(walkmove(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 = self.time + 0.5;
back_flag = false;
return 0;
}
else
{
ForceUp(20); // jump up, forward and to side
ForceForward(10);
if(random(1,10)<6)
{
ForceRight(10);
}
else
{
ForceLeft(10);
}
}
}
}
}
else
{
if(back_flag = false) // go backward 1/2 sec
{
if(back_time > self.time)
{
walkmove((self.current_yaw-(3.14159)), dist);
return 0;
}
else
{
back_time = self.time + 0.5;
back_flag = true;
}
}
if(back_time > self.time) // go sideways 1/2 sec
{
walkmove((self.current_yaw-(1.570796)), dist);
return 0;
}
back_up = false;
}
} ]


// check if nearly facing enemy

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

// check if ready to do actual attacking

CheckAnyAttack[()
{
if(attack_delay>self.time)
{
return false;
}
if(enemy_range<SHOOTRANGE) // inside missile range
{
attack_state = AS_SHOOT; // do a missile attack
return true;
}
return false;
}]

}
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
User avatar
QuestOfDreams
Site Admin
Posts: 1520
Joined: Sun Jul 03, 2005 11:12 pm
Location: Austria
Contact:

Post by QuestOfDreams »

remove

Code: Select all

TargetGroup [false] // hostile to a certain group, true or false doesnt work 
HostileDifferent [true] // hostile to different group, true or false doesnt work 

Code: Select all

TargetGroup(robot); //added by me, didnt work 
HostileDifferent(robot); //added by me, didnt work 
should be

Code: Select all

TargetGroup("robot"); 
HostileDifferent(true); 
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Post by incenseman2003 »

The GROUP info now looks like this:
GROUP [friendly_robot]
HOSTILEPLAYER [false] // hostile to player
HOSTILESAME [false] // hostile to same Pawn group


The SPAWN info now looks like this:
Spawn[ ()
{
//Console(true);
SetFOV(FOV); // set field of view
BoxWidth(40);
SetGroup(GROUP);
HostilePlayer(HOSTILEPLAYER);
HostileSame(HOSTILESAME);
TargetGroup(robot);
HostileDifferent(true);


The pawn that I assign the script to does not attack me but also will not attack other pawns. I tried with and without the quotes. With the quotes "TargetGroup("robot");" the pawn just dies upon spawning. Also the pawns that I make thoes or similar changes to the script for them cannot be killed by me.

Nice try though. It does seem that it should have worked. But I am no expert.

Is there be another approach that could be tried?
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
Jay
RF Dev Team
Posts: 1232
Joined: Fri Jul 08, 2005 1:56 pm
Location: Germany

Post by Jay »

You also need to have pawns with another GroupName, meaning you need another script for them(the hostile ones) where it looks like this:

GROUP [hostile]
HOSTILEPLAYER [false] // hostile to player, if you want the hostile ones to attack the player, set to true
HOSTILESAME [false] // hostile to same Pawn group

hope that helps. :)
Everyone can see the difficult, but only the wise can see the simple.
-----
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Post by incenseman2003 »

Thanks Jay,

Have done thoes things. I have 2 groups, properly identified each in tjier own script. I have mucked around and got one robot to kill another in the same group.

However, If I use 1 or more of a different group some of them die when spawning and others that use the same script dont. Then the next time I restart the same level they will all die, or they wont. It seems pretty random. What I really want to have done is this. One script for each group. Each group should target a spacific group. I have tried what the manual said. It didnt work. I just need more detail than the manual gives. I havent read about any success stories of people doing this. The commands are there but is it truely possible?
---
Edit: 11:55 AM 1/6/2007
I just used the same scripts and the same commands but added all new pawns for both groups from scatch, no copy and paste. It works fine now. There is something funky about doing this with copy and paste I guess.

thanks a ton.
Last edited by incenseman2003 on Sat Jan 06, 2007 5:57 pm, edited 1 time in total.
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
Jay
RF Dev Team
Posts: 1232
Joined: Fri Jul 08, 2005 1:56 pm
Location: Germany

Post by Jay »

Now that's really strange. I am completely lost what could have caused this.

You have already tried the TargetGroup() command and it didn't work?
Everyone can see the difficult, but only the wise can see the simple.
-----
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Post by incenseman2003 »

I now have the "perfectai.s" set up to allow my own pawn to attack pawns of a different group. That part works great.

I now have the issue as follows:
My new pawn does great when shooting other pawns to kill them, but when he kicks or punches a pawn once he just keeps kicking or punching even after the pawn is dead and does not move on to the next target or return to the idle state.

Any way to get him to stop and go back to idle or move on to the next target?
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
Jay
RF Dev Team
Posts: 1232
Joined: Fri Jul 08, 2005 1:56 pm
Location: Germany

Post by Jay »

If you are using the script that you have shown in your first post i am not even sure if the pawn actually damages the other pawns while kicking or punching because there is no Damage() command anywhere.
If you are using another script then please let me know.


So if you are using the script above:
Add these lines after you have damaged another pawn:

Code: Select all

if(EnemyExist(DAMAGEATTRIBUTE) < 3) 
{ 
HighLevel("LostTarget"); // enemy is gone or dead 
return 0; 
} 
because this makes the pawn find other pawns to attack if its enemy is dead.
(these lines are from the script you posted)

Ok hope this helps. :)
Everyone can see the difficult, but only the wise can see the simple.
-----
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Post by incenseman2003 »

As I stated, I am using the perfectai.s to run my pawns. I have made mods to it that allow it to actually damage and kill a pawn of another group. That parts works fine. Just the way I want it.

The is that when my pawn uses any of the melee attacks he commits the first one and then keeps doin it. He will not move on to the next target or go back to the idle state.

Damaging or killing another pawn group is not the issue. getting him to stop the malee attack on the dead pawn and move on to the next target is.

Edit 2:13 PM 1/7/2007:

I did more modding on the perfectai.s and got my pawn to stop the melee attack when the pawn it attacks is dead by doing the following in the melee attack section.

if(exist = 2)
{
SetHoldAtEnd(true);
HighLevel("DeadTarget"); // enemy is dead but body remains
return 0;

However it will not move on to the next target.

Any ideas.
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
Jay
RF Dev Team
Posts: 1232
Joined: Fri Jul 08, 2005 1:56 pm
Location: Germany

Post by Jay »

Ah ok now i understand it correctly.

In your 'DeadTarget' Order you have to renew the FindTargetOrder()-command. Just paste in what you have used the first time. I think that's all. Tell me if it works or if it doesn't.
Everyone can see the difficult, but only the wise can see the simple.
-----
incenseman2003
Posts: 320
Joined: Sat Mar 11, 2006 11:41 pm

Post by incenseman2003 »

I finally did get the script to make my pawn do what I wanted. I made the following script in the perfectai.s:

// melee attack

monster_melee[ ()
{
self.ThinkTime = 0;
if(self.health<=0)
{
PlaySound("die1.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(true);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 0)
{
SetHoldAtEnd(true);
HighLevel("DeadTarget"); // enemy is dead but body remains
return 0;
}
if(enemy_vis = false)
{
SetHoldAtEnd(true);
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;
}




Works perfect now.
Patience and tolerance are the keys to the passage of knowledge. Even those that are the most knowledgeable started with many questions.
Post Reply