13 string undir
= "_src";
16 void exportActions (Gmk gmk
, File fo
, GMObject o
, usize evidx
, GMEvent ev
, string dir
) {
20 import std
.string
: format
, replace
;
21 if (ev
is null) return;
23 string
destarg (int idx
) {
24 if (idx
== -1) return "self";
25 if (idx
== -2) return "other";
26 return gmk
.objByNum(idx
).name
;
29 foreach (immutable aidx
, auto act
; ev
.actions
) {
30 if (aidx
!= 0) fo
.writeln("\n");
31 fo
.writeln("============ new_action ", act
.kind
, " for ", destarg(act
.applyobj
), " ============");
32 if (act
.type
== act
.Type
.Nothing
) {
34 fo
.writeln("funcname=", act
.funcname
);
35 fo
.writeln("codename=", act
.codename
);
39 case GMAction
.Kind
.act_normal
:
40 if (act
.type
== act
.Type
.Function
) {
41 fo
.write(act
.funcname
);
42 foreach (immutable ai
; 0..act
.argused
) {
43 switch (act
.argtypes
[ai
]) {
44 case GMAction
.ArgType
.t_expr
: fo
.write(" e", act
.argvals
[ai
].quote
); break;
45 case GMAction
.ArgType
.t_string
: fo
.write(" ", act
.argvals
[ai
].quote
); break;
46 case GMAction
.ArgType
.t_boolean
: fo
.write(" ", act
.argvals
[ai
]); break;
47 case GMAction
.ArgType
.t_sprite
: fo
.write(" ", gmk
.sprByNum(to
!int(act
.argvals
[0])).name
); break;
48 case GMAction
.ArgType
.t_background
: fo
.write(" ", gmk
.bgByNum(to
!int(act
.argvals
[0])).name
); break;
49 case GMAction
.ArgType
.t_script
: fo
.write(" ", gmk
.scriptByNum(to
!int(act
.argvals
[0])).name
); break;
50 case GMAction
.ArgType
.t_object
: fo
.write(" ", gmk
.objByNum(to
!int(act
.argvals
[0])).name
); break;
51 case GMAction
.ArgType
.t_room
: fo
.write(" ", gmk
.roomByNum(to
!int(act
.argvals
[0])).name
); break;
52 default: assert(0, "bad argument type:"~to
!string(act
.argtypes
[ai
]));
59 case GMAction
.Kind
.act_code
:
60 if (act
.argused
!= 1 || act
.argtypes
[0] != act
.ArgType
.t_string
) assert(0, "wtf?! "~to
!string(act
.argused
)~" : "~to
!string(act
.argtypes
[0]));
61 string code
= act
.argvals
[0].outdentAll
;
62 while (code
.length
&& code
[$-1] <= ' ') code
= code
[0..$-1];
64 foreach (string s
; code
.byLine
) {
65 //while (s.length && s[0] <= ' ') s = s[1..$];
66 while (s
.length
&& s
[$-1] <= ' ') s
= s
[0..$-1];
67 if (s
.length
== 0 && skip
) continue;
72 case GMAction
.Kind
.act_var
: // variable assignment
73 if (act
.argused
!= 2 || act
.argtypes
[0] != act
.ArgType
.t_string || act
.argtypes
[1] != act
.ArgType
.t_expr
) {
74 assert(0, "invalid action code arguments for '"~o
.name
~"': used="~to
!string(act
.argused
)~"; kinds="~to
!string(act
.argtypes
));
76 fo
.writeln(act
.argvals
[0]," = ", act
.argvals
[1]);
78 default: assert(0, "invalid action type: '"~to
!string(cast(GMAction
.Kind
)act
.kind
)~"'");
84 void exportObject (Gmk gmk
, GMObject o
, string dir
) {
88 import std
.string
: format
, replace
, toLower
;
90 try { mkdirRecurse(dir
); } catch (Exception
) {}
92 auto fo
= File(buildPath(dir
, "object.ini"), "w");
93 //fo.writeln("name=", o.name);
94 if (o
.parentobjidx
>= 0) fo
.writeln("parent=", gmk
.objByNum(o
.parentobjidx
).name
);
95 if (o
.spridx
>= 0) fo
.writeln("sprite=", gmk
.sprByNum(o
.spridx
).name
);
96 if (o
.maskspridx
>= 0) fo
.writeln("mask=", gmk
.sprByNum(o
.maskspridx
).name
);
97 fo
.writeln("solid=", o
.solid
);
98 fo
.writeln("persistent=", o
.persistent
);
99 fo
.writeln("visible=", o
.visible
);
100 fo
.writeln("depth=", o
.depth
);
102 foreach (immutable etidx
, auto evl
; o
.events
[]) {
103 foreach (immutable eidx
, auto ev
; evl
) {
104 // we HAVE to export empty events, as they prevents inherited events to run
107 case GMEvent
.Type
.ev_create
:
109 fname
= buildPath(dir
, "%s.gma".format(cast(GMEvent
.Type
)etidx
));
111 case GMEvent
.Type
.ev_destroy
:
113 fname
= buildPath(dir
, "%s.gma".format(cast(GMEvent
.Type
)etidx
));
115 case GMEvent
.Type
.ev_alarm
:
117 fname
= buildPath(dir
, "%s_%02s.gma".format(cast(GMEvent
.Type
)etidx
, ev
.id
));
119 case GMEvent
.Type
.ev_step
:
120 if (ev
.id
== 0) fname
= buildPath(dir
, "%s_normal.gma".format(cast(GMEvent
.Type
)etidx
));
121 else if (ev
.id
== 1) fname
= buildPath(dir
, "%s_begin.gma".format(cast(GMEvent
.Type
)etidx
));
122 else if (ev
.id
== 2) fname
= buildPath(dir
, "%s_end.gma".format(cast(GMEvent
.Type
)etidx
));
125 case GMEvent
.Type
.ev_collision
:
126 fname
= buildPath(dir
, "%s_with_%s.gma".format(cast(GMEvent
.Type
)etidx
, gmk
.objByNum(ev
.id
).name
));
128 case GMEvent
.Type
.ev_keyboard
:
129 case GMEvent
.Type
.ev_keypress
:
130 case GMEvent
.Type
.ev_keyrelease
:
131 if (auto kn
= ev
.id
in evKeyNames
) fname
= buildPath(dir
, "%s_%s.gma".format(cast(GMEvent
.Type
)etidx
, (*kn
).replace(" ", "_").toLower
));
132 else assert(0, "wtf key "~to
!string(ev
.id
));
134 case GMEvent
.Type
.ev_mouse
:
135 if (auto mn
= ev
.id
in evMouseNames
) fname
= buildPath(dir
, "%s_%s.gma".format(cast(GMEvent
.Type
)etidx
, (*mn
).replace(" ", "_").toLower
));
136 else assert(0, "wtf mouse "~to
!string(ev
.id
));
138 case GMEvent
.Type
.ev_other
:
139 if (auto on
= ev
.id
in evOtherNames
) fname
= buildPath(dir
, "%s_%s.gma".format(cast(GMEvent
.Type
)etidx
, (*on
).replace(" ", "_").toLower
));
140 else assert(0, "wtf other "~to
!string(ev
.id
));
142 case GMEvent
.Type
.ev_draw
:
144 fname
= buildPath(dir
, "%s.gma".format(cast(GMEvent
.Type
)etidx
));
146 case GMEvent
.Type
.ev_trigger
:
147 assert(0, "no triggers yet");
150 exportActions(gmk
, File(fname
, "w"), o
, eidx
, ev
, dir
);
156 void exportSprite (Gmk gmk
, GMSprite o
, string dir
) {
157 import std
.conv
: to
;
160 import std
.string
: format
, replace
;
162 try { mkdirRecurse(dir
); } catch (Exception
) {}
164 auto fo
= File(buildPath(dir
, "sprite.ini"), "w");
165 //fo.writeln("name=", o.name);
166 if (o
.xofs || o
.yofs
) fo
.writeln("ofs=", o
.xofs
, " ", o
.yofs
);
167 if (o
.shape
!= GMSprite
.Shape
.Rectangle
) fo
.writeln("shape=", o
.shape
);
168 if (o
.alphaTolerance
!= 0) fo
.writeln("alphaTolerance=", o
.alphaTolerance
);
169 fo
.writeln("separateCollisionMasks=", o
.separateCollisionMasks
);
170 if (o
.bboxType
!= GMSprite
.BBoxType
.Automatic
) fo
.writeln("bboxType=", o
.bboxType
);
171 fo
.writeln("bbox=", o
.bbleft
, " ", o
.bbtop
, " ", o
.bbright
, " ", o
.bbbottom
);
175 foreach (immutable iidx
, auto img
; o
.images
) {
176 writePng(buildPath(dir
, "image_%03s.png".format(iidx
)), img
);
181 void exportBg (Gmk gmk
, GMBackground o
, string dir
) {
182 import std
.conv
: to
;
185 import std
.string
: format
, replace
;
187 try { mkdirRecurse(dir
); } catch (Exception
) {}
189 auto fo
= File(buildPath(dir
, "sprite.ini"), "w");
190 //fo.writeln("name=", o.name);
192 fo
.writeln("tileset=true");
194 fo
.writeln("tileWidth=", o
.tileWidth
);
195 fo
.writeln("tileHeight=", o
.tileHeight
);
197 if (o
.xofs || o
.yofs
) fo
.writeln("ofs=", o
.xofs
, " ", o
.yofs
);
198 if (o
.xsep || o
.ysep
) fo
.writeln("sep=", o
.xsep
, " ", o
.ysep
);
202 writePng(buildPath(dir
, "image.png"), o
.image
);
206 void exportScript (Gmk gmk
, GMScript o
, string dir
) {
207 import std
.conv
: to
;
210 import std
.string
: format
, replace
;
212 try { mkdirRecurse(dir
.dirName
); } catch (Exception
) {}
213 auto fo
= File(dir
~".gml", "w");
214 string code
= o
.code
;
215 while (code
.length
&& code
[$-1] <= ' ') code
= code
[0..$-1];
217 foreach (string s
; code
.byLine
) {
218 //while (s.length && s[0] <= ' ') s = s[1..$];
219 while (s
.length
&& s
[$-1] <= ' ') s
= s
[0..$-1];
220 if (s
.length
== 0 && skip
) continue;
227 void exportRoom (Gmk gmk
, GMRoom o
, string dir
) {
228 import std
.conv
: to
;
231 import std
.string
: format
, replace
, strip
;
233 try { mkdirRecurse(dir
.dirName
); } catch (Exception
) {}
234 if (o
.createcode
.strip
.length
) {
235 auto fs
= File(dir
~".gml", "w");
236 string code
= o
.createcode
;
237 while (code
.length
&& code
[$-1] <= ' ') code
= code
[0..$-1];
239 foreach (string s
; code
.byLine
) {
240 //while (s.length && s[0] <= ' ') s = s[1..$];
241 while (s
.length
&& s
[$-1] <= ' ') s
= s
[0..$-1];
242 if (s
.length
== 0 && skip
) continue;
247 auto fo
= File(dir
~".gmr", "w");
248 if (o
.caption
.length
!= 0) fo
.writeln("caption=", o
.caption
.quote
);
249 fo
.writeln("width=", o
.width
);
250 fo
.writeln("height=", o
.height
);
251 fo
.writeln("speed=", o
.speed
);
252 fo
.writeln("persistent=", o
.persistent
);
253 if (o
.xsnap || o
.ysnap
) fo
.writeln("snap=", o
.xsnap
, " ", o
.ysnap
);
254 if (o
.isogrid
) fo
.writeln("isogrid=", o
.isogrid
);
255 fo
.writeln("drawbgcolor=", o
.drawbgcolor
);
256 fo
.writefln("bgcolor=$%08X", o
.bgcolor
);
257 fo
.writeln("viewsEnabled=", o
.viewsEnabled
);
258 fo
.writeln("tileWidth=", o
.tilew
);
259 fo
.writeln("tileHeight=", o
.tileh
);
260 if (o
.xtofs || o
.ytofs
) fo
.writeln("tileOfs=", o
.xtofs
, " ", o
.ytofs
);
261 if (o
.xtsep || o
.ytsep
) fo
.writeln("tileSep=", o
.xtsep
, " ", o
.ytsep
);
264 foreach (immutable idx
, ref bg
; o
.backs
) {
265 if (bg
.bgimageidx
< 0) continue;
267 fo
.writefln("back%s=%s", idx
, gmk
.bgByNum(bg
.bgimageidx
).name
);
268 fo
.writefln("back%s=%s %s", idx
, bg
.x
, bg
.y
);
269 fo
.writefln("back%s_visible=%s", idx
, bg
.visibleOnStart
);
270 if (bg
.fgimage
) fo
.writefln("back%s_foreground=%s", idx
, bg
.fgimage
);
271 fo
.writefln("back%s_tile=%s %s", idx
, bg
.xtile
, bg
.ytile
);
272 fo
.writefln("back%s_speed=%s %s", idx
, bg
.xspeed
, bg
.yspeed
);
273 if (bg
.stretch
) fo
.writefln("back%s_stretch=%s", idx
, bg
.stretch
);
281 * view2_visible=false
282 * view2_port=0 0 640 480
286 foreach (immutable idx
, ref v
; o
.views
) {
287 if (v
.x
== 0 && v
.y
== 0 &&
288 v
.width
== 640 && v
.height
== 480 &&
290 v
.portx
== 0 && v
.porty
== 0 && v
.portw
== v
.width
&& v
.porth
== v
.height
&&
291 v
.xborder
== 32 && v
.yborder
== 32 &&
292 v
.xspace
== -1 && v
.yspace
== -1)
298 fo
.writefln("view%s=%s %s", idx
, v
.x
, v
.y
);
299 fo
.writefln("view%s_width=%s", idx
, v
.width
);
300 fo
.writefln("view%s_height=%s", idx
, v
.height
);
301 fo
.writefln("view%s_visible=%s", idx
, v
.visibleOnStart
);
302 fo
.writefln("view%s_port=%s %s %s %s", idx
, v
.portx
, v
.porty
, v
.portw
, v
.porth
);
303 fo
.writefln("view%s_border=%s %s", idx
, v
.xborder
, v
.yborder
);
304 fo
.writefln("view%s_space=%s %s", idx
, v
.xspace
, v
.yspace
);
305 if (v
.objfollow
>= 0) fo
.writefln("view%s_follow=%s", idx
, gmk
.objByNum(v
.objfollow
).name
);
309 if (o
.tiles
.length
) {
311 foreach (immutable idx
, ref t
; o
.tiles
) {
313 fo
.writefln("tile%s=%s %s %s", idx
, gmk
.bgByNum(t
.bgidx
).name
, t
.x
, t
.y
);
314 fo
.writefln("tile%s_tilerc=%s %s %s %s", idx
, t
.xtile
, t
.ytile
, t
.wtile
, t
.htile
);
315 fo
.writefln("tile%s_layer=%s", idx
, t
.layer
);
316 //fo.writefln("tile%s_id=%s", idx, t.id); // starting from 10000000
317 if (t
.locked
) fo
.writefln("tile%s_locked=%s", idx
, t
.locked
);
321 if (o
.insts
.length
) {
323 foreach (immutable idx
, ref i
; o
.insts
) {
325 auto oo
= gmk
.objByNum(i
.objidx
);
327 fo
.writefln("inst%s=%s %s %s", idx
, gmk
.objByNum(i
.objidx
).name
, i
.x
, i
.y
);
328 //fo.writefln("inst%s_id=%s", idx, i.id); // starting from 100000
330 fo
.writefln("inst%s=%s %s %s", idx
, "<???>", i
.x
, i
.y
);
332 if (i
.locked
) fo
.writefln("inst%s_locked=%s", idx
, i
.locked
);
333 if (i
.createcode
.strip
.length
) assert(0);
339 void main (string
[] args
) {
340 import std
.path
: buildPath
;
341 auto gmk
= new Gmk(args
.length
> 1 ? args
[1] : "/home/ketmar/back/D/prj/spel/spelunky_collection/yasmk8/yasm_k8.gmk");
343 gmk
.forEachObject((o
) {
344 auto path
= gmk
.tree
.pathForName(GMResTree
.Node
.Type
.Object
, o
.name
);
346 writeln(o
.name
, " : ", path
);
347 gmk
.exportObject(o
, buildPath(undir
, path
));
349 assert(0, "object '"~o
.name
~"' has no path!");
354 gmk
.forEachSprite((o
) {
355 auto path
= gmk
.tree
.pathForName(GMResTree
.Node
.Type
.Sprite
, o
.name
);
357 writeln(o
.name
, " : ", path
);
358 gmk
.exportSprite(o
, buildPath(undir
, path
));
360 assert(0, "sprite '"~o
.name
~"' has no path!");
366 auto path
= gmk
.tree
.pathForName(GMResTree
.Node
.Type
.Background
, o
.name
);
368 writeln(o
.name
, " : ", path
);
369 gmk
.exportBg(o
, buildPath(undir
, path
));
371 assert(0, "background '"~o
.name
~"' has no path!");
376 gmk
.forEachScript((o
) {
377 auto path
= gmk
.tree
.pathForName(GMResTree
.Node
.Type
.Script
, o
.name
);
379 writeln(o
.name
, " : ", path
);
380 gmk
.exportScript(o
, buildPath(undir
, path
));
382 assert(0, "script '"~o
.name
~"' has no path!");
387 gmk
.forEachRoom((o
) {
388 auto path
= gmk
.tree
.pathForName(GMResTree
.Node
.Type
.Room
, o
.name
);
390 writeln(o
.name
, " : ", path
);
391 gmk
.exportRoom(o
, buildPath(undir
, path
));
393 assert(0, "room '"~o
.name
~"' has no path!");