| @@ -9,29 +9,126 @@ · 8 unmodified lines |
| 9 | 9 | |
| 10 | 10 | enum |
| 11 | 11 | { |
| 12 | | − LSIZE = 10, |
| 12 | + LSIZE = 20, |
| 13 | 13 | }; |
| 14 | 14 | |
| 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; |
| 17 | 20 | |
| 18 | | −Tileset *tiles; |
| 19 | | −Level *level; |
| 21 | +enum |
| 22 | +{ |
| 23 | + CGREEN, |
| 24 | + CYELLOW, |
| 25 | + CORANGE, |
| 26 | + CRED, |
| 27 | + CGREY, |
| 28 | +}; |
| 20 | 29 | |
| 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 | +}; |
| 23 | 37 | |
| 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; |
| 26 | 52 | |
| 27 | | −static int |
| 28 | | −min(int a, int b) |
| 53 | +static void |
| 54 | +initui(char *name) |
| 29 | 55 | { |
| 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); |
| 33 | 111 | } |
| 34 | 112 | |
| 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 | + |
| 35 | 132 | /* draw the whole level on the screen using tileset ts. |
| 36 | 133 | * r.min is the upper left visible tile, and r.max is |
| 37 | 134 | * the bottom right visible tile. |
| @@ -43,15 +140,13 @@ drawlevel(Level *l, Tileset *ts, Rectangle r) · 5 unmodified lines |
| 43 | 140 | Point xy, tpos; |
| 44 | 141 | Tile *t; |
| 45 | 142 | |
| 46 | | − draw(screen, screen->r, display->black, nil, ZP); |
| 47 | | − |
| 48 | 143 | for(x = r.min.x; x < r.max.x; x++){ |
| 49 | 144 | for(y = r.min.y; y < r.max.y; y++){ |
| 50 | 145 | /* world cell */ |
| 51 | 146 | xy = (Point){x, y}; |
| 52 | 147 | /* screen space */ |
| 53 | 148 | tpos = xy; |
| 54 | | − tpos = addpt(tpos, campos); |
| 149 | + tpos = addpt(tpos, ui.camp); |
| 55 | 150 | tpos.x *= ts->width; |
| 56 | 151 | tpos.y *= ts->height; |
| 57 | 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 | |
| 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 | + |
| 71 | 217 | Rectangle |
| 72 | 218 | view(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 | 221 | Rectangle r; |
| 76 | 222 | |
| 77 | 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 | 225 | r = Rpt(subpt(pos, p), addpt(pos, p)); |
| 80 | 226 | rectclip(&r, Rect(0, 0, l->width, l->height)); |
| 81 | 227 | return r; |
| 82 | 228 | } |
| 83 | 229 | |
| 84 | | −enum |
| 230 | +void |
| 231 | +redraw(UI *ui, int new) |
| 85 | 232 | { |
| 86 | | − DUMMY, |
| 87 | | − WEST, |
| 88 | | − NORTH, |
| 89 | | − EAST, |
| 90 | | − SOUTH, |
| 91 | | − UP, |
| 92 | | − DOWN, |
| 93 | | −}; |
| 233 | + int width, height; |
| 94 | 234 | |
| 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"); |
| 104 | 238 | |
| 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; |
| 156 | 243 | } |
| 157 | | − break; |
| 158 | | − } |
| 159 | 244 | |
| 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 | + } |
| 171 | 247 | |
| 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); |
| 186 | 255 | } |
| 256 | + drawui(ui->uir); |
| 257 | + flushimage(display, 1); |
| 258 | +} |
| 187 | 259 | |
| 188 | | − return ZP; |
| 260 | +static int |
| 261 | +min(int a, int b) |
| 262 | +{ |
| 263 | + if(a < b) |
| 264 | + return a; |
| 265 | + return b; |
| 189 | 266 | } |
| 190 | 267 | |
| 191 | 268 | void |
| 192 | 269 | movemons(void) |
| 193 | 270 | { |
| 194 | | − int i, movdir, nmove, npath; |
| 271 | + int i, nmove, npath; |
| 195 | 272 | Point p, p2, *tomove, *path; |
| 273 | + Monster *m; |
| 196 | 274 | |
| 197 | 275 | nmove = 0; |
| 198 | 276 | for(p.x = 0; p.x < level->width; p.x++){ |
| 199 | 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 | 279 | nmove++; |
| 202 | 280 | } |
| 203 | 281 | } |
| @@ -209,27 +287,32 @@ movemons(void) · 5 unmodified lines |
| 209 | 287 | i = 0; |
| 210 | 288 | for(p.x = 0; p.x < level->width; p.x++){ |
| 211 | 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 | 291 | tomove[i++] = p; |
| 214 | 292 | } |
| 215 | 293 | } |
| 216 | 294 | |
| 217 | 295 | for(i = 0; i < nmove; i++){ |
| 218 | 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 | 304 | /* move the monster toward player */ |
| 221 | | − npath = pathfind(level, p, pos, &path); |
| 305 | + npath = pathfind(level, m->pt, player->pt, &path); |
| 222 | 306 | if(npath >= 0){ |
| 223 | 307 | /* 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]); |
| 228 | 309 | free(path); |
| 229 | 310 | } |
| 230 | 311 | } else { |
| 231 | 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 |
| 240 | 323 | threadmain(int argc, char *argv[]) |
| 241 | 324 | { |
| 242 | 325 | Rune c; |
| 326 | + Msg *l, *lp; |
| 243 | 327 | |
| 244 | 328 | /* of viewport, in size of tiles */ |
| 245 | | − int width, height, movdir; |
| 246 | | − Rectangle r; |
| 247 | | − Point p; |
| 329 | + int move, dir; |
| 248 | 330 | Tile *t; |
| 249 | 331 | |
| 250 | 332 | ARGBEGIN{ |
| @@ -252,112 +334,131 @@ threadmain(int argc, char *argv[]) · 1 unmodified line |
| 252 | 334 | |
| 253 | 335 | srand(truerand()); |
| 254 | 336 | |
| 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"); |
| 260 | 338 | |
| 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); |
| 266 | 340 | |
| 267 | 341 | if((level = genlevel(nrand(LSIZE)+LSIZE, nrand(LSIZE)+LSIZE)) == nil) |
| 268 | 342 | sysfatal("genlevel: %r"); |
| 269 | 343 | |
| 270 | 344 | /* 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); |
| 273 | 352 | 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); |
| 278 | 355 | |
| 279 | | − r = view(pos, level, width, height); |
| 280 | | − campos = subpt(Pt(width/2, height/2), pos); |
| 356 | + redraw(&ui, 1); |
| 281 | 357 | |
| 282 | | − drawlevel(level, tiles, r); |
| 283 | | − flushimage(display, 1); |
| 284 | | − |
| 285 | | − enum { AMOUSE, ARESIZE, AKEYBOARD, AEND }; |
| 358 | + enum { AMOUSE, ARESIZE, AKEYBOARD, ALOG, AEND }; |
| 286 | 359 | 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 }, |
| 291 | 365 | }; |
| 292 | 366 | |
| 367 | + static int turns=0; |
| 368 | + |
| 293 | 369 | for(;;){ |
| 294 | 370 | switch(alt(a)){ |
| 295 | 371 | case AMOUSE: |
| 296 | 372 | break; |
| 297 | 373 | 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); |
| 308 | 375 | break; |
| 309 | 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 | 392 | switch(c){ |
| 312 | 393 | case Kdel: |
| 313 | 394 | threadexitsall(nil); |
| 314 | 395 | break; |
| 315 | 396 | case 'h': |
| 316 | 397 | case Kleft: |
| 317 | | − movdir = WEST; |
| 398 | + move = MMOVE; |
| 399 | + dir = WEST; |
| 318 | 400 | break; |
| 319 | 401 | case 'j': |
| 320 | 402 | case Kdown: |
| 321 | | − movdir = SOUTH; |
| 403 | + move = MMOVE; |
| 404 | + dir = SOUTH; |
| 322 | 405 | break; |
| 323 | 406 | case 'k': |
| 324 | 407 | case Kup: |
| 325 | | − movdir = NORTH; |
| 408 | + move = MMOVE; |
| 409 | + dir = NORTH; |
| 326 | 410 | break; |
| 327 | 411 | case 'l': |
| 328 | 412 | case Kright: |
| 329 | | − movdir = EAST; |
| 413 | + move = MMOVE; |
| 414 | + dir = EAST; |
| 330 | 415 | break; |
| 331 | 416 | case '<': |
| 332 | | − movdir = UP; |
| 333 | | − break; |
| 334 | 417 | case '>': |
| 335 | | − movdir = DOWN; |
| 418 | + move = MUSE; |
| 336 | 419 | break; |
| 337 | 420 | case '.': |
| 338 | | − movdir = DUMMY; |
| 339 | 421 | break; |
| 422 | + case ' ': |
| 423 | + msg(""); |
| 340 | 424 | default: |
| 341 | 425 | /* don't waste a move */ |
| 342 | 426 | continue; |
| 343 | 427 | } |
| 344 | 428 | |
| 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!"); |
| 350 | 432 | } |
| 351 | 433 | |
| 352 | | − static int turns=0; |
| 353 | | − if(++turns % 3 ==0){ |
| 434 | + if(++turns % 2 ==0){ |
| 354 | 435 | movemons(); |
| 355 | 436 | } |
| 356 | 437 | |
| 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); |
| 361 | 462 | break; |
| 362 | 463 | } |
| 363 | 464 | } |