From d17a16785ed4056689e487a9816d3017ad5af704 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Sun, 7 Feb 2016 22:31:01 +0200 Subject: [PATCH] console logger; template loader --- console.d | 864 +++++++++++++++++++++++++++ d2dmap.d | 14 +- d2dmon.d | 166 +++++- data/items.txt | 476 +++++++++++++++ data/monsters.txt | 1682 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tparser.d | 42 -- wadarc.d | 21 +- xmain_d2d.d | 11 +- 8 files changed, 3182 insertions(+), 94 deletions(-) create mode 100644 console.d create mode 100644 data/items.txt create mode 100644 data/monsters.txt diff --git a/console.d b/console.d new file mode 100644 index 0000000..9de4f23 --- /dev/null +++ b/console.d @@ -0,0 +1,864 @@ +/* Invisible Vector Library + * coded by Ketmar // Invisible Vector + * Understanding is not required. Only obedience. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* very simple compile-time format writer + * understands [+|-]width[.maxlen] + * negative width: add spaces to right + * negative maxlen: get right part + * specifiers: + * 's': use to!string to write argument + * note that writer can print strings, bools and integrals without allocation + * 'S': print asciiz C string + * 'x': write integer as hex + * 'X': write integer as HEX + * '|': write all arguments that's left with "%s" + * '@': go to argument with number 'width' (use sign to relative goto) + * argument count starts with '1' + * '!': skip all arguments that's left, no width allowed + * '%': just a percent sign, no width allowed + * '$': go to argument with number 'width' (use sign to relative goto), continue parsing + * argument count starts with '1' + * options (must immediately follow '%'): + * '/': center string; negative width means "add extra space (if any) to the right" + * '~': fill with the following char instead of space + * second '~': right filling char for 'center' + * '\0'...'\0': separator string for '%|' + */ +module console /*is aliced*/; +private: + +private import std.traits : isBoolean, isIntegral, isPointer; +static if (!is(typeof(usize))) private alias usize = size_t; +private alias StripTypedef(T) = T; + + +__gshared void delegate (scope const(char[]), scope int fd=1) @trusted nothrow @nogc conwriter; + +public @property auto ConWriter () @trusted nothrow @nogc { return conwriter; } +public @property auto ConWriter (typeof(conwriter) cv) @trusted nothrow @nogc { auto res = conwriter; conwriter = cv; return res; } + + +shared static this () { + conwriter = (scope str, scope fd) @trusted nothrow @nogc { + import core.sys.posix.unistd : STDOUT_FILENO, STDERR_FILENO, write; + if (fd >= 0) { + if (fd == 0 || fd == 1) fd = STDOUT_FILENO; + else if (fd == 2) fd = STDERR_FILENO; + if (str.length > 0) write(fd, str.ptr, str.length); + } + }; +} + + +// width<0: pad right +// width == int.min: no width specified +// maxlen == int.min: no maxlen specified +private void wrWriteWidth(char lfill=' ', char rfill=' ') + (int fd, + int width, + int maxlen, + bool center, + const(char[]) s, + bool leftIsMinus=false) { + static immutable char[64] spacesl = () { char[64] r; foreach (immutable p; 0..64) r[p] = lfill; return r; }(); + static immutable char[64] spacesr = () { char[64] r; foreach (immutable p; 0..64) r[p] = rfill; return r; }(); + usize stpos = 0; + // fix maxlen + if (maxlen != int.min) { + if (maxlen < 0) { + maxlen = -maxlen; + if (maxlen > s.length) { + maxlen = cast(int)s.length; + } else { + stpos = s.length-maxlen; + } + } else if (maxlen > 0) { + if (maxlen > s.length) maxlen = cast(int)s.length; + } + } else { + // no maxlen specified + maxlen = cast(int)s.length; + } + // fuck overflows + if (maxlen < 0) maxlen = 666; + // fix width + if (width == int.min) { + // no width specified, defaults to visible string width + width = cast(int)(s.length-stpos); + // fuck overflows + if (width < 0) width = 666; + } + // centering? + if (center && ((width > 0 && width > maxlen) || (width < 0 && -width > maxlen))) { + // center string + int wdt = (width > 0 ? width : -width)-maxlen; + int spleft = wdt/2+(width > 0 && wdt%2); + int spright = wdt-spleft; + while (spleft > 0) { + if (spleft > spacesl.length) { + conwriter(spacesl, fd); + spleft -= spacesl.length; + continue; + } else { + conwriter(spacesl[0..spleft], fd); + break; + } + } + if (maxlen > 0) conwriter(s[stpos..stpos+maxlen], fd); + while (spright > 0) { + if (spright > spacesr.length) { + conwriter(spacesr, fd); + spright -= spacesr.length; + continue; + } else { + conwriter(spacesr[0..spright], fd); + break; + } + } + } else { + // pad string + bool writeS = true; + if (width < 0) { + // right padding, write string + width = -width; + if (maxlen > 0) conwriter(s[stpos..stpos+maxlen], fd); + writeS = false; + } + if (maxlen < width) { + width -= maxlen; + if (writeS && stpos == 0 && leftIsMinus && width > 0) { + conwriter("-", fd); + // remove '-' + ++stpos; + --maxlen; + } + for (;;) { + if (width > spacesl.length) { + if (writeS) conwriter(spacesl, fd); else conwriter(spacesr, fd); + width -= spacesl.length; + } else { + if (writeS) conwriter(spacesl[0..width], fd); else conwriter(spacesr[0..width], fd); + break; + } + } + } + if (writeS && maxlen > 0) conwriter(s[stpos..stpos+maxlen], fd); + } +} + +// width<0: pad right +// width == int.min: no width specified +// maxlen == int.min: no maxlen specified +private void wrWriteWidthStrZ(char lfill=' ', char rfill=' ') + (int fd, + int width, + int maxlen, + bool center, + const char *s, + bool leftIsMinus=false) { + usize end = 0; + while (s[end]) ++end; + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, s[0..end], leftIsMinus); +} + + +private void wrWriteWidthHex(char lfill=' ', char rfill=' ', T) + (int fd, + int width, + int maxlen, + bool center, + bool upcase, + T numm) +if (isIntegral!T) +{ + import std.traits : isSigned, isMutable, Unqual; + static if (isMutable!T) alias num = numm; else Unqual!T num = cast(Unqual!T)numm; + char[18] hstr = void; + auto pos = hstr.length; + static if (isSigned!T) { + static if (T.sizeof == 8) { + if (num == 0x8000_0000_0000_0000uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-8000000000000000", (lfill == '0')); return; } + } else static if (T.sizeof == 4) { + if (num == 0x8000_0000uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-80000000", (lfill == '0')); return; } + } else static if (T.sizeof == 2) { + if (num == 0x8000uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-8000", (lfill == '0')); return; } + } else static if (T.sizeof == 1) { + if (num == 0x80uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-80", (lfill == '0')); return; } + } + bool neg = (num < 0); + if (neg) num = -num; + } + do { + assert(pos > 0); + ubyte b = num&0x0f; + num >>= 4; + if (b < 10) { + hstr[--pos] = cast(char)('0'+b); + } else if (upcase) { + hstr[--pos] = cast(char)('A'+b-10); + } else { + hstr[--pos] = cast(char)('a'+b-10); + } + } while (num); + static if (isSigned!T) { + if (neg) { + assert(pos > 0); + hstr[--pos] = '-'; + } + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, hstr[pos..$], (neg && lfill == '0')); + } else { + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, hstr[pos..$]); + } +} + + +// 2**64: 18446744073709551616 (20 chars) +// 2**64: 0x1_0000_0000_0000_0000 +// width<0: pad right +private void wrWriteWidthInt(char lfill=' ', char rfill=' ', T) + (int fd, + int width, + int maxlen, + bool center, + T numm) +if (isIntegral!T) +{ + import std.traits : isSigned, isMutable, Unqual; + static if (isMutable!T) alias num = numm; else Unqual!T num = cast(Unqual!T)numm; + char[22] hstr; + auto pos = hstr.length; + static if (isSigned!T) { + static if (T.sizeof == 8) { + if (num == 0x8000_0000_0000_0000uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-9223372036854775808", (lfill == '0')); return; } + } else static if (T.sizeof == 4) { + if (num == 0x8000_0000uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-2147483648", (lfill == '0')); return; } + } else static if (T.sizeof == 2) { + if (num == 0x8000uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-32768", (lfill == '0')); return; } + } else static if (T.sizeof == 1) { + if (num == 0x80uL) { wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, "-128", (lfill == '0')); return; } + } + bool neg = (num < 0); + if (neg) num = -num; + } + do { + assert(pos > 0); + ubyte b = cast(ubyte)(num%10); + num /= 10; + hstr[--pos] = cast(char)('0'+b); + } while (num); + static if (isSigned!T) { + if (neg) { + assert(pos > 0); + hstr[--pos] = '-'; + } + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, hstr[pos..$], (neg && lfill == '0')); + } else { + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, hstr[pos..$]); + } +} + + +private void wrWriteWidthBool(char lfill=' ', char rfill=' ', T) + (int fd, + int width, + int maxlen, + bool center, + T v) +if (isBoolean!T) +{ + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, (v ? "true" : "false")); +} + + +import std.traits : Unqual; +private void wrWriteWidthChar(char lfill=' ', char rfill=' ', T) + (int fd, + int width, + int maxlen, + bool center, + T v) +if (is(Unqual!T == char)) +{ + char[1] s = v; + wrWriteWidth!(lfill, rfill)(fd, width, maxlen, center, s); +} + + +//////////////////////////////////////////////////////////////////////////////// +private auto WrData (int fd, int alen) { + static struct Data { + string fd; // just to pass to writers; string, 'cause we will concat it with other strings + int aidx; // current arg index + int alen; // number of args + // changeable + int width = int.min; // this means 'not specified' + char widthSign = ' '; // '+', '-', '*' (no sign), ' ' (absent) + bool widthZeroStarted; + bool widthWasDigits; + int maxlen = int.min; // this means 'not specified' + char maxlenSign = ' '; // '+', '-', '*' (no sign), ' ' (absent) + bool maxlenZeroStarted; + bool maxlenWasDigits; + bool optCenter; // center string? + char lfchar = ' '; // "left fill" + char rfchar = ' '; // "right fill" + int fillhcharIdx; // 0: next will be lfchar, 1: next will be rfchar; 2: no more fills + string wsep; // separator string for "%|" + + @disable this (); + + this (int afd, usize aalen) { + import std.conv : to; + fd = to!string(afd); + if (aalen >= 1024) assert(0, "too many arguments for writer"); + alen = cast(int)aalen; + } + + // set named field + auto set(string name, T) (in T value) if (__traits(hasMember, this, name)) { + __traits(getMember, this, name) = value; + return this; + } + + // increment current index + auto incAIdx () { + ++aidx; + if (aidx > alen) aidx = alen; + return this; + } + + // prepare for next formatted output (reset all format params) + auto resetFmt () { + // trick with saving necessary fields + auto sfd = fd; + auto saidx = aidx; + auto salen = alen; + this = this.init; + fd = sfd; + aidx = saidx; + alen = salen; + return this; + } + + // set filling char + auto setFillChar (char ch) { + switch (fillhcharIdx) { + case 0: lfchar = ch; break; + case 1: rfchar = ch; break; + default: + } + ++fillhcharIdx; + return this; + } + + // prepare to parse integer field + auto initInt(string name) (char sign) if (__traits(hasMember, this, name)) { + __traits(getMember, this, name) = (sign == '-' ? -1 : 0); + __traits(getMember, this, name~"Sign") = sign; + __traits(getMember, this, name~"ZeroStarted") = false; + __traits(getMember, this, name~"WasDigits") = false; + return this; + } + + // integer field parsing: process next char + auto putIntChar(string name) (char ch) if (__traits(hasMember, this, name)) { + bool wd = __traits(getMember, this, name~"WasDigits"); + if (!wd) { + __traits(getMember, this, name~"ZeroStarted") = (ch == '0'); + __traits(getMember, this, name~"WasDigits") = true; + } + int n = __traits(getMember, this, name); + if (n == int.min) n = 0; + if (n < 0) { + n = -(n+1); + immutable nn = n*10+ch-'0'; + if (nn < n || nn == int.max) assert(0, "integer overflow"); + n = (-nn)-1; + } else { + immutable nn = n*10+ch-'0'; + if (nn < n || nn == int.max) assert(0, "integer overflow"); + n = nn; + } + __traits(getMember, this, name) = n; + return this; + } + + //TODO: do more checks on getInt, getBool, etc. + auto getInt(string name) () if (__traits(hasMember, this, name)) { + import std.traits; + immutable n = __traits(getMember, this, name); + static if (isSigned!(typeof(n))) { + return (n < 0 && n != n.min ? n+1 : n); + } else { + return n; + } + } + + auto getIntDef(string name) () if (__traits(hasMember, this, name)) { + import std.traits; + immutable n = __traits(getMember, this, name); + static if (isSigned!(typeof(n))) { + if (n == n.min) return 0; + else if (n < 0) return n+1; + else return n; + } else { + return n; + } + } + + string getIntStr(string name) () if (__traits(hasMember, this, name)) { + import std.conv : to; + return to!string(getInt!name()); + } + + string getBoolStr(string name) () if (__traits(hasMember, this, name)) { + return (__traits(getMember, this, name) ? "true" : "false"); + } + + // set fillchar according to width flags + auto fixWidthFill () { + if (fillhcharIdx == 0 && widthZeroStarted) { + lfchar = '0'; + fillhcharIdx = 1; + } + return this; + } + } + + return Data(fd, alen); +} + + +//////////////////////////////////////////////////////////////////////////////// +// parse (possibly signed) number +template conwritefImpl(string state, string field, string fmt, alias data, AA...) +if (state == "parse-int") +{ + static assert(fmt.length > 0, "invalid format string"); + static if (fmt[0] == '-' || fmt[0] == '+') { + static assert(fmt.length > 1 && fmt[1] >= '0' && fmt[1] <= '9', "invalid number for '"~field~"'"); + enum conwritefImpl = conwritefImpl!("parse-digits", field, fmt[1..$], data.initInt!field(fmt[0]), AA); + } else static if (fmt[0] >= '0' && fmt[0] <= '9') { + enum conwritefImpl = conwritefImpl!("parse-digits", field, fmt, data.initInt!field('*'), AA); + } else { + enum conwritefImpl = conwritefImpl!("got-"~field, fmt, data.initInt!field(' '), AA); + } +} + + +// parse integer digits +template conwritefImpl(string state, string field, string fmt, alias data, AA...) +if (state == "parse-digits") +{ + static assert(fmt.length > 0, "invalid format string"); + static if (fmt[0] >= '0' && fmt[0] <= '9') { + enum conwritefImpl = conwritefImpl!(state, field, fmt[1..$], data.putIntChar!field(fmt[0]), AA); + } else { + enum conwritefImpl = conwritefImpl!("got-"~field, fmt, data, AA); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// got maxlen, done with width parsing +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "parse-format") +{ + static assert(fmt.length > 0, "invalid format string"); + static assert(fmt[0] == '%', "internal error"); + enum conwritefImpl = conwritefImpl!("parse-options", fmt[1..$], data, AA); +} + + +// parse options +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "parse-options") +{ + import std.string : indexOf; + static if (fmt[0] == '/') { + enum conwritefImpl = conwritefImpl!(state, fmt[1..$], data.set!"optCenter"(true), AA); + } else static if (fmt[0] == '~') { + static assert(fmt.length > 1, "invalid format option: '~'"); + enum conwritefImpl = conwritefImpl!(state, fmt[2..$], data.setFillChar(fmt[1]), AA); + } else static if (fmt[0] == '\0') { + enum epos = fmt.indexOf('\0', 1); + static assert(epos > 0, "unterminated separator option"); + static assert(fmt[epos] == '\0'); + enum conwritefImpl = conwritefImpl!(state, fmt[epos+1..$], data.set!"wsep"(fmt[1..epos]), AA); + } else { + enum conwritefImpl = conwritefImpl!("parse-int", "width", fmt, data, AA); + } +} + + +// got width, try maxlen +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "got-width") +{ + static assert(fmt.length > 0, "invalid format string"); + static if (fmt[0] == '.') { + // got maxlen, parse it + enum conwritefImpl = conwritefImpl!("parse-int", "maxlen", fmt[1..$], data.fixWidthFill(), AA); + } else { + enum conwritefImpl = conwritefImpl!("got-maxlen", fmt, data.fixWidthFill(), AA); + } +} + + +// got maxlen, done with width parsing +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "got-maxlen") +{ + static assert(fmt.length > 0, "invalid format string"); + enum conwritefImpl = conwritefImpl!("format-spec", fmt, data, AA); +} + + +//////////////////////////////////////////////////////////////////////////////// +static template isStaticNarrowString(T) { + import std.traits : isStaticArray; + static if (isStaticArray!T) { + import std.traits : Unqual; + static alias ArrayElementType(T: T[]) = Unqual!T; + enum isStaticNarrowString = is(ArrayElementType!T == char); + } else { + enum isStaticNarrowString = false; + } +} + +template conwritefImpl(string state, alias data, AA...) +if (state == "write-argument-s") +{ + import std.traits : Unqual; + import std.conv : to; + static assert(data.aidx >= 0 && data.aidx < data.alen, "argument index out of range"); + enum aidx = data.aidx; + alias aatype = StripTypedef!(AA[aidx]); + //pragma(msg, "TYPE: ", Unqual!aatype); + static if (is(Unqual!aatype == char[]) || + is(Unqual!aatype == const(char)[]) || + is(aatype == string) || + isStaticNarrowString!aatype) { + //pragma(msg, "STRING!"); + enum callFunc = "wrWriteWidth"; + enum func = ""; + } else static if (isIntegral!aatype) { + enum callFunc = "wrWriteWidthInt"; + enum func = ""; + } else static if (isBoolean!aatype) { + enum callFunc = "wrWriteWidthBool"; + enum func = ""; + } else static if (is(Unqual!aatype == char)) { + enum callFunc = "wrWriteWidthChar"; + enum func = ""; + } else { + // this may allocate! + enum callFunc = "wrWriteWidth"; + enum func = "to!string"; + } + enum lfchar = data.lfchar; + enum rfchar = data.rfchar; + enum conwritefImpl = + callFunc~"!("~lfchar.stringof~","~rfchar.stringof~")("~ + data.fd~","~ + data.getIntStr!"width"()~","~ + data.getIntStr!"maxlen"()~","~ + data.getBoolStr!"optCenter"()~","~ + func~"(args["~to!string(aidx)~"]));\n"; +} + + +template conwritefImpl(string state, alias data, AA...) +if (state == "write-argument-S") +{ + import std.traits : Unqual; + import std.conv : to; + static assert(data.aidx >= 0 && data.aidx < data.alen, "argument index out of range"); + enum aidx = data.aidx; + alias aatype = StripTypedef!(AA[aidx]); + //pragma(msg, "TYPE: ", Unqual!aatype); + static if (is(Unqual!aatype == char*) || + is(Unqual!aatype == const(char)*) || + is(Unqual!aatype == immutable(char)*) || + is(Unqual!aatype == const(char*)) || + is(Unqual!aatype == immutable(char*))) { + enum lfchar = data.lfchar; + enum rfchar = data.rfchar; + enum conwritefImpl = + "wrWriteWidthStrZ!("~lfchar.stringof~","~rfchar.stringof~")("~ + data.fd~","~ + data.getIntStr!"width"()~","~ + data.getIntStr!"maxlen"()~","~ + data.getBoolStr!"optCenter"()~","~ + "(cast(const char*)args["~to!string(aidx)~"]));\n"; + } else { + enum conwritefImpl = conwritefImpl!"write-argument-s"(state, data, AA); + } +} + + +template conwritefImpl(string state, bool upcase, alias data, AA...) +if (state == "write-argument-xx") +{ + import std.traits : Unqual; + import std.conv : to; + static assert(data.aidx >= 0 && data.aidx < data.alen, "argument index out of range"); + enum aidx = data.aidx; + private alias TTA = StripTypedef!(AA[aidx]); + static assert(isIntegral!TTA || isPointer!TTA, "'x' expects integer or pointer argument"); + enum lfchar = data.lfchar; + enum rfchar = data.rfchar; + enum conwritefImpl = + "wrWriteWidthHex!("~lfchar.stringof~","~rfchar.stringof~")("~ + data.fd~","~ + data.getIntStr!"width"()~","~ + data.getIntStr!"maxlen"()~","~ + data.getBoolStr!"optCenter"()~","~ + (upcase ? "true," : "false,")~ + (isPointer!TTA ? "cast(usize)" : "cast("~TTA.stringof~")")~ + "(args["~to!string(aidx)~"]));\n"; +} + + +template conwritefImpl(string state, alias data, AA...) +if (state == "write-argument-x") +{ + enum conwritefImpl = conwritefImpl!("write-argument-xx", false, data, AA); +} + + +template conwritefImpl(string state, alias data, AA...) +if (state == "write-argument-X") +{ + enum conwritefImpl = conwritefImpl!("write-argument-xx", true, data, AA); +} + + +template conwritefImpl(string state, string field, alias data) +if (state == "write-field") +{ + enum fld = __traits(getMember, data, field); + static if (fld.length > 0) { + enum conwritefImpl = "conwriter("~fld.stringof~", "~data.fd~");\n"; + } else { + enum conwritefImpl = ""; + } +} + + +template conwritefImpl(string state, string str, alias data) +if (state == "write-strlit") +{ + static if (str.length > 0) { + enum conwritefImpl = "conwriter("~str.stringof~", "~data.fd~");\n"; + } else { + enum conwritefImpl = ""; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "format-spec") +{ + static assert(fmt.length > 0, "invalid format string"); + static if (fmt[0] == 's' || fmt[0] == 'x' || fmt[0] == 'X' || fmt[0] == 'S') { + // known specs + enum conwritefImpl = + conwritefImpl!("write-argument-"~fmt[0], data, AA)~ + conwritefImpl!("main", fmt[1..$], data.incAIdx(), AA); + } else static if (fmt[0] == '|') { + // write all unprocessed arguments + static if (data.aidx < data.alen) { + // has argument to process + static if (data.aidx+1 < data.alen && data.wsep.length > 0) { + // has separator + enum conwritefImpl = + conwritefImpl!("write-argument-s", data, AA)~ + conwritefImpl!("write-field", "wsep", data)~ + conwritefImpl!(state, fmt, data.incAIdx(), AA); + } else { + // has no separator + enum conwritefImpl = + conwritefImpl!("write-argument-s", data, AA)~ + conwritefImpl!(state, fmt, data.incAIdx(), AA); + } + } else { + // no more arguments + enum conwritefImpl = conwritefImpl!("main", fmt[1..$], data, AA); + } + } else static if (fmt[0] == '@' || fmt[0] == '$') { + // set current argument index + // we must have no maxlen here + static assert(data.maxlenSign == ' ', "invalid position for '@'"); + static if (data.widthSign == '+' || data.widthSign == '-') + enum newpos = data.aidx+data.getIntDef!"width"()+1; + else + enum newpos = data.getIntDef!"width"(); + static assert(newpos >= 1 && newpos <= data.alen+1, "position out of range for '"~fmt[0]~"'"); + static if (fmt[0] == '@' || (fmt.length > 1 && fmt[1] == '%')) { + enum conwritefImpl = conwritefImpl!("main", fmt[1..$], data.set!"aidx"(newpos-1), AA); + } else { + enum conwritefImpl = conwritefImpl!("main", "%"~fmt[1..$], data.set!"aidx"(newpos-1), AA); + } + } else { + static assert(0, "invalid format specifier: '"~fmt[0]~"'"); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +template conwritefImpl(string state, string accum, string fmt, alias data, AA...) +if (state == "main-with-accum") +{ + static if (fmt.length == 0) { + static assert(data.aidx == data.alen, "too many arguments to writer"); + enum conwritefImpl = conwritefImpl!("write-strlit", accum, data); + } else static if (fmt[0] == '%') { + static assert (fmt.length > 1, "invalid format string"); + static if (fmt[1] == '%') { + // '%%' + enum conwritefImpl = conwritefImpl!(state, accum~"%", fmt[2..$], data, AA); + } else static if (fmt[1] == '!') { + // '%!' + enum conwritefImpl = conwritefImpl!(state, accum, fmt[2..$], data.set!"aidx"(data.alen), AA); + } else { + // other format specifiers + enum conwritefImpl = + conwritefImpl!("write-strlit", accum, data)~ + conwritefImpl!("parse-format", fmt, data, AA); + } + } else { + import std.string : indexOf; + enum ppos = fmt.indexOf('%'); + static if (ppos < 0) { + // no format specifiers + enum conwritefImpl = conwritefImpl!("write-strlit", accum~fmt, data); + } else { + enum conwritefImpl = conwritefImpl!(state, accum~fmt[0..ppos], fmt[ppos..$], data, AA); + } + } +} + + +//////////////////////////////////////////////////////////////////////////////// +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "main") +{ + enum conwritefImpl = conwritefImpl!("main-with-accum", "", fmt, data.resetFmt(), AA); +} + + +//////////////////////////////////////////////////////////////////////////////// +void fdwritef(int fd, string fmt, AA...) (AA args) { + import std.string : indexOf; + static if (fmt.indexOf('%') < 0) { + conwriter(fmt, fd); + } else { + import std.conv : to; + enum mixstr = conwritefImpl!("main", fmt, WrData(fd, AA.length), AA); + //pragma(msg, "-------\n"~mixstr~"-------"); + mixin(mixstr); + } + conwriter(null, fd); +} + + +//////////////////////////////////////////////////////////////////////////////// +public: + +//void fdwritef(int fd, string fmt, A...) (A args) { fdwritef!(fd, fmt)(args); } +void fdwrite(int fd, A...) (A args) { fdwritef!(fd, "%|")(args); } +void fdwriteln(int fd, A...) (A args) { fdwritef!(fd, "%|\n")(args); } + +void conwritef(string fmt, A...) (A args) { fdwritef!(1, fmt)(args); } +void errwritef(string fmt, A...) (A args) { fdwritef!(2, fmt)(args); } + +void conwritefln(string fmt, A...) (A args) { fdwritef!(1, fmt~"\n")(args); } +void errwritefln(string fmt, A...) (A args) { fdwritef!(2, fmt~"\n")(args); } + +void conwrite(A...) (A args) { fdwritef!(1, "%|")(args); } +void errwrite(A...) (A args) { fdwritef!(2, "%|")(args); } + +void conwriteln(A...) (A args) { fdwritef!(1, "%|\n")(args); } +void errwriteln(A...) (A args) { fdwritef!(2, "%|\n")(args); } + + +//////////////////////////////////////////////////////////////////////////////// +version(writer_test) +unittest { + class A { + override string toString () const { return "{A}"; } + } + + char[] n = ['x', 'y', 'z']; + char[3] t = "def";//['d', 'e', 'f']; + conwriter("========================\n"); + conwritef!"`%%`\n"(); + conwritef!"`%-3s`\n"(42); + conwritef!"<`%3s`%%{str=%s}%|>\n"(cast(int)42, "[a]", new A(), n, t[]); + conwritefln!"<`%3@%3s`>%!"(cast(int)42, "[a]", new A(), n, t); + errwriteln("stderr"); + conwritefln!"`%-3s`"(42); + conwritefln!"`%!z%-2@%-3s`%!"(69, 42, 666); + conwritefln!"`%!%1@%-3s%!`"(69, 42, 666); + conwritefln!"`%!%-1@%+0@%-3s%!`"(69, 42, 666); + conwritefln!"`%3.5s`"("a"); + conwritefln!"`%7.5s`"("abcdefgh"); + conwritef!"%|\n"(42, 666); + conwritefln!"`%/10.5s`"("abcdefgh"); + conwritefln!"`%/-10.-5s`"("abcdefgh"); + conwritefln!"`%/~+-10.-5s`"("abcdefgh"); + conwritefln!"`%/~+~:-10.-5s`"("abcdefgh"); + conwritef!"%\0<>\0|\n"(42, 666, 999); + conwritef!"%\0\t\0|\n"(42, 666, 999); + conwritefln!"`%~*05s %~.5s`"(42, 666); + conwritef!"`%s`\n"(t); + conwritef!"`%08s`\n"("alice"); + conwritefln!"#%08x"(16396); + conwritefln!"#%08X"(-16396); + conwritefln!"#%02X"(-16385); + conwritefln!"[%06s]"(-666); + conwritefln!"[%06s]"(cast(long)0x8000_0000_0000_0000uL); + conwritefln!"[%06x]"(cast(long)0x8000_0000_0000_0000uL); + + version(aliced) { + enum TypedefTestStr = q{ + typedef MyInt = int; + typedef MyString = string; + + MyInt mi = 42; + MyString ms = cast(MyString)"hurry"; + conwritefln!"%s"(mi); + conwritefln!"%x"(mi); + conwritefln!"%s"(ms); + + void testBool () @nogc { + conwritefln!"%s"(true); + conwritefln!"%s"(false); + } + testBool(); + + conwritefln!"Hello, %2$s, I'm %1$s."("Alice", "Miriel"); + conwritef!"%2$7s|\n%1$%7s|\n%||\n"("Alice", "Miriel"); + }; + //mixin(TypedefTestStr); + } + + immutable char *strz = "stringz\0s"; + conwritefln!"[%S]"(strz); +} diff --git a/d2dmap.d b/d2dmap.d index 2fad255..2b8196a 100644 --- a/d2dmap.d +++ b/d2dmap.d @@ -5,6 +5,7 @@ import arsd.color; import iv.stream; import glutils; +import console; import wadarc; @@ -284,12 +285,11 @@ public: void dump (int idx) { static char to62 (ubyte b) { pragma(inline, true); return cast(char)(b < 10 ? '0'+b : (b-10 < 26 ? 'A'+(b-10) : 'a'+(b-10-26))); } - import std.stdio; foreach (immutable y; 0..MapSize) { foreach (immutable x; 0..MapSize) { - write(to62(tiles[idx][y][x])); + conwrite(to62(tiles[idx][y][x])); } - writeln; + conwriteln; } } @@ -376,15 +376,15 @@ private: tn = texname[0..idx+1]; } wallnames ~= tn.idup; - //debug { import std.stdio; writeln(wallnames.length-1, " : ", wallnames[$-1]); } + //debug { conwriteln(wallnames.length-1, " : ", wallnames[$-1]); } //if (wallnames[$-1][$-1] == '_') wallnames[$-1] ~= "1"; //wallnames[$-1] ~= ".vga"; - //writeln(wallnames[$-1]); + //conwriteln(wallnames[$-1]); //walltypes ~= type; bsize -= 8+1; } if (bsize != 0) throw new Exception("invalid texture chunk size"); - debug { import std.stdio; writeln(wallnames.length, " textures loaded"); } + debug { conwriteln(wallnames.length, " textures loaded"); } } else { auto pkdata = new ubyte[](bsize); st.rawReadExact(pkdata[]); @@ -411,7 +411,7 @@ private: } skytex = new WallTexture("sprites/rsky1.vga"); skytex.sx = skytex.sy = 0; - debug { import std.stdio; writeln(width, "x", height); } + debug { conwriteln(width, "x", height); } } } diff --git a/d2dmon.d b/d2dmon.d index b632ebc..0fd8364 100644 --- a/d2dmon.d +++ b/d2dmon.d @@ -1,6 +1,8 @@ module d2dmon is aliced; +import console; import tparser; +import wadarc; // ////////////////////////////////////////////////////////////////////////// // @@ -100,6 +102,51 @@ enum MonType { // ////////////////////////////////////////////////////////////////////////// // +enum ItemType { + Nothing, + Clip, + Shell, + Rocket, + Cell, + Ammo, + ShellBox, + RocketBox, + CellPack, + StimPack, + MediKit, + BackPack, + Chainsaw, + Shotgun, + SuperShotgun, + MachineGun, + RocketLauncher, + Plasmagun, + BFG900, + Armor1, + Armor2, + MegaSphere, + Invulnerability, + Aqualung, + RedKey, + GreenKey, + BlueKey, + ProtectionSuit, + Super, //??? + RedTorch, + GreenTorch, + BlueTorch, + Gor1, //??? + FCan, //??? + Gun2, //??? +} + + +// ////////////////////////////////////////////////////////////////////////// // +__gshared ItemTemplate[ItemType.max+1] itemTpls; +__gshared MonsterTemplate[MonType.max+1] monTpls; + + +// ////////////////////////////////////////////////////////////////////////// // class AnimAction { int len; // in frames this (int alen) { len = (alen < 0 ? 0 : alen); } @@ -352,6 +399,7 @@ class ThingTemplate { enum FieldIntPos; enum FieldStr; + string classname = null; string name; // thing name @FieldIntPos int radius = -1; @FieldIntPos int height = -1; @@ -361,6 +409,7 @@ class ThingTemplate { // should be at starting "{" this(PR) (ref PR parser) { + if (classname is null) classname = "Thing"; int getEqIntPos () { parser.popFront(); // skip name parser.skipDelim('='); @@ -493,11 +542,46 @@ public: return FieldInfo(FieldInfo.Type.None, null, ""); } }; + + private import std.stdio : File; + enum DumpMixin = q{ + void dump (File fo) { + fo.writeln(classname, " ", name, " {"); + foreach (string mem; __traits(allMembers, typeof(this))) { + static if (is(typeof(mixin("this."~mem)))) { + import std.traits : hasUDA; + static if (hasUDA!(mixin("this."~mem), FieldIntPos)) { + mixin("fo.writeln(` "~mem~" = `, this."~mem~", `;`);"); + } else static if (hasUDA!(mixin("this."~mem), FieldStr)) { + mixin("fo.writeln(` "~mem~" = \"`, this."~mem~", `\";`);"); + } + } + } + asc.dump(fo); + fo.writeln("}"); + fo.writeln("//============="); + } + }; + mixin(DumpMixin); +} + + +// ////////////////////////////////////////////////////////////////////////// // +final class ItemTemplate : ThingTemplate { + mixin("override "~FindFieldMixin); + mixin("override "~DumpMixin); + + override void checkProps () { + super.checkProps(); + } + + // "Item" is skipped + this(PR) (ref PR parser) { classname = "Item"; super(parser); } } // ////////////////////////////////////////////////////////////////////////// // -final class MonsterInfo : ThingTemplate { +final class MonsterTemplate : ThingTemplate { @FieldIntPos int painin = -1; @FieldIntPos int xvel = -1; @FieldIntPos int yvel = -1; @@ -505,6 +589,7 @@ final class MonsterInfo : ThingTemplate { @FieldIntPos int painout = -1; mixin("override "~FindFieldMixin); + mixin("override "~DumpMixin); override void checkProps () { if (hitpoints < 0) err("undefined hitpoints"); @@ -517,40 +602,57 @@ final class MonsterInfo : ThingTemplate { } // "Actor" is skipped - this(PR) (ref PR parser) { super(parser); } - - private import std.stdio : File; - void dump (File fo) { - fo.writeln("Actor ", name, " {"); - foreach (string mem; __traits(allMembers, typeof(this))) { - static if (is(typeof(mixin("this."~mem)))) { - import std.traits : hasUDA; - static if (hasUDA!(mixin("this."~mem), FieldIntPos)) { - mixin("fo.writeln(` "~mem~" = `, this."~mem~", `;`);"); - } else static if (hasUDA!(mixin("this."~mem), FieldStr)) { - mixin("fo.writeln(` "~mem~" = \"`, this."~mem~", `\";`);"); - } - } - } - asc.dump(fo); - fo.writeln("}"); - fo.writeln("//============="); - } + this(PR) (ref PR parser) { classname = "Actor"; super(parser); } } // ////////////////////////////////////////////////////////////////////////// // -/* -unittest { - import std.file : readText; - import std.stdio; - auto parser = TextParser(readText("zmon.txt")); - while (!parser.empty) { - if (parser.tstr != "Actor") parser.error("'Actor' expected"); - parser.popFront(); - auto mon = new MonsterInfo(parser); - //writeln(mon.name, ": loaded"); - mon.dump(stdout); +public void loadTemplates () { + import std.conv : to; + conwriteln("loading monsters..."); + { + auto parser = TextParser(loadTextFile("monsters.txt")); + while (!parser.empty) { + if (parser.tstr != "Actor") parser.error("'Actor' expected, got '"~parser.tstr.idup~"'"); + parser.popFront(); + parser.expectStr(); + int midx = -1; + try { + midx = cast(int)(to!MonType(parser.tstr)); + } catch (Exception e) { + conwriteln("unknown monster: '", parser.tstr, "'"); + assert(0); + } + if (midx < 1 || midx > MonType.max) { + conwriteln("unknown monster: '", parser.tstr, "'"); + assert(0); + } + monTpls[midx] = new MonsterTemplate(parser); + conwriteln(monTpls[midx].name, ": loaded"); + //mon.dump(stdout); + } + } + conwriteln("loading items..."); + { + auto parser = TextParser(loadTextFile("items.txt")); + while (!parser.empty) { + if (parser.tstr != "Item") parser.error("'Item' expected, got '"~parser.tstr.idup~"'"); + parser.popFront(); + parser.expectStr(); + int midx = -1; + try { + midx = cast(int)(to!ItemType(parser.tstr)); + } catch (Exception e) { + conwriteln("unknown item: '", parser.tstr, "'"); + assert(0); + } + if (midx < 1 || midx > ItemType.max) { + conwriteln("unknown item: '", parser.tstr, "'"); + assert(0); + } + itemTpls[midx] = new ItemTemplate(parser); + conwriteln(itemTpls[midx].name, ": loaded"); + //mon.dump(stdout); + } } } -*/ diff --git a/data/items.txt b/data/items.txt new file mode 100644 index 0000000..660bf01 --- /dev/null +++ b/data/items.txt @@ -0,0 +1,476 @@ +//////////////////////////////////////////////////////////////////////////////// +Item Clip { + radius = 10; + height = 8; + base = "sprites/items/clip"; + + states { + sleep: + clip; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Shell { + radius = 10; + height = 8; + base = "sprites/items/shell"; + + states { + sleep: + shel; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Rocket { + radius = 10; + height = 8; + base = "sprites/items/rocket"; + + states { + sleep: + rocket; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Cell { + radius = 10; + height = 8; + base = "sprites/items/cell"; + + states { + sleep: + cell; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Ammo { + radius = 10; + height = 8; + base = "sprites/items/ammo"; + + states { + sleep: + ammo; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item ShellBox { + radius = 10; + height = 8; + base = "sprites/items/shellbox"; + + states { + sleep: + sbox; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item RocketBox { + radius = 10; + height = 8; + base = "sprites/items/rocketbox"; + + states { + sleep: + rbox; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item CellPack { + radius = 10; + height = 8; + base = "sprites/items/cellpack"; + + states { + sleep: + celp; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item StimPack { + radius = 10; + height = 8; + base = "sprites/items/stimpack"; + + states { + sleep: + stim; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item MediKit { + radius = 10; + height = 8; + base = "sprites/items/medikit"; + + states { + sleep: + medi; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item BackPack { + radius = 10; + height = 8; + base = "sprites/items/backpack"; + + states { + sleep: + bpack; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Chainsaw { + radius = 10; + height = 8; + base = "sprites/items/chainsaw"; + + states { + sleep: + csaw; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Shotgun { + radius = 10; + height = 8; + base = "sprites/items/shotgun"; + + states { + sleep: + sgun; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item SuperShotgun { + radius = 10; + height = 8; + base = "sprites/items/supershotgun"; + + states { + sleep: + sgun2; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item MachineGun { + radius = 10; + height = 8; + base = "sprites/items/machinegun"; + + states { + sleep: + mgun; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item RocketLauncher { + radius = 10; + height = 8; + base = "sprites/items/rocketlauncher"; + + states { + sleep: + laun; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Plasmagun { + radius = 10; + height = 8; + base = "sprites/items/plasmagun"; + + states { + sleep: + plas; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item BFG900 { + radius = 10; + height = 8; + base = "sprites/items/bfg900"; + + states { + sleep: + bfg; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Armor1 { + radius = 10; + height = 8; + base = "sprites/items/armor1"; + + states { + sleep: + arm1; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Armor2 { + radius = 10; + height = 8; + base = "sprites/items/armor2"; + + states { + sleep: + arm2; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item MegaSphere { + radius = 10; + height = 8; + base = "sprites/items/megasphere"; + + states { + sleep: + mega; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Invulnerability { + radius = 10; + height = 8; + base = "sprites/items/invulnerability"; + + states { + sleep: + invl; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Aqualung { + radius = 10; + height = 8; + base = "sprites/items/aqualung"; + + states { + sleep: + aqua; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item RedKey { + radius = 10; + height = 8; + base = "sprites/items/redkey"; + + states { + sleep: + keyr; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item GreenKey { + radius = 10; + height = 8; + base = "sprites/items/greenkey"; + + states { + sleep: + keyg; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item BlueKey { + radius = 10; + height = 8; + base = "sprites/items/bluekey"; + + states { + sleep: + keyb; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item ProtectionSuit { + radius = 10; + height = 8; + base = "sprites/items/protectionsuit"; + + states { + sleep: + suit; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Super { + radius = 10; + height = 8; + base = "sprites/items/super"; + + states { + sleep: + super; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item RedTorch { + radius = 10; + height = 8; + base = "sprites/items/redtorch"; + + states { + sleep: + rtorch; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item GreenTorch { + radius = 10; + height = 8; + base = "sprites/items/greentorch"; + + states { + sleep: + gtorch; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item BlueTorch { + radius = 10; + height = 8; + base = "sprites/items/bluetorch"; + + states { + sleep: + btorch; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Gor1 { + radius = 10; + height = 8; + base = "sprites/items/gor1"; + + states { + sleep: + gor1; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item FCan { + radius = 10; + height = 8; + base = "sprites/items/fcan"; + + states { + sleep: + fcan; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Item Gun2 { + radius = 10; + height = 8; + base = "sprites/items/gun2"; + + states { + sleep: + gun2; + @loop; + } +} + + diff --git a/data/monsters.txt b/data/monsters.txt new file mode 100644 index 0000000..356394e --- /dev/null +++ b/data/monsters.txt @@ -0,0 +1,1682 @@ +//////////////////////////////////////////////////////////////////////////////// +Actor Demon { + radius = 15; + height = 28; + hitpoints = 60; + painin = 20; + xvel = 7; + yvel = 10; + slophit = 0; + painout = 10; + base = "sprites/monsters/demon"; + + states { + sleep: /*MNST_SLEEP*/ + sarga(3); + sargb; + @loop; + + sighted: /*MNST_RUN*/ + sarga @sound("sgtsit"); + sarga; + sargb(2); + sargc; + sargd(2); + @loop; + + walk: /*MNST_GO*/ + sarga @sound("dmact"); + sarga; + sargb(2); + sargc; + sargd(2); + @loop; + + runout: /*MNST_RUNOUT*/ + sarga(2); + sargb; + sargc(2); + sargd; + @loop; + + climb: /*MNST_CLIMB*/ + sarga(2); + sargb; + sargc(2); + sargd; + @loop; + + attack: /*MNST_ATTACK*/ + sarge @sound("sgtatk"); + sarge; + sargf(2); + sargg; + @loop; + + pain: /*MNST_PAIN*/ + sargh @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + sarga; + @loop; + + die: /*MNST_DIE*/ + sargi @sound("sgtdth"); + sargi(2); + sargj(2); + sargk(2); + sargl(2); + sargm(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + sargn; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Imp { + radius = 10; + height = 28; + hitpoints = 25; + painin = 15; + xvel = 3; + yvel = 10; + slophit = 30; + painout = 0; + base = "sprites/monsters/imp"; + + states { + sleep: /*MNST_SLEEP*/ + trooa(3); + troob; + @loop; + + sighted: /*MNST_RUN*/ + trooa(2); + troob; + trooc(2); + trood; + @loop; + + walk: /*MNST_GO*/ + trooa @sound("bgact"); + trooa; + troob(2); + trooc; + trood(2); + @loop; + + runout: /*MNST_RUNOUT*/ + trooa(2); + troob; + trooc(2); + trood; + @loop; + + climb: /*MNST_CLIMB*/ + trooa(2); + troob; + trooc(2); + trood; + @loop; + + attack: /*MNST_ATTACK*/ + trooe @sound("claw"); + trooe; + troof(2); + troog; + @loop; + + pain: /*MNST_PAIN*/ + trooh @sound("popain"); + @loop; + + wait: /*MNST_WAIT*/ + trooa; + @loop; + + die: /*MNST_DIE*/ + trooi(3); + trooj; + trook(3); + trool; + @setstate dead; + + slop: /*MNST_DIE*/ + troon(3); + trooo; + troop(3); + troor; + troos(3); + troot; + @loop; + + mess: /*MNST_DIE*/ + troou; + @loop; + + dead: /*MNST_DEAD*/ + troom; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Zombie { + radius = 10; + height = 28; + hitpoints = 15; + painin = 10; + xvel = 3; + yvel = 10; + slophit = 30; + painout = 0; + base = "sprites/monsters/zombie"; + + states { + sleep: /*MNST_SLEEP*/ + possa(3); + possb; + @loop; + + sighted: /*MNST_RUN*/ + possa(2); + possb; + possd(2); + possa; + possc(2); + possd; + @loop; + + walk: /*MNST_GO*/ + possa @sound("posact"); + possa; + possb(2); + possd; + possa(2); + possc; + possd(2); + @loop; + + runout: /*MNST_RUNOUT*/ + possa(2); + possb; + possd(2); + possa; + possc(2); + possd; + @loop; + + climb: /*MNST_CLIMB*/ + possa(2); + possb; + possd(2); + possa; + possc(2); + possd; + @loop; + + attack: /*MNST_ATTACK*/ + posse(5); + @loop; + + pain: /*MNST_PAIN*/ + possg @sound("popain"); + @loop; + + wait: /*MNST_WAIT*/ + possa; + @loop; + + die: /*MNST_DIE*/ + possh(3); + possi; + possj(3); + possk; + @setstate dead; + + slop: /*MNST_DIE*/ + possm(3); + possn; + posso(3); + possp; + possr(3); + posss; + posst(3); + @loop; + + mess: /*MNST_DIE*/ + possu; + @loop; + + dead: /*MNST_DEAD*/ + possl; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Sergeant { + radius = 10; + height = 28; + hitpoints = 20; + painin = 10; + xvel = 3; + yvel = 10; + slophit = 30; + painout = 0; + base = "sprites/monsters/sergeant"; + + states { + sleep: /*MNST_SLEEP*/ + sposa(3); + sposb; + @loop; + + sighted: /*MNST_RUN*/ + sposa(2); + sposb; + sposd(2); + sposa; + sposc(2); + sposd; + @loop; + + walk: /*MNST_GO*/ + sposa @sound("posact"); + sposa; + sposb(2); + sposd; + sposa(2); + sposc; + sposd(2); + @loop; + + runout: /*MNST_RUNOUT*/ + sposa(2); + sposb; + sposd(2); + sposa; + sposc(2); + sposd; + @loop; + + climb: /*MNST_CLIMB*/ + sposa(2); + sposb; + sposd(2); + sposa; + sposc(2); + sposd; + @loop; + + attack: /*MNST_ATTACK*/ + spose(5); + @loop; + + pain: /*MNST_PAIN*/ + sposg @sound("popain"); + @loop; + + wait: /*MNST_WAIT*/ + sposa; + @loop; + + die: /*MNST_DIE*/ + sposh(3); + sposi; + sposj(3); + sposk; + @setstate dead; + + slop: /*MNST_DIE*/ + sposm(3); + sposn; + sposo(3); + sposp; + sposr(3); + sposs; + spost(3); + @loop; + + mess: /*MNST_DIE*/ + sposu; + @loop; + + dead: /*MNST_DEAD*/ + sposl; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Cyberdemon { + radius = 20; + height = 55; + hitpoints = 500; + painin = 70; + xvel = 5; + yvel = 10; + slophit = 0; + painout = 50; + base = "sprites/monsters/cyberdemon"; + + states { + sleep: /*MNST_SLEEP*/ + cybra(3); + cybrb; + @loop; + + sighted: /*MNST_RUN*/ + cybra @sound("cybsit"); + cybra; + cybrb(2); + cybrd; + cybrc(2); + cybrd; + cybrb(2); + @loop; + + walk: /*MNST_GO*/ + cybra(2); + cybrb; + cybrd(2); + cybrc; + cybrd(2); + cybrb; + @loop; + + runout: /*MNST_RUNOUT*/ + cybra(2); + cybrb; + cybrd(2); + cybrc; + cybrd(2); + cybrb; + @loop; + + climb: /*MNST_CLIMB*/ + cybra(2); + cybrb; + cybrd(2); + cybrc; + cybrd(2); + cybrb; + @loop; + + attack: /*MNST_ATTACK*/ + cybre @sound("hoof"); + cybre(4); + @loop; + + pain: /*MNST_PAIN*/ + cybrg @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + cybra; + @loop; + + die: /*MNST_DIE*/ + cybrh @sound("cybdth"); + cybrh(2); + cybri(2); + cybrj(2); + cybrk(2); + cybrl(2); + cybrm(2); + cybrn(2); + cybro(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + cybrp; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Chaingunner { + radius = 12; + height = 28; + hitpoints = 60; + painin = 20; + xvel = 3; + yvel = 10; + slophit = 30; + painout = 10; + base = "sprites/monsters/chaingunner"; + + states { + sleep: /*MNST_SLEEP*/ + cposa(3); + cposb; + @loop; + + sighted: /*MNST_RUN*/ + cposa(2); + cposb; + cposd(2); + cposa; + cposc(2); + cposd; + @loop; + + walk: /*MNST_GO*/ + cposa @sound("posact"); + cposa; + cposb(2); + cposd; + cposa(2); + cposc; + cposd(2); + @loop; + + runout: /*MNST_RUNOUT*/ + cposa(2); + cposb; + cposd(2); + cposa; + cposc(2); + cposd; + @loop; + + climb: /*MNST_CLIMB*/ + cposa(2); + cposb; + cposd(2); + cposa; + cposc(2); + cposd; + @loop; + + attack: /*MNST_ATTACK*/ + cpose; + cposf; + @loop; + + pain: /*MNST_PAIN*/ + cposg @sound("popain"); + @loop; + + wait: /*MNST_WAIT*/ + cposa; + @loop; + + die: /*MNST_DIE*/ + cposh(3); + cposi; + cposj(3); + cposk; + cposl(3); + cposm; + @setstate dead; + + slop: /*MNST_DIE*/ + cposo(3); + cposp; + cposq(3); + cposr; + cposs(3); + @loop; + + mess: /*MNST_DIE*/ + cpost; + @loop; + + dead: /*MNST_DEAD*/ + cposn; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor BaronOfHell { + radius = 12; + height = 32; + hitpoints = 150; + painin = 40; + xvel = 3; + yvel = 10; + slophit = 0; + painout = 30; + base = "sprites/monsters/baron"; + + states { + sleep: /*MNST_SLEEP*/ + bossa(3); + bossb; + @loop; + + sighted: /*MNST_RUN*/ + bossa @sound("brssit"); + bossa; + bossb(2); + bossc; + bossd(2); + @loop; + + walk: /*MNST_GO*/ + bossa(2); + bossb; + bossc(2); + bossd; + @loop; + + runout: /*MNST_RUNOUT*/ + bossa(2); + bossb; + bossc(2); + bossd; + @loop; + + climb: /*MNST_CLIMB*/ + bossa(2); + bossb; + bossc(2); + bossd; + @loop; + + attack: /*MNST_ATTACK*/ + bosse(2); + bossf; + bossg(2); + @loop; + + pain: /*MNST_PAIN*/ + bossh @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + bossa; + @loop; + + die: /*MNST_DIE*/ + bossi @sound("brsdth"); + bossi(2); + bossj(2); + bossk(2); + bossl(2); + bossm(2); + bossn(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + bosso; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor HellKnight { + radius = 12; + height = 32; + hitpoints = 75; + painin = 40; + xvel = 3; + yvel = 10; + slophit = 0; + painout = 30; + base = "sprites/monsters/knight"; + + states { + sleep: /*MNST_SLEEP*/ + bos2a(3); + bos2b; + @loop; + + sighted: /*MNST_RUN*/ + bos2a @sound("kntsit"); + bos2a; + bos2b(2); + bos2c; + bos2d(2); + @loop; + + walk: /*MNST_GO*/ + bos2a(2); + bos2b; + bos2c(2); + bos2d; + @loop; + + runout: /*MNST_RUNOUT*/ + bos2a(2); + bos2b; + bos2c(2); + bos2d; + @loop; + + climb: /*MNST_CLIMB*/ + bos2a(2); + bos2b; + bos2c(2); + bos2d; + @loop; + + attack: /*MNST_ATTACK*/ + bos2e(2); + bos2f; + bos2g(2); + @loop; + + pain: /*MNST_PAIN*/ + bos2h @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + bos2a; + @loop; + + die: /*MNST_DIE*/ + bos2i @sound("kntdth"); + bos2i(2); + bos2j(2); + bos2k(2); + bos2l(2); + bos2m(2); + bos2n(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + bos2o; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Cacodemon { + radius = 15; + height = 28; + hitpoints = 100; + painin = 10; + xvel = 4; + yvel = 4; + slophit = 0; + painout = 0; + base = "sprites/monsters/cacodemon"; + + states { + sleep: /*MNST_SLEEP*/ + heada; + @loop; + + sighted: /*MNST_RUN*/ + heada @sound("cacsit"); + @loop; + + walk: /*MNST_GO*/ + heada @sound("dmact"); + @loop; + + runout: /*MNST_RUNOUT*/ + heada; + @loop; + + climb: /*MNST_CLIMB*/ + heada; + @loop; + + attack: /*MNST_ATTACK*/ + headb(2); + headc; + headd(2); + @loop; + + pain: /*MNST_PAIN*/ + headf @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + heada; + @loop; + + die: /*MNST_DIE*/ + headg @sound("cacdth"); + headg(2); + headh(2); + headi(2); + headj(2); + headk(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + headl; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor LostSoul { + radius = 8; + height = 18; + hitpoints = 60; + painin = 10; + xvel = 4; + yvel = 4; + slophit = 0; + painout = 0; + base = "sprites/monsters/soul"; + + states { + sleep: /*MNST_SLEEP*/ + skula(3); + skulb; + @loop; + + sighted: /*MNST_RUN*/ + skula @sound("sklatk"); + skula; + skulb(2); + @loop; + + walk: /*MNST_GO*/ + skula @sound("dmact"); + skula; + skulb(2); + @loop; + + runout: /*MNST_RUNOUT*/ + skula(2); + skulb; + @loop; + + climb: /*MNST_CLIMB*/ + skula(2); + skulb; + @loop; + + attack: /*MNST_ATTACK*/ + skulc @sound("sklatk"); + skulc; + skuld(2); + @loop; + + pain: /*MNST_PAIN*/ + skule @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + skula(2); + skulb; + @loop; + + die: /*MNST_DIE*/ + skulf @sound("firxpl"); + skulf(2); + skulg(2); + skulh(2); + skuli(2); + skulj(2); + skulk(2); + @setstate dead; + dead: + @remove; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor PainElemental { + radius = 15; + height = 28; + hitpoints = 100; + painin = 10; + xvel = 4; + yvel = 4; + slophit = 0; + painout = 0; + base = "sprites/monsters/painel"; + + states { + sleep: /*MNST_SLEEP*/ + paina(3); + painb; + @loop; + + sighted: /*MNST_RUN*/ + paina @sound("pesit"); + paina; + painb(2); + painc; + painb(2); + @loop; + + walk: /*MNST_GO*/ + paina @sound("dmact"); + paina; + painb(2); + painc; + painb(2); + @loop; + + runout: /*MNST_RUNOUT*/ + paina(2); + painb; + painc(2); + painb; + @loop; + + climb: /*MNST_CLIMB*/ + paina(2); + painb; + painc(2); + painb; + @loop; + + attack: /*MNST_ATTACK*/ + paind(2); + paine; + painf(2); + @loop; + + pain: /*MNST_PAIN*/ + paing @sound("pepain"); + @loop; + + wait: /*MNST_WAIT*/ + paina; + @loop; + + die: /*MNST_DIE*/ + painh @sound("pedth"); + painh(2); + paini(2); + painj(2); + paink(2); + painl(2); + painm(2); + @setstate dead; + dead: + @remove; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor SpiderMastermind { + radius = 64; + height = 50; + hitpoints = 500; + painin = 70; + xvel = 4; + yvel = 10; + slophit = 0; + painout = 50; + base = "sprites/monsters/mastermind"; + + states { + sleep: /*MNST_SLEEP*/ + spida(3); + spidb; + @loop; + + sighted: /*MNST_RUN*/ + spida @sound("spisit"); + spida; + spidb(2); + spidc; + spidd(2); + spide; + spidf(2); + @loop; + + walk: /*MNST_GO*/ + spida(2); + spidb; + spidc(2); + spidd; + spide(2); + spidf; + @loop; + + runout: /*MNST_RUNOUT*/ + spida(2); + spidb; + spidc(2); + spidd; + spide(2); + spidf; + @loop; + + climb: /*MNST_CLIMB*/ + spida(2); + spidb; + spidc(2); + spidd; + spide(2); + spidf; + @loop; + + attack: /*MNST_ATTACK*/ + spidg @sound("metal"); + spidh; + @loop; + + pain: /*MNST_PAIN*/ + spidi @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + spida; + @loop; + + die: /*MNST_DIE*/ + spidj @sound("spidth"); + spidj(3); + spidk(2); + spidl(3); + spidm(2); + spidn(3); + spido(2); + spidp(3); + spidq(2); + spidr(3); + @setstate dead; + + dead: /*MNST_DEAD*/ + spids; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Arachnotron { + radius = 25; + height = 27; + hitpoints = 150; + painin = 20; + xvel = 4; + yvel = 10; + slophit = 0; + painout = 0; + base = "sprites/monsters/arachnotron"; + + states { + sleep: /*MNST_SLEEP*/ + bspia(3); + bspib; + @loop; + + sighted: /*MNST_RUN*/ + bspia @sound("bspsit"); + bspia; + bspib(2); + bspic; + bspid(2); + bspie; + bspif(2); + @loop; + + walk: /*MNST_GO*/ + bspia @sound("bspact"); + bspia; + bspib(2); + bspic; + bspid(2); + bspie; + bspif(2); + @loop; + + runout: /*MNST_RUNOUT*/ + bspia(2); + bspib; + bspic(2); + bspid; + bspie(2); + bspif; + @loop; + + climb: /*MNST_CLIMB*/ + bspia(2); + bspib; + bspic(2); + bspid; + bspie(2); + bspif; + @loop; + + attack: /*MNST_ATTACK*/ + bspig @sound("bspwlk"); + bspih; + @loop; + + pain: /*MNST_PAIN*/ + bspii @sound("dmpain"); + @loop; + + wait: /*MNST_WAIT*/ + bspia; + @loop; + + die: /*MNST_DIE*/ + bspij @sound("bspdth"); + bspij(2); + bspik(2); + bspil(2); + bspim(2); + bspin(2); + bspio(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + bspip; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Mancubus { + radius = 18; + height = 30; + hitpoints = 200; + painin = 40; + xvel = 3; + yvel = 7; + slophit = 0; + painout = 20; + base = "sprites/monsters/mancubus"; + + states { + sleep: /*MNST_SLEEP*/ + fatta(3); + fattb; + @loop; + + sighted: /*MNST_RUN*/ + fatta @sound("mansit"); + fatta; + fattb(2); + fattc; + fattd(2); + fatte; + fattf(2); + @loop; + + walk: /*MNST_GO*/ + fatta @sound("dmact"); + fatta; + fattb(2); + fattc; + fattd(2); + fatte; + fattf(2); + @loop; + + runout: /*MNST_RUNOUT*/ + fatta(2); + fattb; + fattc(2); + fattd; + fatte(2); + fattf; + @loop; + + climb: /*MNST_CLIMB*/ + fatta(2); + fattb; + fattc(2); + fattd; + fatte(2); + fattf; + @loop; + + attack: /*MNST_ATTACK*/ + fattg @sound("manatk"); + fattg(3); + @loop; + + pain: /*MNST_PAIN*/ + fattj @sound("mnpain"); + @loop; + + wait: /*MNST_WAIT*/ + fatti; + @loop; + + die: /*MNST_DIE*/ + fattk @sound("mandth"); + fattk(2); + fattl(2); + fattm(2); + fattn(2); + fatto(2); + fattp(2); + fattr(2); + fatts(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + fattt; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Revenant { + radius = 17; + height = 36; + hitpoints = 200; + painin = 40; + xvel = 6; + yvel = 11; + slophit = 0; + painout = 20; + base = "sprites/monsters/revenant"; + + states { + sleep: /*MNST_SLEEP*/ + skela(3); + skelb; + @loop; + + sighted: /*MNST_RUN*/ + skela @sound("skesit"); + skela; + skelb(2); + skelc; + skeld(2); + skele; + skelf(2); + @loop; + + walk: /*MNST_GO*/ + skela @sound("skeact"); + skela; + skelb(2); + skelc; + skeld(2); + skele; + skelf(2); + @loop; + + runout: /*MNST_RUNOUT*/ + skela(2); + skelb; + skelc(2); + skeld; + skele(2); + skelf; + @loop; + + climb: /*MNST_CLIMB*/ + skela(2); + skelb; + skelc(2); + skeld; + skele(2); + skelf; + @loop; + + attack: /*MNST_ATTACK*/ + skelg @sound("skeatk"); + skelg; + skelh(2); + skeli; + @loop; + + pain: /*MNST_PAIN*/ + skell @sound("popain"); + @loop; + + wait: /*MNST_WAIT*/ + skelk; + @loop; + + die: /*MNST_DIE*/ + skelm @sound("skedth"); + skelm(2); + skeln(2); + skelo(2); + skelp(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + skelq; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Archvile { + radius = 17; + height = 36; + hitpoints = 150; + painin = 30; + xvel = 7; + yvel = 12; + slophit = 0; + painout = 10; + base = "sprites/monsters/archvile"; + + states { + sleep: /*MNST_SLEEP*/ + vilea(3); + vileb; + @loop; + + sighted: /*MNST_RUN*/ + vilea @sound("vilsit"); + vilea; + vileb(2); + vilec; + viled(2); + vilee; + vilef(2); + @loop; + + walk: /*MNST_GO*/ + vilea @sound("vilact"); + vilea; + vileb(2); + vilec; + viled(2); + vilee; + vilef(2); + @loop; + + runout: /*MNST_RUNOUT*/ + vilea(2); + vileb; + vilec(2); + viled; + vilee(2); + vilef; + @loop; + + climb: /*MNST_CLIMB*/ + vilea(2); + vileb; + vilec(2); + viled; + vilee(2); + vilef; + @loop; + + attack: /*MNST_ATTACK*/ + vileq @sound("vilatk"); + vileq; + vileg(3); + vileh; + vilei(2); + vilej; + vilek(2); + vilel; + vilem(2); + vilen; + vileo(2); + vilep; + @loop; + + pain: /*MNST_PAIN*/ + vileq @sound("vipain"); + @loop; + + wait: /*MNST_WAIT*/ + vilea; + @loop; + + die: /*MNST_DIE*/ + viler @sound("vildth"); + viler(2); + viles(2); + vilet(2); + vileu(2); + vilev(2); + vilew(2); + vilex(2); + viley(2); + @setstate dead; + + dead: /*MNST_DEAD*/ + vilez; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Fish { + radius = 5; + height = 5; + hitpoints = 35; + painin = 20; + xvel = 14; + yvel = 6; + slophit = 0; + painout = 10; + base = "sprites/monsters/fish"; + + states { + sleep: /*MNST_SLEEP*/ + fisha(3); + fishb; + @loop; + + sighted: /*MNST_RUN*/ + fisha(2); + fishb; + @loop; + + walk: /*MNST_GO*/ + fisha(2); + fishb; + @loop; + + runout: /*MNST_RUNOUT*/ + fisha(2); + fishb; + @loop; + + climb: /*MNST_CLIMB*/ + fisha(2); + fishb; + @loop; + + attack: /*MNST_ATTACK*/ + fishb @sound("bite1"); + fishb; + fishf(2); + fisha; + @loop; + + pain: /*MNST_PAIN*/ + fishe(2); + fishc; + fishd(2); + fishc; + @loop; + + wait: /*MNST_WAIT*/ + fisha; + @loop; + + die: /*MNST_DIE*/ + fishd(4); + @setstate dead; + + dead: /*MNST_DEAD*/ + fishc; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Barrel { + radius = 5; + height = 17; + hitpoints = 20; + painin = 0; + xvel = 7; + yvel = 6; + slophit = 0; + painout = 0; + base = "sprites/monsters/barrel"; + + states { + sleep: /*MNST_SLEEP*/ + bar1a; + @loop; + + sighted: /*MNST_RUN*/ + bar1a; + @loop; + + walk: /*MNST_GO*/ + bar1a; + @loop; + + runout: /*MNST_RUNOUT*/ + bar1a; + @loop; + + climb: /*MNST_CLIMB*/ + bar1a; + @loop; + + attack: /*MNST_ATTACK*/ + bar1a; + @loop; + + pain: /*MNST_PAIN*/ + bar1a; + @loop; + + wait: /*MNST_WAIT*/ + bar1a; + @loop; + + die: /*MNST_DIE*/ + bar1c @sound("barexp"); + bar1c(2); + bar1d(2); + bar1e(2); + bar1f(2); + bar1g(2); + @setstate dead; + dead: + @remove; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Robot { + radius = 17; + height = 38; + hitpoints = 20; + painin = 40; + xvel = 3; + yvel = 6; + slophit = 0; + painout = 20; + base = "sprites/monsters/robot"; + + states { + sleep: /*MNST_SLEEP*/ + roboa; + @loop; + + sighted: /*MNST_RUN*/ + robod @sound("bspsit"); + robod; + roboe(2); + robof; + robog(2); + roboh; + roboi(2); + roboj; + robok(2); + robol; + roboa(2); + robob; + roboc(2); + @loop; + + walk: /*MNST_GO*/ + robod @sound("bspact"); + robod; + roboe(2); + robof; + robog(2); + roboh; + roboi(2); + roboj; + robok(2); + robol; + roboa(2); + robob; + roboc(2); + @loop; + + runout: /*MNST_RUNOUT*/ + robod(2); + roboe; + robof(2); + robog; + roboh(2); + roboi; + roboj(2); + robok; + robol(2); + roboa; + robob(2); + roboc; + @loop; + + climb: /*MNST_CLIMB*/ + robod(2); + roboe; + robof(2); + robog; + roboh(2); + roboi; + roboj(2); + robok; + robol(2); + roboa; + robob(2); + roboc; + @loop; + + attack: /*MNST_ATTACK*/ + roboo @sound("bspwlk"); + roboo; + robop(2); + roboq; + @loop; + + pain: /*MNST_PAIN*/ + robod; + @loop; + + wait: /*MNST_WAIT*/ + robod; + @loop; + + die: /*MNST_DIE*/ + robod @sound("bspdth"); + @setstate dead; + + dead: /*MNST_DEAD*/ + robod; + @loop; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +Actor Man { + radius = 8; + height = 26; + hitpoints = 400; + painin = 70; + xvel = 8; + yvel = 10; + slophit = 30; + painout = 50; + base = "sprites/monsters/player"; + + states { + sleep: /*MNST_SLEEP*/ + playa(3); + playb; + @loop; + + sighted: /*MNST_RUN*/ + playa @sound("stop1"); + playc; + playd; + playa; + playb; + playd; + @loop; + + walk: /*MNST_GO*/ + playa @sound("haha1"); + playc; + playd; + playa; + playb; + playd; + @loop; + + runout: /*MNST_RUNOUT*/ + playa; + playc; + playd; + playa; + playb; + playd; + @loop; + + climb: /*MNST_CLIMB*/ + playa; + playc; + playd; + playa; + playb; + playd; + @loop; + + attack: /*MNST_ATTACK*/ + playe(4); + @loop; + + pain: /*MNST_PAIN*/ + playg @sound("plpain"); + @loop; + + wait: /*MNST_WAIT*/ + playe; + @loop; + + die: /*MNST_DIE*/ + playh @sound("pdiehi"); + playh(3); + playi(2); + playj(3); + playk(2); + playl(3); + playm(2); + @setstate dead; + + slop: /*MNST_DIE*/ + playo(2); + playp; + playq(2); + playr; + plays(2); + playt; + playu(2); + playv; + @loop; + + mess: /*MNST_DIE*/ + playw; + @loop; + + dead: /*MNST_DEAD*/ + playn; + @loop; + } +} + + diff --git a/tparser.d b/tparser.d index 96fafe0..d00b83c 100644 --- a/tparser.d +++ b/tparser.d @@ -220,45 +220,3 @@ private: putChar(ch); } } -/+ - -enum stt = q{ -Actor Demon { - radius = 15; - height = 28; - hitpoints = 60; - painin = 20; - xvel = 7; - yvel = 10; - slophit = 0; - painout = 10; - base = "sprites/monsters/demon"; - - states { - sleep: /*MNST_SLEEP*/ - sarga(3); - sargb; - @loop; - - sighted: /*MNST_RUN*/ - sarga @sound("sgtsit"); - sarga; - sargb(2); - sargc; - sargd(2); - @loop; - } -} -}; - - -void main () { - import std.utf : byChar; - auto parser = TextParser(stt.byChar); - while (!parser.empty) { - import std.conv : to; - writeln("(", parser.tline, ",", parser.tcol, "): ", to!string(parser.tk), " : <", parser.tstr, "> : ", parser.tchar, " : ", parser.tnum, " : ", parser.tquoted, " : ", parser.isLabel, " : ", parser.isCommand); - parser.popFront(); - } -} -+/ diff --git a/wadarc.d b/wadarc.d index 3942d0b..3aaeac4 100644 --- a/wadarc.d +++ b/wadarc.d @@ -4,6 +4,8 @@ private: static import core.sync.mutex; import std.stdio : File; +import console; + // ////////////////////////////////////////////////////////////////////////// // public __gshared WadArchive[] wadList; @@ -26,7 +28,7 @@ public void setDataPath (const(char)[] path) { public void addWad (string fname) { if (glock !is null) glock.lock(); scope(exit) if (glock !is null) glock.unlock(); - { import std.stdio; writeln("adding '", fname, "'..."); } + conwriteln("adding '", fname, "'..."); wadList ~= new WadArchive(fname); } @@ -152,7 +154,7 @@ public: if (pos) { de.path = cast(string)fname[0..pos]; // it's safe here de.name = cast(string)fname[pos..$]; // it's safe here - //{ import std.stdio; writeln("[", de.path, "] [", de.name, "]"); } + //conwriteln("[", de.path, "] [", de.name, "]"); } else { de.name = cast(string)fname; // it's safe here } @@ -262,7 +264,6 @@ private: } import core.stdc.stdio : SEEK_CUR, SEEK_END; - debug import std.stdio : writeln, writefln; scope(failure) cleanup(); uint readU32 () { @@ -313,9 +314,9 @@ private: dir[fidx].size = lmpsize; dir[fidx].name = fixName(nm); dir[fidx].path = fixPath(nm); - //debug writeln(dir[fidx].path, " : ", dir[fidx].name); + //debug conwriteln(dir[fidx].path, " : ", dir[fidx].name); } - debug writeln(dir.length, " files found"); + debug conwriteln(dir.length, " files found"); } @@ -475,7 +476,7 @@ static: import core.sys.posix.sys.types : ssize_t, off64_t = off_t; ssize_t fcdatpkRead (void* cookie, char* buf, size_t count) { - //{ import iv.writer; writeln("reading ", count, " bytes"); } + //conwriteln("reading ", count, " bytes"); import core.stdc.errno; auto fc = cast(InnerFileCookied*)cookie; auto res = fc.read(buf, count); @@ -484,14 +485,14 @@ static: } ssize_t fcdatpkWrite (void* cookie, const(char)* buf, size_t count) { - //{ import iv.writer; writeln("writing ", count, " bytes"); } + //conwriteln("writing ", count, " bytes"); import core.stdc.errno; errno = EIO; //FIXME: find better code return 0; // error; write should not return `-1` } int fcdatpkSeek (void* cookie, off64_t* offset, int whence) { - //{ import iv.writer; writeln("seeking ", *offset, " bytes, whence=", whence); } + //conwriteln("seeking ", *offset, " bytes, whence=", whence); import core.stdc.errno; auto fc = cast(InnerFileCookied*)cookie; auto res = fc.seek(*offset, whence); @@ -503,7 +504,7 @@ static: int fcdatpkClose (void* cookie) { import core.memory : GC; import core.stdc.stdlib : free; - //{ import iv.writer; writeln("closing"); } + //conwriteln("closing"); auto fc = cast(InnerFileCookied*)cookie; //fc.close(); GC.removeRange(cookie); @@ -512,7 +513,7 @@ static: //try { GC.runFinalizers(cookie[0..InnerFileCookied.sizeof]); } catch (Exception) {} //fc.xfl.__dtor(); free(cookie); - //{ import iv.writer; writeln("closed"); } + //conwriteln("closed"); return 0; } } diff --git a/xmain_d2d.d b/xmain_d2d.d index 8fac1d5..950c698 100644 --- a/xmain_d2d.d +++ b/xmain_d2d.d @@ -7,11 +7,13 @@ import core.time; import glbinds; import glutils; +import console; import wadarc; import iv.stream; import d2dmap; +import d2dmon; // ////////////////////////////////////////////////////////////////////////// // @@ -418,17 +420,20 @@ void main () { //addWad("/home/ketmar/k8prj/doom2d-tl/data/zadoomka.wad"); } - setOpenGLContextVersion(3, 2); // up to GLSL 150 - //openGLContextCompatible = false; - setDP(); + loadTemplates(); loadPalette(); + setOpenGLContextVersion(3, 2); // up to GLSL 150 + //openGLContextCompatible = false; + map = new LevelMap("maps/map01.d2m"); mapOfsX = 8*56; mapOfsY = 8*56; scale = 2; + { import core.memory : GC; GC.collect(); } + sdwindow = new SimpleWindow(vlWidth, vlHeight, "D2D", OpenGlOptions.yes, Resizablity.fixedSize); sdwindow.visibleForTheFirstTime = delegate () { -- 2.11.4.GIT