History

better movement, ui, monsters attack player, game over

mischief committed 11 years ago

Commit a499b841 parent 212ed556 files · +454 −219Browse files

Unified · Split

6 files
  1. dat.h +59 −7
  2. hack9.c +285 −184
  3. level.c +22 −19
  4. mkfile +5 −4
  5. monst.c +78 −1
  6. monstdata.c +5 −4
dat.h+59−7
@@ -1,4 +1,17 @@
11 typedef struct Tileset Tileset;
2+typedef struct Tile Tile;
3+typedef struct Portal Portal;
4+typedef struct Level Level;
5+typedef struct MonsterData MonsterData;
6+typedef struct Monster Monster;
7+typedef struct Camera Camera;
8+
9+/* hack9.c */
10+void msg(char *fmt, ...);
11+void good(char *fmt, ...);
12+void warn(char *fmt, ...);
13+void dbg(char *fmt, ...);
14+
215 struct Tileset
316 {
417 /* of each tile */
@@ -13,13 +26,13 @@ struct Tileset · 8 unmodified lines
1326 Image *image;
1427 };
1528
29+/* tile.c */
1630 Tileset *opentile(char *name, int width, int height);
1731 void freetile(Tileset *t);
1832
1933 /* draw i'th tile onto dst */
2034 void drawtile(Tileset *t, Image *dst, Point p, int i);
2135
22−typedef struct MonsterData MonsterData;
2336 struct MonsterData
2437 {
2538 char *name;
@@ -29,16 +42,33 @@ struct MonsterData · 3 unmodified lines
2942
3043 extern MonsterData monstdata[392];
3144
32−typedef struct Monster Monster;
45+/* possible moves */
46+enum
47+{
48+ MNONE,
49+ MMOVE, /* also attack */
50+ MUSE,
51+};
52+
3353 struct Monster
3454 {
35− int hp;
55+ /* current level */
56+ Level *l;
57+ /* location */
58+ Point pt;
59+
60+ /* alignment */
61+ char align;
3662
37− /* doesn't need to be free'd */
63+ /* current hp */
64+ long hp;
65+
66+ /* no free */
3867 MonsterData *md;
3968 };
4069
4170 Monster *monst(int idx);
71+int maction(Monster *m, int what, Point where);
4272
4373 /* well known tiles, also indexes into monstdata */
4474 enum
@@ -59,11 +89,21 @@ enum · 14 unmodified lines
5989 TDOWNSTAIR = 852,
6090 };
6191
62−typedef struct Tile Tile;
92+struct Portal
93+{
94+ /* where it takes us to */
95+ Level *to;
96+ /* location in to */
97+ Point pt;
98+};
99+
63100 struct Tile
64101 {
65102 /* current monster occupying tile */
66103 Monster *monst;
104+
105+ /* has a portal */
106+ Portal *portal;
67107 /*
68108 Feature *feat;
69109 Item *items[10];
@@ -90,9 +130,9 @@ enum · 20 unmodified lines
90130 Fhasitem = 0x4,
91131 Fhasfeature = 0x8,
92132 Fblocked = 0x10,
133+ Fportal = 0x20,
93134 };
94135
95−typedef struct Level Level;
96136 struct Level
97137 {
98138 int width;
@@ -114,7 +154,6 @@ Tile *tileat(Level *l, Point p); · 15 unmodified lines
114154 #define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))
115155 Point *lneighbor(Level *l, Point p, int *n);
116156
117−typedef struct Camera Camera;
118157 struct Camera
119158 {
120159 Point pos;
@@ -135,3 +174,16 @@ enum { · 14 unmodified lines
135174 int manhattan(Point cur, Point targ);
136175 int pathfind(Level *l, Point start, Point end, Point **path);
137176
177+/* util.c */
178+enum
179+{
180+ NORTH,
181+ SOUTH,
182+ EAST,
183+ WEST,
184+ NCARDINAL,
185+ NODIR,
186+};
187+
188+extern Point cardinals[];
189+
hack9.c+285−184
@@ -9,29 +9,126 @@ · 8 unmodified lines
99
1010 enum
1111 {
12− LSIZE = 10,
12+ LSIZE = 20,
1313 };
1414
15−Mousectl *mc;
16−Keyboardctl *kc;
15+static long turn = 0;
16+static Level *level;
17+static char *user;
18+static Monster *player;
19+static int gameover = 0;
1720
18−Tileset *tiles;
19−Level *level;
21+enum
22+{
23+ CGREEN,
24+ CYELLOW,
25+ CORANGE,
26+ CRED,
27+ CGREY,
28+};
2029
21−/* in tiles */
22−Point campos;
30+typedef struct Msg Msg;
31+struct Msg
32+{
33+ char msg[256];
34+ ulong color;
35+ Msg *next;
36+};
2337
24−/* of player */
25−Point pos;
38+typedef struct UI UI;
39+struct UI
40+{
41+ Image **cols;
42+ Mousectl *mc;
43+ Keyboardctl *kc;
44+ Channel *msgc;
45+ Msg *msg;
46+ int nmsg;
47+ Tileset *tiles;
48+ Rectangle viewr;
49+ Rectangle uir;
50+ Point camp;
51+} ui;
2652
27−static int
28−min(int a, int b)
53+static void
54+initui(char *name)
2955 {
30− if(a < b)
31− return a;
32− return b;
56+ if(initdraw(nil, nil, name) < 0)
57+ sysfatal("initdraw: %r");
58+
59+ if((ui.mc = initmouse(nil, screen)) == nil)
60+ sysfatal("initmouse: %r");
61+
62+ if((ui.kc = initkeyboard(nil)) == nil)
63+ sysfatal("initkeyboard: %r");
64+
65+ if((ui.msgc = chancreate(sizeof(Msg*), 100)) == nil)
66+ sysfatal("chancreate: %r");
67+
68+ if((ui.tiles = opentile("nethack.32x32", 32, 32)) == nil)
69+ sysfatal("opentile: %r");
70+
71+ if((ui.cols = mallocz(2 * sizeof(Image*), 1)) == nil)
72+ sysfatal("malloc cols: %r");
73+
74+ ui.cols[CGREEN] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DGreen);
75+ ui.cols[CYELLOW] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellow);
76+ ui.cols[CORANGE] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xFFA500FF);
77+ ui.cols[CRED] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
78+ ui.cols[CGREY] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xAAAAAAFF);
79+}
80+
81+static void
82+uimsg(uint color, char *fmt, va_list arg)
83+{
84+ Msg *l;
85+
86+ l = mallocz(sizeof(Msg), 1);
87+ assert(l != nil);
88+ l->color = color;
89+ vsnprint(l->msg, sizeof(l->msg)-1, fmt, arg);
90+
91+ while(nbsendp(ui.msgc, l) == 0)
92+ yield();
93+}
94+
95+void
96+msg(char *fmt, ...)
97+{
98+ va_list arg;
99+ va_start(arg, fmt);
100+ uimsg(CGREY, fmt, arg);
101+ va_end(arg);
102+}
103+
104+void
105+good(char *fmt, ...)
106+{
107+ va_list arg;
108+ va_start(arg, fmt);
109+ uimsg(CGREEN, fmt, arg);
110+ va_end(arg);
33111 }
34112
113+void
114+warn(char *fmt, ...)
115+{
116+ va_list arg;
117+ va_start(arg, fmt);
118+ uimsg(CYELLOW, fmt, arg);
119+ va_end(arg);
120+}
121+
122+void
123+dbg(char *fmt, ...)
124+{
125+ va_list arg;
126+ va_start(arg, fmt);
127+ uimsg(CRED, fmt, arg);
128+ va_end(arg);
129+}
130+
131+
35132 /* draw the whole level on the screen using tileset ts.
36133 * r.min is the upper left visible tile, and r.max is
37134 * the bottom right visible tile.
@@ -43,15 +140,13 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 5 unmodified lines
43140 Point xy, tpos;
44141 Tile *t;
45142
46− draw(screen, screen->r, display->black, nil, ZP);
47−
48143 for(x = r.min.x; x < r.max.x; x++){
49144 for(y = r.min.y; y < r.max.y; y++){
50145 /* world cell */
51146 xy = (Point){x, y};
52147 /* screen space */
53148 tpos = xy;
54− tpos = addpt(tpos, campos);
149+ tpos = addpt(tpos, ui.camp);
55150 tpos.x *= ts->width;
56151 tpos.y *= ts->height;
57152 tpos = addpt(tpos, screen->r.min);
@@ -68,6 +163,57 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 10 unmodified lines
68163 }
69164 }
70165
166+void
167+drawui(Rectangle r)
168+{
169+ int i, j;
170+ Point p;
171+ Image *c;
172+ char buf[256];
173+ Msg *m;
174+
175+ draw(screen, r, display->black, nil, ZP);
176+
177+ p = r.min;
178+ p.y += font->height * 2;
179+
180+ m = ui.msg;
181+ for(i = 3; m != nil && i > 0; i--){
182+ snprint(buf, sizeof(buf), "%s", m->msg);
183+ string(screen, p, ui.cols[m->color], ZP, font, buf);
184+ p.y -= font->height;
185+ m = m->next;
186+ }
187+
188+ p = r.min;
189+ p.y += font->height * 3;
190+ line(screen, p, Pt(screen->r.max.x, p.y), Enddisc, Enddisc, 0, display->white, ZP);
191+
192+ if(gameover>0)
193+ return;
194+
195+ snprint(buf, sizeof(buf), "%s the %s", user, player->md->name);
196+ p = string(screen, p, display->white, ZP, font, buf);
197+ p.x += 10;
198+
199+ p.x = r.min.x;
200+ p.y += font->height;
201+ snprint(buf, sizeof(buf), "T:%ld ", turn);
202+ p = string(screen, p, display->white, ZP, font, buf);
203+
204+ snprint(buf, sizeof(buf), "%ld/%d HP ", player->hp, player->md->maxhp);
205+ i = player->hp, j = player->md->maxhp;
206+ if(i > (j/4)*3)
207+ c = ui.cols[CGREEN];
208+ else if(i > j/2)
209+ c = ui.cols[CYELLOW];
210+ else if(i > j/4)
211+ c = ui.cols[CORANGE];
212+ else
213+ c = ui.cols[CRED];
214+ p = string(screen, p, c, ZP, font, buf);
215+}
216+
71217 Rectangle
72218 view(Point pos, Level *l, int scrwidth, int scrheight)
73219 {
@@ -75,129 +221,61 @@ view(Point pos, Level *l, int scrwidth, int scrheight) · 1 unmodified line
75221 Rectangle r;
76222
77223 /* compute vieweable area of the map */
78− p = Pt((scrwidth/2)+2, (scrheight/2)+2);
224+ p = Pt((scrwidth/2)+2, (scrheight/2));
79225 r = Rpt(subpt(pos, p), addpt(pos, p));
80226 rectclip(&r, Rect(0, 0, l->width, l->height));
81227 return r;
82228 }
83229
84−enum
230+void
231+redraw(UI *ui, int new)
85232 {
86− DUMMY,
87− WEST,
88− NORTH,
89− EAST,
90− SOUTH,
91− UP,
92− DOWN,
93−};
233+ int width, height;
94234
95−/* attempt to move the monster/player at src in dir direction
96− * return delta in Point if moved, ZP if not */
97−static Point
98−move(Point src, int dir)
99−{
100− int *adj, c, lim, what;
101− Point dst;
102− Tile *t, *t2;
103− Monster *m;
235+ if(new){
236+ if(getwindow(display, Refnone) < 0)
237+ sysfatal("getwindow: %r");
104238
105− adj = nil;
106− c = lim = 0;
107− dst = src;
108−
109− switch(dir){
110− default:
111− fprint(2, "unknown move %d\n", dir);
112− case DUMMY:
113− return ZP;
114− break;
115− case NORTH:
116− c = -1;
117− if(0){
118− case SOUTH:
119− c = 1;
120− }
121− lim = level->height;
122− adj = &dst.y;
123− break;
124− case WEST:
125− c = -1;
126− if(0){
127− case EAST:
128− c = 1;
129− }
130− lim = level->width;
131− adj = &dst.x;
132− break;
133−
134− /* special cases; use stairs, change level */
135− case UP:
136− case DOWN:
137− t = tileat(level, src);
138− what = t->unit;
139− if(t->feat == (dir==UP ? TUPSTAIR : TDOWNSTAIR)){
140− m = t->monst;
141− t->monst = nil;
142− freelevel(level);
143− if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE)) == nil)
144− sysfatal("genlevel: %r");
145−
146− if(dir == UP)
147− dst = level->down;
148− else
149− dst = level->up;
150−
151− t = tileat(level, dst);
152− t->unit = what;
153− t->monst = m;
154− setflagat(level, dst, Fhasmonster|Fblocked);
155− return subpt(src, dst);
239+ /* height should be big enough for 5 tiles, and 5 text lines. */
240+ if(Dx(screen->r) < 300 || Dy(screen->r) < (ui->tiles->height*5 + font->height*5)){
241+ fprint(2, "window %R too small\n", screen->r);
242+ return;
156243 }
157− break;
158− }
159244
160− if(adj && *adj + c >= 0 && *adj + c < lim){
161− *adj += c;
162− t = tileat(level, dst);
163− if(eqpt(src, pos) && hasflagat(level, dst, Fblocked) && t->monst != nil){
164− /* monster; attack it */
165− if(--t->monst->hp == 0){
166− free(t->monst);
167− t->monst = nil;
168− t->unit = 0;
169− clrflagat(level, dst, Fhasmonster|Fblocked);
170− }
245+ ui->uir = Rpt(Pt(screen->r.min.x, screen->r.max.y-(font->height*5)), screen->r.max);
246+ }
171247
172− /* no movement */
173− return ZP;
174− }
175− if(!hasflagat(level, dst, Fblocked)){
176− /* move */
177− t2 = tileat(level, src);
178− setflagat(level, dst, (Fhasmonster|Fblocked));
179− clrflagat(level, src, (Fhasmonster|Fblocked));
180− t->unit = t2->unit;
181− t2->unit = 0;
182− t->monst = t2->monst;
183− t2->monst = nil;
184− return subpt(src, dst);
185− }
248+ width = Dx(screen->r) / ui->tiles->width;
249+ height = (Dy(screen->r) - (font->height*2)) / ui->tiles->height;
250+ if(gameover<1){
251+ ui->viewr = view(player->pt, level, width, height);
252+ ui->camp = subpt(Pt(width/2, height/2), player->pt);
253+ draw(screen, screen->r, display->black, nil, ZP);
254+ drawlevel(level, ui->tiles, ui->viewr);
186255 }
256+ drawui(ui->uir);
257+ flushimage(display, 1);
258+}
187259
188− return ZP;
260+static int
261+min(int a, int b)
262+{
263+ if(a < b)
264+ return a;
265+ return b;
189266 }
190267
191268 void
192269 movemons(void)
193270 {
194− int i, movdir, nmove, npath;
271+ int i, nmove, npath;
195272 Point p, p2, *tomove, *path;
273+ Monster *m;
196274
197275 nmove = 0;
198276 for(p.x = 0; p.x < level->width; p.x++){
199277 for(p.y = 0; p.y < level->height; p.y++){
200− if(!eqpt(p, pos) && hasflagat(level, p, Fhasmonster))
278+ if(!eqpt(p, player->pt) && hasflagat(level, p, Fhasmonster))
201279 nmove++;
202280 }
203281 }
@@ -209,27 +287,32 @@ movemons(void) · 5 unmodified lines
209287 i = 0;
210288 for(p.x = 0; p.x < level->width; p.x++){
211289 for(p.y = 0; p.y < level->height; p.y++){
212− if(!eqpt(p, pos) && hasflagat(level, p, Fhasmonster))
290+ if(!eqpt(p, player->pt) && hasflagat(level, p, Fhasmonster))
213291 tomove[i++] = p;
214292 }
215293 }
216294
217295 for(i = 0; i < nmove; i++){
218296 p = tomove[i];
219− if(manhattan(p, pos) < 6 * ORTHOCOST){
297+ m = tileat(level, p)->monst;
298+
299+ /* it's possible the monster died in the meantime. */
300+ if(m == nil)
301+ continue;
302+
303+ if(manhattan(p, player->pt) < 6 * ORTHOCOST){
220304 /* move the monster toward player */
221− npath = pathfind(level, p, pos, &path);
305+ npath = pathfind(level, m->pt, player->pt, &path);
222306 if(npath >= 0){
223307 /* step once along path, path[0] is cur pos */
224− p2 = subpt(p, path[1]);
225− double ang = atan2(p2.y, p2.x);
226− movdir = (int)(4 * ang / (2*PI) + 4.5) % 4;
227− p2 = move(p, movdir+1);
308+ maction(m, MMOVE, path[1]);
228309 free(path);
229310 }
230311 } else {
231312 /* random move */
232− move(p, nrand(4)+1);
313+ p2 = addpt(m->pt, cardinals[nrand(NCARDINAL)]);
314+ if(!hasflagat(level, p2, Fblocked))
315+ maction(m, MMOVE, p2);
233316 }
234317 }
235318
@@ -240,11 +323,10 @@ void · 4 unmodified lines
240323 threadmain(int argc, char *argv[])
241324 {
242325 Rune c;
326+ Msg *l, *lp;
243327
244328 /* of viewport, in size of tiles */
245− int width, height, movdir;
246− Rectangle r;
247− Point p;
329+ int move, dir;
248330 Tile *t;
249331
250332 ARGBEGIN{
@@ -252,112 +334,131 @@ threadmain(int argc, char *argv[]) · 1 unmodified line
252334
253335 srand(truerand());
254336
255− if(initdraw(nil, nil, argv0) < 0)
256− sysfatal("initdraw: %r");
257−
258− if((mc = initmouse(nil, screen)) == nil)
259− sysfatal("initmouse: %r");
337+ user = getenv("user");
260338
261− if((kc = initkeyboard(nil)) == nil)
262− sysfatal("initkeyboard: %r");
263−
264− if((tiles = opentile("nethack.32x32", 32, 32)) == nil)
265− sysfatal("opentile: %r");
339+ initui(argv0);
266340
267341 if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE)) == nil)
268342 sysfatal("genlevel: %r");
269343
270344 /* the player */
271− pos = level->up;
272− t = tileat(level, pos);
345+ player = monst(TWIZARD);
346+ if(player == nil)
347+ sysfatal("monst: %r");
348+ player->hp = 5;
349+ player->l = level;
350+ player->pt = level->up;
351+ t = tileat(level, player->pt);
273352 t->unit = TWIZARD;
274− setflagat(level, pos, Fhasmonster|Fblocked);
275−
276− width = Dx(screen->r) / tiles->width;
277− height = Dy(screen->r) / tiles->height;
353+ t->monst = player;
354+ setflagat(level, player->pt, Fhasmonster|Fblocked);
278355
279− r = view(pos, level, width, height);
280− campos = subpt(Pt(width/2, height/2), pos);
356+ redraw(&ui, 1);
281357
282− drawlevel(level, tiles, r);
283− flushimage(display, 1);
284−
285− enum { AMOUSE, ARESIZE, AKEYBOARD, AEND };
358+ enum { AMOUSE, ARESIZE, AKEYBOARD, ALOG, AEND };
286359 Alt a[AEND+1] = {
287− { mc->c, nil, CHANRCV },
288− { mc->resizec, nil, CHANRCV },
289− { kc->c, &c, CHANRCV },
290− { nil, nil, CHANEND },
360+ { ui.mc->c, nil, CHANRCV },
361+ { ui.mc->resizec, nil, CHANRCV },
362+ { ui.kc->c, &c, CHANRCV },
363+ { ui.msgc, &l, CHANRCV },
364+ { nil, nil, CHANEND },
291365 };
292366
367+ static int turns=0;
368+
293369 for(;;){
294370 switch(alt(a)){
295371 case AMOUSE:
296372 break;
297373 case ARESIZE:
298− if(getwindow(display, Refnone) < 0)
299− sysfatal("getwindow: %r");
300− width = Dx(screen->r) / tiles->width;
301− height = Dy(screen->r) / tiles->height;
302−
303− r = view(pos, level, width, height);
304− campos = subpt(Pt(width/2, height/2), pos);
305−
306− drawlevel(level, tiles, r);
307− flushimage(display, 1);
374+ redraw(&ui, 1);
308375 break;
309376 case AKEYBOARD:
310− movdir = DUMMY;
377+ if(c == Kdel)
378+ threadexitsall(nil);
379+ if(gameover > 0){
380+ dbg("you are dead. game over, man.");
381+ break;
382+ }
383+
384+ move = MNONE;
385+ dir = NODIR;
386+
387+ if(turns % 5 == 0 && player->hp < player->md->maxhp){
388+ good("you get 1 hp.");
389+ ainc(&player->hp);
390+ }
391+
311392 switch(c){
312393 case Kdel:
313394 threadexitsall(nil);
314395 break;
315396 case 'h':
316397 case Kleft:
317− movdir = WEST;
398+ move = MMOVE;
399+ dir = WEST;
318400 break;
319401 case 'j':
320402 case Kdown:
321− movdir = SOUTH;
403+ move = MMOVE;
404+ dir = SOUTH;
322405 break;
323406 case 'k':
324407 case Kup:
325− movdir = NORTH;
408+ move = MMOVE;
409+ dir = NORTH;
326410 break;
327411 case 'l':
328412 case Kright:
329− movdir = EAST;
413+ move = MMOVE;
414+ dir = EAST;
330415 break;
331416 case '<':
332− movdir = UP;
333− break;
334417 case '>':
335− movdir = DOWN;
418+ move = MUSE;
336419 break;
337420 case '.':
338− movdir = DUMMY;
339421 break;
422+ case ' ':
423+ msg("");
340424 default:
341425 /* don't waste a move */
342426 continue;
343427 }
344428
345− if(movdir != DUMMY){
346− p=move(pos, movdir);
347− if(!eqpt(p, ZP)){
348− pos = subpt(pos, p);
349− }
429+ if(move != MNONE && dir != NODIR){
430+ if(maction(player, move, addpt(player->pt, cardinals[dir])) < 0)
431+ msg("ouch!");
350432 }
351433
352− static int turns=0;
353− if(++turns % 3 ==0){
434+ if(++turns % 2 ==0){
354435 movemons();
355436 }
356437
357− r = view(pos, level, width, height);
358− campos = subpt(Pt(width/2, height/2), pos);
359− drawlevel(level, tiles, r);
360− flushimage(display, 1);
438+ ainc(&turn);
439+
440+ if(player->hp < 2){
441+ gameover++;
442+ }
443+
444+ redraw(&ui, 0);
445+ break;
446+ case ALOG:
447+ if(ui.msg == nil){
448+ ui.msg = l;
449+ ui.nmsg = 1;
450+ } else {
451+ l->next = ui.msg;
452+ ui.msg = l;
453+ ui.nmsg++;
454+ if(ui.nmsg > 10){
455+ for(lp = ui.msg; lp->next != nil; lp = lp->next)
456+ ;
457+ free(lp->next);
458+ lp->next = nil;
459+ }
460+ }
461+ redraw(&ui, 0);
361462 break;
362463 }
363464 }
level.c+22−19
@@ -29,7 +29,7 @@ static void · 28 unmodified lines
2929 drunk1(Level *l, Point p, int n)
3030 {
3131 int cur, last;
32− Point next, dir[] = { Pt(1, 0), Pt(-1, 0), Pt(0, 1), Pt(0, -1) };
32+ Point next;
3333 Rectangle clipr;
3434 Tile *t;
3535
@@ -38,10 +38,10 @@ drunk1(Level *l, Point p, int n) · 2 unmodified lines
3838 last = 0;
3939 while(n > 0){
4040 if(nrand(3) == 0)
41− cur = nrand(nelem(dir));
41+ cur = nrand(NCARDINAL);
4242 else
4343 cur = last;
44− next = addpt(p, dir[cur]);
44+ next = addpt(p, cardinals[cur]);
4545 if(!ptinrect(next, clipr))
4646 continue;
4747 last = cur;
@@ -62,7 +62,7 @@ drunken(Level *l, int type) · 14 unmodified lines
6262 Point p, *path;
6363 Tile *t;
6464
65− cnt = ((l->width * l->height) / 4); //* 2;
65+ cnt = ((l->width * l->height) / 8); //* 2;
6666
6767 redo:
6868 /* fill */
@@ -92,40 +92,40 @@ redo: · 23 unmodified lines
9292 static void
9393 gen(Level *l)
9494 {
95− int i, q, rnd, space;
96− Point pup, pdown, p;
95+ int i, q, rnd, space, npath;
96+ Point pup, pdown, p, *path;
9797 Tile *t;
98−
99− space = l->width*l->height;
98+ Monster *m;
10099
101100 pup = (Point){nrand(l->width-4)+2, nrand(l->height-4)+2};
102101 tileat(l, pup)->feat = TUPSTAIR;
103− setflagat(l, pup, Fhasfeature);
102+ setflagat(l, pup, Fhasfeature|Fportal);
104103 l->up = pup;
105104
106− space--;
107−
108105 while(1){
109106 pdown = (Point){nrand(l->width-4)+2, nrand(l->height-4)+2};
110107 /* already upstair? */
111− if(flagat(l, pdown) & Fhasfeature)
108+ if(flagat(l, pdown) & Fportal)
112109 continue;
113110 /* too close? */
114111 p = subpt(pup, pdown);
115− if(sqrt(p.x*p.x+p.y*p.y) < 6.0)
112+ if((npath = pathfind(l, pup, pdown, &path)) < 0)
113+ sysfatal("pathfind: %r");
114+ free(path);
115+ if(npath < sqrt(l->width * l->height)-4)
116116 continue;
117− setflagat(l, pdown, Fhasfeature);
117+ setflagat(l, pdown, Fhasfeature|Fportal);
118118 tileat(l, pdown)->feat = TDOWNSTAIR;
119119 l->down = pdown;
120120 break;
121121 }
122122
123− space--;
123+ space = 0;
124124
125− space -= drunken(l, TTREE);
125+ space += drunken(l, TTREE);
126126
127127 /* some monsters */
128− q = (l->width*l->height) / 10;
128+ q = (l->width*l->height) / 20;
129129 rnd = nrand(q)+q;
130130 for(i = 0; i < rnd && space > 10; i++){
131131 do {
@@ -134,8 +134,11 @@ gen(Level *l) · 2 unmodified lines
134134
135135 t = tileat(l, p);
136136 q = nrand(4)+TSOLDIER;
137− t->unit = q; //nrand(320);
138− t->monst = monst(q);
137+ t->unit = q;
138+ m = monst(q);
139+ m->l = l;
140+ m->pt = p;
141+ t->monst = m;
139142 setflagat(l, p, Fblocked|Fhasmonster);
140143
141144 space--;
mkfile+5−4
@@ -7,14 +7,15 @@ HFILES=\ · 6 unmodified lines
77 alg.h\
88
99 OFILES=\
10− hack9.$O\
11− tile.$O\
10+ alg.$O\
1211 camera.$O\
12+ hack9.$O\
1313 level.$O\
14− path.$O\
15− alg.$O\
1614 monst.$O\
1715 monstdata.$O\
16+ path.$O\
17+ tile.$O\
18+ util.$O\
1819
1920 CLEANFILES=$O.alg
2021
monst.c+78−1
@@ -27,7 +27,84 @@ monst(int idx) · 26 unmodified lines
2727 return m;
2828
2929 missing:
30− werrstr("missing monster %d\n", idx);
30+ werrstr("missing monster %d", idx);
3131 return nil;
3232 }
3333
34+int
35+maction(Monster *m, int what, Point where)
36+{
37+ Tile *cur, *targ;
38+ Monster *mtarg;
39+
40+ switch(what){
41+ default:
42+ fprint(2, "unknown move %d\n", what);
43+ case MNONE:
44+ /* do nothing */
45+ return 0;
46+ break;
47+ case MMOVE:
48+ targ = tileat(m->l, where);
49+ if(hasflagat(m->l, where, Fhasmonster) && targ->monst != nil){
50+ /* monster; attack it */
51+ warn("the %s hits!", m->md->name);
52+ mtarg = targ->monst;
53+ mtarg->hp -= m->md->atk;
54+ if(mtarg->hp < 1){
55+ dbg("the %s is killed!", mtarg->md->name);
56+ clrflagat(m->l, where, Fhasmonster|Fblocked);
57+ free(mtarg);
58+ targ->monst = nil;
59+ targ->unit = 0;
60+ }
61+
62+ /* no movement */
63+ return 0;
64+ }
65+ if(!hasflagat(m->l, where, Fblocked)){
66+ /* move */
67+ cur = tileat(m->l, m->pt);
68+ setflagat(m->l, where, (Fhasmonster|Fblocked));
69+ clrflagat(m->l, m->pt, (Fhasmonster|Fblocked));
70+ targ->unit = cur->unit;
71+ cur->unit = 0;
72+ targ->monst = cur->monst;
73+ cur->monst = nil;
74+
75+ m->pt = where;
76+ return 1;
77+ }
78+ break;
79+ case MUSE:
80+ /* portal */
81+/*
82+ t = tileat(level, src);
83+ what = t->unit;
84+ if(t->feat == (dir==UP ? TUPSTAIR : TDOWNSTAIR)){
85+ m = t->monst;
86+ t->monst = nil;
87+ freelevel(level);
88+ if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE)) == nil)
89+ sysfatal("genlevel: %r");
90+
91+ if(dir == UP)
92+ dst = level->down;
93+ else
94+ dst = level->up;
95+
96+ t = tileat(level, dst);
97+ t->unit = what;
98+ t->monst = m;
99+ setflagat(level, dst, Fhasmonster|Fblocked);
100+ return subpt(src, dst);
101+ }
102+*/
103+ return -1;
104+ break;
105+ }
106+
107+ /* bad move. */
108+ return -1;
109+}
110+
monstdata.c+5−4
@@ -7,9 +7,10 @@ · 6 unmodified lines
77 MonsterData monstdata[392] = {
88 [TLARGECAT] {"large cat", 5, 1},
99 [TGWIZARD] {"gnomish wizard", 1, 1},
10−[TSOLDIER] {"soldier", 1, 1},
11−[TSERGEANT] {"sergeant", 2, 1},
12−[TLIEUTENANT] {"lieutenant", 3, 1},
13−[TCAPTAIN] {"captain", 4, 1},
10+[TSOLDIER] {"soldier", 4, 1},
11+[TSERGEANT] {"sergeant", 8, 1},
12+[TLIEUTENANT] {"lieutenant", 16, 1},
13+[TCAPTAIN] {"captain", 32, 1},
14+[TWIZARD] {"wizard", 100, 2},
1415 };
1516

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t