ZScriot item pickup problems [SOLVED]

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

ZScriot item pickup problems [SOLVED]

Postby TheRailgunner » Sun May 30, 2021 6:22 am

So, I've got a ZScript item pickup, but the main issue is that it can't not be picked up - i.e., it acts as if it has +INVENTORY.ALWAYSPICKUP set. I assume this is because it's a CustomInventory item that doesn't have any detectable item limit, and such won't check the player's inventory to see if there's room. The pickup itself is butchered from the coin pickup actor from HorrorMovieRei's Avarice Coins, modified to be pulled towards the player whenever it's close enough to Malice's Tractor Beam weapon (this function works):


Code: Select allExpand view

class NewAmmoPickup : CustomInventory
{
   Default
   {
   Radius 6;
   Height 10;
   //-COUNTITEM
   -INVENTORY.ALWAYSPICKUP
   //+INVENTORY.QUIET
   +DONTGIB
   Inventory.PickupMessage "Picked up a somewhat spent magazine for the Nishimura Seven Battle Rifle [+6 N7 Rounds]";
   }
  int aLifeTime;
  States
  {
  Spawn:
   "####" "#" 0;
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectile", 256) > 0),"Magnetized");
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectileA", 256) > 0),"Magnetized");
   "####" "#" 0 Bright
   {
   bNOGRAVITY = FALSE;
   bNOCLIP = FALSE;
   A_GiveInventory("ItemBounceToken",3);
   }
   Goto Air;
  Air:
    "####" "#" 2 Bright A_CheckFloor("Bounce");
    Loop;
  Bounce:
   "####" "#" 1 Bright
   {
   //A_StartSound("Coin/Bounce",6,0,0.25);
   A_ChangeVelocity(1,0,(CountInv("ItemBounceToken")*1.1),CVF_RELATIVE|CVF_REPLACE);
   A_TakeInventory("ItemBounceToken",1);
   }
   "####" "#" 1 Bright;
   "####" "#" 0 Bright A_JumpIfInventory("ItemBounceToken",1,"Air");
  Ground:
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectile", 256) > 0),"Magnetized");
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectileA", 256) > 0),"Magnetized");
   "####" "#" 0 A_JumpIfInventory("ItemBounceToken",1,"Air");
   "####" "#" 1 Bright
   {
   invoker.aLifeTime++;
   
   If (random(1,200)==1)
         {
         A_SpawnItemEx("HelsturmBulletTrail2Huge",random(radius,-radius),random(radius,-radius),random(0,height));
         }
         Else
         {
         A_Pain();
         }
   
   if(invoker.aLifeTime > 525 && GetCVAR("ItemModCleanup_options")==1)
      {
         A_FadeOut(0.1,FTF_REMOVE);
      }
   }
   Loop;
  Magnetized:
   //"####" A 0 A_JumpIf((CountProximity("TractorBeamProjectile", 64) < 1),"Ground");
    "####" "#" 1 Bright
   {
      if(!target)
      {
         A_CheckProximity("Spawn","PlayerPawn", 1024, 1, CPXF_SETTARGET|CPXF_CHECKSIGHT|CPXF_ANCESTOR);
         invoker.aLifeTime++;
      }
            
      if(target && Distance3D(target) < 1024 && CheckProximity("TractorBeamProjectile", 256.0) > 0)
      {
         invoker.aLifeTime = 35;
         if(target.GetPlayerInput(INPUT_BUTTONS, AAPTR_DEFAULT) & BT_ATTACK)
         {
         bNOGRAVITY = TRUE;
         bNOCLIP = TRUE;
         A_FaceTarget(0, 0);
         A_ChangeVelocity(cos(pitch) * 20, 0, sin(pitch) * -20, CVF_RELATIVE | CVF_REPLACE);
         }
         else
         {
         bNOGRAVITY = FALSE;
         bNOCLIP = FALSE;
         A_ClearTarget();
         A_ChangeVelocity(velx/1.5, vely/2, velz/4, CVF_REPLACE);
         A_GiveInventory("ItemBounceToken",random(1,2));
         }
      }
      else
      {
         bNOGRAVITY = FALSE;
         bNOCLIP = FALSE;
         A_ClearTarget();
         A_ChangeVelocity(velx/1.5, vely/2, velz/4, CVF_REPLACE);
         A_GiveInventory("ItemBounceToken",random(1,2));
         invoker.aLifeTime++;
      }
            
      if(target && target.health < 1)
      {
         bNOGRAVITY = FALSE;
         bNOCLIP = FALSE;
         A_ClearTarget();
         A_ChangeVelocity(velx/1.5, vely/2, velz/4, CVF_REPLACE);
         A_GiveInventory("ItemBounceToken",random(1,2));
      }
         
      If (random(1,200)==1)
         {
         A_SpawnItemEx("HelsturmBulletTrail2Huge",random(radius,-radius),random(radius,-radius),random(0,height));
         }
         Else
         {
         A_Pain();
         }
         
      if(invoker.aLifeTime > 525 && GetCVAR("ItemModCleanup_options")==1)
      {
         A_FadeOut(0.1,FTF_REMOVE);
      }
   }
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectile", 256) > 0),"Magnetized");
    Goto Spawn;
  Pickup:
    "####" "#" 0
   {
   A_GiveInventory("N7Ammo",6);
   A_StartSound("Weapons/N7/APickup",6,CHANF_LOCAL,0.25);
   }
    stop;
  }
}


Is there a way to get the actor to avoid being picked up, in, say, this case, the player has the maximum amount of the inventory item "N7Ammo"?
Last edited by TheRailgunner on Sun May 30, 2021 6:47 pm, edited 1 time in total.
User avatar
TheRailgunner
Words go here.
 
Joined: 08 Jul 2013

Re: ZScriot item pickup problems

Postby Jarewill » Sun May 30, 2021 6:37 am

I don't understand the exact issue, but if it's that the item won't be picked up anymore, it's because it's full.
If MaxAmount it not defined, it uses the default of 1 max, and since your item's Pickup state ends with the "stop" keyword, it gets picked up.
You could increase the MaxAmount to some high amount and modify the Pickup state to be like this:
Code: Select allExpand view
  Pickup:
    "####" "#" 0 A_JumpIfInventory("N7Ammo",0,2);
    "####" "#"
   {
   A_GiveInventory("N7Ammo",6);
   A_StartSound("Weapons/N7/APickup",6,CHANF_LOCAL,0.25);
   }
    stop;
    "####" "#";
    fail;

It's untested though, so I don't know if this will work.
Alternatively you could also make it remove itself once the player gets the item with an AttachToOwner or DoEffect override.

Also I think this should be in the scripting forum.
Jarewill
 
 
 
Joined: 21 Jul 2019

Re: ZScriot item pickup problems

Postby TheRailgunner » Sun May 30, 2021 7:13 am

Jarewill wrote:I don't understand the exact issue, but if it's that the item won't be picked up anymore, it's because it's full.
If MaxAmount it not defined, it uses the default of 1 max, and since your item's Pickup state ends with the "stop" keyword, it gets picked up.
You could increase the MaxAmount to some high amount and modify the Pickup state to be like this:
Code: Select allExpand view
  Pickup:
    "####" "#" 0 A_JumpIfInventory("N7Ammo",0,2);
    "####" "#"
   {
   A_GiveInventory("N7Ammo",6);
   A_StartSound("Weapons/N7/APickup",6,CHANF_LOCAL,0.25);
   }
    stop;
    "####" "#";
    fail;

It's untested though, so I don't know if this will work.
Alternatively you could also make it remove itself once the player gets the item with an AttachToOwner or DoEffect override.

Also I think this should be in the scripting forum.


So, I'll see if I can get a mod to move this to Scripting.

The problem isn't that the item ISN'T being picked up after the inventory is full, it's that it IS - for example, picking up a Stimpack even if I have 100 health. I CAN modify the code you posted to see if it'll work anyway (changing the inventory amount that triggers the jump from 0 to the item's maximum might work). The hope is that doing so doesn't trigger a game-crashing 0-tic state-jump loop.

EDIT: Tried altering the Stimpack pickup to no avail:

Code: Select allExpand view

class StimpackSpawn : NewAmmoPickup replaces Stimpack
{
   Default
   {
   -INVENTORY.ALWAYSPICKUP
   Radius 8;
   Height 16;
   Inventory.PickupMessage "$GOTSTIM";
   Scale 0.75;
   }
  States
  {
  Spawn:
   STIK A 0;
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectile", 256) > 0),"Magnetized");
   "####" "#" 0 A_JumpIf((CountProximity("TractorBeamProjectileA", 256) > 0),"Magnetized");
   "####" "#" 0 Bright
   {
   bNOGRAVITY = FALSE;
   bNOCLIP = FALSE;
   A_GiveInventory("ItemBounceToken",3);
   }
   Goto Air;
  Pickup:
    "####" "#" 0 A_JumpIfInventory("Health",100,2);
    "####" "#" 0
   {
   A_GiveInventory("TR_Stimpack",1);
   A_StartSound("items/stimpack/pickup",6,CHANF_LOCAL);
   }
    stop;
    "####" "#" 0;
    fail;
  }
}


It inherits from the other actor I posted - how do I get it to avoid being picked up if, in this example, the player is at maximum health?
User avatar
TheRailgunner
Words go here.
 
Joined: 08 Jul 2013

Re: ZScriot item pickup problems

Postby Jarewill » Sun May 30, 2021 7:32 am

A_JumpIfInventory treats 0 as max amount.
However when checking for health you have to use A_JumpIfHealthLower so you will need to edit the Pickup state:
Code: Select allExpand view
  Pickup:
    "####" "#" 0 A_JumpIfHealthLower(100,2);
    "####" "#" 0;
    fail;
    "####" "#" 0
   
{
   A_GiveInventory("TR_Stimpack",1);
   A_StartSound("items/stimpack/pickup",6,CHANF_LOCAL);
   }
    stop;
  }
Jarewill
 
 
 
Joined: 21 Jul 2019

Re: ZScriot item pickup problems [SOLVED]

Postby TheRailgunner » Sun May 30, 2021 8:47 am

Jarewill wrote:A_JumpIfInventory treats 0 as max amount.
However when checking for health you have to use A_JumpIfHealthLower so you will need to edit the Pickup state:
Code: Select allExpand view
  Pickup:
    "####" "#" 0 A_JumpIfHealthLower(100,2);
    "####" "#" 0;
    fail;
    "####" "#" 0
   
{
   A_GiveInventory("TR_Stimpack",1);
   A_StartSound("items/stimpack/pickup",6,CHANF_LOCAL);
   }
    stop;
  }


This seems to work - I also adapted it to the other items:

Code: Select allExpand view
class N7AmmoPickup : NewAmmoPickup
{
   Default
   {
   -INVENTORY.ALWAYSPICKUP
   Radius 6;
   Height 10;
   Inventory.PickupMessage "Picked up a somewhat spent magazine for the Nishimura Seven Battle Rifle [+6 N7 Rounds]";
   }
  States
  {
  Spawn:
   N7NP B 0;
   N7NP B 0 A_JumpIf((CountProximity("TractorBeamProjectile", 256) > 0),"Magnetized");
   N7NP B 0 A_JumpIf((CountProximity("TractorBeamProjectileA", 256) > 0),"Magnetized");
   N7NP B 0 Bright
   {
   bNOGRAVITY = FALSE;
   bNOCLIP = FALSE;
   A_GiveInventory("ItemBounceToken",3);
   }
   Goto Air;
  Pickup:
    "####" "#" 0 A_JumpIfInventory("N7Ammo", 0, 2);
    "####" "#" 0 A_Jump(256, 2);
    "####" "#" 0;
    fail;
    "####" "#" 0
   {
   A_GiveInventory("N7Ammo",6);
   A_StartSound("Weapons/N7/APickup",6,CHANF_LOCAL);
   }
    stop;
  }
}


Now all I have to do is sort out animated items (right now the new item pickups are designed for single-frame item animations) - thank you!
Last edited by TheRailgunner on Sun May 30, 2021 9:32 am, edited 1 time in total.
User avatar
TheRailgunner
Words go here.
 
Joined: 08 Jul 2013

Re: ZScriot item pickup problems

Postby Jarewill » Sun May 30, 2021 9:01 am

Wiki wrote:Note that if amount is 0, the jump is only performed if the actor is carrying the maximum number of that item. This is useful for checking whether the player has the maximum amount of ammo for a particular weapon, regardless of whether or not he's found a backpack.

Keep in mind that A_JumpIfInventory treats 0 as maximum amount, so you can simplify your Pickup state to just this:
Code: Select allExpand view
  Pickup:
    "####" "#" 0 A_JumpIfInventory("N7Ammo", 0, 2); //Check if the ammo amount is at max (360 or 720)
    "####" "#" 0 //If not then work
   {
   A_GiveInventory("N7Ammo",6);
   A_StartSound("Weapons/N7/APickup",6,CHANF_LOCAL);
   }
    stop;
    "####" "#" 0; //If yes then fail
    fail
Jarewill
 
 
 
Joined: 21 Jul 2019

Re: ZScriot item pickup problems [SOLVED]

Postby Player701 » Thu Jun 03, 2021 12:46 am

Just wanted to throw in my two cents here.

IMO, CustomInventory should be considered deprecated in ZScript for most purposes (except perhaps when working with overlays, but I can't say much about that since I haven't worked with them at all).

Things like A_JumpIfInventory("N7Ammo", 0, 2) are somewhat difficult to read and understand by their very nature, especially when there's a lot of them in your code. This can eventually lead to subtle bugs that might be very hard to track down - for example, when you add a new state definition to your Pickup sequence and forget to modify the jump offset, and as a result, it no longer points to the correct state.

Since you're using ZScript anyway, consider overriding TryPickup instead of using the Pickup state sequence. In this case, it's also enough to subclass your inventory item directly from Inventory instead of CustomInventory. The following code should be equivalent to Jarewill's last sample:

Code: Select allExpand view
override bool TryPickup(in out Actor toucher)
{
    if (!toucher.CheckInventory('N7Ammo', 0)) //Check if the ammo amount is at max (360 or 720)
    {
        // If not then work
        toucher.A_GiveInventory('N7Ammo', 6);
        toucher.A_StartSound("Weapons/N7/APickup", 6, CHANF_LOCAL);
       
        // This will make sure the item doesn't actually appear in the player's inventory
        // so that it can be "picked up" again without restrictions (apart from when TryPickup returns false)
        GoAwayAndDie();
       
        // Consider the pickup successful
        return true;
    }
   
    //If yes then fail
    return false;
}

A bit of explanation here:

  1. toucher is, obviously, the actor (i.e. player) trying to pick up the item;
  2. CheckInventory works the same way as A_JumpIfInventory, only without the actual jump (it returns true or false depending on the result of the check).
  3. GoAwayAndDie considers the item picked up but it doesn't actually appear in the player's inventory. We call it because the sole purpose of our item is to run some custom logic upon pickup, and its presence inside the inventory is not necessary at all.

Note that I couldn't quite understand the purpose of that code, though. If N7Ammo is an ammo type, it is possible to achieve the same result by creating a new subclass of N7Ammo with Amount set to 6, and no extra Pickup or TryPickup code is necessary.

The Use state sequence from CustomInventory can also be implemented in ZScript directly by overriding Use, if necessary. Also see ZScript_virtual_functions#Inventory for a list of methods that can be overridden.
User avatar
Player701
 
 
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support


Return to Scripting

Who is online

Users browsing this forum: TXTX and 1 guest