cosmetix
[dd2d.git] / d2dadefs.d
blob1fa703e7a2d0ef8a6b169dbca0368001532f4026
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 glutils;
22 import console;
23 import dacs;
24 import d2dgfx;
27 // ////////////////////////////////////////////////////////////////////////// //
28 private enum BIT(ubyte n) = (1U<<n);
31 // ////////////////////////////////////////////////////////////////////////// //
32 // thing flags
33 public enum {
34 AF_NOCOLLISION = BIT!(0),
35 AF_NOGRAVITY = BIT!(1),
36 AF_NOTHINK = BIT!(2),
37 AF_NOONTOUCH = BIT!(3), // `onTouch` will never be called with `me` for this actor
40 // ////////////////////////////////////////////////////////////////////////// //
41 // known D2D actors (and pseudoactors)
42 struct ActorDefD2D {
43 string classtype;
44 string classname;
45 string fullname;
46 ushort mapid; // thing id in map
48 this (string ctype, string cname, ushort thid) { classtype = ctype; classname = cname; fullname = classtype~":"~classname; mapid = thid; }
50 string toString () const {
51 import std.string : format;
52 return "ActorDefD2D(%s, %s, %s)".format(classtype/*.quote*/, classname/*.quote*/, mapid);
56 immutable ActorDefD2D[$] d2dactordefs = [
57 ActorDefD2D("playerstart", "Player1", 1),
58 ActorDefD2D("playerstart", "Player2", 2),
59 ActorDefD2D("playerstart", "DMStart", 3),
60 ActorDefD2D("item", "Clip", 100),
61 ActorDefD2D("item", "Shell", 101),
62 ActorDefD2D("item", "Rocket", 102),
63 ActorDefD2D("item", "Cell", 103),
64 ActorDefD2D("item", "Ammo", 104),
65 ActorDefD2D("item", "ShellBox", 105),
66 ActorDefD2D("item", "RocketBox", 106),
67 ActorDefD2D("item", "CellPack", 107),
68 ActorDefD2D("item", "StimPack", 108),
69 ActorDefD2D("item", "MediKit", 109),
70 ActorDefD2D("item", "BackPack", 110),
71 ActorDefD2D("item", "Chainsaw", 111),
72 ActorDefD2D("item", "Shotgun", 112),
73 ActorDefD2D("item", "SuperShotgun", 113),
74 ActorDefD2D("item", "MachineGun", 114),
75 ActorDefD2D("item", "RocketLauncher", 115),
76 ActorDefD2D("item", "Plasmagun", 116),
77 ActorDefD2D("item", "BFG900", 117),
78 ActorDefD2D("item", "ArmorGreen", 118),
79 ActorDefD2D("item", "ArmorBlue", 119),
80 ActorDefD2D("item", "MegaSphere", 120),
81 ActorDefD2D("item", "Invulnerability", 121),
82 ActorDefD2D("item", "Aqualung", 122),
83 ActorDefD2D("item", "KeyRed", 123),
84 ActorDefD2D("item", "KeyGreen", 124),
85 ActorDefD2D("item", "KeyBlue", 125),
86 ActorDefD2D("item", "ProtectionSuit", 126),
87 ActorDefD2D("item", "Super", 127),
88 ActorDefD2D("item", "TorchRed", 128),
89 ActorDefD2D("item", "TorchGreen", 129),
90 ActorDefD2D("item", "TorchBlue", 130),
91 ActorDefD2D("item", "Gor1", 131),
92 ActorDefD2D("item", "FCan", 132),
93 ActorDefD2D("item", "Gun2", 133),
94 ActorDefD2D("monster", "Demon", 200),
95 ActorDefD2D("monster", "Imp", 201),
96 ActorDefD2D("monster", "Zombie", 202),
97 ActorDefD2D("monster", "Sergeant", 203),
98 ActorDefD2D("monster", "Cyberdemon", 204),
99 ActorDefD2D("monster", "Chaingunner", 205),
100 ActorDefD2D("monster", "BaronOfHell", 206),
101 ActorDefD2D("monster", "HellKnight", 207),
102 ActorDefD2D("monster", "Cacodemon", 208),
103 ActorDefD2D("monster", "LostSoul", 209),
104 ActorDefD2D("monster", "PainElemental", 210),
105 ActorDefD2D("monster", "SpiderMastermind", 211),
106 ActorDefD2D("monster", "Arachnotron", 212),
107 ActorDefD2D("monster", "Mancubus", 213),
108 ActorDefD2D("monster", "Revenant", 214),
109 ActorDefD2D("monster", "Archvile", 215),
110 ActorDefD2D("monster", "Fish", 216),
111 ActorDefD2D("monster", "Barrel", 217),
112 ActorDefD2D("monster", "Robot", 218),
113 ActorDefD2D("monster", "Man", 219),
117 public immutable ActorDefD2D[ushort] d2dactordefsById;
118 //immutable ActorDefD2D[string] d2dactordefsByTN; // by "type:name"
120 shared static this () {
121 foreach (const ref ActorDefD2D d2da; d2dactordefs) {
122 d2dactordefsById[d2da.mapid] = d2da;
123 //d2dactordefsByTN[d2da.fullname] = d2da;
128 // ////////////////////////////////////////////////////////////////////////// //
129 public struct ImgSprite {
130 D2DImage vga;
131 Texture tex;
132 bool mirrored;
134 @disable this (this);
138 public final class ActorDef {
139 string classtype;
140 string classname;
141 string fullname;
142 uint id; // actor's unique id
144 // animation sequences for stated; keyed by state strid
145 StrId[][][uint] anims; // [statestrid][dir][pos]
147 FuncPool.FuncInfo[] fiAnimInit;
148 FuncPool.FuncInfo fiInit;
149 FuncPool.FuncInfo fiThink;
151 __gshared ImgSprite[uint] allSprites; // to avoid loading sprites twice they are keyed by namestrid
152 ImgSprite*[][][uint] animSprites;
153 //__gshared ImgSprite*[][] animCur;
155 // load actor graphics
156 void loadGraphics () {
157 //conwriteln("loading graphics for '", fullname, "'; anims.length=", anims.length, "; allSprites.length=", allSprites.length);
158 if (anims.length == 0) return; // no graphics here
159 //if (allSprites.length > 0) return;
160 // load sprites
161 foreach (auto anma2; anims.byValue) {
162 foreach (auto anma; anma2) {
163 foreach (StrId ssid; anma) {
164 //conwriteln(fullname, ": ssid=", ssid.id, "; is ", ssid.get);
165 ImgSprite* spi = null;
166 if (ssid.id != 0) {
167 spi = ssid.id in allSprites;
168 if (spi is null) {
169 //conwriteln("loading sprite '", ssid.get, "'");
170 D2DImage vga = new D2DImage(ssid.get);
171 allSprites[ssid.id] = ImgSprite();
172 spi = ssid.id in allSprites;
173 assert(spi !is null);
174 spi.vga = vga;
175 spi.tex = new Texture(spi.vga.asTCImage, Texture.Option.Nearest);
176 } else {
177 //conwriteln("cached sprite '", ssid.get, "'");
183 // now fill animSprites
184 foreach (auto anma2; anims.byKeyValue) {
185 if (anma2.key !in animSprites) animSprites[anma2.key] = new ImgSprite*[][](2); // 2 dirs
186 auto aspx = animSprites[anma2.key];
187 foreach (immutable dir, auto anma; anma2.value) {
188 foreach (StrId ssid; anma) {
189 ImgSprite* spi = null;
190 if (ssid.id != 0) spi = ssid.id in allSprites;
191 aspx[dir] ~= spi;
197 // unload actor graphics
198 void releaseGraphics () {
199 animSprites = null;
200 //allSprites.clear();
203 int nextAnimIdx (StrId state, uint dir, int curidx) {
204 if (dir != 0) dir = 1;
205 if (++curidx <= 0) return 0;
206 if (auto spra = state.id in animSprites) {
207 if (curidx < (*spra).ptr[dir].length) return curidx;
208 return 0;
210 return 0;
213 ImgSprite* animSpr (StrId state, uint dir, int curidx) {
214 if (dir != 0) dir = 1;
215 if (curidx < 0) return null;
216 if (auto spra = state.id in animSprites) {
217 if (curidx >= (*spra).ptr[dir].length) return null;
218 return (*spra).ptr[dir].ptr[curidx];
220 return null;
223 private __gshared uint nextId = 1;
225 this (string ctype, string cname) {
226 classtype = ctype;
227 classname = cname;
228 fullname = classtype~":"~classname;
229 id = nextId++;
232 void clearAllFrames (StrId state) {
233 anims.clear();
236 void clearFrames (StrId state) {
237 anims.remove(state.id);
240 void addFrame (StrId state, uint dir, StrId sprname) {
241 //conwriteln("new frame for '", fullname, "'; state=", state.get, "; sprname=", sprname.get, "; dir=", dir);
242 if (dir > 1) throw new Exception("addFrame: invalid dir");
243 if (state.id !in anims) anims[state.id] = new StrId[][](2);
244 auto aa = anims[state.id];
245 aa[dir] ~= sprname;
248 void setAnimInitFunc (FuncPool.FuncInfo fi) {
249 if (fi is null) return;
250 if (fi.mgtype != ":void") throw new Exception("invalid actor animation init function");
251 fiAnimInit ~= fi;
254 void setInitFunc (FuncPool.FuncInfo fi) {
255 if (fi is null) return;
256 if (fi.mgtype != ":void:Actor") throw new Exception("invalid actor init function");
257 fiInit = fi;
260 void setThinkFunc (FuncPool.FuncInfo fi) {
261 if (fi is null) return;
262 if (fi.mgtype != ":void:Actor") throw new Exception("invalid actor think function");
263 fiThink = fi;
266 void callAnimInit () {
267 foreach (auto fi; fiAnimInit) if (fi !is null) fi();
270 void callInit (ActorId aid) {
271 if (fiInit is null || !aid.valid) return;
272 fiInit(aid);
275 void callThink (ActorId aid) {
276 if (fiThink is null || !aid.valid) return;
277 fiThink(aid);
282 // ////////////////////////////////////////////////////////////////////////// //
283 public __gshared ActorDef[string] actordefs; // by fullname
286 public ActorDef findD2DActorDef (ushort mapid) {
287 if (mapid == 0) assert(0);
288 if (mapid == 1 || mapid == 2) return findActorDefByFullName("monster:Player");
289 if (auto dad = mapid in d2dactordefsById) {
290 auto adef = findActorDefByFullName(dad.fullname);
291 if (adef is null) throw new Exception("can't find DACS actor definition for D2D actor '"~dad.fullname~"'");
292 return adef;
294 import std.conv : to;
295 throw new Exception("can't find D2D ActorDef for mapid "~to!string(mapid));
299 import dacs.actor;
301 //FIXME
302 __gshared uint fcltypeofs = uint.max;
303 __gshared uint fclnameofs = uint.max;
306 void initFieldOffsets () {
307 pragma(inline, true);
308 if (fcltypeofs == uint.max) {
309 fcltypeofs = Actor.fields["classtype"].ofs;
310 fclnameofs = Actor.fields["classname"].ofs;
315 public ActorDef findActorDef (ActorId aid) {
316 if (!aid.valid) return null;
317 initFieldOffsets();
319 auto aptr = aid.data.ptr;
320 StrId act = StrId(*cast(uint*)(aptr+fcltypeofs));
321 StrId acn = StrId(*cast(uint*)(aptr+fclnameofs));
322 return findActorDef(act, acn);
326 public ActorDef findActorDefByFullName (const(char)[] fullname) {
327 if (auto fd = fullname in actordefs) return *fd;
328 return null;
332 public ActorDef findActorDef (const(char)[] ctype, const(char)[] cname) {
333 if (ctype.length+cname.length > 1024) assert(0);
334 char[1025] buf;
335 buf[0..ctype.length] = ctype[];
336 buf[ctype.length] = ':';
337 buf[ctype.length+1..ctype.length+1+cname.length] = cname[];
338 if (auto fd = buf[0..ctype.length+1+cname.length] in actordefs) return *fd;
339 return null;
343 public ActorDef findActorDef (StrId ctype, StrId cname) { return findActorDef(ctype.get, cname.get); }
346 public ActorDef registerActorDef (string classtype, string classname) {
347 string fullname = classtype~":"~classname;
348 if (fullname !in actordefs) actordefs[fullname] = new ActorDef(classtype, classname);
349 if (auto fd = fullname in actordefs) return *fd;
350 assert(0);