1*0c5e0addSbostic /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 2*0c5e0addSbostic /* hack.invent.c - version 1.0.3 */ 3*0c5e0addSbostic 4*0c5e0addSbostic #include "hack.h" 5*0c5e0addSbostic #include <stdio.h> 6*0c5e0addSbostic extern struct obj *splitobj(); 7*0c5e0addSbostic extern struct obj zeroobj; 8*0c5e0addSbostic extern char morc; 9*0c5e0addSbostic extern char quitchars[]; 10*0c5e0addSbostic char *xprname(); 11*0c5e0addSbostic 12*0c5e0addSbostic #ifndef NOWORM 13*0c5e0addSbostic #include "def.wseg.h" 14*0c5e0addSbostic extern struct wseg *wsegs[32]; 15*0c5e0addSbostic #endif NOWORM 16*0c5e0addSbostic 17*0c5e0addSbostic #define NOINVSYM '#' 18*0c5e0addSbostic 19*0c5e0addSbostic static int lastinvnr = 51; /* 0 ... 51 */ 20*0c5e0addSbostic static 21*0c5e0addSbostic assigninvlet(otmp) 22*0c5e0addSbostic register struct obj *otmp; 23*0c5e0addSbostic { 24*0c5e0addSbostic boolean inuse[52]; 25*0c5e0addSbostic register int i; 26*0c5e0addSbostic register struct obj *obj; 27*0c5e0addSbostic 28*0c5e0addSbostic for(i = 0; i < 52; i++) inuse[i] = FALSE; 29*0c5e0addSbostic for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) { 30*0c5e0addSbostic i = obj->invlet; 31*0c5e0addSbostic if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else 32*0c5e0addSbostic if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE; 33*0c5e0addSbostic if(i == otmp->invlet) otmp->invlet = 0; 34*0c5e0addSbostic } 35*0c5e0addSbostic if((i = otmp->invlet) && 36*0c5e0addSbostic (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z'))) 37*0c5e0addSbostic return; 38*0c5e0addSbostic for(i = lastinvnr+1; i != lastinvnr; i++) { 39*0c5e0addSbostic if(i == 52) { i = -1; continue; } 40*0c5e0addSbostic if(!inuse[i]) break; 41*0c5e0addSbostic } 42*0c5e0addSbostic otmp->invlet = (inuse[i] ? NOINVSYM : 43*0c5e0addSbostic (i < 26) ? ('a'+i) : ('A'+i-26)); 44*0c5e0addSbostic lastinvnr = i; 45*0c5e0addSbostic } 46*0c5e0addSbostic 47*0c5e0addSbostic struct obj * 48*0c5e0addSbostic addinv(obj) 49*0c5e0addSbostic register struct obj *obj; 50*0c5e0addSbostic { 51*0c5e0addSbostic register struct obj *otmp; 52*0c5e0addSbostic 53*0c5e0addSbostic /* merge or attach to end of chain */ 54*0c5e0addSbostic if(!invent) { 55*0c5e0addSbostic invent = obj; 56*0c5e0addSbostic otmp = 0; 57*0c5e0addSbostic } else 58*0c5e0addSbostic for(otmp = invent; /* otmp */; otmp = otmp->nobj) { 59*0c5e0addSbostic if(merged(otmp, obj, 0)) 60*0c5e0addSbostic return(otmp); 61*0c5e0addSbostic if(!otmp->nobj) { 62*0c5e0addSbostic otmp->nobj = obj; 63*0c5e0addSbostic break; 64*0c5e0addSbostic } 65*0c5e0addSbostic } 66*0c5e0addSbostic obj->nobj = 0; 67*0c5e0addSbostic 68*0c5e0addSbostic if(flags.invlet_constant) { 69*0c5e0addSbostic assigninvlet(obj); 70*0c5e0addSbostic /* 71*0c5e0addSbostic * The ordering of the chain is nowhere significant 72*0c5e0addSbostic * so in case you prefer some other order than the 73*0c5e0addSbostic * historical one, change the code below. 74*0c5e0addSbostic */ 75*0c5e0addSbostic if(otmp) { /* find proper place in chain */ 76*0c5e0addSbostic otmp->nobj = 0; 77*0c5e0addSbostic if((invent->invlet ^ 040) > (obj->invlet ^ 040)) { 78*0c5e0addSbostic obj->nobj = invent; 79*0c5e0addSbostic invent = obj; 80*0c5e0addSbostic } else 81*0c5e0addSbostic for(otmp = invent; ; otmp = otmp->nobj) { 82*0c5e0addSbostic if(!otmp->nobj || 83*0c5e0addSbostic (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){ 84*0c5e0addSbostic obj->nobj = otmp->nobj; 85*0c5e0addSbostic otmp->nobj = obj; 86*0c5e0addSbostic break; 87*0c5e0addSbostic } 88*0c5e0addSbostic } 89*0c5e0addSbostic } 90*0c5e0addSbostic } 91*0c5e0addSbostic 92*0c5e0addSbostic return(obj); 93*0c5e0addSbostic } 94*0c5e0addSbostic 95*0c5e0addSbostic useup(obj) 96*0c5e0addSbostic register struct obj *obj; 97*0c5e0addSbostic { 98*0c5e0addSbostic if(obj->quan > 1){ 99*0c5e0addSbostic obj->quan--; 100*0c5e0addSbostic obj->owt = weight(obj); 101*0c5e0addSbostic } else { 102*0c5e0addSbostic setnotworn(obj); 103*0c5e0addSbostic freeinv(obj); 104*0c5e0addSbostic obfree(obj, (struct obj *) 0); 105*0c5e0addSbostic } 106*0c5e0addSbostic } 107*0c5e0addSbostic 108*0c5e0addSbostic freeinv(obj) 109*0c5e0addSbostic register struct obj *obj; 110*0c5e0addSbostic { 111*0c5e0addSbostic register struct obj *otmp; 112*0c5e0addSbostic 113*0c5e0addSbostic if(obj == invent) 114*0c5e0addSbostic invent = invent->nobj; 115*0c5e0addSbostic else { 116*0c5e0addSbostic for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj) 117*0c5e0addSbostic if(!otmp->nobj) panic("freeinv"); 118*0c5e0addSbostic otmp->nobj = obj->nobj; 119*0c5e0addSbostic } 120*0c5e0addSbostic } 121*0c5e0addSbostic 122*0c5e0addSbostic /* destroy object in fobj chain (if unpaid, it remains on the bill) */ 123*0c5e0addSbostic delobj(obj) register struct obj *obj; { 124*0c5e0addSbostic freeobj(obj); 125*0c5e0addSbostic unpobj(obj); 126*0c5e0addSbostic obfree(obj, (struct obj *) 0); 127*0c5e0addSbostic } 128*0c5e0addSbostic 129*0c5e0addSbostic /* unlink obj from chain starting with fobj */ 130*0c5e0addSbostic freeobj(obj) register struct obj *obj; { 131*0c5e0addSbostic register struct obj *otmp; 132*0c5e0addSbostic 133*0c5e0addSbostic if(obj == fobj) fobj = fobj->nobj; 134*0c5e0addSbostic else { 135*0c5e0addSbostic for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj) 136*0c5e0addSbostic if(!otmp) panic("error in freeobj"); 137*0c5e0addSbostic otmp->nobj = obj->nobj; 138*0c5e0addSbostic } 139*0c5e0addSbostic } 140*0c5e0addSbostic 141*0c5e0addSbostic /* Note: freegold throws away its argument! */ 142*0c5e0addSbostic freegold(gold) register struct gold *gold; { 143*0c5e0addSbostic register struct gold *gtmp; 144*0c5e0addSbostic 145*0c5e0addSbostic if(gold == fgold) fgold = gold->ngold; 146*0c5e0addSbostic else { 147*0c5e0addSbostic for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold) 148*0c5e0addSbostic if(!gtmp) panic("error in freegold"); 149*0c5e0addSbostic gtmp->ngold = gold->ngold; 150*0c5e0addSbostic } 151*0c5e0addSbostic free((char *) gold); 152*0c5e0addSbostic } 153*0c5e0addSbostic 154*0c5e0addSbostic deltrap(trap) 155*0c5e0addSbostic register struct trap *trap; 156*0c5e0addSbostic { 157*0c5e0addSbostic register struct trap *ttmp; 158*0c5e0addSbostic 159*0c5e0addSbostic if(trap == ftrap) 160*0c5e0addSbostic ftrap = ftrap->ntrap; 161*0c5e0addSbostic else { 162*0c5e0addSbostic for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ; 163*0c5e0addSbostic ttmp->ntrap = trap->ntrap; 164*0c5e0addSbostic } 165*0c5e0addSbostic free((char *) trap); 166*0c5e0addSbostic } 167*0c5e0addSbostic 168*0c5e0addSbostic struct wseg *m_atseg; 169*0c5e0addSbostic 170*0c5e0addSbostic struct monst * 171*0c5e0addSbostic m_at(x,y) 172*0c5e0addSbostic register x,y; 173*0c5e0addSbostic { 174*0c5e0addSbostic register struct monst *mtmp; 175*0c5e0addSbostic #ifndef NOWORM 176*0c5e0addSbostic register struct wseg *wtmp; 177*0c5e0addSbostic #endif NOWORM 178*0c5e0addSbostic 179*0c5e0addSbostic m_atseg = 0; 180*0c5e0addSbostic for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){ 181*0c5e0addSbostic if(mtmp->mx == x && mtmp->my == y) 182*0c5e0addSbostic return(mtmp); 183*0c5e0addSbostic #ifndef NOWORM 184*0c5e0addSbostic if(mtmp->wormno){ 185*0c5e0addSbostic for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg) 186*0c5e0addSbostic if(wtmp->wx == x && wtmp->wy == y){ 187*0c5e0addSbostic m_atseg = wtmp; 188*0c5e0addSbostic return(mtmp); 189*0c5e0addSbostic } 190*0c5e0addSbostic } 191*0c5e0addSbostic #endif NOWORM 192*0c5e0addSbostic } 193*0c5e0addSbostic return(0); 194*0c5e0addSbostic } 195*0c5e0addSbostic 196*0c5e0addSbostic struct obj * 197*0c5e0addSbostic o_at(x,y) 198*0c5e0addSbostic register x,y; 199*0c5e0addSbostic { 200*0c5e0addSbostic register struct obj *otmp; 201*0c5e0addSbostic 202*0c5e0addSbostic for(otmp = fobj; otmp; otmp = otmp->nobj) 203*0c5e0addSbostic if(otmp->ox == x && otmp->oy == y) return(otmp); 204*0c5e0addSbostic return(0); 205*0c5e0addSbostic } 206*0c5e0addSbostic 207*0c5e0addSbostic struct obj * 208*0c5e0addSbostic sobj_at(n,x,y) 209*0c5e0addSbostic register n,x,y; 210*0c5e0addSbostic { 211*0c5e0addSbostic register struct obj *otmp; 212*0c5e0addSbostic 213*0c5e0addSbostic for(otmp = fobj; otmp; otmp = otmp->nobj) 214*0c5e0addSbostic if(otmp->ox == x && otmp->oy == y && otmp->otyp == n) 215*0c5e0addSbostic return(otmp); 216*0c5e0addSbostic return(0); 217*0c5e0addSbostic } 218*0c5e0addSbostic 219*0c5e0addSbostic carried(obj) register struct obj *obj; { 220*0c5e0addSbostic register struct obj *otmp; 221*0c5e0addSbostic for(otmp = invent; otmp; otmp = otmp->nobj) 222*0c5e0addSbostic if(otmp == obj) return(1); 223*0c5e0addSbostic return(0); 224*0c5e0addSbostic } 225*0c5e0addSbostic 226*0c5e0addSbostic carrying(type) 227*0c5e0addSbostic register int type; 228*0c5e0addSbostic { 229*0c5e0addSbostic register struct obj *otmp; 230*0c5e0addSbostic 231*0c5e0addSbostic for(otmp = invent; otmp; otmp = otmp->nobj) 232*0c5e0addSbostic if(otmp->otyp == type) 233*0c5e0addSbostic return(TRUE); 234*0c5e0addSbostic return(FALSE); 235*0c5e0addSbostic } 236*0c5e0addSbostic 237*0c5e0addSbostic struct obj * 238*0c5e0addSbostic o_on(id, objchn) unsigned int id; register struct obj *objchn; { 239*0c5e0addSbostic while(objchn) { 240*0c5e0addSbostic if(objchn->o_id == id) return(objchn); 241*0c5e0addSbostic objchn = objchn->nobj; 242*0c5e0addSbostic } 243*0c5e0addSbostic return((struct obj *) 0); 244*0c5e0addSbostic } 245*0c5e0addSbostic 246*0c5e0addSbostic struct trap * 247*0c5e0addSbostic t_at(x,y) 248*0c5e0addSbostic register x,y; 249*0c5e0addSbostic { 250*0c5e0addSbostic register struct trap *trap = ftrap; 251*0c5e0addSbostic while(trap) { 252*0c5e0addSbostic if(trap->tx == x && trap->ty == y) return(trap); 253*0c5e0addSbostic trap = trap->ntrap; 254*0c5e0addSbostic } 255*0c5e0addSbostic return(0); 256*0c5e0addSbostic } 257*0c5e0addSbostic 258*0c5e0addSbostic struct gold * 259*0c5e0addSbostic g_at(x,y) 260*0c5e0addSbostic register x,y; 261*0c5e0addSbostic { 262*0c5e0addSbostic register struct gold *gold = fgold; 263*0c5e0addSbostic while(gold) { 264*0c5e0addSbostic if(gold->gx == x && gold->gy == y) return(gold); 265*0c5e0addSbostic gold = gold->ngold; 266*0c5e0addSbostic } 267*0c5e0addSbostic return(0); 268*0c5e0addSbostic } 269*0c5e0addSbostic 270*0c5e0addSbostic /* make dummy object structure containing gold - for temporary use only */ 271*0c5e0addSbostic struct obj * 272*0c5e0addSbostic mkgoldobj(q) 273*0c5e0addSbostic register long q; 274*0c5e0addSbostic { 275*0c5e0addSbostic register struct obj *otmp; 276*0c5e0addSbostic 277*0c5e0addSbostic otmp = newobj(0); 278*0c5e0addSbostic /* should set o_id etc. but otmp will be freed soon */ 279*0c5e0addSbostic otmp->olet = '$'; 280*0c5e0addSbostic u.ugold -= q; 281*0c5e0addSbostic OGOLD(otmp) = q; 282*0c5e0addSbostic flags.botl = 1; 283*0c5e0addSbostic return(otmp); 284*0c5e0addSbostic } 285*0c5e0addSbostic 286*0c5e0addSbostic /* 287*0c5e0addSbostic * getobj returns: 288*0c5e0addSbostic * struct obj *xxx: object to do something with. 289*0c5e0addSbostic * (struct obj *) 0 error return: no object. 290*0c5e0addSbostic * &zeroobj explicitly no object (as in w-). 291*0c5e0addSbostic */ 292*0c5e0addSbostic struct obj * 293*0c5e0addSbostic getobj(let,word) 294*0c5e0addSbostic register char *let,*word; 295*0c5e0addSbostic { 296*0c5e0addSbostic register struct obj *otmp; 297*0c5e0addSbostic register char ilet,ilet1,ilet2; 298*0c5e0addSbostic char buf[BUFSZ]; 299*0c5e0addSbostic char lets[BUFSZ]; 300*0c5e0addSbostic register int foo = 0, foo2; 301*0c5e0addSbostic register char *bp = buf; 302*0c5e0addSbostic xchar allowcnt = 0; /* 0, 1 or 2 */ 303*0c5e0addSbostic boolean allowgold = FALSE; 304*0c5e0addSbostic boolean allowall = FALSE; 305*0c5e0addSbostic boolean allownone = FALSE; 306*0c5e0addSbostic xchar foox = 0; 307*0c5e0addSbostic long cnt; 308*0c5e0addSbostic 309*0c5e0addSbostic if(*let == '0') let++, allowcnt = 1; 310*0c5e0addSbostic if(*let == '$') let++, allowgold = TRUE; 311*0c5e0addSbostic if(*let == '#') let++, allowall = TRUE; 312*0c5e0addSbostic if(*let == '-') let++, allownone = TRUE; 313*0c5e0addSbostic if(allownone) *bp++ = '-'; 314*0c5e0addSbostic if(allowgold) *bp++ = '$'; 315*0c5e0addSbostic if(bp > buf && bp[-1] == '-') *bp++ = ' '; 316*0c5e0addSbostic 317*0c5e0addSbostic ilet = 'a'; 318*0c5e0addSbostic for(otmp = invent; otmp; otmp = otmp->nobj){ 319*0c5e0addSbostic if(!*let || index(let, otmp->olet)) { 320*0c5e0addSbostic bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet; 321*0c5e0addSbostic 322*0c5e0addSbostic /* ugly check: remove inappropriate things */ 323*0c5e0addSbostic if((!strcmp(word, "take off") && 324*0c5e0addSbostic !(otmp->owornmask & (W_ARMOR - W_ARM2))) 325*0c5e0addSbostic || (!strcmp(word, "wear") && 326*0c5e0addSbostic (otmp->owornmask & (W_ARMOR | W_RING))) 327*0c5e0addSbostic || (!strcmp(word, "wield") && 328*0c5e0addSbostic (otmp->owornmask & W_WEP))) { 329*0c5e0addSbostic foo--; 330*0c5e0addSbostic foox++; 331*0c5e0addSbostic } 332*0c5e0addSbostic } 333*0c5e0addSbostic if(ilet == 'z') ilet = 'A'; else ilet++; 334*0c5e0addSbostic } 335*0c5e0addSbostic bp[foo] = 0; 336*0c5e0addSbostic if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; 337*0c5e0addSbostic (void) strcpy(lets, bp); /* necessary since we destroy buf */ 338*0c5e0addSbostic if(foo > 5) { /* compactify string */ 339*0c5e0addSbostic foo = foo2 = 1; 340*0c5e0addSbostic ilet2 = bp[0]; 341*0c5e0addSbostic ilet1 = bp[1]; 342*0c5e0addSbostic while(ilet = bp[++foo2] = bp[++foo]){ 343*0c5e0addSbostic if(ilet == ilet1+1){ 344*0c5e0addSbostic if(ilet1 == ilet2+1) 345*0c5e0addSbostic bp[foo2 - 1] = ilet1 = '-'; 346*0c5e0addSbostic else if(ilet2 == '-') { 347*0c5e0addSbostic bp[--foo2] = ++ilet1; 348*0c5e0addSbostic continue; 349*0c5e0addSbostic } 350*0c5e0addSbostic } 351*0c5e0addSbostic ilet2 = ilet1; 352*0c5e0addSbostic ilet1 = ilet; 353*0c5e0addSbostic } 354*0c5e0addSbostic } 355*0c5e0addSbostic if(!foo && !allowall && !allowgold && !allownone) { 356*0c5e0addSbostic pline("You don't have anything %sto %s.", 357*0c5e0addSbostic foox ? "else " : "", word); 358*0c5e0addSbostic return(0); 359*0c5e0addSbostic } 360*0c5e0addSbostic for(;;) { 361*0c5e0addSbostic if(!buf[0]) 362*0c5e0addSbostic pline("What do you want to %s [*]? ", word); 363*0c5e0addSbostic else 364*0c5e0addSbostic pline("What do you want to %s [%s or ?*]? ", 365*0c5e0addSbostic word, buf); 366*0c5e0addSbostic 367*0c5e0addSbostic cnt = 0; 368*0c5e0addSbostic ilet = readchar(); 369*0c5e0addSbostic while(digit(ilet) && allowcnt) { 370*0c5e0addSbostic if (cnt < 100000000) 371*0c5e0addSbostic cnt = 10*cnt + (ilet - '0'); 372*0c5e0addSbostic else 373*0c5e0addSbostic cnt = 999999999; 374*0c5e0addSbostic allowcnt = 2; /* signal presence of cnt */ 375*0c5e0addSbostic ilet = readchar(); 376*0c5e0addSbostic } 377*0c5e0addSbostic if(digit(ilet)) { 378*0c5e0addSbostic pline("No count allowed with this command."); 379*0c5e0addSbostic continue; 380*0c5e0addSbostic } 381*0c5e0addSbostic if(index(quitchars,ilet)) 382*0c5e0addSbostic return((struct obj *)0); 383*0c5e0addSbostic if(ilet == '-') { 384*0c5e0addSbostic return(allownone ? &zeroobj : (struct obj *) 0); 385*0c5e0addSbostic } 386*0c5e0addSbostic if(ilet == '$') { 387*0c5e0addSbostic if(!allowgold){ 388*0c5e0addSbostic pline("You cannot %s gold.", word); 389*0c5e0addSbostic continue; 390*0c5e0addSbostic } 391*0c5e0addSbostic if(!(allowcnt == 2 && cnt < u.ugold)) 392*0c5e0addSbostic cnt = u.ugold; 393*0c5e0addSbostic return(mkgoldobj(cnt)); 394*0c5e0addSbostic } 395*0c5e0addSbostic if(ilet == '?') { 396*0c5e0addSbostic doinv(lets); 397*0c5e0addSbostic if(!(ilet = morc)) continue; 398*0c5e0addSbostic /* he typed a letter (not a space) to more() */ 399*0c5e0addSbostic } else if(ilet == '*') { 400*0c5e0addSbostic doinv((char *) 0); 401*0c5e0addSbostic if(!(ilet = morc)) continue; 402*0c5e0addSbostic /* ... */ 403*0c5e0addSbostic } 404*0c5e0addSbostic if(flags.invlet_constant) { 405*0c5e0addSbostic for(otmp = invent; otmp; otmp = otmp->nobj) 406*0c5e0addSbostic if(otmp->invlet == ilet) break; 407*0c5e0addSbostic } else { 408*0c5e0addSbostic if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1; 409*0c5e0addSbostic ilet -= 'a'; 410*0c5e0addSbostic for(otmp = invent; otmp && ilet; 411*0c5e0addSbostic ilet--, otmp = otmp->nobj) ; 412*0c5e0addSbostic } 413*0c5e0addSbostic if(!otmp) { 414*0c5e0addSbostic pline("You don't have that object."); 415*0c5e0addSbostic continue; 416*0c5e0addSbostic } 417*0c5e0addSbostic if(cnt < 0 || otmp->quan < cnt) { 418*0c5e0addSbostic pline("You don't have that many! [You have %u]" 419*0c5e0addSbostic , otmp->quan); 420*0c5e0addSbostic continue; 421*0c5e0addSbostic } 422*0c5e0addSbostic break; 423*0c5e0addSbostic } 424*0c5e0addSbostic if(!allowall && let && !index(let,otmp->olet)) { 425*0c5e0addSbostic pline("That is a silly thing to %s.",word); 426*0c5e0addSbostic return(0); 427*0c5e0addSbostic } 428*0c5e0addSbostic if(allowcnt == 2) { /* cnt given */ 429*0c5e0addSbostic if(cnt == 0) return(0); 430*0c5e0addSbostic if(cnt != otmp->quan) { 431*0c5e0addSbostic register struct obj *obj; 432*0c5e0addSbostic obj = splitobj(otmp, (int) cnt); 433*0c5e0addSbostic if(otmp == uwep) setuwep(obj); 434*0c5e0addSbostic } 435*0c5e0addSbostic } 436*0c5e0addSbostic return(otmp); 437*0c5e0addSbostic } 438*0c5e0addSbostic 439*0c5e0addSbostic ckunpaid(otmp) register struct obj *otmp; { 440*0c5e0addSbostic return( otmp->unpaid ); 441*0c5e0addSbostic } 442*0c5e0addSbostic 443*0c5e0addSbostic /* interactive version of getobj - used for Drop and Identify */ 444*0c5e0addSbostic /* return the number of times fn was called successfully */ 445*0c5e0addSbostic ggetobj(word, fn, max) 446*0c5e0addSbostic char *word; 447*0c5e0addSbostic int (*fn)(), max; 448*0c5e0addSbostic { 449*0c5e0addSbostic char buf[BUFSZ]; 450*0c5e0addSbostic register char *ip; 451*0c5e0addSbostic register char sym; 452*0c5e0addSbostic register int oletct = 0, iletct = 0; 453*0c5e0addSbostic register boolean allflag = FALSE; 454*0c5e0addSbostic char olets[20], ilets[20]; 455*0c5e0addSbostic int (*ckfn)() = (int (*)()) 0; 456*0c5e0addSbostic xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; /* BAH */ 457*0c5e0addSbostic if(!invent && !allowgold){ 458*0c5e0addSbostic pline("You have nothing to %s.", word); 459*0c5e0addSbostic return(0); 460*0c5e0addSbostic } else { 461*0c5e0addSbostic register struct obj *otmp = invent; 462*0c5e0addSbostic register int uflg = 0; 463*0c5e0addSbostic 464*0c5e0addSbostic if(allowgold) ilets[iletct++] = '$'; 465*0c5e0addSbostic ilets[iletct] = 0; 466*0c5e0addSbostic while(otmp) { 467*0c5e0addSbostic if(!index(ilets, otmp->olet)){ 468*0c5e0addSbostic ilets[iletct++] = otmp->olet; 469*0c5e0addSbostic ilets[iletct] = 0; 470*0c5e0addSbostic } 471*0c5e0addSbostic if(otmp->unpaid) uflg = 1; 472*0c5e0addSbostic otmp = otmp->nobj; 473*0c5e0addSbostic } 474*0c5e0addSbostic ilets[iletct++] = ' '; 475*0c5e0addSbostic if(uflg) ilets[iletct++] = 'u'; 476*0c5e0addSbostic if(invent) ilets[iletct++] = 'a'; 477*0c5e0addSbostic ilets[iletct] = 0; 478*0c5e0addSbostic } 479*0c5e0addSbostic pline("What kinds of thing do you want to %s? [%s] ", 480*0c5e0addSbostic word, ilets); 481*0c5e0addSbostic getlin(buf); 482*0c5e0addSbostic if(buf[0] == '\033') { 483*0c5e0addSbostic clrlin(); 484*0c5e0addSbostic return(0); 485*0c5e0addSbostic } 486*0c5e0addSbostic ip = buf; 487*0c5e0addSbostic olets[0] = 0; 488*0c5e0addSbostic while(sym = *ip++){ 489*0c5e0addSbostic if(sym == ' ') continue; 490*0c5e0addSbostic if(sym == '$') { 491*0c5e0addSbostic if(allowgold == 1) 492*0c5e0addSbostic (*fn)(mkgoldobj(u.ugold)); 493*0c5e0addSbostic else if(!u.ugold) 494*0c5e0addSbostic pline("You have no gold."); 495*0c5e0addSbostic allowgold = 2; 496*0c5e0addSbostic } else 497*0c5e0addSbostic if(sym == 'a' || sym == 'A') allflag = TRUE; else 498*0c5e0addSbostic if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else 499*0c5e0addSbostic if(index("!%?[()=*/\"0", sym)){ 500*0c5e0addSbostic if(!index(olets, sym)){ 501*0c5e0addSbostic olets[oletct++] = sym; 502*0c5e0addSbostic olets[oletct] = 0; 503*0c5e0addSbostic } 504*0c5e0addSbostic } 505*0c5e0addSbostic else pline("You don't have any %c's.", sym); 506*0c5e0addSbostic } 507*0c5e0addSbostic if(allowgold == 2 && !oletct) 508*0c5e0addSbostic return(1); /* he dropped gold (or at least tried to) */ 509*0c5e0addSbostic else 510*0c5e0addSbostic return(askchain(invent, olets, allflag, fn, ckfn, max)); 511*0c5e0addSbostic } 512*0c5e0addSbostic 513*0c5e0addSbostic /* 514*0c5e0addSbostic * Walk through the chain starting at objchn and ask for all objects 515*0c5e0addSbostic * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL) 516*0c5e0addSbostic * whether the action in question (i.e., fn) has to be performed. 517*0c5e0addSbostic * If allflag then no questions are asked. Max gives the max nr of 518*0c5e0addSbostic * objects to be treated. Return the number of objects treated. 519*0c5e0addSbostic */ 520*0c5e0addSbostic askchain(objchn, olets, allflag, fn, ckfn, max) 521*0c5e0addSbostic struct obj *objchn; 522*0c5e0addSbostic register char *olets; 523*0c5e0addSbostic int allflag; 524*0c5e0addSbostic int (*fn)(), (*ckfn)(); 525*0c5e0addSbostic int max; 526*0c5e0addSbostic { 527*0c5e0addSbostic register struct obj *otmp, *otmp2; 528*0c5e0addSbostic register char sym, ilet; 529*0c5e0addSbostic register int cnt = 0; 530*0c5e0addSbostic ilet = 'a'-1; 531*0c5e0addSbostic for(otmp = objchn; otmp; otmp = otmp2){ 532*0c5e0addSbostic if(ilet == 'z') ilet = 'A'; else ilet++; 533*0c5e0addSbostic otmp2 = otmp->nobj; 534*0c5e0addSbostic if(olets && *olets && !index(olets, otmp->olet)) continue; 535*0c5e0addSbostic if(ckfn && !(*ckfn)(otmp)) continue; 536*0c5e0addSbostic if(!allflag) { 537*0c5e0addSbostic pline(xprname(otmp, ilet)); 538*0c5e0addSbostic addtopl(" [nyaq]? "); 539*0c5e0addSbostic sym = readchar(); 540*0c5e0addSbostic } 541*0c5e0addSbostic else sym = 'y'; 542*0c5e0addSbostic 543*0c5e0addSbostic switch(sym){ 544*0c5e0addSbostic case 'a': 545*0c5e0addSbostic allflag = 1; 546*0c5e0addSbostic case 'y': 547*0c5e0addSbostic cnt += (*fn)(otmp); 548*0c5e0addSbostic if(--max == 0) goto ret; 549*0c5e0addSbostic case 'n': 550*0c5e0addSbostic default: 551*0c5e0addSbostic break; 552*0c5e0addSbostic case 'q': 553*0c5e0addSbostic goto ret; 554*0c5e0addSbostic } 555*0c5e0addSbostic } 556*0c5e0addSbostic pline(cnt ? "That was all." : "No applicable objects."); 557*0c5e0addSbostic ret: 558*0c5e0addSbostic return(cnt); 559*0c5e0addSbostic } 560*0c5e0addSbostic 561*0c5e0addSbostic obj_to_let(obj) /* should of course only be called for things in invent */ 562*0c5e0addSbostic register struct obj *obj; 563*0c5e0addSbostic { 564*0c5e0addSbostic register struct obj *otmp; 565*0c5e0addSbostic register char ilet; 566*0c5e0addSbostic 567*0c5e0addSbostic if(flags.invlet_constant) 568*0c5e0addSbostic return(obj->invlet); 569*0c5e0addSbostic ilet = 'a'; 570*0c5e0addSbostic for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj) 571*0c5e0addSbostic if(++ilet > 'z') ilet = 'A'; 572*0c5e0addSbostic return(otmp ? ilet : NOINVSYM); 573*0c5e0addSbostic } 574*0c5e0addSbostic 575*0c5e0addSbostic prinv(obj) 576*0c5e0addSbostic register struct obj *obj; 577*0c5e0addSbostic { 578*0c5e0addSbostic pline(xprname(obj, obj_to_let(obj))); 579*0c5e0addSbostic } 580*0c5e0addSbostic 581*0c5e0addSbostic static char * 582*0c5e0addSbostic xprname(obj,let) 583*0c5e0addSbostic register struct obj *obj; 584*0c5e0addSbostic register char let; 585*0c5e0addSbostic { 586*0c5e0addSbostic static char li[BUFSZ]; 587*0c5e0addSbostic 588*0c5e0addSbostic (void) sprintf(li, "%c - %s.", 589*0c5e0addSbostic flags.invlet_constant ? obj->invlet : let, 590*0c5e0addSbostic doname(obj)); 591*0c5e0addSbostic return(li); 592*0c5e0addSbostic } 593*0c5e0addSbostic 594*0c5e0addSbostic ddoinv() 595*0c5e0addSbostic { 596*0c5e0addSbostic doinv((char *) 0); 597*0c5e0addSbostic return(0); 598*0c5e0addSbostic } 599*0c5e0addSbostic 600*0c5e0addSbostic /* called with 0 or "": all objects in inventory */ 601*0c5e0addSbostic /* otherwise: all objects with (serial) letter in lets */ 602*0c5e0addSbostic doinv(lets) 603*0c5e0addSbostic register char *lets; 604*0c5e0addSbostic { 605*0c5e0addSbostic register struct obj *otmp; 606*0c5e0addSbostic register char ilet; 607*0c5e0addSbostic int ct = 0; 608*0c5e0addSbostic char any[BUFSZ]; 609*0c5e0addSbostic 610*0c5e0addSbostic morc = 0; /* just to be sure */ 611*0c5e0addSbostic 612*0c5e0addSbostic if(!invent){ 613*0c5e0addSbostic pline("Not carrying anything."); 614*0c5e0addSbostic return; 615*0c5e0addSbostic } 616*0c5e0addSbostic 617*0c5e0addSbostic cornline(0, (char *) 0); 618*0c5e0addSbostic ilet = 'a'; 619*0c5e0addSbostic for(otmp = invent; otmp; otmp = otmp->nobj) { 620*0c5e0addSbostic if(flags.invlet_constant) ilet = otmp->invlet; 621*0c5e0addSbostic if(!lets || !*lets || index(lets, ilet)) { 622*0c5e0addSbostic cornline(1, xprname(otmp, ilet)); 623*0c5e0addSbostic any[ct++] = ilet; 624*0c5e0addSbostic } 625*0c5e0addSbostic if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A'; 626*0c5e0addSbostic } 627*0c5e0addSbostic any[ct] = 0; 628*0c5e0addSbostic cornline(2, any); 629*0c5e0addSbostic } 630*0c5e0addSbostic 631*0c5e0addSbostic dotypeinv () /* free after Robert Viduya */ 632*0c5e0addSbostic /* Changed to one type only, so he doesnt have to type cr */ 633*0c5e0addSbostic { 634*0c5e0addSbostic char c, ilet; 635*0c5e0addSbostic char stuff[BUFSZ]; 636*0c5e0addSbostic register int stct; 637*0c5e0addSbostic register struct obj *otmp; 638*0c5e0addSbostic boolean billx = inshop() && doinvbill(0); 639*0c5e0addSbostic boolean unpd = FALSE; 640*0c5e0addSbostic 641*0c5e0addSbostic if (!invent && !u.ugold && !billx) { 642*0c5e0addSbostic pline ("You aren't carrying anything."); 643*0c5e0addSbostic return(0); 644*0c5e0addSbostic } 645*0c5e0addSbostic 646*0c5e0addSbostic stct = 0; 647*0c5e0addSbostic if(u.ugold) stuff[stct++] = '$'; 648*0c5e0addSbostic stuff[stct] = 0; 649*0c5e0addSbostic for(otmp = invent; otmp; otmp = otmp->nobj) { 650*0c5e0addSbostic if (!index (stuff, otmp->olet)) { 651*0c5e0addSbostic stuff[stct++] = otmp->olet; 652*0c5e0addSbostic stuff[stct] = 0; 653*0c5e0addSbostic } 654*0c5e0addSbostic if(otmp->unpaid) 655*0c5e0addSbostic unpd = TRUE; 656*0c5e0addSbostic } 657*0c5e0addSbostic if(unpd) stuff[stct++] = 'u'; 658*0c5e0addSbostic if(billx) stuff[stct++] = 'x'; 659*0c5e0addSbostic stuff[stct] = 0; 660*0c5e0addSbostic 661*0c5e0addSbostic if(stct > 1) { 662*0c5e0addSbostic pline ("What type of object [%s] do you want an inventory of? ", 663*0c5e0addSbostic stuff); 664*0c5e0addSbostic c = readchar(); 665*0c5e0addSbostic if(index(quitchars,c)) return(0); 666*0c5e0addSbostic } else 667*0c5e0addSbostic c = stuff[0]; 668*0c5e0addSbostic 669*0c5e0addSbostic if(c == '$') 670*0c5e0addSbostic return(doprgold()); 671*0c5e0addSbostic 672*0c5e0addSbostic if(c == 'x' || c == 'X') { 673*0c5e0addSbostic if(billx) 674*0c5e0addSbostic (void) doinvbill(1); 675*0c5e0addSbostic else 676*0c5e0addSbostic pline("No used-up objects on the shopping bill."); 677*0c5e0addSbostic return(0); 678*0c5e0addSbostic } 679*0c5e0addSbostic 680*0c5e0addSbostic if((c == 'u' || c == 'U') && !unpd) { 681*0c5e0addSbostic pline("You are not carrying any unpaid objects."); 682*0c5e0addSbostic return(0); 683*0c5e0addSbostic } 684*0c5e0addSbostic 685*0c5e0addSbostic stct = 0; 686*0c5e0addSbostic ilet = 'a'; 687*0c5e0addSbostic for (otmp = invent; otmp; otmp = otmp -> nobj) { 688*0c5e0addSbostic if(flags.invlet_constant) ilet = otmp->invlet; 689*0c5e0addSbostic if (c == otmp -> olet || (c == 'u' && otmp -> unpaid)) 690*0c5e0addSbostic stuff[stct++] = ilet; 691*0c5e0addSbostic if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A'; 692*0c5e0addSbostic } 693*0c5e0addSbostic stuff[stct] = '\0'; 694*0c5e0addSbostic if(stct == 0) 695*0c5e0addSbostic pline("You have no such objects."); 696*0c5e0addSbostic else 697*0c5e0addSbostic doinv (stuff); 698*0c5e0addSbostic 699*0c5e0addSbostic return(0); 700*0c5e0addSbostic } 701*0c5e0addSbostic 702*0c5e0addSbostic /* look at what is here */ 703*0c5e0addSbostic dolook() { 704*0c5e0addSbostic register struct obj *otmp, *otmp0; 705*0c5e0addSbostic register struct gold *gold; 706*0c5e0addSbostic char *verb = Blind ? "feel" : "see"; 707*0c5e0addSbostic int ct = 0; 708*0c5e0addSbostic 709*0c5e0addSbostic if(!u.uswallow) { 710*0c5e0addSbostic if(Blind) { 711*0c5e0addSbostic pline("You try to feel what is lying here on the floor."); 712*0c5e0addSbostic if(Levitation) { /* ab@unido */ 713*0c5e0addSbostic pline("You cannot reach the floor!"); 714*0c5e0addSbostic return(1); 715*0c5e0addSbostic } 716*0c5e0addSbostic } 717*0c5e0addSbostic otmp0 = o_at(u.ux, u.uy); 718*0c5e0addSbostic gold = g_at(u.ux, u.uy); 719*0c5e0addSbostic } 720*0c5e0addSbostic 721*0c5e0addSbostic if(u.uswallow || (!otmp0 && !gold)) { 722*0c5e0addSbostic pline("You %s no objects here.", verb); 723*0c5e0addSbostic return(!!Blind); 724*0c5e0addSbostic } 725*0c5e0addSbostic 726*0c5e0addSbostic cornline(0, "Things that are here:"); 727*0c5e0addSbostic for(otmp = otmp0; otmp; otmp = otmp->nobj) { 728*0c5e0addSbostic if(otmp->ox == u.ux && otmp->oy == u.uy) { 729*0c5e0addSbostic ct++; 730*0c5e0addSbostic cornline(1, doname(otmp)); 731*0c5e0addSbostic if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) { 732*0c5e0addSbostic pline("Touching the dead cockatrice is a fatal mistake ..."); 733*0c5e0addSbostic pline("You die ..."); 734*0c5e0addSbostic killer = "dead cockatrice"; 735*0c5e0addSbostic done("died"); 736*0c5e0addSbostic } 737*0c5e0addSbostic } 738*0c5e0addSbostic } 739*0c5e0addSbostic 740*0c5e0addSbostic if(gold) { 741*0c5e0addSbostic char gbuf[30]; 742*0c5e0addSbostic 743*0c5e0addSbostic (void) sprintf(gbuf, "%ld gold piece%s", 744*0c5e0addSbostic gold->amount, plur(gold->amount)); 745*0c5e0addSbostic if(!ct++) 746*0c5e0addSbostic pline("You %s here %s.", verb, gbuf); 747*0c5e0addSbostic else 748*0c5e0addSbostic cornline(1, gbuf); 749*0c5e0addSbostic } 750*0c5e0addSbostic 751*0c5e0addSbostic if(ct == 1 && !gold) { 752*0c5e0addSbostic pline("You %s here %s.", verb, doname(otmp0)); 753*0c5e0addSbostic cornline(3, (char *) 0); 754*0c5e0addSbostic } 755*0c5e0addSbostic if(ct > 1) 756*0c5e0addSbostic cornline(2, (char *) 0); 757*0c5e0addSbostic return(!!Blind); 758*0c5e0addSbostic } 759*0c5e0addSbostic 760*0c5e0addSbostic stackobj(obj) register struct obj *obj; { 761*0c5e0addSbostic register struct obj *otmp = fobj; 762*0c5e0addSbostic for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj) 763*0c5e0addSbostic if(otmp->ox == obj->ox && otmp->oy == obj->oy && 764*0c5e0addSbostic merged(obj,otmp,1)) 765*0c5e0addSbostic return; 766*0c5e0addSbostic } 767*0c5e0addSbostic 768*0c5e0addSbostic /* merge obj with otmp and delete obj if types agree */ 769*0c5e0addSbostic merged(otmp,obj,lose) register struct obj *otmp, *obj; { 770*0c5e0addSbostic if(obj->otyp == otmp->otyp && 771*0c5e0addSbostic obj->unpaid == otmp->unpaid && 772*0c5e0addSbostic obj->spe == otmp->spe && 773*0c5e0addSbostic obj->dknown == otmp->dknown && 774*0c5e0addSbostic obj->cursed == otmp->cursed && 775*0c5e0addSbostic (index("%*?!", obj->olet) || 776*0c5e0addSbostic (obj->known == otmp->known && 777*0c5e0addSbostic (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) { 778*0c5e0addSbostic otmp->quan += obj->quan; 779*0c5e0addSbostic otmp->owt += obj->owt; 780*0c5e0addSbostic if(lose) freeobj(obj); 781*0c5e0addSbostic obfree(obj,otmp); /* free(obj), bill->otmp */ 782*0c5e0addSbostic return(1); 783*0c5e0addSbostic } else return(0); 784*0c5e0addSbostic } 785*0c5e0addSbostic 786*0c5e0addSbostic /* 787*0c5e0addSbostic * Gold is no longer displayed; in fact, when you have a lot of money, 788*0c5e0addSbostic * it may take a while before you have counted it all. 789*0c5e0addSbostic * [Bug: d$ and pickup still tell you how much it was.] 790*0c5e0addSbostic */ 791*0c5e0addSbostic extern int (*occupation)(); 792*0c5e0addSbostic extern char *occtxt; 793*0c5e0addSbostic static long goldcounted; 794*0c5e0addSbostic 795*0c5e0addSbostic countgold(){ 796*0c5e0addSbostic if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) { 797*0c5e0addSbostic long eps = 0; 798*0c5e0addSbostic if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1)); 799*0c5e0addSbostic pline("You probably have about %ld gold pieces.", 800*0c5e0addSbostic u.ugold + eps); 801*0c5e0addSbostic return(0); /* done */ 802*0c5e0addSbostic } 803*0c5e0addSbostic return(1); /* continue */ 804*0c5e0addSbostic } 805*0c5e0addSbostic 806*0c5e0addSbostic doprgold(){ 807*0c5e0addSbostic if(!u.ugold) 808*0c5e0addSbostic pline("You do not carry any gold."); 809*0c5e0addSbostic else if(u.ugold <= 500) 810*0c5e0addSbostic pline("You are carrying %ld gold pieces.", u.ugold); 811*0c5e0addSbostic else { 812*0c5e0addSbostic pline("You sit down in order to count your gold pieces."); 813*0c5e0addSbostic goldcounted = 500; 814*0c5e0addSbostic occupation = countgold; 815*0c5e0addSbostic occtxt = "counting your gold"; 816*0c5e0addSbostic } 817*0c5e0addSbostic return(1); 818*0c5e0addSbostic } 819*0c5e0addSbostic 820*0c5e0addSbostic /* --- end of gold counting section --- */ 821*0c5e0addSbostic 822*0c5e0addSbostic doprwep(){ 823*0c5e0addSbostic if(!uwep) pline("You are empty handed."); 824*0c5e0addSbostic else prinv(uwep); 825*0c5e0addSbostic return(0); 826*0c5e0addSbostic } 827*0c5e0addSbostic 828*0c5e0addSbostic doprarm(){ 829*0c5e0addSbostic if(!uarm && !uarmg && !uarms && !uarmh) 830*0c5e0addSbostic pline("You are not wearing any armor."); 831*0c5e0addSbostic else { 832*0c5e0addSbostic char lets[6]; 833*0c5e0addSbostic register int ct = 0; 834*0c5e0addSbostic 835*0c5e0addSbostic if(uarm) lets[ct++] = obj_to_let(uarm); 836*0c5e0addSbostic if(uarm2) lets[ct++] = obj_to_let(uarm2); 837*0c5e0addSbostic if(uarmh) lets[ct++] = obj_to_let(uarmh); 838*0c5e0addSbostic if(uarms) lets[ct++] = obj_to_let(uarms); 839*0c5e0addSbostic if(uarmg) lets[ct++] = obj_to_let(uarmg); 840*0c5e0addSbostic lets[ct] = 0; 841*0c5e0addSbostic doinv(lets); 842*0c5e0addSbostic } 843*0c5e0addSbostic return(0); 844*0c5e0addSbostic } 845*0c5e0addSbostic 846*0c5e0addSbostic doprring(){ 847*0c5e0addSbostic if(!uleft && !uright) 848*0c5e0addSbostic pline("You are not wearing any rings."); 849*0c5e0addSbostic else { 850*0c5e0addSbostic char lets[3]; 851*0c5e0addSbostic register int ct = 0; 852*0c5e0addSbostic 853*0c5e0addSbostic if(uleft) lets[ct++] = obj_to_let(uleft); 854*0c5e0addSbostic if(uright) lets[ct++] = obj_to_let(uright); 855*0c5e0addSbostic lets[ct] = 0; 856*0c5e0addSbostic doinv(lets); 857*0c5e0addSbostic } 858*0c5e0addSbostic return(0); 859*0c5e0addSbostic } 860*0c5e0addSbostic 861*0c5e0addSbostic digit(c) char c; { 862*0c5e0addSbostic return(c >= '0' && c <= '9'); 863*0c5e0addSbostic } 864