diff --git a/doc/fixes36.2 b/doc/fixes36.2 index a24195e83..fc7a7218e 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -39,6 +39,13 @@ internals for 'sortloot' option have been changed to not reorder the actual give vault guards a cursed tin whistle since there is a shrill whistling sound if hero teleports out of vault while being confronted by guard polymorphing worn amulet triggers panic if it turns into amulet of change +wishing for small mimic corpse or large mimic corpse failed with 'nothing + matching that exists'; wishing for large {dog,cat,kobold} corpse + yielded normal size one (size prefix was being stripped off for globs) +wishing for "glob of grey ooze" failed even though grey ooze is recognized + as a variant spelling for gray ooze +spells of healing and extra healing cast at monsters handled monster blindness + inconsistently compared to other healing Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -46,6 +53,7 @@ Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository fix access violation when --debug:xxxx has no other args after it Setting the inverse attribute for gold had the space before "$:" getting highlighted along with the gold field +sortloot segfaulted when filtering a subset of items (seen with 'A' command) Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index c2d4861a8..9ea974698 100644 --- a/src/invent.c +++ b/src/invent.c @@ -462,7 +462,7 @@ boolean FDECL((*filterfunc), (OBJ_P)); augment_filter = (mode & SORTLOOT_PETRIFY) ? TRUE : FALSE; mode &= ~SORTLOOT_PETRIFY; /* remove flag, leaving mode */ /* populate aliarray[0..n-1] */ - for (i = 0, o = *olist; o; ++i, o = by_nexthere ? o->nexthere : o->nobj) { + for (i = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj) { if (filterfunc && !(*filterfunc)(o) /* caller may be asking us to override filterfunc (in order to do a cockatrice corpse touch check during pickup even @@ -473,6 +473,7 @@ boolean FDECL((*filterfunc), (OBJ_P)); sliarray[i].obj = o, sliarray[i].indx = (int) i; sliarray[i].str = (char *) 0; sliarray[i].orderclass = sliarray[i].subclass = sliarray[i].disco = 0; + ++i; } n = i; /* add a terminator so that we don't have to pass 'n' back to caller */ diff --git a/src/objnam.c b/src/objnam.c index b836530b5..5fa0ddd42 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -2474,7 +2474,7 @@ boolean to_plural; /* true => makeplural, false => makesingular */ int i, al; char *endstr, *spot; /* these are all the prefixes for *man that don't have a *men plural */ - const char *no_men[] = { + static const char *no_men[] = { "albu", "antihu", "anti", "ata", "auto", "bildungsro", "cai", "cay", "ceru", "corner", "decu", "des", "dura", "fir", "hanu", "het", "infrahu", "inhu", "nonhu", "otto", "out", "prehu", "protohu", @@ -2482,11 +2482,11 @@ boolean to_plural; /* true => makeplural, false => makesingular */ "hu", "un", "le", "re", "so", "to", "at", "a", }; /* these are all the prefixes for *men that don't have a *man singular */ - const char *no_man[] = { + static const char *no_man[] = { "abdo", "acu", "agno", "ceru", "cogno", "cycla", "fleh", "grava", "hegu", "preno", "sonar", "speci", "dai", "exa", "fla", "sta", "teg", - "tegu", "vela", "da", "hy", "lu", "no", "nu", "ra", "ru", "se", "vi", "ya", - "o", "a", + "tegu", "vela", "da", "hy", "lu", "no", "nu", "ra", "ru", "se", "vi", + "ya", "o", "a", }; if (!basestr || strlen(basestr) < 4) @@ -2721,9 +2721,9 @@ char oclass; if (!name) return STRANGE_OBJECT; - memset((genericptr_t) validobjs, 0, sizeof(validobjs)); + memset((genericptr_t) validobjs, 0, sizeof validobjs); - for (i = oclass ? bases[(int)oclass] : STRANGE_OBJECT + 1; + for (i = oclass ? bases[(int) oclass] : STRANGE_OBJECT + 1; i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass); ++i) { /* don't match extra descriptions (w/o real name) */ @@ -2775,7 +2775,7 @@ struct obj *no_wish; int wetness, gsize = 0; struct fruit *f; int ftype = context.current_fruit; - char fruitbuf[BUFSZ]; + char fruitbuf[BUFSZ], globbuf[BUFSZ]; /* Fruits may not mess up the ability to wish for real objects (since * you can leave a fruit in a bones file and it will be added to * another person's game), so they must be checked for last, after @@ -2920,12 +2920,25 @@ struct obj *no_wish; } else if (!strncmpi(bp, "empty ", l = 6)) { contents = EMPTY; } else if (!strncmpi(bp, "small ", l = 6)) { /* glob sizes */ + /* "small" might be part of monster name (mimic, if wishing + for its corpse) rather than prefix for glob size; when + used for globs, it might be either "small glob of " or + "small glob" and user might add 's' even though plural + doesn't accomplish anything because globs don't stack */ + if (strncmpi(bp + l, "glob", 4) && !strstri(bp + l, " glob")) + break; gsize = 1; } else if (!strncmpi(bp, "medium ", l = 7)) { /* xname() doesn't display "medium" but without this - there'd be no way to ask for the intermediate size */ + there'd be no way to ask for the intermediate size + ("glob" without size prefix yields smallest one) */ gsize = 2; } else if (!strncmpi(bp, "large ", l = 6)) { + /* "large" might be part of monster name (dog, cat, koboold, + mimic) or object name (box, round shield) rather than + prefix for glob size */ + if (strncmpi(bp + l, "glob", 4) && !strstri(bp + l, " glob")) + break; /* "very large " had "very " peeled off on previous iteration */ gsize = (very != 1) ? 3 : 4; } else @@ -2933,7 +2946,7 @@ struct obj *no_wish; bp += l; } if (!cnt) - cnt = 1; /* %% what with "gems" etc. ? */ + cnt = 1; /* will be changed to 2 if makesingular() changes string */ if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) { boolean keeptrailingchars = TRUE; @@ -3056,15 +3069,28 @@ struct obj *no_wish; * * also don't let player wish for multiple globs. */ - if ((p = strstri(bp, "glob of ")) != 0 + i = (int) strlen(bp); + p = (char *) 0; + /* check for "glob", " glob", and "glob of " */ + if (!strcmpi(bp, "glob") || !BSTRCMPI(bp, bp + i - 5, " glob") + || !strcmpi(bp, "globs") || !BSTRCMPI(bp, bp + i - 6, " globs") + || (p = strstri(bp, "glob of ")) != 0 || (p = strstri(bp, "globs of ")) != 0) { - int globoffset = (*(p + 4) == 's') ? 9 : 8; - - if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE - && mntmp <= PM_BLACK_PUDDING) { - mntmp = NON_PM; /* lie to ourselves */ - cnt = 0; /* force only one */ - } + mntmp = name_to_mon(!p ? bp : (strstri(p, " of ") + 4)); + /* if we didn't recognize monster type, pick a valid one at random */ + if (mntmp == NON_PM) + mntmp = rn1(PM_BLACK_PUDDING - PM_GRAY_OOZE, PM_GRAY_OOZE); + /* construct canonical spelling in case name_to_mon() recognized a + variant (grey ooze) or player used inverted syntax ( glob); + if player has given a valid monster type but not valid glob type, + object name lookup won't find it and wish attempt will fail */ + Sprintf(globbuf, "glob of %s", mons[mntmp].mname); + bp = globbuf; + mntmp = NON_PM; /* not useful for "glob of " object lookup */ + cnt = 0; /* globs don't stack */ + oclass = FOOD_CLASS; + actualn = bp, dn = 0; + goto srch; } else { /* * Find corpse type using "of" (figurine of an orc, tin of orc meat) @@ -3120,6 +3146,7 @@ struct obj *no_wish; /* first change to singular if necessary */ if (*bp) { char *sng = makesingular(bp); + if (strcmp(bp, sng)) { if (cnt == 1) cnt = 2; diff --git a/src/spell.c b/src/spell.c index 2b0e83dd6..27702bfdd 100644 --- a/src/spell.c +++ b/src/spell.c @@ -886,7 +886,7 @@ int spell; boolean atme; { int energy, damage, chance, n, intell; - int skill, role_skill, res = 0; + int otyp, skill, role_skill, res = 0; boolean confused = (Confusion != 0); boolean physical_damage = FALSE; struct obj *pseudo; @@ -1029,10 +1029,11 @@ boolean atme; * Find the skill the hero has in a spell type category. * See spell_skilltype for categories. */ - skill = spell_skilltype(pseudo->otyp); + otyp = pseudo->otyp; + skill = spell_skilltype(otyp); role_skill = P_SKILL(skill); - switch (pseudo->otyp) { + switch (otyp) { /* * At first spells act as expected. As the hero increases in skill * with the appropriate spell type, some spells increase in their @@ -1056,9 +1057,9 @@ boolean atme; } } else { explode(u.dx, u.dy, - pseudo->otyp - SPE_MAGIC_MISSILE + 10, + otyp - SPE_MAGIC_MISSILE + 10, spell_damage_bonus(u.ulevel / 2 + 1), 0, - (pseudo->otyp == SPE_CONE_OF_COLD) + (otyp == SPE_CONE_OF_COLD) ? EXPL_FROSTY : EXPL_FIERY); } @@ -1073,12 +1074,13 @@ boolean atme; } } break; - } /* else fall through... */ + } /* else */ + /*FALLTHRU*/ /* these spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: physical_damage = TRUE; - /* fall through */ + /*FALLTHRU*/ case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: @@ -1096,7 +1098,13 @@ boolean atme; case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: - if (!(objects[pseudo->otyp].oc_dir == NODIR)) { + if (objects[otyp].oc_dir != NODIR) { + if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) { + /* healing and extra healing are actually potion effects, + but they've been extended to take a direction like wands */ + if (role_skill >= P_SKILLED) + pseudo->blessed = 1; + } if (atme) { u.dx = u.dy = u.dz = 0; } else if (!getdir((char *) 0)) { @@ -1136,7 +1144,7 @@ boolean atme; /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; - /* fall through */ + /*FALLTHRU*/ case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: @@ -1152,7 +1160,7 @@ boolean atme; /* high skill yields effect equivalent to blessed potion */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; - /* fall through */ + /*FALLTHRU*/ case SPE_INVISIBILITY: (void) peffects(pseudo); break; diff --git a/src/zap.c b/src/zap.c index b2ff4c77a..1b83a3ad5 100644 --- a/src/zap.c +++ b/src/zap.c @@ -138,7 +138,7 @@ struct obj *otmp; boolean wake = TRUE; /* Most 'zaps' should wake monster */ boolean reveal_invis = FALSE, learn_it = FALSE; boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart; - boolean helpful_gesture = FALSE; + boolean skilled_spell, helpful_gesture = FALSE; int dmg, otyp = otmp->otyp; const char *zap_type_text = "spell"; struct obj *obj; @@ -149,10 +149,12 @@ struct obj *otmp; reveal_invis = FALSE; notonhead = (mtmp->mx != bhitpos.x || mtmp->my != bhitpos.y); + skilled_spell = (otmp && otmp->oclass == SPBOOK_CLASS && otmp->blessed); + switch (otyp) { case WAN_STRIKING: zap_type_text = "wand"; - /* fall through */ + /*FALLTHRU*/ case SPE_FORCE_BOLT: reveal_invis = TRUE; if (disguised_mimic) @@ -343,10 +345,12 @@ struct obj *otmp; mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4); if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - if (mtmp->mblinded) { - mtmp->mblinded = 0; - mtmp->mcansee = 1; - } + /* plain healing must be blessed to cure blindness; extra + healing only needs to not be cursed, so spell always cures + [potions quaffed by monsters behave slightly differently; + we use the rules for the hero here...] */ + if (skilled_spell || otyp == SPE_EXTRA_HEALING) + mcureblindness(mtmp, canseemon(mtmp)); if (canseemon(mtmp)) { if (disguised_mimic) { if (is_obj_mappear(mtmp,STRANGE_OBJECT)) { @@ -2407,7 +2411,7 @@ boolean ordinary; case SPE_EXTRA_HEALING: learn_it = TRUE; /* (no effect for spells...) */ healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4), 0, FALSE, - (obj->otyp == SPE_EXTRA_HEALING)); + (obj->blessed || obj->otyp == SPE_EXTRA_HEALING)); You_feel("%sbetter.", obj->otyp == SPE_EXTRA_HEALING ? "much " : ""); break; case WAN_LIGHT: /* (broken wand) */