Source:NetHack 3.2.0/weapon.c

From NetHackWiki
(Redirected from NetHack 3.2.0/weapon.c)
Jump to navigation Jump to search

Below is the full text to weapon.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.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.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)weapon.c	3.2	96/03/03	*/
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 WEAPON_SKILLS
13.   #ifndef OVLB
14.   
15.   STATIC_DCL NEARDATA const short skill_names_indices[];
16.   STATIC_DCL NEARDATA const char *odd_skill_names[];
17.   
18.   #else	/* OVLB */
19.   
20.   STATIC_OVL NEARDATA const short skill_names_indices[P_NUM_SKILLS] = {
21.   	DAGGER,		KNIFE,		AXE,		PICK_AXE,
22.   	SHORT_SWORD,	BROADSWORD,	LONG_SWORD,	TWO_HANDED_SWORD,
23.   	SCIMITAR,	PN_SABER,	CLUB,		MACE,
24.   	MORNING_STAR,	FLAIL,		WAR_HAMMER,	QUARTERSTAFF,
25.   	PN_POLEARMS,	SPEAR,		JAVELIN,	TRIDENT,
26.   	LANCE,		BOW,		SLING,		CROSSBOW,
27.   	DART,		SHURIKEN,	BOOMERANG,	BULLWHIP,
28.   	UNICORN_HORN,	PN_TWO_WEAPON_COMBAT,
29.   	PN_BARE_HANDED_COMBAT, PN_MARTIAL_ARTS
30.   };
31.   
32.   STATIC_OVL NEARDATA const char *odd_skill_names[] = {
33.       "polearms", "two weapon combat", "bare handed combat",
34.       "martial arts", "saber"
35.   };
36.   
37.   #endif	/* OVLB */
38.   #ifdef OVL1
39.   
40.   static char *FDECL(skill_level_name, (int,char *));
41.   static int FDECL(slots_required, (int));
42.   static boolean FDECL(can_advance, (int));
43.   static void FDECL(skill_advance, (int));
44.   
45.   #endif	/* OVL1 */
46.   
47.   #define P_NAME(type) (skill_names_indices[type] < NUM_OBJECTS ? \
48.   		      OBJ_NAME(objects[skill_names_indices[type]]) : \
49.   		      odd_skill_names[skill_names_indices[type] - NUM_OBJECTS])
50.   #endif /* WEAPON_SKILLS */
51.   
52.   #ifdef OVLB
53.   
54.   static NEARDATA const char kebabable[] = {
55.   	S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0'
56.   };
57.   
58.   /*
59.    *	hitval returns an integer representing the "to hit" bonuses
60.    *	of "otmp" against the monster.
61.    */
62.   int
63.   hitval(otmp, mon)
64.   struct obj *otmp;
65.   struct monst *mon;
66.   {
67.   	int	tmp = 0;
68.   	struct permonst *ptr = mon->data;
69.   	boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
70.   
71.   	if (Is_weapon)
72.   		tmp += otmp->spe;
73.   
74.   /*	Put weapon specific "to hit" bonuses in below:		*/
75.   	tmp += objects[otmp->otyp].oc_hitbon;
76.   #ifdef WEAPON_SKILLS
77.   	tmp += weapon_hit_bonus(otmp);	/* weapon skill */
78.   #endif /* WEAPON_SKILLS */
79.   
80.   /*	Put weapon vs. monster type "to hit" bonuses in below:	*/
81.   
82.   	/* Blessed weapons used against undead or demons */
83.   	if (Is_weapon && otmp->blessed &&
84.   	   (is_demon(ptr) || is_undead(ptr))) tmp += 2;
85.   
86.   	if (objects[otmp->otyp].oc_wepcat == WEP_SPEAR &&
87.   	   index(kebabable, ptr->mlet)) tmp += 2;
88.   
89.   	/* trident is highly effective against swimmers */
90.   	if (otmp->otyp == TRIDENT && is_swimmer(ptr)) {
91.   	   if (is_pool(mon->mx, mon->my)) tmp += 4;
92.   	   else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2;
93.   	}
94.   
95.   	/* pick-axe used against xorns and earth elementals */
96.   	if ((otmp->otyp == PICK_AXE || otmp->otyp == DWARVISH_MATTOCK) &&
97.   	   (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2;
98.   
99.   	/* Check specially named weapon "to hit" bonuses */
100.  	if (otmp->oartifact) tmp += spec_abon(otmp, mon);
101.  
102.  	return tmp;
103.  }
104.  
105.  /*
106.   *	dmgval returns an integer representing the damage bonuses
107.   *	of "otmp" against the monster.
108.   */
109.  int
110.  dmgval(otmp, mon)
111.  struct obj *otmp;
112.  struct monst *mon;
113.  {
114.  	int tmp = 0, otyp = otmp->otyp;
115.  	struct permonst *ptr = mon->data;
116.  	boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp));
117.  
118.  	if (otyp == CREAM_PIE) return 0;
119.  
120.  	if (bigmonst(ptr)) {
121.  	    if (objects[otyp].oc_wldam)
122.  		tmp = rnd(objects[otyp].oc_wldam);
123.  	    switch (otyp) {
124.  		case CROSSBOW_BOLT:
125.  		case MORNING_STAR:
126.  		case PARTISAN:
127.  		case RUNESWORD:
128.  		case ELVEN_BROADSWORD:
129.  		case BROADSWORD:	tmp++; break;
130.  
131.  		case FLAIL:
132.  		case RANSEUR:
133.  		case VOULGE:		tmp += rnd(4); break;
134.  
135.  		case ACID_VENOM:
136.  		case HALBERD:
137.  		case SPETUM:		tmp += rnd(6); break;
138.  
139.  		case BATTLE_AXE:
140.  		case BARDICHE:
141.  		case TRIDENT:		tmp += d(2,4); break;
142.  
143.  		case TSURUGI:
144.  		case DWARVISH_MATTOCK:
145.  		case TWO_HANDED_SWORD:	tmp += d(2,6); break;
146.  	    }
147.  	} else {
148.  	    if (objects[otyp].oc_wsdam)
149.  		tmp = rnd(objects[otyp].oc_wsdam);
150.  	    switch (otyp) {
151.  		case CROSSBOW_BOLT:
152.  		case MACE:
153.  		case WAR_HAMMER:
154.  		case FLAIL:
155.  		case SPETUM:
156.  		case TRIDENT:		tmp++; break;
157.  
158.  		case BATTLE_AXE:
159.  		case BARDICHE:
160.  		case BILL_GUISARME:
161.  		case GUISARME:
162.  		case LUCERN_HAMMER:
163.  		case MORNING_STAR:
164.  		case RANSEUR:
165.  		case BROADSWORD:
166.  		case ELVEN_BROADSWORD:
167.  		case RUNESWORD:
168.  		case VOULGE:		tmp += rnd(4); break;
169.  
170.  		case ACID_VENOM:	tmp += rnd(6); break;
171.  	    }
172.  	}
173.  	if (Is_weapon)
174.  		tmp += otmp->spe;
175.  
176.  	if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr))
177.  		/* thick skinned/scaled creatures don't feel it */
178.  		tmp = 0;
179.  	if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER)
180.  		tmp = 0;
181.  
182.  /*	Put weapon vs. monster type damage bonuses in below:	*/
183.  	if (Is_weapon || otmp->oclass == GEM_CLASS) {
184.  	    int bonus = 0;
185.  
186.  	    if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
187.  		bonus += rnd(4);
188.  	    if ((otyp == AXE || otyp == BATTLE_AXE) && is_wooden(ptr))
189.  		bonus += rnd(4);
190.  	    if (objects[otyp].oc_material == SILVER && hates_silver(ptr))
191.  		bonus += rnd(20);
192.  
193.  	    /* if the weapon is going to get a double damage bonus, adjust
194.  	       this bonus so that effectively it's added after the doubling */
195.  	    if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25)
196.  		bonus = (bonus + 1) / 2;
197.  
198.  	    tmp += bonus;
199.  	}
200.  
201.  	if (tmp > 0) {
202.  		tmp -= otmp->oeroded;
203.  		if (tmp < 1) tmp = 1;
204.  	}
205.  
206.  	return(tmp);
207.  }
208.  
209.  #endif /* OVLB */
210.  #ifdef OVL0
211.  
212.  static struct obj *FDECL(oselect, (struct monst *,int));
213.  #define Oselect(x)	if ((otmp = oselect(mtmp, x)) != 0) return(otmp);
214.  
215.  static struct obj *
216.  oselect(mtmp, x)
217.  struct monst *mtmp;
218.  int x;
219.  {
220.  	struct obj *otmp;
221.  
222.  	for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
223.  	    if (otmp->otyp == x &&
224.  		    /* never select non-cockatrice corpses */
225.  		    !(x == CORPSE && otmp->corpsenm != PM_COCKATRICE) &&
226.  		    (!otmp->oartifact || touch_artifact(otmp,mtmp)))
227.  		return otmp;
228.  	}
229.  	return (struct obj *)0;
230.  }
231.  
232.  static NEARDATA const int rwep[] =
233.  	{ DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
234.  	  SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW,
235.  	  CROSSBOW_BOLT, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, ROCK,
236.  	  LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE
237.  	  /* note: CREAM_PIE should NOT be #ifdef KOPS */
238.  	  };
239.  
240.  static struct obj *propellor;
241.  
242.  struct obj *
243.  select_rwep(mtmp)	/* select a ranged weapon for the monster */
244.  register struct monst *mtmp;
245.  {
246.  	register struct obj *otmp;
247.  	int i;
248.  
249.  #ifdef KOPS
250.  	char mlet = mtmp->data->mlet;
251.  #endif
252.  
253.  	propellor = &zeroobj;
254.  #ifdef KOPS
255.  	if(mlet == S_KOP)	/* pies are first choice for Kops */
256.  	    Oselect(CREAM_PIE);
257.  #endif
258.  	if(throws_rocks(mtmp->data))	/* ...boulders for giants */
259.  	    Oselect(BOULDER);
260.  
261.  	/*
262.  	 * other than these two specific cases, always select the
263.  	 * most potent ranged weapon to hand.
264.  	 */
265.  	for (i = 0; i < SIZE(rwep); i++) {
266.  	    int prop;
267.  
268.  	    propellor = &zeroobj;
269.  	    /* shooting gems from slings; this goes just before the darts */
270.  	    if (rwep[i]==DART && !likes_gems(mtmp->data)
271.  			&& (propellor = m_carrying(mtmp, SLING))) {
272.  		for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
273.  		    if(otmp->oclass==GEM_CLASS &&
274.  				(otmp->otyp != LOADSTONE || !otmp->cursed))
275.  			return(otmp);
276.  		}
277.  	    }
278.  	    prop = (objects[rwep[i]]).w_propellor;
279.  	    if (prop > 0) {
280.  		switch (prop) {
281.  		case WP_BOW:
282.  		  propellor = (oselect(mtmp, YUMI));
283.  		  if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW));
284.  		  if (!propellor) propellor = (oselect(mtmp, BOW));
285.  		  if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
286.  		  break;
287.  		case WP_SLING:
288.  		  propellor = (oselect(mtmp, SLING));
289.  		  break;
290.  		case WP_CROSSBOW:
291.  		  propellor = (oselect(mtmp, CROSSBOW));
292.  		}
293.  		if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
294.  				&& mtmp->weapon_check == NO_WEAPON_WANTED)
295.  			propellor = 0;
296.  	    }
297.  	    /* propellor = obj, propellor to use
298.  	     * propellor = &zeroobj, doesn't need a propellor
299.  	     * propellor = 0, needed one and didn't have one
300.  	     */
301.  	    if (propellor != 0) {
302.  		/* Note: cannot use m_carrying for loadstones, since it will
303.  		 * always select the first object of a type, and maybe the
304.  		 * monster is carrying two but only the first is unthrowable.
305.  		 */
306.  		if (rwep[i] != LOADSTONE) {
307.  			/* Don't throw a cursed weapon-in-hand */
308.  			if ((otmp = oselect(mtmp, rwep[i]))
309.  			    && (!otmp->cursed || otmp != MON_WEP(mtmp)))
310.  				return(otmp);
311.  		} else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
312.  		    if (otmp->otyp == LOADSTONE && !otmp->cursed)
313.  			return otmp;
314.  		}
315.  	    }
316.  	  }
317.  
318.  	/* failure */
319.  	return (struct obj *)0;
320.  }
321.  
322.  /* Weapons in order of preference */
323.  static NEARDATA short hwep[] = {
324.  	  CORPSE,  /* cockatrice corpse */
325.  	  TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE,
326.  	  KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD,
327.  	  ELVEN_BROADSWORD, BROADSWORD, LUCERN_HAMMER, SCIMITAR, SILVER_SABER,
328.  	  HALBERD, PARTISAN, LANCE, FAUCHARD, BILL_GUISARME, BEC_DE_CORBIN,
329.  	  GUISARME, RANSEUR, SPETUM, VOULGE, BARDICHE, MORNING_STAR, GLAIVE,
330.  	  ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD,
331.  	  ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR,
332.  	  ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB,
333.  	  PICK_AXE,
334.  #ifdef KOPS
335.  	  RUBBER_HOSE,
336.  #endif /* KOPS */
337.  	  WAR_HAMMER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME, SCALPEL,
338.  	  KNIFE, WORM_TOOTH
339.  	};
340.  
341.  struct obj *
342.  select_hwep(mtmp)	/* select a hand to hand weapon for the monster */
343.  register struct monst *mtmp;
344.  {
345.  	register struct obj *otmp;
346.  	register int i;
347.  	boolean strong = strongmonst(mtmp->data);
348.  	boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0;
349.  
350.  	/* prefer artifacts to everything else */
351.  	for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
352.  		if (otmp->oclass == WEAPON_CLASS
353.  			&& otmp->oartifact && touch_artifact(otmp,mtmp)
354.  			&& ((strong && !wearing_shield)
355.  			    || !objects[otmp->otyp].oc_bimanual))
356.  		    return otmp;
357.  	}
358.  
359.  	if(is_giant(mtmp->data))	/* giants just love to use clubs */
360.  	    Oselect(CLUB);
361.  
362.  	/* only strong monsters can wield big (esp. long) weapons */
363.  	/* big weapon is basically the same as bimanual */
364.  	/* all monsters can wield the remaining weapons */
365.  	for (i = 0; i < SIZE(hwep); i++)
366.  	    if (((strong && !wearing_shield)
367.  			|| !objects[hwep[i]].oc_bimanual) &&
368.  		    (objects[hwep[i]].oc_material != SILVER
369.  			|| !hates_silver(mtmp->data)))
370.  		Oselect(hwep[i]);
371.  
372.  	/* failure */
373.  	return (struct obj *)0;
374.  }
375.  
376.  /* Called after polymorphing a monster, robbing it, etc....  Monsters
377.   * otherwise never unwield stuff on their own.  Shouldn't print messages.
378.   */
379.  void
380.  possibly_unwield(mon)
381.  register struct monst *mon;
382.  {
383.  	register struct obj *obj;
384.  	struct obj *mw_tmp;
385.  
386.  	if (!(mw_tmp = MON_WEP(mon)))
387.  		return;
388.  	for(obj=mon->minvent; obj; obj=obj->nobj)
389.  		if (obj == mw_tmp) break;
390.  	if (!obj) { /* The weapon was stolen or destroyed */
391.  		MON_NOWEP(mon);
392.  		mon->weapon_check = NEED_WEAPON;
393.  		return;
394.  	}
395.  	if (!attacktype(mon->data, AT_WEAP)) {
396.  		mw_tmp->owornmask &= ~W_WEP;
397.  		MON_NOWEP(mon);
398.  		mon->weapon_check = NO_WEAPON_WANTED;
399.  		obj_extract_self(obj);
400.  		/* flooreffects unnecessary, can't wield boulders */
401.  		place_object(obj, mon->mx, mon->my);
402.  		stackobj(obj);
403.  		if (cansee(mon->mx, mon->my)) {
404.  			pline("%s drops %s.", Monnam(mon),
405.  				distant_name(obj, doname));
406.  			newsym(mon->mx, mon->my);
407.  		}
408.  		return;
409.  	}
410.  	/* The remaining case where there is a change is where a monster
411.  	 * is polymorphed into a stronger/weaker monster with a different
412.  	 * choice of weapons.  This has no parallel for players.  It can
413.  	 * be handled by waiting until mon_wield_item is actually called.
414.  	 * Though the monster still wields the wrong weapon until then,
415.  	 * this is OK since the player can't see it.
416.  	 * Note that if there is no change, setting the check to NEED_WEAPON
417.  	 * is harmless.
418.  	 * Possible problem: big monster with big cursed weapon gets
419.  	 * polymorphed into little monster.  But it's not quite clear how to
420.  	 * handle this anyway....
421.  	 */
422.  	mon->weapon_check = NEED_WEAPON;
423.  }
424.  
425.  /* Let a monster try to wield a weapon, based on mon->weapon_check.
426.   * Returns 1 if the monster took time to do it, 0 if it did not.
427.   */
428.  int
429.  mon_wield_item(mon)
430.  register struct monst *mon;
431.  {
432.  	struct obj *obj;
433.  
434.  	/* This case actually should never happen */
435.  	if (mon->weapon_check == NO_WEAPON_WANTED) return 0;
436.  
437.  	switch(mon->weapon_check) {
438.  		case NEED_HTH_WEAPON:
439.  			obj = select_hwep(mon);
440.  			break;
441.  		case NEED_RANGED_WEAPON:
442.  			(void)select_rwep(mon);
443.  			obj = propellor;
444.  			break;
445.  		case NEED_PICK_AXE:
446.  			obj = m_carrying(mon, PICK_AXE);
447.  			break;
448.  		default: impossible("weapon_check %d for %s?",
449.  				mon->weapon_check, mon_nam(mon));
450.  			return 0;
451.  	}
452.  	if (obj && obj != &zeroobj) {
453.  		struct obj *mw_tmp = MON_WEP(mon);
454.  		if (mw_tmp && mw_tmp->otyp == obj->otyp) {
455.  		/* already wielding it */
456.  			mon->weapon_check = NEED_WEAPON;
457.  			return 0;
458.  		}
459.  		/* Actually, this isn't necessary--as soon as the monster
460.  		 * wields the weapon, the weapon welds itself, so the monster
461.  		 * can know it's cursed and needn't even bother trying.
462.  		 * Still....
463.  		 */
464.  		if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) {
465.  		    if (canseemon(mon)) {
466.  			char welded_buf[BUFSZ];
467.  
468.  			Sprintf(welded_buf, "%s welded to %s hand%s",
469.  				(mw_tmp->quan == 1L) ? "is" : "are",
470.  				his[pronoun_gender(mon)],
471.  				objects[mw_tmp->otyp].oc_bimanual ? "s" : "");
472.  
473.  			if (obj->otyp == PICK_AXE) {
474.  			    pline("Since %s weapon%s %s,",
475.  				  s_suffix(mon_nam(mon)),
476.  				  plur(mw_tmp->quan), welded_buf);
477.  			    pline("%s cannot wield that %s.",
478.  				mon_nam(mon), xname(obj));
479.  			} else {
480.  			    pline("%s tries to wield %s.", Monnam(mon),
481.  				doname(obj));
482.  			    pline("%s %s %s!",
483.  				  s_suffix(Monnam(mon)),
484.  				  xname(mw_tmp), welded_buf);
485.  			}
486.  			mw_tmp->bknown = 1;
487.  		    }
488.  		    mon->weapon_check = NO_WEAPON_WANTED;
489.  		    return 1;
490.  		}
491.  		mon->mw = obj;		/* wield obj */
492.  		if (mw_tmp) mw_tmp->owornmask &= ~W_WEP;
493.  		mon->weapon_check = NEED_WEAPON;
494.  		if (canseemon(mon)) {
495.  			pline("%s wields %s!", Monnam(mon), doname(obj));
496.  			if (obj->cursed && obj->otyp != CORPSE) {
497.  				pline("%s %s to %s hand!",
498.  					The(xname(obj)),
499.  					(obj->quan == 1L) ? "welds itself"
500.  					    : "weld themselves",
501.  					s_suffix(mon_nam(mon)));
502.  				obj->bknown = 1;
503.  			}
504.  		}
505.  		obj->owornmask = W_WEP;
506.  		return 1;
507.  	}
508.  	mon->weapon_check = NEED_WEAPON;
509.  	return 0;
510.  }
511.  
512.  int
513.  abon()		/* attack bonus for strength & dexterity */
514.  {
515.  	int	sbon;
516.  	register int	str = ACURR(A_STR), dex = ACURR(A_DEX);
517.  
518.  	if (u.umonnum >= LOW_PM) return(adj_lev(&mons[u.umonnum]) - 3);
519.  	if (str < 6) sbon = -2;
520.  	else if (str < 8) sbon = -1;
521.  	else if (str < 17) sbon = 0;
522.  	else if (str < 69) sbon = 1;	/* up to 18/50 */
523.  	else if (str < 118) sbon = 2;
524.  	else sbon = 3;
525.  
526.  /* Game tuning kludge: make it a bit easier for a low level character to hit */
527.  	sbon += (u.ulevel < 3) ? 1 : 0;
528.  
529.  	if (dex < 4) return(sbon-3);
530.  	else if (dex < 6) return(sbon-2);
531.  	else if (dex < 8) return(sbon-1);
532.  	else if (dex < 14) return(sbon);
533.  	else return(sbon + dex-14);
534.  }
535.  
536.  #endif /* OVL0 */
537.  #ifdef OVL1
538.  
539.  int
540.  dbon()		/* damage bonus for strength */
541.  {
542.  	register int	str = ACURR(A_STR);
543.  
544.  	if (u.umonnum >= LOW_PM) return(0);
545.  
546.  	if (str < 6) return(-1);
547.  	else if (str < 16) return(0);
548.  	else if (str < 18) return(1);
549.  	else if (str == 18) return(2);		/* up to 18 */
550.  	else if (str < 94) return(3);		/* up to 18/75 */
551.  	else if (str < 109) return(4);		/* up to 18/90 */
552.  	else if (str < 118) return(5);		/* up to 18/99 */
553.  	else return(6);
554.  }
555.  
556.  
557.  #ifdef WEAPON_SKILLS
558.  
559.  /* copy the skill level name into the given buffer */
560.  static char *
561.  skill_level_name(skill, buf)
562.  int skill;
563.  char *buf;
564.  {
565.      const char *ptr;
566.  
567.      if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT) {
568.  	switch (P_SKILL(skill)) {
569.  	    case P_UNSKILLED:	ptr = "Unskilled"; break;
570.  	    case P_BASIC:	ptr = "Basic";     break;
571.  	    case P_SKILLED:	ptr = "Skilled";   break;
572.  	    case P_EXPERT:	ptr = "Expert";    break;
573.  	    default:		ptr = "Unknown?";  break;
574.  	}
575.  	Strcpy(buf, ptr);
576.      } else {
577.  	Sprintf(buf, "%d", P_SKILL(skill));
578.      }
579.      return buf;
580.  }
581.  
582.  /* return the # of slots required to advance the skill */
583.  static int
584.  slots_required(skill)
585.  int skill;
586.  {
587.      /* The more difficult the training, the more slots it takes. */
588.      if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
589.  	return P_SKILL(skill);
590.  
591.      return (P_SKILL(skill) > 5) ? 2 : 1;	/* unarmed or martial */
592.  }
593.  
594.  /* return true if this skill can be advanced */
595.  static boolean
596.  can_advance(skill)
597.  int skill;
598.  {
599.      return !P_RESTRICTED(skill)
600.  	    && P_SKILL(skill) < P_MAX_SKILL(skill)
601.  	    && P_ADVANCE(skill) >=
602.  		(unsigned) practice_needed_to_advance(P_SKILL(skill))
603.  	    && u.skills_advanced < P_SKILL_LIMIT
604.  	    && u.weapon_slots >= slots_required(skill);
605.  }
606.  
607.  /* `#qualifications' extended command */
608.  int
609.  check_weapon_skills()
610.  {
611.      int i, len, name_length;
612.      char buf[BUFSIZ], buf2[BUFSIZ];
613.      winid tmpwin;
614.  
615.      tmpwin = create_nhwindow(NHW_MENU);
616.      putstr(tmpwin, 0, "Current Skills:");
617.      putstr(tmpwin, 0, "");
618.  
619.      /* Find longest available skill name. */
620.      for (name_length = 0, i = 0; i < P_NUM_SKILLS; i++)
621.  	if (!P_RESTRICTED(i) && (len = strlen(P_NAME(i))) > name_length)
622.  	    name_length = len;
623.  
624.      /* list the skills, indicating which ones could be advanced */
625.      for (i = 0; i < P_NUM_SKILLS; i++) {
626.  	if (P_RESTRICTED(i)) continue;
627.  #if 1
628.  	if (i == P_TWO_WEAPON_COMBAT) continue;
629.  #endif
630.  
631.  	/* sigh, this assumes a monospaced font */
632.  	if (wizard)
633.  	    Sprintf(buf2, "%-*s %c%-9s %4d(%4d)", name_length, P_NAME(i),
634.  		    can_advance(i) ? '*' : ' ',
635.  		    skill_level_name(i, buf),
636.  		    P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i)));
637.  	else
638.  	    Sprintf(buf2, "%-*s %c[%s]", name_length, P_NAME(i),
639.  		    can_advance(i) ? '*' : ' ',
640.  		    skill_level_name(i, buf));
641.  	putstr(tmpwin, 0, buf2);
642.      }
643.  
644.      display_nhwindow(tmpwin, TRUE);
645.      destroy_nhwindow(tmpwin);
646.      return 0;
647.  }
648.  
649.  static void
650.  skill_advance(skill)
651.  int skill;
652.  {
653.      You("are now more skilled in %s.", P_NAME(skill));
654.      u.weapon_slots -= slots_required(skill);
655.      P_SKILL(skill)++;
656.      u.skill_record[u.skills_advanced++] = skill;
657.  }
658.  
659.  /* `#enhance' extended command */
660.  int
661.  select_weapon_skill()
662.  {
663.      int i, n, mark, len, longest;
664.      char buf[BUFSIZ], buf2[BUFSIZ];
665.      menu_item *selected;
666.      anything any;
667.      winid win;
668.  
669.      /* count # of skills we can advance */
670.      for (longest = mark = n = i = 0; i < P_NUM_SKILLS; i++)
671.  	if (can_advance(i)) {
672.  	    if ((len = strlen(P_NAME(i))) > longest) longest = len;
673.  	    mark = i;	/* in case we can only advance one */
674.  	    n++;
675.  	}
676.  
677.      if (n == 0) {
678.  	You("are not able to advance any skill right now.");
679.  	return 0;
680.      }
681.  
682.      if (n != 1) {
683.  	/* ask which skill to advance */
684.  	win = create_nhwindow(NHW_MENU);
685.  	start_menu(win);
686.  	any.a_void = 0;
687.  	for (i = 0; i < P_NUM_SKILLS; i++) {
688.  	    if (!can_advance(i)) continue;
689.  
690.  	    if (i <= P_LAST_WEAPON || i == P_TWO_WEAPON_COMBAT)
691.  		(void) skill_level_name(i, buf2);
692.  	    else
693.  		Sprintf(buf2, "%d", slots_required(i));
694.  
695.  	    /* assume monospaced font */
696.  	    Sprintf(buf, "%-*s [%s]", longest, P_NAME(i), buf2);
697.  	    any.a_int = i + 1;	/* must be non-zero */
698.  #if 1
699.  	    if (i == P_TWO_WEAPON_COMBAT) continue;
700.  #endif
701.  	    add_menu(win, NO_GLYPH, &any, 0, 0, buf, MENU_UNSELECTED);
702.  	}
703.  
704.  	end_menu(win, "Pick a skill to advance:");
705.  	n = select_menu(win, PICK_ONE, &selected);
706.  	destroy_nhwindow(win);
707.  	if (n <= 0) return 0;			/* cancelled dialog */
708.  
709.  	mark = selected[0].item.a_int - 1;	/* get item selected */
710.  	free((genericptr_t)selected);
711.      }
712.  
713.      skill_advance(mark);
714.      return 0;
715.  }
716.  
717.  /*
718.   * Change from restricted to unrestricted, allowing P_BASIC as max.  This
719.   * function may be called with with P_NO_TYPE.  Used in pray.c.
720.   */
721.  void
722.  unrestrict_weapon_skill(skill)
723.  int skill;
724.  {
725.      if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) {
726.  	P_SKILL(skill) = P_UNSKILLED;
727.  	P_MAX_SKILL(skill) = P_BASIC;
728.  	P_ADVANCE(skill) = 0;
729.      }
730.  }
731.  
732.  #endif /* WEAPON_SKILLS */
733.  
734.  #endif /* OVL1 */
735.  #ifdef OVLB
736.  
737.  #ifdef WEAPON_SKILLS
738.  
739.  void
740.  add_weapon_skill()
741.  {
742.      u.weapon_slots++;
743.  }
744.  
745.  void
746.  lose_weapon_skill()
747.  {
748.      int skill;
749.  
750.      /* deduct first from unused slots, then from last placed slot, if any */
751.      if (u.weapon_slots) {
752.  	u.weapon_slots--;
753.      } else if (u.skills_advanced) {
754.  	skill = u.skill_record[--u.skills_advanced];
755.  	if (P_SKILL(skill) <= P_UNSKILLED)
756.  	    panic("lose_weapon_skill");
757.  
758.  	P_SKILL(skill)--;	/* drop skill one level */
759.  
760.  	/* Some skills take more than one slot, refund the rest. */
761.  	if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT)
762.  	    u.weapon_slots = P_SKILL(skill) - 1;
763.  	else if (P_SKILL(skill) >= 5)
764.  	    u.weapon_slots = 1;
765.      }
766.  }
767.  
768.  int
769.  weapon_type(obj)
770.  struct obj *obj;
771.  {
772.      int type;
773.  
774.      if (obj) {
775.  	switch (obj->otyp) {
776.  	    case DAGGER:		case ELVEN_DAGGER:
777.  	    case ORCISH_DAGGER:		case ATHAME:
778.  		type = P_DAGGER; break;
779.  	    case KNIFE:			case STILETTO:
780.  	    case WORM_TOOTH:		case CRYSKNIFE:
781.  	    case SCALPEL:
782.  		type = P_KNIFE; break;
783.  	    case AXE:			case BATTLE_AXE:
784.  		type = P_AXE; break;
785.  	    case DWARVISH_MATTOCK:
786.  	    case PICK_AXE:
787.  		type = P_PICK_AXE; break;
788.  	    case SHORT_SWORD:		case ELVEN_SHORT_SWORD:
789.  	    case ORCISH_SHORT_SWORD:	case DWARVISH_SHORT_SWORD:
790.  		type = P_SHORT_SWORD; break;
791.  	    case BROADSWORD:		case ELVEN_BROADSWORD:
792.  	    case RUNESWORD:
793.  		type = P_BROAD_SWORD; break;
794.  	    case LONG_SWORD:		case KATANA:
795.  		type = P_LONG_SWORD; break;
796.  	    case TWO_HANDED_SWORD:	case TSURUGI:
797.  		type = P_TWO_HANDED_SWORD; break;
798.  	    case SCIMITAR:
799.  		type = P_SCIMITAR; break;
800.  	    case SILVER_SABER:
801.  		type = P_SABER; break;
802.  	    case CLUB:			case AKLYS:
803.  		type = P_CLUB; break;
804.  	    case MACE:
805.  		type = P_MACE; break;
806.  	    case MORNING_STAR:
807.  		type = P_MORNING_STAR; break;
808.  	    case FLAIL:
809.  		type = P_FLAIL; break;
810.  	    case WAR_HAMMER:
811.  		type = P_HAMMER; break;
812.  	    case QUARTERSTAFF:
813.  		type = P_QUARTERSTAFF; break;
814.  	    case PARTISAN:		case RANSEUR:
815.  	    case SPETUM:		case GLAIVE:
816.  	    case HALBERD:		case BARDICHE:
817.  	    case VOULGE:		case FAUCHARD:
818.  	    case GUISARME:		case BILL_GUISARME:
819.  	    case LUCERN_HAMMER:		case BEC_DE_CORBIN:
820.  		type = P_POLEARMS; break;
821.  	    case SPEAR:			case ELVEN_SPEAR:
822.  	    case ORCISH_SPEAR:		case DWARVISH_SPEAR:
823.  		type = P_SPEAR; break;
824.  	    case JAVELIN:
825.  		type = P_JAVELIN; break;
826.  	    case LANCE:
827.  		type = P_LANCE; break;
828.  	    case BOW:			case ELVEN_BOW:
829.  	    case ORCISH_BOW:		case YUMI:
830.  		type = P_BOW; break;
831.  	    case SLING:
832.  		type = P_SLING; break;
833.  	    case CROSSBOW:
834.  		type = P_CROSSBOW; break;
835.  	    case DART:
836.  		type = P_DART; break;
837.  	    case SHURIKEN:
838.  		type = P_SHURIKEN; break;
839.  	    case BOOMERANG:
840.  		type = P_BOOMERANG; break;
841.  	    case BULLWHIP:
842.  #ifdef KOPS
843.  	    case RUBBER_HOSE:
844.  #endif
845.  		type = P_WHIP; break;
846.  	    case UNICORN_HORN:
847.  		type = P_UNICORN_HORN; break;
848.  	    default:
849.  		type = P_NO_TYPE; break;
850.  	}
851.  	return type;
852.      }
853.  
854.      /* No object is one of these. */
855.      return P_RESTRICTED(P_BARE_HANDED_COMBAT) ? P_MARTIAL_ARTS :
856.  						P_BARE_HANDED_COMBAT;
857.  }
858.  
859.  /*
860.   * Return hit bonus/penalty based on skill of weapon.
861.   * Treat restricted weapons as unskilled.
862.   */
863.  int
864.  weapon_hit_bonus(weapon)
865.  struct obj *weapon;
866.  {
867.      int type, bonus = 0;
868.      static const char bad_skill[] = "weapon_hit_bonus: bad skill %d";
869.  
870.      type = weapon_type(weapon);
871.      if (type == P_NO_TYPE) {
872.  	bonus = 0;
873.      } else if (type <= P_LAST_WEAPON) {
874.  	switch (P_SKILL(type)) {
875.  	    default: impossible(bad_skill, P_SKILL(type)); /* fall through */
876.  	    case P_ISRESTRICTED:
877.  	    case P_UNSKILLED:   bonus = -4; break;
878.  	    case P_BASIC:       bonus =  0; break;
879.  	    case P_SKILLED:     bonus =  2; break;
880.  	    case P_EXPERT:      bonus =  3; break;
881.  	}
882.      } else if (type == P_TWO_WEAPON_COMBAT) {
883.  	switch (P_SKILL(type)) {
884.  	    default: impossible(bad_skill, P_SKILL(type)); /* fall through */
885.  	    case P_ISRESTRICTED:
886.  	    case P_UNSKILLED:   bonus = -9; break;
887.  	    case P_BASIC:	bonus = -7; break;
888.  	    case P_SKILLED:	bonus = -5; break;
889.  	    case P_EXPERT:	bonus = -3; break;
890.  	}
891.      } else if (type == P_BARE_HANDED_COMBAT) {
892.  	bonus = (P_SKILL(type) + 1) / 2;	/* restricted == 0 */
893.      } else if (type == P_MARTIAL_ARTS) {
894.  	bonus = (P_SKILL(type) + 1) * 2 / 3;	/* restricted == 0 */
895.      }
896.      return bonus;
897.  }
898.  
899.  /*
900.   * Return damage bonus/penalty based on skill of weapon.
901.   * Treat restricted weapons as unskilled.
902.   */
903.  int
904.  weapon_dam_bonus(weapon)
905.  struct obj *weapon;
906.  {
907.      int type, bonus = 0;
908.  
909.      type = weapon_type(weapon);
910.      if (type == P_NO_TYPE) {
911.  	bonus = 0;
912.      } else if (P_RESTRICTED(type) || type <= P_LAST_WEAPON) {
913.  	switch (P_SKILL(type)) {
914.  	    default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type));
915.  		     /* fall through */
916.  	    case P_ISRESTRICTED:
917.  	    case P_UNSKILLED:	bonus = -2; break;
918.  	    case P_BASIC:	bonus =  0; break;
919.  	    case P_SKILLED:	bonus =  1; break;
920.  	    case P_EXPERT:	bonus =  2; break;
921.  	}
922.      } else if (type == P_BARE_HANDED_COMBAT && P_SKILL(type)) {
923.  	bonus = P_SKILL(type) / 2;
924.      } else if (type == P_MARTIAL_ARTS && P_SKILL(type)) {
925.  	bonus = P_SKILL(type) * 2 / 3;
926.      }
927.      return bonus;
928.  }
929.  
930.  /*
931.   * Initialize weapon skill array for the game.  Start by setting all
932.   * skills to restricted, then set the skill for every weapon the
933.   * hero is holding, finally reading the given array that sets
934.   * maximums.
935.   */
936.  void
937.  skill_init(class_skill)
938.  struct def_skill *class_skill;
939.  {
940.  	struct obj *obj;
941.  	int skmax, skill;
942.  
943.  	/* initialize skill array; by default, everything is restricted */
944.  	for (skill = 0; skill < P_NUM_SKILLS; skill++) {
945.  	    P_SKILL(skill) = P_ISRESTRICTED;
946.  	    P_MAX_SKILL(skill) = P_ISRESTRICTED;
947.  	    P_ADVANCE(skill) = 0;
948.  	}
949.  
950.  	/* set skill for all weapons in inventory to be basic */
951.  	for (obj = invent; obj; obj = obj->nobj) {
952.  	    skill = weapon_type(obj);
953.  	    if (skill != P_NO_TYPE)
954.  		P_SKILL(skill) = P_BASIC;
955.  	}
956.  
957.  	/* walk through array to set skill maximums */
958.  	for (; class_skill->skill != P_NO_TYPE; class_skill++) {
959.  	    skmax = class_skill->skmax;
960.  	    skill = class_skill->skill;
961.  
962.  	    P_MAX_SKILL(skill) = skmax;
963.  	    if (P_SKILL(skill) == P_ISRESTRICTED)	/* skill pre-set */
964.  		P_SKILL(skill) = P_UNSKILLED;
965.  	}
966.  
967.  	/*
968.  	 * Make sure we haven't missed setting the max on a skill
969.  	 * & set advance
970.  	 */
971.  	for (skill = 0; skill < P_NUM_SKILLS; skill++) {
972.  	    if (!P_RESTRICTED(skill)) {
973.  		if (P_MAX_SKILL(skill) < P_SKILL(skill)) {
974.  		    impossible("skill_init: curr > max: %s", P_NAME(skill));
975.  		    P_MAX_SKILL(skill) = P_SKILL(skill);
976.  		}
977.  		P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1);
978.  	    }
979.  	}
980.  }
981.  
982.  #endif /* WEAPON_SKILLS */
983.  
984.  #endif /* OVLB */
985.  
986.  /*weapon.c*/