calling overlay from override

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.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
ramon.dexter
Posts: 1562
Joined: Tue Oct 20, 2015 12:50 pm
Graphics Processor: nVidia with Vulkan support
Location: Kozolupy, Bohemia

calling overlay from override

Post by ramon.dexter »

So, I've got a item that uses overlays. When I call the overlay from States using Use abuse, everything works. But I wanted to avoid the Use abuse and use proper zscript approach by overriding bool Use(). Everything works, save for overlay. I just don't know how to call the overlay from the override.

Here is what I have with the Use abuse. It works.

Code: Select all

class soaBinocular : soaPickup {	
	bool binocUsed;
	action void W_equipBinoc(void) {
		if ( player == null ) {
			return;
		}
		let pawn = wastelandRanger(self);
		TextureID id_I_BNC2 = TexMan.CheckForTexture("I_BNC2", 0, 0);
		pawn.selectedWeapon = Weapon(pawn.player.readyWeapon);
		A_GiveInventory("binoc_weapon", 1);
		A_SelectWeapon("binoc_weapon");
		A_Overlay(7, "Binoc");
		invoker.binocUsed = true;
		invoker.icon = id_I_BNC2;
	}
	action void W_RemoveBinoc(void) {
		if ( player == null ) {
			return;
		}
		let pawn = wastelandRanger(self);
		TextureID id_I_BNC1 = TexMan.CheckForTexture("I_BNC1", 0, 0);
		A_SelectWeapon(pawn.selectedWeapon.GetClassName(), SWF_SELECTPRIORITY);
		A_TakeInventory("binoc_weapon", 1);
		A_ClearOverlays(7, 7);
		invoker.binocUsed = false;
		invoker.icon = id_I_BNC1;
	}
	Default {
		//$Category "SoA/Items"
		//$Color 17
		//$Title "Dalekohled"		
		+INVENTORY.INVBAR
		Tag "$T_Binocular";
		Inventory.Icon "I_BNCL";
		//Inventory.Amount 1;
		//Inventory.MaxAmount 2;
		Mass mass_binoc;
		Scale 0.4;
	}
	States {
		Spawn:
			DUMM A -1;
			Stop;
		Use:
			TNT1 A 0 {				
				if ( !invoker.binocUsed ) {
					return resolveState("Equip");
				} else {
					return resolveState("Unequip");
				}
				return resolveState(null);
			}
			Fail;
		Equip:
			TNT1 A 0 W_equipBinoc();
			Fail;
		Unequip:
			TNT1 A 0 W_RemoveBinoc();
			Fail;
		Binoc:
			RBPY ABCD 4;
			loop;
			
	}
}
And here is how I made it with Use() override:

Code: Select all

class soaBinocular : soaPickup {
	
	bool binocUsed;
	

	override bool Use(bool Pickup) {
		TextureID id_I_BNC2 = TexMan.CheckForTexture("I_BNC2", 0, 0);
		TextureID id_I_BNC1 = TexMan.CheckForTexture("I_BNC1", 0, 0);
		let pawn = wastelandRanger(owner);
		if ( !binocUsed ) { //equip binocular		
			pawn.selectedWeapon = Weapon(pawn.player.readyWeapon);
			pawn.A_GiveInventory("binoc_weapon", 1);
			pawn.A_SelectWeapon("binoc_weapon");
			self.A_Overlay(7, "Binoc");
			self.binocUsed = true;
			self.icon = id_I_BNC2;
		} else { //unequip binocular		
			pawn.A_SelectWeapon(pawn.selectedWeapon.GetClassName(), SWF_SELECTPRIORITY);
			pawn.A_TakeInventory("binoc_weapon", 1);
			self.A_ClearOverlays(7, 7);
			self.binocUsed = false;
			self.icon = id_I_BNC1;
		}
		return false; //do not use the item
	}

	Default {
		//$Category "SoA/Items"
		//$Color 17
		//$Title "Dalekohled"		
		+INVENTORY.INVBAR
		Tag "$T_Binocular";
		Inventory.Icon "I_BNCL";
		//Inventory.Amount 1;
		//Inventory.MaxAmount 2;
		Mass mass_binoc;
		Scale 0.4;
	}
	States {
		Spawn:
			DUMM A -1;
			Stop;
		Use:
			TNT1 A 0;
			Stop;
		Binoc:
			RBPY ABCD 4;
			loop;
			
	}
}
Here everything works, save for the overlay. I tried using self.A_Overlay() and pawn.A_Overlay(), but the overlay state is not displayed. How do I properly call the overlay states from inside the override?
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: calling overlay from override

Post by Player701 »

Hey, perhaps I'm a bit late to the party, but here's the gist: A_Overlay will not work like that because it expects to be called from a weapon or a CustomInventory state sequence. If you call Owner.A_Overlay(...), the engine will look for your overlay state definition in the owner class (which is usually the player) and not find it. (Calling without the Owner. prefix is obviously pointless because you want an overlay for the player, not for the item.)

It is, however, possible to emulate A_Overlay in ZScript since it doesn't do much aside from creating a PSprite and setting its state. It may sound a bit troublesome, which is why I guess most people use CustomInventory for that. Actually, this might be the only valid use case for CustomInventory in the ZScript era.

Anyway, here's what you should do. First, you either need to inherit your item class from StateProvider in case you want access to common function calls (e.g. weapon attacks and such); if not, you can derive from Inventory. In any case, you must also do either of the following:
  • All of your overlay state sequences must be encased in a separate states block called States(Item,Overlay); OR:
  • In the default properties block, add the following line: DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_ITEM;
And then, the actual code to add an overlay is rather simple:

Code: Select all

private bool OwnerOverlay(int layer, statelabel st, bool nooverride = false)
{
    // Check that we have a valid owner who is a player
    if (!Owner || !Owner.player)
    {
        return false;
    }

    // Do not override an existing overlay
    if (nooverride && Owner.player.FindPSprite(layer))
    {
        return false;
    }

    let pspr = Owner.player.GetPSprite(layer);
    pspr.Caller = self;
    pspr.SetState(ResolveState(st));
    
    return true;
}
I'm not sure why it doesn't come as a built-in function for inventory items (or at least for StateProvider) - it would be rather useful for those who don't want to use CustomInventory. I've never had to work with overlays myself, otherwise I probably would have suggested this long ago.
Post Reply

Return to “Scripting”