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) {
79 if (animInitFn
.code
.length
== 0) throw new CompilerException("invalid 'initializeAnim' in module '"~mod
.name
~"' for '"~mod
.rmoduletype
.classtype
~":"~mod
.rmoduletype
.classname
~"'");
81 adef
.setAnimInitFunc(animInitFn
);
84 auto initFn
= FuncPool
.findByFQMG(mod
.name
~".initialize", ":void:Actor");
85 if (initFn
!is null) {
86 if (initFn
.code
.length
== 0) throw new CompilerException("invalid 'initialize' in module '"~mod
.name
~"' for '"~mod
.rmoduletype
.classtype
~":"~mod
.rmoduletype
.classname
~"'");
88 adef
.setInitFunc(initFn
);
91 auto thinkFn
= FuncPool
.findByFQMG(mod
.name
~".think", ":void:Actor");
92 if (thinkFn
!is null) {
93 if (thinkFn
.code
.length
== 0) throw new CompilerException("invalid 'think' in module '"~mod
.name
~"' for '"~mod
.rmoduletype
.classtype
~":"~mod
.rmoduletype
.classname
~"'");
95 adef
.setThinkFunc(thinkFn
);
102 // ////////////////////////////////////////////////////////////////////////// //
103 private string
modLoader (string modname
) {
104 static string
getTextFile (string fname
) {
106 auto res
= loadTextFile(fname
);
107 conwriteln("loading DACS module file '", fname
, "' (", res
.length
, " bytes)");
108 if (res
is null) res
= "";
110 } catch (Exception
) {}
116 //res = getTextFile(modname~".dacs");
117 //if (res !is null) return res;
119 res
= getTextFile("scripts/"~modname
~".dacs");
120 if (res
!is null) return res
;
123 string
[] parts
= ["scripts"];
125 while (mn
.length
> 0) {
127 if (mn
[0] >= 'A' && mn
[0] <= 'Z') ++pos
;
128 while (pos
< mn
.length
&& (mn
[pos
] < 'A' || mn
[pos
] > 'Z')) ++pos
;
129 if (mn
[0] >= 'A' && mn
[0] <= 'Z') {
130 parts
~= cast(char)(mn
[0]+32)~mn
[1..pos
];
137 import std
.array
: join
;
138 string path
= parts
.join("/")~".dacs";
139 res
= getTextFile(path
);
140 if (res
!is null) return res
;
144 throw new Exception("module '"~modname
~"' not found");
148 __gshared
int modIteration
= 0;
150 public void loadWadScripts () {
151 if (moduleLoader
is null) moduleLoader
= (string modname
) => modLoader(modname
);
154 import std
.array
: split
;
155 auto t
= loadTextFile("scripts/dacsmain.txt");
156 foreach (string line
; t
.split('\n')) {
157 while (line
.length
&& line
[0] <= ' ') line
= line
[1..$];
158 if (line
.length
== 0 || line
[0] == ';') continue;
159 while (line
.length
&& line
[$-1] <= ' ') line
= line
[0..$-1];
162 } catch (Exception e
) { return; }
164 //conwriteln("loading main DACS module '", mainmod, "'");
165 auto iter
= modIteration
++;
166 foreach (string mod
; mainmods
) {
167 parseModule(mod
, iter
);
169 updateActorClasses(iter
);
171 } catch (CompilerException e
) {
172 _d_print_throwable(e
);
173 conwriteln("PARSE ERROR: ", e
.file
, " at ", e
.line
);
174 conwriteln(e
.toString
);
180 // ////////////////////////////////////////////////////////////////////////// //
181 public __gshared LevelMap map
;
182 public __gshared DACSVM dvm
;
183 public __gshared
uint prngSyncSeed
= 0x29a;
184 public __gshared
uint prngSeed
= 0x29a; // unsynced
187 // ////////////////////////////////////////////////////////////////////////// //
188 // Park-Miller-Carta Pseudo-Random Number Generator, based on David G. Carta paper
189 // 31 bit of randomness
190 // seed is previous result, as usual
191 public uint prngR31next (uint seed
) {
192 if (seed
== 0) seed
= 0x29a;
193 uint lo
= 16807*(seed
&0xffff);
194 uint hi
= 16807*(seed
>>16);
195 lo
+= (hi
&0x7fff)<<16;
197 //if (lo > 0x7fffffff) lo -= 0x7fffffff; // should be >=, actually
198 lo
= (lo
&0x7FFFFFFF)+(lo
>>31); // same as previous code, but branch-less
203 // "synced" random, using common seed for all players
204 public uint syncrandu31 () {
205 pragma(inline
, true);
206 return (prngSyncSeed
= prngR31next(prngSyncSeed
));
210 // ////////////////////////////////////////////////////////////////////////// //
211 // this is VAT function, argument order is reversed
212 void doWrite (DACSVM vm
, bool donl
) {
213 auto count
= vm
.popInt();
214 while (count
-- > 0) {
215 auto type
= vm
.popInt();
216 switch (cast(VATArgType
)type
) {
217 case VATArgType
.Int
: conwrite(vm
.popInt()); break;
218 case VATArgType
.Uint
: conwrite(vm
.popUint()); break;
219 case VATArgType
.Float
: conwrite(vm
.popFloat()); break;
220 case VATArgType
.StrId
: conwrite(StrId(vm
.popUint()).get
); break;
221 case VATArgType
.ActorId
: conwrite("<actor>"); vm
.popUint(); break; //TODO
222 default: conwrite("<invalid-type>"); vm
.popUint(); break; //TODO
225 if (donl
) conwriteln();
226 // push dummy return value
231 // ////////////////////////////////////////////////////////////////////////// //
232 void animClearFrames (StrId classtype
, StrId classname
, StrId state
) {
233 auto adef
= findActorDef(classtype
.get
, classname
.get
);
234 if (adef
is null) throw new Exception("animClearFrames: actor '"~classtype
.get
~":"~classname
.get
~"' not found!");
235 adef
.clearFrames(state
);
239 void animAddFrame (StrId classtype
, StrId classname
, StrId state
, uint dir
, StrId sprname
) {
240 auto adef
= findActorDef(classtype
.get
, classname
.get
);
241 if (adef
is null) throw new Exception("animAddFrame: actor '"~classtype
.get
~":"~classname
.get
~"' not found!");
242 if (dir
!= 0) dir
= 1; //TODO: process mirror flag here
243 adef
.addFrame(state
, dir
, sprname
);
247 // ////////////////////////////////////////////////////////////////////////// //
248 public void registerAPI () {
251 FuncPool
["write"] = delegate void (FuncPool
.FuncInfo fi
, DACSVM vm
) { doWrite(vm
, false); };
252 FuncPool
["writeln"] = delegate void (FuncPool
.FuncInfo fi
, DACSVM vm
) { doWrite(vm
, true); };
254 FuncPool
["syncrandu31"] = &syncrandu31
;
256 FuncPool
["animClearFrames"] = &animClearFrames
;
257 FuncPool
["animAddFrame"] = &animAddFrame
;
259 FuncPool
["actorSetAnimation"] = function void (ActorId me
, StrId state
) {
260 if (!me
.valid
) return;
261 if (auto adef
= findActorDef(me
.classtype
!string
, me
.classname
!string
)) {
262 me
.zAnimstate
= state
;
267 FuncPool
["getPlayer"] = function ActorId () { assert(0); };
269 FuncPool
["getPlayerButtons"] = function uint (uint pidx
) { return (pidx
== 0 ? plrKeysLast
: 0); };
271 FuncPool
["mapGetTypeTile"] = function int (int x
, int y
) {
272 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);
275 FuncPool
["mapGetTile"] = function int (uint layer
, int x
, int y
) {
276 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);
279 // initialize actor animation
280 foreach (ActorDef adef
; actordefs
.byValue
) {
281 adef
.callAnimInit(dvm
);
286 // ////////////////////////////////////////////////////////////////////////// //
287 __gshared ActorId
[2] players
;
289 public void loadMapMonsters () {
290 assert(map
!is null);
291 players
[] = ActorId(0);
292 conwriteln(players
[0].valid
, "; ", players
[0].id
);
293 foreach (ref thing
; map
.things
) {
294 if (thing
.dmonly
) continue;
295 if (auto did
= thing
.type
in d2dactordefsById
) {
296 if (did
.classtype
== "item") continue;
297 if (did
.classtype
== "playerstart") {
298 if (thing
.type
== 1 || thing
.type
== 2) {
299 int pnum
= thing
.type
-1;
300 if (!players
[pnum
].valid
) {
301 auto aid
= Actor
.alloc
;
302 aid
.classtype
= StrPool
.intern("monster");
303 aid
.classname
= StrPool
.intern("Player");
304 aid
.plrnum
= cast(uint)pnum
;
305 aid
.state
= StrPool
.MNST_SLEEP
;
306 aid
.x
= cast(int)thing
.x
;
307 aid
.y
= cast(int)thing
.y
;
308 aid
.dir
= cast(uint)(thing
.right ?
1 : 0);
309 auto adef
= findD2DActorDef(thing
.type
);
310 if (adef
is null) assert(0);
311 adef
.callInit(dvm
, aid
);
313 conwriteln("player #", pnum
+1, " aid is ", aid
.id
);
319 auto adef
= findD2DActorDef(thing
.type
);
321 if (auto did
= thing
.type
in d2dactordefsById
) {
322 conwriteln("ignoring D2D thing '", did
.fullname
, "'");
324 conwriteln("ignoring unknown D2D thing with mapid ", thing
.type
);
328 // load graphics (we'll load all graphics)
329 //adef.loadGraphics();
330 // create actor and initialize it
331 auto aid
= Actor
.alloc
;
332 aid
.classtype
= StrPool
.intern(adef
.classtype
);
333 aid
.classname
= StrPool
.intern(adef
.classname
);
334 if (auto did
= thing
.type
in d2dactordefsById
) {
335 assert(did
.classtype
== adef
.classtype
);
336 assert(did
.classname
== adef
.classname
);
337 conwriteln("mapid=", thing
.type
, "; ", adef
.classtype
, ":", adef
.classname
, "; id=", aid
.id
);
338 assert(aid
.classtype
!string
== adef
.classtype
);
339 assert(aid
.classname
!string
== adef
.classname
);
343 aid
.state
= StrPool
.MNST_SLEEP
;
344 aid
.x
= cast(int)thing
.x
;
345 aid
.y
= cast(int)thing
.y
;
346 aid
.dir
= cast(uint)(thing
.right ?
1 : 0);
347 adef
.callInit(dvm
, aid
);
350 foreach (ActorDef adef
; actordefs
.byValue
) {
351 conwriteln("loading graphics for '", adef
.fullname
, "'");
354 //Actor.dumpActors();
358 // ////////////////////////////////////////////////////////////////////////// //
359 public void doActorsThink () {
360 Actor
.forEach((ActorId me
) {
361 // `act` is always valid here
362 if (auto adef
= findActorDef(me
.classtype
!string
, me
.classname
!string
)) {
363 adef
.callThink(dvm
, me
);
364 int aidx
= me
.zAnimidx
!int;
365 int nidx
= adef
.nextAnimIdx(me
.zAnimstate
!StrId
, me
.dir
!uint, aidx
);
366 //conwriteln("actor ", me.id, " (", me.classtype!string, me.classname!string, "): state=", me.zAnimstate!string, "; aidx=", aidx, "; nidx=", nidx);
368 assert(me
.zAnimidx
!int == nidx
);
372 //{ import std.stdio : stdout; stdout.writeln("========================================="); }
373 //Actor.dumpActors();