``` use std::rng::BasicRng; use std::loaders::SpriteLoader; use std::extras::ColorRgb; use std::features::{self, Feature, FeatureDef}; // 'self' means the unit 'features' itself will also be accessible, // Umports are done on a per unit basis; a file is an anonymous unit that // encompasses everything defined within it. import AdaptiveGlow; // Let's pretend AdaptiveGlow just adds glow to a class; perhaps it is a large, translucent sprite, // with an extra dynamic light on OpenGL builds? apply FeatureDef() unit Effects { item feature { mode = features::FeatureMode::OptOut; // Enums are equivalent to units with child units. } } unit EvilImp { // Child units can be accessed from parent units. Units are accessed // using '::', akin to Rust modules. unit Sprites { // Units can be imported. Loaders make it possible to import // files other than Zad modules as units. import Main from "Assets/Sprites/EvilImp/*.png" using SpriteLoader; // Attributes can be used to supplement // the meaning of an unit, item or property, // often as markers. apply Feature(Effects) // an output artifact may be built with certain features disabled import Effects from "Assets/Sprites/EvilImp/FX/" using SpriteLoader[recursive]; // Flags can be used like boolean generics. } // A macro is a definition that can be reused with parameters. // It can be used to generate extra body content for items, // units, composite properties, or even other macros. macro Glow(color: ColorRgb) { GlowType; } // Any behaviour that is not marked as an item with a specific // identifier or set of keys among its properties is explicitly // added via low-level generators. They're not high-level units, // they're Zad-specific definitions, like ATDs are. import definition Attach from "ActorAttach.zgd"; import definition Monster from "Monster.zgd"; macro EvilImpBase(classname: String, glowcolor: ColorRgb, strength_multiplier: Float) { item class { // Defines a class item. Items don't need names, just an // arbitrary type identifier that ATDs check against, among // other things. // Properties are structures that may either contain // other properties, key-value pairs, lists, or references // to other items. A property's value can, indeed, be // a simple value. // Properties can be evaluated by wrapping them in parentheses. // Here, string concatenation is done with the '..' operator. name = ("EvilImp" .. classname); inherit = "DoomImp"; // They are added via definition imports, which are special imports // that use a list of standard paths, along project-specific // ones, to find imports. generate with Attach { [ // Lists use square brackets. attach = [ Glow!(glowcolor); // Macros use '!' in their invocation, like Rust ones, despite // not being any more special than other language constructs. // This is to differentiate from items and other things that // could be invoked in similar ways. ] } generate with Monster { // Among other things, the Monster def tells the // DECORATE class generator to add monster flags // and DECORATE properties to its output. item MeleeAttack { melee_damage = (BasicRng::random!(5 + RAND * 3 * (strength_multiplier ** 1.5))); // ** = exponentiation, 'to the power of' // Double curly braces mean the tokens are stored directly, rather than parsed by // Zad. Here they're parsed by the Monster generator. The parser in this case // is supplied by Zad; it's an advanced DECORATE source file, whose concept is // similar to ZDCode's. // However, this is even more advanced. For example, frames can be manipulated by // each blocks, followed by clauses like "perform" (for action states). melee_animation = {{ pre { each { frames { ETRO E 4; ETRO F 3; ETRO GH 3; } // 'all' is a selector. Other valid selectors include 'even', 'odd', ... // In fact, the generator has a table of selectors. For such there's a // 'target', which is a specific set of requirements that, when implemented // by an unit's item, can be used by the generator. Think Rust traits. // Of course, the 'selector' concept is not a Zad thing, but rather defined // in Monster. // An example implementation would be: // // import definition Monster from "Monster.zgd"; // unit EveryThreeSelector { // item for Monster::Selector { // token = 'everythree'; // predicate = (frame) -> { // frame.index % 3 == 0 // Returns are implicit, like in Rust. // }; // Closures can also be properties, but they're only used by Zad, i.e. at compile-time. // } // } // // ...and would be used like so: // // perform everythree { ThrustThingZ(...); ... } mod all { [Bright]; } perform all { A_FaceTarget; } } } post { ETRO E 4; } }} } } } } EvilImpbase!("Lesser", ColorRgb(0.6, 0.7, 0.2), 1); EvilImpbase!("Badder", ColorRgb(0.8, 0.4, 0.05), 3); } ```