"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.

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!)
ZZYZX

Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

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();
}
}``````
Major Cooke
Posts: 8186
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

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

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

Graf, does that help?
Caligari87
Posts: 6184
Joined: Thu Feb 26, 2004 3:02 pm
Preferred Pronouns: He/Him

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.

Major Cooke
Posts: 8186
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

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

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

Caligari87
Posts: 6184
Joined: Thu Feb 26, 2004 3:02 pm
Preferred Pronouns: He/Him

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.

ZZYZX

Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

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.
Major Cooke
Posts: 8186
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

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.
Nash

Posts: 17450
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

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
{
}

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);
BloodSpot2:
BSPT B 0 A_SetTics(BLOODSPOT_TICS);
BloodSpot3:
BSPT C 0 A_SetTics(BLOODSPOT_TICS);
BloodSpot4:
BSPT D 0 A_SetTics(BLOODSPOT_TICS);
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
ZZYZX

Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

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.
Graf Zahl
Posts: 49096
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

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.
ZZYZX

Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

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?
Graf Zahl
Posts: 49096
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

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.
ZZYZX

Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

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?
Major Cooke
Posts: 8186
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Location: QZDoom Maintenance Team

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))
{
{
{	A_TakeInventory("StaticRifleChargingToken",1);	}
{	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);
}
if (!(timer % 10))
{
{
{
}
}
}
}``````
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.
{
{	A_TakeInventory("StaticRifleChargingToken",1);	}
{	A_TakeInventory("StaticRifleChargingToken",2);	}
else
{	A_TakeInventory("StaticRifleChargingToken",4);	}
}
A_TakeInventory("PlasmaStunBombCounter",1);
user_lasthp = health + CountInv("BasicArmor");
}

void ProcessCooldown2()
{
A_TakeInventory("SGTripleShotTimer",1);
}

void ProcessCooldown3()
{
{
{
}
}
}
``````
Graf Zahl
Posts: 49096
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

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.