#include #include #include #include #include "vars.h" #include "math.h" #include "dice.h" #include "pline.h" #include "signals.h" #include "display.h" #include "structs.h" #include "disputil.h" #include "objtypes.h" #include "stdio-util.h" #include "obj.h" static const char icv[62] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static void shuffle_name23(int class) { int tlist[OCC__MAX]; int tn; int i; int j; tn = 0; for (i=0;i OCC__MAX) abort(); tlist[tn++] = i; } } for (i=0;itype].ops->old)(o); free(o); } void invobjfree(INVOBJ *io) { int i; for (i=0;in;i++) objfree(io->v[i]); free(io->v); free(io); } int inv_remove(INVENT *inv, INVOBJ *io) { INVOBJ **l; INVOBJ *t; l = &inv->inv; while ((t = *l)) { if (t == io) { *l = t->link; if (t->inv != inv) panic("invobj in wrong inventory"); t->inv = 0; return(1); } l = &t->link; } return(0); } void destroy_inv(INVENT *inv) { INVOBJ *io; while (inv->inv) { io = inv->inv; inv->inv = io->link; invobjfree(io); } } void mergeinv(INVENT *from, INVENT *to) { INVOBJ *o; int i; while (from->inv) { o = from->inv; from->inv = o->link; for (i=0;in;i++) add_obj_to_inv(o->v[i],to); free(o->v); free(o); } } INVOBJ *inv_move_1(INVENT *oldinv, INVOBJ *io, INVENT *newinv) { INVOBJ *p; int i; inv_remove(oldinv,io); for (i=0;in;i++) p = add_obj_to_inv(io->v[i],newinv); return(p); } OBJ *obj_make(int type) { OBJ *o; o = malloc(sizeof(OBJ)); o->type = type; o->number = 1; return((*objtypes[type].ops->new)(type,o)); } static int obj_collapsible(OBJ *o1, OBJ *o2) { if (objtypes[o1->type].ops != objtypes[o2->type].ops) return(0); return((*objtypes[o1->type].ops->collapsible)(o1,o2)); } static int obj_identical(OBJ *o1, OBJ *o2) { if (o1->type != o2->type) return(0); return((*objtypes[o1->type].ops->identical)(o1,o2)); } INVOBJ *add_obj_to_inv(OBJ *o, INVENT *inv) { INVOBJ *io; int i; for (io=inv->inv;io;io=io->link) { if (obj_collapsible(o,io->v[0])) { for (i=0;in;i++) { if (obj_identical(o,io->v[i])) { io->v[i]->number += o->number; io->dispn += o->number; objfree(o); return(io); } } io->n ++; io->v = realloc(io->v,io->n*sizeof(OBJ *)); io->v[io->n-1] = o; io->dispn += o->number; return(io); } } io = malloc(sizeof(INVOBJ)); io->inv = inv; io->xwi = find_xwi(inv); io->dispn = o->number; io->n = 1; io->v = malloc(sizeof(OBJ *)); io->v[0] = o; io->link = inv->inv; inv->inv = io; return(io); } int inv_present(INVENT *inv, OBJ *o) { INVOBJ *io; int i; for (io=inv->inv;io;io=io->link) for (i=io->n-1;i>=0;i--) if (io->v[i] == o) return(1); return(0); } int showinvent_all(INVOBJ *inv __attribute__((__unused__))) { return(1); } void format_inv_line(INVOBJ *io, FILE *f) { if (io->xwi < 26) { putc(' ',f); putc(icv[io->xwi],f); } else { putc(icv[26+((io->xwi-26)/62)],f); putc(icv[(io->xwi-26)%62],f); } putc(')',f); putc(' ',f); (*objtypes[io->v[0]->type].ops->format)(f,io); } static int inv_c_is_1(char c, int *vp) { char *xp; xp = memchr(&icv[0],c,26); if (xp) { *vp = xp - &icv[0]; return(1); } return(0); } static int inv_c_is_2_1(char c, int *vp) { char *xp; xp = memchr(&icv[26],c,36); if (xp) { *vp = (xp - &icv[26]) * 62; return(1); } return(0); } static int inv_c_is_2_2(char c, int *vp) { char *xp; xp = memchr(&icv[0],c,62); if (xp) { *vp += (xp - &icv[0]) + 26; return(1); } return(0); } static INVOBJ *x_in_inv(INVENT *inv, int x, int (*interest)(INVOBJ *)) { INVOBJ *io; for (io=inv->inv;io;io=io->link) if ((io->xwi == x) && (*interest)(io)) return(io); return(0); } typedef enum { SI_K_IGNORE = 1, SI_K_CONTINUE, SI_K_ABORT } SIKA; static void show_inventory_(INVENT *inv, const char **promptp, int (*interest)(INVOBJ *), SIKA (*keystroke)(int)) { INVOBJ *io; DLLS line(FILE *f) { while (io && !(*interest)(io)) io = io->link; if (! io) return(DL_L_DONE); format_inv_line(io,f); io = io->link; return(DL_L_MORE); } DLKS key(int ks) { switch ((*keystroke)(ks)) { case SI_K_IGNORE: return(DL_K_IGNORE); break; case SI_K_CONTINUE: return(DL_K_CONTINUE); break; case SI_K_ABORT: return(DL_K_ABORT); break; default: abort(); break; } } io = inv->inv; display_list(&line,promptp,&key); showdisp(); } static SIKA si_justmore(int ch) { switch (ch) { case ' ': case '\r': case '\n': return(SI_K_CONTINUE); break; case '\e': return(SI_K_ABORT); break; } return(SI_K_IGNORE); } void show_inventory(INVENT *inv, const char *prompt, int (*interest)(INVOBJ *)) { show_inventory_(inv,&prompt,interest,&si_justmore); } INVOBJ *pick_inventory(INVENT *inv, const char *prompt, int (*interest)(INVOBJ *)) { INVOBJ *io; int c; int d; const char *pp; int pl; char *pt; int ks; int c2; JMP j; static void setpt(int c) { if (pt == 0) { pl = strlen(prompt); pt = malloc(pl+2); bcopy(prompt,pt,pl); pt[pl+1] = '\0'; } pt[pl] = c; pp = pt; } static SIKA key2(int c) { switch (c) { case ' ': case '\r': case '\n': return(SI_K_CONTINUE); break; case '\e': return(SI_K_ABORT); break; } if (c2) { switch (c) { case '\b': case '\177': c2 = 0; pp = prompt; return(SI_K_IGNORE); break; } if (inv_c_is_2_2(c,&ks)) { io = x_in_inv(inv,ks,interest); if (io) return(SI_K_ABORT); } } else { if (inv_c_is_1(c,&ks)) { io = x_in_inv(inv,ks,interest); if (io) return(SI_K_ABORT); } else if (inv_c_is_2_1(c,&ks)) { setpt(c); c2 = 1; } } return(SI_K_IGNORE); } io = 0; pt = 0; c2 = 0; if (setjmp(j.b)) { pop_sigint_throw(); move(LINES-1,0); clrtoeol(); if (pt) free(pt); return(0); } while <"done"> (1) { move(LINES-1,0); addstr(prompt); clrtoeol(); refresh(); push_sigint_throw(&j); c = getch(); pop_sigint_throw(); switch (c) { case '?': pp = prompt; show_inventory_(inv,&pp,interest,key2); if (io) break <"done">; showdisp(); continue; break; case '\e': io = 0; break <"done">; break; case 0x14: /* ^T */ { char prompt[64]; char resp[64]; char c; char lastc; char *cp; int wantunknown; int wantknown; static CHOK pcharok(char typed) { return(index(&resp[0],typed)?CHOK_OK:CHOK_BAD); } static int sub_interest(INVOBJ *io) { return( ( (wantunknown && invobj_unidentified(io)) || (wantknown && !invobj_unidentified(io)) || !!index(&resp[0],objtypes[io->v[0]->type].sym) ) && (*interest)(io) ); } cp = &resp[0]; lastc = '\0'; for (io=inv->inv;io;io=io->link) { c = objtypes[io->v[0]->type].sym; if (c != lastc) { if ((cp == &resp[0]) || !memchr(&resp[0],c,cp-&resp[0])) *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'); pp = prompt; show_inventory_(inv,&pp,&sub_interest,key2); if (io) break <"done">; showdisp(); } } break; default: if (inv_c_is_1(c,&ks)) { io = x_in_inv(inv,ks,interest); if (io) break <"done">; } else if (inv_c_is_2_1(c,&ks)) { addch(c); refresh(); push_sigint_throw(&j); d = getch(); pop_sigint_throw(); switch (d) { case '?': { static int subint(INVOBJ *o) { if ((o->xwi < ks+26) || (o->xwi > ks+26+62)) return(0); return((*interest)(o)); } static SIKA subkey(int ch) { switch (ch) { case ' ': case '\r': case '\n': return(SI_K_CONTINUE); break; case '\e': return(SI_K_ABORT); break; case '\b': case '\177': return(SI_K_ABORT); break; } if (inv_c_is_2_2(ch,&ks)) { io = x_in_inv(inv,ks,interest); if (io) return(SI_K_ABORT); } return(SI_K_IGNORE); } setpt(c); show_inventory_(inv,&pp,&subint,subkey); if (io) break <"done">; } break; case '\b': case '\177': break; default: if (inv_c_is_2_2(d,&ks)) { io = x_in_inv(inv,ks,interest); if (io) break <"done">; } beep(); break; } } else { beep(); } break; } } move(LINES-1,0); clrtoeol(); if (pt) free(pt); return(io); } int find_xwi(INVENT *inv) { static char *map = 0; static int ma = 0; int ml; int i; INVOBJ *io; ml = 0; for (io=inv->inv;io;io=io->link) { if (io->xwi >= ma) map = realloc(map,ma=io->xwi+1); if (io->xwi >= ml) { if (io->xwi > ml) bzero(map+ml,io->xwi-ml); ml = io->xwi + 1; } map[io->xwi] = 1; } for (i=0;idispn <= newn) return(0); nleft = newn; tleft = old->dispn; new = malloc(sizeof(INVOBJ)); new->inv = old->inv; new->xwi = newxwi; new->dispn = old->dispn - newn; new->link = old->link; old->link = new; new->n = old->n; new->v = old->v; old->dispn = newn; if (old->n == 1) { old->v = malloc(sizeof(OBJ *)); old->v[0] = (*objtypes[new->v[0]->type].ops->split)(new->v[0],newn); return(new); } old->v = malloc(old->n*sizeof(OBJ *)); old->n = 0; i = old->n; j = -1; n = 0; while (1) { if (nleft < 1) break; if (j < 0) { if (n > 0) { if (n == o->number) { if (i < new->n-1) new->v[i] = new->v[new->n-1]; new->n --; } else { o = (*objtypes[o->type].ops->split)(o,n); } old->v[old->n++] = o; } i --; if (i < 0) panic("dispn wrong in inventory_split_n"); o = new->v[i]; j = o->number - 1; } else { j --; } if ((tleft <= nleft) || (rnd(tleft) < nleft)) { n ++; nleft --; } tleft --; } return(new); } INVOBJ *inventory_split_n(INVOBJ *old, int newn, int newxwi) { INVOBJ *new; if (newn < 0) { INVOBJ t; new = inventory_split_n_(old,-newn,newxwi); if (! new) return(0); t = *new; new->dispn = old->dispn; new->n = old->n; new->v = old->v; old->dispn = t.dispn; old->n = t.n; old->v = t.v; } else { new = inventory_split_n_(old,newn,newxwi); } return(new); } INVOBJ *sort_inv(INVOBJ *inv, int (*cmp)(INVOBJ *, INVOBJ *)) { INVOBJ *l1; INVOBJ **t1; INVOBJ *l2; INVOBJ **t2; INVOBJ **t; INVOBJ *o; if (! inv->link) return(inv); t1 = &l1; t2 = &l2; while (inv) { *t1 = inv; t1 = &inv->link; inv = inv->link; if (! inv) break; *t2 = inv; t2 = &inv->link; inv = inv->link; } *t1 = 0; *t2 = 0; l1 = sort_inv(l1,cmp); l2 = sort_inv(l2,cmp); t = &inv; while (1) { if (l1 && (!l2 || ((*cmp)(l1,l2) < 0))) { o = l1; l1 = l1->link; } else if (l2) { o = l2; l2 = l2->link; } else { break; } *t = o; t = &o->link; } *t = 0; return(inv); } void inv_init(INVENT *i, INVTYPE t, ...) { va_list ap; i->inv = 0; i->type = t; va_start(ap,t); switch (t) { case IT_MON: i->u.m = va_arg(ap,MONST *); break; case IT_LOC: i->u.l = va_arg(ap,LOC *); break; default: panic("bad type %d to inv_init",t); break; } va_end(ap); } OBJ *std_split(OBJ *old, int n) { OBJ *o; old->number -= n; o = obj_make(old->type); o->number = n; return(o); } INVOBJ *inv_scan(INVENT *inv, int (*interest)(INVOBJ *)) { INVOBJ *io; for (io=inv->inv;io;io=io->link) if ((*interest)(io)) return(io); return(0); } int invobj_unidentified(INVOBJ *io) { return(!(*objtypes[io->v[0]->type].ops->identified)(io)); } void pline_invobj(INVOBJ *io) { char *s; FILE *f; f = fopenmalloc(&s); format_inv_line(io,f); fclose(f); pline(s); free(s); } void identify_it(INVOBJ *io, int noisy) { io = (*objtypes[io->v[0]->type].ops->identify)(io); if (noisy) pline_invobj(io); } OBJ *remove_obj_from_invobj(int inx, INVOBJ *io) { OBJ *o; o = io->v[inx]; io->n --; if (inx != io->n) io->v[inx] = io->v[io->n]; io->dispn -= o->number; return(o); }