hud: keys are on top now
[dd2d.git] / d2dadefs.d
blob160a55729a77c39caf6d5806e9bb727c59fc6cb7
1 /* DooM2D: Midnight on the Firing Line
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module d2dadefs is aliced;
20 private:
21 import iv.glbinds;
22 import glutils;
23 import console;
24 import dacs;
25 import d2dgfx;
26 import d2dsprite;
29 // ////////////////////////////////////////////////////////////////////////// //
30 private enum BIT(ubyte n) = (1U<<n);
33 // ////////////////////////////////////////////////////////////////////////// //
34 // thing flags
35 public enum {
36 AF_NOCOLLISION = BIT!(0),
37 AF_NOGRAVITY = BIT!(1),
38 AF_NOTHINK = BIT!(2),
39 AF_NOONTOUCH = BIT!(3), // `onTouch` will never be called with `me` for this actor
40 AF_NODRAW = BIT!(4), // don't draw sprite
41 AF_NOLIGHT = BIT!(5), // no attached light
42 AF_NOANIMATE = BIT!(6), // don't do animation
43 AF_PIXEL = BIT!(7), // draw pixel, color is `s`
47 // ////////////////////////////////////////////////////////////////////////// //
48 // known D2D actors (and pseudoactors)
49 struct ActorDefD2D {
50 StrId classtype;
51 StrId classname;
52 ushort mapid; // thing id in map
54 this (string ctype, string cname, ushort thid=0) {
55 classtype = StrPool.intern(ctype);
56 classname = StrPool.intern(cname);
57 mapid = thid;
60 string toString () const {
61 import std.string : format;
62 return "ActorDefD2D(%s, %s, %s)".format(classtype.get, classname.get, mapid);
66 immutable ActorDefD2D[] d2dactordefs;
67 public immutable ActorDefD2D[ushort] d2dactordefsById; // by mapid
69 shared static this () {
70 d2dactordefs = [
71 ActorDefD2D("playerstart", "Player1", 1),
72 ActorDefD2D("playerstart", "Player2", 2),
73 ActorDefD2D("playerstart", "DMStart", 3),
74 ActorDefD2D("item", "Clip", 100),
75 ActorDefD2D("item", "Shell", 101),
76 ActorDefD2D("item", "Rocket", 102),
77 ActorDefD2D("item", "Cell", 103),
78 ActorDefD2D("item", "Ammo", 104),
79 ActorDefD2D("item", "ShellBox", 105),
80 ActorDefD2D("item", "RocketBox", 106),
81 ActorDefD2D("item", "CellPack", 107),
82 ActorDefD2D("item", "StimPack", 108),
83 ActorDefD2D("item", "MediKit", 109),
84 ActorDefD2D("item", "BackPack", 110),
85 ActorDefD2D("item", "Chainsaw", 111),
86 ActorDefD2D("item", "Shotgun", 112),
87 ActorDefD2D("item", "SuperShotgun", 113),
88 ActorDefD2D("item", "MachineGun", 114),
89 ActorDefD2D("item", "RocketLauncher", 115),
90 ActorDefD2D("item", "Plasmagun", 116),
91 ActorDefD2D("item", "BFG9000", 117),
92 ActorDefD2D("item", "ArmorGreen", 118),
93 ActorDefD2D("item", "ArmorBlue", 119),
94 ActorDefD2D("item", "MegaSphere", 120),
95 ActorDefD2D("item", "Invulnerability", 121),
96 ActorDefD2D("item", "Aqualung", 122),
97 ActorDefD2D("item", "KeyRed", 123),
98 ActorDefD2D("item", "KeyGreen", 124),
99 ActorDefD2D("item", "KeyBlue", 125),
100 ActorDefD2D("item", "ProtectionSuit", 126),
101 ActorDefD2D("item", "Super", 127),
102 ActorDefD2D("item", "TorchRed", 128),
103 ActorDefD2D("item", "TorchGreen", 129),
104 ActorDefD2D("item", "TorchBlue", 130),
105 ActorDefD2D("item", "Gor1", 131),
106 ActorDefD2D("item", "FCan", 132),
107 ActorDefD2D("item", "Gun2", 133),
108 ActorDefD2D("monster", "Demon", 200),
109 ActorDefD2D("monster", "Imp", 201),
110 ActorDefD2D("monster", "Zombie", 202),
111 ActorDefD2D("monster", "Sergeant", 203),
112 ActorDefD2D("monster", "Cyberdemon", 204),
113 ActorDefD2D("monster", "Chaingunner", 205),
114 ActorDefD2D("monster", "BaronOfHell", 206),
115 ActorDefD2D("monster", "HellKnight", 207),
116 ActorDefD2D("monster", "Cacodemon", 208),
117 ActorDefD2D("monster", "LostSoul", 209),
118 ActorDefD2D("monster", "PainElemental", 210),
119 ActorDefD2D("monster", "SpiderMastermind", 211),
120 ActorDefD2D("monster", "Arachnotron", 212),
121 ActorDefD2D("monster", "Mancubus", 213),
122 ActorDefD2D("monster", "Revenant", 214),
123 ActorDefD2D("monster", "Archvile", 215),
124 ActorDefD2D("monster", "Fish", 216),
125 ActorDefD2D("monster", "Barrel", 217),
126 ActorDefD2D("monster", "Robot", 218),
127 ActorDefD2D("monster", "Man", 219),
129 foreach (const ref ActorDefD2D d2da; d2dactordefs) {
130 if (d2da.mapid) d2dactordefsById[d2da.mapid] = d2da;
135 // ////////////////////////////////////////////////////////////////////////// //
136 public string getD2DSwitchClassName (uint swtype) {
137 switch (swtype) {
138 case 1: return "Exit"; // SW_EXIT
139 case 2: return "ExitSecret"; // SW_EXITS
140 case 3: return "DoorOpen"; // SW_OPENDOOR
141 case 4: return "DoorClose"; // SW_SHUTDOOR
142 case 5: return "TrapClose"; // SW_SHUTTRAP
143 case 6: return "Door"; // SW_DOOR
144 case 7: return "Door5"; // SW_DOOR5
145 case 8: return "Press"; // SW_PRESS
146 case 9: return "Teleport"; // SW_TELE
147 case 10: return "Secret"; // SW_SECRET
148 case 11: return "LiftUp"; // SW_LIFTUP
149 case 12: return "LiftDown"; // SW_LIFTDOWN
150 case 13: return "Trap"; // SW_TRAP
151 case 14: return "Lift"; // SW_LIFT
152 case 64: return "WinGame"; // SW_WINGAME
153 default:
155 return null;
159 // ////////////////////////////////////////////////////////////////////////// //
160 public bool processCL (ref string[] args) {
161 static string h() (const(void)[] src) {
162 static immutable uint[5] g = [0x31c84b1, 0x95eed, 0x1c39, 0x55, 0x1];
163 uint a = 0; int c = 0; auto d = cast(const(ubyte)[])src; string e; ubyte f = 0x5a;
164 foreach (immutable b; d) { a += (b-0x21)*g[c++]; if (c == 5) { foreach (immutable _; 0..4) { e ~= ((a>>24)^(f^=0xff))&0xff; a <<= 8; } a = 0; c = 0; } }
165 if (c > 1) { a += g[--c]; foreach (immutable _; 0..c) { e ~= ((a>>24)^(f^=0xff))&0xff; a <<= 8; } }
166 return e;
169 for (usize idx = 1; idx < args.length; ++idx) {
170 string s = null;
171 if (args[idx] == h("Lj-`b^coRZ")) {
172 s = h("l86;\"KeCe2M0e21^coRZJglC6au@O$_Ks*Wf6Z40cqs6ff0@&oKfmL2f62ib^b4#!f6YOr`\\"~
173 "E/latM@m_)9@`Y8kb;^ikD\\bT_mi_C3>^KfauKf.Y-\"__^+jY6huq^bgmo^b`h_d<:3aau%:'K"~
174 "dkD2gj7<sKf6k%^iZaobV[+YKeC.tM0eJPdm)H1ei(<.eU#.s`&#SYMfc-");
175 } else if (args[idx] == h("Lj.0,a#Lj_dP]$!g]")) {
176 s = h("`=C<Xep>@bbVmR!_KLVpb<CV4bs-n2aYV=\"gj7@*dm)D[KmM]6_0WsCf0=sNb<CVCbW!R#^j="~
177 "3]KeCV7Ke:5&^gO>baYni3bW\")tKe:(g^j=B`^j=$Yf/:E&dm)E,YBkmAb<CV4bs-n@au@+^f/"~
178 "qA8ep>Ild66)Ca$5JYY>Buk^b*JQ^j=B`^j>H2a#Lj_dP]$!M0d5fKdk/$KM[AKnM7n+cTBQ(Ke"~
179 "CV3d<`hhd6EJ6d5&L``\\taeep>_!`%Ha(`%K%bKM^hrdQ?&FKeCV7Kb2TjcS*=ba\"u=2M0d)s_"~
180 "0XZfcnqqPKau?lKfms?a>:slep?L@b<E]iehk;t`\\N3lY>FUNKeCM*c?d_kep>e&f.+]sKdkG-f"~
181 "04mEbBhDpb<DOpKmMu@b<:P3bW!=`d5&L`a?.Qhau@+^__o5Ubs-n2atLUed<^UmY6i?tf0@h=^cmH"~
182 "-^j=$GKeCV7KauHgd4`Red3udpM,8nPj>=]!eh5*&_0X$ObqmI+Kepnud5&it_D9M\\Y>F::_01Mo"~
183 "ep>OsKeL>+bULe_d5&it_D9Mbbs-n2d5B'1M,8nPnM7n+mlSQL^aRVg`\\E<rdPK9+Kg4?Wep>J$Kf"~
184 "mI=a?PMXju^XKKe:P*_`Z$sb<:P3bp^^f_D6ftbs-n7co/a*gj7C+b!(YYKmMf:_0X-Tf/Ul:_0X$KK"~
185 "eq,&`]M7+KM\\ieb<Li0d4NLfKb_cqM0dQ$b'Sg]b<CV4bp^^f_D6g,b<CV4bp^^f_D8<@Kau?lKe1@"~
186 "peN:m!a#:k\"^j=Enb:\\Jtb;7-m^aP!fb<*]uKM_&#Kf6_/d<a\"hKg*:6_01Mob<CV3bV%.dbV%Im"~
187 "bs0-1YBkm8^j=Enb:\\K3`&>t$eM>?*_Ks6a`\\EBJYB]+b_01Mf`$pBmbr*joei(H&bBhPk^j>H2a"~
188 "#Lj_dP]$!RS\\]aju(4EKeCMoa<QC#f/M9(Kf@e5a$7L$bULe_a#2Y!Y8)aRf/q#,atM=l_)pG!Kc."~
189 "feaYh3rKR2cBaYq'^KRL%MKbD1I`\\P[bd5Jd(KepnubqmpscSaL\"Y>DD`nL_[.KfI[?aYq@+M0d)s_"~
190 "0XKa^j=QibV%-bKeCM!^aZI5Kc\\H%Kg\"3>^j<pU_0WsSa>h:+Kepnud5&L`dQ>K6Sl\"K+aa2#aa=5n"~
191 "jdQc>JKeCV7KfI4'b!!lu^aY+:KmMf:_0XKa^j='Za?PA,`%K:`Kf.40_C3>^^iZa");
192 } else if (args[idx] == h("Lj.<*f.+]s") || args[idx] == h("Lj.<*f.+]seh,#m_#") || args[idx] == h("Lj.<*f.+]sa#:k\"^]")) {
193 s = h("r&)iI_)9Dad<a&!dm&Nrbs-mjasbe%aa3,.`'1tYY5");
194 } else if (args[idx] == h("Lj.E7dm)\"")) {
195 s = h("p-7\"jbBh)T^j=B`^a\"\\^ej%VJbBh)T^j=B`^a\"M/lnjDKbs-nBbra**^c$m(_g9]c^j<g]^"
196 "ab$e^b!8XKfdmNKeCV7gj?4<bBhPk^j=To_)'\"d`]o/7_g9Ql`%8\\\\Kdjeg^bga,f0=sAbs1!1Y7o**d5&"~
197 "L``\\PIhb<O*paukA1bs-nG^d$@qbVY#8Kdt#!`&YVZ_C32OKeCV7gj7<sMbrV!aZkJ3bs1!0`$iEIb;I[jKfm"~
198 ".0`&>DWd5&K^KfdmNKf$q)MbrasKeCV7Kf@4>eh2Y6_g9]c^j<g]^ab%\"f0=sAbs0E#Kdt\"nbpeQInh\\0JK"~
199 "eCV7gj74,dm&OCatANsehtWsd5&K^KegRt^j=0]d<)Q,f06tuKfdIAKe^e._)/qVep>Uuat8<\"bs1!0b;I[hY"~
200 "6rlCgcsD:`&,;Veh>Q'aYUpud5/p%KegG*f6Yh\"^a\"OiatATKnM7n+`]MX6f//1;bBhPk^j='Zcns-3bVY#+"~
201 "bs1!0^bjG'f6\"2,b:^q`m6AO8`$iEId5&K^Kege\"d5/m/Mbrq!^j=B`f/:`9LcE13f0@k9Kf-bod5&L`_DT."~
202 "YKfdmNKeCV7giT_@bULpmf/Uu2_KsTb^j=*YaWlKqbBhPk^j=Bcf-nEkd4'c2f0=sAbs1!0ej%Q(Y8G29^c]t%"~
203 "KfdmNKeCV7gieB2`&>Cnco-S>f0=sAbs1!*Y6huq^bga,f0=sAbs1!,Kdjeg^bga,f0=sAbs1!,Kdjeg^bg`td"~
204 "PJm-Kfd.5bVY#8f0=sAbs1!*Y8>,%KeCV7KdkP.f/(f'Kf-bobs0,t^bg`n^c0%fa$81!Kf?ppKeCV7KdkP.f/"~
205 "(f'Kf-bo^cU.#c$Iu+a?Ra*^aP+;");
206 } else if (args[idx] == h("Lj-lsf0'")) {
207 s = h("niqgif0=sAbs-n!asb,KKbhf_^aOm]atM@mehYH6aZe:%`&,;Veh>W'^biklf6Z40cmXSsbqmm!Mbrt/"~
208 "Ke:M,aa1lh_0XlocmXT-bVdL\"_DB1naa1l^_0XKn`\\P^paYgpk`]M@i_)'XpbV[<lbUgOd^a[i\\d5?V8cmXT*"~
209 "dPQkYr&)hLKfRL<d4a*9Ke:M,aa1lh`%'/\\d5?V,^aRYf`]o/1eo\\)$^a[JVd6#N3^j=3RKfm^7bVm7YY5");
210 } else if (args[idx] == h("Lj-]nauI0bec") || args[idx] == h("Lcrm<a$80)")) {
212 if (s.length) {
213 import core.stdc.stdio : printf;
214 printf("%.*s", cast(uint)s.length, s.ptr);
215 foreach (immutable c; idx+1..args.length) args[c-1] = args[c];
216 args.length = args.length-1;
217 --idx;
218 return true;
221 return false;
225 // ////////////////////////////////////////////////////////////////////////// //
226 public final class ActorDef {
227 StrId classtype;
228 StrId classname;
230 // animation sequences for stated; keyed by state strid
231 StrId[][][uint] anims; // [statestrid][dir][pos]
233 FuncPool.FuncInfo fiAnimInit;
234 FuncPool.FuncInfo fiInit;
235 FuncPool.FuncInfo fiThink;
237 ImgSprite[][][uint] animSprites;
239 // load actor graphics
240 void loadGraphics () {
241 //conwriteln("loading graphics for '", fullname, "'; anims.length=", anims.length");
242 if (anims.length == 0) return; // no graphics here
243 // load sprites
244 foreach (auto anma2; anims.byKeyValue) {
245 //if (anma2.key !in animSprites) animSprites[anma2.key] = new ImgSprite[][](2); // 2 dirs
246 //auto aspx = animSprites[anma2.key];
247 if (anma2.key in animSprites) continue;
248 ImgSprite[][] aspx;
249 foreach (immutable dir, auto anma; anma2.value) {
250 ImgSprite[] dsp;
251 foreach (StrId ssid; anma) {
252 //if (dir) { conwriteln("dir: ", dir, "; [", ssid.get, "]"); }
253 dsp ~= loadSprite(ssid.get);
255 aspx ~= dsp;
257 animSprites[anma2.key] = aspx;
261 // unload actor graphics
262 void releaseGraphics () {
263 animSprites = null;
266 int nextAnimIdx (StrId state, uint dir, int curidx) {
267 if (++curidx <= 0) return 0;
268 if (auto spra = state.id in animSprites) {
269 if (dir != 0) dir = 1;
270 return (curidx < (*spra).ptr[dir].length ? curidx : 0);
272 return 0;
275 ImgSprite animSpr (StrId state, uint dir, int curidx) {
276 if (curidx < 0) return null;
277 if (auto spra = state.id in animSprites) {
278 if (dir != 0) dir = 1;
279 auto px = (*spra).ptr[dir];
280 return (curidx < px.length ? px.ptr[curidx] : null);
282 return null;
285 this (string ctype, string cname) {
286 classtype = StrPool.intern(ctype);
287 classname = StrPool.intern(cname);
290 void clearAllFrames (StrId state) {
291 anims.clear();
294 void clearFrames (StrId state) {
295 anims.remove(state.id);
298 void addFrame (StrId state, uint dir, StrId sprname) {
299 //conwriteln("new frame for '", fullname, "'; state=", state.get, "; sprname=", sprname.get, "; dir=", dir);
300 if (dir > 1) throw new Exception("addFrame: invalid dir");
301 if (state.id !in anims) anims[state.id] = new StrId[][](2);
302 auto aa = anims[state.id];
303 aa[dir] ~= sprname;
306 void setAnimInitFunc (FuncPool.FuncInfo fi) {
307 if (fi is null) return;
308 if (fi.mgtype != ":void") throw new Exception("invalid actor animation init function");
309 fiAnimInit = fi;
312 void setInitFunc (FuncPool.FuncInfo fi) {
313 if (fi is null) return;
314 if (fi.mgtype != ":void:Actor") throw new Exception("invalid actor init function");
315 fiInit = fi;
318 void setThinkFunc (FuncPool.FuncInfo fi) {
319 if (fi is null) return;
320 if (fi.mgtype != ":void:Actor") throw new Exception("invalid actor think function");
321 fiThink = fi;
324 void callAnimInit () {
325 if (fiAnimInit !is null) fiAnimInit();
328 void callInit (ActorId aid) {
329 if (fiInit is null || !aid.valid) return;
330 fiInit(aid);
333 void callThink (ActorId aid) {
334 if (fiThink is null || !aid.valid) return;
335 fiThink(aid);
338 static:
339 // return `true` to stop
340 bool forEach (bool delegate (ActorDef d) dg) {
341 foreach (ActorDef adef; actordefs.byValue) if (dg(adef)) return true;
342 return false;
345 void forEach (void delegate (ActorDef d) dg) {
346 foreach (ActorDef adef; actordefs.byValue) dg(adef);
351 // ////////////////////////////////////////////////////////////////////////// //
352 public ActorDef findD2DActorDef (ushort mapid) {
353 if (mapid == 0) assert(0);
354 if (mapid == 1 || mapid == 2) return findActorDef("monster", "Player");
355 if (auto dad = mapid in d2dactordefsById) {
356 auto adef = findActorDef(dad.classtype, dad.classname);
357 if (adef is null) throw new Exception("can't find DACS actor definition for D2D actor '"~dad.classtype.get~":"~dad.classname.get~"'");
358 return adef;
360 import std.conv : to;
361 throw new Exception("can't find D2D ActorDef for mapid "~to!string(mapid));
365 // ////////////////////////////////////////////////////////////////////////// //
366 import dacs.actor;
368 __gshared ActorDef[ulong] actordefs; // by (name<<32)|type
370 mixin(Actor.FieldGetMixin!("classtype", StrId)); // fget_classtype
371 mixin(Actor.FieldGetMixin!("classname", StrId)); // fget_classname
374 ulong ctn2idx (uint ctid, uint cnid) { pragma(inline, true); return ((cast(ulong)cnid)<<32)|ctid; }
375 ulong ctn2idx (StrId ct, StrId cn) { pragma(inline, true); return ctn2idx(ct.id, cn.id); }
378 public ActorDef findActorDef (ActorId aid) {
379 pragma(inline, true);
380 if (!aid.valid) return null;
381 return findActorDef(aid.fget_classtype, aid.fget_classname);
385 public ActorDef findActorDef (StrId ctype, StrId cname) { /*pragma(inline, true);*/ return actordefs.get(ctn2idx(ctype.id, cname.id), null); }
388 public ActorDef findActorDef (const(char)[] ctype, const(char)[] cname) {
389 auto ctid = ctype in StrPool;
390 auto cnid = cname in StrPool;
391 if (!ctid || !cnid) return null;
392 return actordefs.get(ctn2idx(ctid, cnid), null);
396 public ActorDef registerActorDef (string classtype, string classname) {
397 auto ct = StrPool.intern(classtype);
398 auto cn = StrPool.intern(classname);
399 if (findActorDef(ct, cn) is null) actordefs[ctn2idx(ct, cn)] = new ActorDef(classtype, classname);
400 return actordefs[ctn2idx(ct, cn)];