This Patch is licensed under the NetHack General Public License. Created on 2015-07-22, by APic@IRCnet; Credits to ais523 diff --git a/libnethack/include/prop.h b/libnethack/include/prop.h index 2cb5e07..bc49434 100644 --- a/libnethack/include/prop.h +++ b/libnethack/include/prop.h @@ -103,7 +103,8 @@ enum objslot { os_last_armor = os_armu, /* Other worn equipment */ - os_amul, /* amulet */ + os_amull, /* left amulet */ + os_amulr, /* right amulet (only possible for ettins) */ os_ringl, /* left ring */ os_ringr, /* right ring */ os_tool, /* eyewear */ @@ -234,6 +235,7 @@ enum tracked_location { # define W_WORN (W_MASK(os_last_worn) * 2 - 1) # define W_EQUIP (W_MASK(os_last_equip) * 2 - 1) # define W_MASKABLE (W_MASK(os_last_maskable) * 2 - 1) +# define W_AMULET (W_MASK(os_amull) | W_MASK(os_amulr)) # define W_RING (W_MASK(os_ringl) | W_MASK(os_ringr)) # define W_ARTIFACT (W_MASK(os_carried) | W_MASK(os_invoked)) @@ -249,7 +251,8 @@ enum tracked_location { # define uarmg EQUIP(os_armg) # define uarmf EQUIP(os_armf) # define uarmu EQUIP(os_armu) -# define uamul EQUIP(os_amul) +# define uamull EQUIP(os_amull) +# define uamulr EQUIP(os_amulr) # define uleft EQUIP(os_ringl) # define uright EQUIP(os_ringr) # define ublindf EQUIP(os_tool) diff --git a/libnethack/src/do_wear.c b/libnethack/src/do_wear.c index dae6c31..c06bf3d 100644 --- a/libnethack/src/do_wear.c +++ b/libnethack/src/do_wear.c @@ -16,7 +16,8 @@ static const char * const c_slotnames[] = { [os_armg] = "gloves", [os_armf] = "boots", [os_armu] = "shirt", - [os_amul] = "amulet", + [os_amull] = "amulet", + [os_amulr] = "amulet", [os_ringl] = "ring", [os_ringr] = "ring", [os_tool] = "eyewear", @@ -34,7 +35,8 @@ static const char * const c_slotnames_menu[] = { [os_armg] = "Gloves", [os_armf] = "Boots", [os_armu] = "Shirt", - [os_amul] = "Amulet", + [os_amull] = "L. Amulet", + [os_amulr] = "R. Amulet", [os_ringl] = "L. Ring", [os_ringr] = "R. Ring", [os_tool] = "Eyewear", @@ -42,7 +44,7 @@ static const char * const c_slotnames_menu[] = { [os_swapwep] = "Readied", /* special case: "Offhand" if twoweaponing */ [os_quiver] = "Quiver", }; -#define LONGEST_SLOTNAME 7 /* longest length of a c_slotnames_menu entry */ +#define LONGEST_SLOTNAME 9 /* longest length of a c_slotnames_menu entry */ static const char c_that_[] = "that"; @@ -109,8 +111,11 @@ static const struct equip_order { {os_armc, ed_equip }, /* Slots that don't block anything. */ - {os_amul, ed_unequip}, - {os_amul, ed_equip}, + {os_amull, ed_unequip}, + {os_amulr, ed_unequip}, + {os_amulr, ed_equip }, + {os_amull, ed_equip }, + {os_armh, ed_unequip}, {os_armh, ed_equip}, {os_armf, ed_unequip}, @@ -230,7 +235,7 @@ setequip(enum objslot slot, struct obj *otmp, enum equipmsg msgtype) pline("%s falls off your %s!", Yname2(o), (slot == os_ringl || slot == os_ringr) ? body_part(FINGER) : - slot == os_amul ? body_part(NECK) : + (slot == os_amull || slot == os_amulr) ? body_part(NECK) : slot == os_tool ? body_part(FACE) : "body"); } @@ -915,7 +920,8 @@ equip_heartbeat(void) break; case os_ringl: case os_ringr: - case os_amul: + case os_amull: + case os_amulr: case os_tool: action_cost = 1; break; @@ -1302,6 +1308,26 @@ dowear(const struct nh_cmd_arg *arg) } } + /* If we can place an amulet on either hand, try without cblock in order + to see if one amulet head is faster to equip (because there's already + an amulet on the other head). */ + if (mask == W_AMULET && !canwearobj(otmp, &mask, FALSE, FALSE, FALSE)) { + /* We could reach this point if there's an amulet on both heads, or if + the selected amulet is already worn. We don't want to auto-de-equip + an arbitrary amulet. */ + if (otmp->owornmask & W_AMULET) { + /* There is actually a sensible response to this situation: we could + move the amulet to the other head. For the time being, though, we + don't do that unless explicitly requested with A, to avoid + ridiculous accidents. */ + pline("That amulet is already on your head!"); + return 0; + } else { + pline("Both your heads are already full."); + return 0; + } + } + /* The way this (mask & W_MASK(j)) check is written, we pick an arbitrary ring slot for rings that could still reasonably go on either hand, rather than prompting. The player can place a ring on a specific hand using the @@ -1432,7 +1458,9 @@ slot_count(struct monst *mon, enum objslot slot, boolean noisy) * * This function now also checks for the amulet, ring, and blindfold slots. In * the case of rings, *mask will be W_RING if both ring slots are free, - * W_MASK(os_ringl) or W_MASK(os_ringr) if only one ring slot is free. + * W_MASK(os_ringl) or W_MASK(os_ringr) if only one ring slot is free. In the + * case of amulets, *mask will be W_AMULET if both amulet slots are free, + * W_MASK(os_amull) or W_MASK(os_amulr) if only one amulet slot is free. * * You can get different outcomes from this function using the cblock value. * With cblock == TRUE, the return values are based on what could be @@ -1473,7 +1501,7 @@ canwearobj(struct obj *otmp, long *mask, else if (is_shirt(otmp)) slot = os_armu; else if (otmp->oclass == AMULET_CLASS) - slot = os_amul; + slot = os_amull; /* also os_amulr */ else if (otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) slot = os_ringl; /* also os_ringr */ else if (otmp->otyp == BLINDFOLD || otmp->otyp == LENSES || @@ -1486,7 +1514,8 @@ canwearobj(struct obj *otmp, long *mask, if (slot_count(&youmonst, slot, noisy) == 0) { return FALSE; } if ((verysmall(youmonst.data) || nohands(youmonst.data)) && - slot != os_amul && slot != os_ringl && slot != os_ringr && + slot != os_amull && slot != os_amulr && + slot != os_ringl && slot != os_ringr && slot != os_tool) { if (noisy) pline("You are in no state to equip armor!"); @@ -1523,6 +1552,23 @@ canwearobj(struct obj *otmp, long *mask, already_wearing("two rings"); return FALSE; } + } else if (slot == os_amull) { + /* Amulets are a special case because we have two slots to equip them + into, and thus we complain only if both are blocked. */ + temp_mask = W_AMULET; + if (CBLOCK(EQUIP(os_amull))) temp_mask &= ~W_MASK(os_amull); + boolean ettin = (monsndx(youmonst.data) == PM_ETTIN_MUMMY || + monsndx(youmonst.data) == PM_ETTIN_ZOMBIE || + monsndx(youmonst.data) == PM_ETTIN); + if (!ettin) + temp_mask &= ~W_MASK(os_amulr); + else if (CBLOCK(EQUIP(os_amulr))) + temp_mask &= ~W_MASK(os_amulr); + if (!temp_mask) { + if (noisy) + already_wearing(ettin? "two amulets" : "an amulet"); + return FALSE; + } } else { if (CBLOCK(EQUIP(slot))) { if (noisy) @@ -1689,6 +1735,13 @@ canwearobjon(struct obj *otmp, enum objslot slot, else pline("%s won't fit on that part of your body.", Yname2(otmp)); + /* Is this an attempt to wear an amulet on a blocked head, when the other + head is available? */ + if (mask & W_AMULET && (slot == os_amull || slot == os_amulr)) + pline("%s will only fit on your other head.", Yname2(otmp)); + else + pline("%s won't fit on that part of your body.", Yname2(otmp)); + return FALSE; } @@ -1935,9 +1988,12 @@ stuck_ring(struct obj *ring, int otyp) if (ring && ring->otyp == otyp) { /* reasons ring can't be removed match those checked by select_off(); limbless case has extra checks because ordinarily it's temporary */ - if (nolimbs(youmonst.data) && uamul && - uamul->otyp == AMULET_OF_UNCHANGING && uamul->cursed) - return uamul; + if (nolimbs(youmonst.data) && (uamull && + uamull->otyp == AMULET_OF_UNCHANGING && uamull->cursed)) + return uamull; + if (nolimbs(youmonst.data) && (uamulr && + uamull->otyp == AMULET_OF_UNCHANGING && uamull->cursed)) + return uamulr; if ((ring == uright || (uwep && bimanual(uwep))) && welded(uwep)) return uwep; if (uarmg && uarmg->cursed) @@ -1953,8 +2009,10 @@ stuck_ring(struct obj *ring, int otyp) struct obj * unchanger(void) { - if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) - return uamul; + if (uamull && uamull->otyp == AMULET_OF_UNCHANGING) + return uamull; + if (uamulr && uamulr->otyp == AMULET_OF_UNCHANGING) + return uamulr; return 0; } diff --git a/libnethack/src/eat.c b/libnethack/src/eat.c index 7a459bc..7430007 100644 --- a/libnethack/src/eat.c +++ b/libnethack/src/eat.c @@ -1794,7 +1794,9 @@ doeat(const struct nh_cmd_arg *arg) pline("You cannot eat that!"); return 0; } else if ((otmp->owornmask & (W_ARMOR | W_MASK(os_tool) | - W_MASK(os_amul) | W_MASK(os_saddle))) != 0) { + W_MASK(os_amull) | + W_MASK(os_amulr) | + W_MASK(os_saddle))) != 0) { /* let them eat rings */ pline("You can't eat something you're wearing."); return 0; @@ -2035,7 +2037,9 @@ gethungry(void) u.uhunger--; break; case 8: - if (uamul) + if (uamull) + u.uhunger--; + if (uamulr) u.uhunger--; break; case 12: diff --git a/libnethack/src/end.c b/libnethack/src/end.c index 7e83af6..ff0d36e 100644 --- a/libnethack/src/end.c +++ b/libnethack/src/end.c @@ -727,8 +727,10 @@ check_survival(int how) pline("You vomit ..."); pline("You feel much better!"); pline("The medallion crumbles to dust!"); - if (uamul) - useup(uamul); + if (uamull) + useup(uamull); + if (uamulr) + useup(uamulr); adjattrib(A_CON, -1, TRUE); if (u.uhpmax <= 0) diff --git a/libnethack/src/invent.c b/libnethack/src/invent.c index 571a62b..ff07aeb 100644 --- a/libnethack/src/invent.c +++ b/libnethack/src/invent.c @@ -2242,10 +2242,10 @@ int dopramulet(const struct nh_cmd_arg *arg) { (void) arg; - if (!uamul) + if (!uamull && !uamulr) pline("You are not wearing an amulet."); else - prinv(NULL, uamul, 0L); + prinv(NULL, uamull, 0L); return 0; } diff --git a/libnethack/src/mhitu.c b/libnethack/src/mhitu.c index 6644975..67f32d4 100644 --- a/libnethack/src/mhitu.c +++ b/libnethack/src/mhitu.c @@ -934,12 +934,12 @@ hitmu(struct monst *mtmp, const struct attack *mattk) /* No such thing as mindless players... */ if (ABASE(A_INT) <= ATTRMIN(A_INT)) { int lifesaved = 0; - struct obj *wore_amulet = uamul; + struct obj *wore_amulet = uamull; while (1) { /* avoid looping on "die(y/n)?" */ if (lifesaved && (discover || wizard)) { - if (wore_amulet && !uamul) { + if (wore_amulet && !uamull && !uamulr) { /* used up AMULET_OF_LIFE_SAVING; still subject to dying from brainlessness */ wore_amulet = 0; diff --git a/libnethack/src/mon.c b/libnethack/src/mon.c index 130af1c..218a96d 100644 --- a/libnethack/src/mon.c +++ b/libnethack/src/mon.c @@ -1590,7 +1590,12 @@ struct obj * mlifesaver(struct monst *mon) { if (!nonliving(mon->data)) { - struct obj *otmp = which_armor(mon, os_amul); + struct obj *otmp = which_armor(mon, os_amull); + + if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) + return otmp; + + otmp = which_armor(mon, os_amulr); if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) return otmp; diff --git a/libnethack/src/muse.c b/libnethack/src/muse.c index 290f801..5bd2d3f 100644 --- a/libnethack/src/muse.c +++ b/libnethack/src/muse.c @@ -2035,7 +2035,14 @@ mon_reflects(struct monst * mon, const char *str) if (str) pline(str, s_suffix(mon_nam(mon)), "weapon"); return TRUE; - } else if ((orefl = which_armor(mon, os_amul)) && + } else if ((orefl = which_armor(mon, os_amull)) && + orefl->otyp == AMULET_OF_REFLECTION) { + if (str) { + pline(str, s_suffix(mon_nam(mon)), "amulet"); + makeknown(AMULET_OF_REFLECTION); + } + return TRUE; + } else if ((orefl = which_armor(mon, os_amulr)) && orefl->otyp == AMULET_OF_REFLECTION) { if (str) { pline(str, s_suffix(mon_nam(mon)), "amulet"); @@ -2074,7 +2081,13 @@ ureflects(const char *fmt, const char *str) if (fmt && str) pline(fmt, str, "weapon"); return TRUE; - } else if (reflect_reason & W_MASK(os_amul)) { + } else if (reflect_reason & W_MASK(os_amull)) { + if (fmt && str) { + pline(fmt, str, "medallion"); + makeknown(AMULET_OF_REFLECTION); + } + return TRUE; + } else if (reflect_reason & W_MASK(os_amulr)) { if (fmt && str) { pline(fmt, str, "medallion"); makeknown(AMULET_OF_REFLECTION); diff --git a/libnethack/src/objnam.c b/libnethack/src/objnam.c index fc28660..9f118c3 100644 --- a/libnethack/src/objnam.c +++ b/libnethack/src/objnam.c @@ -720,8 +720,14 @@ doname_base(const struct obj *obj, boolean with_price) switch (obj->oclass) { case AMULET_CLASS: - if (obj->owornmask & W_WORN) - buf = msgcat(buf, " (being worn)"); + if (obj->owornmask & W_MASK(os_amulr)) + buf = msgcat(buf, " (on right "); + if (obj->owornmask & W_MASK(os_amull)) + buf = msgcat(buf, " (on left "); + if (obj->owornmask & W_AMULET) { + buf = msgcat(buf, body_part(HEAD)); + buf = msgcat(buf, ")"); + } break; case WEAPON_CLASS: if (ispoisoned) diff --git a/libnethack/src/polyself.c b/libnethack/src/polyself.c index 67be59c..974dc3f 100644 --- a/libnethack/src/polyself.c +++ b/libnethack/src/polyself.c @@ -15,6 +15,7 @@ static void polyman(const char *, const char *); static void break_armor(boolean); +static void drop_amulr(); static void drop_weapon(int, boolean); static void uunstick(void); static int armor_to_dragon(int); @@ -80,6 +81,8 @@ polyman(const char *fmt, const char *arg) } else pline(fmt, arg); + drop_amulr(); + if (u.twoweap && !could_twoweap(youmonst.data)) untwoweapon(); @@ -626,6 +629,7 @@ polymon(int mntmp, boolean noisy) will be set correctly, so break_armor will behave correctly. */ break_armor(noisy); drop_weapon(1, noisy); + drop_amulr(); if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(u.ux, u.uy); else if (youmonst.data->mlet == S_EEL) @@ -895,6 +899,24 @@ drop_weapon(int alone, boolean noisy) } } +void drop_amulr() +{ + struct obj *otmp; + + boolean ettin = (monsndx(youmonst.data) == PM_ETTIN_MUMMY || + monsndx(youmonst.data) == PM_ETTIN_ZOMBIE || + monsndx(youmonst.data) == PM_ETTIN); + + if(ettin) + return; + + if((otmp = uamulr) != 0) { + pline("Your right amulet falls off."); + setequip(os_amulr, NULL, em_silent); + dropx(otmp); + } +} + void rehumanize(int how, const char *killer) { diff --git a/libnethack/src/pray.c b/libnethack/src/pray.c index 14ab38a..16ef8bc 100644 --- a/libnethack/src/pray.c +++ b/libnethack/src/pray.c @@ -204,8 +204,10 @@ worst_cursed_item(void) otmp = uarmf; } else if (uarmu && uarmu->cursed) { /* shirt */ otmp = uarmu; - } else if (uamul && uamul->cursed) { /* amulet */ - otmp = uamul; + } else if (uamull && uamull->cursed) { /* left amulet */ + otmp = uamull; + } else if (uamulr && uamulr->cursed) { /* left amulet */ + otmp = uamulr; } else if (uleft && uleft->cursed) { /* left ring */ otmp = uleft; } else if (uright && uright->cursed) { /* right ring */ @@ -251,9 +253,13 @@ fix_worst_trouble(int trouble) set_delayed_killer(TURNED_SLIME, NULL); break; case ptr_strangled: - if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) { + if (uamull && uamull->otyp == AMULET_OF_STRANGULATION) { pline("Your amulet vanishes!"); - useup(uamul); + useup(uamull); + } + if (uamulr && uamulr->otyp == AMULET_OF_STRANGULATION) { + pline("Your amulet vanishes!"); + useup(uamulr); } pline("You can breathe again."); Strangled = 0; @@ -1298,8 +1304,10 @@ dosacrifice(const struct nh_cmd_arg *arg) return 1; } else { /* The final Test. Did you win? */ - if (uamul == otmp) - setequip(os_amul, NULL, em_voluntary); + if (uamull == otmp) + setequip(os_amull, NULL, em_voluntary); + if (uamulr == otmp) + setequip(os_amulr, NULL, em_voluntary); u.uevent.ascended = 1; if (carried(otmp)) useup(otmp); /* well, it's gone now */ diff --git a/libnethack/src/trap.c b/libnethack/src/trap.c index 3523842..1fd9876 100644 --- a/libnethack/src/trap.c +++ b/libnethack/src/trap.c @@ -2926,7 +2926,8 @@ emergency_disrobe(boolean * lostsome) them; and loadstones and other cursed stuff for obvious reasons. */ if (! - ((obj->otyp == LOADSTONE && obj->cursed) || obj == uamul || + ((obj->otyp == LOADSTONE && obj->cursed) || + obj == uamull || obj == uamulr || obj == uleft || obj == uright || obj == ublindf || obj == uarm || obj == uarmc || obj == uarmg || obj == uarmf || obj == uarmu || (obj->cursed && diff --git a/libnethack/src/wizard.c b/libnethack/src/wizard.c index 9ce0cc9..4424baa 100644 --- a/libnethack/src/wizard.c +++ b/libnethack/src/wizard.c @@ -52,7 +52,8 @@ amulet(void) struct trap *ttmp; struct obj *amu; - if ((((amu = uamul) != 0 && amu->otyp == AMULET_OF_YENDOR) || + if ((((amu = uamull) != 0 && amu->otyp == AMULET_OF_YENDOR) || + ((amu = uamulr) != 0 && amu->otyp == AMULET_OF_YENDOR) || ((amu = uwep) != 0 && amu->otyp == AMULET_OF_YENDOR)) && !rn2(15)) { for (ttmp = level->lev_traps; ttmp; ttmp = ttmp->ntrap) { diff --git a/libnethack/src/worn.c b/libnethack/src/worn.c index 1a35c4c..0d583ce 100644 --- a/libnethack/src/worn.c +++ b/libnethack/src/worn.c @@ -394,7 +394,10 @@ m_dowear(struct monst *mon, boolean creation) (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON]))) return; - m_dowear_type(mon, os_amul, creation, FALSE); + m_dowear_type(mon, os_amull, creation, FALSE); + if ((mon->data == &mons[PM_ETTIN]) || (mon->data == &mons[PM_ETTIN_MUMMY]) + || (mon->data == &mons[PM_ETTIN_ZOMBIE])) + m_dowear_type(mon, os_amulr, creation, FALSE); if (mon->data == &mons[PM_KI_RIN] || mon->data == &mons[PM_COUATL]) return; @@ -436,13 +439,14 @@ m_dowear_type(struct monst *mon, enum objslot slot, boolean creation, old = which_armor(mon, slot); if (old && old->cursed) return; - if (old && slot == os_amul) + if (old && (slot == os_amull || slot == os_amulr)) return; /* no such thing as better amulets */ best = old; for (obj = mon->minvent; obj; obj = obj->nobj) { switch (slot) { - case os_amul: + case os_amull: + case os_amulr: if (obj->oclass != AMULET_CLASS || (obj->otyp != AMULET_OF_LIFE_SAVING && obj->otyp != AMULET_OF_REFLECTION))