Attacking Order

Topics regarding Scripting with Reality Factory
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Attacking Order

Post by metal_head »

OK,I know that if a pawn is hostile to the player and to other groups,he attacks the player first and than when the plyer is killed the pawn starts to attack the other pawn groups,but it attacks the first pawn than the second .I mean if there is a player and pawns "Pawn1" "Pawn2" "Pawn3" and if pawn 1 is hostile to everything,it attacks first Pawn2 and than Pawn3 (at least I think it's like that) so the pawn attacks the pawns by their number in the pawn list.
Is it possible to make the pawn attack the nearest pawn(or player),not the smallest number in the pawn list or not the player first? I'm working on the perfectai,so I was thinking,it's maybe something in the "Spawn[ ()" order...
Last edited by metal_head on Wed Aug 20, 2008 11:25 am, edited 1 time in total.
Danimita92
Posts: 335
Joined: Sat Feb 09, 2008 5:47 pm
Location: Lanzarote/Canary Islands/Spain

Re: Attacking

Post by Danimita92 »

Try checking the distance commands, and the target commands. Sorry I can't do anything more than tellng you this, but I'm kind of busy :(
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking

Post by metal_head »

well,maybe they need some editing..but I can't get what should I do to make this.I think it's something simple,but I don't know what's it :D
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking

Post by metal_head »

OK,here's the attack command in the script,but I looked and I looked at it,but I couldn't get it..where does it say which pawn to attack first (reminding that I want the pawn to attack the nearest enemy no matter is it the player or not). I need a little help please :roll:

Code: Select all

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))
		{
			AddExplosion("headshot",GetLastBoneHit(),0,0,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);
                        AddExplosion(FLASH,"Bip01 R Hand",0,0,0);
			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);
                        AddExplosion(FLASH,"FIREBONE",0,0,0);
			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;
			}
		}
	} ]
User avatar
Juutis
Posts: 1511
Joined: Thu Jan 12, 2006 12:46 pm
Location: Finland

Re: Attacking Order

Post by Juutis »

The thing with perfectAI is that it doesn't "see" anything else than its current target when attacking. It can only acquire new targets with FindTargetOrder(); which is a high level command.
FindTargetOrder(float Distance, string Order, string Attribute);
Search the area within Distance of the Pawn for a target to attack. The target must have the attribute Attribute present to become a target. When a target is acquired the Script Order Order is executed.
The monster_missile order (or any other low level order) has nothing to do with this. When in low level the pawn just attacks the target it got in high level. And if it loses or kills the target it goes back to high level so it can execute FindTargetOrder() again and find a new target.

In low level the only way to set a target is with the SetTarget() command (or TargetPlayer() if you wanna target the player). And for that you need to know the entityname of the pawn you want to target. So there is no command that somehow scans the area and looks for a target like in high level.

So, what can we do?
We can loop through every enemy pawn and manually see if it's alive, if it can be seen and if it's within the sight range. For this you need to name every enemy like enemy1 enemy2 enemy3 etc. And every friend friend1 friend2 friend3 etc. This way we know the entityname of every single pawn in the level. They're always enemy or friend plus a number to separate it from everyone else.

Then let's write a little loop that checks if any enemy pawn is targetable (so this would go to the script of the friendly pawns):

Code: Select all

newtarget[ ()
{

for targetnumber=0 to MAXENEMYPAWNS step 1 //loop through all enemy pawns
{
     targetname = StringCopy("enemy" # targetnumber); //create the entityname of the _possible_ new target

     if(FastDistance(targetname,SIGHTRANGE))  //if the new target is inside sight range
     {
          if(IsEntityVsible(targetname)) //if the new target is visible
          {
               SetTarget(targetname);

               if(EnemyExist(DAMAGEATTRIBUTE) < 3)  //if the new target isn't alive
               {
                    SetTarget(""); //no target
               }
               else
               {
                    break; //new target is alive so keep it and break out of the loop
               }
          }
     }
}

return;
} ]
This order should give the pawn a new target. I can't guarantee it works since I haven't tested it. Now, every time you want the pawn to pick a new target you would just use newtarget();. For example, if you want to take a new target every 5 seconds you would write:

Code: Select all

if(newtargettimer < self.time)
{
     newtarget();
     newtargettimer = self.time +5;
}
Oh, and there are all these new variables and stuff in the script so you better introduce them in the beginning of the script:

Code: Select all

MAXENEMYPAWNS [20]
targetnumber [0]
targetname []

//if you use the timer
newtargettimer [0]

And lastly, I recommend being careful with this thing. If you have a dozen pawns scanning for enemies every frame it just might affect your frame rate "a bit".

Hope this makes sense and helps you.
Pain is only psychological.
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking Order

Post by metal_head »

I'll test it,just a little explanation I need:
so now,I put this in the script and than in the world editor I'll have to name every pawn entity,right?
User avatar
Juutis
Posts: 1511
Joined: Thu Jan 12, 2006 12:46 pm
Location: Finland

Re: Attacking Order

Post by Juutis »

You don't need to name every pawn. Just the enemies and allies.
Pain is only psychological.
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking Order

Post by metal_head »

sorry,that's what I ment,ok I'll try it,thanks!
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking Order

Post by metal_head »

amm,I didn't get where to put this... :oops:

Code: Select all

if(newtargettimer < self.time)
{
     newtarget();
     newtargettimer = self.time +(ammound of time);
}
User avatar
Juutis
Posts: 1511
Joined: Thu Jan 12, 2006 12:46 pm
Location: Finland

Re: Attacking Order

Post by Juutis »

Modified it a bit. Now it can target the player and has correct variables from perfectai (ALERTSIGHTDIST, HOSTILEPLAYER). Also returns true or false depending on if it found a new target.

Code: Select all

newtarget[ ()
{

for targetnumber=0 to MAXENEMYPAWNS step 1 //loop through all enemy pawns
{
     targetname = StringCopy("enemy" # targetnumber); //create the entityname of the _possible_ new target

     if(FastDistance(targetname,ALERTSIGHTDIST))  //if the new target is inside sight range
     {
          if(IsEntityVsible(targetname)) //if the new target is visible
          {
               SetTarget(targetname);

               if(EnemyExist(DAMAGEATTRIBUTE) < 3)  //if the new target isn't alive
               {
                    SetTarget(""); //no target
               }
               else
               {
                    return true; //new target is alive so keep it and break out of the loop
               }
          }
     }
}

if(HOSTILEPLAYER)  //if hostile to player
{
     if(FastDistance("Player",ALERTSIGHTDIST))  //if the player is inside sight range
     {
          if(IsEntityVsible("Player")) //if player is visible
          {
               TargetPlayer();

               if(EnemyExist(DAMAGEATTRIBUTE) < 3)  //if the player isn't alive
               {
                    SetTarget(""); //no target
               }
               else
               {
                    return true; //new target is alive so keep it and break out of the loop
               }
          }
     }
}

return false; //no target so return false
} ]
amm,I didn't get where to put this...
Sorry, it seems I didn't explain it very well. Whenever you want the pawn to find a new target you just need to put:

Code: Select all

newtarget();
So for example if you wanted to look for another target after losing sight of the current, one you'd replace:
(this can be found in all the attacking orders. monster_missile, monster_melee etc.)

Code: Select all

      if(enemy_vis = false)
      {
         self.think = LOSTFUNC;          // lost sight of enemy
         lost_time = time + LOSTTIME;
         SetHoldAtEnd(false);
         return 0;
      }
with

Code: Select all

      if(enemy_vis = false)
      {
         if(newtarget() = false) // if no other target
         {
            self.think = LOSTFUNC;          // lost sight of enemy
            lost_time = time + LOSTTIME;
            SetHoldAtEnd(false);
            return 0;
         }
      }
The timer thing was just an example of how you could use it. You could just put the timer in any of the attacking orders (monster_melee, monster_missile) and the pawn would find a new target every X seconds. For example:

Code: Select all

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))
      {
         AddExplosion("headshot",GetLastBoneHit(),0,0,0);
      }

      if(newtargettimer < self.time)
      {
           newtarget();
           newtargettimer = self.time + 2;
      }

      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)
      {
         if(newtarget() = false) // if no other target
         {
            self.think = LOSTFUNC;          // lost sight of enemy
            lost_time = time + LOSTTIME;
            SetHoldAtEnd(false);
            return 0;
         }
      }
      if(self.player_Y>self.current_Y)
      {
         Animate(SHOOTUP);
                        AddExplosion(FLASH,"Bip01 R Hand",0,0,0);
         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);
                        AddExplosion(FLASH,"FIREBONE",0,0,0);
         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;
         }
      }
   } ]
Would search for enemies every 2 seconds and whenever the pawn loses the current target.


Note: I haven't actually tested the script so make sure you run it with the console on so you see if there are any syntax errors. I'll try to test it when I have the time.
Pain is only psychological.
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking Order

Post by metal_head »

wow! it's working! but I noticed a little change in the framerate...hope that's because my computer got slow for the last 6 months (yep,the computer keeps getting slower and slower,no matter what I do,it's not because of viruses :( :D )
User avatar
bernie
RF Moderator
Posts: 1249
Joined: Tue Nov 15, 2005 10:07 am
Location: Ireland

Re: Attacking Order

Post by bernie »

yep,the computer keeps getting slower and slower,no matter what I do,it's not because of viruses
How much memory have you?
You just installed Vista didn't you? Vista is extremely memory hungry. You need loads more memory for Vista than you needed for XP.
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking Order

Post by metal_head »

yeah,that also,but when I reinstalled my computer with XP,it was also slow... my cimputer is old now,but I don't think 3.02Ghz ,1 GB ram and 256 MB video card should get that slow.
BTW,I'll search in the internet to see if it's possible to remove all thqat graphical extras comming with Vista,because I Don't need them and they take memory,right?
User avatar
bernie
RF Moderator
Posts: 1249
Joined: Tue Nov 15, 2005 10:07 am
Location: Ireland

Re: Attacking Order

Post by bernie »

Vista need 512mb ram just to sit and Idle doing nothing. You can get by on 1gb but to run games you need at least 2gb ram 4gb would be better.
User avatar
metal_head
Posts: 1244
Joined: Sat Jan 05, 2008 8:31 pm
Location: Bulgaria,Sofia
Contact:

Re: Attacking Order

Post by metal_head »

oh,not cool...I'll buy a new computer soon,but I don't have enogh money now :(
Post Reply