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 @@
1typedef struct Tileset Tileset;1typedef struct Tileset Tileset;
2typedef struct Tile Tile;
3typedef struct Portal Portal;
4typedef struct Level Level;
5typedef struct MonsterData MonsterData;
6typedef struct Monster Monster;
7typedef struct Camera Camera;
8
9/* hack9.c */
10void msg(char *fmt, ...);
11void good(char *fmt, ...);
12void warn(char *fmt, ...);
13void dbg(char *fmt, ...);
14
2struct Tileset15struct Tileset
3{16{
4 /* of each tile */17 /* of each tile */
@@ -13,13 +26,13 @@ struct Tileset · 8 unmodified lines
13 Image *image;26 Image *image;
14};27};
15 28
29/* tile.c */
16Tileset *opentile(char *name, int width, int height);30Tileset *opentile(char *name, int width, int height);
17void freetile(Tileset *t);31void freetile(Tileset *t);
18 32
19/* draw i'th tile onto dst */33/* draw i'th tile onto dst */
20void drawtile(Tileset *t, Image *dst, Point p, int i);34void drawtile(Tileset *t, Image *dst, Point p, int i);
21 35
22typedef struct MonsterData MonsterData;
23struct MonsterData36struct MonsterData
24{37{
25 char *name;38 char *name;
@@ -29,16 +42,33 @@ struct MonsterData · 3 unmodified lines
29 42
30extern MonsterData monstdata[392];43extern MonsterData monstdata[392];
31 44
32typedef struct Monster Monster;45/* possible moves */
46enum
47{
48 MNONE,
49 MMOVE, /* also attack */
50 MUSE,
51};
52
33struct Monster53struct Monster
34{54{
35 int hp;55 /* current level */
56 Level *l;
57 /* location */
58 Point pt;
59
60 /* alignment */
61 char align;
36 62
37 /* doesn't need to be free'd */63 /* current hp */
64 long hp;
65
66 /* no free */
38 MonsterData *md;67 MonsterData *md;
39};68};
40 69
41Monster *monst(int idx);70Monster *monst(int idx);
71int maction(Monster *m, int what, Point where);
42 72
43/* well known tiles, also indexes into monstdata */73/* well known tiles, also indexes into monstdata */
44enum74enum
@@ -59,11 +89,21 @@ enum · 14 unmodified lines
59 TDOWNSTAIR = 852,89 TDOWNSTAIR = 852,
60};90};
61 91
62typedef struct Tile Tile;92struct Portal
93{
94 /* where it takes us to */
95 Level *to;
96 /* location in to */
97 Point pt;
98};
99
63struct Tile100struct Tile
64{101{
65 /* current monster occupying tile */102 /* current monster occupying tile */
66 Monster *monst;103 Monster *monst;
104
105 /* has a portal */
106 Portal *portal;
67 /*107 /*
68 Feature *feat;108 Feature *feat;
69 Item *items[10];109 Item *items[10];
@@ -90,9 +130,9 @@ enum · 20 unmodified lines
90 Fhasitem = 0x4,130 Fhasitem = 0x4,
91 Fhasfeature = 0x8,131 Fhasfeature = 0x8,
92 Fblocked = 0x10,132 Fblocked = 0x10,
133 Fportal = 0x20,
93};134};
94 135
95typedef struct Level Level;
96struct Level136struct Level
97{137{
98 int width;138 int width;
@@ -114,7 +154,6 @@ Tile *tileat(Level *l, Point p); · 15 unmodified lines
114#define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))154#define clrflagat(l, p, F) (*(l->flags+(p.y*l->width)+p.x) &= ~(F))
115Point *lneighbor(Level *l, Point p, int *n);155Point *lneighbor(Level *l, Point p, int *n);
116 156
117typedef struct Camera Camera;
118struct Camera157struct Camera
119{158{
120 Point pos;159 Point pos;
@@ -135,3 +174,16 @@ enum { · 14 unmodified lines
135int manhattan(Point cur, Point targ);174int manhattan(Point cur, Point targ);
136int pathfind(Level *l, Point start, Point end, Point **path);175int pathfind(Level *l, Point start, Point end, Point **path);
137 176
177/* util.c */
178enum
179{
180 NORTH,
181 SOUTH,
182 EAST,
183 WEST,
184 NCARDINAL,
185 NODIR,
186};
187
188extern Point cardinals[];
189
hack9.c+285−184
@@ -9,29 +9,126 @@ · 8 unmodified lines
9 9
10enum10enum
11{11{
12 LSIZE = 10,12 LSIZE = 20,
13};13};
14 14
15Mousectl *mc;15static long turn = 0;
16Keyboardctl *kc;16static Level *level;
17static char *user;
18static Monster *player;
19static int gameover = 0;
17 20
18Tileset *tiles;21enum
19Level *level;22{
23 CGREEN,
24 CYELLOW,
25 CORANGE,
26 CRED,
27 CGREY,
28};
20 29
21/* in tiles */30typedef struct Msg Msg;
22Point campos;31struct Msg
32{
33 char msg[256];
34 ulong color;
35 Msg *next;
36};
23 37
24/* of player */38typedef struct UI UI;
25Point pos;39struct 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;
26 52
27static int53static void
28min(int a, int b)54initui(char *name)
29{55{
30 if(a < b)56 if(initdraw(nil, nil, name) < 0)
31 return a;57 sysfatal("initdraw: %r");
32 return b;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
81static void
82uimsg(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
95void
96msg(char *fmt, ...)
97{
98 va_list arg;
99 va_start(arg, fmt);
100 uimsg(CGREY, fmt, arg);
101 va_end(arg);
102}
103
104void
105good(char *fmt, ...)
106{
107 va_list arg;
108 va_start(arg, fmt);
109 uimsg(CGREEN, fmt, arg);
110 va_end(arg);
33}111}
34 112
113void
114warn(char *fmt, ...)
115{
116 va_list arg;
117 va_start(arg, fmt);
118 uimsg(CYELLOW, fmt, arg);
119 va_end(arg);
120}
121
122void
123dbg(char *fmt, ...)
124{
125 va_list arg;
126 va_start(arg, fmt);
127 uimsg(CRED, fmt, arg);
128 va_end(arg);
129}
130
131
35/* draw the whole level on the screen using tileset ts.132/* draw the whole level on the screen using tileset ts.
36 * r.min is the upper left visible tile, and r.max is133 * r.min is the upper left visible tile, and r.max is
37 * the bottom right visible tile.134 * the bottom right visible tile.
@@ -43,15 +140,13 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 5 unmodified lines
43 Point xy, tpos;140 Point xy, tpos;
44 Tile *t;141 Tile *t;
45 142
46 draw(screen, screen->r, display->black, nil, ZP);
47
48 for(x = r.min.x; x < r.max.x; x++){143 for(x = r.min.x; x < r.max.x; x++){
49 for(y = r.min.y; y < r.max.y; y++){144 for(y = r.min.y; y < r.max.y; y++){
50 /* world cell */145 /* world cell */
51 xy = (Point){x, y};146 xy = (Point){x, y};
52 /* screen space */147 /* screen space */
53 tpos = xy;148 tpos = xy;
54 tpos = addpt(tpos, campos);149 tpos = addpt(tpos, ui.camp);
55 tpos.x *= ts->width;150 tpos.x *= ts->width;
56 tpos.y *= ts->height;151 tpos.y *= ts->height;
57 tpos = addpt(tpos, screen->r.min);152 tpos = addpt(tpos, screen->r.min);
@@ -68,6 +163,57 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 10 unmodified lines
68 }163 }
69}164}
70 165
166void
167drawui(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
71Rectangle217Rectangle
72view(Point pos, Level *l, int scrwidth, int scrheight)218view(Point pos, Level *l, int scrwidth, int scrheight)
73{219{
@@ -75,129 +221,61 @@ view(Point pos, Level *l, int scrwidth, int scrheight) · 1 unmodified line
75 Rectangle r;221 Rectangle r;
76 222
77 /* compute vieweable area of the map */223 /* compute vieweable area of the map */
78 p = Pt((scrwidth/2)+2, (scrheight/2)+2);224 p = Pt((scrwidth/2)+2, (scrheight/2));
79 r = Rpt(subpt(pos, p), addpt(pos, p));225 r = Rpt(subpt(pos, p), addpt(pos, p));
80 rectclip(&r, Rect(0, 0, l->width, l->height));226 rectclip(&r, Rect(0, 0, l->width, l->height));
81 return r;227 return r;
82}228}
83 229
84enum230void
231redraw(UI *ui, int new)
85{232{
86 DUMMY,233 int width, height;
87 WEST,
88 NORTH,
89 EAST,
90 SOUTH,
91 UP,
92 DOWN,
93};
94 234
95/* attempt to move the monster/player at src in dir direction235 if(new){
96 * return delta in Point if moved, ZP if not */236 if(getwindow(display, Refnone) < 0)
97static Point237 sysfatal("getwindow: %r");
98move(Point src, int dir)
99{
100 int *adj, c, lim, what;
101 Point dst;
102 Tile *t, *t2;
103 Monster *m;
104 238
105 adj = nil;239 /* height should be big enough for 5 tiles, and 5 text lines. */
106 c = lim = 0;240 if(Dx(screen->r) < 300 || Dy(screen->r) < (ui->tiles->height*5 + font->height*5)){
107 dst = src;241 fprint(2, "window %R too small\n", screen->r);
108 242 return;
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);
156 }243 }
157 break;
158 }
159 244
160 if(adj && *adj + c >= 0 && *adj + c < lim){245 ui->uir = Rpt(Pt(screen->r.min.x, screen->r.max.y-(font->height*5)), screen->r.max);
161 *adj += c;246 }
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 }
171 247
172 /* no movement */248 width = Dx(screen->r) / ui->tiles->width;
173 return ZP;249 height = (Dy(screen->r) - (font->height*2)) / ui->tiles->height;
174 }250 if(gameover<1){
175 if(!hasflagat(level, dst, Fblocked)){251 ui->viewr = view(player->pt, level, width, height);
176 /* move */252 ui->camp = subpt(Pt(width/2, height/2), player->pt);
177 t2 = tileat(level, src);253 draw(screen, screen->r, display->black, nil, ZP);
178 setflagat(level, dst, (Fhasmonster|Fblocked));254 drawlevel(level, ui->tiles, ui->viewr);
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 }
186 }255 }
256 drawui(ui->uir);
257 flushimage(display, 1);
258}
187 259
188 return ZP;260static int
261min(int a, int b)
262{
263 if(a < b)
264 return a;
265 return b;
189}266}
190 267
191void268void
192movemons(void)269movemons(void)
193{270{
194 int i, movdir, nmove, npath;271 int i, nmove, npath;
195 Point p, p2, *tomove, *path;272 Point p, p2, *tomove, *path;
273 Monster *m;
196 274
197 nmove = 0;275 nmove = 0;
198 for(p.x = 0; p.x < level->width; p.x++){276 for(p.x = 0; p.x < level->width; p.x++){
199 for(p.y = 0; p.y < level->height; p.y++){277 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))
201 nmove++;279 nmove++;
202 }280 }
203 }281 }
@@ -209,27 +287,32 @@ movemons(void) · 5 unmodified lines
209 i = 0;287 i = 0;
210 for(p.x = 0; p.x < level->width; p.x++){288 for(p.x = 0; p.x < level->width; p.x++){
211 for(p.y = 0; p.y < level->height; p.y++){289 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))
213 tomove[i++] = p;291 tomove[i++] = p;
214 }292 }
215 }293 }
216 294
217 for(i = 0; i < nmove; i++){295 for(i = 0; i < nmove; i++){
218 p = tomove[i];296 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){
220 /* move the monster toward player */304 /* move the monster toward player */
221 npath = pathfind(level, p, pos, &path);305 npath = pathfind(level, m->pt, player->pt, &path);
222 if(npath >= 0){306 if(npath >= 0){
223 /* step once along path, path[0] is cur pos */307 /* step once along path, path[0] is cur pos */
224 p2 = subpt(p, path[1]);308 maction(m, MMOVE, 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);
228 free(path);309 free(path);
229 }310 }
230 } else {311 } else {
231 /* random move */312 /* 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);
233 }316 }
234 }317 }
235 318
@@ -240,11 +323,10 @@ void · 4 unmodified lines
240threadmain(int argc, char *argv[])323threadmain(int argc, char *argv[])
241{324{
242 Rune c;325 Rune c;
326 Msg *l, *lp;
243 327
244 /* of viewport, in size of tiles */328 /* of viewport, in size of tiles */
245 int width, height, movdir;329 int move, dir;
246 Rectangle r;
247 Point p;
248 Tile *t;330 Tile *t;
249 331
250 ARGBEGIN{332 ARGBEGIN{
@@ -252,112 +334,131 @@ threadmain(int argc, char *argv[]) · 1 unmodified line
252 334
253 srand(truerand());335 srand(truerand());
254 336
255 if(initdraw(nil, nil, argv0) < 0)337 user = getenv("user");
256 sysfatal("initdraw: %r");
257
258 if((mc = initmouse(nil, screen)) == nil)
259 sysfatal("initmouse: %r");
260 338
261 if((kc = initkeyboard(nil)) == nil)339 initui(argv0);
262 sysfatal("initkeyboard: %r");
263
264 if((tiles = opentile("nethack.32x32", 32, 32)) == nil)
265 sysfatal("opentile: %r");
266 340
267 if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE)) == nil)341 if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE)) == nil)
268 sysfatal("genlevel: %r");342 sysfatal("genlevel: %r");
269 343
270 /* the player */344 /* the player */
271 pos = level->up;345 player = monst(TWIZARD);
272 t = tileat(level, pos);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);
273 t->unit = TWIZARD;352 t->unit = TWIZARD;
274 setflagat(level, pos, Fhasmonster|Fblocked);353 t->monst = player;
275 354 setflagat(level, player->pt, Fhasmonster|Fblocked);
276 width = Dx(screen->r) / tiles->width;
277 height = Dy(screen->r) / tiles->height;
278 355
279 r = view(pos, level, width, height);356 redraw(&ui, 1);
280 campos = subpt(Pt(width/2, height/2), pos);
281 357
282 drawlevel(level, tiles, r);358 enum { AMOUSE, ARESIZE, AKEYBOARD, ALOG, AEND };
283 flushimage(display, 1);
284
285 enum { AMOUSE, ARESIZE, AKEYBOARD, AEND };
286 Alt a[AEND+1] = {359 Alt a[AEND+1] = {
287 { mc->c, nil, CHANRCV },360 { ui.mc->c, nil, CHANRCV },
288 { mc->resizec, nil, CHANRCV },361 { ui.mc->resizec, nil, CHANRCV },
289 { kc->c, &c, CHANRCV },362 { ui.kc->c, &c, CHANRCV },
290 { nil, nil, CHANEND },363 { ui.msgc, &l, CHANRCV },
364 { nil, nil, CHANEND },
291 };365 };
292 366
367 static int turns=0;
368
293 for(;;){369 for(;;){
294 switch(alt(a)){370 switch(alt(a)){
295 case AMOUSE:371 case AMOUSE:
296 break;372 break;
297 case ARESIZE:373 case ARESIZE:
298 if(getwindow(display, Refnone) < 0)374 redraw(&ui, 1);
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);
308 break;375 break;
309 case AKEYBOARD:376 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
311 switch(c){392 switch(c){
312 case Kdel:393 case Kdel:
313 threadexitsall(nil);394 threadexitsall(nil);
314 break;395 break;
315 case 'h':396 case 'h':
316 case Kleft:397 case Kleft:
317 movdir = WEST;398 move = MMOVE;
399 dir = WEST;
318 break;400 break;
319 case 'j':401 case 'j':
320 case Kdown:402 case Kdown:
321 movdir = SOUTH;403 move = MMOVE;
404 dir = SOUTH;
322 break;405 break;
323 case 'k':406 case 'k':
324 case Kup:407 case Kup:
325 movdir = NORTH;408 move = MMOVE;
409 dir = NORTH;
326 break;410 break;
327 case 'l':411 case 'l':
328 case Kright:412 case Kright:
329 movdir = EAST;413 move = MMOVE;
414 dir = EAST;
330 break;415 break;
331 case '<':416 case '<':
332 movdir = UP;
333 break;
334 case '>':417 case '>':
335 movdir = DOWN;418 move = MUSE;
336 break;419 break;
337 case '.':420 case '.':
338 movdir = DUMMY;
339 break;421 break;
422 case ' ':
423 msg("");
340 default:424 default:
341 /* don't waste a move */425 /* don't waste a move */
342 continue;426 continue;
343 }427 }
344 428
345 if(movdir != DUMMY){429 if(move != MNONE && dir != NODIR){
346 p=move(pos, movdir);430 if(maction(player, move, addpt(player->pt, cardinals[dir])) < 0)
347 if(!eqpt(p, ZP)){431 msg("ouch!");
348 pos = subpt(pos, p);
349 }
350 }432 }
351 433
352 static int turns=0;434 if(++turns % 2 ==0){
353 if(++turns % 3 ==0){
354 movemons();435 movemons();
355 }436 }
356 437
357 r = view(pos, level, width, height);438 ainc(&turn);
358 campos = subpt(Pt(width/2, height/2), pos);439
359 drawlevel(level, tiles, r);440 if(player->hp < 2){
360 flushimage(display, 1);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);
361 break;462 break;
362 }463 }
363 }464 }
level.c+22−19
@@ -29,7 +29,7 @@ static void · 28 unmodified lines
29drunk1(Level *l, Point p, int n)29drunk1(Level *l, Point p, int n)
30{30{
31 int cur, last;31 int cur, last;
32 Point next, dir[] = { Pt(1, 0), Pt(-1, 0), Pt(0, 1), Pt(0, -1) };32 Point next;
33 Rectangle clipr;33 Rectangle clipr;
34 Tile *t;34 Tile *t;
35 35
@@ -38,10 +38,10 @@ drunk1(Level *l, Point p, int n) · 2 unmodified lines
38 last = 0;38 last = 0;
39 while(n > 0){39 while(n > 0){
40 if(nrand(3) == 0)40 if(nrand(3) == 0)
41 cur = nrand(nelem(dir));41 cur = nrand(NCARDINAL);
42 else42 else
43 cur = last;43 cur = last;
44 next = addpt(p, dir[cur]);44 next = addpt(p, cardinals[cur]);
45 if(!ptinrect(next, clipr))45 if(!ptinrect(next, clipr))
46 continue;46 continue;
47 last = cur;47 last = cur;
@@ -62,7 +62,7 @@ drunken(Level *l, int type) · 14 unmodified lines
62 Point p, *path;62 Point p, *path;
63 Tile *t;63 Tile *t;
64 64
65 cnt = ((l->width * l->height) / 4); //* 2;65 cnt = ((l->width * l->height) / 8); //* 2;
66 66
67redo:67redo:
68 /* fill */68 /* fill */
@@ -92,40 +92,40 @@ redo: · 23 unmodified lines
92static void92static void
93gen(Level *l)93gen(Level *l)
94{94{
95 int i, q, rnd, space;95 int i, q, rnd, space, npath;
96 Point pup, pdown, p;96 Point pup, pdown, p, *path;
97 Tile *t;97 Tile *t;
98 98 Monster *m;
99 space = l->width*l->height;
100 99
101 pup = (Point){nrand(l->width-4)+2, nrand(l->height-4)+2};100 pup = (Point){nrand(l->width-4)+2, nrand(l->height-4)+2};
102 tileat(l, pup)->feat = TUPSTAIR;101 tileat(l, pup)->feat = TUPSTAIR;
103 setflagat(l, pup, Fhasfeature);102 setflagat(l, pup, Fhasfeature|Fportal);
104 l->up = pup;103 l->up = pup;
105 104
106 space--;
107
108 while(1){105 while(1){
109 pdown = (Point){nrand(l->width-4)+2, nrand(l->height-4)+2};106 pdown = (Point){nrand(l->width-4)+2, nrand(l->height-4)+2};
110 /* already upstair? */107 /* already upstair? */
111 if(flagat(l, pdown) & Fhasfeature)108 if(flagat(l, pdown) & Fportal)
112 continue;109 continue;
113 /* too close? */110 /* too close? */
114 p = subpt(pup, pdown);111 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)
116 continue;116 continue;
117 setflagat(l, pdown, Fhasfeature);117 setflagat(l, pdown, Fhasfeature|Fportal);
118 tileat(l, pdown)->feat = TDOWNSTAIR;118 tileat(l, pdown)->feat = TDOWNSTAIR;
119 l->down = pdown;119 l->down = pdown;
120 break;120 break;
121 }121 }
122 122
123 space--;123 space = 0;
124 124
125 space -= drunken(l, TTREE);125 space += drunken(l, TTREE);
126 126
127 /* some monsters */127 /* some monsters */
128 q = (l->width*l->height) / 10;128 q = (l->width*l->height) / 20;
129 rnd = nrand(q)+q;129 rnd = nrand(q)+q;
130 for(i = 0; i < rnd && space > 10; i++){130 for(i = 0; i < rnd && space > 10; i++){
131 do {131 do {
@@ -134,8 +134,11 @@ gen(Level *l) · 2 unmodified lines
134 134
135 t = tileat(l, p);135 t = tileat(l, p);
136 q = nrand(4)+TSOLDIER;136 q = nrand(4)+TSOLDIER;
137 t->unit = q; //nrand(320);137 t->unit = q;
138 t->monst = monst(q);138 m = monst(q);
139 m->l = l;
140 m->pt = p;
141 t->monst = m;
139 setflagat(l, p, Fblocked|Fhasmonster);142 setflagat(l, p, Fblocked|Fhasmonster);
140 143
141 space--;144 space--;
mkfile+5−4
@@ -7,14 +7,15 @@ HFILES=\ · 6 unmodified lines
7 alg.h\7 alg.h\
8 8
9OFILES=\9OFILES=\
10 hack9.$O\10 alg.$O\
11 tile.$O\
12 camera.$O\11 camera.$O\
12 hack9.$O\
13 level.$O\13 level.$O\
14 path.$O\
15 alg.$O\
16 monst.$O\14 monst.$O\
17 monstdata.$O\15 monstdata.$O\
16 path.$O\
17 tile.$O\
18 util.$O\
18 19
19CLEANFILES=$O.alg20CLEANFILES=$O.alg
20 21
monst.c+78−1
@@ -27,7 +27,84 @@ monst(int idx) · 26 unmodified lines
27 return m;27 return m;
28 28
29missing:29missing:
30 werrstr("missing monster %d\n", idx);30 werrstr("missing monster %d", idx);
31 return nil;31 return nil;
32}32}
33 33
34int
35maction(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
7MonsterData monstdata[392] = {7MonsterData monstdata[392] = {
8[TLARGECAT] {"large cat", 5, 1},8[TLARGECAT] {"large cat", 5, 1},
9[TGWIZARD] {"gnomish wizard", 1, 1},9[TGWIZARD] {"gnomish wizard", 1, 1},
10[TSOLDIER] {"soldier", 1, 1},10[TSOLDIER] {"soldier", 4, 1},
11[TSERGEANT] {"sergeant", 2, 1},11[TSERGEANT] {"sergeant", 8, 1},
12[TLIEUTENANT] {"lieutenant", 3, 1},12[TLIEUTENANT] {"lieutenant", 16, 1},
13[TCAPTAIN] {"captain", 4, 1},13[TCAPTAIN] {"captain", 32, 1},
14[TWIZARD] {"wizard", 100, 2},
14};15};
15 16

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