Below is the full text to src/steal.c from NetHack 3.4.3. To link to a particular line, write [[steal.c#line123]], for example.
Top of File
Edit
1. /* SCCS Id: @(#)steal.c 3.4 2003/12/04 */
2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3. /* NetHack may be freely redistributed. See license for details. */
4.
5. #include "hack.h"
6.
7. STATIC_PTR int NDECL(stealarm);
8.
9. #ifdef OVLB
10. STATIC_DCL const char *FDECL(equipname, (struct obj *));
11. STATIC_DCL void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P));
12.
equipname
Edit
13. STATIC_OVL const char *
14. equipname(otmp)
15. register struct obj *otmp;
16. {
17. return (
18. #ifdef TOURIST
19. (otmp == uarmu) ? "shirt" :
20. #endif
21. (otmp == uarmf) ? "boots" :
22. (otmp == uarms) ? "shield" :
23. (otmp == uarmg) ? "gloves" :
24. (otmp == uarmc) ? cloak_simple_name(otmp) :
25. (otmp == uarmh) ? "helmet" : "armor");
26. }
27.
somegold without GOLDOBJ
Edit
28. #ifndef GOLDOBJ
29. long /* actually returns something that fits in an int */
30. somegold()
31. {
32. #ifdef LINT /* long conv. ok */
33. return(0L);
34. #else
35. return (long)( (u.ugold < 100) ? u.ugold :
36. (u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) );
37. #endif
38. }
39.
stealgold without GOLDOBJ
Edit
40. void
41. stealgold(mtmp)
42. register struct monst *mtmp;
43. {
44. register struct obj *gold = g_at(u.ux, u.uy);
45. register long tmp;
46.
47. if (gold && ( !u.ugold || gold->quan > u.ugold || !rn2(5))) {
48. mtmp->mgold += gold->quan;
49. delobj(gold);
50. newsym(u.ux, u.uy);
51. pline("%s quickly snatches some gold from between your %s!",
52. Monnam(mtmp), makeplural(body_part(FOOT)));
53. if(!u.ugold || !rn2(5)) {
54. if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
55. /* do not set mtmp->mavenge here; gold on the floor is fair game */
56. monflee(mtmp, 0, FALSE, FALSE);
57. }
58. } else if(u.ugold) {
59. u.ugold -= (tmp = somegold());
60. Your("purse feels lighter.");
61. mtmp->mgold += tmp;
62. if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
63. mtmp->mavenge = 1;
64. monflee(mtmp, 0, FALSE, FALSE);
65. flags.botl = 1;
66. }
67. }
68.
somegold with GOLDOBJ
Edit
69. #else /* !GOLDOBJ */
70.
71. long /* actually returns something that fits in an int */
72. somegold(umoney)
73. long umoney;
74. {
75. #ifdef LINT /* long conv. ok */
76. return(0L);
77. #else
78. return (long)( (umoney < 100) ? umoney :
79. (umoney > 10000) ? rnd(10000) : rnd((int) umoney) );
80. #endif
81. }
82.
findgold
Edit
83. /*
84. Find the first (and hopefully only) gold object in a chain.
85. Used when leprechaun (or you as leprechaun) looks for
86. someone else's gold. Returns a pointer so the gold may
87. be seized without further searching.
88. May search containers too.
89. Deals in gold only, as leprechauns don't care for lesser coins.
90. */
91. struct obj *
92. findgold(chain)
93. register struct obj *chain;
94. {
95. while (chain && chain->otyp != GOLD_PIECE) chain = chain->nobj;
96. return chain;
97. }
98.
stealgold with GOLDOBJ
Edit
99. /*
100. Steal gold coins only. Leprechauns don't care for lesser coins.
101. */
102. void
103. stealgold(mtmp)
104. register struct monst *mtmp;
105. {
106. register struct obj *fgold = g_at(u.ux, u.uy);
107. register struct obj *ygold;
108. register long tmp;
109.
110. /* skip lesser coins on the floor */
111. while (fgold && fgold->otyp != GOLD_PIECE) fgold = fgold->nexthere;
112.
113. /* Do you have real gold? */
114. ygold = findgold(invent);
115.
116. if (fgold && ( !ygold || fgold->quan > ygold->quan || !rn2(5))) {
117. obj_extract_self(fgold);
118. add_to_minv(mtmp, fgold);
119. newsym(u.ux, u.uy);
120. pline("%s quickly snatches some gold from between your %s!",
121. Monnam(mtmp), makeplural(body_part(FOOT)));
122. if(!ygold || !rn2(5)) {
123. if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
124. monflee(mtmp, 0, FALSE, FALSE);
125. }
126. } else if(ygold) {
127. const int gold_price = objects[GOLD_PIECE].oc_cost;
128. tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price;
129. tmp = min(tmp, ygold->quan);
130. if (tmp < ygold->quan) ygold = splitobj(ygold, tmp);
131. freeinv(ygold);
132. add_to_minv(mtmp, ygold);
133. Your("purse feels lighter.");
134. if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
135. monflee(mtmp, 0, FALSE, FALSE);
136. flags.botl = 1;
137. }
138. }
139. #endif /* GOLDOBJ */
140.
stealarm
Edit
141. /* steal armor after you finish taking it off */
142. unsigned int stealoid; /* object to be stolen */
143. unsigned int stealmid; /* monster doing the stealing */
144.
145. STATIC_PTR int
146. stealarm()
147. {
148. register struct monst *mtmp;
149. register struct obj *otmp;
150.
151. for(otmp = invent; otmp; otmp = otmp->nobj) {
152. if(otmp->o_id == stealoid) {
153. for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
154. if(mtmp->m_id == stealmid) {
155. if(DEADMONSTER(mtmp)) impossible("stealarm(): dead monster stealing");
156. if(!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */
157. goto botm;
158. if(otmp->unpaid)
159. subfrombill(otmp, shop_keeper(*u.ushops));
160. freeinv(otmp);
161. pline("%s steals %s!", Monnam(mtmp), doname(otmp));
162. (void) mpickobj(mtmp,otmp); /* may free otmp */
163. /* Implies seduction, "you gladly hand over ..."
164. so we don't set mavenge bit here. */
165. monflee(mtmp, 0, FALSE, FALSE);
166. if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
167. break;
168. }
169. }
170. break;
171. }
172. }
173. botm: stealoid = 0;
174. return 0;
175. }
176.
remove_worn_item
Edit
177. /* An object you're wearing has been taken off by a monster (theft or
178. seduction). Also used if a worn item gets transformed (stone to flesh). */
179. void
180. remove_worn_item(obj, unchain_ball)
181. struct obj *obj;
182. boolean unchain_ball; /* whether to unpunish or just unwield */
183. {
184. if (donning(obj))
185. cancel_don();
186. if (!obj->owornmask)
187. return;
188.
189. if (obj->owornmask & W_ARMOR) {
190. if (obj == uskin) {
191. impossible("Removing embedded scales?");
192. skinback(TRUE); /* uarm = uskin; uskin = 0; */
193. }
194. if (obj == uarm) (void) Armor_off();
195. else if (obj == uarmc) (void) Cloak_off();
196. else if (obj == uarmf) (void) Boots_off();
197. else if (obj == uarmg) (void) Gloves_off();
198. else if (obj == uarmh) (void) Helmet_off();
199. else if (obj == uarms) (void) Shield_off();
200. #ifdef TOURIST
201. else if (obj == uarmu) (void) Shirt_off();
202. #endif
203. /* catchall -- should never happen */
204. else setworn((struct obj *)0, obj->owornmask & W_ARMOR);
205. } else if (obj->owornmask & W_AMUL) {
206. Amulet_off();
207. } else if (obj->owornmask & W_RING) {
208. Ring_gone(obj);
209. } else if (obj->owornmask & W_TOOL) {
210. Blindf_off(obj);
211. } else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) {
212. if (obj == uwep)
213. uwepgone();
214. if (obj == uswapwep)
215. uswapwepgone();
216. if (obj == uquiver)
217. uqwepgone();
218. }
219.
220. if (obj->owornmask & (W_BALL|W_CHAIN)) {
221. if (unchain_ball) unpunish();
222. } else if (obj->owornmask) {
223. /* catchall */
224. setnotworn(obj);
225. }
226. }
227.
228. /* Returns 1 when something was stolen (or at least, when N should flee now)
229. * Returns -1 if the monster died in the attempt
230. * Avoid stealing the object stealoid
231. */
232. int
233. steal(mtmp, objnambuf)
234. struct monst *mtmp;
235. char *objnambuf;
236. {
237. struct obj *otmp;
238. int tmp, could_petrify, named = 0, armordelay;
239. boolean monkey_business; /* true iff an animal is doing the thievery */
240.
241. if (objnambuf) *objnambuf = '\0';
242. /* the following is true if successful on first of two attacks. */
243. if(!monnear(mtmp, u.ux, u.uy)) return(0);
244.
245. /* food being eaten might already be used up but will not have
246. been removed from inventory yet; we don't want to steal that,
247. so this will cause it to be removed now */
248. if (occupation) (void) maybe_finished_meal(FALSE);
249.
250. if (!invent || (inv_cnt() == 1 && uskin)) {
251. nothing_to_steal:
252. /* Not even a thousand men in armor can strip a naked man. */
253. if(Blind)
254. pline("Somebody tries to rob you, but finds nothing to steal.");
255. else
256. pline("%s tries to rob you, but there is nothing to steal!",
257. Monnam(mtmp));
258. return(1); /* let her flee */
259. }
260.
261. monkey_business = is_animal(mtmp->data);
262. if (monkey_business) {
263. ; /* skip ring special cases */
264. } else if (Adornment & LEFT_RING) {
265. otmp = uleft;
266. goto gotobj;
267. } else if (Adornment & RIGHT_RING) {
268. otmp = uright;
269. goto gotobj;
270. }
271.
272. tmp = 0;
273. for(otmp = invent; otmp; otmp = otmp->nobj)
274. if ((!uarm || otmp != uarmc) && otmp != uskin
275. #ifdef INVISIBLE_OBJECTS
276. && (!otmp->oinvis || perceives(mtmp->data))
277. #endif
278. )
279. tmp += ((otmp->owornmask &
280. (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1);
281. if (!tmp) goto nothing_to_steal;
282. tmp = rn2(tmp);
283. for(otmp = invent; otmp; otmp = otmp->nobj)
284. if ((!uarm || otmp != uarmc) && otmp != uskin
285. #ifdef INVISIBLE_OBJECTS
286. && (!otmp->oinvis || perceives(mtmp->data))
287. #endif
288. )
289. if((tmp -= ((otmp->owornmask &
290. (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1)) < 0)
291. break;
292. if(!otmp) {
293. impossible("Steal fails!");
294. return(0);
295. }
296. /* can't steal gloves while wielding - so steal the wielded item. */
297. if (otmp == uarmg && uwep)
298. otmp = uwep;
299. /* can't steal armor while wearing cloak - so steal the cloak. */
300. else if(otmp == uarm && uarmc) otmp = uarmc;
301. #ifdef TOURIST
302. else if(otmp == uarmu && uarmc) otmp = uarmc;
303. else if(otmp == uarmu && uarm) otmp = uarm;
304. #endif
305. gotobj:
306. if(otmp->o_id == stealoid) return(0);
307.
308. /* animals can't overcome curse stickiness nor unlock chains */
309. if (monkey_business) {
310. boolean ostuck;
311. /* is the player prevented from voluntarily giving up this item?
312. (ignores loadstones; the !can_carry() check will catch those) */
313. if (otmp == uball)
314. ostuck = TRUE; /* effectively worn; curse is implicit */
315. else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap))
316. ostuck = FALSE; /* not really worn; curse doesn't matter */
317. else
318. ostuck = (otmp->cursed && otmp->owornmask);
319.
320. if (ostuck || !can_carry(mtmp, otmp)) {
321. static const char * const how[] = { "steal","snatch","grab","take" };
322. cant_take:
323. pline("%s tries to %s your %s but gives up.",
324. Monnam(mtmp), how[rn2(SIZE(how))],
325. (otmp->owornmask & W_ARMOR) ? equipname(otmp) :
326. cxname(otmp));
327. /* the fewer items you have, the less likely the thief
328. is going to stick around to try again (0) instead of
329. running away (1) */
330. return !rn2(inv_cnt() / 5 + 2);
331. }
332. }
333.
334. if (otmp->otyp == LEASH && otmp->leashmon) {
335. if (monkey_business && otmp->cursed) goto cant_take;
336. o_unleash(otmp);
337. }
338.
339. /* you're going to notice the theft... */
340. stop_occupation();
341.
342. if((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))){
343. switch(otmp->oclass) {
344. case TOOL_CLASS:
345. case AMULET_CLASS:
346. case RING_CLASS:
347. case FOOD_CLASS: /* meat ring */
348. remove_worn_item(otmp, TRUE);
349. break;
350. case ARMOR_CLASS:
351. armordelay = objects[otmp->otyp].oc_delay;
352. /* Stop putting on armor which has been stolen. */
353. if (donning(otmp)) {
354. remove_worn_item(otmp, TRUE);
355. break;
356. } else if (monkey_business) {
357. /* animals usually don't have enough patience
358. to take off items which require extra time */
359. if (armordelay >= 1 && rn2(10)) goto cant_take;
360. remove_worn_item(otmp, TRUE);
361. break;
362. } else {
363. int curssv = otmp->cursed;
364. int slowly;
365. boolean seen = canspotmon(mtmp);
366.
367. otmp->cursed = 0;
368. /* can't charm you without first waking you */
369. if (multi < 0 && is_fainted()) unmul((char *)0);
370. slowly = (armordelay >= 1 || multi < 0);
371. if(flags.female)
372. pline("%s charms you. You gladly %s your %s.",
373. !seen ? "She" : Monnam(mtmp),
374. curssv ? "let her take" :
375. slowly ? "start removing" : "hand over",
376. equipname(otmp));
377. else
378. pline("%s seduces you and %s off your %s.",
379. !seen ? "She" : Adjmonnam(mtmp, "beautiful"),
380. curssv ? "helps you to take" :
381. slowly ? "you start taking" : "you take",
382. equipname(otmp));
383. named++;
384. /* the following is to set multi for later on */
385. nomul(-armordelay);
386. remove_worn_item(otmp, TRUE);
387. otmp->cursed = curssv;
388. if(multi < 0){
389. /*
390. multi = 0;
391. nomovemsg = 0;
392. afternmv = 0;
393. */
394. stealoid = otmp->o_id;
395. stealmid = mtmp->m_id;
396. afternmv = stealarm;
397. return(0);
398. }
399. }
400. break;
401. default:
402. impossible("Tried to steal a strange worn thing. [%d]",
403. otmp->oclass);
404. }
405. }
406. else if (otmp->owornmask)
407. remove_worn_item(otmp, TRUE);
408.
409. /* do this before removing it from inventory */
410. if (objnambuf) Strcpy(objnambuf, yname(otmp));
411. /* set mavenge bit so knights won't suffer an
412. * alignment penalty during retaliation;
413. */
414. mtmp->mavenge = 1;
415.
416. freeinv(otmp);
417. pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
418. could_petrify = (otmp->otyp == CORPSE &&
419. touch_petrifies(&mons[otmp->corpsenm]));
420. (void) mpickobj(mtmp,otmp); /* may free otmp */
421. if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) {
422. minstapetrify(mtmp, TRUE);
423. return -1;
424. }
425. return((multi < 0) ? 0 : 1);
426. }
427.
428. #endif /* OVLB */
mpickobj
Edit
429. #ifdef OVL1
430.
431. /* Returns 1 if otmp is free'd, 0 otherwise. */
432. int
433. mpickobj(mtmp,otmp)
434. register struct monst *mtmp;
435. register struct obj *otmp;
436. {
437. int freed_otmp;
438.
439. #ifndef GOLDOBJ
440. if (otmp->oclass == COIN_CLASS) {
441. mtmp->mgold += otmp->quan;
442. obfree(otmp, (struct obj *)0);
443. freed_otmp = 1;
444. } else {
445. #endif
446. boolean snuff_otmp = FALSE;
447. /* don't want hidden light source inside the monster; assumes that
448. engulfers won't have external inventories; whirly monsters cause
449. the light to be extinguished rather than letting it shine thru */
450. if (otmp->lamplit && /* hack to avoid function calls for most objs */
451. obj_sheds_light(otmp) &&
452. attacktype(mtmp->data, AT_ENGL)) {
453. /* this is probably a burning object that you dropped or threw */
454. if (u.uswallow && mtmp == u.ustuck && !Blind)
455. pline("%s out.", Tobjnam(otmp, "go"));
456. snuff_otmp = TRUE;
457. }
458. /* Must do carrying effects on object prior to add_to_minv() */
459. carry_obj_effects(otmp);
460. /* add_to_minv() might free otmp [if merged with something else],
461. so we have to call it after doing the object checks */
462. freed_otmp = add_to_minv(mtmp, otmp);
463. /* and we had to defer this until object is in mtmp's inventory */
464. if (snuff_otmp) snuff_light_source(mtmp->mx, mtmp->my);
465. #ifndef GOLDOBJ
466. }
467. #endif
468. return freed_otmp;
469. }
470.
471. #endif /* OVL1 */
stealamulet
Edit
472. #ifdef OVLB
473.
474. void
475. stealamulet(mtmp)
476. struct monst *mtmp;
477. {
478. struct obj *otmp = (struct obj *)0;
479. int real=0, fake=0;
480.
481. /* select the artifact to steal */
482. if(u.uhave.amulet) {
483. real = AMULET_OF_YENDOR;
484. fake = FAKE_AMULET_OF_YENDOR;
485. } else if(u.uhave.questart) {
486. for(otmp = invent; otmp; otmp = otmp->nobj)
487. if(is_quest_artifact(otmp)) break;
488. if (!otmp) return; /* should we panic instead? */
489. } else if(u.uhave.bell) {
490. real = BELL_OF_OPENING;
491. fake = BELL;
492. } else if(u.uhave.book) {
493. real = SPE_BOOK_OF_THE_DEAD;
494. } else if(u.uhave.menorah) {
495. real = CANDELABRUM_OF_INVOCATION;
496. } else return; /* you have nothing of special interest */
497.
498. if (!otmp) {
499. /* If we get here, real and fake have been set up. */
500. for(otmp = invent; otmp; otmp = otmp->nobj)
501. if(otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz))
502. break;
503. }
504.
505. if (otmp) { /* we have something to snatch */
506. if (otmp->owornmask)
507. remove_worn_item(otmp, TRUE);
508. freeinv(otmp);
509. /* mpickobj wont merge otmp because none of the above things
510. to steal are mergable */
511. (void) mpickobj(mtmp,otmp); /* may merge and free otmp */
512. pline("%s stole %s!", Monnam(mtmp), doname(otmp));
513. if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
514. (void) rloc(mtmp, FALSE);
515. }
516. }
517.
518. #endif /* OVLB */
mdrop_obj
Edit
519. #ifdef OVL0
520.
521. /* drop one object taken from a (possibly dead) monster's inventory */
522. STATIC_OVL void
523. mdrop_obj(mon, obj, verbosely)
524. struct monst *mon;
525. struct obj *obj;
526. boolean verbosely;
527. {
528. int omx = mon->mx, omy = mon->my;
529.
530. if (obj->owornmask) {
531. /* perform worn item handling if the monster is still alive */
532. if (mon->mhp > 0) {
533. mon->misc_worn_check &= ~obj->owornmask;
534. update_mon_intrinsics(mon, obj, FALSE, TRUE);
535. /* obj_no_longer_held(obj); -- done by place_object */
536. if (obj->owornmask & W_WEP) setmnotwielded(mon, obj);
537. #ifdef STEED
538. /* don't charge for an owned saddle on dead steed */
539. } else if (mon->mtame && (obj->owornmask & W_SADDLE) &&
540. !obj->unpaid && costly_spot(omx, omy)) {
541. obj->no_charge = 1;
542. #endif
543. }
544. obj->owornmask = 0L;
545. }
546. if (verbosely && cansee(omx, omy))
547. pline("%s drops %s.", Monnam(mon), distant_name(obj, doname));
548. if (!flooreffects(obj, omx, omy, "fall")) {
549. place_object(obj, omx, omy);
550. stackobj(obj);
551. }
552. }
553.
mdrop_special_objs
Edit
554. /* some monsters bypass the normal rules for moving between levels or
555. even leaving the game entirely; when that happens, prevent them from
556. taking the Amulet or invocation tools with them */
557. void
558. mdrop_special_objs(mon)
559. struct monst *mon;
560. {
561. struct obj *obj, *otmp;
562.
563. for (obj = mon->minvent; obj; obj = otmp) {
564. otmp = obj->nobj;
565. /* the Amulet, invocation tools, and Rider corpses resist even when
566. artifacts and ordinary objects are given 0% resistance chance */
567. if (obj_resists(obj, 0, 0)) {
568. obj_extract_self(obj);
569. mdrop_obj(mon, obj, FALSE);
570. }
571. }
572. }
573.
574. /* release the objects the creature is carrying */
575. void
576. relobj(mtmp,show,is_pet)
577. register struct monst *mtmp;
578. register int show;
579. boolean is_pet; /* If true, pet should keep wielded/worn items */
580. {
581. register struct obj *otmp;
582. register int omx = mtmp->mx, omy = mtmp->my;
583. struct obj *keepobj = 0;
584. struct obj *wep = MON_WEP(mtmp);
585. boolean item1 = FALSE, item2 = FALSE;
586.
587. if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
588. item1 = item2 = TRUE;
589. if (!tunnels(mtmp->data) || !needspick(mtmp->data))
590. item1 = TRUE;
591.
592. while ((otmp = mtmp->minvent) != 0) {
593. obj_extract_self(otmp);
594. /* special case: pick-axe and unicorn horn are non-worn */
595. /* items that we also want pets to keep 1 of */
596. /* (It is a coincidence that these can also be wielded.) */
597. if (otmp->owornmask || otmp == wep ||
598. ((!item1 && otmp->otyp == PICK_AXE) ||
599. (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
600. if (is_pet) { /* dont drop worn/wielded item */
601. if (otmp->otyp == PICK_AXE)
602. item1 = TRUE;
603. if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
604. item2 = TRUE;
605. otmp->nobj = keepobj;
606. keepobj = otmp;
607. continue;
608. }
609. }
610. mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
611. }
612.
613. /* put kept objects back */
614. while ((otmp = keepobj) != (struct obj *)0) {
615. keepobj = otmp->nobj;
616. (void) add_to_minv(mtmp, otmp);
617. }
618. #ifndef GOLDOBJ
619. if (mtmp->mgold) {
620. register long g = mtmp->mgold;
621. (void) mkgold(g, omx, omy);
622. if (is_pet && cansee(omx, omy) && flags.verbose)
623. pline("%s drops %ld gold piece%s.", Monnam(mtmp),
624. g, plur(g));
625. mtmp->mgold = 0L;
626. }
627. #endif
628.
629. if (show & cansee(omx, omy))
630. newsym(omx, omy);
631. }
632.
633. #endif /* OVL0 */
634.
635. /*steal.c*/