History

convert ai from old state machine to new behavior trees

mischief committed 9 years ago

Commit ef328b71 parent ad3734d11 files · +421 −356Browse files

Unified · Split

11 files
  1. ai.c +358 −274
  2. dat.h +10 −23
  3. hack9.c +5 −4
  4. item.c +3 −0
  5. level.c +5 −2
  6. levelgen.c +10 −5
  7. monst.c +7 −45
  8. path.c +3 −0
  9. tile.c +3 −0
  10. ui.c +14 −3
  11. util.c +3 −0
ai.c+358−274
@@ -3,360 +3,444 @@ · 2 unmodified lines
3#include <draw.h>3#include <draw.h>
4#include <thread.h>4#include <thread.h>
5 5
6#include "bt.h"
7#include "map.h"
8
6#include "dat.h"9#include "dat.h"
7#include "alg.h"10#include "alg.h"
8 11
9AIState*
10mkstate(char *name, Monster *m, void *aux, AIFun enter, AIFun exec, AIFun exit)
11{
12 AIState *i;
13 i = mallocz(sizeof(AIState), 1);
14 assert(i != nil);
15 snprint(i->name, sizeof(i->name), "%s", name);
16 i->m = m;
17 i->aux = aux;
18 i->enter = enter;
19 i->exec = exec;
20 i->exit = exit;
21 return i;
22}
23
24void
25freestate(AIState *a)
26{
27 free(a);
28}
29
30enum12enum
31{13{
32 IDLERADIUS = 4,14 IDLERADIUS = 6,
33 IDLEIDLE = 4,15 IDLEIDLE = 4,
34};16};
35 17
36typedef struct idledata idledata;18enum
37struct idledata
38{19{
39 int idle;20 AIPOINT = 0,
40 int attacking;21 AIINT,
22 AIMONST,
23 AIPATH,
24 AIWALKTO,
41};25};
42 26
43static void27typedef struct AiData AiData;
44idleenter(AIState *a)28struct AiData
45{29{
46 idledata *d;30 u32int type;
47 d = mallocz(sizeof(idledata), 1);31 union {
48 assert(d != nil);32 int i;
49 a->aux = d;33 Point pt;
50 d->idle = nrand(IDLEIDLE);34 Monster *m;
51}35 Point *path;
36 WalkToData *wd;
37 };
38};
52 39
53static void40static void
54idleexec(AIState *a)41aivfree(void *v)
55{42{
56 idledata *d;43 AiData *d;
57 Monster *m, *mt;
58 int i, r, xd, yd, xs, ys, npath;
59 Point c, p, s, *path;
60 d = a->aux;
61 m = a->m;
62
63 if(m->ai == nil)
64 d->idle++;
65
66 if(d->idle > IDLEIDLE){
67 mpushstate(m, wander(m));
68 d->idle = 0;
69 return;
70 }
71 44
72 if(m->ai == nil)45 d = v;
73 d->attacking = 0;46
74 if(d->attacking != 0)47 if(d == nil)
75 return;48 return;
76 49
77 /* find something to attack */50 switch(d->type){
78 r = 8;51 case AIMONST:
79 c = m->pt;52 mfree(d->m);
80 for(p.x = c.x; p.x >= c.x - r; p.x--){53 break;
81 for(p.y = c.y; p.y >= c.y - r; p.y--){54 case AIPATH:
82 if(eqpt(p, c))55 free(d->path);
83 continue;56 break;
84 xd = p.x - c.x;57 case AIWALKTO:
85 yd = p.y - c.y;58 free(d->wd->path);
86 if(xd*xd+yd*yd <= r*r){59 free(d->wd);
87 xs = c.x - xd;60 break;
88 ys = c.y - yd;
89
90 Point pts[] = { p, Pt(p.x, ys), Pt(xs, p.y), Pt(xs, ys) };
91 shuffle(pts, 4, sizeof(Point));
92 for(i = 0; i < 4; i++){
93 s = pts[i];
94 if(!ptinrect(s, m->l->r))
95 continue;
96 if(hasflagat(m->l, s, Fhasmonster)){
97 mt = tileat(m->l, s)->monst;
98 /* BUG: should not be nil. */
99 if(mt == nil)
100 continue;
101 if(abs(m->align - mt->align) > 15){
102 if(manhattan(m->pt, s) != ORTHOCOST){
103 npath = pathfind(m->l, m->pt, s, &path, Fblocked);
104 if(npath < 0)
105 continue;
106 if(npath > r*2){
107 free(path);
108 continue;
109 }
110 free(path);
111 }
112 d->attacking = 1;
113 mpushstate(m, attack(m, mt));
114 return;
115 }
116 }
117 }
118 }
119 }
120 }61 }
62
63 free(d);
121}64}
122 65
123static void66static AiData*
124idleexit(AIState *a)67aidata(u32int typ)
125{68{
126 free(a->aux);69 AiData *d = emalloc(sizeof(AiData));
70 d->type = typ;
71 return d;
127}72}
128 73
129void74AiData*
130idle(Monster *m)75aipt(Point pt)
76{
77 AiData *d = aidata(AIPOINT);
78 d->pt = pt;
79 return d;
80}
81
82AiData*
83aiint(int i)
84{
85 AiData *d = aidata(AIINT);
86 d->i = i;
87 return d;
88}
89
90AiData*
91aimonst(Monster *m)
92{
93 AiData *d = aidata(AIMONST);
94 d->m = m;
95 return d;
96}
97
98AiData*
99aipath(Point *path)
100{
101 AiData *d = aidata(AIPATH);
102 d->path = path;
103 return d;
104}
105
106AiData*
107aiwd(WalkToData *wd)
131{108{
132 AIState *i;109 AiData *d = aidata(AIWALKTO);
133 i = mkstate("idle", m, nil, idleenter, idleexec, idleexit);110 d->wd = wd;
134 i->enter(i);111 return d;
135 m->aglobal = i;
136}112}
137 113
138static void114static void
139wanderexec(AIState *a)115OOM(void)
116{
117 sysfatal("ai: %r");
118}
119
120static int
121wander(void *v)
140{122{
141 int try;123 int try;
142 Point p;124 Point p;
143 Monster *m;125 Monster *m;
144 AIState *ai;126 AiData *pt, *in;
145 m = a->m;
146 127
147 if(a->aux != nil){128 m = v;
148leave:
149 ai = mpopstate(m);
150 freestate(ai);
151 return;
152 }
153 129
154 try = 0;130 for(try = 0; try < 5; try++){
155 do {
156 p = addpt(m->pt, Pt(nrand(IDLERADIUS*2+1)-IDLERADIUS, nrand(IDLERADIUS*2+1)-IDLERADIUS));131 p = addpt(m->pt, Pt(nrand(IDLERADIUS*2+1)-IDLERADIUS, nrand(IDLERADIUS*2+1)-IDLERADIUS));
157 if(try++ > 10)
158 goto leave;
159 } while(!ptinrect(p, m->l->r) || hasflagat(m->l, p, Fblocked) || manhattan(m->pt, p) < ORTHOCOST*2);
160 132
161 mpushstate(m, walkto(m, p, 1));133 if(ptinrect(p, m->l->r) &&
162 a->aux=a;134 !hasflagat(m->l, p, Fblocked|Fhasmonster) &&
163}135 manhattan(m->pt, p) >= ORTHOCOST*2)
136 break;
137 }
164 138
165AIState*139 if(try == 5)
166wander(Monster *m)140 return TASKFAIL;
167{141
168 AIState *i;142 pt = aipt(p);
169 i = mkstate("wander", m, nil, nil, wanderexec, nil);143 in = aiint(0);
170 return i;144
145 if(mapset(m->bb, "wander_dst", pt) < 0)
146 OOM();
147
148 if(mapset(m->bb, "wander_offset", in) < 0)
149 OOM();
150
151 return TASKSUCCESS;
171}152}
172 153
173typedef struct walktodata walktodata;154static WalkToData*
174struct walktodata155planpathcalc(Monster *m, Point dst, int offset)
175{156{
176 Point dst;
177 Point last;
178 int npath;157 int npath;
179 int next;
180 Point *path;158 Point *path;
181 int wait;159 WalkToData *wd;
182 int blocked;160
183};161 npath = pathfind(m->l, m->pt, dst, &path, Fhasmonster|Fblocked);
162 if(npath < 0)
163 return nil;
164
165 wd = emalloc(sizeof(WalkToData));
166 wd->next = 1;
167 wd->npath = npath - offset;
168 wd->path = path;
169
170 return wd;
171}
184 172
185static int173static int
186walktoinner(AIState *a)174planpathkey(Monster *m, char *dst, char *offset, char *data)
187{175{
188 Point p;176 WalkToData *wd;
189 walktodata *d;177 AiData *dd, *doff;
190 Monster *m;
191 d = a->aux;
192 m = a->m;
193 178
194 /* d->last might not equal m->pt if some other179 dd = mapget(m->bb, dst);
195 * state pre-empted us, like attack */180 doff = mapget(m->bb, offset);
196 if(!eqpt(d->last, m->pt) || d->blocked > d->wait){
197 goto cleanup;
198 }
199 181
200 //dbg("%s path -> %P %d/%d", m->md->name, d->dst, d->next, d->npath);182 wd = planpathcalc(m, dd->pt, doff->i);
201 if(d->path == nil){183 if(wd == nil)
202 /* plan route */184 return TASKFAIL;
203 d->npath = pathfind(m->l, m->pt, d->dst, &d->path, Fhasmonster|Fblocked);
204 d->next = 1;
205 if(d->npath < 0){
206 if(d->wait > 0){
207 //dbg("%s route to %P blocked; routing through monsters", m->md->name, d->dst);
208 /* path not through monsters available? */
209 d->npath = pathfind(m->l, m->pt, d->dst, &d->path, Fblocked);
210 d->next = 1;
211 if(d->npath < 0){
212 d->blocked++;
213 return 0;
214 }
215 }
216 }
217 }
218 185
219 if(d->next == d->npath){186 if(mapset(m->bb, data, aiwd(wd)) < 0)
220 goto cleanup;187 OOM();
221 }
222 188
223 p = d->path[d->next];189 return TASKSUCCESS;
224 //dbg("next %P %06b", p, flagat(m->l, p));190}
225 191
226 if(hasflagat(m->l, p, Fhasmonster|Fblocked)){192static int
227 d->blocked++;193planpathwander(void *v)
228 dbg("%s blocked %d/%d", m->md->name, d->blocked, d->wait);194{
229 return 0;195 Monster *m;
230 }
231 196
232 d->blocked = 0;197 m = v;
233 d->next++;
234 198
235 maction(m, MMOVE, p);199 return planpathkey(m, "wander_dst", "wander_offset", "wander_data");
236 d->last = p;
237 return 0;
238cleanup:
239 free(d->path);
240 d->path = nil;
241 d->npath = 0;
242 d->blocked = 0;
243 return -1;
244}200}
245 201
246static void202static int
247walktoexec(AIState *a)203planpathattack(void *v)
248{204{
249 Monster *m;205 Monster *m;
250 m = a->m;
251 206
252 if(walktoinner(a) < 0){207 m = v;
253 a = mpopstate(m);208
254 freestate(a);209 return planpathkey(m, "attack_dst", "attack_offset", "attack_data");
255 return;
256 }
257}210}
258 211
259static void212static int
260walktoexit(AIState *a)213walktoinner(Monster *m, char *data)
261{214{
262 walktodata *d;215 Point np;
263 d = a->aux;216 WalkToData *wd;
264 if(d->path != nil)217 AiData *dwd;
265 free(d->path);218
266 free(d);219 dwd = mapget(m->bb, data);
220 assert(dwd != nil);
221
222 wd = dwd->wd;
223
224 if(wd->next == wd->npath)
225 return TASKSUCCESS;
226
227 np = wd->path[wd->next++];
228
229 /* could just call maction(m,MMOVE,np) but
230 * this prevents friendly fire
231 */
232 if(hasflagat(m->l, np, Fhasmonster|Fblocked))
233 return TASKFAIL;
234
235 int rv = maction(m, MMOVE, np);
236 if(rv != 1)
237 return TASKFAIL;
238
239 return TASKRUNNING;
267}240}
268 241
269AIState*242static int
270walkto(Monster *m, Point p, int wait)243walktowander(void *v)
271{244{
272 walktodata *d;245 Monster *m;
273 AIState *i;246
274 d = mallocz(sizeof(*d), 1);247 m = v;
275 d->dst = p;248
276 d->last = m->pt;249 return walktoinner(m, "wander_data");
277 d->wait = wait;
278 assert(d != nil);
279 i = mkstate("walk", m, d, nil, walktoexec, walktoexit);
280 return i;
281}250}
282 251
283typedef struct attackdata attackdata;252static int
284struct attackdata253walktoattack(void *v)
285{254{
286 Monster *mt;255 Monster *m;
287 Point last;256 m = v;
288 AIState *w;257 return walktoinner(m, "attack_data");
289 walktodata *wd;258}
259
260enum {
261 ATTACKRADIUS = 6,
290};262};
291 263
292static void264static int
293attackenter(AIState *a)265checkenemy(Monster *m, Monster *target)
294{266{
295 attackdata *d;267 if(m == target)
296 d = a->aux;268 return -1;
297 if(d->w->enter != nil)269 if(target->flags & Mdead)
298 d->w->enter(d->w);270 return -1;
271 if(abs(m->align - target->align) <= 15)
272 return -1;
273 return 0;
299}274}
300 275
301static void276static int
302attackexec(AIState *a)277findenemy(void *v)
303{278{
304 int n;279 int i, r, xd, yd, xs, ys;
305 attackdata *d;280 Point c, p, s;
306 Monster *m, *mt;281 Tile *t;
307 m = a->m;282 Monster *m, *target;
308 d = a->aux;283 AiData *dtgt;
309 mt = d->mt;284
310 285 m = v;
311 n = manhattan(m->pt, mt->pt);286 c = m->pt;
312 if(mt->flags & Mdead || n > ORTHOCOST*8 ){287
313 /* stop the chase */288 r = ATTACKRADIUS;
314 a = mpopstate(m);289
315 freestate(a);290 target = nil;
316 return;291
317 } else if(n > ORTHOCOST){292 /* check if we already have a target */
318 /* walk to target */293 dtgt = mapget(m->bb, "attack_target");
319 if(!eqpt(mt->pt, d->last)){294 if(dtgt != nil)
320 d->wd->dst = mt->pt;295 target = dtgt->m;
321 }296
322 d->wd->wait = 2;297 if(target != nil && checkenemy(m, target) == 0)
323 d->wd->last = m->pt;298 return TASKSUCCESS;
324 if(walktoinner(d->w) < 0){299
325 a = mpopstate(m);300 for(p.x = c.x; p.x >= c.x - r; p.x--){
326 freestate(a);301 for(p.y = c.y; p.y >= c.y - r; p.y--){
327 return;302 xd = p.x - c.x;
303 yd = p.y - c.y;
304
305 /* skip points outside circle */
306 if(xd*xd+yd*yd > r*r)
307 continue;
308
309 xs = c.x - xd;
310 ys = c.y - yd;
311
312 Point pts[] = { p, Pt(p.x, ys), Pt(xs, p.y), Pt(xs, ys) };
313 shuffle(pts, 4, sizeof(Point));
314 for(i = 0; i < 4; i++){
315 s = pts[i];
316
317 if(!ptinrect(s, m->l->r))
318 continue;
319 if(!hasflagat(m->l, s, Fhasmonster))
320 continue;
321
322 t = tileat(m->l, s);
323 target = t->monst;
324
325 if(checkenemy(m, target) != 0)
326 continue;
327
328 //fprint(2, "FINDENEMY: %s %P\n", target->md->name, target->pt);
329
330 /* found a suitable target */
331 incref(&target->ref);
332 if(mapset(m->bb, "attack_target", aimonst(target)) < 0)
333 OOM();
334
335 return TASKSUCCESS;
336 }
328 }337 }
329 d->last = mt->pt;
330 } else {
331 /* attack! */
332 maction(m, MMOVE, mt->pt);
333 }338 }
339
340 return TASKFAIL;
334}341}
335 342
336static void343static int
337attackexit(AIState *a)344targetenemy(void *v)
338{345{
339 attackdata *d;346 Monster *m;
340 d = a->aux;347 AiData *dtgt, *dst, *off;
341 348
342 if(d->w->exit != nil)349 m = v;
343 d->w->exit(d->w);350
344 freestate(d->w);351 dtgt = mapget(m->bb, "attack_target");
345 mfree(d->mt);352 if(dtgt == nil)
346 free(d);353 return TASKFAIL;
354
355 dst = aipt(dtgt->m->pt);
356 off = aiint(1);
357
358 if(mapset(m->bb, "attack_dst", dst) < 0)
359 OOM();
360
361 if(mapset(m->bb, "attack_offset", off) < 0)
362 OOM();
363
364 return TASKSUCCESS;
365}
366
367static int
368attackenemy(void *v)
369{
370 Monster *m, *target;
371 AiData *dtgt;
372 m = v;
373
374 dtgt = mapget(m->bb, "attack_target");
375 assert(dtgt != nil);
376
377 target = dtgt->m;
378
379 /* monster has moved */
380 if(manhattan(m->pt, target->pt) > ORTHOCOST)
381 return TASKFAIL;
382
383 /* hit the enemy */
384 if(maction(m, MMOVE, target->pt) != 0)
385 return TASKFAIL;
386
387 if(target->flags & Mdead)
388 return TASKSUCCESS;
389
390 return TASKRUNNING;
391}
392
393static BehaviorNode*
394bnidle(void)
395{
396 BehaviorNode *bnwfind, *bnplanpath, *bnwalkto;
397
398 bnwfind = btleaf("wander find", wander);
399 bnplanpath = btleaf("wander plan path", planpathwander);
400 bnwalkto = btleaf("wander move", walktowander);
401
402 btsetguard(bnwalkto, bnplanpath);
403 btsetguard(bnplanpath, bnwfind);
404
405 return bnwalkto;
347}406}
348 407
349AIState*408static BehaviorNode*
350attack(Monster *m, Monster *targ)409bnattack(void)
351{410{
352 attackdata *d;411 BehaviorNode *bnfind, *bntarget;
353 AIState *i;412 BehaviorNode *bnplanpath, *bnmove, *bnhit;
354 d = mallocz(sizeof(*d), 1);413 BehaviorNode *bnatk;
355 incref(&targ->ref);414
356 d->mt = targ;415 bnfind = btleaf("find enemy", findenemy);
357 d->wd = mallocz(sizeof(walktodata), 1);416
358 d->w = mkstate("chase", m, d->wd, nil, nil, walktoexit);417 bntarget = btleaf("target enemy", targetenemy);
359 i = mkstate("attack", m, d, attackenter, attackexec, attackexit);418 bnplanpath = btleaf("attack plan path", planpathattack);
360 return i;419 bnmove = btleaf("move to enemy", walktoattack);
420 bnhit = btleaf("hit enemy", attackenemy);
421
422 bnatk = btsequence("attack", bnplanpath, bnmove, bnhit, nil);
423 btsetguard(bnatk, bntarget);
424 btsetguard(bntarget, bnfind);
425
426 return bnatk;
361}427}
362 428
429void
430idle(Monster *m)
431{
432 Map *map;
433 BehaviorNode *root;
434
435 map = mapnew(aivfree);
436 if(map == nil)
437 OOM();
438
439 root = btdynguard("root", bnattack(), bnidle(), nil);
440
441 if(root == nil)
442 OOM();
443
444 m->bt = root;
445 m->bb = map;
446}
dat.h+10−23
@@ -1,4 +1,3 @@
1typedef struct AIState AIState;
2typedef struct EquipData EquipData;1typedef struct EquipData EquipData;
3typedef struct ItemData ItemData;2typedef struct ItemData ItemData;
4typedef struct Item Item;3typedef struct Item Item;
@@ -39,26 +38,15 @@ extern long turn; · 34 unmodified lines
39int isyou(Monster *m);38int isyou(Monster *m);
40int nearyou(Point p);39int nearyou(Point p);
41 40
42typedef void (*AIFun)(AIState *);41typedef struct WalkToData WalkToData;
43 42struct WalkToData {
44struct AIState43 int next;
45{44 int npath;
46 AIState *prev;45 Point *path;
47 char name[16];
48 Monster *m;
49 void *aux;
50 AIFun enter;
51 AIFun exec;
52 AIFun exit;
53};46};
54 47
55/* ai.c */48/* ai.c */
56AIState *mkstate(char *name, Monster *m, void *aux, AIFun enter, AIFun exec, AIFun exit);
57void freestate(AIState *a);
58void idle(Monster *m);49void idle(Monster *m);
59AIState* wander(Monster *m);
60AIState* walkto(Monster *m, Point p, int wait);
61AIState* attack(Monster *m, Monster *targ);
62 50
63enum51enum
64{52{
@@ -258,8 +246,8 @@ struct Monster · 193 unmodified lines
258 u32int flags;246 u32int flags;
259 247
260 /* ai state */248 /* ai state */
261 AIState *ai;249 BehaviorNode *bt;
262 AIState *aglobal;250 Map *bb;
263 251
264 /* inventory */252 /* inventory */
265 ItemList inv;253 ItemList inv;
@@ -277,8 +265,6 @@ MonsterData *mdbyname(char *monster); · 11 unmodified lines
277Monster *mbyname(char *monster);265Monster *mbyname(char *monster);
278void mfree(Monster *m);266void mfree(Monster *m);
279int mupdate(Monster *m);267int mupdate(Monster *m);
280void mpushstate(Monster *m, AIState *a);
281AIState *mpopstate(Monster *m);
282int maction(Monster *m, int what, Point where);268int maction(Monster *m, int what, Point where);
283int mwield(Monster *m, int n);269int mwield(Monster *m, int n);
284int munwield(Monster *m, int type);270int munwield(Monster *m, int type);
@@ -385,7 +371,7 @@ struct Level · 100 unmodified lines
385 Point up;371 Point up;
386 Point down;372 Point down;
387 373
388 AIState *ai;374 BehaviorNode *bt;
389 375
390 int nspawns;376 int nspawns;
391 Spawn spawns[10];377 Spawn spawns[10];
@@ -429,7 +415,8 @@ void warn(char *fmt, ...); · 37 unmodified lines
429void bad(char *fmt, ...);415void bad(char *fmt, ...);
430void dbg(char *fmt, ...);416void dbg(char *fmt, ...);
431void uiinit(char *name);417void uiinit(char *name);
432void uiexec(AIState *ai);418void uirun(void);
419int uibt(void *a);
433void uiredraw(int justui);420void uiredraw(int justui);
434 421
435/* util.c */422/* util.c */
hack9.c+5−4
@@ -3,6 +3,9 @@ · 2 unmodified lines
3#include <thread.h>3#include <thread.h>
4#include <draw.h>4#include <draw.h>
5 5
6#include "map.h"
7#include "bt.h"
8
6#include "dat.h"9#include "dat.h"
7#include "alg.h"10#include "alg.h"
8 11
@@ -67,8 +70,7 @@ movemons(void) · 58 unmodified lines
67 l = player->l;70 l = player->l;
68 71
69 /* run ai on level, for spawns etc */72 /* run ai on level, for spawns etc */
70 if(l->ai != nil && l->ai->exec != nil)73 bttick(l->bt, l);
71 l->ai->exec(l->ai);
72 74
73 for(p.x = 0; p.x < l->width; p.x++){75 for(p.x = 0; p.x < l->width; p.x++){
74 for(p.y = 0; p.y < l->height; p.y++){76 for(p.y = 0; p.y < l->height; p.y++){
@@ -166,7 +168,7 @@ threadmain(int argc, char *argv[]) · 91 unmodified lines
166 t->monst = player;168 t->monst = player;
167 setflagat(level, player->pt, Fhasmonster);169 setflagat(level, player->pt, Fhasmonster);
168 170
169 player->ai = mkstate("input", player, nil, nil, uiexec, nil);171 player->bt = btleaf("input", uibt);
170 172
171 if(debug > 0){173 if(debug > 0){
172 player->hp = 500;174 player->hp = 500;
@@ -180,4 +182,3 @@ threadmain(int argc, char *argv[]) · 7 unmodified lines
180 movemons();182 movemons();
181 }183 }
182}184}
183
item.c+3−0
@@ -5,6 +5,9 @@ · 4 unmodified lines
5#include <bio.h>5#include <bio.h>
6#include <ndb.h>6#include <ndb.h>
7 7
8#include "map.h"
9#include "bt.h"
10
8#include "dat.h"11#include "dat.h"
9 12
10enum13enum
level.c+5−2
@@ -3,6 +3,9 @@ · 2 unmodified lines
3#include <draw.h>3#include <draw.h>
4#include <thread.h>4#include <thread.h>
5 5
6#include "map.h"
7#include "bt.h"
8
6#include "dat.h"9#include "dat.h"
7#include "alg.h"10#include "alg.h"
8 11
@@ -103,6 +106,8 @@ freelevel(Level *l) · 94 unmodified lines
103 Point p;106 Point p;
104 Tile *t;107 Tile *t;
105 108
109 btfree(l->bt, l);
110
106 for(x = 0; x < l->width; x++){111 for(x = 0; x < l->width; x++){
107 for(y = 0; y < l->height; y++){112 for(y = 0; y < l->height; y++){
108 p = (Point){x, y};113 p = (Point){x, y};
@@ -119,8 +124,6 @@ freelevel(Level *l) · 10 unmodified lines
119 124
120 free(l->tiles);125 free(l->tiles);
121 free(l->flags);126 free(l->flags);
122 if(l->ai != nil)
123 freestate(l->ai);
124 free(l);127 free(l);
125}128}
126 129
levelgen.c+10−5
@@ -3,6 +3,9 @@ · 2 unmodified lines
3#include <draw.h>3#include <draw.h>
4#include <thread.h>4#include <thread.h>
5 5
6#include "map.h"
7#include "bt.h"
8
6#include "dat.h"9#include "dat.h"
7#include "alg.h"10#include "alg.h"
8 11
@@ -246,8 +249,8 @@ genmonsters(Level *l, char *type, int count) · 237 unmodified lines
246 }249 }
247}250}
248 251
249static void252static int
250levelexec(AIState *a)253levelexec(void *v)
251{254{
252 int i, j, n;255 int i, j, n;
253 Point p, np, *neigh;256 Point p, np, *neigh;
@@ -258,7 +261,7 @@ levelexec(AIState *a) · 4 unmodified lines
258 Monster *m;261 Monster *m;
259 Item *it;262 Item *it;
260 263
261 l = a->aux;264 l = v;
262 265
263 for(i = 0; i < l->nspawns; i++){266 for(i = 0; i < l->nspawns; i++){
264 sp = &l->spawns[i];267 sp = &l->spawns[i];
@@ -305,6 +308,8 @@ levelexec(AIState *a) · 40 unmodified lines
305 }308 }
306 }309 }
307 }310 }
311
312 return TASKSUCCESS;
308}313}
309 314
310Level*315Level*
@@ -331,8 +336,8 @@ mklevel(int width, int height, int floor) · 20 unmodified lines
331 if(l->flags == nil)336 if(l->flags == nil)
332 goto err1;337 goto err1;
333 338
334 l->ai = mkstate("level", nil, l, nil, levelexec, nil);339 l->bt = btleaf("level", levelexec);
335 if(l->ai == nil)340 if(l->bt == nil)
336 goto err2;341 goto err2;
337 342
338 for(p.x = 0; p.x < width; p.x++){343 for(p.x = 0; p.x < width; p.x++){
monst.c+7−45
@@ -5,6 +5,9 @@ · 4 unmodified lines
5#include <bio.h>5#include <bio.h>
6#include <ndb.h>6#include <ndb.h>
7 7
8#include "map.h"
9#include "bt.h"
10
8#include "dat.h"11#include "dat.h"
9 12
10enum13enum
@@ -207,20 +210,12 @@ void · 196 unmodified lines
207mfree(Monster *m)210mfree(Monster *m)
208{211{
209 int n;212 int n;
210 AIState *a;
211 213
212 if(decref(&m->ref) != 0)214 if(decref(&m->ref) != 0)
213 return;215 return;
214 216
215 if(m->aglobal != nil){217 btfree(m->bt, m);
216 if(m->aglobal->exit != nil)218 mapfree(m->bb);
217 m->aglobal->exit(m->aglobal);
218 freestate(m->aglobal);
219 }
220 if(m->ai != nil){
221 while((a = mpopstate(m)) != nil)
222 freestate(a);
223 }
224 219
225 for(n = 0; n < NEQUIP; n++){220 for(n = 0; n < NEQUIP; n++){
226 if(m->armor[n] != nil){221 if(m->armor[n] != nil){
@@ -230,6 +225,7 @@ mfree(Monster *m) · 3 unmodified lines
230 225
231 ilfree(&m->inv);226 ilfree(&m->inv);
232 227
228 memset(m, 0, sizeof(Monster));
233 free(m);229 free(m);
234}230}
235 231
@@ -239,15 +235,7 @@ mupdate(Monster *m) · 3 unmodified lines
239 m->mvp += m->mvr;235 m->mvp += m->mvr;
240 236
241 while(m->mvp > 12){237 while(m->mvp > 12){
242 if(m->aglobal != nil)238 bttick(m->bt, m);
243 m->aglobal->exec(m->aglobal);
244 if(m->ai != nil){
245 //dbg("the %s is %sing...", m->md->name, m->ai->name);
246 if(m->ai->exec != nil)
247 m->ai->exec(m->ai);
248 } else {
249 //dbg("the %s is %sing...", m->md->name, m->aglobal->name);
250 }
251 239
252 m->mvp -= 12;240 m->mvp -= 12;
253 m->turns++;241 m->turns++;
@@ -263,32 +251,6 @@ mupdate(Monster *m) · 9 unmodified lines
263 return 0;251 return 0;
264}252}
265 253
266void
267mpushstate(Monster *m, AIState *a)
268{
269 assert(a != nil);
270 a->prev = m->ai;
271 m->ai = a;
272 if(a->enter != nil)
273 a->enter(a);
274}
275
276AIState*
277mpopstate(Monster *m)
278{
279 AIState *a;
280
281 if(m->ai == nil)
282 return nil;
283
284 a = m->ai;
285 if(a->exit != nil)
286 a->exit(a);
287 m->ai = a->prev;
288
289 return a;
290}
291
292/* determines what happens when a monster gets some xp */254/* determines what happens when a monster gets some xp */
293static void255static void
294maddxp(Monster *m, int xp)256maddxp(Monster *m, int xp)
path.c+3−0
@@ -3,6 +3,9 @@ · 2 unmodified lines
3#include <draw.h>3#include <draw.h>
4#include <thread.h>4#include <thread.h>
5 5
6#include "map.h"
7#include "bt.h"
8
6#include "dat.h"9#include "dat.h"
7#include "alg.h"10#include "alg.h"
8 11
tile.c+3−0
@@ -3,6 +3,9 @@ · 2 unmodified lines
3#include <draw.h>3#include <draw.h>
4#include <thread.h>4#include <thread.h>
5 5
6#include "map.h"
7#include "bt.h"
8
6#include "dat.h"9#include "dat.h"
7 10
8Tileset*11Tileset*
ui.c+14−3
@@ -5,6 +5,9 @@ · 4 unmodified lines
5#include <keyboard.h>5#include <keyboard.h>
6#include <mouse.h>6#include <mouse.h>
7 7
8#include "map.h"
9#include "bt.h"
10
8#include "dat.h"11#include "dat.h"
9#include "alg.h"12#include "alg.h"
10 13
@@ -311,11 +314,13 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 300 unmodified lines
311 stringbg(screen, p2, display->white, ZP, smallfont, buf, display->black, ZP);314 stringbg(screen, p2, display->white, ZP, smallfont, buf, display->black, ZP);
312 /* debugging the ai state */315 /* debugging the ai state */
313 if(debug){316 if(debug){
317/*
314 if(m->ai != nil){318 if(m->ai != nil){
315 stringbg(screen, sp, display->white, ZP, smallfont, m->ai->name, display->black, ZP);319 stringbg(screen, sp, display->white, ZP, smallfont, m->ai->name, display->black, ZP);
316 } else {320 } else {
317 stringbg(screen, sp, display->white, ZP, smallfont, m->aglobal->name, display->black, ZP);321 stringbg(screen, sp, display->white, ZP, smallfont, m->aglobal->name, display->black, ZP);
318 }322 }
323*/
319 }324 }
320 } else if(hasflagat(l, p, Fhasitem)){325 } else if(hasflagat(l, p, Fhasitem)){
321 drawtile(ts, screen, sp, ilnth(&t->items, 0)->id->tile);326 drawtile(ts, screen, sp, ilnth(&t->items, 0)->id->tile);
@@ -854,14 +859,12 @@ chelp(Rune c) · 532 unmodified lines
854}859}
855 860
856void861void
857uiexec(AIState *ai)862uirun(void)
858{863{
859 int al;864 int al;
860 Rune c;865 Rune c;
861 Msg *l, *lp;866 Msg *l, *lp;
862 867
863 USED(ai);
864
865 enum { ALOG, ATICK, AMOUSE, ARESIZE, AKEYBOARD, AEND };868 enum { ALOG, ATICK, AMOUSE, ARESIZE, AKEYBOARD, AEND };
866 Alt a[AEND+1] = {869 Alt a[AEND+1] = {
867 { ui.msgc, &l, CHANRCV },870 { ui.msgc, &l, CHANRCV },
@@ -952,6 +955,14 @@ uiexec(AIState *ai) · 84 unmodified lines
952 }955 }
953}956}
954 957
958int
959uibt(void *a)
960{
961 USED(a);
962 uirun();
963 return TASKSUCCESS;
964}
965
955static int966static int
956ch2ind(KeyMenu *km, Rune want)967ch2ind(KeyMenu *km, Rune want)
957{968{
util.c+3−0
@@ -3,6 +3,9 @@ · 2 unmodified lines
3#include <draw.h>3#include <draw.h>
4#include <thread.h>4#include <thread.h>
5 5
6#include "map.h"
7#include "bt.h"
8
6#include "dat.h"9#include "dat.h"
7 10
8Point cardinals[] = {11Point cardinals[] = {