From: nethack.rankin Date: Sat, 26 Oct 2013 21:33:47 +0000 (+0000) Subject: fix #H3033 - Crash upon teleport onto a sink while equipping levitation boots X-Git-Tag: MOVE2GIT~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d7a467fff1e4a141aae3655401119928ec9adcd4;p=nethack fix #H3033 - Crash upon teleport onto a sink while equipping levitation boots From a bug report, being teleported onto a sink while busy putting on levitation boots triggered a crash when Boots_on() was called (as '(*aftermv)()' on the next turn) because 'uarmf' would be null by then. Not mentioned, but the same problem was encountered by Boots_off() if the teleport happened while you were busy taking boots off. It could be fixed by having having dosinkfall() call cancel_don() if donning(uarmf) yields true, but this patch does a little more than that: cancel donning/doffing of any multi-turn armor if you fall onto a sink. It also prevents you from falling if you end up flying (which will have been blocked while levitating). The situation when putting on levitation boots has a sequencing issue: setworn() causes you to be flagged as levitating immediately, but the float_up() feedback doesn't occur until Boots_on() gets called a turn later. Teleporting to the sink will tell you that you crash onto the sink and and that you stop putting on boots, without having been told that you've floated up into the air. It's suboptimal but it doesn't seem to actually be incorrect. --- diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 118ba60c8..8aef6e126 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -848,6 +848,8 @@ entering an untended shop while blind gave an inappropriate message engraving feedback about partial text when weapon became too dull to finish was lacking sentence-ending period impossible() might display inaccurate feedback after updating paniclog +fix crash which occurred if hero was teleported onto a sink while busy putting + on or taking off levitation boots Platform- and/or Interface-Specific Fixes diff --git a/src/hack.c b/src/hack.c index 055930d9f..728e75774 100644 --- a/src/hack.c +++ b/src/hack.c @@ -497,9 +497,13 @@ dosinkfall() { register struct obj *obj; int dmg; + boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS), + innate_lev = ((HLevitation & (FROMOUTSIDE|FROMFORM)) != 0L), + ufall = (!innate_lev && !(HFlying || EFlying)); /* BFlying */ - if (HLevitation & (FROMOUTSIDE|FROMFORM)) { - You("wobble unsteadily for a moment."); + if (!ufall) { + You(innate_lev ? "wobble unsteadily for a moment." : + "gain control of your flight."); } else { long save_ELev = ELevitation, save_HLev = HLevitation; @@ -524,6 +528,25 @@ dosinkfall() HLevitation = save_HLev; } + /* + * Interrupt multi-turn putting on/taking off of armor (in which + * case we reached the sink due to being teleported while busy; + * in 3.4.3, Boots_on()/Boots_off() [called via (*aftermv)() when + * 'multi' reaches 0] triggered a crash if we were donning/doffing + * levitation boots [because the Boots_off() below causes 'uarmf' + * to be null by the time 'aftermv' gets called]). + * + * Interrupt donning/doffing if we fall onto the sink, or if the + * code below is going to remove levitation boots even when we + * haven't fallen (innate floating or flying becoming unblocked). + */ + if (ufall || lev_boots) { + (void) stop_donning(lev_boots ? uarmf : (struct obj *)0); + /* recalculate in case uarmf just got set to null */ + lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS); + } + + /* remove worn levitation items */ ELevitation &= ~W_ARTI; HLevitation &= ~(I_SPECIAL|TIMEOUT); HLevitation++; @@ -537,7 +560,7 @@ dosinkfall() Ring_off(obj); off_msg(obj); } - if(uarmf && uarmf->otyp == LEVITATION_BOOTS) { + if (lev_boots) { obj = uarmf; (void)Boots_off(); off_msg(obj);