Proper "Pickup" State In ZScript

Mon Oct 25, 2021 4:04 am

While converting DECORATE code to ZScript in encountered bug, that are not allowing me to pickup item.
Idea is to have, for example, "AK47" as weapon and two tricky items: "AK47_pkup" for new weapon, that are spawning in game's world with corresponding ammo and "AK47" dropped, that contains no ammo at all, 'cause player drop "AK47" away with grabbing all ammo from magazine.

This was DECORATE code:
Code:
ACTOR APS_pkup : CustomInventory
{
   Speed 8
   +NOBLOCKMAP
   Inventory.PickupSound "misc/pkupitem"
   Inventory.PickupMessage "Picked up a APS!"
   Scale 0.22
   States
   {
   Spawn:
      APSL B 26 NoDelay A_SpawnItemEx("ammo_9x18mm_pkup",0,0,0,velx,vely,velz)
      TNT1 A 0 A_ChangeFlag("NOBLOCKMAP", false)
      APSL B -1
      Wait
   Pickup:
      TNT1 A 0 A_JumpIfInventory("HasPistol", 1, 4)
      TNT1 A 0 A_GiveInventory("APS")
      TNT1 A 0 A_GiveInventory("Mag_APS", 20)
      TNT1 A 0 A_GiveInventory("HasPistol")
      stop
      TNT1 A 0
      fail
   }
}

ACTOR APS_dropped : APS_pkup
{
   States
   {
   Spawn:
      APSL B 52
      TNT1 A 0 A_ChangeFlag("NOBLOCKMAP", false)
      APSL B -1
      Wait
   Pickup:
      TNT1 A 0 A_JumpIfInventory("HasPistol", 1, 3)
      TNT1 A 0 A_GiveInventory("APS")
      TNT1 A 0 A_GiveInventory("HasPistol")
      stop
      TNT1 A 0
      fail
   }
}

This code worked well in DECORATE, but i converted it to ZScript and now only weapon itself can be picked up, but no "_pkup" and "_dropped" variants.

Here is ZScript code:
Code:
Class APS_pkup : Inventory
{
   Default
   {
      Speed 8;
      +NoBlockMap;
      Inventory.PickupSound "misc/pkupitem";
      Inventory.PickupMessage "Picked up a APS!";
      Scale 0.18;
   }
   States
   {
      Spawn:
         APSL B 26 NoDelay A_SpawnItemEx("ammo_9x18mm_pkup",0,0,0,vel.x,vel.y,vel.z);
         TNT1 A 0 { bNoBlockMap==false; }
         APSL B -1;
         Wait;
      Pickup:
         TNT1 A 0 A_JumpIfInventory("HasPistol",1,4);
         TNT1 A 0 A_GiveInventory("APS");
         TNT1 A 0 A_GiveInventory("Mag_APS",20);
         TNT1 A 0 A_GiveInventory("HasPistol");
         Stop;
         TNT1 A 0;
         Fail;
   }
}

Class APS_dropped : APS_pkup
{
   States
   {
      Spawn:
         APSL B 52;
         TNT1 A 0 { bNoBlockMap==false; }
         APSL B -1;
         Wait;
      Pickup:
         TNT1 A 0 A_JumpIfInventory("hasPistol",1,3);
         TNT1 A 0 A_GiveInventory("APS");
         TNT1 A 0 A_GiveInventory("HasPistol");
         Stop;
         TNT1 A 0;
         Fail;
   }
}

I converted "CustomInvetory" to just "Inventory", 'cause (as i read up in the wiki) it was created for simple scripted events a way before ZScript. Also "A_ChangeFlag" now is "bFLAG==true/false" as well. Same with "VelX -> Vel.X" and etc.
There is no error in usual logs of GZDoom. Just weapons with sprites, that can't be picked up at all...
Where this little bug are appeared after converting code?

Re: Proper "Pickup" State In ZScript

Mon Oct 25, 2021 5:04 am

Well, zscript has more intricate behaviour. I'm note sure if I'll describe it properly, but zscript ignores any lines in pickup. So, this will never work.
Actually, zscript allows you to use normal logic instead of A_JumpIf() functions.

Use this instead:
Code:
TNT1 A 0 {
    if(CheckInventory("HasPistol", 1)) {
        return ResolveState("noPickup");
    } else {
        return resolveState("doPickup");
    }
    return resolveState(null);
}

Or better with casting the player:
Code:
TNT1 A 0 {
    let pawn = yourPlayerClass(self); //replace 'yourPlayerClass' with the classname of your player
    if(pawn.CountInv("haspistol") > 0) {
        return ResolveState("noPickup");
    } else {
        return resolveState("doPickup");
    }
    return resolveState(null);
}

Not 100% sure with code, whipped it out of head without testing. But something like that.

All you have to do is defined new NoPickup and DoPickup states.

Re: Proper "Pickup" State In ZScript

Mon Oct 25, 2021 6:00 am

Even in ZScript you need to inherit from CustomInventory to get the Pickup state to work. The base Inventory class does not handle this at all.

Re: Proper "Pickup" State In ZScript

Tue Oct 26, 2021 4:36 am

Even with "CustomInvetory" instead of just "Inventory" it not working.
For now, i am gonna try possible fix made by @ramon.dexter.

UPD: I have a bizarre idea.
What if we can get rid of "_pkup" and "_dropped" versions of weapon?
Something like this right inside of usual weapon itself:
Code:
      Spawn:
         APSL B 1
         {
            if(invoker.isDropped==true)
            {
               return resolveState("emptySpawn");
            }
            else
            {
               return resolveState("fullSpawn");
            }
         }
         Wait;
      emptySpawn:
         APSL B -1;
         Wait;
      fullSpawn:
         APSL B 26 NoDelay A_SpawnItemEx("ammo_9x18mm_pkup",0,0,0,vel.x,vel.y,vel.z);
         TNT1 A 0 { bNOBLOCKMAP==false; }
         APSL B -1;
         Wait;
      Pickup:
         TNT1 A 0
         {
            if(CheckInventory("HasPistol",1))
            {
               return ResolveState("noPickup");
            }
            else
            {
               if(invoker.isDropped==true)
               {
                  return resolveState("emptyPickup");
               }
               else
               {
                  return resolveState("fullPickup");
               }
            }
            return resolveState(null);
         }
      emptyPickup:
         TNT1 A 0 A_GiveInventory("APS");
         TNT1 A 0 A_GiveInventory("hasPistol");
      fullPickup:
         TNT1 A 0 A_GiveInventory("APS");
         TNT1 A 0 A_GiveInventory("Mag_APS",20);
         TNT1 A 0 A_GiveInventory("hasPistol");
      noPickup:
         TNT1 A 0;
         Fail;

After dropping this weapon it's "isDropped" var gonna be "true".
In that state game can check if player has free space for this gun and then check, if this gun was dropped in the past (which gonna always lead to magazine's discharge with bullets that can go into player's backpack. If it is player's first time, then he can have gun with charged magazine.
I can't think now about something like player, that can't has free space in his backpack, so ammo from magazine then can be dropped as basic ammo pickup item.
What is the proper method to implement this? Using variables inside of classes not easy task for me...

Re: Proper "Pickup" State In ZScript

Tue Oct 26, 2021 7:01 am

RastaManGames wrote:Even with "CustomInvetory" instead of just "Inventory" it not working.
For now, i am gonna try possible fix made by @ramon.dexter.


Yeah, it cannot work with your solution, because even CutomInventory classes basically ignore any durations in Use/Pickup states, so the A_Jump just cannot jump. It just dont work the same as weapons and other. So it cannot decide anything, it cannot jump anywhere. Therefore, I proposed the zscript solution, which only works.

Also, for your 'wild" solution: It would be better to store the variable in player class. This way I'm able to, for example, store the class of the equipped weapon. This is used to automatically give player certain weapon (bare hands, so player is unable to attack) and when needed, I'm able to return him previously equipped weapon.

Re: Proper "Pickup" State In ZScript

Wed Oct 27, 2021 6:18 am

I think, since you already use ZScript, instead of littering your code with more hacks, to implement a proper TryPickup method where you have far more control over what happens.

Re: Proper "Pickup" State In ZScript

Wed Oct 27, 2021 7:45 am

ramon.dexter wrote:because even CutomInventory classes basically ignore any durations in Use/Pickup states, so the A_Jump just cannot jump.
A_Jump and its ilk (A_JumpIfInventory etc.) work just fine in CustomInventory's Pickup state. See the powerups in Samsara for an example. Please double check things if you're not sure before spouting off about them, you have a history of doing this and it just creates confusion and frustration.