Author Topic: [Solved] Getting Zombie distracted by a Pipe Bomb weapon  (Read 3173 times)

I want to make the default zombie bots distracted and only focus on the pipe bomb. In the video, you'll see that the bots run to it first, then they leave it alone and go ahead and attack the player instead, then repeat. I just want them to focus on the pipe bomb instead of doing that. Then they can return to their normal roots after the pipe bomb explodes, of course. I tried looking at Bot_Dogs but I had no luck looking for something to use in that code, and I'm not sure how to do it myself.

I also ripped the weapon out of Gamemode_Zombie, but still functions the same.

Video of the Pipe Bomb

Here's the code for the function to make the bots follow the weapon.
Code: [Select]
package PipeSpawn
{
function Projectile::spawnPipeFlash(%this,%flashcount)
{
   %pos = %this.getPosition();
   
   if(%flashCount % 4 == 0)
   {
      %radius = 5000;
      %searchMasks = $TypeMasks::PlayerObjectType;
      InitContainerRadiusSearch(%pos, %radius, %searchMasks);
      while ((%targetid = containerSearchNext()) != 0 )
      {
         if(%targetid.getClassName() $= "AIPlayer")
         {
          if(%targetid.hType $= "Zombie")
          {
         %targetid.setMoveObject(%this);
         %targetid.setAimObject(%this);
        }
         }
      }
   }
   
   if(%flashcount < 5)
   {
      %sound = Phone_Tone_1_Sound;
      %time = 750;
   }
   else if(%flashcount < 10)
   {
      %sound = Phone_Tone_3_Sound;
      %time = 250;
   }
   else
   {
      %this.explode();
      return;
   }
   
   %this.schedule(%time,spawnPipeFlash,%flashcount+1);
   serverPlay3d(%sound,%pos); //if(%flashCount % 2 == 0)
   
   %p = new Projectile()
   {
      dataBlock = sPipeBombLightProjectile;
      initialPosition = %pos;
      initialVelocity = "0 0 1";
      sourceObject = %this.sourceObject;
      client = %this.client;
      sourceSlot = 0;
      originPoint = %this.originPoint;
   };
   if(isObject(%p))
   {
      MissionCleanup.add(%p);
      %p.setScale(%this.getScale());
   }
}
};activatePackage(PipeSpawn);
« Last Edit: February 06, 2019, 09:55:32 PM by Spartan224 »

Through code, turn the bot activation off so it has no ai, then have it move towards the pipe bomb transform. There are only two functions you need, I'm sure one of them is aiplayer.movetowards or something. Then when it detonates, reactivate the group of bots so they resume their normal evented behavior

I thought of that as well, but I'm not sure how to get the zombie bots around the pipe bomb's radius disabled, then re-enabling them if they survive after the detonation, I think that the SetBotPowered event has that though, so I could use that.

Use a radius search around the bomb that checks all bots and adds them to a simgroup or something. Make sure you check each iteration and skip any bots already in the group. When it detonates, iterate through the group, activating all the members again, then destroy the group

I tried using the stopHoleloop(); line when the pipe bomb spawns in, but that made the bots stop whatever they're doing for 1 second then head to the bomb. Which is weird and I'm wondering if it's possible to fix that, I'll record a video to show the problem.

Code: [Select]
      %radius = 5000;
      %searchMasks = $TypeMasks::PlayerObjectType;
      InitContainerRadiusSearch(%pos, %radius, %searchMasks);
      while ((%targetid = containerSearchNext()) != 0 )
      {
         if(%targetid.getClassName() $= "AIPlayer")
         {
          if(%targetid.hType $= "Zombie")
          {
         %targetid.setMoveObject(%this);
         %targetid.setAimObject(%this);
%targetid.stopHoleLoop(0);

Still working on figuring out how to reactivate them with what you suggested.
« Last Edit: February 02, 2019, 03:45:58 PM by Spartan224 »

I tried using the stopHoleloop(); line when the pipe bomb spawns in, but that made the bots stop whatever they're doing for 1 second then head to the bomb. Which is weird and I'm wondering if it's possible to fix that, I'll record a video to show the problem.

Code: [Select]
      %radius = 5000;
      %searchMasks = $TypeMasks::PlayerObjectType;
      InitContainerRadiusSearch(%pos, %radius, %searchMasks);
      while ((%targetid = containerSearchNext()) != 0 )
      {
         if(%targetid.getClassName() $= "AIPlayer")
         {
          if(%targetid.hType $= "Zombie")
          {
         %targetid.setMoveObject(%this);
         %targetid.setAimObject(%this);
%targetid.stopHoleLoop(0);

Still working on figuring out how to reactivate them with what you suggested.
You should keep it like that only have them look at the pipe bomb just to add exaggeration

You should keep it like that only have them look at the pipe bomb just to add exaggeration
I want to get the pipe bomb working similarly like it does in the original Gamemode_Zombie where they go to it and stay distracted until it explodes though, I thought of using that idea for a flashbang weapon.

Perhaps not the most optimal solution, but does this work? I have added comments where I added code.
Code: [Select]
package PipeSpawn
{
function Projectile::spawnPipeFlash(%this,%flashcount)
{
   %pos = %this.getPosition();
   //Count how many zombies
   %zmbcount = 0;
   
   if(%flashCount % 4 == 0)
   {
      %radius = 5000;
      %searchMasks = $TypeMasks::PlayerObjectType;
      InitContainerRadiusSearch(%pos, %radius, %searchMasks);
      while ((%targetid = containerSearchNext()) != 0 )
      {
         if(%targetid.getClassName() $= "AIPlayer")
         {
            if(%targetid.hType $= "Zombie")
    {
%targetid.stopHoleLoop();
%targetid.setmoveobject(%this);
%targetid.setaimobject(%this);
//Remember targeted zombie and add it to the list.
%targetzombie[%zmbcount] = %targetid;
%zmbcount++;
     }
          }
      }
   }
   
   if(%flashcount < 5)
   {
      %sound = Phone_Tone_1_Sound;
      %time = 750;
   }
   else if(%flashcount < 10)
   {
      %sound = Phone_Tone_3_Sound;
      %time = 250;
   }
   else
   {
      %this.explode();
      //Return zombies to its usual state if it survives
      for(%i = 0; %i <= %zmbcount; %i++)
      {
         if(isObject(%targetzombie[%i]))
         {
     %targetzombie[%i].startHoleLoop(1);
}
      }
      return;
   }
   
   %this.schedule(%time,spawnPipeFlash,%flashcount+1);
   serverPlay3d(%sound,%pos); //if(%flashCount % 2 == 0)
   
   %p = new Projectile()
   {
      dataBlock = sPipeBombLightProjectile;
      initialPosition = %pos;
      initialVelocity = "0 0 1";
      sourceObject = %this.sourceObject;
      client = %this.client;
      sourceSlot = 0;
      originPoint = %this.originPoint;
   };
   if(isObject(%p))
   {
      MissionCleanup.add(%p);
      %p.setScale(%this.getScale());
   }
}
};activatePackage(PipeSpawn);

Sure, let me try it out now.  I might also use that code for a bile bomb if it works correctly.

EDIT: So the bots that end up surviving the blast or just weren't nearby still target the pipe bomb's original position even though it already exploded. Even if I try shooting the bots, they wouldn't care and still want to move to the location of the pipe bomb's location. I'll add a video to show this issue.

https://www.youtube.com/watch?v=eM_UGyboLAM&feature=youtu.be
« Last Edit: February 04, 2019, 05:47:41 PM by Spartan224 »

The code literally stops the bot loop, so it works like the code says it should.

From what i have seen the bot code makes bots like zombies constantly search for the closest player.

I am gonna propose you overwrite the function AIPlayer::hFindClosestPlayer to find the closest available pipe bomb if the bot is of a zombie type literally on top of the original search code.
You would have to keep track of the projectiles in that case though.

Any other ideas are welcome.
EDIT ALREADY:
Oof, just saw that the solution was already explained, you just still need to save the affected bots in a SimGroup and when the pipebomb explodes make sure the loop on the saved group starts again.
Then again, shutting down the bot loop might not always be so nice because it also means they won't do any of their special loop behaviours.
« Last Edit: February 04, 2019, 06:09:08 PM by lordician »

pipe bomb loop: keep searching for bots nearby and run %bot.stopHoleLoop(); on them, then make them look at pipe bomb location and walk in that direction

once pipe bomb explodes: search for nearby bots (in a slightly larger radius) and run %bot.startholeloop() on them.

pipe bomb loop: keep searching for bots nearby and run %bot.stopHoleLoop(); on them, then make them look at pipe bomb location and walk in that direction

once pipe bomb explodes: search for nearby bots (in a slightly larger radius) and run %bot.startholeloop() on them.
Revive provided the top part which helped me understand how that works, but the main issue now is that the bots won't resume their loop once the pipe bomb's gone.
Code: [Select]
      %this.explode();
      //Return zombies to its usual state if it survives
      for(%i = 0; %i <= %zmbcount; %i++)
      {
         if(isObject(%targetzombie[%i]))
         {
     %targetzombie[%i].startHoleLoop(1);
Would I have to make another       InitContainerRadiusSearch       for it to find the bots that were disabled?
« Last Edit: February 04, 2019, 06:32:59 PM by Spartan224 »

add them to a simgroup then you wont have to search because you'll have all the already disabled bots saved. the whole point of the simgroup is to keep track of the disabled bots so they can be re-enabled later. you dont even need a simgroup either you can just use one string with a list of all the objectids of the disabled bots like PipeProjectileInstance.disabl edBots = "44432 44438 44439 44452"; and loop through that string to re-enable them.

thats probably faster and uses less memory than a simgroup

if you have a stringContains function handy you can use that to check the bots if they are already in the list. like

if(!contains(PipeProjectileInstance.disabl edBots,%currBot))
     PipeProjectileInstance.disabl edBots = PipeProjectileInstance.disabl edBots SPC %currBot;

that basically checks if the list already has the disabled bot in it and if it doesn't, it adds the bots ID to the list. Later, just loop through it like

for(%i=0;%i<(%bot=PipeProjectileInstance.disabledBots.getWordCount());%i++) {
         %bot.startHoleLoop(1);
         }

but make sure the above is packaged and parented into the projectile::delete method so that that routine is run just before the projectile explodes and is deleted
       
« Last Edit: February 04, 2019, 08:39:16 PM by PhantOS »

Hmmm, yeah I could try that.

Sorry for the double post, but I managed to get it working, sort of. I used a different function, like what Conan suggested to search for bots after the explosion to re-enable them

Here's the code I added in, which only works out of minigames for some reason?
Code: [Select]
function sPipeBombProjectile::OnExplode(%this, %obj, %col, %amt, %fade)
{
Parent::OnExplode(%this, %obj, %col, %amt, %fade);
  %radius = 5000;
      %searchMasks = $TypeMasks::PlayerObjectType;
      InitContainerRadiusSearch(%pos, %radius, %searchMasks);
      while ((%targetid = containerSearchNext()) != 0 )
      {
         if(%targetid.getClassName() $= "AIPlayer")
         {
            if(%targetid.hType $= "Zombie")
    {
%targetid.startHoleLoop();
     }
          }
      }
}
« Last Edit: February 05, 2019, 05:30:19 PM by Spartan224 »