Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
rabidrage

Zombies shooting barrels code

Recommended Posts

So I'm not great with code.  Barely understand it.  That being said, I asked ChatGPT to help me with ACS code that'll make Zombiemen, Shotgunguys, Chaingunguys and WolfensteinSS shoot barrels when you're close to them.  It spit this out:

 

#define BLAST_RADIUS 256

#define ZOMBIEMAN 2001
#define SHOTGUNGUY 3002
#define CHAINGUY 3004
#define WOLFENSTEINSS 9

script "BarrelFinder" (int type) {
    int FindNearestBarrel() {
        // code to find the nearest barrel goes here
        return barrel;
    }

    int PlayerNumber() {
        // code to get the player's number goes here
        return player;
    }

    int barrel = FindNearestBarrel();
    int player = PlayerNumber();
    int distance = Distance(barrel, player);

    if (distance <= BLAST_RADIUS) {
        SetActorTarget(0, barrel);
    } else {
        SetActorTarget(0, player);
    }
}

script "BarrelHunter" (int type) {
    if (type == ZOMBIEMAN || type == SHOTGUNGUY || type == CHAINGUY || type == WOLFENSTEINSS) {
        BarrelFinder(type);
    }
}

script "BarrelHunter_onSpawn" (int type) {
    if (type == ZOMBIEMAN || type == SHOTGUNGUY || type == CHAINGUY || type == WOLFENSTEINSS) {
        BarrelFinder (type);
    }
}

script "BarrelHunter_onDeath" (int type) {
    if (type == ZOMBIEMAN || type == SHOTGUNGUY || type == CHAINGUY || type == WOLFENSTEINSS) {
        BarrelFinder (type);
    }
}

But I get this error when I try to compile:

Line 9 in file "C:\Program Files (x86)\Doom Builder 2\Plugins\Barrels.acs" ...
C:\Program Files (x86)\Doom Builder 2\Plugins\Barrels.acs:9: Missing semicolon.
>     int FindNearestBarrel()
>                          ^

I don't see where a semicolon goes on that line, and if I throw one in where I think it goes, it doesn't exactly fix the problem.  What's wrong with this?

Share this post


Link to post

Before anyone replies, I've updated it so monsters stop targeting barrels if you move out of range.  But it's the same issue with a damn semicolon, this time on line 9!

 

#define BLAST_RADIUS 256

script "BarrelHunter" (int type) {
    // get player's current target
    int playerTarget = GetActorTarget(0);
    // check if player's target is a barrel
    if(CheckActorClass(playerTarget, "barrel")) {
        // if it is, check the distance to the barrel
        int distance = Distance (playerTarget, 0);
        // if the distance is greater than the blast radius, target the player again
        if(distance > BLAST_RADIUS) {
            SetActorTarget(0, playerTarget);
        }
    }
    // if player doesn't have a barrel as target, find nearest barrel within blast radius
    else {
        int nearestBarrel = FindBarrelInRadius(0, BLAST_RADIUS);
        // if a barrel is found, set it as the target
        if(nearestBarrel) {
            SetActorTarget(0, nearestBarrel);
        }
    }
}

function int FindBarrelInRadius(int player, int radius) {
    int nearestBarrel = 0;
    int nearestDistance = radius + 1;
    // iterate through all barrels in the map
    for(int i = 1; i <= GetActorCount(); i++) {
        if(CheckActorClass(i, "barrel")) {
            // check the distance to the player
            int distance = Distance(i, player);
            // if the distance is less than the current nearest distance and within the blast radius
            if(distance < nearestDistance && distance <= radius) {
                nearestBarrel = i;
                nearestDistance = distance;
            }
        }
    }
    return nearestBarrel;
}

 

Share this post


Link to post

ACS dont know funtion FindBarrelInRadius, that's why it's giving you an error. 

 

If you want a new function, you have to define it as an action.

 

Defining it like int something() = ...  don't work with acs, wrong declaration.

 

https://zdoom.org/wiki/Functions

 

 

Wait wait wait, you have declared the function after you use it. How should compiler use it, when it's not decalred? Just move the function declaration before use of the function and it will work.

Edited by ramon.dexter

Share this post


Link to post

I've declared functions after using them, and they work just fine. It even says on the wiki that they "can be easily called from anywhere in your scripts or other functions. You can place functions anywhere in your script file."

 

I tried the code from above, and these are my questions:

  1. Do you have this at the top of your ACS file?  #include "zcommon.acs"
  2. What are GetActorTarget and SetActorTarget? I've never heard of them, and don't find anything when I search for them on Google (other than this thread). And I get errors related to them when I try that code. Compiler doesn't even get to line 9 because of GetActorTarget on line 5.
  3. What is Distance on line 9? There's no ACS function named "Distance" that I'm aware of.
Edited by The DANDY Company

Share this post


Link to post
1 hour ago, The DANDY Company said:

I've declared functions after using them, and they work just fine. It even says on the wiki that they "can be easily called from anywhere in your scripts or other functions. You can place functions anywhere in your script file."

 

I tried the code from above, and these are my questions:

  1. Do you have this at the top of your ACS file?  #include "zcommon.acs"
  2. What are GetActorTarget and SetActorTarget? I've never heard of them, and don't find anything when I search for them on Google (other than this thread). And I get errors related to them when I try that code. Compiler doesn't even get to line 9 because of GetActorTarget on line 5.
  3. What is Distance on line 9? There's no ACS function named "Distance" that I'm aware of.

As to the very first part of your question, no.  The rest of it?  I thought they should pertain to whatever the monsters in question are currently targeting and change them.  But I'm the last person who will actually know, as I cheated to make this at all.  Is there a function that would do those things?

Share this post


Link to post
3 hours ago, rabidrage said:

As to the very first part of your question, no.  The rest of it?  I thought they should pertain to whatever the monsters in question are currently targeting and change them.  But I'm the last person who will actually know, as I cheated to make this at all.  Is there a function that would do those things?

 

2 hours ago, rabidrage said:

As for "distance", I guess "proximity" is what I'd want to use?


Ah okay. I checked, and there’s a function called CheckProximity that might help. As for the targeting, I’m not sure yet. I will do more research and get back to you.

 

Edit: This might require some DECORATE changes as well to change the behavior for ZombieMan, ShotgunGuy, ChaingunGuy, and WolfensteinSS. If so, I will let you know.

Edited by The DANDY Company

Share this post


Link to post

Yes, I know Decorate, which I'm a thousand times better with--it's much easier for a non-coder to grasp.  But I was never able to make this work.  I'm impressed and extremely grateful!  Thank you!

 

I noticed it works beautifully, except I couldn't get the SS guy to do it.

 

My attempts involved trying to make Thing_Hate work, which gave me absurd results.  Either they'd ignore the barrels or stay on them after I left.

Share this post


Link to post

No problem. The SS guy works for me, but I'll double check it. Also, I need to make another change cause if the player goes out of range of the barrel and is also out of line of sight with the monster, the monster will keep attacking the barrel instead of searching for the player. I'll fix it and update the code in the above post.

Share this post


Link to post

I had that problem with a lot of my attempts, but the way you've done it hasn't demonstrated that problem on my end yet.

Share this post


Link to post

This works incredibly.  I want to include this in Rabid's Crap v31.  There hasn't been much I can come up with to improve enemy AI, but this is a huge step forward!

 

Share this post


Link to post

Sorry for the delay, it took a while to work out all the kinks that were present in the last version, plus I got busy with other stuff. This latest version should resolve everything. I ended up having to use a little ACS to easily perform a distance check that checks if the barrel is still in range of the target upon refiring. I couldn't figure out an easy way to do the distance check using DECORATE only since the check is performed between two pointers (the caller's target and tracer). So I added an ACS library for the distance check function, and everything else is still in DECORATE.

 

This version:

  • Resolves issues with infighting
  • Resolves issues that occurred when the original target (player or infighting monster) going out of range of the targeted barrel
  • Resolves issues during the refiring functions of ChaingunGuy and WolfensteinSS
  • Adds a couple more example rooms to demonstrate infighting
  • Added rotated sprites of WolfensteinSS shooting his gun (courtesy of Revenant100's sprite fixes) since it was difficult to see what he was shooting at when always facing forward (I suspect this might be why it seemed to not work correctly in the previous version)
  • Added comments to the code

Please let me know if you find any bugs when testing :)

 

DECORATE code:

 

const float BarrelExplosionRadius = 128.0;

//MyZombieMan is a custom ZombieMan that will target barrels near its current target (the player, or another monster if infighting).
ACTOR MyZombieMan : ZombieMan REPLACES ZombieMan
{
  Tag "Former Human"
  States
  {
  Missile:
    TNT1 A 0 //THIS STATE TRIES TO TARGET A BARREL BY CHECKING CERTAIN CRITERIA.
    {
      //If there is an existing tracer that meets the following criteria:
      // - Is a barrel
      // - Is in the caller's line-of-sight
      // - Is not dead (not already exploding)
      // - Is still within range of the target (player/monster) NOTE: This check uses ACS.
      if(CheckClass("ExplosiveBarrel",AAPTR_TRACER,TRUE)
      && A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP)
      && (CallACS("DistanceCheck")/65536.0) <= BarrelExplosionRadius)
      {
        //Make the barrel the new target, and store the original target as the tracer.
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else
      {
        //Otherwise, keep the current target and make sure the tracer is null (it might already be null).
        A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);

        //Then run a barrel check:
        //If any ExplosiveBarrel actors (parent class names are also checked) are within BarrelExplosionRadius
        //of the current target and in the current target's line-of-sight (since explosions don't damage thru walls)...
        if(CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT,AAPTR_TARGET) > 0)
        {
          //Make the closest of those barrels the tracer.
          CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_SETTRACER|CPXF_CLOSEST,AAPTR_TARGET);

          //If the tracer (barrel) is in the caller's line-of-sight and is not dead...
          if(A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP))
          {
            //Make the barrel the new target, and store the original target as the tracer.
            A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
          }
          else
          {
            //Otherwise, keep the current target and remove the barrel from the tracer pointer by making it null.
            A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
          }
        }
      }
    }
    POSS E 10 A_FaceTarget
    POSS F 8 A_PosAttack
    POSS E 8
    TNT1 A 0 //THIS STATE HANDLES THE POINTERS AFTER ATTACKING (BEFORE RETURNING TO THE SEE STATE).
    {
      //If the target is a barrel...
      if(CheckClass("ExplosiveBarrel",AAPTR_TARGET,TRUE))
      {
        //Restore the player/monster as the target and make the barrel the tracer.
        //This done so the caller will chase the correct actor (the player/monster) in the See state
        //and so the caller keeps targeting the same barrel each time it meets the criteria.
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      //Otherwise, if there is no target (barrel was destroyed) but there is still a tracer value stored (original target)...
      else if(IsPointerEqual(AAPTR_TARGET,AAPTR_NULL)
      && !IsPointerEqual(AAPTR_TRACER,AAPTR_NULL))
      {
         //Restore the original target (player/monster) and make the tracer pointer null.
         A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_NULL,0);
      }
    }
    Goto See
  }
}

//See MyZombieMan for comments.
ACTOR MyShotgunGuy : ShotgunGuy REPLACES ShotgunGuy
{
  Tag "Former Sergeant"
  States
  {
  Missile:
    TNT1 A 0
    {
      if(CheckClass("ExplosiveBarrel",AAPTR_TRACER,TRUE)
      && A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP)
      && (CallACS("DistanceCheck")/65536.0) <= BarrelExplosionRadius)
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else
      {
        A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
        if(CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT,AAPTR_TARGET) > 0)
        {
          CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_SETTRACER|CPXF_CLOSEST,AAPTR_TARGET);
          if(A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP))
          {
            A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
          }
          else
          {
            A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
          }
        }
      }
    }
    SPOS E 10 A_FaceTarget
    SPOS F 10 Bright A_SPosAttackUseAtkSound
    SPOS E 10
    TNT1 A 0
    {
      if(CheckClass("ExplosiveBarrel",AAPTR_TARGET,TRUE))
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else if(IsPointerEqual(AAPTR_TARGET,AAPTR_NULL)
      && !IsPointerEqual(AAPTR_TRACER,AAPTR_NULL))
      {
         A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_NULL,0);
      }
    }
    Goto See
  }
}

//MyChaingunGuy is mostly different from MyZombieMan/MyShotgunGuy due to repeat firing of his weapon.
ACTOR MyChaingunGuy : ChaingunGuy REPLACES ChaingunGuy
{
  Tag "Chaingunner"
  States
  {
  Missile:
    TNT1 A 0 //Same as MyZombieMan/MyShotgunGuy
    {
      if(CheckClass("ExplosiveBarrel",AAPTR_TRACER,TRUE)
      && A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP)
      && (CallACS("DistanceCheck")/65536.0) <= BarrelExplosionRadius)
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else
      {
        A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
        if(CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT,AAPTR_TARGET) > 0)
        {
          CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_SETTRACER|CPXF_CLOSEST,AAPTR_TARGET);
          if(A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP))
          {
            A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
          }
          else
          {
            A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
          }
        }
      }
    }
    CPOS E 10 A_FaceTarget
    CPOS FE 4 Bright A_CPosAttack
    CPOS F 1 //This state is a substitute for A_CPosRefire that also performs the usual barrel check functions.
    {
      //If the target is a barrel...
      if(CheckClass("ExplosiveBarrel",AAPTR_TARGET,TRUE))
      {
        //Restore the player/monster as the target and make the barrel the tracer.
        //This done so the caller will chase the correct actor (the player/monster) in the See state
        //and so the caller keeps targeting the same barrel each time it meets the criteria.
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      //Otherwise, if there is no target (barrel was destroyed) but there is still a tracer value stored (original target)...
      else if(IsPointerEqual(AAPTR_TARGET,AAPTR_NULL)
      && !IsPointerEqual(AAPTR_TRACER,AAPTR_NULL))
      {
         //Restore the original target (player/monster) and make the tracer pointer null.
         A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_NULL,0);
      }

      //If the attack would have been aborted...
      if(A_MonsterRefire(40,"See"))
      {
        //Jump to the See state.
        return A_Jump(256,"See");
      }
      //Otherwise (attack not aborted), perform another barrel check...
      else if(CheckClass("ExplosiveBarrel",AAPTR_TRACER,TRUE)
      && A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP)
      && (CallACS("DistanceCheck")/65536.0) <= BarrelExplosionRadius)
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else
      {
        A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
        if(CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT,AAPTR_TARGET) > 0)
        {
          CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_SETTRACER|CPXF_CLOSEST,AAPTR_TARGET);
          if(A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP))
          {
            A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
          }
          else
          {
            A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
          }
        }
      }

      //Return an empty state since we return a jump function in the refire section and there must be a matching return of the same type.
      return state("");
    }
    Goto Missile+2
  }
}

//MyWolfensteinSS is the same as MyChaingunGuy.
ACTOR MyWolfensteinSS : WolfensteinSS REPLACES WolfensteinSS
{
  Tag "Wolfenstein SS"
  States
  {
  Missile:
    TNT1 A 0
    {
      if(CheckClass("ExplosiveBarrel",AAPTR_TRACER,TRUE)
      && A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP)
      && (CallACS("DistanceCheck")/65536.0) <= BarrelExplosionRadius)
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else
      {
        A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
        if(CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT,AAPTR_TARGET) > 0)
        {
          CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_SETTRACER|CPXF_CLOSEST,AAPTR_TARGET);
          if(A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP))
          {
            A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
          }
          else
          {
            A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
          }
        }
      }
    }
    SSWV E 10 A_FaceTarget
    SSWV F 10 A_FaceTarget
    SSWV G 4 Bright A_CPosAttack
    SSWV F 6 A_FaceTarget
    SSWV G 4 Bright A_CPosAttack
    SSWV F 1
    {
      if(CheckClass("ExplosiveBarrel",AAPTR_TARGET,TRUE))
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else if(IsPointerEqual(AAPTR_TARGET,AAPTR_NULL)
      && !IsPointerEqual(AAPTR_TRACER,AAPTR_NULL))
      {
         A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_NULL,0);
      }

      if(A_MonsterRefire(40,"See"))
      {
        return A_Jump(256,"See");
      }
      else if(CheckClass("ExplosiveBarrel",AAPTR_TRACER,TRUE)
      && A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP)
      && (CallACS("DistanceCheck")/65536.0) <= BarrelExplosionRadius)
      {
        A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
      }
      else
      {
        A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
        if(CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT,AAPTR_TARGET) > 0)
        {
          CountProximity("ExplosiveBarrel",BarrelExplosionRadius,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_SETTRACER|CPXF_CLOSEST,AAPTR_TARGET);
          if(A_JumpIfTargetInLOS("Null",0,JLOSF_CHECKTRACER|JLOSF_DEADNOJUMP))
          {
            A_RearrangePointers(AAPTR_TRACER,AAPTR_DEFAULT,AAPTR_TARGET,0);
          }
          else
          {
            A_RearrangePointers(AAPTR_DEFAULT,AAPTR_DEFAULT,AAPTR_NULL,0);
          }
        }
      }

      return state("");
    }
    Goto Missile+2
  }
}

 

ACS library code:

 

#library "brlacs"
#include "zcommon.acs"

Script "DistanceCheck" (void)
{
	int caller_OldTID;
	int caller_TempTID;
	int target_OldTID;
	int target_TempTID;
	int tracer_OldTID;
	int tracer_TempTID;
	int distance;

	//Set up caller TIDs
	caller_OldTID = ActivatorTID();
	caller_TempTID = UniqueTID();
	Thing_ChangeTID(0,caller_TempTID);

	//Set up target TIDs
	SetActivator(0,AAPTR_TARGET);
	target_OldTID = ActivatorTID();
	target_TempTID = UniqueTID();
	Thing_ChangeTID(0,target_TempTID);

	//Set up tracer TIDs
	SetActivator(caller_TempTID);
	SetActivator(0,AAPTR_TRACER);
	tracer_OldTID = ActivatorTID();
	tracer_TempTID = UniqueTID();
	Thing_ChangeTID(0,tracer_TempTID);

	//Reset activator to original caller (not necessary, but nice to have)
	SetActivator(caller_TempTID);

	//Call distance function and set resulting value
	distance = fdistance(target_TempTID,tracer_TempTID);
	SetResultValue(distance);

	//Restore TIDs
	Thing_ChangeTID(caller_TempTID,caller_OldTID);
	Thing_ChangeTID(target_TempTID,target_OldTID);
	Thing_ChangeTID(tracer_TempTID,tracer_OldTID);
}

function int fdistance (int tid1, int tid2)
{
	int len;
	int y = getactory(tid1) - getactory(tid2);
	int x = getactorx(tid1) - getactorx(tid2);
	int z = getactorz(tid1) - getactorz(tid2);

	int ang = vectorangle(x,y);
	if(((ang+0.125)%0.5) > 0.25) len = fixeddiv(y, sin(ang));
	else len = fixeddiv(x, cos(ang));

	ang = vectorangle(len, z);
	if(((ang+0.125)%0.5) > 0.25) len = fixeddiv(z, sin(ang));
	else len = fixeddiv(len, cos(ang));

	return len;
}

 

 

BarrelTestV2.zip

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×