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