thing y output fix
[dd2d.git] / d2dactors.d
blob7b874d48b9925283d8ad6e955360d528439ef766
1 module d2dactors is aliced;
2 private:
4 import arsd.color;
6 import glutils;
7 import console;
8 import wadarc;
10 import d2dmap;
11 import d2dtpl;
14 // ////////////////////////////////////////////////////////////////////////// //
15 public class Actor {
16 ThingTemplate tpl;
17 bool dead;
19 //obj_t o;
20 int x, y; // coords
21 int xv, yv; // current velocity
22 int vx, vy; // desired velocity (usually)
23 int radius;
24 int height; // radius, height
26 // monster fields
27 ubyte t, d, st, ftime;
28 int fobj;
29 int s; // for item too
30 //const char *ap;
31 int aim, life, pain, ac, tx, ty, ammo;
32 short atm;
34 // action script
35 ActionScript acs; // just a cache; NEVER change this!
36 string state;
37 int pc;
38 int framesLeft; // # of frames left before next state
39 ImgSprite frame; // can be null
41 // future API
42 // snapSave, snapLoad
44 void acsSetState (string astate) {
45 state = astate;
46 pc = acs.getLabelId(astate);
49 void acsRemove () {
50 dead = true; // mark as dead, so game gc will collect it
51 frame = null;
54 void doAcsTick () {
55 if (framesLeft > 0) { --framesLeft; return; }
56 if (acs is null) { acsRemove(); return; }
57 while (framesLeft <= 0) {
58 if (pc < 0 || pc >= acs.actions.length) { acsRemove(); return; }
59 auto act = acs.actions.ptr[pc++];
60 if (auto a = cast(AnimActionRemove)act) {
61 acsRemove();
62 return;
64 framesLeft = act.len;
65 // sprite
66 if (auto a = cast(AnimActionSpr)act) {
67 frame = findSprite(tpl.base, a.spr);
68 continue;
70 // goto
71 if (auto a = cast(AnimActionJump)act) {
72 pc = a.dest;
73 continue;
75 // setstate
76 if (auto a = cast(AnimActionJumpState)act) {
77 pc = a.dest;
78 state = a.stname;
79 continue;
86 // ////////////////////////////////////////////////////////////////////////// //
87 public class ImgSprite {
88 D2DImage vga;
89 Texture tex;
91 string name; // full disk name
95 // ////////////////////////////////////////////////////////////////////////// //
96 public __gshared ImgSprite[string] sprites;
97 public __gshared Actor[] actors;
100 // ////////////////////////////////////////////////////////////////////////// //
101 char[] buildCacheName (char[] buf, const(char)[] path, const(char)[] name=null) nothrow @safe @nogc {
102 usize pos = 0;
103 if (path.length && name.length) {
104 buf[0..path.length] = path[];
105 pos = path.length;
106 if (path[$-1] != '/') buf[pos++] = '/';
107 buf[pos..pos+name.length] = name[];
108 pos += name.length;
109 } else if (path.length) {
110 buf[0..path.length] = path[];
111 pos = path.length;
112 } else if (name.length) {
113 buf[0..name.length] = name[];
114 pos = name.length;
116 return buf[0..pos];
120 void cacheSprite (string path, string name=null) {
121 if (path.length+name.length+5 > 256) throw new Exception("sprite name too long");
122 char[256] namebuf = void;
123 auto nm = buildCacheName(namebuf, path, name);
124 if (nm in sprites) return;
125 conwriteln("precaching '", nm, ".vga'...");
126 auto snm = nm.idup;
127 D2DImage img;
128 try {
129 img = new D2DImage(snm~"0.vga");
130 } catch (Exception) {
131 try {
132 img = new D2DImage(snm~"1.vga");
133 } catch (Exception) {
134 img = new D2DImage(snm~"1"~snm[$-1]~"2.vga");
137 //conwriteln(" sx=", img.sx, "; sy=", img.sy);
138 auto spr = new ImgSprite();
139 spr.vga = img;
140 spr.tex = new Texture(spr.vga.asTCImage, Texture.Option.Nearest);
141 spr.name = snm;
142 sprites[snm] = spr;
146 void cacheSpritesForActor (Actor actor) {
147 if (actor is null || actor.acs is null) return;
148 foreach (auto act; actor.acs.actions) {
149 if (auto sp = cast(AnimActionSpr)act) {
150 if (sp.spr.length == 0) continue;
151 cacheSprite(actor.tpl.base, sp.spr);
157 ImgSprite findSprite (string path, string name=null) nothrow @nogc {
158 if (path.length+name.length+5 > 256) return null;
159 char[256] namebuf = void;
160 auto nm = buildCacheName(namebuf, path, name);
161 if (auto sp = nm in sprites) return *sp;
162 return null;
166 // ////////////////////////////////////////////////////////////////////////// //
167 public void initActors (LevelMap map) {
168 actors = null;
169 foreach (ref tg; map.things) {
170 auto act = new Actor();
171 act.x = tg.x;
172 act.y = tg.y;
173 if (tg.type >= ThingId.FirstMonster && tg.type <= ThingId.LastMonster) {
174 act.tpl = monTpls[tg.type-ThingId.FirstMonster];
175 } else if (tg.type >= ThingId.FirstItem && tg.type <= ThingId.LastItem) {
177 if (act.tpl is null) continue;
178 act.radius = act.tpl.radius;
179 act.height = act.tpl.height;
180 act.acs = act.tpl.acs;
181 act.acsSetState("sleep");
182 cacheSpritesForActor(act);
183 actors ~= act;
188 public void doActorTick (Actor actor, LevelMap map) {
189 if (actor is null) return;
190 if (actor.dead) return;
191 actor.doAcsTick();
195 public void doAllActorTicks (LevelMap map) {
196 foreach (auto actor; actors) doActorTick(actor, map);