Wikia

Wikihack

Source:NetHack 3.1.0/weapon.c

2,032pages on
this wiki
Talk0

Below is the full text to weapon.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/weapon.c#line123]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.
1.    /*	SCCS Id: @(#)weapon.c	3.1	93/01/15	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    /*
6.     *	This module contains code for calculation of "to hit" and damage
7.     *	bonuses for any given weapon used, as well as weapons selection
8.     *	code for monsters.
9.     */
10.   #include	"hack.h"
11.   
12.   #ifdef OVLB
13.   
14.   static const char NEARDATA kebabable[] = { S_XORN, S_DRAGON, S_NAGA, S_GIANT, 0 };
15.   
16.   /*
17.    *	hitval returns an integer representing the "to hit" bonuses
18.    *	of "otmp" against the monster type "ptr".
19.    */
20.   int
21.   hitval(otmp, ptr)
22.   struct	obj *otmp;
23.   struct	permonst *ptr;
24.   {
25.   	int	tmp = 0;
26.   
27.   	if (otmp->oclass == WEAPON_CLASS ||
28.   	    otmp->otyp == PICK_AXE || otmp->otyp == UNICORN_HORN)
29.   		tmp += otmp->spe;
30.   
31.   /*	Put weapon specific "to hit" bonuses in below:		*/
32.   	tmp += objects[otmp->otyp].oc_hitbon;
33.   
34.   /*	Put weapon vs. monster type "to hit" bonuses in below:	*/
35.   
36.   	/* Blessed weapons used against undead or demons */
37.   	if(otmp->oclass == WEAPON_CLASS && otmp->blessed &&
38.   	   (is_demon(ptr) || is_undead(ptr))) tmp += 2;
39.   
40.   	if(otmp->otyp >= SPEAR && otmp->otyp <= JAVELIN &&
41.   	   index(kebabable, ptr->mlet)) tmp += 2;
42.   
43.   	/* Check specially named weapon "to hit" bonuses */
44.   	if (otmp->oartifact) tmp += spec_abon(otmp, ptr);
45.   	return tmp;
46.   }
47.   
48.   /*
49.    *	dmgval returns an integer representing the damage bonuses
50.    *	of "otmp" against the monster type "ptr".
51.    */
52.   int
53.   dmgval(otmp, ptr)
54.   struct	obj *otmp;
55.   struct	permonst *ptr;
56.   {
57.   	int	tmp = 0;
58.   
59.   	if(otmp->otyp == CREAM_PIE)	return(0);
60.   
61.   	if(ptr->msize >= MZ_HUMAN) {
62.   	    if(objects[otmp->otyp].oc_wldam)
63.   		tmp = rnd(objects[otmp->otyp].oc_wldam);
64.   	    switch (otmp->otyp) {
65.   		case CROSSBOW_BOLT:
66.   		case MORNING_STAR:
67.   		case PARTISAN:
68.   		case ELVEN_BROADSWORD:
69.   		case BROADSWORD:	tmp++; break;
70.   
71.   		case FLAIL:
72.   		case RANSEUR:
73.   		case VOULGE:		tmp += rnd(4); break;
74.   
75.   		case ACID_VENOM:
76.   		case HALBERD:
77.   		case SPETUM:		tmp += rnd(6); break;
78.   
79.   		case BATTLE_AXE:
80.   		case BARDICHE:
81.   		case TRIDENT:		tmp += d(2,4); break;
82.   
83.   		case TSURUGI:
84.   		case DWARVISH_MATTOCK:
85.   		case TWO_HANDED_SWORD:	tmp += d(2,6); break;
86.   	    }
87.   	} else {
88.   	    if(objects[otmp->otyp].oc_wsdam)
89.   		tmp = rnd(objects[otmp->otyp].oc_wsdam);
90.   	    switch (otmp->otyp) {
91.   		case CROSSBOW_BOLT:
92.   		case MACE:
93.   		case WAR_HAMMER:
94.   		case FLAIL:
95.   		case SPETUM:
96.   		case TRIDENT:		tmp++; break;
97.   
98.   		case BATTLE_AXE:
99.   		case BARDICHE:
100.  		case BILL_GUISARME:
101.  		case GUISARME:
102.  		case LUCERN_HAMMER:
103.  		case MORNING_STAR:
104.  		case RANSEUR:
105.  		case BROADSWORD:
106.  		case ELVEN_BROADSWORD:
107.  		case VOULGE:		tmp += rnd(4); break;
108.  
109.  		case ACID_VENOM:	tmp += rnd(6); break;
110.  	    }
111.  	}
112.  	if (otmp->oclass == WEAPON_CLASS || otmp->otyp == PICK_AXE
113.  						|| otmp->otyp == UNICORN_HORN)
114.  		tmp += otmp->spe;
115.  
116.  	tmp -= otmp->oeroded;
117.  
118.  	if (objects[otmp->otyp].oc_material <= LEATHER && thick_skinned(ptr))
119.  		/* thick skinned/scaled creatures don't feel it */
120.  		tmp = 0;
121.  	if (ptr == &mons[PM_SHADE] && objects[otmp->otyp].oc_material != SILVER)
122.  		tmp = 0;
123.  
124.  /*	Put weapon vs. monster type damage bonuses in below:	*/
125.  	if(otmp->oclass == WEAPON_CLASS) {
126.  	    if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
127.  		tmp += rnd(4);
128.  	    if ((otmp->otyp == AXE || otmp->otyp == BATTLE_AXE)
129.  		&& is_wooden(ptr))
130.  		tmp += rnd(4);
131.  	    if (objects[otmp->otyp].oc_material == SILVER && hates_silver(ptr))
132.  		tmp += rnd(20);
133.  	}
134.  
135.  	return(tmp);
136.  }
137.  
138.  void
139.  set_uasmon()		/* update the "uasmon" structure */
140.  {
141.  #ifdef POLYSELF
142.  	if(u.umonnum >= 0) uasmon = &mons[u.umonnum];
143.  	else {
144.  #endif
145.  
146.  		uasmon = &playermon;
147.  		playermon.mlevel = u.ulevel;
148.  		playermon.ac = u.uac;
149.  		playermon.mr = (u.ulevel > 8) ? 5 * (u.ulevel-7) : u.ulevel;
150.  #ifdef POLYSELF
151.  	}
152.  #endif
153.  	return;
154.  }
155.  
156.  #endif /* OVLB */
157.  #ifdef OVL0
158.  
159.  #define	Oselect(x)	if((otmp = oselect(mtmp, x))) return(otmp);
160.  
161.  static struct obj * FDECL(oselect, (struct monst *,int));
162.  
163.  static struct obj *
164.  oselect(mtmp, x)
165.  struct monst *mtmp;
166.  int x;
167.  {
168.  	struct obj *otmp;
169.  
170.  	for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
171.  		if (otmp->otyp == x && touch_artifact(otmp,mtmp))
172.  			return otmp;
173.  	}
174.  	return (struct obj *)0;
175.  }
176.  
177.  static const int NEARDATA rwep[] =
178.  	{ DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
179.  	  SHURIKEN, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW,
180.  	  CROSSBOW_BOLT, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, ROCK,
181.  	  LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE
182.  	  /* note: CREAM_PIE should NOT be #ifdef KOPS */
183.  	  };
184.  
185.  static struct obj *propellor;
186.  
187.  struct obj *
188.  select_rwep(mtmp)	/* select a ranged weapon for the monster */
189.  register struct monst *mtmp;
190.  {
191.  	register struct obj *otmp;
192.  	int i;
193.  
194.  #ifdef KOPS
195.  	char mlet = mtmp->data->mlet;
196.  #endif
197.  
198.  	propellor = &zeroobj;
199.  #ifdef KOPS
200.  	if(mlet == S_KOP)	/* pies are first choice for Kops */
201.  	    Oselect(CREAM_PIE);
202.  #endif
203.  	if(throws_rocks(mtmp->data))	/* ...boulders for giants */
204.  	    Oselect(BOULDER);
205.  	/*
206.  	 * other than these two specific cases, always select the
207.  	 * most potent ranged weapon to hand.
208.  	 */
209.  	for (i = 0; i < SIZE(rwep); i++) {
210.  	    int prop;
211.  
212.  	    propellor = &zeroobj;
213.  	    /* shooting gems from slings; this goes just before the darts */
214.  	    if (rwep[i]==DART && !likes_gems(mtmp->data)
215.  			&& (propellor = m_carrying(mtmp, SLING))) {
216.  		for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
217.  		    if(otmp->oclass==GEM_CLASS &&
218.  				(otmp->otyp != LOADSTONE || !otmp->cursed))
219.  			return(otmp);
220.  		}
221.  	    }
222.  	    prop = (objects[rwep[i]]).w_propellor;
223.  	    if (prop > 0) {
224.  		switch (prop) {
225.  		case WP_BOW:
226.  		  propellor = (oselect(mtmp, ELVEN_BOW));
227.  		  if (!propellor) propellor = (oselect(mtmp, BOW));
228.  		  if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
229.  		  break;
230.  		case WP_SLING:
231.  		  propellor = (oselect(mtmp, SLING));
232.  		  break;
233.  		case WP_CROSSBOW:
234.  		  propellor = (oselect(mtmp, CROSSBOW));
235.  		}
236.  #ifdef MUSE
237.  		if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
238.  				&& mtmp->weapon_check == NO_WEAPON_WANTED)
239.  			propellor = 0;
240.  #endif
241.  	    }
242.  	    /* propellor = obj, propellor to use
243.  	     * propellor = &zeroobj, doesn't need a propellor
244.  	     * propellor = 0, needed one and didn't have one
245.  	     */
246.  	    if (propellor != 0) {
247.  		/* Note: cannot use m_carrying for loadstones, since it will
248.  		 * always select the first object of a type, and maybe the
249.  		 * monster is carrying two but only the first is unthrowable.
250.  		 */
251.  		if (rwep[i] != LOADSTONE) {
252.  #ifdef MUSE
253.  			/* Don't throw a cursed weapon-in-hand */
254.  			if ((otmp = oselect(mtmp, rwep[i]))
255.  			    && (!otmp->cursed || otmp != MON_WEP(mtmp)))
256.  				return(otmp);
257.  #else
258.  			Oselect(rwep[i]);
259.  #endif
260.  		} else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
261.  		    if (otmp->otyp == LOADSTONE && !otmp->cursed)
262.  			return otmp;
263.  		}
264.  	    }
265.  	  }
266.  
267.  	/* failure */
268.  	return (struct obj *)0;
269.  }
270.  
271.  /* 0 = used by any monster; 1 = only used by strong monsters */
272.  static const struct hwep { short otyp, big; } NEARDATA hwep[] = {
273.  	  {TSURUGI,1}, {RUNESWORD,0},
274.  	  {DWARVISH_MATTOCK,1}, {TWO_HANDED_SWORD,1}, {BATTLE_AXE,1},
275.  	  {KATANA,0}, {UNICORN_HORN,1}, {CRYSKNIFE,0},
276.  	  {TRIDENT,0}, {LONG_SWORD,0}, {ELVEN_BROADSWORD,0}, {BROADSWORD,0},
277.  	  {LUCERN_HAMMER,1}, {SCIMITAR,1}, {SILVER_SABER,0}, {HALBERD,1},
278.  	  {PARTISAN,1}, {LANCE,1}, {FAUCHARD,1}, {BILL_GUISARME,1},
279.  	  {BEC_DE_CORBIN,1}, {GUISARME,1}, {RANSEUR,1}, {SPETUM,1},
280.  	  {VOULGE,1}, {BARDICHE,0}, {MORNING_STAR,0}, {GLAIVE,0},
281.  	  {ELVEN_SHORT_SWORD,0}, {DWARVISH_SHORT_SWORD,0}, {SHORT_SWORD,0},
282.  	  {ORCISH_SHORT_SWORD,0}, {MACE,0}, {AXE,0}, {DWARVISH_SPEAR,0},
283.  	  {ELVEN_SPEAR,0}, {SPEAR,0}, {ORCISH_SPEAR,0}, {FLAIL,0},
284.  	  {QUARTERSTAFF,1}, {JAVELIN,0}, {AKLYS,0}, {CLUB,0}, {PICK_AXE,0},
285.  #ifdef KOPS
286.  	  {RUBBER_HOSE,0},
287.  #endif /* KOPS */
288.  	  {WAR_HAMMER,0}, {ELVEN_DAGGER,0}, {DAGGER,0}, {ORCISH_DAGGER,0},
289.  	  {ATHAME,0}, {SCALPEL,0}, {KNIFE,0}, {WORM_TOOTH,0}, {BULLWHIP,0}
290.  	};
291.  
292.  struct obj *
293.  select_hwep(mtmp)	/* select a hand to hand weapon for the monster */
294.  register struct monst *mtmp;
295.  {
296.  	register struct obj *otmp;
297.  	register int i;
298.  	register const struct hwep *hw;
299.  	boolean strong = strongmonst(mtmp->data);
300.  
301.  	if(is_giant(mtmp->data))	/* giants just love to use clubs */
302.  	    Oselect(CLUB);
303.  
304.  	/* only strong monsters can wield big (esp. long) weapons */
305.  	/* all monsters can wield the remaining weapons */
306.  	for (i = 0, hw = hwep; i < SIZE(hwep); i++, hw++)
307.  	    if ((strong || !hw->big) &&
308.  #ifdef MUSE
309.  	      (!objects[hw->otyp].oc_bimanual || !which_armor(mtmp, W_ARMS)) &&
310.  #endif
311.  	(objects[hw->otyp].oc_material != SILVER || !hates_silver(mtmp->data)))
312.  		Oselect(hw->otyp);
313.  
314.  	/* failure */
315.  	return (struct obj *)0;
316.  }
317.  
318.  #ifdef MUSE
319.  /* Called after polymorphing a monster, robbing it, etc....  Monsters
320.   * otherwise never unwield stuff on their own.  Shouldn't print messages.
321.   */
322.  void
323.  possibly_unwield(mon)
324.  register struct monst *mon;
325.  {
326.  	register struct obj *obj;
327.  	struct obj *otmp, *backobj, *mw_tmp;
328.  
329.  	if (!(mw_tmp = MON_WEP(mon)))
330.  		return;
331.  	for(obj=mon->minvent; obj; obj=obj->nobj)
332.  		if (obj == mw_tmp) break;
333.  	if (!obj) { /* The weapon was stolen or destroyed */
334.  		MON_NOWEP(mon);
335.  		mon->weapon_check = NEED_WEAPON;
336.  		return;
337.  	}
338.  	if (!attacktype(mon->data, AT_WEAP)) {
339.  		MON_NOWEP(mon);
340.  		mon->weapon_check = NO_WEAPON_WANTED;
341.  		if (cansee(mon->mx, mon->my)) {
342.  			pline("%s drops %s.", Monnam(mon),
343.  				distant_name(obj, doname));
344.  		}
345.  		backobj = 0;
346.  		for(otmp = mon->minvent; otmp; otmp = otmp->nobj) {
347.  			/* flooreffects unnecessary, can't wield boulders */
348.  			if (otmp == obj) {
349.  				if (!backobj) mon->minvent = otmp->nobj;
350.  				else backobj->nobj = otmp->nobj;
351.  				place_object(otmp, mon->mx, mon->my);
352.  				otmp->nobj = fobj;
353.  				fobj = otmp;
354.  				stackobj(fobj);
355.  				if(cansee(mon->mx,mon->my))
356.  					newsym(mon->mx, mon->my);
357.  				break;
358.  			}
359.  			backobj = otmp;
360.  		}
361.  		return;
362.  	}
363.  	/* The remaining case where there is a change is where a monster
364.  	 * is polymorphed into a stronger/weaker monster with a different
365.  	 * choice of weapons.  This has no parallel for players.  It can
366.  	 * be handled by waiting until mon_wield_item is actually called.
367.  	 * Though the monster still wields the wrong weapon until then,
368.  	 * this is OK since the player can't see it.
369.  	 * Possible problem: big monster with big cursed weapon gets
370.  	 * polymorphed into little monster.  But it's not quite clear how to
371.  	 * handle this anyway....
372.  	 */
373.  	mon->weapon_check = NEED_WEAPON;
374.  	return;
375.  }
376.  
377.  /* Let a monster try to wield a weapon, based on mon->weapon_check.
378.   * Returns 1 if the monster took time to do it, 0 if it did not.
379.   */
380.  int
381.  mon_wield_item(mon)
382.  register struct monst *mon;
383.  {
384.  	struct obj *obj;
385.  
386.  	/* This case actually should never happen */
387.  	if (mon->weapon_check == NO_WEAPON_WANTED) return 0;
388.  
389.  	switch(mon->weapon_check) {
390.  		case NEED_HTH_WEAPON:
391.  			obj = select_hwep(mon);
392.  			break;
393.  		case NEED_RANGED_WEAPON:
394.  			(void)select_rwep(mon);
395.  			obj = propellor;
396.  			break;
397.  		case NEED_PICK_AXE:
398.  			obj = m_carrying(mon, PICK_AXE);
399.  			break;
400.  		default: impossible("weapon_check %d for %s?",
401.  				mon->weapon_check, mon_nam(mon));
402.  			return 0;
403.  	}
404.  	if (obj && obj != &zeroobj) {
405.  		struct obj *mw_tmp = MON_WEP(mon);
406.  		if (mw_tmp == obj) { /* already wielding it */
407.  			mon->weapon_check = NEED_WEAPON;
408.  			return 0;
409.  		}
410.  		/* Actually, this isn't necessary--as soon as the monster
411.  		 * wields the weapon, the weapon welds itself, so the monster
412.  		 * can know it's cursed and needn't even bother trying.
413.  		 * Still....
414.  		 */
415.  		if (mw_tmp && mw_tmp->cursed) {
416.  		    if (obj->otyp == PICK_AXE) {
417.  			if (canseemon(mon)) {
418.  			    pline("Since %s weapon %s welded to %s hand,",
419.  				s_suffix(mon_nam(mon)),
420.  				(mw_tmp->quan == 1L) ? "is" : "are",
421.  				humanoid(mon->data)
422.  					? (mon->female ? "her" : "his")
423.  					: "its");
424.  			    pline("%s cannot wield that %s.",
425.  				mon_nam(mon), xname(obj));
426.  			    mw_tmp->bknown = 1;
427.  			}
428.  		    } else {
429.  			if (canseemon(mon)) {
430.  			    pline("%s tries to wield %s.", Monnam(mon),
431.  				doname(obj));
432.  			    pline("%s %s %s welded to %s hand!",
433.  				s_suffix(Monnam(mon)), xname(mw_tmp),
434.  				(mw_tmp->quan == 1L) ? "is" : "are",
435.  				humanoid(mon->data)
436.  					? (mon->female ? "her" : "his")
437.  					: "its");
438.  			    mw_tmp->bknown = 1;
439.  			}
440.  		    }
441.  		    mon->weapon_check = NO_WEAPON_WANTED;
442.  		    return 1;
443.  		}
444.  		mon->mw = obj;		/* wield obj */
445.  		mon->weapon_check = NEED_WEAPON;
446.  		if (canseemon(mon)) {
447.  			pline("%s wields %s!", Monnam(mon), doname(obj));
448.  			if (obj->cursed) {
449.  				pline("%s %s to %s hand!",
450.  					The(xname(obj)),
451.  					(obj->quan == 1L) ? "welds itself"
452.  					    : "weld themselves",
453.  					s_suffix(mon_nam(mon)));
454.  				obj->bknown = 1;
455.  			}
456.  		}
457.  		return 1;
458.  	}
459.  	mon->weapon_check = NEED_WEAPON;
460.  	return 0;
461.  }
462.  
463.  /* rearrange a monster's inventory so that wielded weapon is first */
464.  void
465.  sort_mwep(mon)
466.  struct monst *mon;
467.  {
468.  	struct obj *otmp, *prev, *mw_tmp = MON_WEP(mon);
469.  
470.  	if (!mw_tmp) return;
471.  	for (otmp = mon->minvent, prev = 0; otmp; otmp = otmp->nobj) {
472.  		if (otmp == mw_tmp)  break;
473.  		prev = otmp;
474.  	}
475.  	if (!otmp) {
476.  		MON_NOWEP(mon);
477.  	} else if (prev) {
478.  		prev->nobj = otmp->nobj;
479.  		otmp->nobj = mon->minvent;
480.  		mon->minvent = otmp;
481.  	}
482.  }
483.  #endif
484.  
485.  int
486.  abon() {	/* attack bonus for strength & dexterity */
487.  	int	sbon;
488.  	register int	str = ACURR(A_STR), dex = ACURR(A_DEX);
489.  
490.  #ifdef POLYSELF
491.  	if (u.umonnum >= 0) return(adj_lev(&mons[u.umonnum])-3);
492.  #endif
493.  	if (str < 6) sbon = -2;
494.  	else if (str < 8) sbon = -1;
495.  	else if (str < 17) sbon = 0;
496.  	else if (str < 69) sbon = 1;	/* up to 18/50 */
497.  	else if (str < 118) sbon = 2;
498.  	else sbon = 3;
499.  /*
500.   *	Temporary kludge - make it a bit easier for a low level character
501.   *			   to hit until we tune the game a little better.
502.   */
503.  	sbon += (u.ulevel < 3) ? 1 : 0;
504.  
505.  	if (dex < 4) return(sbon-3);
506.  	else if (dex < 6) return(sbon-2);
507.  	else if (dex < 8) return(sbon-1);
508.  	else if (dex < 14) return(sbon);
509.  	else return(sbon + dex-14);
510.  }
511.  
512.  #endif /* OVL0 */
513.  #ifdef OVL1
514.  
515.  int
516.  dbon() {	/* damage bonus for strength */
517.  	register int	str = ACURR(A_STR);
518.  
519.  #ifdef POLYSELF
520.  	if (u.umonnum >= 0) return(0);
521.  #endif
522.  
523.  	if (str < 6) return(-1);
524.  	else if (str < 16) return(0);
525.  	else if (str < 18) return(1);
526.  	else if (str == 18) return(2);		/* up to 18 */
527.  	else if (str < 94) return(3);		/* up to 18/75 */
528.  	else if (str < 109) return(4);		/* up to 18/90 */
529.  	else if (str < 118) return(5);		/* up to 18/99 */
530.  	else return(6);
531.  }
532.  
533.  #endif /* OVL1 */
534.  
535.  /*weapon.c*/

Around Wikia's network

Random Wiki