ZDCode [2.13.0] - The high-level DECORATE wrapper

Any utility that assists in the creation of mods, assets, etc, go here. For example: Ultimate Doom Builder, Slade, WadSmoosh, Oblige, etc.
Forum rules
The Projects forums are ONLY for YOUR PROJECTS! If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

I am in the process of adding a condition system, where one can use AND, OR and NOT to check conditions (which are state action templates that jump a given number of states only in the desired condition). Those are special macros that can be used as components in conditions (in statements like while, if, etc.).

Code: Select all

class FrogBoots extends Inventory {
    set Inventory.MaxAmount to 1;
}

class Tired extends Inventory {
    set Inventory.MaxAmount to 3;
}

class FrogZombie extends ZombieMan replaces ZombieMan {
    condition<Offset> C_HasInventory(InventoryName, Amount = 1) {
        TNT1 A 0 A_JumpIfInventory(InventoryName, Amount, Offset);
    }

    condition<Offset> C_Closer(Distance) {
        A_JumpIfCloser(Distance, Offset);
    }

    condition<Offset> C_OnFloor() {
        A_JumpIf(z < floor + 1, Offset);
    }

    label Spawn {
        TNT1 A 0;
        TNT1 A 0 A_Give("FrogBoots");
        goto Super.Spawn;
    }

    macro Jump {
        TNT1 A 0 {
            A_FaceTarget();
            ThrustThingZ(0, 30, 0, 0);
            ThrustThing(angle * 256 / 360, 25, 1, 0);
        }
    }

    label See {
        if (HasInventory("Tired"))  POSS ABCD 10 A_Chase;
        else                        POSS ABCD 4  A_Chase;

        sometimes 15 if (C_HasInventory("FrogBoots") && !C_Closer(128) && !C_HasInventory("Tired", 3) && C_OnFloor()) {
            TNT1 A 0 {
                A_Give("Tired", 1);
                inject Jump;
            };
        }
    
        sometimes 20 TNT1 A 0 A_Take("Tired", 1);

        loop;
    }
}
ZDCode will internally use offset jumps to compute these conditions in the generated DECORATE output.
CBM wrote:anything in zcode II that will make generation of actors based soly on frame information very easy?
What exactly do you mean frame information?

Also, a complete specification & documentation of the language is still in the todo list. I haven't gotten to do it yet.
User avatar
TDRR
Posts: 815
Joined: Sun Mar 11, 2018 4:15 pm
Operating System Version (Optional): Manjaro/Win 8.1
Graphics Processor: Intel (Modern GZDoom)
Location: Venezuela

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by TDRR »

Gustavo6046 wrote:Also, a complete specification & documentation of the language is still in the todo list. I haven't gotten to do it yet.
If it helps, i have been doing a tutorial of sorts that runs through various use-cases of ZDCode. Thing is, i don't have many use cases for all of the new features ZDCode has.
I only got basic conversion from DECORATE to ZDCode, and usage of functions and macros to this point. If you think it may be useful to you i can send it over though it's not much.

SLADE should support ZDCode, that would be really awesome. At least compiling from SLADE directly instead of compiling and putting that into the .pk3, and syntax highlighting would be cool but just that would be nice. Ever thought of asking SLADE's dev for such a thing?
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

I took a brief break from ZDCode, but development will resume either Saturday or Sunday.

Good night.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

A new update has come out! Welcome to ZDCode 2.6.1. Template classes, abstract labels and macros, many things that can be parametrized (from expressions to repeat and chance values to freaking sprite names!), and much, much more! You're excited? So am I! It's available in the GitHub repository. You can run it using Python and "dist/zdcode.pex", which comes with all the libraries needed to run it. You'll still need Python 3, though.
User avatar
Kappes Buur
 
 
Posts: 4114
Joined: Thu Jul 17, 2003 12:19 am
Graphics Processor: nVidia (Legacy GZDoom)
Location: British Columbia, Canada
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Kappes Buur »

Gustavo6046 wrote:A new update has come out! Welcome to ZDCode 2.6.1.
It appears that Github has only up to 2.5.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

That's odd. Its latest commit is the 2.6.4 one, and that should be reflected when you download ZDCode in either the pex or source format. I'm not sure what you mean.
User avatar
Kappes Buur
 
 
Posts: 4114
Joined: Thu Jul 17, 2003 12:19 am
Graphics Processor: nVidia (Legacy GZDoom)
Location: British Columbia, Canada
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Kappes Buur »

Gustavo6046 wrote:I'm not sure what you mean.
When I click on the Github link in the OP I get this
Spoiler:
releases 2.5.0 and below
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

Oh. I forgot to add a Release. Thank you for pointing this out!

I will still be unable to annex a .exe file. Remember, this is still Python, and even the top freezers (like PyInstaller) can't build against a system other than the host one! And using Wine does not seem to fix this. However, I will add a .pex file, which requires only the Python runtime, and does not need any further setup. Win win!
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

I feel like I should have addressed this question waaay ago.
TDRR wrote:SLADE should support ZDCode, that would be really awesome. At least compiling from SLADE directly instead of compiling and putting that into the .pk3, and syntax highlighting would be cool but just that would be nice. Ever thought of asking SLADE's dev for such a thing?
I think sirjuddington has more to worry about than a random convoluted Python project that compiles a silly syntax to a language superseded to ZScript. This thing would have made so much more sense a few years ago, when "DoomScript" was but a rumor.

Besides, I was thinking, maybe we should instead make the ecosystem, where ZDCode projects are bundled into a single DECORATE file. In fact, this ZDCode part would just be an extension to the actual ecosystem, whose actual job would be to build PK3 files from a filesystem project. So I don't have SLADE in mind right now.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

v2.8.0 is out! Conditional flow is now great again!

Code: Select all

    macro Tick_Chase {
        TNT1 A 0 A_FaceTarget(2);

        // bite if possible!
        TNT1 A 0 A_JumpIfTargetInsideMeleeRange("Melee");

        // "more realistic eye movements"
        sometimes 15 ifjump A_JumpIfTargetInLOS($offset, 15) {
            x 4 TNT1 A 0 A_SetAngle(angle + Random(-5, 5));
        };

        // chase!
        ifjump A_JumpIfTargetInLOS($offset) TNT1 A 0 {
            A_FaceTarget(12);
            A_Recoil(-0.55);
        };

        // can't see target... :c
        else {
            TNT1 A 0 A_ClearTarget;
            goto Idle;
        };
    };
...and A_Jump(255) pays for it!
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

You know what? Since it is often needed to interoperate between separate lumps (like keeping TEXTURES, SNDINFO, DECORATE, ACS stuff, etc in sync with each other), I will
slowly deprecate ZDCode II in favor of something much larger, much prettier, and a powerful, convenient all-in-one modding and project organization solution. Please hang on as I work on the ZDK!


EDIT: This idea for ZDK (or Zad) is actually not a good idea and has been scrapped. I was instead thinking about having it being a framework to generate ZDoom mods with definitions in a language like Python. Probably not Python.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

ZDCode is still being maintained. In fact, I added a few nifty features lately. Check the README in the repository for a somewhat comprehensive list (not including minor things like frame unrolling, state keyword parameter expansion, etc).

One of the shiniest additions is the dynamic state modifier block. "Dynamic" is a bit of a misnomer - it is compile-time, as eveything else in ZDCode ever -, but it is very powerful and not too difficult to understand.

A modifier is composed of clauses, where each clause applies a set of one or more effects to a state selector. Modifiers are declared and applied separately, using the class-level mod blocks and the state-level apply blocks, respectively.

Code: Select all

class DiscoZombie extends Zombieman {
    mod DiscoLight {
        (sprite(TNT1)) suffix TNT1 A 0 A_PlaySound("disco/yeah"); // now we can use TNT1 frames to play some weird sound!

        (all) +flag Bright; // Always bright, all the time!
    };

    label Spawn {
        apply DiscoLight {
            POSS AB 4;
        };

        loop;
    };

    // You can also apply the modifier to other state labels (like See or Missile)
    // using the apply syntax, but you get the gist.
}
State selectors can actually use boolean operators, which is cool but in retrospect does not seem all that useful really. But hey, it's cool!
It also supports multiple effects per selector, and effects that take a state as argument (such as prefix or suffix) can actually take a state block, too.

Code: Select all

class LitZombie extends Zombieman {
    mod Lit {
        // Only lit POSS frames, and only if they have the BRIGHT keyword.
        (sprite(POSS) && flag(Bright)) {
            prefix invisi A_SpawnItemEx("OooShinyZombieFlare");
            -flag Bright;
        };
    };

    label Spawn {
        apply DiscoLight {
            POSS AB 4;
        };

        loop;
    };

    // You can also apply the modifier to other state labels (like See or Missile)
    // using the apply syntax, but you get the gist.
}
There is also a more advanced effect, called manipulate, that basically allows you to replace affected states, as you supply a replacement block of states, and may inject the original state as if it were a macro.

Code: Select all

class SpinZombie extends Zombieman {
    mod SpinAndRepeat {
        (!sprite(TNT1)) {
            +flag Bright;
            manipulate State {
                x 24 {
                    invisi A_SetAngle(angle + 15);
                    inject State; // state duration effects (and selectors) will be added soon(TM)
                };
            };
        };
    };

    label Missile {
        POSS E 10 A_FaceTarget;
        apply SpinAndRepeat POSS F 8 A_PosAttack;

        POSS EDE 10; // phew!..
        goto See;
    };
}
Also, what about the Zad? The Zad is not necessary. We have many tools, already. SLADE, etc. It would be more productive to add PK3 and UDMF support to Eureka or something, I don't know. Maybe for asset organization and artifact output, such as producing variations of a mod with omitted lumps and different ZDCode preprocessor definitions. Or just building C libraries, I don't know if ZDoom already has some FFI interface for code placed in PK3s or whatever.
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

Sorry for this yet another post in what may have become a spree, but I am very stoked now as I announce that I have successfully finished the build system, Zake.
(get it? Make, but with a Z.. haha I'm hilarious)

Rather than having to write command-line arguments, simply write a Zake.ini file!
This example from GitHub demonstrates the capabilities well:

Code: Select all

# Builds the ZDCode example mod, as 'ZDWorld';

[General]
Name: ZDWorld
Version: 2.11.1
Targets: debug release

[Paths]
Inputs = example/assets
Bundle.Asset: example/out/${name}-${version}-${target}-asset.pk3
Bundle.Code: example/out/${name}-${version}-${target}-code.pk3
Decorate: example/out/${name}-${version}-${target}.dec

[Definitions.debug]
# only define it, no value (ifdef checks for key presence anyway)
DEBUG =

  • The General section specifies the name and the version of the project (currently used only as parameters to format other text), as well as a set of targets.
  • The Paths section specifies inputs (a set of entry points ZDCode is to process) and outputs (the location of the output asset PK3, code PK3, and the DECORATE output for debugging purposes).
  • The Definitions section is a list of preprocessor definitions to be used in source files compiled by ZDCode.
For each target, there can be "subsections", which are values specific to the build of that target, overriding the more general values. In the example above, there is [Definitions.debug], which means that DEBUG is only set in the debug build.

What this means is that you can have things like this...

Code: Select all

            manipulate State {
                x 12 {
                    invisi A_SetAngle(30 + angle);
                    inject State;

                    #ifdef DEBUG // <-- here
                        invisi A_LogFloat(angle);
                    #endif
                };
And ZDCode will, of course, build each target with its respective settings and paths:



And, if you compare the DECORATE outputs of both builds, you'll see that the A_LogFloat calls are, indeed, omitted entirely from the Release build:

Code: Select all

Actor SpinZombie : Zombieman // debug
{
    
    States {
        Missile:
            POSS E 10 A_FaceTarget
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_LogFloat(angle)
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_LogFloat(angle)
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                ...
    }
}

Code: Select all

Actor SpinZombie : Zombieman // release
{
    
    States {
        Missile:
            POSS E 10 A_FaceTarget
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                TNT1 A 0 A_SetAngle(30 + angle)
                POSS F 4  Bright A_PosAttack
                ...
    }
}
User avatar
CBM
Posts: 373
Joined: Wed Oct 09, 2019 3:39 am
Graphics Processor: nVidia with Vulkan support
Location: The Shores of Hell

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by CBM »

Gustavo6046 wrote:
CBM wrote:anything in zcode II that will make generation of actors based soly on frame information very easy?
What exactly do you mean frame information?

Also, a complete specification & documentation of the language is still in the todo list. I haven't gotten to do it yet.
anything really that can easy the use of 3d models in gzdoom...

here are some examples, instead of this

Code: Select all

Model ultramarinetactical
{ 
   Path "Models\spacemarine"
   Model 0 "tacticalmarine.md3"

	SurfaceSkin 0 0 "Models\spacemarine\default_2.tga"
	SurfaceSkin 0 1 "Models\spacemarine\default_2.tga"
	SurfaceSkin 0 2 "Models\spacemarine\default_2.tga"	
	SurfaceSkin 0 3 "Models\spacemarine\default_1.tga"
	SurfaceSkin 0 4 "Models\spacemarine\default_2.tga"
	SurfaceSkin 0 5 "Models\spacemarine\bolter.tga"
	SurfaceSkin 0 6 "Models\spacemarine\fire.tga"
	
   Scale 1.15 1.15 1.15
   offset 1.0 1.0 1.0
   
   // 1 standing
   FrameIndex umta A 0 0	
   
   // 164-176 walk
   FrameIndex umta B 0 166	
   FrameIndex umta C 0 170	
   FrameIndex umta D 0 175
   
   // 137-139 attack
   FrameIndex umta E 0 134	
   FrameIndex umta F 0 272	
   FrameIndex umta G 0 138
   
   // 34 pain
   FrameIndex umta H 0 135
   
   // 58-80 death 
   FrameIndex umta I 0 58	
   FrameIndex umta J 0 59	
   FrameIndex umta K 0 60
   FrameIndex umta L 0 61	
   FrameIndex umta M 0 62	
   FrameIndex umta N 0 63
   FrameIndex umta O 0 64	
   FrameIndex umta P 0 65	
   FrameIndex umta Q 0 66
   FrameIndex umta R 0 67	
   FrameIndex umta S 0 68	
   FrameIndex umta T 0 69
   FrameIndex umta U 0 70	
   FrameIndex umta V 0 71	
   FrameIndex umta W 0 72
   FrameIndex umta X 0 73	
   FrameIndex umta Y 0 74	
   FrameIndex umta Z 0 79
}
I would rather write this

Code: Select all

Model ultramarinetactical
{ 
   Path "Models\spacemarine"
   Model 0 "tacticalmarine.md3"

	SurfaceSkin 0 0 "Models\spacemarine\default_2.tga"
	SurfaceSkin 0 1 "Models\spacemarine\default_2.tga"
	SurfaceSkin 0 2 "Models\spacemarine\default_2.tga"	
	SurfaceSkin 0 3 "Models\spacemarine\default_1.tga"
	SurfaceSkin 0 4 "Models\spacemarine\default_2.tga"
	SurfaceSkin 0 5 "Models\spacemarine\bolter.tga"
	SurfaceSkin 0 6 "Models\spacemarine\fire.tga"
	
   Scale 1.15 1.15 1.15
   offset 1.0 1.0 1.0
   
   // 1 standing
   FrameIndex umta A 0 0	
   
   // 164-176 walk
   FrameIndex umta B 0 166	
   FrameIndex umta C 0 170	
   FrameIndex umta D 0 175
   
   // 137-139 attack
   FrameIndex umta E 0 134	
   FrameIndex umta F 0 272	
   FrameIndex umta G 0 138
   
   // 34 pain
   FrameIndex umta H 0 135
   
   // 58-80 death 
   FrameIndex umta I-Z 0 58-79	
}
and instead of this

Code: Select all

actor ultramarinetactical : ChaingunGuy 
{
	//$Category Models/Ultramarines
	//$Title Ultramarines Tactical Marine
  Health 300
  SeeSound "umsg/sight"
  PainSound "umsg/pain"
  DeathSound "umsg/death"
  ActiveSound "umsg/active"
  DropItem "Backpack" 
 Obituary "%o was shot, ripped and teared to death by a tactical ultra marine."
   States
  {
  Spawn:
    umta A 10 a_look 
	loop
    See:
    umta AABBCCDD 2 Fast A_Chase
    Loop
  Melee:
  Missile:
	umta E 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta G 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta E 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta G 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta E 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta G 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta E 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta G 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta E 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta G 1 A_FaceTarget	
	umta F 1 BRIGHT A_CPosAttack
	umta E 1 A_FaceTarget	
	umta G 1 BRIGHT A_CPosAttack	
	Goto See
  Pain:
    umta H 2 Fast
    umta H 2 Fast A_Pain
    Goto See
  Death:
    umta IJ 4
    umta KLM 4	
    umta NOP 8 A_Scream
    umta QRS 4
    umta TUV 4 A_NoBlocking
    umta WXY 4
    umta Z -1
    Stop
  Raise:
    umta ZYXWVUTSR 5
    umta QPONMLKJI 5
    Goto See	
  }
}
Id rather write this

Code: Select all

actor ultramarinetactical : ChaingunGuy 
{
	//$Category Models/Ultramarines
	//$Title Ultramarines Tactical Marine
  Health 300
  Sounds "umsg"
  DropItem "Backpack" 
 Obituary "%o was shot, ripped and teared to death by a tactical ultra marine."
   States
  {
  Spawn:
    umta A 10 a_look 
	loop
    See:
    umta AABBCCDD 2 Fast A_Chase
    Loop
  Melee:
  Missile:
        loop E,F,G 1 12 times
{ 
       A_FaceTarget	
       BRIGHT A_CPosAttack
      A_FaceTarget
}
	Goto See
  Pain:
    umta H 2 Fast
    umta H 2 Fast A_Pain
    Goto See
  Death:
    umta IJ 4
    umta KLM 4	
    umta NOP 8 A_Scream
    umta QRS 4
    umta TUV 4 A_NoBlocking
    umta WXY 4
    umta Z -1
    Stop
  Raise:
    umta ZYXWVUTSR 5
    umta QPONMLKJI 5
    Goto See	
  }
}
User avatar
Gustavo6046
Posts: 136
Joined: Sat May 13, 2017 3:11 pm
Location: Brazil
Contact:

Re: ZDCode II - The pretty language that compiles to DECORAT

Post by Gustavo6046 »

@CBM I think you mean looping states. Yes, that functionality does exist and is implemented in ZDCode; in fact it's one of the earliest additions to the language! The keyword "x", followed by a number, will repeat the succeeding state or block of states that number of times.

However, there is no GLDEFS support; ZDCode can only compile to DECORATE. The bundler can include GLDEFS lumps, and any other lumps, if you specify a PK3 as an input file in the command line (which automatically converts ZDCODE.* into DECORATE lumps, as well as optional dependency resolution ). The bundler can only operate with PK3 files, not WADs. I never actually used GLDEFS, so there are no warranties that any conditions or restrictions required by GLDEFS be respected by the DECORATE code generated by the ZDCode compiler.
Post Reply

Return to “Creation, Conversion, and Editing”