1 module dengapi
is aliced
;
19 // ////////////////////////////////////////////////////////////////////////// //
20 private extern (C
) void _d_print_throwable (Throwable t
);
23 // ////////////////////////////////////////////////////////////////////////// //
28 // ////////////////////////////////////////////////////////////////////////// //
31 enum PLK_DOWN
= (1<<1);
32 enum PLK_LEFT
= (1<<2);
33 enum PLK_RIGHT
= (1<<3);
34 enum PLK_FIRE
= (1<<4);
35 enum PLK_JUMP
= (1<<5);
36 enum PLK_USE
= (1<<6);
39 __gshared
uint plrKeysLast
;
40 __gshared
uint plrKeyState
;
43 public void plrKeyDown (uint plidx
, uint mask
) {
44 if (mask
== 0 || plidx
> 0) return;
50 public void plrKeyUp (uint plidx
, uint mask
) {
51 if (mask
== 0 || plidx
> 0) return;
56 public void plrKeyUpDown (uint plidx
, uint mask
, bool down
) {
57 if (down
) plrKeyDown(plidx
, mask
); else plrKeyUp(plidx
, mask
);
61 void plrKeysFix (uint plidx
) {
62 if (plidx
> 0) return;
63 //conwritefln!"plrKeyState=0x%02x; plrKeysLast=0x%02x"(plrKeyState, plrKeysLast);
64 foreach (uint n
; 0..12) {
65 if ((plrKeyState
&(1<<n
)) == 0) plrKeysLast
&= ~(1<<n
);
70 // ////////////////////////////////////////////////////////////////////////// //
71 void updateActorClasses (int iteration
) {
72 foreach (string ctype
; dacsClassTypes(iteration
)) {
73 foreach (auto mod
; dacsClassModules(ctype
, iteration
)) {
74 auto adef
= registerActorDef(mod
.rmoduletype
.classtype
, mod
.rmoduletype
.classname
);
75 conwriteln("found info for actor '", adef
.fullname
, "'");
77 auto animInitFn
= FuncPool
.findByFQMG(mod
.name
~".initializeAnim", ":void");
78 if (animInitFn
!is null) adef
.setAnimInitFunc(animInitFn
);
81 auto initFn
= FuncPool
.findByFQMG(mod
.name
~".initialize", ":void:Actor");
82 if (initFn
!is null) adef
.setInitFunc(initFn
);
85 auto thinkFn
= FuncPool
.findByFQMG(mod
.name
~".think", ":void:Actor");
86 if (thinkFn
!is null) adef
.setThinkFunc(thinkFn
);
93 // ////////////////////////////////////////////////////////////////////////// //
94 private string
modLoader (string modname
) {
95 static string
getTextFile (string fname
) {
97 auto res
= loadTextFile(fname
);
98 conwriteln("loading DACS module file '", fname
, "' (", res
.length
, " bytes)");
99 if (res
is null) res
= "";
101 } catch (Exception
) {}
107 //res = getTextFile(modname~".dacs");
108 //if (res !is null) return res;
110 res
= getTextFile("scripts/"~modname
~".dacs");
111 if (res
!is null) return res
;
114 string
[] parts
= ["scripts"];
116 while (mn
.length
> 0) {
118 if (mn
[0] >= 'A' && mn
[0] <= 'Z') ++pos
;
119 while (pos
< mn
.length
&& (mn
[pos
] < 'A' || mn
[pos
] > 'Z')) ++pos
;
120 if (mn
[0] >= 'A' && mn
[0] <= 'Z') {
121 parts
~= cast(char)(mn
[0]+32)~mn
[1..pos
];
128 import std
.array
: join
;
129 string path
= parts
.join("/")~".dacs";
130 res
= getTextFile(path
);
131 if (res
!is null) return res
;
135 throw new Exception("module '"~modname
~"' not found");
139 __gshared
int modIteration
= 0;
141 public void loadWadScripts () {
142 if (moduleLoader
is null) moduleLoader
= (string modname
) => modLoader(modname
);
145 import std
.array
: split
;
146 auto t
= loadTextFile("scripts/dacsmain.txt");
147 foreach (string line
; t
.split('\n')) {
148 while (line
.length
&& line
[0] <= ' ') line
= line
[1..$];
149 if (line
.length
== 0 || line
[0] == ';') continue;
150 while (line
.length
&& line
[$-1] <= ' ') line
= line
[0..$-1];
153 } catch (Exception e
) { return; }
155 //conwriteln("loading main DACS module '", mainmod, "'");
156 auto iter
= modIteration
++;
157 conwriteln("iteration=", iter
);
158 foreach (string mod
; mainmods
) {
159 parseModule(mod
, iter
);
161 conwriteln("calling parseComplete; iteration=", iter
);
163 updateActorClasses(iter
);
164 } catch (CompilerException e
) {
165 _d_print_throwable(e
);
166 conwriteln("PARSE ERROR: ", e
.file
, " at ", e
.line
);
167 conwriteln(e
.toString
);
173 public void scriptLoadingComplete () {
175 dacsFinalizeCompiler();
179 // ////////////////////////////////////////////////////////////////////////// //
180 public __gshared LevelMap map
;
181 //public __gshared DACSVM dvm;
182 public __gshared
uint prngSyncSeed
= 0x29a;
183 public __gshared
uint prngSeed
= 0x29a; // unsynced
186 // ////////////////////////////////////////////////////////////////////////// //
187 // Park-Miller-Carta Pseudo-Random Number Generator, based on David G. Carta paper
188 // 31 bit of randomness
189 // seed is previous result, as usual
190 public uint prngR31next (uint seed
) {
191 if (seed
== 0) seed
= 0x29a;
192 uint lo
= 16807*(seed
&0xffff);
193 uint hi
= 16807*(seed
>>16);
194 lo
+= (hi
&0x7fff)<<16;
196 //if (lo > 0x7fffffff) lo -= 0x7fffffff; // should be >=, actually
197 lo
= (lo
&0x7FFFFFFF)+(lo
>>31); // same as previous code, but branch-less
202 // "synced" random, using common seed for all players
203 public uint syncrandu31 () {
204 pragma(inline
, true);
205 return (prngSyncSeed
= prngR31next(prngSyncSeed
));
209 // ////////////////////////////////////////////////////////////////////////// //
210 version(dacs_use_vm
) {
211 // this is VAT function, argument order is reversed
212 void doWrite(bool donl
) (FuncPool
.FuncInfo fi
, DACSVM vm
) {
214 auto count
= vm
.popInt();
215 while (count
-- > 0) {
216 auto type
= vm
.popInt();
217 switch (cast(VATArgType
)type
) {
218 case VATArgType
.Int
: write(vm
.popInt()); break;
219 case VATArgType
.Uint
: write(vm
.popUint()); break;
220 case VATArgType
.Float
: write(vm
.popFloat()); break;
221 case VATArgType
.StrId
: write(StrId(vm
.popUint()).get
); break;
222 case VATArgType
.ActorId
: write("<actor>"); vm
.popUint(); break; //TODO
223 default: write("<invalid-type>"); vm
.popUint(); break; //TODO
226 static if (donl
) writeln();
227 // push dummy return value
231 extern(C
) void doWrite(bool donl
) (uint argc
, ...) {
234 mainloop
: while (argc
>= 2) {
236 int tp
= va_arg
!int(_argptr
);
239 auto v
= va_arg
!int(_argptr
);
242 case VATArgType
.Uint
:
243 auto v
= va_arg
!uint(_argptr
);
246 case VATArgType
.Float
:
247 auto v
= va_arg
!float(_argptr
);
250 case VATArgType
.StrId
:
251 auto v
= StrId(va_arg
!uint(_argptr
)).get
;
254 case VATArgType
.ActorId
:
255 auto v
= ActorId(va_arg
!uint(_argptr
));
256 //write("<actor:", v.valid, ":", v.id, ">");
259 default: write("<invalid-type>"); break mainloop
;
262 static if (donl
) writeln();
267 // ////////////////////////////////////////////////////////////////////////// //
268 void animClearFrames (StrId classtype
, StrId classname
, StrId state
) {
269 auto adef
= findActorDef(classtype
.get
, classname
.get
);
270 if (adef
is null) throw new Exception("animClearFrames: actor '"~classtype
.get
~":"~classname
.get
~"' not found!");
271 adef
.clearFrames(state
);
275 void animAddFrame (StrId classtype
, StrId classname
, StrId state
, uint dir
, StrId sprname
) {
276 auto adef
= findActorDef(classtype
.get
, classname
.get
);
277 if (adef
is null) throw new Exception("animAddFrame: actor '"~classtype
.get
~":"~classname
.get
~"' not found!");
278 if (dir
!= 0) dir
= 1; //TODO: process mirror flag here
279 adef
.addFrame(state
, dir
, sprname
);
283 // ////////////////////////////////////////////////////////////////////////// //
285 conwriteln("setting up D API");
287 FuncPool
["write"] = &doWrite
!false;
288 FuncPool
["writeln"] = &doWrite
!true;
290 FuncPool
["syncrandu31"] = &syncrandu31
;
292 FuncPool
["animClearFrames"] = &animClearFrames
;
293 FuncPool
["animAddFrame"] = &animAddFrame
;
295 FuncPool
["actorSetAnimation"] = function void (ActorId me
, StrId state
) {
296 if (!me
.valid
) return;
297 if (auto adef
= findActorDef(me
.classtype
!string
, me
.classname
!string
)) {
298 me
.zAnimstate
= state
;
303 FuncPool
["getPlayer"] = function ActorId () { assert(0); };
305 FuncPool
["getPlayerButtons"] = function uint (uint pidx
) { return (pidx
== 0 ? plrKeysLast
: 0); };
307 FuncPool
["mapGetTypeTile"] = function int (int x
, int y
) {
308 return (map
!is null && x
>= 0 && y
>= 0 && x
< map
.width
&& y
< map
.height ? map
.tiles
.ptr
[LevelMap
.Type
].ptr
[y
*map
.width
+x
] : 0);
311 FuncPool
["mapGetTile"] = function int (uint layer
, int x
, int y
) {
312 return (map
!is null && x
>= 0 && y
>= 0 && x
< map
.width
&& y
< map
.height
&& layer
>= 0 && layer
<= 1 ? map
.tiles
.ptr
[LevelMap
.Front
+layer
].ptr
[y
*map
.width
+x
] : 0);
316 public void registerAPI () {
317 conwriteln("actor size is ", Actor
.actorSize
, " bytes");
319 version(dacs_use_vm
) FuncPool
.vm
= new DACSVM();
320 //dvm = new DACSVM();
322 // initialize actor animation
323 foreach (ActorDef adef
; actordefs
.byValue
) {
327 conwriteln("API registered");
331 // ////////////////////////////////////////////////////////////////////////// //
332 __gshared ActorId
[2] players
;
334 public void loadMapMonsters () {
335 assert(map
!is null);
336 players
[] = ActorId(0);
337 //conwriteln(players[0].valid, "; ", players[0].id);
338 foreach (ref thing
; map
.things
) {
339 if (thing
.dmonly
) continue;
340 if (auto did
= thing
.type
in d2dactordefsById
) {
341 if (did
.classtype
== "item") continue;
342 if (did
.classtype
== "playerstart") {
343 if (thing
.type
== 1 || thing
.type
== 2) {
344 int pnum
= thing
.type
-1;
345 if (!players
[pnum
].valid
) {
346 auto aid
= Actor
.alloc
;
347 aid
.classtype
= StrPool
.intern("monster");
348 aid
.classname
= StrPool
.intern("Player");
349 aid
.plrnum
= cast(uint)pnum
;
350 aid
.state
= StrPool
.MNST_SLEEP
;
351 aid
.x
= cast(int)thing
.x
;
352 aid
.y
= cast(int)thing
.y
;
353 aid
.dir
= cast(uint)(thing
.right ?
1 : 0);
354 auto adef
= findD2DActorDef(thing
.type
);
355 if (adef
is null) assert(0);
358 conwriteln("player #", pnum
+1, " aid is ", aid
.id
);
364 auto adef
= findD2DActorDef(thing
.type
);
366 if (auto did
= thing
.type
in d2dactordefsById
) {
367 conwriteln("ignoring D2D thing '", did
.fullname
, "'");
369 conwriteln("ignoring unknown D2D thing with mapid ", thing
.type
);
373 // load graphics (we'll load all graphics)
374 //adef.loadGraphics();
375 // create actor and initialize it
376 auto aid
= Actor
.alloc
;
377 aid
.classtype
= StrPool
.intern(adef
.classtype
);
378 aid
.classname
= StrPool
.intern(adef
.classname
);
379 //conwriteln("found '", aid.classtype.get, ":", aid.classname.get, "'");
380 if (auto did
= thing
.type
in d2dactordefsById
) {
381 assert(did
.classtype
== adef
.classtype
);
382 assert(did
.classname
== adef
.classname
);
383 conwriteln("mapid=", thing
.type
, "; ", adef
.classtype
, ":", adef
.classname
, "; id=", aid
.id
);
384 assert(aid
.classtype
!string
== adef
.classtype
);
385 assert(aid
.classname
!string
== adef
.classname
);
389 aid
.state
= StrPool
.MNST_SLEEP
;
390 aid
.x
= cast(int)thing
.x
;
391 aid
.y
= cast(int)thing
.y
;
392 aid
.dir
= cast(uint)(thing
.right ?
1 : 0);
396 foreach (ActorDef adef
; actordefs
.byValue
) {
397 conwriteln("loading graphics for '", adef
.fullname
, "'");
400 //Actor.dumpActors();
402 conwriteln("initial snapshot size: ", Actor
.snapshotSize
, " bytes");
406 // ////////////////////////////////////////////////////////////////////////// //
407 public void doActorsThink () {
408 Actor
.forEach((ActorId me
) {
409 // `act` is always valid here
410 if (auto adef
= findActorDef(me
.classtype
!string
, me
.classname
!string
)) {
412 int aidx
= me
.zAnimidx
!int;
413 int nidx
= adef
.nextAnimIdx(me
.zAnimstate
!StrId
, me
.dir
!uint, aidx
);
414 //conwriteln("actor ", me.id, " (", me.classtype!string, me.classname!string, "): state=", me.zAnimstate!string, "; aidx=", aidx, "; nidx=", nidx);
416 assert(me
.zAnimidx
!int == nidx
);
420 //{ import std.stdio : stdout; stdout.writeln("========================================="); }
421 //Actor.dumpActors();