diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 3a183935f..7aff12fb6 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1514,6 +1514,7 @@ cursed magic whistle can teleport you to your pet Fire and Frost Brand can be invoked for expert level fireball or cone of cold wielding Trollsbane grants hungerless regeneration hitting with Ogresmasher gives a higher chance of knockback +Snickersnee can hit at a distance once per turn for free Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/context.h b/include/context.h index ab9baf3bb..d98ada70e 100644 --- a/include/context.h +++ b/include/context.h @@ -148,6 +148,7 @@ struct context_info { int warnlevel; /* threshold (digit) to warn about unseen mons */ long next_attrib_check; /* next attribute check */ long seer_turn; /* when random clairvoyance will next kick in */ + long snickersnee_turn; /* Snickersnee last used to distance attack */ long stethoscope_seq; /* when a stethoscope was last used; first use * during a move takes no time, second uses move */ boolean travel; /* find way automatically to u.tx,u.ty */ diff --git a/include/obj.h b/include/obj.h index 782f545bf..e23c5f457 100644 --- a/include/obj.h +++ b/include/obj.h @@ -222,10 +222,12 @@ struct obj { (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= P_SHORT_SWORD \ && objects[otmp->otyp].oc_skill <= P_SABER) +/* Snickersnee is not a polearm, but can hit from distance */ #define is_pole(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && (objects[otmp->otyp].oc_skill == P_POLEARMS \ - || objects[otmp->otyp].oc_skill == P_LANCE)) + || objects[otmp->otyp].oc_skill == P_LANCE \ + || is_art(otmp, ART_SNICKERSNEE))) #define is_spear(otmp) \ (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill == P_SPEAR) #define is_launcher(otmp) \ diff --git a/include/patchlevel.h b/include/patchlevel.h index 905dff4fe..bfb185ef1 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 123 +#define EDITLEVEL 124 /* * Development status possibilities. diff --git a/include/seffects.h b/include/seffects.h index 91a9153a9..0774209b0 100644 --- a/include/seffects.h +++ b/include/seffects.h @@ -197,6 +197,7 @@ seffect(stone_breaking), seffect(stone_crumbling), seffect(swoosh), + seffect(sword_blade_rings), seffect(thud), seffect(thump), seffect(thunderclap), diff --git a/src/apply.c b/src/apply.c index a9142e75a..61219a716 100644 --- a/src/apply.c +++ b/src/apply.c @@ -33,6 +33,7 @@ staticfn int use_stone(struct obj *); staticfn int set_trap(void); /* occupation callback */ staticfn void display_polearm_positions(boolean); staticfn void calc_pole_range(int *, int *); +staticfn boolean snickersnee_used_dist_attk(struct obj *); staticfn int use_cream_pie(struct obj *); staticfn int jelly_ok(struct obj *); staticfn int use_royal_jelly(struct obj **); @@ -3403,6 +3404,16 @@ could_pole_mon(void) return FALSE; } +/* was Snickersnee used to attack at distance this turn already? */ +staticfn boolean +snickersnee_used_dist_attk(struct obj *obj) +{ + if (obj && obj == uwep && u_wield_art(ART_SNICKERSNEE) + && svc.context.snickersnee_turn == svm.moves) + return TRUE; + return FALSE; +} + /* Distance attacks by pole-weapons */ int use_pole(struct obj *obj, boolean autohit) @@ -3412,6 +3423,7 @@ use_pole(struct obj *obj, boolean autohit) coord cc; struct monst *mtmp; struct monst *hitm = svc.context.polearm.hitmon; + boolean freehit = FALSE; /* Are you allowed to use the pole? */ if (u.uswallow) { @@ -3480,8 +3492,25 @@ use_pole(struct obj *obj, boolean autohit) if (overexertion()) return ECMD_TIME; /* burn nutrition; maybe pass out */ svc.context.polearm.hitmon = mtmp; + + if (snickersnee_used_dist_attk(obj)) { + pline_The("blade doesn't reach there!"); + return ECMD_FAIL; + } + check_caitiff(mtmp); gn.notonhead = (gb.bhitpos.x != mtmp->mx || gb.bhitpos.y != mtmp->my); + + /* Snickersnee allows one free hit from a distance per turn */ + if (obj == uwep && u_wield_art(ART_SNICKERSNEE)) { + freehit = (svm.moves != svc.context.snickersnee_turn); + svc.context.snickersnee_turn = svm.moves; + if (freehit && !Deaf) { + Soundeffect(se_sword_blade_rings, 100); + pline("Shkinng!"); /* /sha-kin!/ */ + } + } + (void) thitmonst(mtmp, uwep); } else if (glyph_is_statue(glyph) /* might be hallucinatory */ && sobj_at(STATUE, gb.bhitpos.x, gb.bhitpos.y)) { @@ -3523,7 +3552,7 @@ use_pole(struct obj *obj, boolean autohit) } } u_wipe_engr(2); /* same as for melee or throwing */ - return ECMD_TIME; + return freehit ? ECMD_OK : ECMD_TIME; } #undef glyph_is_poleable diff --git a/src/wield.c b/src/wield.c index 9aaea38fc..53b0aa94f 100644 --- a/src/wield.c +++ b/src/wield.c @@ -123,7 +123,7 @@ setuwep(struct obj *obj) if (obj) { gu.unweapon = (obj->oclass == WEAPON_CLASS) ? is_launcher(obj) || is_ammo(obj) || is_missile(obj) - || (is_pole(obj) && !u.usteed) + || (is_pole(obj) && !u.usteed && !is_art(obj, ART_SNICKERSNEE)) : !is_weptool(obj) && !is_wet_towel(obj); } else gu.unweapon = TRUE; /* for "bare hands" message */