1 module ungmk
is aliced
;
11 //version = gmk_debug_dump;
14 // ////////////////////////////////////////////////////////////////////////// //
15 static immutable string
[uint] evKeyNames
;
16 static immutable string
[uint] evMouseNames
;
17 static immutable string
[uint] evOtherNames
;
19 shared static this () {
21 evKeyNames
[37] = "left";
22 evKeyNames
[39] = "right";
23 evKeyNames
[38] = "up";
24 evKeyNames
[40] = "down";
26 evKeyNames
[17] = "control";
27 evKeyNames
[18] = "alt";
28 evKeyNames
[16] = "shift";
29 evKeyNames
[32] = "space";
30 evKeyNames
[13] = "enter";
32 evKeyNames
[96] = "numpad 0";
33 evKeyNames
[97] = "numpad 1";
34 evKeyNames
[98] = "numpad 2";
35 evKeyNames
[99] = "numpad 3";
36 evKeyNames
[100] = "numpad 4";
37 evKeyNames
[101] = "numpad 5";
38 evKeyNames
[102] = "numpad 6";
39 evKeyNames
[103] = "numpad 7";
40 evKeyNames
[104] = "numpad 8";
41 evKeyNames
[105] = "numpad 9";
43 evKeyNames
[111] = "numpad divide";
44 evKeyNames
[106] = "numpad multiply";
45 evKeyNames
[109] = "numpad subtract";
46 evKeyNames
[107] = "numpad add";
47 evKeyNames
[110] = "numpad decimal";
87 evKeyNames
[112] = "f1";
88 evKeyNames
[113] = "f2";
89 evKeyNames
[114] = "f3";
90 evKeyNames
[115] = "f4";
91 evKeyNames
[116] = "f5";
92 evKeyNames
[117] = "f6";
93 evKeyNames
[118] = "f7";
94 evKeyNames
[119] = "f8";
95 evKeyNames
[120] = "f9";
96 evKeyNames
[121] = "f10";
97 evKeyNames
[122] = "f11";
98 evKeyNames
[123] = "f12";
100 evKeyNames
[8] = "backspace";
101 evKeyNames
[27] = "escape";
102 evKeyNames
[36] = "home";
103 evKeyNames
[35] = "end";
104 evKeyNames
[33] = "pageup";
105 evKeyNames
[34] = "pagedown";
106 evKeyNames
[46] = "delete";
107 evKeyNames
[45] = "insert";
109 evKeyNames
[0] = "no key";
110 evKeyNames
[1] = "any key";
113 evMouseNames
[0] = "mouse left button";
114 evMouseNames
[1] = "mouse right button";
115 evMouseNames
[2] = "mouse middle button";
116 evMouseNames
[3] = "mouse no button";
117 evMouseNames
[4] = "mouse left button pressed";
118 evMouseNames
[5] = "mouse right button pressed";
119 evMouseNames
[6] = "mouse middle button pressed";
120 evMouseNames
[7] = "mouse left button released";
121 evMouseNames
[8] = "mouse right button released";
122 evMouseNames
[9] = "mouse middle button released";
123 evMouseNames
[10] = "mouse enter";
124 evMouseNames
[11] = "mouse leave";
125 evMouseNames
[16] = "joystick 1 left";
126 evMouseNames
[17] = "joystick 1 right";
127 evMouseNames
[18] = "joystick 1 up";
128 evMouseNames
[19] = "joystick 1 down";
129 evMouseNames
[21] = "joystick 1 button 1";
130 evMouseNames
[22] = "joystick 1 button 2";
131 evMouseNames
[23] = "joystick 1 button 3";
132 evMouseNames
[24] = "joystick 1 button 4";
133 evMouseNames
[25] = "joystick 1 button 5";
134 evMouseNames
[26] = "joystick 1 button 6";
135 evMouseNames
[27] = "joystick 1 button 7";
136 evMouseNames
[28] = "joystick 1 button 8";
137 evMouseNames
[31] = "joystick 2 left";
138 evMouseNames
[32] = "joystick 2 right";
139 evMouseNames
[33] = "joystick 2 up";
140 evMouseNames
[34] = "joystick 2 down";
141 evMouseNames
[36] = "joystick 2 button 1";
142 evMouseNames
[37] = "joystick 2 button 2";
143 evMouseNames
[38] = "joystick 2 button 3";
144 evMouseNames
[39] = "joystick 2 button 4";
145 evMouseNames
[40] = "joystick 2 button 5";
146 evMouseNames
[41] = "joystick 2 button 6";
147 evMouseNames
[42] = "joystick 2 button 7";
148 evMouseNames
[43] = "joystick 2 button 8";
149 evMouseNames
[50] = "mouse global left button";
150 evMouseNames
[51] = "mouse global right button";
151 evMouseNames
[52] = "mouse global middle button";
152 evMouseNames
[53] = "mouse global left pressed";
153 evMouseNames
[54] = "mouse global right pressed";
154 evMouseNames
[55] = "mouse global middle pressed";
155 evMouseNames
[56] = "mouse global left released";
156 evMouseNames
[57] = "mouse global right released";
157 evMouseNames
[58] = "mouse global middle released";
158 evMouseNames
[60] = "mouse wheel up";
159 evMouseNames
[61] = "mouse wheel down";
162 evOtherNames
[0] = "outside room";
163 evOtherNames
[1] = "intersect boundary";
164 evOtherNames
[2] = "game start";
165 evOtherNames
[3] = "game end";
166 evOtherNames
[4] = "room start";
167 evOtherNames
[5] = "room end";
168 evOtherNames
[6] = "no more lives";
169 evOtherNames
[7] = "animation end";
170 evOtherNames
[8] = "end of path";
171 evOtherNames
[9] = "no more health";
173 evOtherNames
[10] = "user 0";
174 evOtherNames
[11] = "user 1";
175 evOtherNames
[12] = "user 2";
176 evOtherNames
[13] = "user 3";
177 evOtherNames
[14] = "user 4";
178 evOtherNames
[15] = "user 5";
179 evOtherNames
[16] = "user 6";
180 evOtherNames
[17] = "user 7";
181 evOtherNames
[18] = "user 8";
182 evOtherNames
[19] = "user 9";
183 evOtherNames
[20] = "user 10";
184 evOtherNames
[21] = "user 11";
185 evOtherNames
[22] = "user 12";
186 evOtherNames
[23] = "user 13";
187 evOtherNames
[24] = "user 14";
188 evOtherNames
[25] = "user 15";
190 evOtherNames
[30] = "close button";
192 evOtherNames
[40] = "outside view 0";
193 evOtherNames
[41] = "outside view 1";
194 evOtherNames
[42] = "outside view 2";
195 evOtherNames
[43] = "outside view 3";
196 evOtherNames
[44] = "outside view 4";
197 evOtherNames
[45] = "outside view 5";
198 evOtherNames
[46] = "outside view 6";
199 evOtherNames
[47] = "outside view 7";
201 evOtherNames
[50] = "boundary view 0";
202 evOtherNames
[51] = "boundary view 1";
203 evOtherNames
[52] = "boundary view 2";
204 evOtherNames
[53] = "boundary view 3";
205 evOtherNames
[54] = "boundary view 4";
206 evOtherNames
[55] = "boundary view 5";
207 evOtherNames
[56] = "boundary view 6";
208 evOtherNames
[57] = "boundary view 7";
212 // ////////////////////////////////////////////////////////////////////////// //
213 DateTime
fromDelphiDT (double d
) {
215 import core
.stdc
.math
: modf
;
216 auto dt = Date(Date(1899, 12, 30).dayOfGregorianCal
+cast(int)d
);
219 auto seconds
= cast(int)(24*60*60*f
+0.5);
220 if (seconds
> 59) seconds
= 59;
221 auto tm
= TimeOfDay(seconds
/(60*60), (seconds
/60)%60, seconds
%60);
222 return DateTime(dt, tm
);
226 double toDelphiDT (DateTime
dt) {
227 double d
= dt.dayOfGregorianCal
-Date(1899, 12, 30).dayOfGregorianCal
;
228 d
+= (dt.hour
*(60*60)+dt.minute
*60+dt.second
)/(24.0*60.0*60.0);
233 // ////////////////////////////////////////////////////////////////////////// //
234 string
readPStr (VFile fl
) {
235 auto sz
= fl
.readNum
!uint;
236 if (sz
> 1024*1024) throw new Exception("string too long");
237 if (sz
== 0) return "";
238 auto res
= new char[](sz
);
239 fl
.rawReadExact(res
[]);
240 return cast(string
)res
; // it's safe here
244 void writePStr (VFile fl
, string s
) {
245 if (s
.length
> 1024*1024) throw new Exception("string too long");
246 fl
.writeNum
!uint(cast(uint)s
.length
);
247 if (s
.length
) fl
.rawWriteExact(s
[]);
252 DateTime
readDateTime (VFile fl
) {
253 auto d
= fl
.readNum
!double;
255 auto dt = fromDelphiDT(d
);
256 auto dd = toDelphiDT(dt);
257 auto xd
= fromDelphiDT(dd);
262 return fromDelphiDT(d
);
266 void writeDateTime (VFile fl
, DateTime
dt) {
267 auto d
= toDelphiDT(dt);
268 fl
.writeNum
!double(d
);
272 // ////////////////////////////////////////////////////////////////////////// //
273 TrueColorImage
readImage (VFile fl
) {
274 auto w
= fl
.readNum
!uint;
275 auto h
= fl
.readNum
!uint;
276 if (w
> 32767 || h
> 32767) {
277 import std
.conv
: to
;
278 throw new Exception("too big image: "~to
!string(w
)~"x"~to
!string(h
));
280 if (w
> 0 && h
> 0) {
281 auto isz
= fl
.readNum
!uint;
282 if (isz
< w
*h
*4) throw new Exception("image data size too small");
284 auto img
= new TrueColorImage(w
, h
);
286 foreach (int y; 0..h) {
287 foreach (int x; 0..w) {
289 clr.b = fl.readNum!ubyte;
290 clr.g = fl.readNum!ubyte;
291 clr.r = fl.readNum!ubyte;
292 clr.a = fl.readNum!ubyte;
293 img.setPixel(x, y, clr);
297 fl
.rawReadExact(img
.imageData
.bytes
[0..w
*h
*4]);
299 auto bp
= img
.imageData
.bytes
.ptr
;
300 foreach (immutable _
; 0..w
*h
) {
306 //while (isz--) fl.readNum!ubyte;
307 if (isz
> 0) fl
.seek(isz
, Seek
.Cur
);
310 return new TrueColorImage(0, 0);
315 void writeImage (VFile fl
, TrueColorImage img
) {
316 if (img
.width
> 32767 || img
.height
> 32767) throw new Exception("too big image");
317 fl
.writeNum
!uint(cast(uint)img
.width
);
318 fl
.writeNum
!uint(cast(uint)img
.height
);
319 if (img
.width
> 0 && img
.height
> 0) {
320 fl
.writeNum
!uint(cast(uint)img
.width
*cast(uint)img
.height
*4);
321 foreach (int y
; 0..img
.height
) {
322 foreach (int x
; 0..img
.width
) {
323 Color clr
= img
.getPixel(x
, y
);
324 fl
.writeNum
!ubyte(clr
.b
);
325 fl
.writeNum
!ubyte(clr
.g
);
326 fl
.writeNum
!ubyte(clr
.r
);
327 fl
.writeNum
!ubyte(clr
.a
);
334 // ////////////////////////////////////////////////////////////////////////// //
335 struct XField(string typename
) {
336 enum TypeName
= typename
;
341 // ////////////////////////////////////////////////////////////////////////// //
342 mixin template GenIO() {
343 private static alias Id(alias T
) = T
;
345 private static string
genRead(T
) () {
347 foreach (immutable fname
; __traits(derivedMembers
, T
)) {
348 alias mem
= Id
!(__traits(getMember
, T
, fname
));
349 foreach (immutable uda
; __traits(getAttributes
, mem
)) {
350 static if (typeof(uda
).stringof
.length
> 6 && typeof(uda
).stringof
[0..7] == "XField!") {
351 static if (uda
.TypeName
[0] == '!') {
353 res
~= "read_"~fname
~"(fl);\n";
354 } else static if (uda
.TypeName
== "Color") {
355 res
~= fname
~".b = fl.readNum!ubyte;\n";
356 res
~= fname
~".g = fl.readNum!ubyte;\n";
357 res
~= fname
~".r = fl.readNum!ubyte;\n";
358 res
~= fname
~".a = fl.readNum!ubyte;\n";
359 } else static if (uda
.TypeName
== "pstr") {
360 res
~= fname
~" = fl.readPStr;\n";
361 } else static if (uda
.TypeName
== "tdatetime") {
362 res
~= fname
~" = fl.readDateTime;\n";
363 } else static if (typeof(mem
).stringof
== uda
.TypeName
) {
364 res
~= fname
~" = fl.readNum!"~uda
.TypeName
~";\n";
365 } else static if (is(typeof(mem
) == bool)) {
366 res
~= fname
~" = (fl.readNum!"~uda
.TypeName
~" != 0);\n";
368 res
~= fname
~" = cast("~typeof(mem
).stringof
~")fl.readNum!"~uda
.TypeName
~";\n";
369 //static assert(0, "wtf for '"~fname~"': uda says '"~uda.TypeName~"', type is '"~typeof(mem).stringof~"'");
377 private static string
genWrite(T
) () {
379 foreach (immutable fname
; __traits(derivedMembers
, T
)) {
380 alias mem
= Id
!(__traits(getMember
, T
, fname
));
381 foreach (immutable uda
; __traits(getAttributes
, mem
)) {
382 static if (typeof(uda
).stringof
.length
> 6 && typeof(uda
).stringof
[0..7] == "XField!") {
383 static if (uda
.TypeName
[0] == '!') {
385 res
~= "write_"~fname
~"(fl);\n";
386 } else static if (uda
.TypeName
== "Color") {
387 res
~= "fl.writeNum!ubyte("~fname
~".b);\n";
388 res
~= "fl.writeNum!ubyte("~fname
~".g);\n";
389 res
~= "fl.writeNum!ubyte("~fname
~".r);\n";
390 res
~= "fl.writeNum!ubyte("~fname
~".a);\n";
391 } else static if (uda
.TypeName
== "pstr") {
392 res
~= "fl.writePStr("~fname
~");\n";
393 } else static if (uda
.TypeName
== "tdatetime") {
394 res
~= "fl.writeDateTime("~fname
~");\n";
395 } else static if (typeof(mem
).stringof
== uda
.TypeName
) {
396 res
~= "fl.writeNum!"~uda
.TypeName
~"("~fname
~");\n";
397 } else static if (is(typeof(mem
) == bool)) {
398 res
~= "fl.writeNum!"~uda
.TypeName
~"(cast("~uda
.TypeName
~")("~fname
~" ? 1 : 0));\n";
400 //static assert(0, "wtf for '"~fname~"'!");
401 res
~= "fl.writeNum!"~uda
.TypeName
~"(cast("~uda
.TypeName
~")"~fname
~");\n";
409 private static string
genDump(T
) () {
411 foreach (immutable fname
; __traits(derivedMembers
, T
)) {
412 alias mem
= Id
!(__traits(getMember
, T
, fname
));
413 foreach (immutable uda
; __traits(getAttributes
, mem
)) {
414 static if (uda
.TypeName
[0] == '!') {
416 } else static if (typeof(uda
).stringof
.length
> 6 && typeof(uda
).stringof
[0..7] == "XField!") {
417 static if (uda
.TypeName
== "Color") {
418 res
~= "writefln(\""~uda
.desc
~": rgba(%s,%s,%s,%s)\", "~fname
~".r, "~fname
~".g, "~fname
~".b, "~fname
~".a);\n";
419 } else static if (uda
.TypeName
== "pstr") {
420 res
~= "writeln(\""~uda
.desc
~": [\", "~fname
~", \"]\");\n";
421 } else static if (uda
.TypeName
== "tdatetime") {
422 //res ~= "writeln(\""~uda.desc~": \", "~fname~");\n";
424 res
~= "writeln(\""~uda
.desc
~": \", "~fname
~");\n";
432 //pragma(msg, genRead!(typeof(this)));
433 //pragma(msg, genWrite!(typeof(this)));
434 //pragma(msg, genDump!(typeof(this)));
435 mixin("void read (VFile fl) {\n"~genRead
!(typeof(this))~"}");
436 mixin("void write (VFile fl) {\n"~genWrite
!(typeof(this))~"}");
437 mixin("void dump () {\nimport std.stdio;\n"~genDump
!(typeof(this))~"}");
443 @XField!uint("this is some flag") bool flag;
449 // ////////////////////////////////////////////////////////////////////////// //
450 final class GMSprite
{
452 enum Shape
{ Precise
, Rectangle
, Disk
, Diamond
}
453 enum BBox
{ Automatic
, Full
, Manual
}
460 TrueColorImage
[] images
;
462 ubyte alphaTolerance
;
463 bool separateCollisionMasks
;
465 int bbleft
, bbtop
, bbright
, bbbottom
;
467 this (uint aidx
, VFile fl
) { idx
= aidx
; load(fl
); }
471 writeln("name: [", name
, "]");
472 //writeln("lastmod: ", lastmod);
473 writeln("ofs: ", xofs
, ", ", yofs
);
474 writeln("images: ", images
.length
);
475 foreach (immutable idx
, TrueColorImage img
; images
) {
476 writeln(" #", idx
, "; ", img
.width
, "x", img
.height
);
478 writeln("shape: ", shape
);
479 writeln("alpha tolerance: ", alphaTolerance
);
480 writeln("separate collision masks: ", separateCollisionMasks
);
481 writeln("bbox: ", bbox
, " (", bbleft
, ",", bbtop
, ")-(", bbright
, ",", bbbottom
, ")");
485 void load (VFile fl
) {
487 lastmod
= fl
.readDateTime
;
488 auto xver
= fl
.readNum
!uint;
489 //writeln("xver: ", xver);
490 if (xver
< 800 || xver
> 810) throw new Exception("invalid sprite version");
491 xofs
= fl
.readNum
!int;
492 yofs
= fl
.readNum
!int;
493 auto count
= fl
.readNum
!uint;
494 if (count
> 65535) throw new Exception("too many images in sprite sprite");
496 foreach (immutable idx
; 0..count
) {
497 xver
= fl
.readNum
!uint;
498 if (xver
< 800) throw new Exception("invalid sprite image version");
499 images
~= fl
.readImage
;
502 auto v
= fl
.readNum
!uint;
503 if (v
> Shape
.max
) throw new Exception("invalid sprite shape");
504 shape
= cast(Shape
)v
;
507 auto v
= fl
.readNum
!uint;
508 if (v
> alphaTolerance
.max
) throw new Exception("invalid sprite alpha tolerance");
509 alphaTolerance
= cast(ubyte)v
;
511 separateCollisionMasks
= (fl
.readNum
!uint != 0);
513 auto v
= fl
.readNum
!uint;
514 if (v
> BBox
.max
) throw new Exception("invalid sprite bounding box type");
517 bbleft
= fl
.readNum
!int;
518 bbright
= fl
.readNum
!int;
519 bbbottom
= fl
.readNum
!int;
520 bbtop
= fl
.readNum
!int;
525 // ////////////////////////////////////////////////////////////////////////// //
526 final class GMBackground
{
532 int tileWidth
, tileHeight
;
535 TrueColorImage image
;
537 this (uint aidx
, VFile fl
) { idx
= aidx
; load(fl
); }
541 writeln("name: [", name
, "]");
542 //writeln("lastmod: ", lastmod);
543 writeln("tileset: ", tileset
, "; ", tileWidth
, "x", tileHeight
);
544 writeln("ofs: ", xofs
, ", ", yofs
);
545 writeln("sep: ", xsep
, ", ", ysep
);
546 writeln("image: ", image
.width
, "x", image
.height
);
550 void load (VFile fl
) {
552 lastmod
= fl
.readDateTime
;
553 auto xver
= fl
.readNum
!uint;
554 //writeln("xver: ", xver);
555 if (xver
!= 710) throw new Exception("invalid background version");
556 tileset
= (fl
.readNum
!uint != 0);
557 tileWidth
= fl
.readNum
!int;
558 tileHeight
= fl
.readNum
!int;
559 xofs
= fl
.readNum
!int;
560 yofs
= fl
.readNum
!int;
561 xsep
= fl
.readNum
!int;
562 ysep
= fl
.readNum
!int;
563 xver
= fl
.readNum
!uint;
564 //writeln("xver: ", xver);
565 if (xver
< 800 || xver
> 810) throw new Exception("invalid background info version");
566 image
= fl
.readImage
;
571 // ////////////////////////////////////////////////////////////////////////// //
572 final class GMAction
{
574 enum Type
{ Nothing
, Function
, Code
}
621 int applyobj
; // object index to apply; -1: self; -2: other
627 this (VFile fl
) { load(fl
); }
631 writeln(" libid: ", libid
);
632 writeln(" id: ", id
);
633 writeln(" kind: ", kind
);
634 writeln(" mayberelative: ", mayberelative
);
635 writeln(" question: ", question
);
636 writeln(" applied: ", applied
);
637 writeln(" type: ", type
);
638 writeln(" funcname: [", funcname
, "]");
639 writeln(" codename: [", codename
, "]");
640 writeln(" argused: ", argused
);
641 if (argused
> 0) writeln(" argtypes: ", argtypes
[0..argused
]);
642 writeln(" applyobj: ", applyobj
);
643 writeln(" relative: ", relative
);
645 writeln(" argvals (", argused
, "):");
646 foreach (immutable idx
, string s
; argvals
[0..argused
]) {
648 s
= s
.detab
.outdentAll
;
649 writeln(" #", idx
, ":");
650 foreach (auto ln
; s
.byLine
) if (ln
.length
) writeln(" ", ln
);
652 //writeln(" argvals: ", argvals[0..argused]);
654 writeln(" negated: ", negated
);
658 void load (VFile fl
) {
659 auto xver
= fl
.readNum
!uint;
660 if (xver
!= 440) throw new Exception("invalid action version");
661 libid
= fl
.readNum
!uint;
662 id
= fl
.readNum
!uint;
664 auto v
= fl
.readNum
!uint;
665 if (v
> Kind
.max
) throw new Exception("invalid action kind");
668 mayberelative
= (fl
.readNum
!uint != 0);
669 question
= (fl
.readNum
!uint != 0);
670 applied
= (fl
.readNum
!uint != 0);
672 auto v
= fl
.readNum
!uint;
673 if (v
> Type
.max
) throw new Exception("invalid action type");
676 funcname
= fl
.readPStr
;
677 codename
= fl
.readPStr
;
678 argused
= fl
.readNum
!uint;
679 if (argused
> 8) throw new Exception("invalid number of arguments used in action");
680 auto akcount
= fl
.readNum
!uint;
681 if (akcount
> 8) { import std
.conv
: to
; throw new Exception("invalid number of argument kinds for action: "~to
!string(akcount
)); }
682 argtypes
[] = ArgType
.t_string
; //FIXME
683 foreach (immutable idx
; 0..akcount
) {
684 auto v
= fl
.readNum
!uint;
685 if (v
> ArgType
.max
) throw new Exception("invalid argument type");
686 argtypes
[idx
] = cast(ArgType
)v
;
688 applyobj
= fl
.readNum
!int;
689 relative
= fl
.readNum
!uint;
690 auto akvals
= fl
.readNum
!uint;
691 if (akvals
!= akcount
) { import std
.conv
: to
; throw new Exception("invalid number of argument values for action: "~to
!string(akvals
)); }
693 foreach (immutable idx
; 0..akvals
) argvals
[idx
] = fl
.readPStr
;
694 negated
= (fl
.readNum
!uint != 0);
699 // ////////////////////////////////////////////////////////////////////////// //
700 final class GMEvent
{
722 this (VFile fl
, Type atype
, uint aid
) { type
= atype
; load(fl
, aid
); }
726 writeln("event id=", id
, "; type=", evType(type
), "; action count: ", actions
.length
);
727 foreach (immutable idx
, GMAction act
; actions
) {
728 writeln(" -- action #", idx
, " --");
733 static string
evType (Type t
) {
734 import std
.string
: format
;
735 return (t
<= Type
.max ?
"%s".format(t
) : "<%s>".format(cast(uint)t
));
739 void load (VFile fl
, uint aid
) {
741 auto xver
= fl
.readNum
!uint;
742 if (xver
!= 400) throw new Exception("invalid event version");
743 auto count
= fl
.readNum
!uint;
744 if (count
> 1024) throw new Exception("too many actions in event");
745 foreach (immutable idx
; 0..count
) actions
~= new GMAction(fl
);
750 // ////////////////////////////////////////////////////////////////////////// //
751 final class GMObject
{
756 int spridx
; // -1: none
761 int parentobjidx
; // -100: none
762 int maskspridx
; // -1: none
763 GMEvent
[][GMEvent
.Type
.max
+1] events
;
766 this (uint aidx
, VFile fl
) { idx
= aidx
; load(fl
); }
770 writeln("name: [", name
, "]");
771 //writeln("lastmod: ", lastmod);
772 writeln("spridx:", spridx
);
773 writeln("solid: ", solid
);
774 writeln("visible: ", visible
);
775 writeln("depth: ", depth
);
776 writeln("persistent: ", persistent
);
777 writeln("parentobjidx: ", parentobjidx
);
778 writeln("maskspridx: ", maskspridx
);
779 foreach (immutable evidx
, GMEvent
[] evs
; events
) {
780 if (evs
.length
== 0) continue;
781 writeln(" -- evidx: ", evidx
, " --");
782 foreach (immutable idx
, GMEvent ev
; evs
) {
783 writeln(" -- event #", idx
, " --");
790 void load (VFile fl
) {
792 lastmod
= fl
.readDateTime
;
793 auto xver
= fl
.readNum
!uint;
794 if (xver
!= 430) throw new Exception("invalid object version");
795 spridx
= fl
.readNum
!int;
796 solid
= (fl
.readNum
!uint != 0);
797 visible
= (fl
.readNum
!uint != 0);
798 depth
= fl
.readNum
!int;
799 persistent
= (fl
.readNum
!uint != 0);
800 parentobjidx
= fl
.readNum
!int;
801 maskspridx
= fl
.readNum
!int;
802 auto ecount
= fl
.readNum
!uint;
803 if (ecount
!= 10 && ecount
!= 11) throw new Exception("invalid number of event types");
804 foreach (immutable evidx
; 0..ecount
+1) {
807 int eid
= fl
.readNum
!int;
808 if (eid
== -1) break;
809 lst
~= new GMEvent(fl
, cast(GMEvent
.Type
)evidx
, eid
);
817 // ////////////////////////////////////////////////////////////////////////// //
824 int bgimageidx
; // -1: none
833 writeln("visibleOnStart: ", visibleOnStart
);
834 writeln("fgimage: ", fgimage
);
835 writeln("bgimageidx: ", bgimageidx
);
836 writeln("pos: (", x
, ",", y
, ")");
837 writeln("tile: (", xtile
, ",", ytile
, ")");
838 writeln("speed: (", xspeed
, ",", yspeed
, ")");
839 writeln("stretch: ", stretch
);
843 void load (VFile fl
) {
844 visibleOnStart
= (fl
.readNum
!uint != 0);
845 fgimage
= (fl
.readNum
!uint != 0);
846 bgimageidx
= fl
.readNum
!int;
849 xtile
= fl
.readNum
!int;
850 ytile
= fl
.readNum
!int;
851 xspeed
= fl
.readNum
!int;
852 yspeed
= fl
.readNum
!int;
853 stretch
= (fl
.readNum
!uint != 0);
864 int xborder
, yborder
;
866 int objfollow
; // -1: none
871 writeln("visibleOnStart: ", visibleOnStart
);
872 writeln("view: (", x
, ",", y
, "); ", width
, "x", height
);
873 writeln("port: (", portx
, ",", porty
, "); ", portw
, "x", porth
);
874 writeln("border: (", xborder
, ",", yborder
, ")");
875 writeln("space: (", xspace
, ",", yspace
, ")");
876 writeln("objfollow: ", objfollow
);
880 void load (VFile fl
, uint xver
) {
881 visibleOnStart
= (fl
.readNum
!uint != 0);
885 width
= fl
.readNum
!int;
886 height
= fl
.readNum
!int;
887 portx
= fl
.readNum
!int;
888 porty
= fl
.readNum
!int;
893 width
= fl
.readNum
!int;
894 height
= fl
.readNum
!int;
895 portx
= fl
.readNum
!int;
896 porty
= fl
.readNum
!int;
897 portw
= fl
.readNum
!int;
898 porth
= fl
.readNum
!int;
900 xborder
= fl
.readNum
!int;
901 yborder
= fl
.readNum
!int;
902 xspace
= fl
.readNum
!int;
903 yspace
= fl
.readNum
!int;
904 objfollow
= fl
.readNum
!int;
917 this (VFile fl
) { load(fl
); }
921 writeln("position: ", x
, "x", y
);
922 writeln("objidx: ", objidx
);
924 writeln("createcode: ", createcode
.quote
);
925 writeln("locked: ", locked
);
929 void load (VFile fl
) {
932 objidx
= fl
.readNum
!int;
933 id
= fl
.readNum
!uint;
934 createcode
= fl
.readPStr
;
935 locked
= (fl
.readNum
!uint != 0);
950 this (VFile fl
) { load(fl
); }
954 writeln("position: ", x
, "x", y
);
955 writeln("bgidx: ", bgidx
);
956 writeln("tile: (", xtile
, ",", ytile
, "); ", wtile
, "x", htile
);
957 writeln("layer: ", layer
);
959 writeln("locked: ", locked
);
963 void load (VFile fl
) {
966 bgidx
= fl
.readNum
!int;
967 xtile
= fl
.readNum
!int;
968 ytile
= fl
.readNum
!int;
969 wtile
= fl
.readNum
!int;
970 htile
= fl
.readNum
!int;
971 layer
= fl
.readNum
!int;
972 id
= fl
.readNum
!uint;
973 locked
= (fl
.readNum
!uint != 0);
1000 this (uint aidx
, VFile fl
) { idx
= aidx
; load(fl
); }
1004 writeln("name: [", name
, "]");
1005 //writeln("lastmod: ", lastmod);
1006 writeln("caption: [", caption
, "]");
1007 writeln("size: ", width
, "x", height
);
1008 writeln("snap: ", xsnap
, "x", ysnap
);
1009 writeln("isogrid: ", isogrid
);
1010 writeln("speed: ", speed
);
1011 writeln("persistent: ", persistent
);
1012 writefln("bgcolor: 0x%08x", bgcolor
);
1013 writeln("drawbgcolor: ", drawbgcolor
);
1014 writeln("tile size: ", tilew
, "x", tileh
);
1015 writeln("tile sep: ", xtsep
, "x", ytsep
);
1016 writeln("tile ofs: ", xtofs
, "x", ytofs
);
1017 writeln("createcode: ", createcode
.quote
);
1018 foreach (immutable idx
, ref Back b
; backs
) {
1019 if (b
.bgimageidx
== -1) continue;
1020 writeln("-- background #", idx
, " --");
1023 writeln("viewsEnabled: ", viewsEnabled
);
1024 foreach (immutable idx
, ref View v
; views
) {
1025 writeln("-- view #", idx
, " --");
1028 foreach (immutable idx
, ref Inst i
; insts
) {
1029 writeln("-- instance #", idx
, " --");
1032 foreach (immutable idx
, ref Tile t
; tiles
) {
1033 writeln("-- tile #", idx
, " --");
1039 void load (VFile fl
) {
1041 lastmod
= fl
.readDateTime
;
1042 auto xver
= fl
.readNum
!uint;
1043 if (xver
!= 520 && xver
!= 541) throw new Exception("invalid room version");
1044 caption
= fl
.readPStr
;
1045 width
= fl
.readNum
!uint;
1046 height
= fl
.readNum
!uint;
1047 xsnap
= fl
.readNum
!int;
1048 ysnap
= fl
.readNum
!int;
1049 isogrid
= (fl
.readNum
!uint != 0);
1050 speed
= fl
.readNum
!int;
1051 persistent
= (fl
.readNum
!uint != 0);
1052 bgcolor
= fl
.readNum
!uint;
1053 drawbgcolor
= (fl
.readNum
!uint != 0);
1054 createcode
= fl
.readPStr
;
1055 if (fl
.readNum
!uint != 8) throw new Exception("invalid number of backgrounds in room");
1056 foreach (ref Back b
; backs
) b
.load(fl
);
1057 viewsEnabled
= (fl
.readNum
!uint != 0);
1058 if (fl
.readNum
!uint != 8) throw new Exception("invalid number of views in room");
1059 foreach (ref View v
; views
) v
.load(fl
, xver
);
1060 auto count
= fl
.readNum
!uint;
1061 if (count
> 1024*1024) throw new Exception("too many instances in room");
1062 foreach (immutable idx
; 0..count
) insts
~= Inst(fl
);
1063 count
= fl
.readNum
!uint;
1064 if (count
> 1024*1024) throw new Exception("too many tiles in room");
1065 foreach (immutable idx
; 0..count
) tiles
~= Tile(fl
);
1066 bool rei
= (fl
.readNum
!uint != 0); // room editor info
1068 fl
.readNum
!uint; // REI width
1069 fl
.readNum
!uint; // REI height
1070 fl
.readNum
!uint; // REI grid show bool
1071 fl
.readNum
!uint; // REI objects show bool
1072 fl
.readNum
!uint; // REI tiles show bool
1073 fl
.readNum
!uint; // REI bg show bool
1074 fl
.readNum
!uint; // REI fg show bool
1075 fl
.readNum
!uint; // REI views show bool
1076 fl
.readNum
!uint; // REI delete underlying objects bool
1077 fl
.readNum
!uint; // REI delete underlying tiles bool
1079 tilew
= fl
.readNum
!int;
1080 tileh
= fl
.readNum
!int;
1081 xtsep
= fl
.readNum
!int;
1082 ytsep
= fl
.readNum
!int;
1083 xtofs
= fl
.readNum
!int;
1084 ytofs
= fl
.readNum
!int;
1090 fl
.readNum
!uint; // REI tab
1091 fl
.readNum
!uint; // REI scroll x
1092 fl
.readNum
!uint; // REI scroll y
1097 // ////////////////////////////////////////////////////////////////////////// //
1098 final class GMTrigger
{
1100 enum When
{ Begin
, Middle
, End
}
1110 this (uint aidx
, VFile fl
) { idx
= aidx
; load(fl
); }
1114 writeln("name: [", name
, "]");
1115 writeln("condition: [", condition
.quote
, "]");
1116 writeln("when: ", when
);
1117 writeln("constname: [", constname
, "]");
1121 void load (VFile fl
) {
1122 auto xver
= fl
.readNum
!uint;
1124 if (xver
!= 800) throw new Exception("invalid trigger version");
1126 condition
= fl
.readPStr
;
1128 auto v
= fl
.readNum
!uint;
1129 if (v
> When
.max
) throw new Exception("invalid trigger when");
1132 constname
= fl
.readPStr
;
1137 // ////////////////////////////////////////////////////////////////////////// //
1138 final class GMGameInfo
{
1139 @XField!("uint")("fullscreen") bool fullscreen
;
1140 @XField!("uint")("color interpolation") bool cinterp
;
1141 @XField!("uint")("window border") bool winborder
;
1142 @XField!("uint")("show cursor") bool showcursor
;
1143 @XField!("int")("scale") int scale
;
1144 @XField!("uint")("allow resize") bool allowresize
;
1145 @XField!("uint")("always on top") bool alwaysontop
;
1146 @XField!("Color")("background color") Color bgcolor
;
1147 @XField!("uint")("change resolution") bool changeres
;
1148 @XField!("uint")("color depth") uint colordepth
;
1149 @XField!("uint")("resolution") uint resolution
;
1150 @XField!("uint")("fps") uint fps
;
1151 @XField!("uint")("window title buttons") bool wintitle
;
1152 @XField!("uint")("vsync") bool vsync
;
1153 @XField!("uint")("disable screensaver") bool noscreensaver
;
1154 @XField!("uint")("enable F4 fullscreen switch") bool enablef4
;
1155 @XField!("uint")("enable F1 game info") bool enablef1
;
1156 @XField!("uint")("enable Esc game end") bool enableesc
;
1157 @XField!("uint")("enable F5/F6 game save/load") bool enablef5f6
;
1158 @XField!("uint")("enable F9 game screenshot") bool enablef9
;
1159 @XField!("uint")("close button as Esc") bool closeasesc
;
1160 @XField!("uint")("process priority") uint procprio
;
1161 @XField!("uint")("vsync") bool pauseonbloor
;
1163 @XField!("!")("loading progress bar") uint pbar
;
1164 TrueColorImage bgpbar
, fgpbar
;
1166 @XField!("!")("show splashscreen") bool showsplash
;
1167 //TrueColorImage splashimg;
1168 ubyte[] splashimg
; // BMP
1170 @XField!("uint")("transparent splashscreen") bool slpashtransparent
;
1171 @XField!("uint")("translucent splashscreen alpha") ubyte splashalpha
;
1172 @XField!("uint")("scale progress bar image") bool pbarscale
;
1173 @XField!("!")("icon data") /*TrueColorImage*/ubyte[] icon
; // windoze .ico
1174 @XField!("uint")("display error messages") bool showerrors
;
1175 @XField!("uint")("log error messages to 'game_errors.log'") bool logerrors
;
1176 @XField!("uint")("abort on error") bool abortonerror
;
1177 @XField!("uint")("tread uninited vars as '0'") bool zeroallvars
;
1178 @XField!("pstr")("author") string author
;
1179 @XField!("pstr")("version") string ver
;
1180 @XField!("tdatetime")("lastmod for info") DateTime lastmodnfo
;
1182 @XField!("pstr")("information") string information
;
1183 @XField!("uint")("major") uint major
;
1184 @XField!("uint")("minor") uint minor
;
1185 @XField!("uint")("release") uint release
;
1186 @XField!("uint")("build") uint build
;
1187 @XField!("pstr")("company") string company
;
1188 @XField!("pstr")("product") string product
;
1189 @XField!("pstr")("copyright") string copyright
;
1190 @XField!("pstr")("description") string descritpion
;
1191 @XField!("tdatetime")("lastmod for global game settings") DateTime lastmod
;
1196 void read_pbar (VFile fl
) {
1197 pbar
= fl
.readNum
!uint;
1202 if (fl
.readNum
!uint) {
1203 auto sz
= fl
.readNum
!uint;
1204 auto npos
= fl
.tell
+sz
;
1205 //fl.seek(sz, Seek.Cur);
1206 bgpbar
= readImage(fl
);
1210 if (fl
.readNum
!uint) {
1211 auto sz
= fl
.readNum
!uint;
1212 auto npos
= fl
.tell
+sz
;
1213 //fl.seek(sz, Seek.Cur);
1214 fgpbar
= readImage(fl
);
1220 void write_pbar (VFile fl
) {
1221 fl
.writeNum
!uint(pbar
);
1223 if (bgpbar
!is null) {
1224 fl
.writeNum
!uint(bgpbar
.width
*bgpbar
.height
*4+3*4); // data size
1225 fl
.writeImage(bgpbar
);
1227 fl
.writeNum
!uint(0);
1229 if (fgpbar
!is null) {
1230 fl
.writeNum
!uint(fgpbar
.width
*fgpbar
.height
*4+3*4); // data size
1231 fl
.writeImage(fgpbar
);
1233 fl
.writeNum
!uint(0);
1238 void read_showsplash (VFile fl
) {
1239 auto showsplash
= fl
.readNum
!uint;
1243 if (fl
.readNum
!uint) {
1244 auto sz
= fl
.readNum
!uint;
1248 writeln("SPLASH! sz=", sz);
1250 auto zst = wrapZLibStreamRO(fl, VFSZLibMode.ZLib, -1, pos, sz);
1253 ubyte[1024] tmp = void;
1254 auto rd = zst.rawRead(tmp[]);
1255 if (rd.length == 0) break;
1258 auto fo = VFile("zsp00.bin", "w");
1260 fl.rawReadExact(buf[]);
1262 fo.rawWriteExact(buf[]);
1266 auto npos
= fl
.tell
+sz
;
1267 //fl.seek(sz, Seek.Cur);
1268 auto zst
= wrapZLibStreamRO(fl
, VFSZLibMode
.ZLib
, -1, fl
.tell
, sz
);
1269 splashimg
.length
= 0;
1271 ubyte[1024] tmp
= void;
1272 auto rd
= zst
.rawRead(tmp
[]);
1273 if (rd
.length
== 0) break;
1281 void write_showsplash (VFile fl
) {
1282 fl
.writeNum
!uint(showsplash ?
1 : 0);
1284 if (splashimg
!is null) {
1285 //fl.writeNum!uint(splashimg.width*splashimg.height*4+3*4); // data size
1286 //fl.writeImage(splashimg);
1287 fl
.writeNum
!uint(0);
1289 fl
.writeNum
!uint(0);
1294 void read_icon (VFile fl
) {
1297 auto sz
= fl
.readNum
!uint;
1298 icon
= new ubyte[](sz
);
1299 fl
.rawReadExact(icon
[]);
1302 void write_icon (VFile fl
) {
1303 fl
.writeNum
!uint(cast(uint)icon
.length
);
1304 if (icon
.length
) fl
.rawWriteExact(icon
[]);
1309 // ////////////////////////////////////////////////////////////////////////// //
1310 final class GMGameHelp
{
1311 @XField!("Color")("background color") Color bgcolor
;
1312 @XField!("uint")("show help in separate window") bool newwindow
;
1313 @XField!("pstr")("caption") string caption
;
1314 @XField!("int")("position x") int x
;
1315 @XField!("int")("position y") int y
;
1316 @XField!("int")("width") int w
;
1317 @XField!("int")("height") int h
;
1318 @XField!("uint")("show window border") bool windowborder
;
1319 @XField!("uint")("allow window resizing") bool allowresize
;
1320 @XField!("uint")("window on top") bool alwaysontop
;
1321 @XField!("uint")("pause game") bool pause
;
1322 @XField!("tdatetime")("lastmod") DateTime lastmod
;
1323 @XField!("pstr")("help text") string text
;
1329 // ////////////////////////////////////////////////////////////////////////// //
1330 final class GMScript
{
1335 this (uint aidx
, string aname
, string acode
) { idx
= aidx
; name
= aname
; code
= acode
; }
1339 // ////////////////////////////////////////////////////////////////////////// //
1341 GMGameInfo gameInfo
;
1342 GMGameHelp gameHelp
;
1343 private GMTrigger
[] triggers
;
1344 private GMSprite
[] sprites
;
1345 private GMBackground
[] backgrounds
;
1346 private GMRoom
[] rooms
;
1347 private GMObject
[] objects
;
1348 private GMScript
[] scripts
;
1350 private GMObject
[string
] oByNameAA
; // objects by name
1351 private GMRoom
[string
] rByNameAA
; // rooms by name
1352 private GMSprite
[string
] sByNameAA
; // sprites by name
1353 private GMBackground
[string
] bByNameAA
; // backgrounds by name
1354 private GMScript
[string
] scrByNameAA
; // scripts by name
1356 this (VFile fl
, bool dump
=false) { load(fl
, dump
); }
1357 this (const(char)[] fname
, bool dump
=false) { load(VFile(fname
), dump
); }
1359 pure nothrow @trusted @nogc {
1360 GMObject
objParent (GMObject o
) {
1361 pragma(inline
, true);
1362 return (o
is null ?
null : objByNum(o
.parentobjidx
));
1365 GMObject
objByNum (int num
) { pragma(inline
, true); return (num
>= 0 && num
< objects
.length ? objects
.ptr
[num
] : null); }
1366 GMRoom
roomByNum (int num
) { pragma(inline
, true); return (num
>= 0 && num
< rooms
.length ? rooms
.ptr
[num
] : null); }
1367 GMSprite
sprByNum (int num
) { pragma(inline
, true); return (num
>= 0 && num
< sprites
.length ? sprites
.ptr
[num
] : null); }
1368 GMBackground
bgByNum (int num
) { pragma(inline
, true); return (num
>= 0 && num
< backgrounds
.length ? backgrounds
.ptr
[num
] : null); }
1369 GMScript
scriptByNum (int num
) { pragma(inline
, true); return (num
>= 0 && num
< scripts
.length ? scripts
.ptr
[num
] : null); }
1371 GMObject
objByName (const(char)[] name
) { /*pragma(inline, true);*/ if (auto v
= name
in oByNameAA
) return *v
; else return null; }
1372 GMRoom
roomByName (const(char)[] name
) { /*pragma(inline, true);*/ if (auto v
= name
in rByNameAA
) return *v
; else return null; }
1373 GMSprite
sprByName (const(char)[] name
) { /*pragma(inline, true);*/ if (auto v
= name
in sByNameAA
) return *v
; else return null; }
1374 GMBackground
bgByName (const(char)[] name
) { /*pragma(inline, true);*/ if (auto v
= name
in bByNameAA
) return *v
; else return null; }
1375 GMScript
scriptByName (const(char)[] name
) { /*pragma(inline, true);*/ if (auto v
= name
in scrByNameAA
) return *v
; else return null; }
1379 GMObject
forEachObject (bool delegate (GMObject o
) dg
) { foreach (auto v
; objects
) if (v
!is null && dg(v
)) return v
; return null; }
1380 GMRoom
forEachRoom (bool delegate (GMRoom o
) dg
) { foreach (auto v
; rooms
) if (v
!is null && dg(v
)) return v
; return null; }
1381 GMSprite
forEachSprite (bool delegate (GMSprite o
) dg
) { foreach (auto v
; sprites
) if (v
!is null && dg(v
)) return v
; return null; }
1382 GMBackground
forEachBg (bool delegate (GMBackground o
) dg
) { foreach (auto v
; backgrounds
) if (v
!is null && dg(v
)) return v
; return null; }
1383 GMScript
forEachScript (bool delegate (GMScript o
) dg
) { foreach (auto v
; scripts
) if (v
!is null && dg(v
)) return v
; return null; }
1386 void postProcess () {
1387 forEachObject((v
) { oByNameAA
[v
.name
] = v
; return false; });
1388 forEachRoom((v
) { rByNameAA
[v
.name
] = v
; return false; });
1389 forEachSprite((v
) { sByNameAA
[v
.name
] = v
; return false; });
1390 forEachBg((v
) { bByNameAA
[v
.name
] = v
; return false; });
1391 forEachScript((v
) { scrByNameAA
[v
.name
] = v
; return false; });
1394 void load (VFile fl
, bool dodump
) {
1395 auto sign
= fl
.readNum
!uint;
1396 if (sign
!= 1234321) throw new Exception("invalid signature");
1397 auto ver
= fl
.readNum
!uint;
1398 if (dodump
) writeln("version: ", ver
/100, ".", ver
%100);
1399 if (ver
< 800) throw new Exception("invalid version");
1400 auto gameid
= fl
.readNum
!uint;
1401 if (dodump
) writeln("game id: ", gameid
);
1402 ubyte[16] gameguid
= void;
1403 fl
.rawReadExact(gameguid
[]);
1404 if (dodump
) { write("game id: "); foreach (ubyte b
; gameguid
[]) writef("%02x", b
); writeln
; }
1407 if (dodump
) writeln("=== game settings ===");
1408 auto xver
= fl
.readNum
!uint;
1409 if (dodump
) writeln("xver: ", xver
);
1410 assert(xver
>= 800);
1411 auto pksize
= fl
.readNum
!uint;
1412 auto npos
= fl
.tell
+pksize
;
1413 scope(exit
) fl
.seek(npos
);
1414 //writeln("size: ", pksize);
1415 auto zst
= wrapZLibStreamRO(fl
, VFSZLibMode
.ZLib
, -1, fl
.tell
, pksize
);
1416 //writeln("unpacked size: ", zst.size);
1417 auto gi
= new GMGameInfo();
1419 if (dodump
) gi
.dump
;
1424 if (dodump
) writeln("=== triggers ===");
1425 auto xver
= fl
.readNum
!uint;
1426 if (dodump
) writeln("xver: ", xver
);
1427 assert(xver
>= 800);
1428 auto count
= fl
.readNum
!uint;
1429 if (dodump
) writeln("count: ", count
);
1431 auto pksize
= fl
.readNum
!uint;
1432 auto npos
= fl
.tell
+pksize
;
1433 scope(exit
) fl
.seek(npos
);
1434 if (dodump
) writeln("pksize: ", pksize
);
1435 auto zst
= wrapZLibStreamRO(fl
, VFSZLibMode
.ZLib
, -1, fl
.tell
, pksize
);
1436 if (dodump
) writeln("upsize: ", zst
.size
);
1437 foreach (uint idx
; 0..count
) {
1438 if (zst
.readNum
!uint) {
1439 auto tg
= new GMTrigger(idx
, zst
);
1440 if (dodump
) writeln("-- trigger #", idx
, " --");
1441 if (dodump
) tg
.dump
;
1442 assert(triggers
.length
== idx
);
1445 assert(triggers
.length
== idx
);
1450 auto lastmod
= fl
.readDateTime
;
1451 //if (dodump) writeln("lastmod: ", lastmod);
1455 if (dodump
) writeln("=== constants ===");
1456 auto xver
= fl
.readNum
!uint;
1457 if (dodump
) writeln("xver: ", xver
);
1458 assert(xver
>= 800);
1459 auto count
= fl
.readNum
!uint;
1460 if (dodump
) writeln("count: ", count
);
1461 foreach (immutable idx
; 0..count
) {
1462 auto name
= fl
.readPStr
;
1463 auto value
= fl
.readPStr
;
1464 if (dodump
) writeln("[", name
, "]=[", value
, "]");
1466 auto lastmod
= fl
.readDateTime
;
1467 //if (dodump) writeln("lastmod: ", lastmod);
1470 static immutable string
[9] ResNames
= [
1492 foreach (immutable idx
, string resname
; ResNames
) {
1493 if (dodump
) writeln("=== res:", resname
, " ===");
1494 auto xver
= fl
.readNum
!uint;
1495 if (dodump
) writeln("xver: ", ver
);
1496 assert(xver
>= 800);
1497 auto count
= fl
.readNum
!uint;
1498 if (dodump
) writeln("count: ", count
);
1500 foreach (uint c
; 0..count
) {
1501 auto pksize
= fl
.readNum
!uint;
1502 auto npos
= fl
.tell
+pksize
;
1503 scope(exit
) fl
.seek(npos
);
1504 //writeln("zstream size: ", pksize);
1505 auto zst
= wrapZLibStreamRO(fl
, VFSZLibMode
.ZLib
, -1, fl
.tell
, pksize
);
1506 if (idx
== ResType
.Sprites
) {
1508 if (zst
.readNum
!uint) {
1509 auto spr
= new GMSprite(c
, zst
);
1510 if (dodump
) writeln("-- sprite #", c
, " --");
1511 if (dodump
) spr
.dump
;
1512 assert(sprites
.length
== c
);
1515 if (dodump
) writeln("-- sprite #", c
, " --");
1516 if (dodump
) writeln(" NONE");
1517 assert(sprites
.length
== c
);
1520 } else if (idx
== ResType
.Backrounds
) {
1522 if (zst
.readNum
!uint) {
1523 auto bg
= new GMBackground(c
, zst
);
1524 if (dodump
) writeln("-- background #", c
, " --");
1525 if (dodump
) bg
.dump
;
1526 assert(backgrounds
.length
== c
);
1529 if (dodump
) writeln("-- background #", c
, " --");
1530 if (dodump
) writeln(" NONE");
1531 assert(backgrounds
.length
== c
);
1532 backgrounds
~= null;
1534 } else if (idx
== ResType
.Scripts
) {
1536 if (zst
.readNum
!uint) {
1537 string name
= zst
.readPStr
;
1538 auto lastmod
= zst
.readDateTime
;
1539 if (dodump
) writeln("-- script #", c
, " --");
1540 if (dodump
) writeln("name: [", name
, "]");
1541 //if (dodump) writeln("lastmod: ", lastmod);
1542 auto vv
= zst
.readNum
!uint;
1543 if (vv
!= 400 && (vv
< 800 || vv
> 810)) throw new Exception("invalid script version");
1544 //writeln("===========\n", zst.readPStr, "\n===========");
1547 import std
.string
: replace
;
1548 string s
= zst
.readPStr
.replace("\r\n", "\n").replace("\r", "\n");
1550 auto sc
= new GMScript(c
, name
, s
);
1552 writeln("===========");
1553 foreach (auto ln
; s
.byLine
) if (ln
.length
) writeln(" ", ln
);
1554 writeln("===========");
1556 assert(scripts
.length
== c
);
1560 if (dodump
) writeln("-- script #", c
, " --");
1561 if (dodump
) writeln(" NONE");
1562 assert(scripts
.length
== c
);
1565 } else if (idx
== ResType
.Objects
) {
1567 if (zst
.readNum
!uint) {
1568 if (dodump
) writeln("-- object #", c
, " --");
1569 auto obj
= new GMObject(c
, zst
);
1570 if (dodump
) obj
.dump
;
1571 assert(objects
.length
== c
);
1574 //writeln("-- object #", c, " --");
1576 assert(objects
.length
== c
);
1579 } else if (idx
== ResType
.Rooms
) {
1581 if (zst
.readNum
!uint) {
1582 if (dodump
) writeln("-- room #", c
, " --");
1583 auto room
= new GMRoom(c
, zst
);
1584 if (dodump
) room
.dump
;
1585 assert(rooms
.length
== c
);
1588 //writeln("-- room #", c, " --");
1590 assert(rooms
.length
== c
);
1597 // done with resources
1598 auto lastInstanceId
= fl
.readNum
!uint;
1599 auto lastTileId
= fl
.readNum
!uint;
1600 if (dodump
) writeln("last instance placed id: ", lastInstanceId
);
1601 if (dodump
) writeln("last tile placed id: ", lastTileId
);
1604 auto xver
= fl
.readNum
!uint;
1605 if (/*xver != 620 &&*/ (xver
< 800 || xver
> 810)) throw new Exception("invalid include files version");
1606 auto count
= fl
.readNum
!uint;
1607 if (dodump
) writeln("number of include files: ", count
);
1609 auto pksize
= fl
.readNum
!uint;
1610 fl
.seek(pksize
, Seek
.Cur
);
1615 auto xver
= fl
.readNum
!uint;
1616 if (xver
!= 700) throw new Exception("invalid package list version");
1617 auto count
= fl
.readNum
!uint;
1618 if (dodump
) writeln("number of packages files: ", count
);
1620 string name
= fl
.readPStr
;
1621 if (dodump
) writeln(" package: [", name
, "]");
1626 auto xver
= fl
.readNum
!uint;
1627 if (xver
< 800 || xver
> 810) throw new Exception("invalid game information version");
1628 auto pksize
= fl
.readNum
!uint;
1629 auto npos
= fl
.tell
+pksize
;
1630 scope(exit
) fl
.seek(npos
);
1631 auto zst
= wrapZLibStreamRO(fl
, VFSZLibMode
.ZLib
, -1, fl
.tell
, pksize
);
1632 gameHelp
= new GMGameHelp();
1634 if (dodump
) gameHelp
.dump
;
1638 auto xver
= fl
.readNum
!uint;
1639 if (xver
!= 500) throw new Exception("invalid library dependency version");
1640 auto count
= fl
.readNum
!uint;
1642 auto lcc
= fl
.readPStr
;
1643 if (dodump
) if (lcc
.length
) writeln("libcreatecode: [", lcc
.quote
, "]");
1646 // room execution index
1648 auto xver
= fl
.readNum
!uint;
1649 if (xver
!= 500 && xver
!= 540 && xver
!= 700) throw new Exception("invalid library dependency version");
1650 auto count
= fl
.readNum
!uint;
1651 if (count
> 1024*1024) throw new Exception("room execution sequence too long");
1653 auto sq
= new uint[](count
);
1654 foreach (immutable idx
, ref i
; sq
) i
= fl
.readNum
!uint;
1655 if (dodump
) writeln("room sequence: ", sq
);
1660 static immutable string
[14] GroupName
= [
1672 "Global Game Settings",
1674 "Extension Packages",
1677 static immutable string
[12] FileGroupName
= [
1688 "Global Game Settings",
1689 "Extension Packages"
1692 static void writeIndent (int indent
) { foreach (immutable n
; 0..indent
) write(' '); }
1694 static void dumpTree (VFile fl
, int ind
, int curgrp
=-1) {
1695 enum Type
{ Invalid
, Root
, SubDir
, Leaf
}
1698 auto v
= fl
.readNum
!uint; // 0: root; 1: subdir; 2: leaf
1699 if (v
== 0 || v
> Type
.max
) { import std
.conv
: to
; throw new Exception("invalid resource type: "~to
!string(v
)); }
1703 writeIndent(ind
); writeln("---- [", FileGroupName
[curgrp
], "] ---");
1705 writeIndent(ind
); writeln("----");
1708 writeIndent(ind
); writeln("type: ", type
);
1709 auto grp
= fl
.readNum
!uint;
1710 if (grp
< GroupName
.length
) {
1711 writeIndent(ind
); writeln("grouping: ", grp
, " <", GroupName
[grp
], ">");
1713 writeIndent(ind
); writeln("grouping: ", grp
);
1715 if (type
== Type
.Leaf
) {
1716 writeIndent(ind
); writeln("index: ", fl
.readNum
!uint);
1718 writeIndent(ind
); writeln("parent: ", fl
.readNum
!uint);
1720 writeIndent(ind
); writeln("name: [", fl
.readPStr
, "]");
1721 auto childrenCount
= fl
.readNum
!uint;
1722 writeIndent(ind
); writeln("childrenCount: ", childrenCount
);
1724 foreach (immutable _
; 0..childrenCount
) dumpTree(fl
, ind
);
1727 //if (dodump) foreach (immutable ridx; 0..12) dumpTree(fl, 0, cast(int)ridx);