| @@ -9,29 +9,126 @@ · 8 unmodified lines |
| 9 | | 9 | |
| 10 | enum | 10 | enum |
| 11 | { | 11 | { |
| 12 | LSIZE = 10, | 12 | LSIZE = 20, |
| 13 | }; | 13 | }; |
| 14 | | 14 | |
| 15 | Mousectl *mc; | 15 | static long turn = 0; |
| 16 | Keyboardctl *kc; | 16 | static Level *level; |
| | 17 | static char *user; |
| | 18 | static Monster *player; |
| | 19 | static int gameover = 0; |
| 17 | | 20 | |
| 18 | Tileset *tiles; | 21 | enum |
| 19 | Level *level; | 22 | { |
| | 23 | CGREEN, |
| | 24 | CYELLOW, |
| | 25 | CORANGE, |
| | 26 | CRED, |
| | 27 | CGREY, |
| | 28 | }; |
| 20 | | 29 | |
| 21 | /* in tiles */ | 30 | typedef struct Msg Msg; |
| 22 | Point campos; | 31 | struct Msg |
| | 32 | { |
| | 33 | char msg[256]; |
| | 34 | ulong color; |
| | 35 | Msg *next; |
| | 36 | }; |
| 23 | | 37 | |
| 24 | /* of player */ | 38 | typedef struct UI UI; |
| 25 | Point pos; | 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 | 53 | static void |
| 28 | min(int a, int b) | 54 | initui(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 | |
| | 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 | /* 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 is | 133 | * 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 | |
| | 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 | Rectangle | 217 | Rectangle |
| 72 | view(Point pos, Level *l, int scrwidth, int scrheight) | 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 | 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 | |
| 84 | enum | 230 | void |
| | 231 | redraw(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 direction | 235 | if(new){ |
| 96 | * return delta in Point if moved, ZP if not */ | 236 | if(getwindow(display, Refnone) < 0) |
| 97 | static Point | 237 | sysfatal("getwindow: %r"); |
| 98 | move(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; | 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 | void | 268 | void |
| 192 | movemons(void) | 269 | movemons(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 |
| 240 | threadmain(int argc, char *argv[]) | 323 | threadmain(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 | } |