level scrolling
[dd2d.git] / d2dadefs.d
blob445023b903b8b731b719d73fea84c7c9c3c6a5ae
1 module d2dadefs is aliced;
3 private:
4 import glutils;
5 import console;
6 import dacs;
7 import d2dgfx;
10 // ////////////////////////////////////////////////////////////////////////// //
11 // known D2D actors (and pseudoactors)
12 struct ActorDefD2D {
13 string classtype;
14 string classname;
15 string fullname;
16 ushort mapid; // thing id in map
18 this (string ctype, string cname, ushort thid) { classtype = ctype; classname = cname; fullname = classtype~":"~classname; mapid = thid; }
20 string toString () const {
21 import std.string : format;
22 return "ActorDefD2D(%s, %s, %s)".format(classtype/*.quote*/, classname/*.quote*/, mapid);
26 immutable ActorDefD2D[$] d2dactordefs = [
27 ActorDefD2D("playerstart", "Player1", 1),
28 ActorDefD2D("playerstart", "Player2", 2),
29 ActorDefD2D("playerstart", "DMStart", 3),
30 ActorDefD2D("item", "Clip", 100),
31 ActorDefD2D("item", "Shell", 101),
32 ActorDefD2D("item", "Rocket", 102),
33 ActorDefD2D("item", "Cell", 103),
34 ActorDefD2D("item", "Ammo", 104),
35 ActorDefD2D("item", "ShellBox", 105),
36 ActorDefD2D("item", "RocketBox", 106),
37 ActorDefD2D("item", "CellPack", 107),
38 ActorDefD2D("item", "StimPack", 108),
39 ActorDefD2D("item", "MediKit", 109),
40 ActorDefD2D("item", "BackPack", 110),
41 ActorDefD2D("item", "Chainsaw", 111),
42 ActorDefD2D("item", "Shotgun", 112),
43 ActorDefD2D("item", "SuperShotgun", 113),
44 ActorDefD2D("item", "MachineGun", 114),
45 ActorDefD2D("item", "RocketLauncher", 115),
46 ActorDefD2D("item", "Plasmagun", 116),
47 ActorDefD2D("item", "BFG900", 117),
48 ActorDefD2D("item", "ArmorGreen", 118),
49 ActorDefD2D("item", "ArmorBlue", 119),
50 ActorDefD2D("item", "MegaSphere", 120),
51 ActorDefD2D("item", "Invulnerability", 121),
52 ActorDefD2D("item", "Aqualung", 122),
53 ActorDefD2D("item", "KeyRed", 123),
54 ActorDefD2D("item", "KeyGreen", 124),
55 ActorDefD2D("item", "KeyBlue", 125),
56 ActorDefD2D("item", "ProtectionSuit", 126),
57 ActorDefD2D("item", "Super", 127),
58 ActorDefD2D("item", "TorchRed", 128),
59 ActorDefD2D("item", "TorchGreen", 129),
60 ActorDefD2D("item", "TorchBlue", 130),
61 ActorDefD2D("item", "Gor1", 131),
62 ActorDefD2D("item", "FCan", 132),
63 ActorDefD2D("item", "Gun2", 133),
64 ActorDefD2D("monster", "Demon", 200),
65 ActorDefD2D("monster", "Imp", 201),
66 ActorDefD2D("monster", "Zombie", 202),
67 ActorDefD2D("monster", "Sergeant", 203),
68 ActorDefD2D("monster", "Cyberdemon", 204),
69 ActorDefD2D("monster", "Chaingunner", 205),
70 ActorDefD2D("monster", "BaronOfHell", 206),
71 ActorDefD2D("monster", "HellKnight", 207),
72 ActorDefD2D("monster", "Cacodemon", 208),
73 ActorDefD2D("monster", "LostSoul", 209),
74 ActorDefD2D("monster", "PainElemental", 210),
75 ActorDefD2D("monster", "SpiderMastermind", 211),
76 ActorDefD2D("monster", "Arachnotron", 212),
77 ActorDefD2D("monster", "Mancubus", 213),
78 ActorDefD2D("monster", "Revenant", 214),
79 ActorDefD2D("monster", "Archvile", 215),
80 ActorDefD2D("monster", "Fish", 216),
81 ActorDefD2D("monster", "Barrel", 217),
82 ActorDefD2D("monster", "Robot", 218),
83 ActorDefD2D("monster", "Man", 219),
87 public immutable ActorDefD2D[ushort] d2dactordefsById;
88 //immutable ActorDefD2D[string] d2dactordefsByTN; // by "type:name"
90 shared static this () {
91 foreach (const ref ActorDefD2D d2da; d2dactordefs) {
92 d2dactordefsById[d2da.mapid] = d2da;
93 //d2dactordefsByTN[d2da.fullname] = d2da;
98 // ////////////////////////////////////////////////////////////////////////// //
99 public struct ImgSprite {
100 D2DImage vga;
101 Texture tex;
102 bool mirrored;
104 @disable this (this);
108 public final class ActorDef {
109 string classtype;
110 string classname;
111 string fullname;
112 uint id; // actor's unique id
114 // animation sequences for stated; keyed by state strid
115 StrId[][][uint] anims; // [statestrid][dir][pos]
117 FuncPool.FuncInfo[] fiAnimInit;
118 FuncPool.FuncInfo fiInit;
119 FuncPool.FuncInfo fiThink;
120 FuncPool.FuncInfo fiOnTouch;
122 __gshared ImgSprite[uint] allSprites; // to avoid loading sprites twice they are keyed by namestrid
123 ImgSprite*[][][uint] animSprites;
124 //__gshared ImgSprite*[][] animCur;
126 // load actor graphics
127 void loadGraphics () {
128 //conwriteln("loading graphics for '", fullname, "'; anims.length=", anims.length, "; allSprites.length=", allSprites.length);
129 if (anims.length == 0) return; // no graphics here
130 //if (allSprites.length > 0) return;
131 // load sprites
132 foreach (auto anma2; anims.byValue) {
133 foreach (auto anma; anma2) {
134 foreach (StrId ssid; anma) {
135 //conwriteln(fullname, ": ssid=", ssid.id, "; is ", ssid.get);
136 ImgSprite* spi = null;
137 if (ssid.id != 0) {
138 spi = ssid.id in allSprites;
139 if (spi is null) {
140 //conwriteln("loading sprite '", ssid.get, "'");
141 D2DImage vga = new D2DImage(ssid.get);
142 allSprites[ssid.id] = ImgSprite();
143 spi = ssid.id in allSprites;
144 assert(spi !is null);
145 spi.vga = vga;
146 spi.tex = new Texture(spi.vga.asTCImage, Texture.Option.Nearest);
147 } else {
148 //conwriteln("cached sprite '", ssid.get, "'");
154 // now fill animSprites
155 foreach (auto anma2; anims.byKeyValue) {
156 if (anma2.key !in animSprites) animSprites[anma2.key] = new ImgSprite*[][](2); // 2 dirs
157 auto aspx = animSprites[anma2.key];
158 foreach (immutable dir, auto anma; anma2.value) {
159 foreach (StrId ssid; anma) {
160 ImgSprite* spi = null;
161 if (ssid.id != 0) spi = ssid.id in allSprites;
162 aspx[dir] ~= spi;
168 // unload actor graphics
169 void releaseGraphics () {
170 animSprites = null;
171 //allSprites.clear();
174 int nextAnimIdx (StrId state, uint dir, int curidx) {
175 if (dir != 0) dir = 1;
176 if (++curidx <= 0) return 0;
177 if (auto spra = state.id in animSprites) {
178 if (curidx < (*spra).ptr[dir].length) return curidx;
179 return 0;
181 return 0;
184 ImgSprite* animSpr (StrId state, uint dir, int curidx) {
185 if (dir != 0) dir = 1;
186 if (curidx < 0) return null;
187 if (auto spra = state.id in animSprites) {
188 if (curidx >= (*spra).ptr[dir].length) return null;
189 return (*spra).ptr[dir].ptr[curidx];
191 return null;
194 private __gshared uint nextId = 1;
196 this (string ctype, string cname) {
197 classtype = ctype;
198 classname = cname;
199 fullname = classtype~":"~classname;
200 id = nextId++;
203 void clearAllFrames (StrId state) {
204 anims.clear();
207 void clearFrames (StrId state) {
208 anims.remove(state.id);
211 void addFrame (StrId state, uint dir, StrId sprname) {
212 //conwriteln("new frame for '", fullname, "'; state=", state.get, "; sprname=", sprname.get, "; dir=", dir);
213 if (dir > 1) throw new Exception("addFrame: invalid dir");
214 if (state.id !in anims) anims[state.id] = new StrId[][](2);
215 auto aa = anims[state.id];
216 aa[dir] ~= sprname;
219 void setAnimInitFunc (FuncPool.FuncInfo fi) {
220 if (fi is null) return;
221 if (fi.mgtype != ":void") throw new Exception("invalid actor animation init function");
222 fiAnimInit ~= fi;
225 void setInitFunc (FuncPool.FuncInfo fi) {
226 if (fi is null) return;
227 if (fi.mgtype != ":void:Actor") throw new Exception("invalid actor init function");
228 fiInit = fi;
231 void setThinkFunc (FuncPool.FuncInfo fi) {
232 if (fi is null) return;
233 if (fi.mgtype != ":void:Actor") throw new Exception("invalid actor think function");
234 fiThink = fi;
237 void setOnTouchFunc (FuncPool.FuncInfo fi) {
238 if (fi is null) return;
239 if (fi.mgtype != ":void:Actor:Actor") throw new Exception("invalid actor onTouch function");
240 fiOnTouch = fi;
243 void callAnimInit () {
244 foreach (auto fi; fiAnimInit) if (fi !is null) fi();
247 void callInit (ActorId aid) {
248 if (fiInit is null || !aid.valid) return;
249 fiInit(aid);
252 void callThink (ActorId aid) {
253 if (fiThink is null || !aid.valid) return;
254 fiThink(aid);
257 void callOnTouch (ActorId aid, ActorId aother) {
258 if (fiOnTouch is null || !aid.valid || !aother.valid) return;
259 fiOnTouch(aid, aother);
264 // ////////////////////////////////////////////////////////////////////////// //
265 public __gshared ActorDef[string] actordefs; // by fullname
268 public ActorDef findD2DActorDef (ushort mapid) {
269 if (mapid == 0) assert(0);
270 if (mapid == 1 || mapid == 2) return findActorDefByFullName("monster:Player");
271 if (auto dad = mapid in d2dactordefsById) {
272 auto adef = findActorDefByFullName(dad.fullname);
273 if (adef is null) throw new Exception("can't find DACS actor definition for D2D actor '"~dad.fullname~"'");
274 return adef;
276 import std.conv : to;
277 throw new Exception("can't find D2D ActorDef for mapid "~to!string(mapid));
281 public ActorDef findActorDefByFullName (const(char)[] fullname) {
282 if (auto fd = fullname in actordefs) return *fd;
283 return null;
287 public ActorDef findActorDef (const(char)[] ctype, const(char)[] cname) {
288 if (ctype.length+cname.length > 1024) assert(0);
289 char[1025] buf;
290 buf[0..ctype.length] = ctype[];
291 buf[ctype.length] = ':';
292 buf[ctype.length+1..ctype.length+1+cname.length] = cname[];
293 if (auto fd = buf[0..ctype.length+1+cname.length] in actordefs) return *fd;
294 return null;
298 public ActorDef findActorDef (StrId ctype, StrId cname) { return findActorDef(ctype.get, cname.get); }
301 public ActorDef registerActorDef (string classtype, string classname) {
302 string fullname = classtype~":"~classname;
303 if (fullname !in actordefs) actordefs[fullname] = new ActorDef(classtype, classname);
304 if (auto fd = fullname in actordefs) return *fd;
305 assert(0);