History

rearrange some level gen code

mischief committed 9 years ago

Commit dcb054e1 parent c512cb55 files · +218 −215Browse files

Unified · Split

5 files
  1. dat.h +2 −5
  2. hack9.c +1 −1
  3. level.c +1 −91
  4. levelgen.c +213 −117
  5. monst.c +1 −1
dat.h+2−5
@@ -381,9 +381,7 @@ struct Level · 380 unmodified lines
381};381};
382 382
383/* level.c */383/* level.c */
384Level *genlevel(int width, int height, int type);384void lfree(Level *l);
385void freelevel(Level *l);
386void addspawn(Level *l, Point p, char *what, int freq, int istrap);
387Tile *tileat(Level *l, Point p);385Tile *tileat(Level *l, Point p);
388#define flagat(l, p) (*(l->flags+(p.y*l->width)+p.x))386#define flagat(l, p) (*(l->flags+(p.y*l->width)+p.x))
389#define hasflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) & (F))387#define hasflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) & (F))
@@ -391,8 +389,7 @@ Tile *tileat(Level *l, Point p); · 1 unmodified line
391#define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))389#define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))
392 390
393/* levelgen.c */391/* levelgen.c */
394Level *mklevel(int width, int height, int floor, char *name);392Level *lgenerate(int width, int height, int type);
395void several(Level *l, Point *p, int count, char *type, int r);
396int mkldebug(Level *l);393int mkldebug(Level *l);
397int mklforest(Level *l);394int mklforest(Level *l);
398int mklgraveyard(Level *l);395int mklgraveyard(Level *l);
hack9.c+1−1
@@ -152,7 +152,7 @@ threadmain(int argc, char *argv[]) · 151 unmodified lines
152 sysfatal("monstdbopen: %r");152 sysfatal("monstdbopen: %r");
153 153
154 /* initial level */154 /* initial level */
155 if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE, debug?0:nrand(3)+1)) == nil)155 if((level = lgenerate(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE, debug?0:nrand(3)+1)) == nil)
156 sysfatal("genlevel: %r");156 sysfatal("genlevel: %r");
157 157
158 /* the player */158 /* the player */
level.c+1−91
@@ -10,97 +10,7 @@ · 9 unmodified lines
10#include "alg.h"10#include "alg.h"
11 11
12void12void
13addspawn(Level *l, Point p, char *what, int freq, int istrap)13lfree(Level *l)
14{
15 Spawn sp;
16
17 if(l->nspawns < nelem(l->spawns)-1){
18 sp.pt = p;
19 strcpy(sp.what, what);
20 sp.freq = freq;
21 sp.turn = nrand(1000);
22 sp.istrap = istrap;
23 l->spawns[l->nspawns++] = sp;
24 tileat(l, p)->feat = TSPAWN;
25 setflagat(l, p, Fhasfeature);
26 }
27}
28
29static void
30mkportal(Level *l, Point p, int feat, Level *to, Point tp)
31{
32 Tile *t;
33
34 flagat(l, p) = (Fhasfeature|Fportal);
35 t = tileat(l, p);
36 t->feat = feat;
37 t->portal = emalloc(sizeof(Portal));
38 t->portal->to = to;
39 t->portal->pt = tp;
40}
41
42static void
43lrandstairs(Level *l)
44{
45 Rectangle in;
46 Point pup, pdown;
47
48 in = insetrect(l->r, 3);
49
50 pup = (Point){nrand(Dx(in))+3, nrand(Dy(in))+3};
51 do {
52 pdown = (Point){nrand(Dx(in))+3, nrand(Dy(in))+3};
53 } while(eqpt(pdown, pup) || manhattan(pdown, pup) < ORTHOCOST*15);
54
55 l->up = pup;
56 l->down = pdown;
57
58 mkportal(l, pup, TUPSTAIR, nil, ZP);
59 mkportal(l, pdown, TDOWNSTAIR, nil, ZP);
60}
61
62static int
63gen(Level *l, int type)
64{
65 lrandstairs(l);
66
67 switch(type){
68 case 0:
69 mkldebug(l);
70 break;
71 case 1:
72 mklforest(l);
73 break;
74 case 2:
75 mklgraveyard(l);
76 break;
77 case 3:
78 mklvolcano(l);
79 break;
80 }
81
82 return 0;
83}
84
85Level*
86genlevel(int width, int height, int type)
87{
88 Level *l;
89
90 l = nil;
91
92 do {
93 if(l != nil)
94 freelevel(l);
95
96 l = mklevel(width, height, TFLOOR, "somewhere");
97 } while(gen(l, type) < 0);
98
99 return l;
100}
101
102void
103freelevel(Level *l)
104{14{
105 int x, y;15 int x, y;
106 Point p;16 Point p;
levelgen.c+213−117
@@ -61,18 +61,41 @@ lclearrect(Level *l, Rectangle r) · 60 unmodified lines
61}61}
62 62
63static void63static void
64lfillrect(Level *l, Rectangle r, int type)64lfeature(Level *l, Point p, int type, int flags)
65{
66 Tile *t;
67
68 t = tileat(l, p);
69 t->feat = type;
70
71 flagat(l, p) = flags;
72}
73
74static void
75lfeatrect(Level *l, Rectangle r, int type, int flags)
65{76{
66 Point p;77 Point p;
78
79 for(p.x = r.min.x; p.x <= r.max.x; p.x++)
80 for(p.y = r.min.y; p.y <= r.max.y; p.y++)
81 lfeature(l, p, type, flags);
82}
83
84static void
85lportal(Level *l, Point p, int feat, Level *to, Point tp)
86{
67 Tile *t;87 Tile *t;
88 Portal *port;
68 89
69 for(p.x = r.min.x; p.x <= r.max.x; p.x++){90 lfeature(l, p, feat, Fhasfeature);
70 for(p.y = r.min.y; p.y <= r.max.y; p.y++){91
71 t = tileat(l, p);92 port = emalloc(sizeof(Portal));
72 t->feat = type;93 port->to = to;
73 flagat(l, p) = (Fblocked|Fhasfeature);94 port->pt = tp;
74 }95
75 }96 t = tileat(l, p);
97
98 t->portal = port;
76}99}
77 100
78static void101static void
@@ -91,93 +114,79 @@ lborder(Level *l, Rectangle r, int i, int type) · 12 unmodified lines
91 114
92 tmp = Rect(r.min.x, r.min.y, r.max.x, r.min.y+i);115 tmp = Rect(r.min.x, r.min.y, r.max.x, r.min.y+i);
93 lclearrect(l, tmp);116 lclearrect(l, tmp);
94 lfillrect(l, tmp, type);117 lfeatrect(l, tmp, type, Fblocked|Fhasfeature);
95 118
96 tmp = Rect(r.min.x, r.max.y-i, r.max.x, r.max.y);119 tmp = Rect(r.min.x, r.max.y-i, r.max.x, r.max.y);
97 lclearrect(l, tmp);120 lclearrect(l, tmp);
98 lfillrect(l, tmp, type);121 lfeatrect(l, tmp, type, Fblocked|Fhasfeature);
99 122
100 tmp = Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i);123 tmp = Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i);
101 lclearrect(l, tmp);124 lclearrect(l, tmp);
102 lfillrect(l, tmp, type);125 lfeatrect(l, tmp, type, Fblocked|Fhasfeature);
103 126
104 tmp = Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i);127 tmp = Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i);
105 lclearrect(l, tmp);128 lclearrect(l, tmp);
106 lfillrect(l, tmp, type);129 lfeatrect(l, tmp, type, Fblocked|Fhasfeature);
107}130}
108 131
109/* more sbias makes it straighter. */
110static void132static void
111drunk1(Level *l, Point p, uint count, uint sbias)133lspawn(Level *l, Point p, char *what, int freq, int istrap)
112{134{
113 int cur, last;135 Spawn sp;
114 Point next;136
115 Rectangle clipr;137 if(l->nspawns < nelem(l->spawns)-1){
116 Tile *t;138 sp.pt = p;
117 139 strcpy(sp.what, what);
118 clipr = insetrect(l->or, 1);140 sp.freq = freq;
119 141 sp.turn = nrand(1000);
120 last = nrand(NCARDINAL);142 sp.istrap = istrap;
121 while(count > 0){143 l->spawns[l->nspawns++] = sp;
122 if(nrand(sbias+1) == 0)144 tileat(l, p)->feat = TSPAWN;
123 cur = nrand(NCARDINAL);145 setflagat(l, p, Fhasfeature);
124 else
125 cur = last;
126 next = addpt(p, cardinals[cur]);
127 if(!ptinrect(next, clipr))
128 continue;
129 last = cur;
130 p = next;
131 if(!eqpt(p, l->up) && !eqpt(p, l->down) && hasflagat(l, p, Fblocked|Fhasfeature)){
132 t = tileat(l, p);
133 t->feat = 0;
134 flagat(l, p) = 0;
135 count--;
136 }
137 }146 }
138}147}
139 148
140/*149static void
141 * drunken performs the drunkard's walk. as s1 and150lrandstairs(Level *l)
142 * s2 increase, the paths become more biased toward
143 * 'straight'. it loops until the downstairs is
144 * reachable from the upstairs.
145 */
146static int
147drunken(Level *l, int type, int howmuch, int s1, int s2)
148{151{
149 int cnt, npath, redos;152 Rectangle in;
150 Point p, *path;153 Point pup, pdown;
151 Tile *t;
152 154
153 cnt = ((l->width * l->height) / howmuch); //* 2;155 in = insetrect(l->r, 3);
154 redos = 0;
155 156
156redo:157 pup = (Point){nrand(Dx(in))+3, nrand(Dy(in))+3};
157 if(redos++ > 10)158 do {
158 return 0;159 pdown = (Point){nrand(Dx(in))+3, nrand(Dy(in))+3};
159 /* fill */160 } while(eqpt(pdown, pup) || manhattan(pdown, pup) < ORTHOCOST*15);
160 for(p.x = 0; p.x < l->width; p.x++){
161 for(p.y = 0; p.y < l->height; p.y++){
162 if(!hasflagat(l, p, Fblocked|Fhasfeature)){
163 t = tileat(l, p);
164 t->feat = type;
165 flagat(l, p) = (Fblocked|Fhasfeature);
166 }
167 }
168 }
169 161
170 drunk1(l, l->up, cnt/2, s1);162 l->up = pup;
171 drunk1(l, l->down, cnt/2, s2);163 l->down = pdown;
172 164
173 /* check reachability */165 lportal(l, pup, TUPSTAIR, nil, ZP);
174 npath = pathfind(l, l->up, l->down, &path, Fblocked);166 lportal(l, pdown, TDOWNSTAIR, nil, ZP);
175 if(npath < 0)167}
176 goto redo;
177 else
178 free(path);
179 168
180 return cnt * 2;169static int
170lgen(Level *l, int type)
171{
172 lrandstairs(l);
173
174 switch(type){
175 case 0:
176 mkldebug(l);
177 break;
178 case 1:
179 mklforest(l);
180 break;
181 case 2:
182 mklgraveyard(l);
183 break;
184 case 3:
185 mklvolcano(l);
186 break;
187 }
188
189 return 0;
181}190}
182 191
183/* create a monster in the idle state */192/* create a monster in the idle state */
@@ -229,28 +238,9 @@ several(Level *l, Point *p, int count, char *type, int r) · 45 unmodified lines
229 }238 }
230}239}
231 240
232/* genmonsters spawns count of type monsters at random places on l. */241/* AI function for levels */
233static void
234genmonsters(Level *l, char *type, int count)
235{
236 int i;
237 Point p;
238 Tile *t;
239
240 for(i = 0; i < count; i++){
241 do{
242 p = (Point){nrand(l->width), nrand(l->height)};
243 }while(hasflagat(l, p, Fhasmonster|Fhasfeature|Fblocked));
244
245 t = tileat(l, p);
246 t->monst = mkmons(l, p, type);
247 t->unit = t->monst->md->tile;
248 setflagat(l, p, Fhasmonster);
249 }
250}
251
252static int242static int
253levelexec(void *v)243lexec(void *v)
254{244{
255 int i, j, n;245 int i, j, n;
256 Point p, np, *neigh;246 Point p, np, *neigh;
@@ -312,8 +302,8 @@ levelexec(void *v) · 55 unmodified lines
312 return TASKSUCCESS;302 return TASKSUCCESS;
313}303}
314 304
315Level*305static Level*
316mklevel(int width, int height, int floor, char *name)306lmk(int width, int height, int floor, char *name)
317{307{
318 int i;308 int i;
319 Point p;309 Point p;
@@ -338,7 +328,7 @@ mklevel(int width, int height, int floor, char *name) · 18 unmodified lines
338 if(l->flags == nil)328 if(l->flags == nil)
339 goto err1;329 goto err1;
340 330
341 l->bt = btleaf("level", levelexec);331 l->bt = btleaf("level", lexec);
342 if(l->bt == nil)332 if(l->bt == nil)
343 goto err2;333 goto err2;
344 334
@@ -362,6 +352,112 @@ err0: · 17 unmodified lines
362 return nil;352 return nil;
363}353}
364 354
355Level*
356lgenerate(int width, int height, int type)
357{
358 Level *l;
359
360 l = nil;
361
362 do {
363 if(l != nil)
364 lfree(l);
365
366 l = lmk(width, height, TFLOOR, "somewhere");
367 } while(lgen(l, type) < 0);
368
369 return l;
370}
371/* more sbias makes it straighter. */
372static void
373drunk1(Level *l, Point p, uint count, uint sbias)
374{
375 int cur, last;
376 Point next;
377 Rectangle clipr;
378 Tile *t;
379
380 clipr = insetrect(l->or, 1);
381
382 last = nrand(NCARDINAL);
383 while(count > 0){
384 if(nrand(sbias+1) == 0)
385 cur = nrand(NCARDINAL);
386 else
387 cur = last;
388 next = addpt(p, cardinals[cur]);
389 if(!ptinrect(next, clipr))
390 continue;
391 last = cur;
392 p = next;
393 if(!eqpt(p, l->up) && !eqpt(p, l->down) && hasflagat(l, p, Fblocked|Fhasfeature)){
394 t = tileat(l, p);
395 t->feat = 0;
396 flagat(l, p) = 0;
397 count--;
398 }
399 }
400}
401
402/*
403 * drunken performs the drunkard's walk. as s1 and
404 * s2 increase, the paths become more biased toward
405 * 'straight'. it loops until the downstairs is
406 * reachable from the upstairs.
407 */
408static int
409drunken(Level *l, int type, int howmuch, int s1, int s2)
410{
411 int cnt, npath, redos;
412 Point p, *path;
413
414 cnt = ((l->width * l->height) / howmuch); //* 2;
415 redos = 0;
416
417redo:
418 if(redos++ > 10)
419 return 0;
420 /* fill */
421 for(p.x = 0; p.x < l->width; p.x++){
422 for(p.y = 0; p.y < l->height; p.y++){
423 if(!hasflagat(l, p, Fblocked|Fhasfeature))
424 lfeature(l, p, type, Fblocked|Fhasfeature);
425 }
426 }
427
428 drunk1(l, l->up, cnt/2, s1);
429 drunk1(l, l->down, cnt/2, s2);
430
431 /* check reachability */
432 npath = pathfind(l, l->up, l->down, &path, Fblocked);
433 if(npath < 0)
434 goto redo;
435 else
436 free(path);
437
438 return cnt * 2;
439}
440
441/* genmonsters spawns count of type monsters at random places on l. */
442static void
443genmonsters(Level *l, char *type, int count)
444{
445 int i;
446 Point p;
447 Tile *t;
448
449 for(i = 0; i < count; i++){
450 do{
451 p = (Point){nrand(l->width), nrand(l->height)};
452 }while(hasflagat(l, p, Fhasmonster|Fhasfeature|Fblocked));
453
454 t = tileat(l, p);
455 t->monst = mkmons(l, p, type);
456 t->unit = t->monst->md->tile;
457 setflagat(l, p, Fhasmonster);
458 }
459}
460
365int461int
366mkldebug(Level *l)462mkldebug(Level *l)
367{463{
@@ -401,18 +497,18 @@ mklforest(Level *l) · 33 unmodified lines
401 lclear(l, p, 2);497 lclear(l, p, 2);
402 several(l, &p, 1, "captain", 0);498 several(l, &p, 1, "captain", 0);
403 several(l, &p, 1, "lieutenant", 1);499 several(l, &p, 1, "lieutenant", 1);
404 addspawn(l, p, "soldier", 57, 2);500 lspawn(l, p, "soldier", 57, 2);
405 addspawn(l, p, "sergeant", 91, 1);501 lspawn(l, p, "sergeant", 91, 1);
406 addspawn(l, p, "lieutenant", 97, 1);502 lspawn(l, p, "lieutenant", 97, 1);
407 addspawn(l, p, "captain", 131, 1);503 lspawn(l, p, "captain", 131, 1);
408 504
409 lclear(l, p2, 2);505 lclear(l, p2, 2);
410 several(l, &p2, 1, "gnome king", 0);506 several(l, &p2, 1, "gnome king", 0);
411 several(l, &p2, 1, "gnome wizard", 1);507 several(l, &p2, 1, "gnome wizard", 1);
412 addspawn(l, p2, "gnome", 13, 1);508 lspawn(l, p2, "gnome", 13, 1);
413 addspawn(l, p2, "gnome lord", 17, 2);509 lspawn(l, p2, "gnome lord", 17, 2);
414 addspawn(l, p2, "gnome wizard", 27, 1);510 lspawn(l, p2, "gnome wizard", 27, 1);
415 addspawn(l, p2, "gnome king", 101, 1);511 lspawn(l, p2, "gnome king", 101, 1);
416 512
417 /* don't start empty */513 /* don't start empty */
418 genmonsters(l, "gnome lord", space/128);514 genmonsters(l, "gnome lord", space/128);
@@ -444,18 +540,18 @@ mklgraveyard(Level *l) · 25 unmodified lines
444 lclear(l, p, 2);540 lclear(l, p, 2);
445 lclear(l, p2, 2);541 lclear(l, p2, 2);
446 542
447 addspawn(l, p, "lich", 101, 1);543 lspawn(l, p, "lich", 101, 1);
448 addspawn(l, p, "demilich", 157, 0);544 lspawn(l, p, "demilich", 157, 0);
449 addspawn(l, p, "ghost", 15, 2);545 lspawn(l, p, "ghost", 15, 2);
450 addspawn(l, p, "human zombie", 27, 2);546 lspawn(l, p, "human zombie", 27, 2);
451 addspawn(l, p, "skeleton", 71, 1);547 lspawn(l, p, "skeleton", 71, 1);
452 548
453 several(l, &p2, 1, "gnome king", 0);549 several(l, &p2, 1, "gnome king", 0);
454 several(l, &p2, 1, "gnome wizard", 1);550 several(l, &p2, 1, "gnome wizard", 1);
455 addspawn(l, p2, "gnome", 29, 1);551 lspawn(l, p2, "gnome", 29, 1);
456 addspawn(l, p2, "gnome lord", 45, 2);552 lspawn(l, p2, "gnome lord", 45, 2);
457 addspawn(l, p2, "gnome wizard", 57, 2);553 lspawn(l, p2, "gnome wizard", 57, 2);
458 addspawn(l, p2, "gnome king", 71, 1);554 lspawn(l, p2, "gnome king", 71, 1);
459 555
460 genmonsters(l, "ghost", space/64);556 genmonsters(l, "ghost", space/64);
461 genmonsters(l, "gnome", space/64);557 genmonsters(l, "gnome", space/64);
@@ -486,8 +582,8 @@ mklvolcano(Level *l) · 24 unmodified lines
486 lclear(l, p, 2);582 lclear(l, p, 2);
487 lclear(l, p2, 2);583 lclear(l, p2, 2);
488 584
489 addspawn(l, p, "large cat", 77, 0);585 lspawn(l, p, "large cat", 77, 0);
490 addspawn(l, p2, "gnome lord", 27, 2);586 lspawn(l, p2, "gnome lord", 27, 2);
491 587
492 genmonsters(l, "large cat", space/128);588 genmonsters(l, "large cat", space/128);
493 genmonsters(l, "gnome lord", space/64);589 genmonsters(l, "gnome lord", space/64);
@@ -519,7 +615,7 @@ mklcastle(Level *l) · 25 unmodified lines
519 615
520 lclearrect(l, Rpt(p, addpt(p, Pt(0,1))));616 lclearrect(l, Rpt(p, addpt(p, Pt(0,1))));
521 617
522 addspawn(l, addpt(mid.min, Pt(Dx(mid)/2, Dy(mid)/2)), "soldier", 21, 0);618 lspawn(l, addpt(mid.min, Pt(Dx(mid)/2, Dy(mid)/2)), "soldier", 21, 0);
523 619
524 l->up = Pt(1,1);620 l->up = Pt(1,1);
525 l->down = Pt(4,1);621 l->down = Pt(4,1);
monst.c+1−1
@@ -439,7 +439,7 @@ maction(Monster *m, int what, Point where) · 438 unmodified lines
439 m = cur->monst;439 m = cur->monst;
440 cur->monst = nil;440 cur->monst = nil;
441 if(cur->portal->to == nil){441 if(cur->portal->to == nil){
442 if((cur->portal->to = genlevel(nrand(20)+50, nrand(20)+20, nrand(3)+1)) == nil)442 if((cur->portal->to = lgenerate(nrand(20)+50, nrand(20)+20, nrand(3)+1)) == nil)
443 sysfatal("genlevel: %r");443 sysfatal("genlevel: %r");
444 444
445 cur->portal->pt = cur->portal->to->up;445 cur->portal->pt = cur->portal->to->up;