## "How do I ZScript?"

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.

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

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();    }}`

ZZYZX
le chat du rabbin

Joined: 14 Oct 2012
Location: Ukraine
Discord: ZZYZX#1394
Github ID: jewalky

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

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

Graf, does that help?

Major Cooke
QZDoom Maintenance Team

Joined: 28 Jan 2007

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

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.

Caligari87
I'm just here for the community
User Accounts Assistant

Joined: 26 Feb 2004
Location: Salt Lake City, Utah, USA
Discord: Caligari87#3089

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

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

Major Cooke
QZDoom Maintenance Team

Joined: 28 Jan 2007

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

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.

Caligari87
I'm just here for the community
User Accounts Assistant

Joined: 26 Feb 2004
Location: Salt Lake City, Utah, USA
Discord: Caligari87#3089

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

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.

ZZYZX
le chat du rabbin

Joined: 14 Oct 2012
Location: Ukraine
Discord: ZZYZX#1394
Github ID: jewalky

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

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.

Major Cooke
QZDoom Maintenance Team

Joined: 28 Jan 2007

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

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;    }} `

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

Nash

Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

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

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.

ZZYZX
le chat du rabbin

Joined: 14 Oct 2012
Location: Ukraine
Discord: ZZYZX#1394
Github ID: jewalky

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

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.

Graf Zahl

Joined: 19 Jul 2003
Location: Germany

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

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?

ZZYZX
le chat du rabbin

Joined: 14 Oct 2012
Location: Ukraine
Discord: ZZYZX#1394
Github ID: jewalky

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

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.

Graf Zahl

Joined: 19 Jul 2003
Location: Germany

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

Nowhere, hence minus two
I was asking about the previous one, why does scripted vs native CALL (not execution even!) cost more?

ZZYZX
le chat du rabbin

Joined: 14 Oct 2012
Location: Ukraine
Discord: ZZYZX#1394
Github ID: jewalky

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

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");         }      }   }`

Major Cooke
QZDoom Maintenance Team

Joined: 28 Jan 2007

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

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.

Graf Zahl