Untitled
4 years ago in Plain Text
```
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<color: color>;
}
// 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!<RAND>(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);
}
```