ref: d4cabc863723fbc7bc94d9223c27665a9f95ed26
dir: /demo/monsters.c/
#include <stdio.h> #include <stdlib.h> #include "dungeon_generator.h" #include "binheap.h" /* check if we can move to a location (objectively) */ Bool test_loc(Dungeon * dungeon, int x, int y, Sprite *s) { if(x > 0 && x < dungeon->w-1 && y > 0 && y < dungeon->h-1) { int hard = dungeon->d[y][x].h; if(dungeon->d[y][x].h < 255) { if(s->s.tu == FALSE && hard > 0) return FALSE; return TRUE; } } return FALSE; } /* checks if a given sprite shares a room with the PC */ void with_pc(Dungeon * dungeon, Sprite * s, Bool *in) { int pc_rid = -1; int s_rid = -1; Sprite *pc = &(dungeon->ss[dungeon->pc]); int i; for(i = 0; i < dungeon->nr; i++) { if(s->p.x <= dungeon->r[i].br.x && s->p.y <= dungeon->r[i].br.y && s->p.x >= dungeon->r[i].tl.x && s->p.y >= dungeon->r[i].tl.y) { s_rid = i; } if(pc->p.x <= dungeon->r[i].br.x && pc->p.y <= dungeon->r[i].br.y && pc->p.x >= dungeon->r[i].tl.x && pc->p.y >= dungeon->r[i].tl.y) { pc_rid = i; } } if(pc_rid > 0 && s_rid > 0 && pc_rid == s_rid) *in = TRUE; } void gen_move_sprite(Dungeon * dungeon, int sn) { //make ss[sn] when possible int sx = dungeon->ss[sn].p.x; int sy = dungeon->ss[sn].p.y; int xs[8] = {-1,0,1,1,1,0,-1,-1}; int ys[8] = {-1,-1,-1,0,1,1,1,0}; Sprite *s = &(dungeon->ss[sn]); /* increment the turn */ dungeon->ss[sn].t += (100 / s->s.s); Position new = {-1, -1}; dungeon->d[s->p.y][s->p.x].h -= 85; if(dungeon->d[s->p.y][s->p.x].h < 0) dungeon->d[s->p.y][s->p.x].h = 0; // make sure we're alive if(s->a == TRUE) { int i; int j; int eb = rand() % 2; /* we have a 50% chance to behave erratically */ for(i = 0; i < 8; i++) { int px = sx + xs[i]; int py = sy + ys[i]; if(px >= 0 && px < dungeon->w && py >= 0 && py < dungeon->h) { /* drunken PC movement as per assignment 1.04 */ /* check erratic behaviour */ if(s->s.eb == FALSE || (s->s.eb == TRUE && eb)) { /** check if intelligent / telepathic **/ //new.x = sx; //new.y = sy; if(s->s.te == FALSE) { /* see if you're in the same room */ Bool in_room = FALSE; with_pc(dungeon, s, &in_room); if(in_room == TRUE) { //cache PC location s->pc = dungeon->ss[dungeon->pc].p; IN: ; if(s->s.in == TRUE) { /* we are intelligent and can see our mark (tele or otherwise) */ int k; int lowest = 0; Bool set = FALSE; if(s->s.tu) { //tunneling for(k = 0; k < 8; k++) { if(xs[k]+sx >= 0 && xs[k]+sx < dungeon->w && ys[k]+sy >= 0 && ys[k]+sy < dungeon->h) { if(dungeon->d[ys[k]+sy][xs[k]+sx].h < 255 && dungeon->cst[ys[k]+sy][xs[k]+sx] < dungeon->cst[ys[lowest]+sy][xs[lowest]+sx] && test_loc(dungeon, xs[k]+sx, ys[k]+sy, s) == TRUE && test_loc(dungeon, xs[lowest]+sx, ys[lowest]+sy, s) == TRUE) { lowest = k; set = TRUE; } } } } else { //non-tunneling for(k = 0; k < 8; k++) { px = xs[k]+sx; py = ys[k]+sy; if(px >= 0 && px < dungeon->w && py >= 0 && py < dungeon->h) { if(dungeon->d[py][px].h == 0 && dungeon->csnt[py][px] <= dungeon->csnt[ys[lowest]+sy][xs[lowest]+sx]) { lowest = k; set = TRUE; } } } /* for(k = 0; k < 8; k++) { if(xs[k]+sx >= 0 && xs[k]+sx < dungeon->w && ys[k]+sy >= 0 && ys[k]+sy < dungeon->h) { if(dungeon->d[ys[k]+sy][xs[k]+sx].h < 255 && dungeon->csnt[ys[k]+sy][xs[k]+sx] < dungeon->csnt[ys[lowest]+sy][xs[lowest]+sx] && test_loc(dungeon, xs[k]+sx, ys[k]+sy, s) == TRUE && test_loc(dungeon, xs[lowest]+sx, ys[lowest]+sy, s) == TRUE) { lowest = k; set = TRUE; } } } */ } if(set == TRUE) { new.x = xs[lowest] + sx; new.y = ys[lowest] + sy; break; } else { new.x = sx; new.y = sy; break; } /* if(test_loc(dungeon, px, py, s) == TRUE) { //if we can move to the point if(s->s.tu) { //tunneling if(new.x > 0 && new.y > 0 && new.x != sx && new.y != sy) { if(dungeon->cst[py][px] < dungeon->cst[new.y][new.x]) { new.x = px; new.y = py; } } else { new.x = px; new.y = py; } } else { //non-tunneling if(new.x > 0 && new.y > 0 && new.x != sx && new.y != sy) { if(dungeon->csnt[py][px] < dungeon->csnt[new.y][new.x]) { new.x = px; new.y = py; } } else { new.x = px; new.y = py; } } } */ } else { //if not intelligent if(s->pc.x < sx) px = sx - 1; if(s->pc.x > sx) px = sx + 1; if(s->pc.y < sy) py = sy - 1; if(s->pc.y > sy) py = sy + 1; if(test_loc(dungeon, px, py, s) == TRUE) { new.x = px; new.y = py; break; } } } else { //not in the same room and not telepathic //randomize goto PCEB; } } else { //we know where the PC is s->pc = dungeon->ss[dungeon->pc].p; /** intelligence test still applies we just treat it as if we're always in the room " " **/ goto IN; } //printf("%c in room? %d\n",s->c , in_room); } else { /* we are erratically behaving */ PCEB: ; j = 0; EB: ; int c = rand() % 9; px = xs[c] + sx; py = ys[c] + sy; /* try to find a place to go up to n times */ if(test_loc(dungeon, px, py, s) == FALSE && j < 8) { j++; goto EB; } if(test_loc(dungeon, px, py, s) == TRUE) { /* if the location is okay, commit it*/ new.x = px; new.y = py; } break; } } } } /* safety net */ if(new.x < 0) new.x = sx; if(new.y < 0) new.y = sy; dungeon->ss[sn].to.x = new.x; dungeon->ss[sn].to.y = new.y; if(new.x == dungeon->ss[dungeon->pc].p.x && new.y == dungeon->ss[dungeon->pc].p.y) dungeon->go = TRUE; /* check if we have to kill another sprite */ int i; for(i = 0; i < dungeon->ns; i++) { if(i != sn) { if((dungeon->ss[i].to.x == dungeon->ss[sn].to.x) && (dungeon->ss[i].to.y == dungeon->ss[sn].to.y) && dungeon->ss[sn].a == TRUE) dungeon->ss[i].a = FALSE; /* else if(dungeon->ss[i].p.x == dungeon->ss[sn].p.x && dungeon->ss[i].p.y == dungeon->ss[sn].p.y && dungeon->ss[i].a == TRUE) dungeon->ss[sn].a = FALSE; */ } } } /* parse and apply a movement */ void parse_move(Dungeon * dungeon, int sn) { dungeon->ss[sn].p.x = dungeon->ss[sn].to.x; dungeon->ss[sn].p.y = dungeon->ss[sn].to.y; } /* move a sprite following its built in rules */ Event gen_move_sprite_old(Dungeon * dungeon, int sn) { Event e; int xs[8] = {-1,0,1,1,1,0,-1,-1}; int ys[8] = {-1,-1,-1,0,1,1,1,0}; int sx = dungeon->ss[sn].p.x; int sy = dungeon->ss[sn].p.y; Sprite s = dungeon->ss[sn]; int qp = -1; /* increment the turn */ dungeon->ss[sn].t += (100 / s.s.s); int i; for(i = 0; i < 8; i++) { int x = sx + xs[i]; int y = sy + ys[i]; if(x > 0 && x < dungeon->w-1 && y > 0 && y < dungeon->h-1) { int hard = dungeon->d[y][x].h; if(hard < 255) { /* check for erratic behaviour */ if(s.s.eb == TRUE) { int b = rand() % 2; if(b) { goto RP; } } /* check if tunneling */ if(hard > 0 && s.s.tu == FALSE) { continue; } /* check for line of sight / telepathic */ if(s.s.te == FALSE) { /* if line of sight ;; path and cache -> exit ;; else go to RP ; */ if(dungeon->d[y][x].c == '.') { } else { goto RP; } } else { /* path direct to PC if possible */ Sprite pc = dungeon->ss[dungeon->pc]; if(sx < pc.p.x) x = sx + 1; if(sx > pc.p.x) x = sx - 1; if(sy < pc.p.y) y = sy + 1; if(sy > pc.p.y) y = sy - 1; } /* check for lowest if intelligent */ if(s.s.in == TRUE) { if(s.s.tu == TRUE) { if(dungeon->cst[ys[qp]+sy][xs[qp]+sx] > dungeon->cst[y][x] || qp == -1) { qp = i; } } else { if(dungeon->csnt[ys[qp]+sy][xs[qp]+sx] > dungeon->csnt[y][x] || qp == -1) { qp = i; } } } else { RP: ; qp = rand() % 9; break; } } } } return e; } /* add a sprite to the dungeon */ void add_sprite(Dungeon * dungeon, Sprite s) { if(dungeon->ns < dungeon->ms) { dungeon->ns++; } else { goto END; } if(s.c == '@') { dungeon->pc = dungeon->ns - 1; } dungeon->ss[dungeon->ns - 1] = s; END: ; } /* generate a sprite, because in-line structs are icky if r(oom) = 1 then x and y will be ignored and should be passed as -1 as such (normally meaning random) */ Sprite gen_sprite(Dungeon * dungeon, char c, int x, int y, int r) { Sprite s; s.c = c; s.a = TRUE; /* set stats */ if(s.c == '@') { s.s.s = 10; s.s.tu = FALSE; s.s.eb = FALSE; s.s.te = FALSE; s.s.in = FALSE; } else { /* if not the pc a value 5-20 */ s.s.s = (rand() % 16) + 5; /* generate stats */ s.s.in = rand() % 2; s.s.te = rand() % 2; s.s.tu = rand() % 2; s.s.eb = rand() % 2; /* set character as per assignment 4 */ if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == FALSE) s.c = '0'; else if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == TRUE) s.c = '1'; else if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == FALSE) s.c = '2'; else if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == TRUE) s.c = '3'; else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == FALSE) s.c = '4'; else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == TRUE) s.c = '5'; else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == FALSE) s.c = '6'; else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == TRUE) s.c = '7'; else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == FALSE) s.c = '8'; else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == TRUE) s.c = '9'; else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == FALSE) s.c = 'a'; else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == TRUE) s.c = 'b'; else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == FALSE) s.c = 'c'; else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == TRUE) s.c = 'd'; else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == FALSE) s.c = 'e'; else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == TRUE) s.c = 'f'; } /* put the tunneling monsters anywhere */ if(s.s.tu == TRUE) { int t = 0; PRT: ; /* randomize location anywhere in the dungeon */ if(x < 0 || x > dungeon->w) { x = (rand() % (dungeon->w-2)) + 1; } if(y < 0 || y > dungeon->h) { y = (rand() % (dungeon->h-2)) + 1; } if(s.c != '@' && dungeon->nr > 1) { s.p.x = x; s.p.y = y; Bool w_pc = FALSE; with_pc(dungeon, &s, &w_pc); if(w_pc == TRUE && t < 8) { t++; goto PRT; } } } /* place in a room if 1 or more. implicitly random ;; force in a room even if tunneling */ if(r > 0 || s.s.tu == FALSE) { int t = 0; PRNT: ; int r_id = rand() % dungeon->nr; x = (rand() % dungeon->r[r_id].w) + dungeon->r[r_id].tl.x; y = (rand() % dungeon->r[r_id].h) + dungeon->r[r_id].tl.y; if(s.c != '@' && dungeon->nr > 1) { s.p.x = x; s.p.y = y; Bool w_pc = FALSE; with_pc(dungeon, &s, &w_pc); if(w_pc == TRUE && t < 8) { t++; goto PRNT; } } } else { } s.p.x = x; s.p.y = y; s.to.x = x; s.to.y = y; //s.t = 100/s.s.s; s.t = 0; return s; } /* checks if any monsters other than the player are alive */ Bool check_any_monsters(Dungeon * dungeon) { int i; for(i = 0; i < dungeon->ns; i++) { if(dungeon->ss[i].a == TRUE && i != 0) return TRUE; } return FALSE; }