Page 1 of 1

Defend Script

Posted: Fri Dec 17, 2021 10:47 am
by Drake Raider
This possibly one of my more oddly-specific requests, and I'd try to do it myself if I really had any idea how zScript worked, but I need (Particularly in zScript) a specific weapon function:

As long as you hold down the mouse button, it lowers your camera, reduces your collision box, and reduces all incoming damage by 60% or so.

You can keep it running as long as you want, but you can't attack/use items while it's active, and once you release it has a cooldown equal to half the time it was active (regardless of duration.)

I plan on using it as an altfire for a couple different weapons, so whatever I would need to do to impliment it flexibly as possible is also a plus. No idea where to start.

Re: Defend Script

Posted: Sat Dec 25, 2021 5:37 am
by Jekyll Grim Payne
I had a bit of time so I went ahead and coded the thing below.
I'm also attaching it as a text file to the post. It's rather heavily commented, so it should be fairly clear what does what.

Code: Select all

version "4.7.0"

// To make this work in other weapons, the easiest approach would be
// to put all of this into your custom base weapon class that other
// weapons in the mod inherit from. Then, in those weapons where
// you don't want this altfire to be useable, either replace it
// with a different altfire, or use A_WeaponReady(WRF_NOSECONDARY)
// to disable altfire in a specific weapon completely.

class DefendWeapon : Weapon
{	
	bool defenseactive;
	
	double prevheight; // cache player's original height
	double prevradius; // cache player's original radius
	double prevViewheight; // cache player's original viewheight
	double prevAttackZOffset; // cache player's original AttackZOffset
	
	// Using constants isn't necessary here but it makes it
	// easier to tweak these values in the future, since 
	// you can tweak them in one place instead of editing them
	// throughout the code.
	const SIZEREDUCTION = 0.75; //by how much to reduce player's hitbox
	const VIEWLOWER = 8; //by how much to lower player's view
	
	// The following could be done in anonymous functions,
	// but wrapping it into simple custom functions just
	// lets us keep the code a bit cleaner:
	
	action void ActivateDefense()
	{
		if (invoker.defenseactive)
			return;
		invoker.defenseactive = true;
		// record current values:
		invoker.prevheight = height;
		invoker.prevradius = radius;
		invoker.prevViewheight = player.ViewHeight;
		invoker.prevAttackZOffset = player.mo.AttackZOffset;
		// set size and view:
		A_SetSize(height * SIZEREDUCTION, radius * SIZEREDUCTION);
		// Note that viewheight has to be changed on the player,
		// whereas AttackZOffset has to be changed on the player pawn.
		// It's possible to access AttackZOffset on the player,
		// but it's not properly controllable.
		player.ViewHeight -= VIEWLOWER;
		player.mo.AttackZOffset -= VIEWLOWER;
		GiveInventory("DefendWeaponEffect", 1);
		//console.printf("ACTIVATED: size: %.1f, %.1f | attackZOffset: %.1f | viewheight: %.1f", radius, height, player.mo.AttackZOffset, player.ViewHeight);
	}
	
	action void DeactivateDefense()
	{
		if (!invoker.defenseactive)
			return;
		invoker.defenseactive = false;
		// reset size and view to previous values:
		A_SetSize(invoker.prevheight,invoker.prevradius);
		player.ViewHeight = invoker.prevViewheight;
		player.mo.AttackZOffset = invoker.prevAttackZOffset;
		TakeInventory("DefendWeaponEffect", 1);
		//console.printf("DEACTIVATED: size: %.1f, %.1f | attackZOffset: %.1f | viewheight: %.1f", radius, height, player.mo.AttackZOffset, player.mo.ViewHeight);
	}
	
	States
	{
	Ready:
		TNT1 A 1 A_Weaponready(WRF_NOPRIMARY); //disabling primary fire because we don't need it in this example
		loop;
	//Fire sequence can't be omitted, so we include one that does nothing:
	Fire:
		TNT1 A 1;
		goto ready;
	//Select and deselect sequences 
	Select:
		TNT1 A 1 A_Raise;
		loop;
	Deselect:
		TNT1 A 1 A_Lower;
		loop;
	Altfire:
		TNT1 A 1
		{
			// Check if the player is pressing and holding altfire button:
			if (player.cmd.buttons & BT_ALTATTACK && player.oldbuttons & BT_ALTATTACK)
			{
				// If defense isn't active yet, activate it:
				if (!invoker.defenseactive)
					ActivateDefense();
				// And do nothing else, jump to 'wait':
				return ResolveState(null);
			}
			// OTHERWISE deactivate defense and goto Ready:
			DeactivateDefense();
			return ResolveState("Ready");
		}
		wait;
	}
}

// A powerup-like item that reduces incoming damage:
class DefendWeaponEffect : Inventory
{
	Default
	{
		inventory.maxamount 1;
		+INVENTORY.UNDROPPABLE
		+INVENTORY.UNTOSSABLE
	}
	
	override void ModifyDamage (int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags)
	{
		if (!passive && damage > 0)
			newdamage = damage * 0.6;
	}
}