Source:NetHack 3.2.0/weapon.c

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

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*/