multi-shot throwing for knives & spears (trunk only)

Make all stackable weapons capable of multi-shot volleys when thrown.
Affects knives, spears & javelins, and boomerangs; requires advanced skill
assignment (skilled:  1-2 missiles per throw, expert:  1-3 missiles) or
role-specific bonus (ranger class's general +1 bonus is the only one that
applies to any of these weapon types).  For monsters, prince-caste get 1-3
missiles and lord-caste get 1-2, as before, with fake player monsters now
also getting 1-2; those counts apply to all stackable weapons regardless
of whether the species or role ordinarily uses whatever is being thrown.

     Related changes:  monks now get a role-based +1 count for shuriken,
throwing 1-2 instead of just one (they're only allowed to achieve basic
skill so won't reach any higher volley count).  Monster monks and ninjas
get that too; ninjas now get the same for darts and they're guaranteed
weapons in starting inventory.  Also, fake player rogues now sometimes
get orcish daggers instead of short sword, providing a decent chance to
occasionally have Grimtooth be randomly generated on the Astral level.

     Potentially controversial:  wizards can still become expert in dagger
skill and receive the to-hit and damage bonuses for that when throwing as
well as when wielding, but the number of missiles for them has now been
reduced to 1-2 (in other words, going from skilled to expert no longer
improves the max count for the volley amount for wizard role).  They're
supposed to be spellcasters; being able to throw up to three +7 daggers
at a pop was a big temptation for resorting to brute force, particularly
since they'll already want highest dagger skill for wielding Magicbane.

     To do:  throwing multiple boomerangs either needs to behave as if
they're all in flight before the first returns, or else the volley needs
to be cut short if one comes back and isn't successfully caught.  The
latter is a lot easier to do but the former fits better with what multi-
shot volley is supposed to represent.  Another alternative is to change
them to no longer be stackable, then this sequencing issue goes away.

     To do too:  make worm teeth and crysknives become stackable like the
other knife-skill weapons.
This commit is contained in:
nethack.rankin
2006-12-17 05:47:17 +00:00
parent cc19fff23d
commit 212623962e
6 changed files with 80 additions and 34 deletions

View File

@@ -269,6 +269,7 @@ add oracle and rumor regarding priestly donations
anti-magic traps have alternate effect on targets who have magic resistance
the Amulet can be offered to Moloch
javelins and spears now share the same weapon skill
all stackable weapons are capable of being thrown/shot for multi-shot volleys
Platform- and/or Interface-Specific New Features

View File

@@ -474,6 +474,7 @@ E void FDECL(impact_drop, (struct obj *,XCHAR_P,XCHAR_P,XCHAR_P));
E int NDECL(dothrow);
E int NDECL(dofire);
E void FDECL(endmultishot, (BOOLEAN_P));
E void FDECL(hitfloor, (struct obj *));
E void FDECL(hurtle, (int,int,int,BOOLEAN_P));
E void FDECL(mhurtle, (struct monst *,int,int,int));

View File

@@ -37,7 +37,7 @@ struct obj *obj;
int shotlimit;
{
struct obj *otmp;
int multishot = 1;
int multishot;
schar skill;
long wep_mask;
boolean twoweap;
@@ -109,18 +109,30 @@ int shotlimit;
/* Multishot calculations
*/
multishot = 1;
skill = objects[obj->otyp].oc_skill;
if ((ammo_and_launcher(obj, uwep) || skill == P_DAGGER ||
skill == -P_DART || skill == -P_SHURIKEN) &&
if (obj->quan > 1L && /* no point checking if there's only 1 */
/* ammo requires corresponding launcher be wielded */
(is_ammo(obj) ? matching_launcher(obj, uwep) :
/* otherwise any stackable (non-ammo) weapon */
obj->oclass == WEAPON_CLASS) &&
!(Confusion || Stunned)) {
/* Bonus if the player is proficient in this weapon... */
switch (P_SKILL(weapon_type(obj))) {
default: break; /* No bonus */
case P_SKILLED: multishot++; break;
case P_EXPERT: multishot += 2; break;
case P_EXPERT:
if (!Role_if(PM_WIZARD)) multishot++;
/*FALLTHRU*/
case P_SKILLED:
multishot++;
break;
default: /* No bonus */
break;
}
/* ...or is using a special weapon for their role... */
switch (Role_switch) {
case PM_MONK:
if (skill == -P_SHURIKEN) multishot++;
break;
case PM_RANGER:
multishot++;
break;
@@ -146,17 +158,20 @@ int shotlimit;
default:
break; /* No bonus */
}
}
/* crossbows are slow to load and probably shouldn't allow multiple
shots at all, but that would result in players never using them;
instead, we require high strength to load and shoot quickly */
if (multishot > 1 && (int)ACURRSTR < (Race_if(PM_GNOME) ? 16 : 18) &&
ammo_and_launcher(obj, uwep) && weapon_type(uwep) == P_CROSSBOW)
multishot = rnd(multishot);
if ((long)multishot > obj->quan) multishot = (int)obj->quan;
multishot = rnd(multishot);
if (shotlimit > 0 && multishot > shotlimit) multishot = shotlimit;
/* crossbows are slow to load and probably shouldn't allow multiple
shots at all, but that would result in players never using them;
instead, we require high strength to load and shoot quickly */
if (multishot > 1 &&
(int)ACURRSTR < (Race_if(PM_GNOME) ? 16 : 18) &&
ammo_and_launcher(obj, uwep) &&
weapon_type(uwep) == P_CROSSBOW)
multishot = rnd(multishot);
multishot = rnd(multishot);
if ((long)multishot > obj->quan) multishot = (int)obj->quan;
if (shotlimit > 0 && multishot > shotlimit) multishot = shotlimit;
}
m_shot.s = ammo_and_launcher(obj,uwep) ? TRUE : FALSE;
/* give a message if shooting more than one, or if player
@@ -192,7 +207,6 @@ int shotlimit;
return 1;
}
int
dothrow()
{
@@ -338,6 +352,19 @@ dofire()
return throw_obj(uquiver, shotlimit);
}
/* if in midst of multishot shooting/throwing, stop early */
void
endmultishot(verbose)
boolean verbose;
{
if (m_shot.i < m_shot.n) {
if (verbose && !context.mon_moving) {
You("stop %s after the %d%s %s.", m_shot.s ? "firing" : "throwing",
m_shot.i, ordin(m_shot.i), m_shot.s ? "shot" : "toss");
}
m_shot.n = m_shot.i; /* make current shot be the last */
}
}
/*
* Object hits floor at hero's feet. Called from drop() and throwit().
@@ -646,12 +673,7 @@ hurtle(dx, dy, range, verbose)
if (verbose)
You("%s in the opposite direction.", range > 1 ? "hurtle" : "float");
/* if we're in the midst of shooting multiple projectiles, stop */
if (m_shot.i < m_shot.n) {
/* last message before hurtling was "you shoot N arrows" */
You("stop %sing after the first %s.",
m_shot.s ? "shoot" : "throw", m_shot.s ? "shot" : "toss");
m_shot.n = m_shot.i; /* make current shot be the last */
}
endmultishot(TRUE);
if (In_sokoban(&u.uz))
change_luck(-1); /* Sokoban guilt */
uc.x = u.ux;

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)makemon.c 3.5 2006/09/06 */
/* SCCS Id: @(#)makemon.c 3.5 2006/12/15 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -244,6 +244,9 @@ register struct monst *mtmp;
if(!rn2(2)) curse(otmp);
(void) mpickobj(mtmp, otmp);
}
} else if (mm == PM_NINJA) { /* extra quest villains */
(void)mongets(mtmp, rn2(4) ? SHURIKEN : DART);
(void)mongets(mtmp, rn2(4) ? SHORT_SWORD : AXE);
}
break;

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)mplayer.c 3.5 2006/04/14 */
/* SCCS Id: @(#)mplayer.c 3.5 2006/12/15 */
/* Copyright (c) Izchak Miller, 1992. */
/* NetHack may be freely redistributed. See license for details. */
@@ -179,7 +179,7 @@ register boolean special;
if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL);
break;
case PM_MONK:
weapon = STRANGE_OBJECT;
weapon = !rn2(3) ? SHURIKEN : STRANGE_OBJECT;
armor = STRANGE_OBJECT;
cloak = ROBE;
if (rn2(2)) shield = STRANGE_OBJECT;
@@ -196,7 +196,7 @@ register boolean special;
if (rn2(2)) weapon = ELVEN_DAGGER;
break;
case PM_ROGUE:
if (rn2(2)) weapon = SHORT_SWORD;
if (rn2(2)) weapon = rn2(2) ? SHORT_SWORD : ORCISH_DAGGER;
break;
case PM_SAMURAI:
if (rn2(2)) weapon = KATANA;
@@ -232,6 +232,9 @@ register boolean special;
else if (!rn2(2)) otmp->greased = 1;
if (special && rn2(2))
otmp = mk_artifact(otmp, A_NONE);
/* usually increase stack size if stackable weapon */
if (objects[otmp->otyp].oc_merge && !otmp->oartifact)
otmp->quan += (long) rn2(is_spear(otmp) ? 4 : 8);
/* mplayers knew better than to overenchant Magicbane */
if (otmp->oartifact == ART_MAGICBANE)
otmp->spe = rnd(4);

View File

@@ -481,7 +481,6 @@ struct monst *mtmp;
{
struct obj *otmp, *mwep;
xchar x, y;
schar skill;
int multishot;
const char *onm;
@@ -533,18 +532,29 @@ struct monst *mtmp;
rn2(BOLT_LIM - distmin(x,y,mtmp->mux,mtmp->muy))))
return;
skill = objects[otmp->otyp].oc_skill;
mwep = MON_WEP(mtmp); /* wielded weapon */
/* Multishot calculations */
multishot = 1;
if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER ||
skill == -P_DART || skill == -P_SHURIKEN) && !mtmp->mconf) {
if (otmp->quan > 1L && /* no point checking if there's only 1 */
/* ammo requires corresponding launcher be wielded */
(is_ammo(otmp) ? matching_launcher(otmp, mwep) :
/* otherwise any stackable (non-ammo) weapon */
otmp->oclass == WEAPON_CLASS) &&
!mtmp->mconf) {
int skill = (int)objects[otmp->otyp].oc_skill;
/* Assumes lords are skilled, princes are expert */
if (is_prince(mtmp->data)) multishot += 2;
else if (is_lord(mtmp->data)) multishot++;
/* fake players treated as skilled (regardless of role limits) */
else if (is_mplayer(mtmp->data)) multishot++;
/* class bonus */
switch (monsndx(mtmp->data)) {
case PM_MONK:
if (skill == -P_SHURIKEN) multishot++;
break;
case PM_RANGER:
multishot++;
break;
@@ -552,6 +562,8 @@ struct monst *mtmp;
if (skill == P_DAGGER) multishot++;
break;
case PM_NINJA:
if (skill == -P_SHURIKEN || skill == -P_DART) multishot++;
/*FALLTHRU*/
case PM_SAMURAI:
if (otmp->otyp == YA && mwep &&
mwep->otyp == YUMI) multishot++;
@@ -568,9 +580,8 @@ struct monst *mtmp;
mwep && mwep->otyp == ORCISH_BOW))
multishot++;
multishot = rnd(multishot);
if ((long)multishot > otmp->quan) multishot = (int)otmp->quan;
if (multishot < 1) multishot = 1;
else multishot = rnd(multishot);
}
if (canseemon(mtmp)) {
@@ -595,9 +606,14 @@ struct monst *mtmp;
}
m_shot.n = multishot;
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++)
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
/* this continues even if mtmp gets killed (shot kills
adjacent gas spore and triggers explosion, perhaps)
because they're supposed to have been shot in a rapid
fire volley and conceptually all be in flight at once */
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
}
m_shot.n = m_shot.i = 0;
m_shot.o = STRANGE_OBJECT;
m_shot.s = FALSE;