Skip to content

Commit b963d19

Browse files
committed
Sling bullets can have object properties.
Sling bullets can now randomly spawn with certain object properties, the same types that are commonly found with arrow, darts, etc. You can also wish for an object property on sling bullets. In making this commit, I found and fixed several bugs - weapon tools (pick-axes) that had an object property wouldn't use its property if used to attack. Same for any weapon a monster used vs another monster that had properties. And a few other minor things.
1 parent 72eb0a2 commit b963d19

10 files changed

+51
-23
lines changed

doc/evilhack-changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -3412,4 +3412,5 @@ The following changes to date are:
34123412
- Set max skill for Wizards and quarterstaff back to expert
34133413
- Allow lightning spell to be cast as an area of effect ball of
34143414
lightning at skilled or greater in attack spells
3415+
- Sling bullets can have object properties
34153416

include/obj.h

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct obj {
210210
((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \
211211
&& objects[otmp->otyp].oc_skill >= -P_BOOMERANG \
212212
&& objects[otmp->otyp].oc_skill <= -P_DART)
213+
#define is_bullet(otmp) (otmp->otyp == SLING_BULLET)
213214
#define is_weptool(o) \
214215
((o)->oclass == TOOL_CLASS && objects[(o)->otyp].oc_skill != P_NONE)
215216
/* towel is not a weptool: spe isn't an enchantment, cursed towel

src/artifact.c

+12-6
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ boolean allow_detrimental;
368368
return otmp;
369369

370370
/* properties only added to weapons and armor */
371-
if (otmp->oclass != WEAPON_CLASS
371+
if (otmp->oclass != WEAPON_CLASS && !is_bullet(otmp)
372372
&& !is_weptool(otmp) && otmp->oclass != ARMOR_CLASS)
373373
return otmp;
374374

@@ -397,7 +397,7 @@ boolean allow_detrimental;
397397
| ITEM_VENOM | ITEM_DRLI | ITEM_OILSKIN)))
398398
continue;
399399

400-
if ((is_ammo(otmp) || is_missile(otmp))
400+
if ((is_ammo(otmp) || is_missile(otmp) || is_bullet(otmp))
401401
&& (j & (ITEM_DRLI | ITEM_OILSKIN | ITEM_ESP
402402
| ITEM_EXCEL | ITEM_SEARCHING | ITEM_WARNING
403403
| ITEM_FUMBLING | ITEM_HUNGER)))
@@ -428,7 +428,7 @@ boolean allow_detrimental;
428428
/* Fix it up as necessary */
429429
if (otmp->oprops
430430
&& (otmp->oclass == WEAPON_CLASS
431-
|| otmp->oclass == ARMOR_CLASS)
431+
|| otmp->oclass == ARMOR_CLASS || is_bullet(otmp))
432432
&& !(otmp->oprops & (ITEM_FUMBLING | ITEM_HUNGER))) {
433433
if (!rn2(8)) {
434434
blessorcurse(otmp, 8);
@@ -683,7 +683,8 @@ struct obj *otmp;
683683
return TRUE;
684684

685685
if (!weap && otmp->oprops
686-
&& (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)
686+
&& (otmp->oclass == WEAPON_CLASS
687+
|| is_weptool(otmp) || is_bullet(otmp)
687688
|| (uarms && otmp == uarms)
688689
|| (uarmg && otmp == uarmg))) {
689690
if (adtyp == AD_FIRE
@@ -1350,7 +1351,8 @@ int tmp;
13501351
int dbon = 0, adtype;
13511352

13521353
if (!weap && otmp->oprops
1353-
&& (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)
1354+
&& (otmp->oclass == WEAPON_CLASS
1355+
|| is_weptool(otmp) || is_bullet(otmp)
13541356
|| (uarms && otmp == uarms)
13551357
|| (uarmg && otmp == uarmg))) {
13561358
/* until we know otherwise... */
@@ -1826,6 +1828,7 @@ int dieroll; /* needed for Magicbane and vorpal blades */
18261828
: "burns",
18271829
hittee, !spec_dbon_applies ? '.' : '!');
18281830
} else if ((otmp->oclass == WEAPON_CLASS
1831+
|| is_weptool(otmp) || is_bullet(otmp)
18291832
|| otmp == uarms || otmp == uarmg)
18301833
&& (otmp->oprops & ITEM_FIRE)) {
18311834
pline_The("%s %s %s%c",
@@ -1905,6 +1908,7 @@ int dieroll; /* needed for Magicbane and vorpal blades */
19051908
: "freezes",
19061909
hittee, !spec_dbon_applies ? '.' : '!');
19071910
} else if ((otmp->oclass == WEAPON_CLASS
1911+
|| is_weptool(otmp) || is_bullet(otmp)
19081912
|| otmp == uarms || otmp == uarmg)
19091913
&& (otmp->oprops & ITEM_FROST)) {
19101914
pline_The("%s %s %s%c",
@@ -1950,6 +1954,7 @@ int dieroll; /* needed for Magicbane and vorpal blades */
19501954
: "! Lightning strikes",
19511955
hittee, !spec_dbon_applies ? '.' : '!');
19521956
} else if ((otmp->oclass == WEAPON_CLASS
1957+
|| is_weptool(otmp) || is_bullet(otmp)
19531958
|| otmp == uarms || otmp == uarmg)
19541959
&& (otmp->oprops & ITEM_SHOCK)) {
19551960
pline_The("%s %s %s%c",
@@ -2137,7 +2142,8 @@ int dieroll; /* needed for Magicbane and vorpal blades */
21372142
? "hits"
21382143
: rn2(2) ? "poisons" : "eviscerates",
21392144
hittee, !spec_dbon_applies ? '.' : '!');
2140-
} else if (otmp->oclass == WEAPON_CLASS
2145+
} else if ((otmp->oclass == WEAPON_CLASS
2146+
|| is_weptool(otmp) || is_bullet(otmp))
21412147
&& (otmp->oprops & ITEM_VENOM)) {
21422148
pline_The("%s %s %s%c",
21432149
distant_name(otmp, xname),

src/dothrow.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,8 @@ boolean hitsroof;
12011201
int dmg = dmgval(obj, &youmonst);
12021202

12031203
if (obj->oartifact
1204-
|| (obj->oclass == WEAPON_CLASS && obj->oprops))
1204+
|| ((obj->oclass == WEAPON_CLASS
1205+
|| is_weptool(obj) || is_bullet(obj)) && obj->oprops))
12051206
/* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
12061207
artimsg = artifact_hit((struct monst *) 0, &youmonst, obj, &dmg,
12071208
rn1(18, 2));
@@ -1350,7 +1351,8 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
13501351
You("hit yourself in the %s!", body_part(LEG));
13511352

13521353
if (obj->oartifact
1353-
|| (obj->oclass == WEAPON_CLASS && obj->oprops))
1354+
|| ((obj->oclass == WEAPON_CLASS
1355+
|| is_weptool(obj) || is_bullet(obj)) && obj->oprops))
13541356
/* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
13551357
(void) artifact_hit((struct monst *) 0, &youmonst, obj, &dmg,
13561358
rn1(18, 2));

src/mhitm.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,10 @@ struct obj **ootmp; /* to return worn armor for caller to disintegrate */
15491549
tmp += rn1(4, 3); /* 3..6 */
15501550
if (tmp < 1) /* is this necessary? mhitu.c has it... */
15511551
tmp = 1;
1552-
if (mwep->oartifact) {
1552+
if (mwep->oartifact
1553+
|| ((mwep->oclass == WEAPON_CLASS
1554+
|| is_weptool(mwep) || is_bullet(mwep))
1555+
&& mwep->oprops)) {
15531556
(void) artifact_hit(magr, mdef, mwep, &tmp, dieroll);
15541557
if (DEADMONSTER(mdef))
15551558
return (MM_DEF_DIED

src/mhitu.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -1511,9 +1511,10 @@ register struct attack *mattk;
15111511
dmg += rn1(4, 3); /* 3..6 */
15121512
if (dmg <= 0)
15131513
dmg = 1;
1514-
if (!(((otmp->oclass == WEAPON_CLASS
1514+
if (!((((otmp->oclass == WEAPON_CLASS
1515+
|| is_weptool(otmp) || is_bullet(otmp))
15151516
&& otmp->oprops) || otmp->oartifact)
1516-
&& artifact_hit(mtmp, &youmonst, otmp, &dmg, dieroll)))
1517+
&& artifact_hit(mtmp, &youmonst, otmp, &dmg, dieroll)))
15171518
hitmsg(mtmp, mattk);
15181519

15191520
if (otmp->opoisoned && is_poisonable(otmp))

src/mkobj.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,9 @@ boolean artif;
991991
otmp->quan = 2L;
992992
else
993993
otmp->quan = 1L;
994+
995+
if (is_bullet(otmp) && !rn2(150))
996+
otmp = create_oprop(otmp, TRUE);
994997
break;
995998
case TOOL_CLASS:
996999
switch (otmp->otyp) {
@@ -2050,7 +2053,7 @@ register struct obj *otmp;
20502053
else if (attacks(AD_FIRE, otmp) || defends(AD_FIRE, otmp))
20512054
return FALSE;
20522055
/* weapons of fire are handled above; armor is not*/
2053-
else if (otmp->oprops && otmp->oprops & ITEM_FIRE)
2056+
else if (otmp->oprops && otmp->oprops & ITEM_FIRE)
20542057
return FALSE;
20552058

20562059
if (otyp == SPE_BOOK_OF_THE_DEAD)

src/mthrowu.c

+12-7
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,17 @@ const char *name; /* if null, then format `*objp' */
112112

113113
return 0;
114114
} else {
115-
if (Blind || !flags.verbose)
115+
if (obj
116+
&& (obj->oartifact ||
117+
((obj->oclass == WEAPON_CLASS
118+
|| is_weptool(obj) || is_bullet(obj))
119+
&& obj->oprops & ITEM_PROP_MASK)))
120+
(void) artifact_hit((struct monst *) 0, &youmonst, obj, &dam, 0);
121+
else if (Blind || !flags.verbose)
116122
You("are hit%s", exclam(dam));
117123
else
118124
You("are hit by %s%s", onm, exclam(dam));
119125

120-
if (obj && obj->oclass == WEAPON_CLASS
121-
&& obj->oprops & ITEM_PROP_MASK)
122-
(void) artifact_hit((struct monst *) 0, &youmonst, obj, &dam, 0);
123-
124126
if (ammo_stack)
125127
ammo_stack->oprops_known |= obj->oprops_known;
126128

@@ -615,8 +617,11 @@ boolean verbose; /* give message(s) even when you can't see what happened */
615617
/* Extra damage is already handled in dmgval(). */
616618
searmsg((struct monst *) 0, mtmp, otmp, FALSE);
617619
}
618-
if (!DEADMONSTER(mtmp) && otmp->oclass == WEAPON_CLASS
619-
&& otmp->oprops & ITEM_PROP_MASK) {
620+
if (!DEADMONSTER(mtmp)
621+
&& (otmp->oartifact
622+
|| ((otmp->oclass == WEAPON_CLASS
623+
|| is_weptool(otmp) || is_bullet(otmp))
624+
&& otmp->oprops & ITEM_PROP_MASK))) {
620625
/* damage from objects with offensive object properties */
621626
(void) artifact_hit((struct monst *) 0, mtmp, otmp, &damage, 0);
622627
}

src/objnam.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,8 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */
10111011
Strcat(buf, actualn);
10121012
if (GemStone(typ))
10131013
Strcat(buf, " stone");
1014+
propnames(buf, obj->oprops, obj->oprops_known,
1015+
TRUE, !!strstri(buf, " of "));
10141016
}
10151017
break;
10161018
}
@@ -5242,7 +5244,7 @@ struct obj *no_wish;
52425244

52435245
/* object property restrictions */
52445246
if (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)
5245-
|| otmp->oclass == ARMOR_CLASS) {
5247+
|| is_bullet(otmp) || otmp->oclass == ARMOR_CLASS) {
52465248
if (objprops & ITEM_FROST)
52475249
objprops &= ~(ITEM_FIRE | ITEM_DRLI
52485250
| ITEM_SHOCK | ITEM_VENOM);
@@ -5274,7 +5276,7 @@ struct obj *no_wish;
52745276
objprops &= ~(ITEM_FIRE | ITEM_FROST | ITEM_DRLI
52755277
| ITEM_SHOCK | ITEM_VENOM | ITEM_OILSKIN);
52765278

5277-
if (is_ammo(otmp) || is_missile(otmp))
5279+
if (is_ammo(otmp) || is_missile(otmp) || is_bullet(otmp))
52785280
objprops &= ~(ITEM_DRLI | ITEM_OILSKIN | ITEM_ESP
52795281
| ITEM_SEARCHING | ITEM_WARNING | ITEM_FUMBLING
52805282
| ITEM_HUNGER | ITEM_EXCEL);

src/uhitm.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,9 @@ struct attack *uattk;
855855
Your("cursed %s turns against you!", simpleonames(uwep));
856856
You("hit yourself in the %s!", body_part(FACE));
857857
if (uwep->oartifact
858-
|| (uwep->oclass == WEAPON_CLASS && uwep->oprops))
858+
|| ((uwep->oclass == WEAPON_CLASS
859+
|| is_weptool(uwep) || is_bullet(uwep))
860+
&& uwep->oprops))
859861
/* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
860862
(void) artifact_hit((struct monst *) 0, &youmonst, uwep, &dmg_wep,
861863
rn1(18, 2));
@@ -1338,7 +1340,9 @@ int dieroll;
13381340
monflee(mon, d(2, 3), TRUE, TRUE);
13391341
hittxt = TRUE;
13401342
}
1341-
if (((obj->oclass == WEAPON_CLASS && obj->oprops) || obj->oartifact)
1343+
if ((((obj->oclass == WEAPON_CLASS
1344+
|| is_weptool(obj) || is_bullet(obj)) && obj->oprops)
1345+
|| obj->oartifact)
13421346
&& artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
13431347
if (DEADMONSTER(mon)) /* artifact killed monster */
13441348
return FALSE;

0 commit comments

Comments
 (0)