Split some parts of getobj into functions

This commit is contained in:
Pasi Kallinen
2020-11-27 18:10:47 +02:00
parent bb9df368af
commit 2a7cb3c4b6
+166 -138
View File
@@ -1464,97 +1464,13 @@ const char *action;
return !strcmp(action, "wear") || !strcmp(action, "put on"); return !strcmp(action, "wear") || !strcmp(action, "put on");
} }
/* /* helper for getobj(), exclude obj if it cannot be used to do word */
* getobj returns: static boolean
* struct obj *xxx: object to do something with. getobj_obj_exclude(word, otmp)
* (struct obj *) 0 error return: no object. const char *word;
* &cg.zeroobj explicitly no object (as in w-). struct obj *otmp;
!!!! test if gold can be used in unusual ways (eaten etc.)
!!!! may be able to remove "usegold"
*/
struct obj *
getobj(let, word)
register const char *let, *word;
{ {
register struct obj *otmp; return ((taking_off(word) /* exclude if not worn */
register char ilet = 0;
char buf[BUFSZ], qbuf[QBUFSZ];
char lets[BUFSZ], altlets[BUFSZ], *ap;
register int foo = 0;
register char *bp = buf;
xchar allowcnt = 0; /* 0, 1 or 2 */
boolean usegold = FALSE; /* can't use gold because its illegal */
boolean allowall = FALSE;
boolean allownone = FALSE;
boolean useboulder = FALSE;
xchar foox = 0;
long cnt;
boolean cntgiven = FALSE;
boolean msggiven = FALSE;
boolean oneloop = FALSE;
long dummymask;
Loot *sortedinvent, *srtinv;
if (*let == ALLOW_COUNT)
let++, allowcnt = 1;
if (*let == COIN_CLASS)
let++, usegold = TRUE;
/* Equivalent of an "ugly check" for gold */
if (usegold && !strcmp(word, "eat")
&& (!metallivorous(g.youmonst.data)
|| g.youmonst.data == &mons[PM_RUST_MONSTER]))
usegold = FALSE;
if (*let == ALL_CLASSES)
let++, allowall = TRUE;
if (*let == ALLOW_NONE)
let++, allownone = TRUE;
/* "ugly check" for reading fortune cookies, part 1.
* The normal 'ugly check' keeps the object on the inventory list.
* We don't want to do that for shirts/cookies, so the check for
* them is handled a bit differently (and also requires that we set
* allowall in the caller).
*/
if (allowall && !strcmp(word, "read"))
allowall = FALSE;
/* another ugly check: show boulders (not statues) */
if (*let == WEAPON_CLASS && !strcmp(word, "throw")
&& throws_rocks(g.youmonst.data))
useboulder = TRUE;
if (allownone)
*bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
ap = altlets;
if (!flags.invlet_constant)
reassign();
/* force invent to be in invlet order before collecting candidate
inventory letters */
sortedinvent = sortloot(&g.invent, SORTLOOT_INVLET, FALSE,
(boolean FDECL((*), (OBJ_P))) 0);
for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
if (&bp[foo] == &buf[sizeof buf - 1]
|| ap == &altlets[sizeof altlets - 1]) {
/* we must have a huge number of NOINVSYM items somehow */
impossible("getobj: inventory overflow");
break;
}
if (!*let || index(let, otmp->oclass)
|| (usegold && otmp->invlet == GOLD_SYM)
|| (useboulder && otmp->otyp == BOULDER)) {
register int otyp = otmp->otyp;
bp[foo++] = otmp->invlet;
/* clang-format off */
/* *INDENT-OFF* */
/* ugly check: remove inappropriate things */
if (
(taking_off(word) /* exclude if not worn */
&& !(otmp->owornmask & (W_ARMOR | W_ACCESSORY))) && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
|| (putting_on(word) /* exclude if already worn */ || (putting_on(word) /* exclude if already worn */
&& (otmp->owornmask & (W_ARMOR | W_ACCESSORY))) && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
@@ -1566,17 +1482,19 @@ register const char *let, *word;
&& ((otmp == uwep || (otmp == uswapwep && u.twoweap)) && ((otmp == uwep || (otmp == uswapwep && u.twoweap))
&& otmp->quan == 1L)) /* ...unless more than one */ && otmp->quan == 1L)) /* ...unless more than one */
|| ((!strcmp(word, "dip") || !strcmp(word, "grease")) || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
&& inaccessible_equipment(otmp, (const char *) 0, FALSE)) && inaccessible_equipment(otmp, (const char *) 0, FALSE)));
) { }
foo--;
foox++; /* helper for getobj(), exclude obj if it cannot be used to do word */
} static boolean
/* Second ugly check; unlike the first it won't trigger an getobj_obj_exclude_too(word, otmp)
* "else" in "you don't have anything else to ___". const char *word;
*/ struct obj *otmp;
else if ( {
(putting_on(word) short otyp = otmp->otyp;
&& ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
return ((putting_on(word)
&& ((otmp->oclass == FOOD_CLASS && otyp != MEAT_RING)
|| (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
&& otyp != TOWEL && otyp != LENSES))) && otyp != TOWEL && otyp != LENSES)))
|| (!strcmp(word, "wield") || (!strcmp(word, "wield")
@@ -1635,26 +1553,28 @@ register const char *let, *word;
|| !objects[HORN_OF_PLENTY].oc_name_known)) || !objects[HORN_OF_PLENTY].oc_name_known))
|| (!strcmp(word, "charge") && !is_chargeable(otmp)) || (!strcmp(word, "charge") && !is_chargeable(otmp))
|| (!strcmp(word, "open") && otyp != TIN) || (!strcmp(word, "open") && otyp != TIN)
|| (!strcmp(word, "call") && !objtyp_is_callable(otyp)) || (!strcmp(word, "call") && !objtyp_is_callable(otyp)));
|| (!strcmp(word, "adjust") && otmp->oclass == COIN_CLASS }
&& !usegold)
) { /* helper for getobj(), obj is acceptable but not listed */
foo--; static boolean
} getobj_obj_acceptable_unlisted(word, otmp, let)
/* Third ugly check: acceptable but not listed as likely const char *word;
* candidates in the prompt or in the inventory subset if struct obj *otmp;
* player responds with '?'. char let;
*/ {
else if ( long dummymask;
/* ugly check for unworn armor that can't be worn */ short otyp = otmp->otyp;
(putting_on(word) && *let == ARMOR_CLASS
return (/* ugly check for unworn armor that can't be worn */
(putting_on(word) && let == ARMOR_CLASS
&& !canwearobj(otmp, &dummymask, FALSE)) && !canwearobj(otmp, &dummymask, FALSE))
/* or armor with 'P' or 'R' or accessory with 'W' or 'T' */ /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
|| ((putting_on(word) || taking_off(word)) || ((putting_on(word) || taking_off(word))
&& ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS))) && ((let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
/* or unsuitable items rubbed on known touchstone */ /* or unsuitable items rubbed on known touchstone */
|| (!strncmp(word, "rub on the stone", 16) || (!strncmp(word, "rub on the stone", 16)
&& *let == GEM_CLASS && otmp->dknown && let == GEM_CLASS && otmp->dknown
&& objects[otyp].oc_name_known) && objects[otyp].oc_name_known)
/* suppress corpses on astral, amulets elsewhere */ /* suppress corpses on astral, amulets elsewhere */
|| (!strcmp(word, "sacrifice") || (!strcmp(word, "sacrifice")
@@ -1669,15 +1589,138 @@ register const char *let, *word;
(boolean) (otmp->oclass == RING_CLASS))) (boolean) (otmp->oclass == RING_CLASS)))
|| (!strcmp(word, "write on") || (!strcmp(word, "write on")
&& (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER) && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
|| !otmp->dknown || !objects[otyp].oc_name_known)) || !otmp->dknown || !objects[otyp].oc_name_known)));
) { }
/* acceptable but not listed as likely candidate */
void
mime_action(word)
const char *word;
{
char buf[BUFSZ];
char *bp = buf;
char *suf = (char *) 0;
strcpy(buf, word);
if ((bp = strstr(buf, " on the ")) != 0) {
/* rub on the stone[s] */
*bp = '\0';
suf = (bp + 1);
}
if ((bp = strstr(buf, " or ")) != 0) {
*bp = '\0';
bp = (rn2(2) ? buf : (bp + 4));
} else
bp = buf;
You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
suf ? suf : "");
}
/*
* getobj returns:
* struct obj *xxx: object to do something with.
* (struct obj *) 0 error return: no object.
* &cg.zeroobj explicitly no object (as in w-).
!!!! test if gold can be used in unusual ways (eaten etc.)
!!!! may be able to remove "usegold"
*/
struct obj *
getobj(let, word)
register const char *let, *word;
{
register struct obj *otmp;
register char ilet = 0;
char buf[BUFSZ], qbuf[QBUFSZ];
char lets[BUFSZ], altlets[BUFSZ], *ap;
register int foo = 0;
register char *bp = buf;
xchar allowcnt = 0; /* 0, 1 or 2 */
boolean usegold = FALSE; /* can't use gold because its illegal */
boolean allowall = FALSE;
boolean allownone = FALSE;
boolean useboulder = FALSE;
xchar foox = 0;
long cnt;
boolean cntgiven = FALSE;
boolean msggiven = FALSE;
boolean oneloop = FALSE;
Loot *sortedinvent, *srtinv;
if (*let == ALLOW_COUNT)
let++, allowcnt = 1;
if (*let == COIN_CLASS)
let++, usegold = TRUE;
/* Equivalent of an "ugly check" for gold */
if (usegold && !strcmp(word, "eat")
&& (!metallivorous(g.youmonst.data)
|| g.youmonst.data == &mons[PM_RUST_MONSTER]))
usegold = FALSE;
if (*let == ALL_CLASSES)
let++, allowall = TRUE;
if (*let == ALLOW_NONE)
let++, allownone = TRUE;
/* "ugly check" for reading fortune cookies, part 1.
* The normal 'ugly check' keeps the object on the inventory list.
* We don't want to do that for shirts/cookies, so the check for
* them is handled a bit differently (and also requires that we set
* allowall in the caller).
*/
if (allowall && !strcmp(word, "read"))
allowall = FALSE;
/* another ugly check: show boulders (not statues) */
if (*let == WEAPON_CLASS && !strcmp(word, "throw")
&& throws_rocks(g.youmonst.data))
useboulder = TRUE;
if (allownone)
*bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
ap = altlets;
if (!flags.invlet_constant)
reassign();
/* force invent to be in invlet order before collecting candidate
inventory letters */
sortedinvent = sortloot(&g.invent, SORTLOOT_INVLET, FALSE,
(boolean FDECL((*), (OBJ_P))) 0);
for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
if (&bp[foo] == &buf[sizeof buf - 1]
|| ap == &altlets[sizeof altlets - 1]) {
/* we must have a huge number of NOINVSYM items somehow */
impossible("getobj: inventory overflow");
break;
}
if (!*let || index(let, otmp->oclass)
|| (usegold && otmp->invlet == GOLD_SYM)
|| (useboulder && otmp->otyp == BOULDER)) {
register int otyp = otmp->otyp;
bp[foo++] = otmp->invlet;
/* remove inappropriate things */
if (getobj_obj_exclude(word, otmp)) {
foo--;
foox++;
}
/* remove inappropriate thing, but unlike the first it won't
* trigger an "else" in "you don't have anything else to ___".
*/
else if (getobj_obj_exclude_too(word, otmp)
|| (!strcmp(word, "adjust") && otmp->oclass == COIN_CLASS
&& !usegold)) {
foo--;
}
else if (getobj_obj_acceptable_unlisted(word, otmp, *let)) {
/* acceptable but not listed as likely candidates in the prompt
* or in the inventory subset if player responds with '?'.
*/
foo--; foo--;
allowall = TRUE; allowall = TRUE;
*ap++ = otmp->invlet; *ap++ = otmp->invlet;
} }
/* *INDENT-ON* */
/* clang-format on */
} else { } else {
/* "ugly check" for reading fortune cookies, part 2 */ /* "ugly check" for reading fortune cookies, part 2 */
if ((!strcmp(word, "read") && is_readable(otmp))) if ((!strcmp(word, "read") && is_readable(otmp)))
@@ -1743,23 +1786,8 @@ register const char *let, *word;
return (struct obj *) 0; return (struct obj *) 0;
} }
if (ilet == HANDS_SYM) { /* '-' */ if (ilet == HANDS_SYM) { /* '-' */
if (!allownone) { if (!allownone)
char *suf = (char *) 0; mime_action(word);
strcpy(buf, word);
if ((bp = strstr(buf, " on the ")) != 0) {
/* rub on the stone[s] */
*bp = '\0';
suf = (bp + 1);
}
if ((bp = strstr(buf, " or ")) != 0) {
*bp = '\0';
bp = (rn2(2) ? buf : (bp + 4));
} else
bp = buf;
You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
suf ? suf : "");
}
return (allownone ? (struct obj *) &cg.zeroobj : (struct obj *) 0); return (allownone ? (struct obj *) &cg.zeroobj : (struct obj *) 0);
} }
redo_menu: redo_menu: