"How do I ZScript?"

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!)
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript-only "How do I..." thread

Post by ZZYZX »

I can do this http://i.imgur.com/QjzNbfm.png
But not sure how to also apply random angle to that.
I know that to rotate it by 90 degrees, I need to swap smth with smth, I think roll with angle. But whatevs.
What order does Doom apply these angles in?

Code currently looks like this

Code: Select all

class SlopedThing : Candelabra
{
    Default
    {
        +FLATSPRITE;
        //+ROLLCENTER;
    }
    
    private void SetToSlope(double dang)
    {
        vector3 fnormal = CurSector.floorplane.normal;
        if (!CurSector.floorplane.isSlope())
            fnormal = (0, 0, 1);
        vector2 fnormalp1 = (fnormal.x != 0 || fnormal.y != 0) ? (fnormal.x, fnormal.y).Unit() : (0, 0);
        vector2 fnormalp2 = ((fnormal.x, fnormal.y).Length(), fnormal.z);

        self.roll = 0;
        self.angle = atan2(fnormalp1.y, fnormalp1.x);
        self.pitch = -90+atan2(fnormalp2.x, fnormalp2.y);
        //Console.Printf("angles = %.2f, %.2f, %.2f\n", angle, pitch, roll);
    }
    
    override void PostBeginPlay()
    {
        Super.PostBeginPlay();
    }
    
    override void Tick()
    {
        double dang = (level.time*3)%360;
        //dang = 45;
        SetToSlope(dang);
        Super.Tick();
    }
}
User avatar
Major Cooke
Posts: 8082
Joined: Sun Jan 28, 2007 3:55 pm

Re: ZScript-only "How do I..." thread

Post by Major Cooke »

For starters it should affect the roll, not the angle. Will experiment.

Graf, does that help?
User avatar
Caligari87
User Accounts Assistant
Posts: 5997
Joined: Thu Feb 26, 2004 3:02 pm
Preferred Pronouns: He/Him

Re: ZScript-only "How do I..." thread

Post by Caligari87 »

viewtopic.php?f=3&t=50334

@ZZYZX: I made a little demo here of combining pitch and roll for the playercamera to (kind of) defeat gimbal-lock and make it appear as if the level were "tilted". It's likely very crude compared to what you're doing but perhaps there's a little bit of code in there that would help.

8-)
User avatar
Major Cooke
Posts: 8082
Joined: Sun Jan 28, 2007 3:55 pm

Re: ZScript-only "How do I..." thread

Post by Major Cooke »

What we're trying to do is this with the green stickmen.

Image
User avatar
Caligari87
User Accounts Assistant
Posts: 5997
Joined: Thu Feb 26, 2004 3:02 pm
Preferred Pronouns: He/Him

Re: ZScript-only "How do I..." thread

Post by Caligari87 »

I know. I'm just offering some math that worked for my use case, which seemed somewhat similar in the general purpose. If it's helpful, great. If not, disregard.

8-)
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript-only "How do I..." thread

Post by ZZYZX »

Ok so I got this horrible geometrical hack based on observing how it rotates :)
Has nothing to do with Caligari's solution though (in fact I didn't even understand what's going on there and why the /50).
http://pastebin.com/6qs9jviW (nevermind Sign, it's unused)

It's a little tiny bit off though (almost unnoticeable). I believe it needs to be upscaled/downscaled by 1.2 or smth.
Also, you probably can make it a shadow by giving it pitch of 90/-90. But it's a little tiny bit off too.
User avatar
Major Cooke
Posts: 8082
Joined: Sun Jan 28, 2007 3:55 pm

Re: ZScript-only "How do I..." thread

Post by Major Cooke »

I'm not worried about the shadows. In fact I probably might exclude them because that's going to be a bit costly -- I'd rather wait on GZDoom to support a real light/sun system for that.

Also it works, so I'm not complaining. :P
User avatar
Nash
 
 
Posts: 17319
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript-only "How do I..." thread

Post by Nash »

ZZYZX wrote:Ok so I got this horrible geometrical hack based on observing how it rotates :)
Has nothing to do with Caligari's solution though (in fact I didn't even understand what's going on there and why the /50).
http://pastebin.com/6qs9jviW (nevermind Sign, it's unused)

It's a little tiny bit off though (almost unnoticeable). I believe it needs to be upscaled/downscaled by 1.2 or smth.
Also, you probably can make it a shadow by giving it pitch of 90/-90. But it's a little tiny bit off too.
Very cool! Can you make a version that would work for things like flat blood splats, etc? I tried messing around by compensating the angle, pitch and roll but can't seem to come up with anything that looks correct...

EDIT:

Code: Select all

class Z_BloodSpot : Z_BloodBase
{
    Default
    {
        Radius 8;
        RenderStyle "Shaded";
    }

    private void SetToSlope(double dAng)
    {
        vector3 fNormal = CurSector.FloorPlane.Normal;
        if (!CurSector.FloorPlane.isSlope())
        fNormal = (0, 0, 1);
        vector2 fNormalP1 = (fNormal.X != 0 || fNormal.Y != 0) ? (fNormal.X, fNormal.Y).Unit() : (0, 0);
        vector2 fNormalP2 = ((fNormal.X, fNormal.Y).Length(), fNormal.Z);
        vector2 angNormal1 = (cos(dAng - 90), sin(dAng - 90)).Unit();
        vector2 angNormal2 = (cos(dAng), sin(dAng)).Unit();
        double dDiff1 = (angNormal1.X * fNormalP1.X + angNormal1.Y * fNormalP1.Y); // dot product
        double dDiff2 = (angNormal2.X * fNormalP1.X + angNormal2.Y * fNormalP1.Y); // dot product
        Self.Pitch = -atan2(fNormalP2.X, fNormalP2.Y) * dDiff2;
        Self.Roll = atan2(fNormalP2.X, fNormalP2.Y);
        Self.Roll *= dDiff1;
        Self.Angle = dAng;
    }

    override void PostBeginPlay()
    {
        Super.PostBeginPlay();
    }

    override void Tick()
    {

        SetToSlope(Angle);
        Super.Tick();
    }

    States
    {
    Spawn:
        TNT1 A 0 NoDelay A_SpawnItemEx("Z_BloodDrop", flags: BLOOD_FLAGS);
        TNT1 A 1 A_Jump(256, "BloodSpot1", "BloodSpot2", "BloodSpot3", "BloodSpot4");
        Stop;
    BloodSpot1:
        BSPT A 0 A_SetTics(BLOODSPOT_TICS);
        Goto FadeOut;
    BloodSpot2:
        BSPT B 0 A_SetTics(BLOODSPOT_TICS);
        Goto FadeOut;
    BloodSpot3:
        BSPT C 0 A_SetTics(BLOODSPOT_TICS);
        Goto FadeOut;
    BloodSpot4:
        BSPT D 0 A_SetTics(BLOODSPOT_TICS);
        Goto FadeOut;
    FadeOut:
        "####" "#" 2 A_FadeOut(BLOODSPOT_FADEOUTSPEED);
        Loop;
    }
}
 
Image

This works for 3D blood splats. The only difference is I flipped the atan signs for Self.Roll and Self.Pitch, and removed the -90 from the Self.Pitch. Very nice!! Thank you ZZYZX-senpai
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript-only "How do I..." thread

Post by ZZYZX »

http://pastebin.com/hNGuPrQQ an optimized (?) version without dot product, replaced with AngDiffAs10. That function would compare two angles and return 1 for matching, and -1 for opposite.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48332
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript-only "How do I..." thread

Post by Graf Zahl »

That's actually de-optimized. If you are out for speed, do not use scripted subfunctions - they are really costly - my profiling showed they take 30x as long to call as a native function call.
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript-only "How do I..." thread

Post by ZZYZX »

Ok, minus two scripted calls and minus four native calls http://pastebin.com/pmfTPmAq, because 30x slower function call here means noticeably smaller FPS with large usage counts.
Anyway, why do scripted functions lag that much?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48332
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript-only "How do I..." thread

Post by Graf Zahl »

Where's scripted function calls in there? All those math functions are actually intrinsics. Sure, the operation they perform costs time but they are single opcodes. That function actually has no 'call' opcode whatsoever.
User avatar
ZZYZX
 
 
Posts: 1382
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: ZScript-only "How do I..." thread

Post by ZZYZX »

Nowhere, hence minus two :)
I was asking about the previous one, why does scripted vs native CALL (not execution even!) cost more?
User avatar
Major Cooke
Posts: 8082
Joined: Sun Jan 28, 2007 3:55 pm

Re: ZScript-only "How do I..." thread

Post by Major Cooke »

Graf, which would be healthier for speed?

One single function call all the time? (Calls ProcessCooldowns which only performs its stuff if the timer is %3, %2 or %10, all = 0)

Code: Select all

	override void Tick()
	{
		if (isVoodoo() || health <= 0)
		{
			Super.Tick();
			return;
		}
		
		if (PentaNoiseWait > 0)	PentaNoiseWait--;
		if (level.maptime <= 1)	InitPlayer();
		
		ProcessCooldowns();
		if (GetClass() == "Doom4Player")		UpdateHAM();
		Super.Tick();
	}
	
	void ProcessCooldowns()
	{
                // Use common denominator.
		int timer = level.maptime % 30; 
		// No need to check for StaticChargeDrain since the upgrade alone
		// shuts this off.
		if (!(timer % 3))
		{
			if (!CountInv("StaticUpgrade4"))
			{
					 if (CountInv("StaticUpgrade3"))
				{	A_TakeInventory("StaticRifleChargingToken",1);	}
				else if (CountInv("StaticUpgrade2"))
				{	A_TakeInventory("StaticRifleChargingToken",2);	}
				else
				{	A_TakeInventory("StaticRifleChargingToken",4);	}
			}
			A_TakeInventory("PlasmaStunBombCounter",1);
			user_lasthp = health + CountInv("BasicArmor");
		}
		
		if (!(timer % 2))
		{
			A_TakeInventory("SGTripleShotTimer",1);
			A_TakeInventory("SGGrenadeTimer",1);
		}
		if (!(timer % 10))
		{
			if (CountInv("GrenadeCooldown"))
			{
				A_TakeInventory("GrenadeCooldown",1);
				if (!CountInv("GrenadeCooldown"))
				{
					A_PlaySound("Doom4/Weapon/Grenade/GrenadeRegen");
				}
			}
		}
	}
Or multiple functions split up over time?

In this version, ProcessCooldown1, 2, and 3 are only called after 3, 2, and 10 tics passed respectively.

Code: Select all

	int CooldownTimer[3];
	override void Tick()
	{
		if (isVoodoo() || health <= 0)
		{
			Super.Tick();
			return;
		}
		
		if (PentaNoiseWait > 0)	PentaNoiseWait--;
		if (level.maptime <= 1)	InitPlayer();
		
		static const int CooldownCaps[] = { 3, 2, 10 };
		for (int i = 0; i < 3; i++)
		{
			CooldownTimer[i] = (CooldownTimer[i] + 1) % CooldownCaps[i];
		}
		
		if (!CooldownTimer[0])	ProcessCooldown1();
		if (!CooldownTimer[1])	ProcessCooldown2();
		if (!CooldownTimer[2])	ProcessCooldown3();	
		if (GetClass() == "Doom4Player")		UpdateHAM();
		Super.Tick();
	}
	
	void ProcessCooldown1()
	{
		// No need to check for StaticChargeDrain since the upgrade alone
		// shuts this off.
		if (!CountInv("StaticUpgrade4"))
		{
				 if (CountInv("StaticUpgrade3"))
			{	A_TakeInventory("StaticRifleChargingToken",1);	}
			else if (CountInv("StaticUpgrade2"))
			{	A_TakeInventory("StaticRifleChargingToken",2);	}
			else
			{	A_TakeInventory("StaticRifleChargingToken",4);	}
		}
		A_TakeInventory("PlasmaStunBombCounter",1);
		user_lasthp = health + CountInv("BasicArmor");
	}
	
	void ProcessCooldown2()
	{
		A_TakeInventory("SGTripleShotTimer",1);
		A_TakeInventory("SGGrenadeTimer",1);
	}
	
	void ProcessCooldown3()
	{
		if (CountInv("GrenadeCooldown"))
		{
			A_TakeInventory("GrenadeCooldown",1);
			if (!CountInv("GrenadeCooldown"))
			{
				A_PlaySound("Doom4/Weapon/Grenade/GrenadeRegen");
			}
		}
	}
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48332
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript-only "How do I..." thread

Post by Graf Zahl »

In that case it really doesn't matter because the native code being called by those subfunctions requires a lot more time than the VM function calls.

Return to “Scripting”