#include #include #include #include #include #include "see.h" #include "obj.h" #include "mon.h" #include "vars.h" #include "util.h" #include "dice.h" #include "time.h" #include "main.h" #include "pline.h" #include "trail.h" #include "fight.h" #include "fuses.h" #include "debug.h" #include "screen.h" #include "options.h" #include "display.h" #include "obj-map.h" #include "signals.h" #include "montypes.h" #include "disputil.h" #include "objtypes.h" #include "obj-wand.h" #include "obj-scroll.h" #include "obj-potion.h" #include "stdio-util.h" #include "mon-@-you.h" #define MSGHISTSIZE 32 static char *pl_buf; static int pl_left; static int pl_left0; static char *pl_bp; static int plineoff = 0; static int auto_mapping = 1; static int invulnerable = 0; static int memory_mapping = 0; static int auto_map_switch = 1; typedef enum { RUN_NONE = 1, RUN_SHIFT, RUN_CTL } RUNSTATE; static RUNSTATE running = RUN_NONE; static int runcount = -1; static char *prefix = 0; static int prefix_a = 0; static int prefix_n = 0; static int prefix_clear = 0; static int repcount = 0; static int repcmd; static XY run_d; static LOC *startat; static int last_interrupt = 0; static int debugmsg = 0; static LEVEL *lastlevel = 0; static LOC *lastloc = 0; static int mh_initted = 0; static char *mh_text[MSGHISTSIZE]; static int mh_head; static int mh_tail; typedef struct xcmd XCMD; struct xcmd { const char *cmd; int (*fn)(void); } ; void inityou(void) { pl_buf = malloc(COLS); pl_left0 = COLS - 2; pl_left = pl_left0; pl_bp = pl_buf; } void extend_memory_mapping(int n) { memory_mapping += n; } static void off_pline(void) { int new; new = ! plineoff; plineoff = 0; pline("Messages %s",new?"off":"on"); plineoff = new; } void pline(const char *fmt, ...) { va_list ap; int l; int o; char *msg; FILE *f; if (plineoff) return; f = fopenmalloc(&msg); va_start(ap,fmt); vfprintf(f,fmt,ap); va_end(ap); fclose(f); l = strlen(msg); if ((l < pl_left-10) && strncmp(msg,"You",3)) { if (pl_bp != pl_buf) { *pl_bp++ = ' '; *pl_bp++ = ' '; pl_left -= 2; } bcopy(msg,pl_bp,l); pl_left -= l; pl_bp += l; return; } showmsgbuf(1); o = 0; while (l-o > pl_left0-10) { bcopy(msg+o,pl_buf,pl_left0-10); pl_bp = pl_buf + pl_left0-10; showmsgbuf(1); o += pl_left0 - 20; } bcopy(msg+o,pl_buf,l-o); pl_bp = pl_buf + (l-o); pl_left = pl_left0 - (l-o); } static void mh_init(void) { int i; if (mh_initted) return; mh_initted = 1; mh_head = 0; mh_tail = 0; for (i=MSGHISTSIZE-1;i>=0;i--) mh_text[i] = 0; } static void mh_save(const char *txt) { mh_init(); free(mh_text[mh_head]); mh_text[mh_head] = strdup(txt); mh_head = (mh_head + 1) % MSGHISTSIZE; if (mh_head == mh_tail) mh_tail = (mh_tail + 1) % MSGHISTSIZE; } void showmsgbuf(int more) { JMP j; if (setjmp(j.b)) { pop_sigint_throw(); } else { if (pl_bp == pl_buf) { move(MYO,0); clrtoeol(); return; } *pl_bp = '\0'; mvaddstr(MYO,0,pl_buf); mh_save(pl_buf); clrtoeol(); if (more) { addstr(" --More--"); refresh(); push_sigint_throw(&j); getch(); pop_sigint_throw(); } } pl_bp = pl_buf; pl_left = pl_left0; } void panic(const char *fmt, ...) { va_list ap; FILE *f; int wf(void *cookie __attribute__((__unused__)), const char *buf, int len) { addbytes(buf,len); return(len); } block_int(); showmsgbuf(1); mvaddstr(LINES-2,0,"PANIC: "); /* grrr, no vprintw */ f = funopen(0,0,wf,0,0); va_start(ap,fmt); vfprintf(f,fmt,ap); va_end(ap); fclose(f); clrtobot(); move(LINES-1,COLS-2); refresh(); getch(); cleanupscreen(); debugsig(0); abort(); } void impossible(void) { pline("Program in disorder, perhaps you'd better Quit"); } static void clearflag(LEVEL *lv, int flg) { int x; int y; LOC *lc; for (x=0;xcells[x][0]; for (y=0;yflags & flg) { lc->flags &= ~flg; upddisp1(lc); } lc ++; } } } void init_track(void) { int x; int y; int i; int j; LOC *lc; LOC *lc2; LEVEL *lv; TRAIL *pending; TRAIL *active; TRAIL *t; for (i=0;icells[x][0]; for (y=0;ytracks[j] = 0; lc->tracktime[j] = 0; } lc->exitdist = ~0U; lc ++; } } } pending = newtrail(); pending->link = 0; pending->loc = entrance; entrance->exitdist = 0; active = 0; while (1) { if (active == 0) { if (pending == 0) break; active = pending; pending = 0; continue; } t = active; active = t->link; lc = t->loc; freetrail(t); j = lc->exitdist + 1; for (i=0;i<8;i++) { lc2 = movecell(lc,delta[i][0],delta[i][1],0); if ( (lc2->type == LOC_GATE) || (lc2->type == LOC_DOOR) || (lc2->type == LOC_SDOOR) || (lc2->type == LOC_CAVE) ) { if (lc2->exitdist > j) { lc2->exitdist = j; t = newtrail(); t->link = pending; pending = t; t->loc = lc2; } } } if ( ( (lc->type == LOC_GATE) || ( (lc->type == LOC_CAVE) && ( (lc->cavetype == LOC_STAIRS_U) || (lc->cavetype == LOC_STAIRS_D) ) ) ) && (lc2=lc->to) && (lc2->exitdist > j) ) { lc2->exitdist = j; t = newtrail(); t->link = pending; pending = t; t->loc = lc2; } } } static void set_dumb_track(void) { LOC *lc; int i; LOC *lc2; lc = you->loc; for (i=0;i<8;i++) { lc2 = movecell(lc,delta[i][0],delta[i][1],0); if ( (lc2->type == LOC_GATE) || (lc2->type == LOC_DOOR) || (lc2->type == LOC_SDOOR) || (lc2->type == LOC_CAVE) ) { lc2->tracks[TRACK_DUMB] = lc; lc2->tracktime[TRACK_DUMB] = curtime; } } if ( ( (lc->type == LOC_GATE) || ( (lc->type == LOC_CAVE) && ( (lc->cavetype == LOC_STAIRS_U) || (lc->cavetype == LOC_STAIRS_D) ) ) ) && (lc2=lc->to) ) { lc2->tracks[TRACK_DUMB] = lc; lc2->tracktime[TRACK_DUMB] = curtime; } } static LOC *getdir(LOC *from) { LEVEL *lv; int x; int y; JMP j; if (setjmp(j.b)) { pop_sigint_throw(); return(0); } lv = from->on; while (1) { refresh(); push_sigint_throw(&j); x = getch(); pop_sigint_throw(); if (! dirkey(x,&x,&y,0,0,0)) return(0); x += from->x; y += from->y; if (lv->flags & LVF_WRAPAROUND) { if (x < 0) x += LEV_X; else if (x >= LEV_X) x -= LEV_X; if (y < 0) y += LEV_Y; else if (y >= LEV_Y) y -= LEV_Y; } else { if ((x < 0) || (y < 0) || (x >= LEV_X) || (y >= LEV_Y)) return(0); } return(&lv->cells[x][y]); } } static void bemoved_see(LOC *lc) { if (lc->objs.inv && lc->objs.inv->link) { INVOBJ *o; INVOBJ **op; o = lc->objs.inv; lc->objs.inv = o->link; for (op=(&lc->objs.inv);*op;op=(&(*op)->link)) ; *op = o; o->link = 0; /* no upddisp needed: seecell below always calls upddisp */ } seecell(lc); } static void set_smart_track(LOC *lc) { int x; int y; x = you->loc->x - lc->x; y = you->loc->y - lc->y; if ((x == 0) && (y == 0)) return; if (lc->on->flags & LVF_WRAPAROUND) { if (x > LEV_X/2) x -= LEV_X; else if (x < -LEV_X/2) x += LEV_X; if (y > LEV_Y/2) y -= LEV_Y; else if (y < -LEV_Y/2) y += LEV_Y; } if (x < 0) x = -1; else if (x > 0) x = 1; if (y < 0) y = -1; else if (y > 0) y = 1; x += lc->x; y += lc->y; if (lc->on->flags & LVF_WRAPAROUND) { if (x < 0) x += LEV_X; else if (x >= LEV_X) x -= LEV_X; if (y < 0) y += LEV_Y; else if (y >= LEV_Y) y -= LEV_Y; } if ((x < 0) || (x >= LEV_X) || (y < 0) || (y >= LEV_Y)) { panic("out of range in set_smart_track"); } lc->tracks[TRACK_SMART] = &lc->on->cells[x][y]; lc->tracktime[TRACK_SMART] = curtime; } static void set_smart_level_track(void) { LOC *lc; LOC *lc2; lc = you->loc; if ( ( (lc->type == LOC_GATE) || ( (lc->type == LOC_CAVE) && ( (lc->cavetype == LOC_STAIRS_U) || (lc->cavetype == LOC_STAIRS_D) ) ) ) && (lc2=lc->to) ) { lc2->tracks[TRACK_SMART] = lc; lc2->tracktime[TRACK_SMART] = curtime; } } static void map_vis_mem(void) { } static void map_vis(void) { int x; int y; LOC *l; if (! map) panic("invalid map_vis"); for (x=0;xloc->on->cells[x][0]; for (y=0;yflags & LF_VISIBLE) map_setcharat(map,x+mapox,y+mapoy,loc_char(l,LC_ORDINARY)); l ++; } } } static void you_bemoved(MONST *m) { LOC *lc; LEVEL *lv; int switched; lc = m->loc; lv = lc->on; if (lv != lastlevel) { clear(); cleardisp(); switched = 0; if (map && auto_map_switch) { if ((lastloc->type == LOC_CAVE) && (lastloc->to == lc)) { switch (lastloc->cavetype) { case LOC_STAIRS_U: switched = map_auto_switch_up(lv->longname); break; case LOC_STAIRS_D: switched = map_auto_switch_dn(lv->longname); break; default: break; } } else { LOC *lc2; lc2 = lastloc->tracks[TRACK_SMART]; if (lc2 && (lc2->type == LOC_GATE) && (lc2->to->on == lv)) { switched = map_auto_switch_gate(lc2,lv->longname); } } } if (! switched) map = 0; if (lastlevel) { clearflag(lastlevel,LF_VISIBLE); dispox += lastlevel->off.x - lv->off.x; dispoy += lastlevel->off.y - lv->off.y; } drawmapped(lv); lastlevel = lv; lastloc = 0; } if (lc != lastloc) { set_dumb_track(); clearflag(lv,LF_VISIBLE); seecell_loc = lc; see(lc,lv->visibility,LF_VISIBLE,&bemoved_see); if (auto_mapping && map) map_vis(); if (memory_mapping > 0) { map_vis_mem(); memory_mapping --; } see(lc,7,0,&set_smart_track); set_smart_level_track(); lastloc = lc; if (lc->objs.inv) pline("There's something here you could pick up."); } } static void search(void) { int i; LOC *lc; int found; found = 0; for (i=0;i<8;i++) { lc = movecell(you->loc,delta[i][0],delta[i][1],0); if (lc->type == LOC_SDOOR) { finddoor(lc); found = 1; } } if (found) resee(); } static int get_iline(const char *prompt, char *rbuf, int rblen, int ilen, const char *suffix, const char *xtc) { int rlen; int plen; int xoff; int c; int suflen; int cursx; JMP j; void fullredraw(void) { move(LINES-1,0); if (xoff > 0) addch('<'); else addch(' '); if (xoff < plen) { addstr(prompt+xoff); addbytes(rbuf,rlen); addbytes(suffix,suflen); } else if (xoff < plen+rlen) { addbytes(rbuf+(xoff-plen),rlen-(xoff-plen)); addbytes(suffix,suflen); } else { addbytes(suffix+(xoff-plen-rlen),suflen-(xoff-plen-rlen)); } clrtoeol(); } int shiftxoff(void) { if ((xoff > 0) && (plen+rlen+suflen-xoff < (COLS/4))) { xoff = plen + rlen + suflen - ((2*COLS)/3); if (xoff < 0) xoff = 0; return(1); } if (plen+rlen+suflen-xoff >= COLS-4) { xoff = plen + rlen + suflen - ((2*COLS)/3); return(1); } return(0); } if (setjmp(j.b)) { pop_sigint_throw(); rbuf[0] = '\0'; move(LINES-1,0); clrtoeol(); return('\33'); } suflen = strlen(suffix); plen = strlen(prompt); rlen = ilen; xoff = 0; shiftxoff(); fullredraw(); while (1) { if (shiftxoff()) fullredraw(); cursx = (xoff <= plen+rlen) ? 1+plen+rlen-xoff : 0; move(LINES-1,cursx); refresh(); push_sigint_throw(&j); c = getch(); pop_sigint_throw(); if ((c == '\177') || (c == '\b')) { if (rlen > 0) { rlen --; if (cursx) { move(LINES-1,cursx-1); addch(' '); } } } else if (c == '\33') { rlen = 0; break; } else if (c == '\f') { fullredraw(); } else if ((c == '\r') || (c == '\n') || index(xtc,c)) { break; } else if ((c >= ' ') && (c <= '~')) { if (rlen < rblen-1) { addch(c); rbuf[rlen++] = c; } else { beep(); } } if (suflen) { suffix = ""; suflen = 0; fullredraw(); } } rbuf[rlen] = '\0'; move(LINES-1,0); clrtoeol(); return(c); } static int get_n(const char *prompt, int starval) { int plen; int n; int n2; char nbuf[64]; int nblen; int c; JMP j; void fullredraw(void) { move(LINES-1,0); addbytes(prompt,plen); addbytes(&nbuf[0],nblen); clrtoeol(); } if (setjmp(j.b)) { pop_sigint_throw(); move(LINES-1,0); clrtoeol(); return(-1); } plen = strlen(prompt); n = 0; nblen = 0; fullredraw(); while (1) { move(LINES-1,plen+nblen); refresh(); push_sigint_throw(&j); c = getch(); pop_sigint_throw(); if ((c == '\177') || (c == '\b')) { if (nblen > 0) { nblen --; move(LINES-1,plen+nblen); addch(' '); n /= 10; } } else if (c == '\33') { n = -1; break; } else if (c == '\f') { fullredraw(); } else if ((c == '\r') || (c == '\n')) { if (nblen > 0) break; beep(); } else if ((c >= '0') && (c <= '9')) { if ((nblen == 0) || (n == 0)) { nbuf[0] = c; nblen = 1; n = c - '0'; move(LINES-1,plen); addch(c); } else { n2 = (n * 10) + (c - '0'); if (n2/10 != n) { beep(); } else { addch(c); nbuf[nblen++] = c; n = n2; } } } else if ((c == '*') && (nblen == 0)) { n = starval; break; } else { beep(); } } move(LINES-1,0); clrtoeol(); return(n); } static int you_inv_cmp(INVOBJ *io1, INVOBJ *io2) { OBJTYPE *ot1; OBJTYPE *ot2; char *ix1; char *ix2; const char order[] = "~)[:%(=/?!"; ot1 = &objtypes[io1->v[0]->type]; ot2 = &objtypes[io2->v[0]->type]; if (ot1->sym != ot2->sym) { ix1 = index(&order[0],ot1->sym); ix2 = index(&order[0],ot2->sym); if (ix1 && ix2) return(ix1-ix2); if (! ix1) pline("unknown symbol %c in you_inv_cmp",ot1->sym); if (! ix2) pline("unknown symbol %c in you_inv_cmp",ot2->sym); impossible(); } if (ot1->class != ot2->class) return(ot1->class-ot2->class); switch (ot1->class) { /*case OC_ARMOR: if (armor_worn(io1) && !armor_worn(io2)) return(-1); if (armor_worn(io2) && !armor_worn(io1)) return(1); break; case OC_WEAPON: if (weapon_wielded(io1) && !weapon_wielded(io2)) return(-1); if (weapon_wielded(io2) && !weapon_wielded(io1)) return(1); break;*/ case OC_MAP: if (io1->v[0] == map) return(-1); if (io2->v[0] == map) return(1); if (map_blank(io1->v[0])) { if (! map_blank(io2->v[0])) return(1); } else { if (map_blank(io2->v[0])) return(-1); } break; case OC_SCROLL: case OC_POTION: case OC_WAND: case OC_RING: if ((ot1->flags & ~ot2->flags) & OTF_KNOWN) return(-1); if ((ot2->flags & ~ot1->flags) & OTF_KNOWN) return(1); if (ot1->called && !ot2->called) return(-1); if (ot2->called && !ot1->called) return(1); break; } return(io1->xwi-io2->xwi); } static void sort_you_inv(void) { you->invent.inv = sort_inv(you->invent.inv,&you_inv_cmp); } static int drop(int mult) { INVOBJ *io; int n; int rv; sort_you_inv(); rv = 0; do { showmsgbuf(1); io = pick_inventory(&you->invent,"Drop what? ",&showinvent_all); if (io == 0) break; if (io->dispn > 1) { n = get_n("Drop how many? ",io->dispn); if (n < 1) { pline("Aborted."); continue; } if (n < io->dispn) io = inventory_split_n(io,-n,-1); } inv_move_1(&you->invent,io,&you->loc->objs); pline("Dropped."); rv = 1; } while (mult); return(rv); } static int showinvent_readable(INVOBJ *io) { return(objtypes[io->v[0]->type].class == OC_SCROLL); } static int read(void) { INVOBJ *io; INVOBJ *n; sort_you_inv(); io = pick_inventory(&you->invent,"Read what? ",&showinvent_readable); if (io == 0) return(0); if (io->dispn > 1) { n = inventory_split_n(io,-1,find_xwi(&you->invent)); if (n) io = n; } read_it(io); return(1); } static int showinvent_quaffable(INVOBJ *io) { return(objtypes[io->v[0]->type].class == OC_POTION); } static int quaff(void) { INVOBJ *io; INVOBJ *n; sort_you_inv(); io = pick_inventory(&you->invent,"Quaff what? ",&showinvent_quaffable); if (io == 0) return(0); if (io->dispn > 1) { n = inventory_split_n(io,-1,find_xwi(&you->invent)); if (n) io = n; } quaff_it(io); return(1); } static int showinvent_zappable(INVOBJ *io) { return(objtypes[io->v[0]->type].class == OC_WAND); } static int zap(void) { INVOBJ *io; INVOBJ *n; sort_you_inv(); io = pick_inventory(&you->invent,"Zap what? ",&showinvent_zappable); if (io == 0) return(0); if (io->dispn > 1) { n = inventory_split_n(io,-1,find_xwi(&you->invent)); if (n) io = n; } zap_it(io); return(1); } static int pickup(void) { INVOBJ *io; int n; int rv; char *msg; FILE *f; rv = 0; while (you->loc->objs.inv) { showmsgbuf(1); io = pick_inventory(&you->loc->objs,"Pick up what? ",&showinvent_all); if (io == 0) break; if (io->dispn > 1) { n = get_n("Pick up how many? ",io->dispn); if (n < 1) continue; if (n < io->dispn) io = inventory_split_n(io,-n,-1); } io = inv_move_1(&you->loc->objs,io,&you->invent); f = fopenmalloc(&msg); format_inv_line(io,f); fclose(f); pline(msg); rv = 1; } return(rv); } static void auto_map_toggle(void) { auto_mapping = ! auto_mapping; pline("Automatic mapping turned %s",auto_mapping?"on":"off"); } static void vulnerability_toggle(void) { invulnerable = ! invulnerable; pline("Invulnerability turned %s",invulnerable?"on":"off"); } static int x_cmd(const char *prompt, const XCMD *cmdtab) { char cmdbuf[32]; int i; int l; int p; int c; JMP j; l = 0; if (setjmp(j.b)) { pop_sigint_throw(); c = '\33'; } else { c = get_iline(prompt,&cmdbuf[0],sizeof(cmdbuf),l,""," ?"); } while (1) { l = strlen(&cmdbuf[0]); if (c == '?') { int x; int cl; void morebreak(const char *s) { addstr(s); push_sigint_throw(&j); getch(); pop_sigint_throw(); move(LINES-2,0); clrtoeol(); } move(LINES-2,0); clrtoeol(); x = 0; for (i=0;cmdtab[i].cmd;i++) { cl = strlen(cmdtab[i].cmd); if ((cl < l) || strncmp(cmdtab[i].cmd,&cmdbuf[0],l)) continue; if (x && (x+1+cl >= COLS-10)) { morebreak(" --More--"); x = 0; } if (x) { addch(' '); x ++; } addstr(cmdtab[i].cmd); x += cl; } morebreak(" --End--"); c = get_iline(prompt,&cmdbuf[0],sizeof(cmdbuf),l,""," ?"); continue; } move(LINES-1,0); clrtoeol(); if (! cmdbuf[0]) return(0); p = -1; for (i=0;cmdtab[i].cmd;i++) { if (!strcmp(&cmdbuf[0],cmdtab[i].cmd)) return((*cmdtab[i].fn)()); if (!strncmp(&cmdbuf[0],cmdtab[i].cmd,l)) { if (p == -1) p = i; else p = -2; } } if (p >= 0) return((*cmdtab[p].fn)()); c = get_iline(prompt,&cmdbuf[0],sizeof(cmdbuf),l,(p==-1)?" [no match]":" [ambiguous]"," ?"); } } static int showinvent_map(INVOBJ *io) { return(io->v[0]->type == OBJ_MAP); } static int xcmd_map_use(void) { INVOBJ *io; OBJ *m; int ox; int oy; OBJ *msave; int rv; sort_you_inv(); io = pick_inventory(&you->invent,"Use which map? ",&showinvent_map); if (io == 0) return(0); m = io->v[0]; if (map_blank(m)) { inventory_split_n(io,1,find_xwi(&you->invent)); map = io->v[0]; mapox = 0; mapoy = 0; pline("This map is blank."); return(1); } msave = map; map = 0; cleardisp(); drawmapped(you->loc->on); map = msave; if (place_map(m,&ox,&oy,"Position the map...")) { map = m; mapox = ox; mapoy = oy; pline("Done."); rv = 1; } else { pline("Aborted."); rv = 0; } cleardisp(); drawmapped(you->loc->on); return(rv); } static int xcmd_map_view(void) { INVOBJ *io; OBJ *m; sort_you_inv(); io = pick_inventory(&you->invent,"View which map? ",&showinvent_map); if (io == 0) return(0); m = io->v[0]; if (map_blank(m)) { pline("This map is blank."); return(0); } view_map(m); return(1); } static int xcmd_map(void) { static const XCMD cmds[] = { { "use", xcmd_map_use }, { "view", xcmd_map_view }, /*{ "name", xcmd_map_name },*/ { 0 } }; return(x_cmd("#map ",&cmds[0])); } static int xcmd_drop(void) { return(drop(1)); } static int extended_command(void) { static const XCMD cmds[] = { { "map", xcmd_map }, { "drop", xcmd_drop }, { 0 } }; return(x_cmd("#",&cmds[0])); } static LOC *move_by(LOC *l, XY d) { int x; int y; x = l->x + d.x; y = l->y + d.y; if ((x < 0) || (y < 0) || (x >= LEV_X) || (y >= LEV_Y)) { if (l->on->flags & LVF_WRAPAROUND) { x = (x + LEV_X) % LEV_X; y = (y + LEV_Y) % LEV_Y; } else { return(0); } } return(&l->on->cells[x][y]); } static int move_you(XY d) { LOC *lc; LOC *lc2; lc = you->loc; lc2 = move_by(lc,d); if ( (abs(lc->x-lc2->x) > 1) || (abs(lc->y-lc2->y) > 1) ) { running = RUN_NONE; } if (! lc2) panic("Outside level"); if ( (lc2->type == LOC_CAVE) || ( (lc2->type == LOC_DOOR) && (lc2->walldoor & LOC_DOOR_OPEN) ) ) { if (lc2->monst) { running = RUN_NONE; mhitm(you,lc2->monst); } else { movemon(you,lc2); if ( lc2->objs.inv || !( (lc2->type == LOC_CAVE) && (lc2->cavetype == LOC_JUSTCAVE) ) ) running = RUN_NONE; } } else if (lc2->type == LOC_GATE) { lc->tracks[TRACK_DUMB] = lc2; lc->tracktime[TRACK_DUMB] = curtime; lc2->tracks[TRACK_DUMB] = 0; lc2->tracktime[TRACK_DUMB] = curtime; lc->tracks[TRACK_SMART] = lc2; lc->tracktime[TRACK_SMART] = curtime; lc2->tracks[TRACK_SMART] = 0; lc2->tracktime[TRACK_SMART] = curtime; gatemon(you,lc2->to); running = RUN_NONE; } else { running = RUN_NONE; return(0); } return(1); } static void do_type_inv(void) { char prompt[64]; char resp[64]; char *cp; INVOBJ *io; char c; char lastc; int wantunknown; int wantknown; int invent_interest(INVOBJ *io) { return( (wantunknown && invobj_unidentified(io)) || (wantknown && !invobj_unidentified(io)) || !!index(&resp[0],objtypes[io->v[0]->type].sym) ); } CHOK pcharok(char typed) { return(index(&resp[0],typed)?CHOK_OK:CHOK_BAD); } cp = &resp[0]; lastc = '\0'; sort_you_inv(); for (io=you->invent.inv;io;io=io->link) { c = objtypes[io->v[0]->type].sym; if (c != lastc) { *cp++ = c; lastc = c; } } *cp++ = 'u'; *cp++ = 'k'; *cp = '\0'; sprintf(&prompt[0],"What types [%s]? ",&resp[0]); if (prompt_and_read(&prompt[0],&resp[0],sizeof(resp),0,&pcharok) == PR_OK) { wantunknown = !!index(&resp[0],'u'); wantknown = !!index(&resp[0],'k'); show_inventory(&you->invent,"",&invent_interest); } } static void prefix_add(int ch) { if (prefix_n >= prefix_a) prefix = realloc(prefix,prefix_a=(prefix_n+8)); prefix[prefix_n++] = ch; } static int prefix_num(void) { long int v; int iv; prefix_add('\0'); v = strtol(prefix,0,10); iv = v; if ((v < 0) || (v != iv)) return(-1); return(iv); } static int run_stop(void) { LOC *f; LOC *l; LOC *r; LOC *l45; LOC *r45; LOC *of; LOC *ol45; LOC *or45; switch (running) { default: abort(); break; case RUN_SHIFT: break; case RUN_CTL: { int foo(LOC *l) { return(l->monst || l->objs.inv); } int bar(LOC *a, LOC *b) { LOCTYPE at; LOCTYPE bt; at = a->type; bt = b->type; if (at == LOC_SDOOR) at = LOC_WALL; if (bt == LOC_SDOOR) bt = LOC_WALL; if (at != bt) return(1); switch (at) { case LOC_WALL: case LOC_ROCK: return(0); break; case LOC_CAVE: return(a->cavetype!=b->cavetype); break; case LOC_GATE: return(a->gatetype!=b->gatetype); break; case LOC_DOOR: return(a->walldoor!=b->walldoor); break; default: abort(); break; } } f = move_by(you->loc,run_d); l = move_by(you->loc,turn_l(run_d)); r = move_by(you->loc,turn_r(run_d)); l45 = move_by(you->loc,turn_l45(run_d)); r45 = move_by(you->loc,turn_r45(run_d)); if (! f) return(1); if (foo(f)) { if (debugmsg) pline("f (%d,%d) monst %p inv %p",f->x,f->y,(void *)f->monst,(void *)f->objs.inv); return(1); } if (l && foo(l)) { if (debugmsg) pline("l (%d,%d) monst %p inv %p",l->x,l->y,(void *)l->monst,(void *)l->objs.inv); return(1); } if (r && foo(r)) { if (debugmsg) pline("r (%d,%d) monst %p inv %p",r->x,r->y,(void *)r->monst,(void *)r->objs.inv); return(1); } if (r45 && foo(r45)) { if (debugmsg) pline("r45 (%d,%d) monst %p inv %p",r45->x,r45->y,(void *)r45->monst,(void *)r45->objs.inv); return(1); } if (l45 && foo(l45)) { if (debugmsg) pline("l45 (%d,%d) monst %p inv %p",l45->x,l45->y,(void *)l45->monst,(void *)l45->objs.inv); return(1); } of = move_by(startat,run_d); if (bar(f,of)) return(1); ol45 = move_by(startat,turn_l45(run_d)); if (bar(l45,ol45)) return(1); or45 = move_by(startat,turn_r45(run_d)); if (bar(r45,or45)) return(1); } break; } return(0); } static void mh_show_hist(void) { int x; int o; JMP j; int c; if (setjmp(j.b)) { pop_sigint_throw(); return; } mh_init(); mvprintw(MYO,0,"%d %d",mh_head,mh_tail); getch(); if (mh_head == mh_tail) return; o = 1; while (1) { x = (mh_head + MSGHISTSIZE - o) % MSGHISTSIZE; mvprintw(MYO,0,"(%d) %s",o,mh_text[x]); clrtoeol(); refresh(); push_sigint_throw(&j); c = getch(); pop_sigint_throw(); switch (c) { case '\020': if (x == mh_tail) { beep(); } else { o ++; } break; case '\016': if (o < 2) { beep(); } else { o --; } break; default: repcmd = c; repcount = 1; /* fall through */ case '\33': case '\r': case '\n': case '\7': move(MYO,0); clrtoeol(); return; break; } } } static void you_tick(MONST *m) { XY d; int ch; int f; LEVEL *lv; LOC *lc; int i; JMP j; gainhp(m,m->heal); if (setjmp(j.b)) { pop_sigint_throw(); } while (1) { i = interrupted(); if (i != last_interrupt) { last_interrupt = i; running = RUN_NONE; repcount = 0; prefix_clear = 1; clear(); continue; } lc = m->loc; lv = lc->on; if (lastloc == 0) you_bemoved(you); showmsgbuf(0); showdisp(); mvprintw(0,MXO,"%s",lc->on->longname); clrtoeol(); mvprintw(1,MXO,"HP:%d/%d",m->hp,m->maxhp); clrtoeol(); mvprintw(3,MXO,"disp %d %d",dispox,dispoy); clrtoeol(); mvprintw(4,MXO,"at %d %d",lc->x,lc->y); clrtoeol(); mvprintw(5,MXO,"on %s",lc->on->shortname); clrtoeol(); if (prefix_clear) { prefix_n = 0; prefix_clear = 0; move(LINES-1,0); clrtoeol(); } if (prefix_n > 0) { move(LINES-1,0); addnstr(prefix,prefix_n); } move(lc->y+dispoy,lc->x+dispox); refresh(); if (running != RUN_NONE) { if (run_stop()) { running = RUN_NONE; continue; } if (! move_you(run_d)) { running = RUN_NONE; continue; } if (runcount > 0) runcount --; if (! runcount) running = RUN_NONE; return; } if (repcount > 0) { ch = repcmd; repcount --; } else { push_sigint_throw(&j); ch = getch(); pop_sigint_throw(); } switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': prefix_add(ch); continue; break; case '\7': prefix_n = 0; continue; break; case '\b': case '\177': if (prefix_n > 0) { prefix_n --; continue; } break; } prefix_clear = 1; if (dirkey(ch,0,0,&d,&f,0)) { if (f & DK_CAPS) { running = RUN_SHIFT; runcount = (prefix_n > 0) ? prefix_num() : -1; startat = you->loc; run_d = d; } else if (f & DK_CTL) { running = RUN_CTL; runcount = (prefix_n > 0) ? prefix_num() : -1; startat = you->loc; run_d = d; } else if (prefix_n > 0) { repcount = prefix_num(); repcmd = ch; } else { if (move_you(d)) return; } continue; } else { if (prefix_n > 0) { repcount = prefix_num(); repcmd = ch; continue; } switch (ch) { case '.': return; break; case 's': search(); return; break; } repcount = 0; switch (ch) { case '<': if (lc->cavetype != LOC_STAIRS_U) break; if (0) { case '>': if (lc->cavetype != LOC_STAIRS_D) break; } if (lc->to == 0) { die(0); /* XXX leaving dungeon */ } else if (seestairs()) { continue; } else if (lc->to->monst) { mhitm(m,lc->to->monst); return; } else { movemon(m,lc->to); return; } break; case 'D': { LOC *lc2; lc2 = getdir(lc); if (lc2 && (lc2->type == LOC_DOOR)) { if (lc2->walldoor & LOC_DOOR_OPEN) { closedoor(lc2); } else { opendoor(lc2); } return; } } break; case 'I': do_type_inv(); break; case 'M': if (map) map_vis(); else pline("No map in use!"); break; case 'O': options(); break; case 'd': if (drop(0)) return; break; case 'i': sort_you_inv(); show_inventory(&you->invent,"",&showinvent_all); break; case 'p': if (lc->objs.inv && pickup()) return; break; case 'q': if (quaff()) return; break; case 'Q': /* XXX ask for confirmation */ endwin(); exit(0); break; case 'r': if (read()) return; break; case 'z': if (zap()) return; break; case '#': if (extended_command()) return; break; case '\020': mh_show_hist(); break; default: continue; break; case '~': push_sigint_throw(&j); ch = getch(); pop_sigint_throw(); switch (ch) { case 'A': aggravate(); break; case 'C': addfuse_rel(&makemon_fuse,1,0,0); pline("Created monster"); break; case 'D': debugmsg = ! debugmsg; pline("Debugging %s.",debugmsg?"on":"off"); break; case 'E': for (i=0;iinvent); o = obj_make(OBJ_SCROLL_OF_IDENTIFY); add_obj_to_inv(o,&you->invent); } } break; case 'I': while (inv_scan(&you->invent,&invobj_unidentified)) { INVOBJ *io; for (io=you->invent.inv;io;io=io->link) { if (invobj_unidentified(io)) { identify_it(io,0); break; } } } break; case 'M': auto_map_toggle(); break; case 'O': off_pline(); break; case 'P': probe(); break; case 'S': structure(); break; case 'T': you->flags ^= MF_TELEPATHIC; pline("Telepathy %s",(you->flags&MF_TELEPATHIC)?"on":"off"); break; case 'V': vulnerability_toggle(); break; } continue; break; } } } } void finddoor(LOC *lc) { if (lc->type != LOC_SDOOR) panic("finddoor on non-sdoor"); lc->type = LOC_DOOR; switch (lc->walldoor) { case LOC_HWALL: lc->walldoor = LOC_CVDOOR; break; case LOC_VWALL: lc->walldoor = LOC_CHDOOR; break; default: pline("bad walldoor %d in finddoor?",lc->walldoor); impossible(); lc->type = LOC_CAVE; lc->cavetype = LOC_JUSTCAVE; break; } upddisp(lc); } void opendoor(LOC *lc) { lc->walldoor &= ~LOC_DOOR_CLOSED; lc->walldoor |= LOC_DOOR_OPEN; if (lc->flags & LF_VISIBLE) resee(); upddisp(lc); } void closedoor(LOC *lc) { lc->walldoor &= ~LOC_DOOR_OPEN; lc->walldoor |= LOC_DOOR_CLOSED; if (lc->flags & LF_VISIBLE) resee(); upddisp(lc); } void resee(void) { lastloc = 0; } static const char *you_name(MONST *m __attribute__((__unused__))) { return("you"); } static const char *you_Name(MONST *m __attribute__((__unused__))) { return("You"); } static void you_destroy(MONST *m __attribute__((__unused__))) { panic("destroying you?"); } void teleport_you(LOC *lc) { you->loc->tracks[TRACK_DUMB] = 0; you->loc->tracktime[TRACK_DUMB] = curtime; you->loc->tracks[TRACK_SMART] = 0; you->loc->tracktime[TRACK_SMART] = curtime; movemon(you,lc); } void setup_you(void) { OBJ *o; int i; if (entrance->monst) killmon(entrance->monst); destroy_inv(&entrance->objs); you = newmon(MON_YOU,entrance->on); if (placemon(you,entrance)) panic("can't place you"); dispox = (LEV_X/2) - entrance->x; dispoy = (LEV_Y/2) - entrance->y; map = obj_make(OBJ_MAP); mapox = 0; mapoy = 0; map_setlabel(map,entrance->on->longname); add_obj_to_inv(map,&you->invent); lastlevel = entrance->on; lastloc = 0; for (i=0;i<5;i++) { o = obj_make(OBJ_MAP); add_obj_to_inv(o,&you->invent); } makemon_fuse(0,0); } static int you_attack(MONST *m __attribute__((__unused__))) { return(rnd(100)); } static int you_defend(MONST *m __attribute__((__unused__))) { return(invulnerable?1000000000:rnd(100)); } static int you_givedamage(MONST *m __attribute__((__unused__)), int dd __attribute__((__unused__))) { return(roll("3d1000")); } static void you_kill(MONST *m __attribute__((__unused__))) { pline("You die"); showmsgbuf(1); die(0); } static MONOPS ops = { &you_tick, &you_bemoved, &you_name, &you_Name, &you_attack, &you_defend, &you_givedamage, &std_takedamage, &you_kill, &you_destroy }; static MONST *new(MONST *m, LEVEL *lv __attribute__((__unused__))) { m->symbol = '@'; m->hp = 12000; m->maxhp = 12000; m->heal = 12; m->ops = &ops; return(m); } static void ctl(MONST *m __attribute__((__unused__)), int op, ...) { va_list ap; va_start(ap,op); switch (op) { } va_end(ap); } static PROBINIT probs[] = { PROBALL(0), PROBEND() }; extern MTINFO mtinfo_you; MTINFO mtinfo_you = { &probs[0], &new, &ctl };