switched to GPLv3 ONLY, because i don't trust FSF anymore
[gaemu.git] / ung.d
blobc6e26ac841fc7ade04aacafb3bff1dd52647a795
1 module ung is aliced;
3 import std.stdio;
5 import iv.vfs;
6 import iv.strex;
8 import gaem.ungmk;
10 import arsd.png;
13 string undir = "_src";
16 void exportActions (Gmk gmk, File fo, GMObject o, usize evidx, GMEvent ev, string dir) {
17 import std.conv : to;
18 import std.file;
19 import std.path;
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) {
33 // comment
34 fo.writeln("funcname=", act.funcname);
35 fo.writeln("codename=", act.codename);
36 continue;
38 switch (act.kind) {
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]));
55 fo.writeln;
56 break;
58 assert(0, "wtf?!");
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];
63 bool skip = true;
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;
68 skip = false;
69 fo.writeln(s);
71 break;
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]);
77 break;
78 default: assert(0, "invalid action type: '"~to!string(cast(GMAction.Kind)act.kind)~"'");
84 void exportObject (Gmk gmk, GMObject o, string dir) {
85 import std.conv : to;
86 import std.file;
87 import std.path;
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
105 string fname;
106 switch (etidx) {
107 case GMEvent.Type.ev_create:
108 assert(ev.id == 0);
109 fname = buildPath(dir, "%s.gma".format(cast(GMEvent.Type)etidx));
110 break;
111 case GMEvent.Type.ev_destroy:
112 assert(ev.id == 0);
113 fname = buildPath(dir, "%s.gma".format(cast(GMEvent.Type)etidx));
114 break;
115 case GMEvent.Type.ev_alarm:
116 assert(ev.id < 12);
117 fname = buildPath(dir, "%s_%02s.gma".format(cast(GMEvent.Type)etidx, ev.id));
118 break;
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));
123 else assert(0);
124 break;
125 case GMEvent.Type.ev_collision:
126 fname = buildPath(dir, "%s_with_%s.gma".format(cast(GMEvent.Type)etidx, gmk.objByNum(ev.id).name));
127 break;
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));
133 break;
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));
137 break;
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));
141 break;
142 case GMEvent.Type.ev_draw:
143 assert(ev.id == 0);
144 fname = buildPath(dir, "%s.gma".format(cast(GMEvent.Type)etidx));
145 break;
146 case GMEvent.Type.ev_trigger:
147 assert(0, "no triggers yet");
148 default: assert(0);
150 exportActions(gmk, File(fname, "w"), o, eidx, ev, dir);
156 void exportSprite (Gmk gmk, GMSprite o, string dir) {
157 import std.conv : to;
158 import std.file;
159 import std.path;
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);
174 // export images
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;
183 import std.file;
184 import std.path;
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);
191 if (o.tileset) {
192 fo.writeln("tileset=true");
193 // default: 16x16
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);
201 // export image
202 writePng(buildPath(dir, "image.png"), o.image);
206 void exportScript (Gmk gmk, GMScript o, string dir) {
207 import std.conv : to;
208 import std.file;
209 import std.path;
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];
216 bool skip = true;
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;
221 skip = false;
222 fo.writeln(s);
227 void exportRoom (Gmk gmk, GMRoom o, string dir) {
228 import std.conv : to;
229 import std.file;
230 import std.path;
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];
238 bool skip = true;
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;
243 skip = false;
244 fs.writeln(s);
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);
263 // backgrounds
264 foreach (immutable idx, ref bg; o.backs) {
265 if (bg.bgimageidx < 0) continue;
266 fo.writeln;
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);
276 // views
277 /* default:
278 * view2=0 0
279 * view2_width=640
280 * view2_height=480
281 * view2_visible=false
282 * view2_port=0 0 640 480
283 * view2_border=32 32
284 * view2_space=-1 -1
286 foreach (immutable idx, ref v; o.views) {
287 if (v.x == 0 && v.y == 0 &&
288 v.width == 640 && v.height == 480 &&
289 !v.visibleOnStart &&
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)
294 // skip defaults
295 continue;
297 fo.writeln;
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);
308 // tiles
309 if (o.tiles.length) {
310 fo.writeln;
311 foreach (immutable idx, ref t; o.tiles) {
312 fo.writeln;
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) {
322 fo.writeln;
323 foreach (immutable idx, ref i; o.insts) {
324 //fo.writeln;
325 auto oo = gmk.objByNum(i.objidx);
326 if (oo) {
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
329 } else {
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);
345 if (path.length) {
346 writeln(o.name, " : ", path);
347 gmk.exportObject(o, buildPath(undir, path));
348 } else {
349 assert(0, "object '"~o.name~"' has no path!");
351 return false;
354 gmk.forEachSprite((o) {
355 auto path = gmk.tree.pathForName(GMResTree.Node.Type.Sprite, o.name);
356 if (path.length) {
357 writeln(o.name, " : ", path);
358 gmk.exportSprite(o, buildPath(undir, path));
359 } else {
360 assert(0, "sprite '"~o.name~"' has no path!");
362 return false;
365 gmk.forEachBg((o) {
366 auto path = gmk.tree.pathForName(GMResTree.Node.Type.Background, o.name);
367 if (path.length) {
368 writeln(o.name, " : ", path);
369 gmk.exportBg(o, buildPath(undir, path));
370 } else {
371 assert(0, "background '"~o.name~"' has no path!");
373 return false;
376 gmk.forEachScript((o) {
377 auto path = gmk.tree.pathForName(GMResTree.Node.Type.Script, o.name);
378 if (path.length) {
379 writeln(o.name, " : ", path);
380 gmk.exportScript(o, buildPath(undir, path));
381 } else {
382 assert(0, "script '"~o.name~"' has no path!");
384 return false;
387 gmk.forEachRoom((o) {
388 auto path = gmk.tree.pathForName(GMResTree.Node.Type.Room, o.name);
389 if (path.length) {
390 writeln(o.name, " : ", path);
391 gmk.exportRoom(o, buildPath(undir, path));
392 } else {
393 assert(0, "room '"~o.name~"' has no path!");
395 return false;