NetHack brass as a patch

From NetHackWiki
Jump to navigation Jump to search
NetHack brass as a patch
Author Code by Youkan
Patch from Kernigh
Download link
NetHack PatchDB 279

This page presents NetHack brass as a patch against vanilla NetHack 3.4.3.

Kernigh used the diff program to generate this "unified diff" between NetHack 3.4.3 and NetHack brass 040923 after pruning some files from the 040923. In particular, Youkan's zip of the 040923 source code was not clean of generated files created during the build process on Microsoft Windows, including some Windows executables. Youkan's zip also contains old versions of some of the dungeon files, with DOS batch (*.bat) scripts to enable them.

The patch presented here contains neither the Windows-generated files, nor the old dungeons and DOS batch script. After applying this patch to the vanilla sources, you do have everything needed to build NetHack brass 040923 from source code. If you are building upon Unix, then you also want the brass interface patch, or at least the Unix fixes from that patch.

Download the patch from:

http://kernigh.pbwiki.com/f/brass-040923.diff

A user has suggested improving this page or section as follows:

"Merge this into the main NetHack brass page. Additionally someone who still has the diff file should upload it and replace this now-dead link."

Files patched

  • dat/*.des
    • Most objects are made from normal material mat_normal to handle a change in the des-file format.
    • Changes to the maps of the Quest levels for the Monk, attributed to Bill Foust.
    • Many, many changes at the Castle and below, including a serious redesign of Gehennom.
  • dat/rumor.{fal,tru}
    • This rumor becomes false: "They say that you can't break an amulet of reflection."
  • Numerous changes to source files.

Note that the source files do contain several instances of // style comments. This comment syntax, borrowed from C++, may not work in compilers older than C99. Some C compilers (including GCC) supported // comments in C before C99.

Changes to some source files

Here are some excerpts of changes to some but not all of the source files. These might be useful for those wanting to study the differences between vanilla and NetHack brass.

The line numbers are those of the diff file.

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.

artifact.h

2079. diff -pruN nethack-3.4.3/include/artifact.h nhbrass-040923/include/artifact.h
2080. --- nethack-3.4.3/include/artifact.h	Sun Dec  7 18:39:13 2003
2081. +++ nhbrass-040923/include/artifact.h	Thu Oct 16 09:05:02 2003
2082. @@ -38,12 +38,13 @@
2083.  
2084.  struct artifact {
2085.  	short	    otyp;
2086. -	const char  *name;
2087. +	/*const*/ char  *name;
2088.  	unsigned long spfx;	/* special effect from wielding/wearing */
2089.  	unsigned long cspfx;	/* special effect just from carrying obj */
2090.  	unsigned long mtype;	/* monster type, symbol, or flag */
2091.  	struct attack attk, defn, cary;
2092.  	uchar	    inv_prop;	/* property obtained by invoking artifact */
2093. +	uchar	    material;	/* if artifact is made of special material */
2094.  	aligntyp    alignment;	/* alignment of bequeathing gods */
2095.  	short	    role;	/* character role associated with */
2096.  	short	    race;	/* character race associated with */
2097. @@ -60,5 +61,13 @@ struct artifact {
2098.  #define CREATE_PORTAL	(LAST_PROP+7)
2099.  #define ENLIGHTENING	(LAST_PROP+8)
2100.  #define CREATE_AMMO	(LAST_PROP+9)
2101. +#define EMIT_LIGHT	(LAST_PROP+10)
2102. +
2103. +/* additional alighment */
2104. +#define	A_CROSSALIGNED	(-127)
2105. +
2106. +/* special damage bonus identifiers */
2107. +#define ADMG_DOUBLE	255
2108. +#define ADMG_MAX	254
2109.  
2110.  #endif /* ARTIFACT_H */

artilist.h

2111. diff -pruN nethack-3.4.3/include/artilist.h nhbrass-040923/include/artilist.h
2112. --- nethack-3.4.3/include/artilist.h	Sun Dec  7 18:39:13 2003
2113. +++ nhbrass-040923/include/artilist.h	Sun Jan  4 01:41:00 2004
2114. @@ -5,14 +5,14 @@
2115.  #ifdef MAKEDEFS_C
2116.  /* in makedefs.c, all we care about is the list of names */
2117.  
2118. -#define A(nam,typ,s1,s2,mt,atk,dfn,cry,inv,al,cl,rac,cost) nam
2119. +#define A(nam,typ,mat,s1,s2,mt,atk,dfn,cry,inv,al,cl,rac,cost) nam
2120.  
2121.  static const char *artifact_names[] = {
2122.  #else
2123.  /* in artifact.c, set up the actual artifact list structure */
2124.  
2125. -#define A(nam,typ,s1,s2,mt,atk,dfn,cry,inv,al,cl,rac,cost) \
2126. - { typ, nam, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, cost }
2127. +#define A(nam,typ,mat,s1,s2,mt,atk,dfn,cry,inv,al,cl,rac,cost) \
2128. + { typ, nam, s1, s2, mt, atk, dfn, cry, inv, mat, al, cl, rac, cost }
2129.  
2130.  #define     NO_ATTK	{0,0,0,0}		/* no attack */
2131.  #define     NO_DFNS	{0,0,0,0}		/* no defense */
2132. @@ -35,42 +35,55 @@ STATIC_OVL NEARDATA struct artifact arti
2133.   * 3.  Chaotic artifacts are inflated due to scarcity (and balance).
2134.   */
2135.  
2136. +/* Arc	---		*/
2137. +/* Bar	Cleaver		*/
2138. +/* Cav	Skullcrusher	*/
2139. +/* Hea	---		*/
2140. +/* Kni	Excalibur	*/
2141. +/* Mon	---		*/
2142. +/* Pri	Disrupter	*/
2143. +/* Ran	---		*/
2144. +/* Rog	---		*/
2145. +/* Sam	Snickersnee	*/
2146. +/* Tou	---		*/
2147. +/* Val	Mjollnir	*/
2148. +/* Wiz	Magicbane	*/
2149.  
2150.  /*  dummy element #0, so that all interesting indices are non-zero */
2151. -A("",				STRANGE_OBJECT,
2152. +A("",				STRANGE_OBJECT,	0,
2153.  	0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L ),
2154.  
2155. -A("Excalibur",			LONG_SWORD,
2156. +A("Excalibur",			LONG_SWORD,	METAL,
2157.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_SEEK|SPFX_DEFN|SPFX_INTEL|SPFX_SEARCH),0,0,
2158.  	PHYS(5,10),	DRLI(0,0),	NO_CARY,	0, A_LAWFUL, PM_KNIGHT, NON_PM, 4000L ),
2159.  /*
2160.   *	Stormbringer only has a 2 because it can drain a level,
2161.   *	providing 8 more.
2162.   */
2163. -A("Stormbringer",		RUNESWORD,
2164. +A("Stormbringer",		RUNESWORD,	0,
2165.  	(SPFX_RESTR|SPFX_ATTK|SPFX_DEFN|SPFX_INTEL|SPFX_DRLI), 0, 0,
2166.  	DRLI(5,2),	DRLI(0,0),	NO_CARY,	0, A_CHAOTIC, NON_PM, NON_PM, 8000L ),
2167.  /*
2168.   *	Mjollnir will return to the hand of the wielder when thrown
2169.   *	if the wielder is a Valkyrie wearing Gauntlets of Power.
2170.   */
2171. -A("Mjollnir",			WAR_HAMMER,		/* Mjo:llnir */
2172. +A("Mjollnir",			HEAVY_HAMMER,	0,	/* Mjo:llnir */
2173.  	(SPFX_RESTR|SPFX_ATTK),  0, 0,
2174. -	ELEC(5,24),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, PM_VALKYRIE, NON_PM, 4000L ),
2175. +	ELEC(0,20),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, PM_VALKYRIE, NON_PM, 4000L ),
2176.  
2177. -A("Cleaver",			BATTLE_AXE,
2178. +A("Cleaver",			BATTLE_AXE,	0,
2179.  	SPFX_RESTR, 0, 0,
2180. -	PHYS(3,6),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, PM_BARBARIAN, NON_PM, 1500L ),
2181. +	PHYS(3,10),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, PM_BARBARIAN, NON_PM, 1500L ),
2182.  
2183. -A("Grimtooth",			ORCISH_DAGGER,
2184. +A("Grimtooth",			ORCISH_DAGGER,	0,
2185.  	SPFX_RESTR, 0, 0,
2186.  	PHYS(2,6),	NO_DFNS,	NO_CARY,	0, A_CHAOTIC, NON_PM, PM_ORC, 300L ),
2187.  /*
2188.   *	Orcrist and Sting have same alignment as elves.
2189.   */
2190. -A("Orcrist",			ELVEN_BROADSWORD,
2191. -	SPFX_DFLAG2, 0, M2_ORC,
2192. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_CHAOTIC, NON_PM, PM_ELF, 2000L ),
2193. +A("Orcrist",			ELVEN_BROADSWORD,	0,
2194. +	(SPFX_WARN|SPFX_DFLAG2), 0, M2_ORC,
2195. +	PHYS(15,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_CHAOTIC, NON_PM, PM_ELF, 2000L ),
2196.  
2197.  /*
2198.   *	The combination of SPFX_WARN and M2_something on an artifact
2199. @@ -78,60 +91,72 @@ A("Orcrist",			ELVEN_BROADSWORD,
2200.   *	M2_something flags.  In Sting's case it will trigger EWarn_of_mon
2201.   *	for M2_ORC monsters.
2202.   */
2203. -A("Sting",			ELVEN_DAGGER,
2204. +A("Sting",			ELVEN_DAGGER,	0,
2205.  	(SPFX_WARN|SPFX_DFLAG2), 0, M2_ORC,
2206. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_CHAOTIC, NON_PM, PM_ELF, 800L ),
2207. +	PHYS(15,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_CHAOTIC, NON_PM, PM_ELF, 800L ),
2208.  /*
2209.   *	Magicbane is a bit different!  Its magic fanfare
2210.   *	unbalances victims in addition to doing some damage.
2211.   */
2212. -A("Magicbane",			ATHAME,
2213. +A("Magicbane",			ATHAME,	0,
2214.  	(SPFX_RESTR|SPFX_ATTK|SPFX_DEFN), 0, 0,
2215.  	STUN(3,4),	DFNS(AD_MAGM),	NO_CARY,	0, A_NEUTRAL, PM_WIZARD, NON_PM, 3500L ),
2216.  
2217. -A("Frost Brand",		LONG_SWORD,
2218. +A("Disrupter",			MACE,	SILVER,
2219. +	(SPFX_RESTR|SPFX_DFLAG2), 0, M2_UNDEAD,
2220. +	PHYS(10,30),	NO_DFNS,	NO_CARY,	0, A_NONE, PM_PRIEST, NON_PM, 2000L ),
2221. +
2222. +A("Skullcrusher",			CLUB,	BONE,
2223. +	(SPFX_RESTR|SPFX_ATTK), 0, 0,
2224. +	PHYS(3,15),	NO_DFNS,	NO_CARY,	0, A_NONE, PM_CAVEMAN, NON_PM, 1000L ),
2225. +
2226. +A("Frost Brand",		LONG_SWORD,	0,
2227.  	(SPFX_RESTR|SPFX_ATTK|SPFX_DEFN), 0, 0,
2228. -	COLD(5,0),	COLD(0,0),	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 3000L ),
2229. +	COLD(5,ADMG_DOUBLE),	COLD(0,0),	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 3000L ),
2230.  
2231. -A("Fire Brand",			LONG_SWORD,
2232. +A("Fire Brand",			LONG_SWORD,	0,
2233.  	(SPFX_RESTR|SPFX_ATTK|SPFX_DEFN), 0, 0,
2234. -	FIRE(5,0),	FIRE(0,0),	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 3000L ),
2235. +	FIRE(5,ADMG_DOUBLE),	FIRE(0,0),	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 3000L ),
2236.  
2237. -A("Dragonbane",			BROADSWORD,
2238. -	(SPFX_RESTR|SPFX_DCLAS), 0, S_DRAGON,
2239. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 500L ),
2240. +A("Dragonslayer",		BROADSWORD,	0,
2241. +	(SPFX_RESTR|SPFX_DCLAS|SPFX_REFLECT), 0, S_DRAGON,
2242. +	PHYS(10,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 2500L ),
2243.  
2244. -A("Demonbane",			LONG_SWORD,
2245. +A("Demonbane",			LONG_SWORD,	SILVER,
2246.  	(SPFX_RESTR|SPFX_DFLAG2), 0, M2_DEMON,
2247. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_LAWFUL, NON_PM, NON_PM, 2500L ),
2248. +	PHYS(10,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_LAWFUL, NON_PM, NON_PM, 2500L ),
2249.  
2250. -A("Werebane",			SILVER_SABER,
2251. +A("Werebane",			REVOLVER,	0,
2252.  	(SPFX_RESTR|SPFX_DFLAG2), 0, M2_WERE,
2253. -	PHYS(5,0),	DFNS(AD_WERE),	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 1500L ),
2254. -
2255. -A("Grayswandir",		SILVER_SABER,
2256. +	PHYS(20,ADMG_DOUBLE),	DFNS(AD_WERE),	NO_CARY,
2257. +	CREATE_AMMO, A_NONE, NON_PM, NON_PM, 5000L ),
2258. +A("Grayswandir",		SABER,		SILVER,
2259.  	(SPFX_RESTR|SPFX_HALRES), 0, 0,
2260. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_LAWFUL, NON_PM, NON_PM, 8000L ),
2261. +	PHYS(3,12),	NO_DFNS,	NO_CARY,	0, A_LAWFUL, NON_PM, NON_PM, 8000L ),
2262.  
2263. -A("Giantslayer",		LONG_SWORD,
2264. +A("Quick Blade",		ELVEN_SHORT_SWORD,	0,
2265. +	SPFX_RESTR,		  0, 0,
2266. +	PHYS(10,0),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 1500L ),
2267. +
2268. +A("Giantkiller",		TWO_HANDED_SWORD,	0,
2269.  	(SPFX_RESTR|SPFX_DFLAG2), 0, M2_GIANT,
2270. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, NON_PM, NON_PM, 200L ),
2271. +	PHYS(15,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, NON_PM, NON_PM, 200L ),
2272.  
2273. -A("Ogresmasher",		WAR_HAMMER,
2274. +A("Ogresmasher",		LUCERN_HAMMER,	0,
2275.  	(SPFX_RESTR|SPFX_DCLAS), 0, S_OGRE,
2276. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 200L ),
2277. +	PHYS(15,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 200L ),
2278.  
2279. -A("Trollsbane",			MORNING_STAR,
2280. +A("Trollsbane",			MORNING_STAR,	0,
2281.  	(SPFX_RESTR|SPFX_DCLAS), 0, S_TROLL,
2282. -	PHYS(5,0),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 200L ),
2283. +	PHYS(15,ADMG_DOUBLE),	NO_DFNS,	NO_CARY,	0, A_NONE, NON_PM, NON_PM, 800L ),
2284.  /*
2285.   *	Two problems:  1) doesn't let trolls regenerate heads,
2286.   *	2) doesn't give unusual message for 2-headed monsters (but
2287.   *	allowing those at all causes more problems than worth the effort).
2288.   */
2289. -A("Vorpal Blade",		LONG_SWORD,
2290. +A("Vorpal Blade",		LONG_SWORD,	0,
2291.  	(SPFX_RESTR|SPFX_BEHEAD), 0, 0,
2292. -	PHYS(5,1),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, NON_PM, NON_PM, 4000L ),
2293. +	PHYS(15,0),	NO_DFNS,	NO_CARY,	0, A_NEUTRAL, NON_PM, NON_PM, 4000L ),
2294.  /*
2295.   *	Ah, never shall I forget the cry,
2296.   *		or the shriek that shrieked he,
2297. @@ -140,101 +165,122 @@ A("Vorpal Blade",		LONG_SWORD,
2298.   *			--Koko, Lord high executioner of Titipu
2299.   *			  (From Sir W.S. Gilbert's "The Mikado")
2300.   */
2301. -A("Snickersnee",		KATANA,
2302. +A("Snickersnee",		KATANA,	0,
2303.  	SPFX_RESTR, 0, 0,
2304. -	PHYS(0,8),	NO_DFNS,	NO_CARY,	0, A_LAWFUL, PM_SAMURAI, NON_PM, 1200L ),
2305. +	PHYS(10,8),	NO_DFNS,	NO_CARY,	0, A_LAWFUL, PM_SAMURAI, NON_PM, 1200L ),
2306.  
2307. -A("Sunsword",			LONG_SWORD,
2308. +A("Sunsword",			LONG_SWORD,	0,
2309.  	(SPFX_RESTR|SPFX_DFLAG2), 0, M2_UNDEAD,
2310. -	PHYS(5,0),	DFNS(AD_BLND),	NO_CARY,	0, A_LAWFUL, NON_PM, NON_PM, 1500L ),
2311. +	PHYS(10,ADMG_DOUBLE),	DFNS(AD_BLND),	NO_CARY,
2312. +	EMIT_LIGHT, A_LAWFUL, NON_PM, NON_PM, 1500L ),
2313. +/*
2314. + *	Artifact gloves for Monks
2315. + */
2316. +A("Gauntlets of Defence",	GAUNTLETS_OF_DEXTERITY,	0,
2317. +	(SPFX_RESTR|SPFX_HPHDAM|SPFX_INTEL), 0, 0,
2318. +	NO_ATTK,	NO_DFNS,	NO_CARY,
2319. +	0,		A_CROSSALIGNED, PM_MONK, NON_PM, 2000L ),
2320.  
2321. +A("Fist of Fury",		GAUNTLETS,	SILVER,
2322. +	(SPFX_RESTR|SPFX_INTEL), 0,	0,
2323. +	PHYS(5,10),	NO_DFNS,	NO_CARY,
2324. +	0,		A_CROSSALIGNED, PM_MONK, NON_PM, 2000L ),
2325. +
2326.  /*
2327.   *	The artifacts for the quest dungeon, all self-willed.
2328.   */
2329.  
2330. -A("The Orb of Detection",	CRYSTAL_BALL,
2331. +A("The Orb of Detection",	CRYSTAL_BALL,	0,
2332.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), (SPFX_ESP|SPFX_HSPDAM), 0,
2333.  	NO_ATTK,	NO_DFNS,	CARY(AD_MAGM),
2334.  	INVIS,		A_LAWFUL, PM_ARCHEOLOGIST, NON_PM, 2500L ),
2335.  
2336. -A("The Heart of Ahriman",	LUCKSTONE,
2337. +A("The Heart of Ahriman",	LUCKSTONE,	0,
2338.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), SPFX_STLTH, 0,
2339.  	/* this stone does double damage if used as a projectile weapon */
2340.  	PHYS(5,0),	NO_DFNS,	NO_CARY,
2341.  	LEVITATION,	A_NEUTRAL, PM_BARBARIAN, NON_PM, 2500L ),
2342.  
2343. -A("The Sceptre of Might",	MACE,
2344. +A("The Sceptre of Might",	MACE,	0,
2345.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_DALIGN), 0, 0,
2346. -	PHYS(5,0),	NO_DFNS,	CARY(AD_MAGM),
2347. +	PHYS(5,ADMG_DOUBLE),	NO_DFNS,	CARY(AD_MAGM),
2348.  	CONFLICT,	A_LAWFUL, PM_CAVEMAN, NON_PM, 2500L ),
2349.  
2350.  #if 0	/* OBSOLETE */
2351. -A("The Palantir of Westernesse",	CRYSTAL_BALL,
2352. +A("The Palantir of Westernesse",	CRYSTAL_BALL,	0,
2353.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL),
2354.  		(SPFX_ESP|SPFX_REGEN|SPFX_HSPDAM), 0,
2355.  	NO_ATTK,	NO_DFNS,	NO_CARY,
2356.  	TAMING,		A_CHAOTIC, NON_PM , PM_ELF, 8000L ),
2357.  #endif
2358.  
2359. -A("The Staff of Aesculapius",	QUARTERSTAFF,
2360. +A("The Staff of Aesculapius",	QUARTERSTAFF,	0,
2361.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_ATTK|SPFX_INTEL|SPFX_DRLI|SPFX_REGEN), 0,0,
2362. -	DRLI(0,0),	DRLI(0,0),	NO_CARY,
2363. +	DRLI(0,ADMG_DOUBLE),	DRLI(0,0),	NO_CARY,
2364.  	HEALING,	A_NEUTRAL, PM_HEALER, NON_PM, 5000L ),
2365.  
2366. -A("The Magic Mirror of Merlin", MIRROR,
2367. +A("The Magic Mirror of Merlin", MIRROR,	0,
2368.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_SPEAK), SPFX_ESP, 0,
2369.  	NO_ATTK,	NO_DFNS,	CARY(AD_MAGM),
2370.  	0,		A_LAWFUL, PM_KNIGHT, NON_PM, 1500L ),
2371.  
2372. -A("The Eyes of the Overworld",	LENSES,
2373. +A("The Eyes of the Overworld",	LENSES, 0,
2374.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_XRAY), 0, 0,
2375.  	NO_ATTK,	NO_DFNS,	CARY(AD_MAGM),
2376.  	ENLIGHTENING,	A_NEUTRAL,	 PM_MONK, NON_PM, 2500L ),
2377.  
2378. -A("The Mitre of Holiness",	HELM_OF_BRILLIANCE,
2379. +A("The Mitre of Holiness",	HELM_OF_BRILLIANCE,	0,
2380.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_DFLAG2|SPFX_INTEL), 0, M2_UNDEAD,
2381.  	NO_ATTK,	NO_DFNS,	CARY(AD_FIRE),
2382.  	ENERGY_BOOST,	A_LAWFUL, PM_PRIEST, NON_PM, 2000L ),
2383.  
2384. -A("The Longbow of Diana", BOW,
2385. -	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_REFLECT), SPFX_ESP, 0,
2386. -	PHYS(5,0),	NO_DFNS,	NO_CARY,
2387. +A("The Longbow of Diana", BOW, 0,
2388. +	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL/*|SPFX_REFLECT*/), SPFX_ESP, 0,
2389. +	PHYS(5,3),	NO_DFNS,	NO_CARY,
2390.  	CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM, 4000L ),
2391.  
2392. -A("The Master Key of Thievery", SKELETON_KEY,
2393. +A("The Master Key of Thievery", SKELETON_KEY, 0,
2394.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_SPEAK),
2395.  		(SPFX_WARN|SPFX_TCTRL|SPFX_HPHDAM), 0,
2396.  	NO_ATTK,	NO_DFNS,	NO_CARY,
2397.  	UNTRAP,		A_CHAOTIC, PM_ROGUE, NON_PM, 3500L ),
2398.  
2399. -A("The Tsurugi of Muramasa",	TSURUGI,
2400. +A("The Tsurugi of Muramasa",	TSURUGI, 0,
2401.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_BEHEAD|SPFX_LUCK), 0, 0,
2402.  	PHYS(0,8),	NO_DFNS,	NO_CARY,
2403.  	0,		A_LAWFUL, PM_SAMURAI, NON_PM, 4500L ),
2404.  
2405.  #ifdef TOURIST
2406. -A("The Platinum Yendorian Express Card", CREDIT_CARD,
2407. +A("The Platinum Yendorian Express Card", CREDIT_CARD, 0,
2408.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_DEFN),
2409.  		(SPFX_ESP|SPFX_HSPDAM), 0,
2410.  	NO_ATTK,	NO_DFNS,	CARY(AD_MAGM),
2411.  	CHARGE_OBJ,	A_NEUTRAL, PM_TOURIST, NON_PM, 7000L ),
2412.  #endif
2413.  
2414. -A("The Orb of Fate",		CRYSTAL_BALL,
2415. +A("The Orb of Fate",		CRYSTAL_BALL, 0,
2416.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL|SPFX_LUCK),
2417.  		(SPFX_WARN|SPFX_HSPDAM|SPFX_HPHDAM), 0,
2418.  	NO_ATTK,	NO_DFNS,	NO_CARY,
2419.  	LEV_TELE,	A_NEUTRAL, PM_VALKYRIE, NON_PM, 3500L ),
2420.  
2421. -A("The Eye of the Aethiopica",	AMULET_OF_ESP,
2422. +A("The Eye of the Aethiopica",	AMULET_OF_ESP, 0,
2423.  	(SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), (SPFX_EREGEN|SPFX_HSPDAM), 0,
2424.  	NO_ATTK,	NO_DFNS,	CARY(AD_MAGM),
2425.  	CREATE_PORTAL,	A_NEUTRAL, PM_WIZARD, NON_PM, 4000L ),
2426.  
2427.  /*
2428. + *	dummy entry for user-made weapon
2429. + */
2430. +A("Custom Made Weapon",	TIN_OPENER, 0,  /* dummy otyp */
2431. +	(SPFX_NOGEN|SPFX_RESTR), 0, 0,
2432. +	NO_ATTK,	NO_DFNS,	NO_CARY,
2433. +	0,	A_NONE, NON_PM, NON_PM, 0L ),
2434. +
2435. +/*
2436.   *  terminator; otyp must be zero
2437.   */
2438. -A(0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L )
2439. +A(0, 0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L )
2440.  
2441.  };	/* artilist[] (or artifact_names[]) */
2442.  

attrib.h

2443. diff -pruN nethack-3.4.3/include/attrib.h nhbrass-040923/include/attrib.h
2444. --- nethack-3.4.3/include/attrib.h	Sun Dec  7 18:39:13 2003
2445. +++ nhbrass-040923/include/attrib.h	Wed Apr 10 11:29:56 2002
2446. @@ -38,7 +38,8 @@ struct	attribs {
2447.  	schar	a[A_MAX];
2448.  };
2449.  
2450. -#define ATTRMAX(x) ((x == A_STR && Upolyd && strongmonst(youmonst.data)) ? STR18(100) : urace.attrmax[x])
2451. +/* #define ATTRMAX(x) ((x == A_STR && Upolyd && strongmonst(youmonst.data)) ? STR18(100) : urace.attrmax[x])*/
2452. +#define ATTRMAX(x) ((x == A_STR && Upolyd && strongmonst(youmonst.data)) ? STR18(100) : urole.attrmax[x])
2453.  #define ATTRMIN(x) (urace.attrmin[x])
2454.  
2455.  #endif /* ATTRIB_H */

config.h

2456. diff -pruN nethack-3.4.3/include/config.h nhbrass-040923/include/config.h
2457. --- nethack-3.4.3/include/config.h	Sun Dec  7 18:39:13 2003
2458. +++ nhbrass-040923/include/config.h	Sat Dec 27 17:30:16 2003
2459. @@ -338,6 +338,15 @@ typedef unsigned char	uchar;
2460.  #endif
2461.  
2462.  #define EXP_ON_BOTL	/* Show experience on bottom line */
2463. +//#define AUTOTHRUST	/* Automatically target a monster in range with polearms */
2464. +#define FIRSTAID	/* scissors/bandage */
2465. +#define NOPOLYPILE	/* polymorph affects only one item on the first pile */
2466. +#define SHOWDMG		/* show damage value */
2467. +#define RAND_MT		/* use mersenne twister for random number */
2468. +#define NEWGEHENNOM	/* under construction */
2469. +#ifdef STEED
2470. +# define MONSTEED	/* monster is riding steeds */
2471. +#endif /*STEED*/
2472.  /* #define SCORE_ON_BOTL */	/* added by Gary Erickson (erickson@ucivax) */
2473.  
2474.  /*

The AUTOTHRUST line is commented out because the AUTOTHRUST macro no longer does anything. The autothrust feature (pressing [v] to hit the nearest monster with your wielded polearm) is always on, and it is not possible to disable it by defining or undefining a macro.

display.h

2551. diff -pruN nethack-3.4.3/include/display.h nhbrass-040923/include/display.h
2552. --- nethack-3.4.3/include/display.h	Sun Dec  7 18:39:13 2003
2553. +++ nhbrass-040923/include/display.h	Sat Dec 27 14:11:50 2003
2554. @@ -40,9 +40,11 @@
2555.   * vicinity, and a glyph representing the warning level is displayed.
2556.   */
2557.  
2558. +//#define mon_warning(mon) (Warning && !(mon)->mpeaceful &&
2559. +//			 (distu((mon)->mx, (mon)->my) < 100) &&
2560. +//			 (((int) ((mon)->m_lev / 4)) >= flags.warnlevel))
2561.  #define mon_warning(mon) (Warning && !(mon)->mpeaceful && 				\
2562. -			 (distu((mon)->mx, (mon)->my) < 100) &&				\
2563. -			 (((int) ((mon)->m_lev / 4)) >= flags.warnlevel))
2564. +			 (distu((mon)->mx, (mon)->my) < 100))
2565.  
2566.  /*
2567.   * mon_visible()
2568. @@ -92,6 +94,23 @@
2569.  #define canspotmon(mon) \
2570.  	(canseemon(mon) || sensemon(mon))
2571.  
2572. +
2573. +/*
2574. + * canspotmons(mon)
2575. + *
2576. + * This function is variation of canspotmon() which returns TRUE if
2577. + * you can spot any monsters in the same place as mon's.
2578. + */
2579. +#ifndef MONSTEED
2580. +#define canspotmons canspotmon
2581. +#else
2582. +#define canspotmons(mon) \
2583. +	(canspotmon(mon) || \
2584. +	 ((mon)->mriding && canspotmon((mon)->mchild)) || \
2585. +	 ((mon)->msteed && canspotmon((mon)->mparent)))
2586. +#endif /*MONSTEED*/
2587. +
2588. +
2589.  /* knowninvisible(mon)
2590.   * This one checks to see if you know a monster is both there and invisible.
2591.   * 1) If you can see the monster and have see invisible, it is assumed the
2592. @@ -234,7 +253,8 @@
2593.   *
2594.   * ridden	Represents all monsters being ridden.  Count: NUMMONS 
2595.   *
2596. - * object	One for each object.  Count: NUM_OBJECTS
2597. + * object	32(number of materials) for each object.
2598. + *		Lower 5 bits indicate materials.  Count: NUM_OBJECTS << 5
2599.   *
2600.   * cmap		One for each entry in the character map.  The character map
2601.   *		is the dungeon features and other miscellaneous things.
2602. @@ -258,16 +278,18 @@
2603.   *
2604.   * The following are offsets used to convert to and from a glyph.
2605.   */
2606. -#define NUM_ZAP 8	/* number of zap beam types */
2607. +#define NUM_ZAP 9	/* number of zap beam types */
2608.  
2609.  #define GLYPH_MON_OFF		0
2610.  #define GLYPH_PET_OFF		(NUMMONS	+ GLYPH_MON_OFF)
2611.  #define GLYPH_INVIS_OFF		(NUMMONS	+ GLYPH_PET_OFF)
2612.  #define GLYPH_DETECT_OFF	(1		+ GLYPH_INVIS_OFF)
2613.  #define GLYPH_BODY_OFF		(NUMMONS	+ GLYPH_DETECT_OFF)
2614. -#define GLYPH_RIDDEN_OFF	(NUMMONS	+ GLYPH_BODY_OFF)
2615. +#define GLYPH_RIDING_OFF	(NUMMONS	+ GLYPH_BODY_OFF)
2616. +#define GLYPH_RIDDEN_OFF	(NUMMONS	+ GLYPH_RIDING_OFF)
2617.  #define GLYPH_OBJ_OFF		(NUMMONS	+ GLYPH_RIDDEN_OFF)
2618. -#define GLYPH_CMAP_OFF		(NUM_OBJECTS	+ GLYPH_OBJ_OFF)
2619. +#define GLYPH_CMAP_OFF		((NUM_OBJECTS << 5) + GLYPH_OBJ_OFF) /* material patch */
2620. +/*#define GLYPH_CMAP_OFF		(NUM_OBJECTS	+ GLYPH_OBJ_OFF)*/
2621.  #define GLYPH_EXPLODE_OFF	((MAXPCHARS - MAXEXPCHARS) + GLYPH_CMAP_OFF)
2622.  #define GLYPH_ZAP_OFF		((MAXEXPCHARS * EXPL_MAX) + GLYPH_EXPLODE_OFF)
2623.  #define GLYPH_SWALLOW_OFF	((NUM_ZAP << 2) + GLYPH_ZAP_OFF)
2624. @@ -281,6 +303,7 @@
2625.  #define warning_to_glyph(mwarnlev) ((mwarnlev)+GLYPH_WARNING_OFF)
2626.  #define mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_MON_OFF)
2627.  #define detected_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_DETECT_OFF)
2628. +#define riding_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_RIDING_OFF)
2629.  #define ridden_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_RIDDEN_OFF)
2630.  #define pet_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_PET_OFF)
2631.  
2632. @@ -290,10 +313,11 @@
2633.      (Hallucination ?							      \
2634.  	((otg_temp = random_object()) == CORPSE ?			      \
2635.  	    random_monster() + GLYPH_BODY_OFF :				      \
2636. -	    otg_temp + GLYPH_OBJ_OFF)	:				      \
2637. +	    (otg_temp<<5) + rnd(MAX_MATERIAL) + GLYPH_OBJ_OFF)	:	      \
2638.  	((obj)->otyp == CORPSE ?					      \
2639.  	    (int) (obj)->corpsenm + GLYPH_BODY_OFF :			      \
2640. -	    (int) (obj)->otyp + GLYPH_OBJ_OFF))
2641. +	    ((int) (obj)->otyp << 5) +					      \
2642. +		(is_material_variable(obj) ? get_material(obj) : 0) + GLYPH_OBJ_OFF))
2643.  
2644.  #define cmap_to_glyph(cmap_idx) ((int) (cmap_idx)   + GLYPH_CMAP_OFF)
2645.  #define explosion_to_glyph(expltype,idx)	\
2646. @@ -303,7 +327,7 @@
2647.  			cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp)))
2648.  
2649.  /* Not affected by hallucination.  Gives a generic body for CORPSE */
2650. -#define objnum_to_glyph(onum)	((int) (onum) + GLYPH_OBJ_OFF)
2651. +#define objnum_to_glyph(onum)	(((int) (onum) << 5) + GLYPH_OBJ_OFF)
2652.  #define monnum_to_glyph(mnum)	((int) (mnum) + GLYPH_MON_OFF)
2653.  #define detected_monnum_to_glyph(mnum)	((int) (mnum) + GLYPH_DETECT_OFF)
2654.  #define ridden_monnum_to_glyph(mnum)	((int) (mnum) + GLYPH_RIDDEN_OFF)
2655. @@ -316,7 +340,6 @@
2656.  	                (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : \
2657.  	                urace.malenum)
2658.  
2659. -
2660.  /*
2661.   * Change the given glyph into it's given type.  Note:
2662.   *	1) Pets, detected, and ridden monsters are animals and are converted
2663. @@ -333,11 +356,12 @@
2664.  	(glyph_is_normal_monster(glyph) ? ((glyph)-GLYPH_MON_OFF) :	\
2665.  	glyph_is_pet(glyph) ? ((glyph)-GLYPH_PET_OFF) :			\
2666.  	glyph_is_detected_monster(glyph) ? ((glyph)-GLYPH_DETECT_OFF) :	\
2667. +	glyph_is_riding_monster(glyph) ? ((glyph)-GLYPH_RIDING_OFF) :	\
2668.  	glyph_is_ridden_monster(glyph) ? ((glyph)-GLYPH_RIDDEN_OFF) :	\
2669.  	NO_GLYPH)
2670.  #define glyph_to_obj(glyph)						\
2671.  	(glyph_is_body(glyph) ? CORPSE :				\
2672. -	glyph_is_normal_object(glyph) ? ((glyph)-GLYPH_OBJ_OFF) :	\
2673. +	glyph_is_normal_object(glyph) ? (((glyph)-GLYPH_OBJ_OFF) >> 5) :	\
2674.  	NO_GLYPH)
2675.  #define glyph_to_trap(glyph)						\
2676.  	(glyph_is_trap(glyph) ?						\
2677. @@ -360,6 +384,7 @@
2678.  #define glyph_is_monster(glyph)						\
2679.  		(glyph_is_normal_monster(glyph)				\
2680.  		|| glyph_is_pet(glyph)					\
2681. +		|| glyph_is_riding_monster(glyph)			\
2682.  		|| glyph_is_ridden_monster(glyph)			\
2683.  		|| glyph_is_detected_monster(glyph))
2684.  #define glyph_is_normal_monster(glyph)					\
2685. @@ -368,13 +393,15 @@
2686.      ((glyph) >= GLYPH_PET_OFF && (glyph) < (GLYPH_PET_OFF+NUMMONS))
2687.  #define glyph_is_body(glyph)						\
2688.      ((glyph) >= GLYPH_BODY_OFF && (glyph) < (GLYPH_BODY_OFF+NUMMONS))
2689. +#define glyph_is_riding_monster(glyph)					\
2690. +    ((glyph) >= GLYPH_RIDING_OFF && (glyph) < (GLYPH_RIDING_OFF+NUMMONS))
2691.  #define glyph_is_ridden_monster(glyph)					\
2692.      ((glyph) >= GLYPH_RIDDEN_OFF && (glyph) < (GLYPH_RIDDEN_OFF+NUMMONS))
2693.  #define glyph_is_detected_monster(glyph)				\
2694.      ((glyph) >= GLYPH_DETECT_OFF && (glyph) < (GLYPH_DETECT_OFF+NUMMONS))
2695.  #define glyph_is_invisible(glyph) ((glyph) == GLYPH_INVISIBLE)
2696.  #define glyph_is_normal_object(glyph)					\
2697. -    ((glyph) >= GLYPH_OBJ_OFF && (glyph) < (GLYPH_OBJ_OFF+NUM_OBJECTS))
2698. +    ((glyph) >= GLYPH_OBJ_OFF && (glyph) < (GLYPH_OBJ_OFF+(NUM_OBJECTS<<5)))
2699.  #define glyph_is_object(glyph)						\
2700.  		(glyph_is_normal_object(glyph)				\
2701.  		|| glyph_is_body(glyph))

Because monsters riding steeds is a new feature in NetHack brass, the display code needs to know how to draw them on screen.

obj.h

3623. diff -pruN nethack-3.4.3/include/obj.h nhbrass-040923/include/obj.h
3624. --- nethack-3.4.3/include/obj.h	Sun Dec  7 18:39:13 2003
3625. +++ nhbrass-040923/include/obj.h	Wed Dec 10 07:49:36 2003
3626. @@ -72,12 +72,15 @@ struct obj {
3627.  #define norevive oeroded2
3628.  	Bitfield(oerodeproof,1); /* erodeproof weapon/armor */
3629.  	Bitfield(olocked,1);	/* object is locked */
3630. +#define sokoprize olocked	/* special flag for sokoban prize */
3631.  	Bitfield(obroken,1);	/* lock has been broken */
3632. +#define oshot obroken		/* a bullet is shot from a gun, not thrown */
3633.  	Bitfield(otrapped,1);	/* container is trapped */
3634.  				/* or accidental tripped rolling boulder trap */
3635.  #define opoisoned otrapped	/* object (weapon) is coated with poison */
3636.  
3637.  	Bitfield(recharged,3);	/* number of times it's been recharged */
3638. +#define oacadjust recharged	/* armor-class adjustment (-4 to +3) */
3639.  	Bitfield(lamplit,1);	/* a light-source -- can be lit */
3640.  #ifdef INVISIBLE_OBJECTS
3641.  	Bitfield(oinvis,1);	/* invisible */
3642. @@ -91,13 +94,15 @@ struct obj {
3643.  
3644.  	Bitfield(in_use,1);	/* for magic items before useup items */
3645.  	Bitfield(bypass,1);	/* mark this as an object to be skipped by bhito() */
3646. -	/* 6 free bits */
3647. +	Bitfield(etherial,1);	/* magically created object */
3648. +	Bitfield(madeof,5);	/* material num if obj is made of unusual material */
3649.  
3650.  	int	corpsenm;	/* type of corpse is mons[corpsenm] */
3651.  #define leashmon  corpsenm	/* gets m_id of attached pet */
3652.  #define spestudied corpsenm	/* # of times a spellbook has been studied */
3653.  #define fromsink  corpsenm	/* a potion from a sink */
3654.  	unsigned oeaten;	/* nutrition left in food, if partly eaten */
3655. +#define odamaged oeaten		/* how much object's special power worn out */
3656.  	long age;		/* creation date */
3657.  
3658.  	uchar onamelth;		/* length of name (following oxlth) */
3659. @@ -125,50 +130,69 @@ struct obj {
3660.   *	#define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN)
3661.   */
3662.  #define is_blade(otmp)	(otmp->oclass == WEAPON_CLASS && \
3663. -			 objects[otmp->otyp].oc_skill >= P_DAGGER && \
3664. -			 objects[otmp->otyp].oc_skill <= P_SABER)
3665. +			 objects[otmp->otyp].oc_skill >= P_DAGGER_GROUP && \
3666. +			 objects[otmp->otyp].oc_skill <= P_SABER_GROUP)
3667.  #define is_axe(otmp)	((otmp->oclass == WEAPON_CLASS || \
3668.  			 otmp->oclass == TOOL_CLASS) && \
3669. -			 objects[otmp->otyp].oc_skill == P_AXE)
3670. +			 objects[otmp->otyp].oc_skill == P_AXE_GROUP)
3671.  #define is_pick(otmp)	((otmp->oclass == WEAPON_CLASS || \
3672.  			 otmp->oclass == TOOL_CLASS) && \
3673. -			 objects[otmp->otyp].oc_skill == P_PICK_AXE)
3674. +			 objects[otmp->otyp].oc_skill == P_PICKAXE_GROUP)
3675.  #define is_sword(otmp)	(otmp->oclass == WEAPON_CLASS && \
3676. -			 objects[otmp->otyp].oc_skill >= P_SHORT_SWORD && \
3677. -			 objects[otmp->otyp].oc_skill <= P_SABER)
3678. +			 objects[otmp->otyp].oc_skill >= P_SHORT_BLADE_GROUP && \
3679. +			 objects[otmp->otyp].oc_skill <= P_SABER_GROUP)
3680.  #define is_pole(otmp)	((otmp->oclass == WEAPON_CLASS || \
3681.  			otmp->oclass == TOOL_CLASS) && \
3682. -			 (objects[otmp->otyp].oc_skill == P_POLEARMS || \
3683. -			 objects[otmp->otyp].oc_skill == P_LANCE))
3684. +			 objects[otmp->otyp].oc_skill == P_POLEARM_GROUP)
3685.  #define is_spear(otmp)	(otmp->oclass == WEAPON_CLASS && \
3686. -			 objects[otmp->otyp].oc_skill >= P_SPEAR && \
3687. -			 objects[otmp->otyp].oc_skill <= P_JAVELIN)
3688. +			 objects[otmp->otyp].oc_skill == P_SPEAR_GROUP)
3689. +#define is_gun(otmp)	(otmp->oclass == WEAPON_CLASS && \
3690. +			 objects[otmp->otyp].oc_skill == P_FIREARM_GROUP)
3691. +#define maxbullets(otmp) (otmp->otyp == REVOLVER ? 6 : \
3692. +                          otmp->otyp == MUSKET ? 1 : 0)
3693.  #define is_launcher(otmp)	(otmp->oclass == WEAPON_CLASS && \
3694. -			 objects[otmp->otyp].oc_skill >= P_BOW && \
3695. -			 objects[otmp->otyp].oc_skill <= P_CROSSBOW)
3696. +			 (objects[otmp->otyp].oc_wprop & WP_WEAPONTYPE) == WP_LAUNCHER)
3697.  #define is_ammo(otmp)	((otmp->oclass == WEAPON_CLASS || \
3698.  			 otmp->oclass == GEM_CLASS) && \
3699. -			 objects[otmp->otyp].oc_skill >= -P_CROSSBOW && \
3700. -			 objects[otmp->otyp].oc_skill <= -P_BOW)
3701. +			 (objects[otmp->otyp].oc_wprop & WP_WEAPONTYPE) == WP_AMMUNITION)
3702. +#define is_bullet(otmp)	(otmp->oclass == WEAPON_CLASS && \
3703. +			 (objects[otmp->otyp].oc_wprop & (WP_WEAPONTYPE|WP_SUBTYPE)) == \
3704. +			 (WP_AMMUNITION|WP_BULLET))
3705.  #define ammo_and_launcher(otmp,ltmp) \
3706. -			 (is_ammo(otmp) && (ltmp) && \
3707. -			 objects[(otmp)->otyp].oc_skill == -objects[(ltmp)->otyp].oc_skill)
3708. -#define is_missile(otmp)	((otmp->oclass == WEAPON_CLASS || \
3709. -			 otmp->oclass == TOOL_CLASS) && \
3710. -			 objects[otmp->otyp].oc_skill >= -P_BOOMERANG && \
3711. -			 objects[otmp->otyp].oc_skill <= -P_DART)
3712. +			 (is_ammo(otmp) && (ltmp) && is_launcher(ltmp) && \
3713. +			 ((objects[(otmp)->otyp].oc_wprop & WP_SUBTYPE) == \
3714. +			  (objects[(ltmp)->otyp].oc_wprop & WP_SUBTYPE) ))
3715. +#define is_missile(otmp)	(otmp->oclass == WEAPON_CLASS && \
3716. +			 (objects[otmp->otyp].oc_wprop & WP_THROWING) && \
3717. +			 (objects[otmp->otyp].oc_wprop & WP_CONSUMABLE) && \
3718. +			 (objects[otmp->otyp].oc_wprop & WP_WEAPONTYPE) == WP_NORMAL)
3719.  #define is_weptool(o)	((o)->oclass == TOOL_CLASS && \
3720.  			 objects[(o)->otyp].oc_skill != P_NONE)
3721.  #define bimanual(otmp)	((otmp->oclass == WEAPON_CLASS || \
3722.  			 otmp->oclass == TOOL_CLASS) && \
3723.  			 objects[otmp->otyp].oc_bimanual)
3724. -#define is_multigen(otmp)	(otmp->oclass == WEAPON_CLASS && \
3725. -			 objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
3726. -			 objects[otmp->otyp].oc_skill <= -P_BOW)
3727. +#define is_multigen(otmp)	(is_ammo(otmp) || is_missile(otmp))
3728.  #define is_poisonable(otmp)	(otmp->oclass == WEAPON_CLASS && \
3729. -			 objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \
3730. -			 objects[otmp->otyp].oc_skill <= -P_BOW)
3731. -#define uslinging()	(uwep && objects[uwep->otyp].oc_skill == P_SLING)
3732. +			(objects[otmp->otyp].oc_wprop & WP_POISONABLE))
3733. +#define is_consumable(otmp)	((otmp->oclass == WEAPON_CLASS || otmp->oclass == GEM_CLASS) && \
3734. +			(objects[otmp->otyp].oc_wprop & WP_CONSUMABLE))
3735. +#define is_ranged(otmp)	((otmp->oclass == WEAPON_CLASS || is_weptool(otmp)) && \
3736. +			 (objects[otmp->otyp].oc_wprop & WP_WEAPONTYPE) == WP_RANGED)
3737. +#define uslinging()	(uwep && uwep->oclass == WEAPON_CLASS && \
3738. +			(objects[uwep->otyp].oc_wprop & (WP_WEAPONTYPE|WP_SUBTYPE)) == (WP_LAUNCHER|WP_STONE))
3739. +#define is_hammer(otmp)	(otmp->oclass == WEAPON_CLASS && \
3740. +			 (objects[otmp->otyp].oc_skill == P_CRUSHING_GROUP || \
3741. +			  objects[otmp->otyp].oc_skill == P_FLAIL_GROUP || \
3742. +			  otmp->otyp == LUCERN_HAMMER || otmp->otyp == BEC_DE_CORBIN))
3743. +/* The amount added to the victim's total hit points to insure that the
3744. +   victim will be killed even after damage bonus/penalty adjustments.
3745. +   Most such penalties are small, and 200 is plenty; the exception is
3746. +   half physical damage.  3.3.1 and previous versions tried to use a very
3747. +   large number to account for this case; now, we just compute the fatal
3748. +   damage by adding it to 2 times the total hit points instead of 1 time.
3749. +   Note: this will still break if they have more than about half the number
3750. +   of hit points that will fit in a 15 bit integer. */
3751. +#define FATAL_DAMAGE_MODIFIER 200
3752.  
3753.  /* Armor */
3754.  #define is_shield(otmp) (otmp->oclass == ARMOR_CLASS && \
3755. @@ -185,6 +209,10 @@ struct obj {
3756.  			 objects[otmp->otyp].oc_armcat == ARM_SHIRT)
3757.  #define is_suit(otmp)	(otmp->oclass == ARMOR_CLASS && \
3758.  			 objects[otmp->otyp].oc_armcat == ARM_SUIT)
3759. +#define is_robe(otmp)	(otmp->oclass == ARMOR_CLASS && \
3760. +			 otmp->otyp >= ROBE && otmp->otyp <= ROBE_OF_WEAKNESS)
3761. +#define is_clothes(otmp) (otmp->oclass == ARMOR_CLASS && \
3762. +			  (get_material(otmp) == CLOTH || otmp->otyp == LEATHER_JACKET))
3763.  #define is_elven_armor(otmp)	((otmp)->otyp == ELVEN_LEATHER_HELM\
3764.  				|| (otmp)->otyp == ELVEN_MITHRIL_COAT\
3765.  				|| (otmp)->otyp == ELVEN_CLOAK\
3766. @@ -202,7 +230,9 @@ struct obj {
3767.  				|| (otmp)->otyp == DWARVISH_ROUNDSHIELD)
3768.  #define is_gnomish_armor(otmp)	(FALSE)
3769.  
3770. -				
3771. +#define WEP_ENCHANT_MAX  5
3772. +#define WEP_ENCHANT_WARN 3
3773. +
3774.  /* Eggs and other food */
3775.  #define MAX_EGG_HATCH_TIME 200	/* longest an egg can remain unhatched */
3776.  #define stale_egg(egg)	((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME))
3777. @@ -222,6 +252,8 @@ struct obj {
3778.  #define Is_mbag(otmp)	(otmp->otyp == BAG_OF_HOLDING || \
3779.  			 otmp->otyp == BAG_OF_TRICKS)
3780.  
3781. +#define Is_sokoprize(otmp)	((otmp)->sokoprize && !Is_box(otmp))
3782. +
3783.  /* dragon gear */
3784.  #define Is_dragon_scales(obj)	((obj)->otyp >= GRAY_DRAGON_SCALES && \
3785.  				 (obj)->otyp <= YELLOW_DRAGON_SCALES)
3786. @@ -260,9 +292,14 @@ struct obj {
3787.  /* Gnomish gear */
3788.  #define is_gnomish_obj(otmp)	(is_gnomish_armor(otmp))
3789.  
3790. +#define is_special_armor(obj)	(is_elven_armor(obj) || \
3791. +			(Role_if(PM_WIZARD) && (obj)->otyp == CORNUTHAUM))
3792. +
3793. +
3794.  /* Light sources */
3795.  #define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \
3796. -			 otmp->otyp == WAX_CANDLE)
3797. +			 otmp->otyp == WAX_CANDLE || \
3798. +			 otmp->otyp == MAGIC_CANDLE)
3799.  #define MAX_OIL_IN_FLASK 400	/* maximum amount of oil in a potion of oil */
3800.  
3801.  /* MAGIC_LAMP intentionally excluded below */
3802. @@ -289,10 +326,10 @@ struct obj {
3803.  
3804.  /* misc */
3805.  #ifdef KOPS
3806. -#define is_flimsy(otmp)		(objects[(otmp)->otyp].oc_material <= LEATHER || \
3807. +#define is_flimsy(otmp)		(get_material(otmp) <= LEATHER || \
3808.  				 (otmp)->otyp == RUBBER_HOSE)
3809.  #else
3810. -#define is_flimsy(otmp)		(objects[(otmp)->otyp].oc_material <= LEATHER)
3811. +#define is_flimsy(otmp)		(get_material(otmp) <= LEATHER) /* material patch */
3812.  #endif
3813.  
3814.  /* helpers, simple enough to be macros */

Among the changes to objects: support for the Sokoban prizes, the three items from which you may take only one; support for unusual materials for some objects. Also, some of the macros here have to be adjusted to work with the new skills system.

zap.c

30960.diff -pruN nethack-3.4.3/src/zap.c nhbrass-040923/src/zap.c
30961.--- nethack-3.4.3/src/zap.c	Sun Dec  7 18:39:13 2003
30962.+++ nhbrass-040923/src/zap.c	Sun Jun 13 13:37:04 2004
30963.@@ -48,7 +48,8 @@ STATIC_DCL int FDECL(spell_hit_bonus, (i
30964. #define ZT_LIGHTNING		(AD_ELEC-1)
30965. #define ZT_POISON_GAS		(AD_DRST-1)
30966. #define ZT_ACID			(AD_ACID-1)
30967.-/* 8 and 9 are currently unassigned */
30968.+#define ZT_PARALYSIS		(AD_PLYS-1)
30969.+/* 9 is currently unassigned */
30970. 
30971. #define ZT_WAND(x)		(x)
30972. #define ZT_SPELL(x)		(10+(x))
30973.@@ -93,7 +94,7 @@ const char * const flash_types[] = {	/* 
30974. 	"blast of lightning",
30975. 	"blast of poison gas",
30976. 	"blast of acid",
30977.-	"",
30978.+	"blast of paralysis gas",
30979. 	""
30980. };
30981. 
30982.@@ -259,7 +260,10 @@ struct obj *otmp;
30983. 		reveal_invis = TRUE;
30984. 	    if (mtmp->data != &mons[PM_PESTILENCE]) {
30985. 		wake = FALSE;		/* wakeup() makes the target angry */
30986.-		mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
30987.+		mtmp->mhp += d( 6+(Role_if(PM_HEALER) ? 1 : 0)+
30988.+				  ((flags.female && uarmh && uarmh->otyp == NURSE_CAP) ? 1 : 0)+
30989.+				  ((flags.female && uarm  && uarm->otyp  == NURSE_UNIFORM) ? 1 : 0),
30990.+				otyp == SPE_EXTRA_HEALING ? 8 : 4);
30991. 		if (mtmp->mhp > mtmp->mhpmax)
30992. 		    mtmp->mhp = mtmp->mhpmax;
30993. 		if (mtmp->mblinded) {
30994.@@ -354,7 +358,7 @@ struct obj *otmp;
30995. 	 */
30996. 	if (reveal_invis) {
30997. 	    if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) &&
30998.-							!canspotmon(mtmp))
30999.+							!canspotmons(mtmp))
31000. 		map_invisible(bhitpos.x, bhitpos.y);
31001. 	}
31002. 	return 0;
31003.@@ -674,7 +678,7 @@ register struct obj *obj;
31004. 		    }
31005. 		}
31006. 		if (mtmp) {
31007.-			if (obj->oeaten)
31008.+			if (obj->oclass == FOOD_CLASS && obj->oeaten)
31009. 				mtmp->mhp = eaten_stat(mtmp->mhp, obj);
31010. 			/* track that this monster was revived at least once */
31011. 			mtmp->mrevived = 1;
31012.@@ -822,6 +826,7 @@ register struct obj *obj;
31013. 		case RIN_GAIN_CONSTITUTION:
31014. 			if ((obj->owornmask & W_RING) && u_ring) {
31015. 				ABON(A_CON) -= obj->spe;
31016.+				recalchpmax();
31017. 				flags.botl = 1;
31018. 			}
31019. 			break;
31020.@@ -839,12 +844,16 @@ register struct obj *obj;
31021. 			if ((obj->owornmask & W_RING) && u_ring)
31022. 				u.udaminc -= obj->spe;
31023. 			break;
31024.-		case GAUNTLETS_OF_DEXTERITY:
31025.-			if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
31026.-				ABON(A_DEX) -= obj->spe;
31027.-				flags.botl = 1;
31028.-			}
31029.+		case RIN_PROTECTION:
31030.+			if ((obj->owornmask & W_RING) && u_ring)
31031.+				u.uprotection -= obj->spe;
31032. 			break;
31033.+//		case GAUNTLETS_OF_DEXTERITY:
31034.+//			if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
31035.+//				ABON(A_DEX) -= obj->spe;
31036.+//				flags.botl = 1;
31037.+//			}
31038.+//			break;
31039. 		case HELM_OF_BRILLIANCE:
31040. 			if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
31041. 				ABON(A_INT) -= obj->spe;
31042.@@ -938,6 +947,7 @@ register struct obj *obj;
31043. 	case RIN_GAIN_CONSTITUTION:
31044. 	    if ((obj->owornmask & W_RING) && u_ring) {
31045. 	    	ABON(A_CON)--;
31046.+		recalchpmax();
31047. 	    	flags.botl = 1;
31048. 	    }
31049. 	    break;
31050.@@ -1040,7 +1050,7 @@ polyuse(objhdr, mat, minwt)
31051. 	if (otmp->otyp == SCR_MAIL) continue;
31052. #endif
31053. 
31054.-	if (((int) objects[otmp->otyp].oc_material == mat) ==
31055.+	if (((int) get_material(otmp) == mat) ==
31056. 		(rn2(minwt + 1) != 0)) {
31057. 	    /* appropriately add damage to bill */
31058. 	    if (costly_spot(otmp->ox, otmp->oy)) {
31059.@@ -1161,7 +1171,7 @@ struct obj *obj;
31060. 	    /* some may metamorphosize */
31061. 	    for (i = obj->quan; i; i--)
31062. 		if (! rn2(Luck + 45)) {
31063.-		    poly_zapped = objects[obj->otyp].oc_material;
31064.+		    poly_zapped = get_material(obj);
31065. 		    break;
31066. 		}
31067. 	}
31068.@@ -1348,12 +1358,20 @@ poly_obj(obj, id)
31069. 
31070. 	case GEM_CLASS:
31071. 	    if (otmp->quan > (long) rnd(4) &&
31072.-		    objects[obj->otyp].oc_material == MINERAL &&
31073.-		    objects[otmp->otyp].oc_material != MINERAL) {
31074.+		    get_material(obj) == MINERAL &&
31075.+		    get_material(otmp) != MINERAL) {
31076. 		otmp->otyp = ROCK;	/* transmutation backfired */
31077. 		otmp->quan /= 2L;	/* some material has been lost */
31078. 	    }
31079. 	    break;
31080.+
31081.+	case FOOD_CLASS:
31082.+	    if (otmp->otyp == CORPSE) {
31083.+		otmp->age = monstermoves; /* if stone-to-freshed, make it fresh */
31084.+		start_corpse_timeout(otmp);
31085.+	    }
31086.+	    break;
31087.+
31088. 	}
31089. 
31090. 	/* update the weight */
31091.@@ -1603,8 +1621,8 @@ struct obj *obj, *otmp;
31092. 		break;
31093. 	case SPE_STONE_TO_FLESH:
31094. 		refresh_x = obj->ox; refresh_y = obj->oy;
31095.-		if (objects[obj->otyp].oc_material != MINERAL &&
31096.-			objects[obj->otyp].oc_material != GEMSTONE) {
31097.+		if (get_material(obj) != MINERAL &&
31098.+			get_material(obj) != GEMSTONE) {
31099. 		    res = 0;
31100. 		    break;
31101. 		}
31102.@@ -1734,6 +1752,9 @@ bhitpile(obj,fhito,tx,ty)
31103. 	/* Fix for polymorph bug, Tim Wright */
31104. 	next_obj = otmp->nexthere;
31105. 	hitanything += (*fhito)(otmp, obj);
31106.+#ifdef NOPOLYPILE
31107.+	if (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH) break;
31108.+#endif /*NOPOLYPILE*/
31109.     }
31110.     if(poly_zapped >= 0)
31111. 	create_polymon(level.objects[tx][ty], poly_zapped);
31112.@@ -1829,7 +1850,7 @@ dozap()
31113. 	int	damage;
31114. 
31115. 	if(check_capacity((char *)0)) return(0);
31116.-	obj = getobj(zap_syms, "zap");
31117.+	obj = getobj(zap_syms, "zap", 0);
31118. 	if(!obj) return(0);
31119. 
31120. 	check_unpaid(obj);
31121.@@ -1883,29 +1904,31 @@ boolean ordinary;
31122. 		case WAN_STRIKING:
31123. 		    makeknown(WAN_STRIKING);
31124. 		case SPE_FORCE_BOLT:
31125.-		    if(Antimagic) {
31126.-			shieldeff(u.ux, u.uy);
31127.-			pline("Boing!");
31128.-		    } else {
31129.+/* Striking/force bolt is now physical attack */
31130.+//		    if(Antimagic) {
31131.+//			shieldeff(u.ux, u.uy);
31132.+//			pline("Boing!");
31133.+//		    } else {
31134. 			if (ordinary) {
31135. 			    You("bash yourself!");
31136. 			    damage = d(2,12);
31137. 			} else
31138. 			    damage = d(1 + obj->spe,6);
31139. 			exercise(A_STR, FALSE);
31140.-		    }
31141.+//		    }
31142. 		    break;
31143. 
31144. 		case WAN_LIGHTNING:
31145. 		    makeknown(WAN_LIGHTNING);
31146.-		    if (!Shock_resistance) {
31147.-			You("shock yourself!");
31148.-			damage = d(12,6);
31149.-			exercise(A_CON, FALSE);
31150.-		    } else {
31151.+		    if (Shock_resistance && is_full_resist(SHOCK_RES)) {
31152. 			shieldeff(u.ux, u.uy);
31153. 			You("zap yourself, but seem unharmed.");
31154. 			ugolemeffects(AD_ELEC, d(12,6));
31155.+			break;
31156.+		    } else {
31157.+			You("shock yourself!");
31158.+			damage = d((Shock_resistance) ? 3: 12, 6);
31159.+			exercise(A_CON, FALSE);
31160. 		    }
31161. 		    destroy_item(WAND_CLASS, AD_ELEC);
31162. 		    destroy_item(RING_CLASS, AD_ELEC);
31163.@@ -1923,32 +1946,33 @@ boolean ordinary;
31164. 		case WAN_FIRE:
31165. 		    makeknown(WAN_FIRE);
31166. 		case FIRE_HORN:
31167.-		    if (Fire_resistance) {
31168.+		    if (Fire_resistance && is_full_resist(FIRE_RES)) {
31169. 			shieldeff(u.ux, u.uy);
31170. 			You_feel("rather warm.");
31171. 			ugolemeffects(AD_FIRE, d(12,6));
31172. 		    } else {
31173. 			pline("You've set yourself afire!");
31174.-			damage = d(12,6);
31175.+			damage = d((Fire_resistance) ? 3 : 12, 6);
31176. 		    }
31177. 		    burn_away_slime();
31178. 		    (void) burnarmor(&youmonst);
31179. 		    destroy_item(SCROLL_CLASS, AD_FIRE);
31180. 		    destroy_item(POTION_CLASS, AD_FIRE);
31181. 		    destroy_item(SPBOOK_CLASS, AD_FIRE);
31182.+		    destroy_item(TOOL_CLASS, AD_FIRE);
31183. 		    break;
31184. 
31185. 		case WAN_COLD:
31186. 		    makeknown(WAN_COLD);
31187. 		case SPE_CONE_OF_COLD:
31188. 		case FROST_HORN:
31189.-		    if (Cold_resistance) {
31190.+		    if (Cold_resistance && is_full_resist(COLD_RES)) {
31191. 			shieldeff(u.ux, u.uy);
31192. 			You_feel("a little chill.");
31193. 			ugolemeffects(AD_COLD, d(12,6));
31194. 		    } else {
31195. 			You("imitate a popsicle!");
31196.-			damage = d(12,6);
31197.+			damage = d((Cold_resistance) ? 3 : 12, 6);
31198. 		    }
31199. 		    destroy_item(POTION_CLASS, AD_COLD);
31200. 		    break;
31201.@@ -1959,6 +1983,7 @@ boolean ordinary;
31202. 		    if(Antimagic) {
31203. 			shieldeff(u.ux, u.uy);
31204. 			pline_The("missiles bounce!");
31205.+			damage_resistant_obj(ANTIMAGIC, 1);
31206. 		    } else {
31207. 			damage = d(4,6);
31208. 			pline("Idiot!  You've shot yourself!");
31209.@@ -1997,11 +2022,12 @@ boolean ordinary;
31210. 		        You_feel("rather itchy under your %s.", xname(uarmc));
31211. 		        break;
31212. 		    }
31213.-		    if (ordinary || !rn2(10)) {	/* permanent */
31214.-			HInvis |= FROMOUTSIDE;
31215.-		    } else {			/* temporary */
31216.+/* never get permanent invisibity by wand - youkan */
31217.+//		    if (ordinary || !rn2(10)) {	/* permanent */
31218.+//			HInvis |= FROMOUTSIDE;
31219.+//		    } else {			/* temporary */
31220. 		    	incr_itimeout(&HInvis, d(obj->spe, 250));
31221.-		    }
31222.+//		    }
31223. 		    if (msg) {
31224. 			makeknown(WAN_MAKE_INVISIBLE);
31225. 			newsym(u.ux, u.uy);
31226.@@ -2011,15 +2037,25 @@ boolean ordinary;
31227. 		}
31228. 
31229. 		case WAN_SPEED_MONSTER:
31230.-		    if (!(HFast & INTRINSIC)) {
31231.-			if (!Fast)
31232.-			    You("speed up.");
31233.-			else
31234.-			    Your("quickness feels more natural.");
31235.-			makeknown(WAN_SPEED_MONSTER);
31236.-			exercise(A_DEX, TRUE);
31237.+		    if (Very_fast) {
31238.+			Your("%s get new energy.",
31239.+				makeplural(body_part(LEG)));
31240.+			break;
31241. 		    }
31242.-		    HFast |= FROMOUTSIDE;
31243.+		    You("are suddenly moving %sfaster.",
31244.+				(Fast || BFast) ? "" : "much ");
31245.+		    u.uspdbon2 = 2;
31246.+		    incr_itimeout(&HFast, rn1(10, 10));
31247.+/* wand of speed monster no longer convey intrinsic speed */
31248.+//		    if (!(HFast & INTRINSIC)) {
31249.+//			if (!Fast)
31250.+//			    You("speed up.");
31251.+//			else
31252.+//			    Your("quickness feels more natural.");
31253.+//			makeknown(WAN_SPEED_MONSTER);
31254.+//			exercise(A_DEX, TRUE);
31255.+//		    }
31256.+//		    HFast |= FROMOUTSIDE;
31257. 		    break;
31258. 
31259. 		case WAN_SLEEP:
31260.@@ -2049,7 +2085,7 @@ boolean ordinary;
31261. 
31262. 		case WAN_DEATH:
31263. 		case SPE_FINGER_OF_DEATH:
31264.-		    if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
31265.+		    if (vs_death_factor(youmonst.data)) {
31266. 			pline((obj->otyp == WAN_DEATH) ?
31267. 			  "The wand shoots an apparently harmless beam at you."
31268. 			  : "You seem no deader than before.");
31269.@@ -2537,13 +2573,11 @@ int skill;
31270.     int hit_bon = 0;
31271.     int dex = ACURR(A_DEX);
31272. 
31273.-    switch (P_SKILL(spell_skilltype(skill))) {
31274.-	case P_ISRESTRICTED:
31275.-	case P_UNSKILLED:   hit_bon = -4; break;
31276.-	case P_BASIC:       hit_bon =  0; break;
31277.-	case P_SKILLED:     hit_bon =  2; break;
31278.-	case P_EXPERT:      hit_bon =  3; break;
31279.-    }
31280.+    schar hbon[11] = {
31281.+	   /*  0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% */
31282.+		-4, -2, -2, -1, -1,  0,  0, +1, +2, +2, +3
31283.+    };
31284.+    hit_bon = hbon[P_SKILL(spell_skilltype(skill))/10];
31285. 
31286.     if (dex < 4)
31287. 	hit_bon -= 3;
31288.@@ -2622,23 +2656,41 @@ int FDECL((*fhitm), (MONST_P, OBJ_P)),	/
31289.     FDECL((*fhito), (OBJ_P, OBJ_P));
31290. struct obj *obj;			/* object tossed/used */
31291. {
31292.-	struct monst *mtmp;
31293.-	uchar typ;
31294.-	boolean shopdoor = FALSE, point_blank = TRUE;
31295.+	register boolean shopdoor = FALSE;
31296.+	int sx, sy;
31297. 
31298. 	if (weapon == KICKED_WEAPON) {
31299. 	    /* object starts one square in front of player */
31300.-	    bhitpos.x = u.ux + ddx;
31301.-	    bhitpos.y = u.uy + ddy;
31302.+	    sx = u.ux + ddx;
31303.+	    sy = u.uy + ddy;
31304. 	    range--;
31305. 	} else {
31306.-	    bhitpos.x = u.ux;
31307.-	    bhitpos.y = u.uy;
31308.+	    sx = u.ux;
31309.+	    sy = u.uy;
31310. 	}
31311.+	return bhitcore(sx,sy, ddx, ddy, range, weapon, fhitm, fhito, obj, TRUE);
31312.+}
31313. 
31314.-	if (weapon == FLASHED_LIGHT) {
31315.+struct monst *
31316.+bhitcore(startx,starty, ddx,ddy, range, weapon, fhitm,fhito, obj, youshoot)
31317.+int startx, starty;			/* starting position */
31318.+int ddx,ddy,range;			/* direction and range */
31319.+int weapon;				/* see values in hack.h */
31320.+int FDECL((*fhitm), (MONST_P, OBJ_P)),	/* fns called when mon/obj hit (return value: ) */
31321.+    FDECL((*fhito), (OBJ_P, OBJ_P));	/* 	return value -- 0:keep going 1:stop */
31322.+struct obj *obj;			/* object tossed/used */
31323.+boolean youshoot;			/* TRUE:you shot it */
31324.+{
31325.+	struct monst *mtmp;
31326.+	uchar typ;
31327.+	boolean shopdoor = FALSE, point_blank = TRUE;
31328.+
31329.+	bhitpos.x = startx;
31330.+	bhitpos.y = starty;
31331.+
31332.+	if ((weapon & BHIT_GLYPHMASK) == BHIT_GLYPH_FLASH) {
31333. 	    tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
31334.-	} else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
31335.+	} else if ((weapon & BHIT_GLYPHMASK) == BHIT_GLYPH_OBJ)
31336. 	    tmp_at(DISP_FLASH, obj_to_glyph(obj));
31337. 
31338. 	while(range-- > 0) {
31339.@@ -2654,7 +2706,7 @@ struct obj *obj;			/* object tossed/used
31340. 		break;
31341. 	    }
31342. 
31343.-	    if(is_pick(obj) && inside_shop(x, y) &&
31344.+	    if(obj && is_pick(obj) && inside_shop(x, y) &&
31345. 					   (mtmp = shkcatch(obj, x, y))) {
31346. 		tmp_at(DISP_END, 0);
31347. 		return(mtmp);
31348.@@ -2663,8 +2715,8 @@ struct obj *obj;			/* object tossed/used
31349. 	    typ = levl[bhitpos.x][bhitpos.y].typ;
31350. 
31351. 	    /* iron bars will block anything big enough */
31352.-	    if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) &&
31353.-		    typ == IRONBARS &&
31354.+	    if ((weapon & BHIT_OBJTHROWN) /* physical flying or sliding object */
31355.+	    		 && typ == IRONBARS &&
31356. 		    hits_bars(&obj, x - ddx, y - ddy,
31357. 			      point_blank ? 0 : !rn2(5), 1)) {
31358. 		/* caveat: obj might now be null... */
31359.@@ -2673,7 +2725,8 @@ struct obj *obj;			/* object tossed/used
31360. 		break;
31361. 	    }
31362. 
31363.-	    if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y))
31364.+	    /* drawbridge handling */
31365.+	    if ((weapon & BHIT_ZAPPEDWAND) && find_drawbridge(&x,&y))
31366. 		switch (obj->otyp) {
31367. 		    case WAN_OPENING:
31368. 		    case SPE_KNOCK:
31369.@@ -2696,45 +2749,39 @@ struct obj *obj;			/* object tossed/used
31370. 			    destroy_drawbridge(x,y);
31371. 			makeknown(obj->otyp);
31372. 			break;
31373.+		    default:
31374.+			break;
31375. 		}
31376. 
31377.-	    if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
31378.+	    if (!youshoot && bhitpos.x==u.ux && bhitpos.y==u.uy)
31379.+		 mtmp = &youmonst;
31380.+	    else mtmp = m_at(bhitpos.x, bhitpos.y);
31381.+	    if (mtmp) {
31382.+#ifdef MONSTEED
31383.+		mtmp = mrider_or_msteed(mtmp, !rn2(3));
31384.+#endif
31385.+		/* hit a monster */
31386. 		notonhead = (bhitpos.x != mtmp->mx ||
31387. 			     bhitpos.y != mtmp->my);
31388.-		if (weapon != FLASHED_LIGHT) {
31389.-			if(weapon != ZAPPED_WAND) {
31390.-			    if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
31391.-			    if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) {
31392.-				if (weapon != INVIS_BEAM) {
31393.-				    map_invisible(bhitpos.x, bhitpos.y);
31394.-				    return(mtmp);
31395.-				}
31396.-			    } else
31397.-				return(mtmp);
31398.-			}
31399.-			if (weapon != INVIS_BEAM) {
31400.-			    (*fhitm)(mtmp, obj);
31401.-			    range -= 3;
31402.-			}
31403.-		} else {
31404.-		    /* FLASHED_LIGHT hitting invisible monster
31405.-		       should pass through instead of stop so
31406.-		       we call flash_hits_mon() directly rather
31407.-		       than returning mtmp back to caller. That
31408.-		       allows the flash to keep on going. Note
31409.-		       that we use mtmp->minvis not canspotmon()
31410.-		       because it makes no difference whether
31411.-		       the hero can see the monster or not.*/
31412.-		    if (mtmp->minvis) {
31413.-			obj->ox = u.ux,  obj->oy = u.uy;
31414.-			(void) flash_hits_mon(mtmp, obj);
31415.+		if (!((weapon & BHIT_PASSINVIS) && mtmp->minvis)) {
31416.+		    if (!fhitm) {
31417.+			/* no hitmon callback -- return the first monster hit */
31418.+			if ((weapon & BHIT_SENSEINVIS) &&
31419.+			    cansee(bhitpos.x,bhitpos.y) && !canspotmons(mtmp))
31420.+				map_invisible(bhitpos.x, bhitpos.y);
31421.+			if((weapon & BHIT_GLYPHMASK) != BHIT_GLYPH_NONE)
31422.+				tmp_at(DISP_END, 0);
31423.+			return(mtmp);
31424. 		    } else {
31425.-			tmp_at(DISP_END, 0);
31426.-		    	return(mtmp); 	/* caller will call flash_hits_mon */
31427.+			/* hitmon callback -- call fhitm for every monster to hit */
31428.+			if ((*fhitm)(mtmp, obj)) break; /* stopped: exit the loop */
31429.+			range -= 3;			/* keep going */
31430. 		    }
31431. 		}
31432.+
31433. 	    } else {
31434.-		if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING &&
31435.+		/* did not hit a monster */
31436.+		if ((weapon & BHIT_ZAPPEDWAND) && obj->otyp == WAN_PROBING &&
31437. 		   glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
31438. 		    unmap_object(bhitpos.x, bhitpos.y);
31439. 		    newsym(x, y);
31440.@@ -2743,7 +2790,13 @@ struct obj *obj;			/* object tossed/used
31441. 	    if(fhito) {
31442. 		if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
31443. 		    range--;
31444.+#ifdef NOPOLYPILE
31445.+		if ((weapon & BHIT_ZAPPEDWAND) &&
31446.+		    (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH))
31447.+		    range = 0;
31448.+#endif /*NOPOLYPILE*/
31449. 	    } else {
31450.+		/* hero tries to kick dropped gold out of the shop */
31451. 		if(weapon == KICKED_WEAPON &&
31452. 		      ((obj->oclass == COIN_CLASS &&
31453. 			 OBJ_AT(bhitpos.x, bhitpos.y)) ||
31454.@@ -2753,7 +2806,9 @@ struct obj *obj;			/* object tossed/used
31455. 			return (struct monst *)0;
31456. 		}
31457. 	    }
31458.-	    if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
31459.+
31460.+	    /* door handling(open/close/crash etc.) */
31461.+	    if((weapon & BHIT_ZAPPEDWAND) && (IS_DOOR(typ) || typ == SDOOR)) {
31462. 		switch (obj->otyp) {
31463. 		case WAN_OPENING:
31464. 		case WAN_LOCKING:
31465.@@ -2768,39 +2823,46 @@ struct obj *obj;			/* object tossed/used
31466. 			if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
31467. 			    && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
31468. 			    shopdoor = TRUE;
31469.-			    add_damage(bhitpos.x, bhitpos.y, 400L);
31470.+			    add_damage(bhitpos.x, bhitpos.y, youshoot ? 400L : 0L);
31471. 			}
31472. 		    }
31473. 		    break;
31474.+		default:
31475.+		    break;
31476. 		}
31477. 	    }
31478.+
31479.+	    /* blocked by door */
31480. 	    if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
31481. 		bhitpos.x -= ddx;
31482. 		bhitpos.y -= ddy;
31483. 		break;
31484. 	    }
31485.-	    if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
31486.-		/* 'I' present but no monster: erase */
31487.-		/* do this before the tmp_at() */
31488.-		if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
31489.-			&& cansee(x, y)) {
31490.-		    unmap_object(bhitpos.x, bhitpos.y);
31491.-		    newsym(x, y);
31492.-		}
31493.+	    /* 'I' present but no monster: erase */
31494.+	    /* do this before the tmp_at() */
31495.+	    if (!(weapon & BHIT_PASSINVIS) &&
31496.+		glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) &&
31497.+		cansee(x, y)) {
31498.+		unmap_object(bhitpos.x, bhitpos.y);
31499.+		newsym(x, y);
31500.+	    }
31501.+	    /* show the symbol flying */
31502.+	    if((weapon & BHIT_GLYPHMASK) != BHIT_GLYPH_NONE) {
31503. 		tmp_at(bhitpos.x, bhitpos.y);
31504. 		delay_output();
31505.-		/* kicked objects fall in pools */
31506.-		if((weapon == KICKED_WEAPON) &&
31507.-		   (is_pool(bhitpos.x, bhitpos.y) ||
31508.-		   is_lava(bhitpos.x, bhitpos.y)))
31509.+	    }
31510.+	    /* kicked objects fall in pools */
31511.+	    if((weapon & BHIT_FALLTOPOOL) &&
31512.+	       (is_pool(bhitpos.x, bhitpos.y) ||
31513.+		is_lava(bhitpos.x, bhitpos.y)))
31514. 		    break;
31515. #ifdef SINKS
31516.-		if(IS_SINK(typ) && weapon != FLASHED_LIGHT)
31517.-		    break;	/* physical objects fall onto sink */
31518.+	    /* physical objects fall onto sink */
31519.+	    if(IS_SINK(typ) && (weapon & BHIT_STOPATSINK))
31520.+		break;
31521. #endif
31522.-	    }
31523. 	    /* limit range of ball so hero won't make an invalid move */
31524.-	    if (weapon == THROWN_WEAPON && range > 0 &&
31525.+	    if ((weapon & BHIT_OBJTHROWN) && range > 0 &&
31526. 		obj->otyp == HEAVY_IRON_BALL) {
31527. 		struct obj *bobj;
31528. 		struct trap *t;
31529.@@ -2829,9 +2891,9 @@ struct obj *obj;			/* object tossed/used
31530. 	    point_blank = FALSE;	/* affects passing through iron bars */
31531. 	}
31532. 
31533.-	if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
31534.+	if ((weapon & BHIT_GLYPHMASK) != BHIT_GLYPH_NONE) tmp_at(DISP_END, 0);
31535. 
31536.-	if(shopdoor)
31537.+	if(shopdoor && youshoot)
31538. 	    pay_for_damage("destroy", FALSE);
31539. 
31540. 	return (struct monst *)0;
31541.@@ -2962,6 +3024,15 @@ struct obj **ootmp;	/* to return worn ar
31542. 		(void)sleep_monst(mon, d(nd, 25),
31543. 				type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
31544. 		break;
31545.+	case ZT_PARALYSIS:
31546.+		tmp = 0;
31547.+		if (resists_paraly(mon)) {
31548.+		    sho_shieldeff = TRUE;
31549.+		    break;
31550.+		}
31551.+		mon->mcanmove = 0;
31552.+		mon->mfrozen = d(nd, 6);
31553.+		break;
31554. 	case ZT_DEATH:		/* death/disintegration */
31555. 		if(abs(type) != ZT_BREATH(ZT_DEATH)) {	/* death */
31556. 		    if(mon->data == &mons[PM_DEATH]) {
31557.@@ -2972,8 +3043,8 @@ struct obj **ootmp;	/* to return worn ar
31558. 			tmp = 0;
31559. 			break;
31560. 		    }
31561.-		    if (nonliving(mon->data) || is_demon(mon->data) ||
31562.-			    resists_magm(mon)) {	/* similar to player */
31563.+		    if (vs_death_factor(mon->data) ||
31564.+			resists_magm(mon)) {	/* similar to player */
31565. 			sho_shieldeff = TRUE;
31566. 			break;
31567. 		    }
31568.@@ -3071,41 +3142,55 @@ const char *fltxt;
31569. xchar sx, sy;
31570. {
31571. 	int dam = 0;
31572.+	boolean not_effected = FALSE;
31573. 
31574. 	switch (abs(type) % 10) {
31575. 	case ZT_MAGIC_MISSILE:
31576. 	    if (Antimagic) {
31577. 		shieldeff(sx, sy);
31578. 		pline_The("missiles bounce off!");
31579.+		damage_resistant_obj(ANTIMAGIC, 1);
31580. 	    } else {
31581. 		dam = d(nd,6);
31582. 		exercise(A_STR, FALSE);
31583. 	    }
31584. 	    break;
31585. 	case ZT_FIRE:
31586.+	    dam = d(nd, 6);
31587. 	    if (Fire_resistance) {
31588.-		shieldeff(sx, sy);
31589.-		You("don't feel hot!");
31590.+		if (not_effected = is_full_resist(FIRE_RES)) {
31591.+		    shieldeff(sx, sy);
31592.+		    You("don't feel hot!");
31593.+		    dam = 0;
31594.+		} else {
31595.+		    You("endure the heat.");
31596.+		    dam = (dam+3) / 4;
31597.+		}
31598. 		ugolemeffects(AD_FIRE, d(nd, 6));
31599.-	    } else {
31600.-		dam = d(nd, 6);
31601. 	    }
31602. 	    burn_away_slime();
31603.-	    if (burnarmor(&youmonst)) {	/* "body hit" */
31604.+	    if (!not_effected && burnarmor(&youmonst)) {	/* "body hit" */
31605. 		if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE);
31606. 		if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE);
31607. 		if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE);
31608.+		if (!rn2(3)) destroy_item(TOOL_CLASS, AD_FIRE);
31609. 	    }
31610. 	    break;
31611. 	case ZT_COLD:
31612.+	    dam = d(nd, 6);
31613. 	    if (Cold_resistance) {
31614.-		shieldeff(sx, sy);
31615.-		You("don't feel cold.");
31616.+		if (not_effected = is_full_resist(COLD_RES)) {
31617.+		    shieldeff(sx, sy);
31618.+		    You("don't feel cold.");
31619.+		    dam = 0;
31620.+		} else {
31621.+		    You("feel slightly cold.");
31622.+		    dam = (dam+3) / 4;
31623.+		}
31624. 		ugolemeffects(AD_COLD, d(nd, 6));
31625.-	    } else {
31626.-		dam = d(nd, 6);
31627. 	    }
31628.-	    if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD);
31629.+	    if (!not_effected && !rn2(3))
31630.+		destroy_item(POTION_CLASS, AD_COLD);
31631. 	    break;
31632. 	case ZT_SLEEP:
31633. 	    if (Sleep_resistance) {
31634.@@ -3115,10 +3200,22 @@ xchar sx, sy;
31635. 		fall_asleep(-d(nd,25), TRUE); /* sleep ray */
31636. 	    }
31637. 	    break;
31638.+	case ZT_PARALYSIS:
31639.+	    if (Free_action) {
31640.+		shieldeff(u.ux, u.uy);
31641.+		You("stiffen momentarily.");
31642.+	    } else {
31643.+		You("are frozen!");
31644.+		nomul(-d(nd, 4));
31645.+		nomovemsg = You_can_move_again;
31646.+		exercise(A_DEX, FALSE);
31647.+	    }
31648.+	    break;
31649. 	case ZT_DEATH:
31650. 	    if (abs(type) == ZT_BREATH(ZT_DEATH)) {
31651.-		if (Disint_resistance) {
31652.-		    You("are not disintegrated.");
31653.+		if (is_full_resist(DISINT_RES)) {
31654.+		    shieldeff(sx, sy);
31655.+		    You("aren't affected.");
31656. 		    break;
31657. 		} else if (uarms) {
31658. 		    /* destroy shield; other possessions are safe */
31659.@@ -3136,13 +3233,18 @@ xchar sx, sy;
31660. #ifdef TOURIST
31661. 		if (uarmu) (void) destroy_arm(uarmu);
31662. #endif
31663.-	    } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
31664.+		if (Disint_resistance) {
31665.+		    You("are not disintegrated.");
31666.+		    break;
31667.+		}
31668.+	    } else if (vs_death_factor(youmonst.data)) {
31669. 		shieldeff(sx, sy);
31670. 		You("seem unaffected.");
31671. 		break;
31672. 	    } else if (Antimagic) {
31673. 		shieldeff(sx, sy);
31674. 		You("aren't affected.");
31675.+		damage_resistant_obj(ANTIMAGIC, rnd(3));
31676. 		break;
31677. 	    }
31678. 	    killer_format = KILLED_BY_AN;
31679.@@ -3152,19 +3254,30 @@ xchar sx, sy;
31680. 	    done(DIED);
31681. 	    return; /* lifesaved */
31682. 	case ZT_LIGHTNING:
31683.+	    dam = d(nd, 6);
31684. 	    if (Shock_resistance) {
31685.-		shieldeff(sx, sy);
31686.-		You("aren't affected.");
31687.+		if (not_effected = is_full_resist(SHOCK_RES)) {
31688.+		    shieldeff(sx, sy);
31689.+		    You("aren't affected.");
31690.+		    dam = 0;
31691.+		} else {
31692.+		    You("nearly resist the shock.");
31693.+		    dam = (dam+3) / 4;
31694.+		}
31695. 		ugolemeffects(AD_ELEC, d(nd, 6));
31696. 	    } else {
31697.-		dam = d(nd, 6);
31698. 		exercise(A_CON, FALSE);
31699. 	    }
31700.-	    if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
31701.-	    if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
31702.+	    if (!not_effected) {
31703.+		if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
31704.+		if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
31705.+	    }
31706. 	    break;
31707. 	case ZT_POISON_GAS:
31708. 	    poisoned("blast", A_DEX, "poisoned blast", 15);
31709.+	    if (!is_full_resist(POISON_RES)) {
31710.+		if (!rn2(3)) hurtarmor(AD_DCAY);
31711.+	    }
31712. 	    break;
31713. 	case ZT_ACID:
31714. 	    if (Acid_resistance) {
31715.@@ -3174,10 +3287,12 @@ xchar sx, sy;
31716. 		dam = d(nd,6);
31717. 		exercise(A_STR, FALSE);
31718. 	    }
31719.-	    /* using two weapons at once makes both of them more vulnerable */
31720.-	    if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE);
31721.-	    if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE);
31722.-	    if (!rn2(6)) erode_armor(&youmonst, TRUE);
31723.+	    if (!is_full_resist(ACID_RES)) {
31724.+		/* using two weapons at once makes both of them more vulnerable */
31725.+		if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE);
31726.+		if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE);
31727.+		if (!rn2(6)) erode_armor(&youmonst, TRUE);
31728.+	    }
31729. 	    break;
31730. 	}
31731. 
31732.@@ -3239,6 +3354,19 @@ boolean u_caused;
31733. 			    pline("%s burns.", An(buf1));
31734. 		    }
31735. 		}
31736.+	    } else if (obj->otyp == STATUE && get_material(obj) == LIQUID) {
31737.+		struct trap *trap;
31738.+		if ((trap = t_at(x,y)) && trap->ttyp == STATUE_TRAP) {
31739.+		    activate_statue_trap(trap, x, y, TRUE);
31740.+		    continue;
31741.+		}
31742.+		if (give_feedback) {
31743.+		    pline("%s thaws.", An(xname(obj)));
31744.+		}
31745.+		(void) mkcorpstat(CORPSE, (struct monst *) 0,
31746.+				  &mons[obj->corpsenm], x, y, TRUE);
31747.+		if (u_caused) useupf(obj, 1);
31748.+		else delobj(obj);
31749. 	    }
31750. 	}
31751. 	return cnt;
31752.@@ -3317,7 +3445,7 @@ register int dx,dy;
31753. 	    mon = m_at(sx, sy);
31754. 	    if(cansee(sx,sy)) {
31755. 		/* reveal/unreveal invisible monsters before tmp_at() */
31756.-		if (mon && !canspotmon(mon))
31757.+		if (mon && !canspotmons(mon))
31758. 		    map_invisible(sx, sy);
31759. 		else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
31760. 		    unmap_object(sx, sy);
31761.@@ -3327,6 +3455,9 @@ register int dx,dy;
31762. 		    tmp_at(sx,sy);
31763. 		delay_output(); /* wait a little */
31764. 	    }
31765.+#ifdef MONSTEED
31766.+	    if (mon) mon = mrider_or_msteed(mon, !rn2(3));
31767.+#endif
31768. 	} else
31769. 	    goto make_bounce;
31770. 
31771.@@ -3447,6 +3578,7 @@ register int dx,dy;
31772. 		range -= 2;
31773. 		pline("%s hits you!", The(fltxt));
31774. 		if (Reflecting) {
31775.+		    int objdmg = 0;
31776. 		    if (!Blind) {
31777. 		    	(void) ureflects("But %s reflects from your %s!", "it");
31778. 		    } else
31779.@@ -3454,13 +3586,35 @@ register int dx,dy;
31780. 		    dx = -dx;
31781. 		    dy = -dy;
31782. 		    shieldeff(sx, sy);
31783.+		    switch (abstype) {		/* reflector gets damaged */
31784.+			case ZT_MAGIC_MISSILE:
31785.+			case ZT_SLEEP:
31786.+			case ZT_POISON_GAS:
31787.+			case ZT_PARALYSIS:
31788.+				objdmg = d(1,4);
31789.+				break;
31790.+			case ZT_FIRE:
31791.+			case ZT_COLD:
31792.+			case ZT_LIGHTNING:
31793.+			case ZT_ACID:
31794.+				objdmg = d(2,4);
31795.+			case ZT_DEATH:
31796.+				if (abs(type) == ZT_BREATH(ZT_DEATH))
31797.+				    objdmg = rn1(10, 10);
31798.+				else
31799.+				    objdmg = d(3,4);
31800.+			default:
31801.+				break;
31802.+		    }
31803.+		    damage_resistant_obj(REFLECTING, objdmg);
31804. 		} else {
31805. 		    zhitu(type, nd, fltxt, sx, sy);
31806. 		}
31807. 	    } else {
31808. 		pline("%s whizzes by you!", The(fltxt));
31809. 	    }
31810.-	    if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) {
31811.+	    if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst) &&
31812.+		!is_full_resist(SHOCK_RES)) {
31813. 		You(are_blinded_by_the_flash);
31814. 		make_blinded((long)d(nd,50),FALSE);
31815. 		if (!Blind) Your(vision_clears);
31816.@@ -3584,7 +3738,7 @@ boolean *shopdamage;
31817. 	    }
31818. 	    if(is_ice(x, y)) {
31819. 		melt_ice(x, y);
31820.-	    } else if(is_pool(x,y)) {
31821.+	    } else if(is_pool(x,y) || is_swamp(x,y)) {
31822. 		const char *msgtxt = "You hear hissing gas.";
31823. 		if(lev->typ != POOL) {	/* MOAT or DRAWBRIDGE_UP */
31824. 		    if (cansee(x,y)) msgtxt = "Some water evaporates.";
31825.@@ -3767,13 +3921,7 @@ register struct obj *obj;		   /* no text
31826. 	if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving)
31827. 	    change_luck(-1);
31828. 
31829.-	obj->otyp = ROCK;
31830.-	obj->quan = (long) rn1(60, 7);
31831.-	obj->owt = weight(obj);
31832.-	obj->oclass = GEM_CLASS;
31833.-	obj->known = FALSE;
31834.-	obj->onamelth = 0;		/* no names */
31835.-	obj->oxlth = 0;			/* no extra data */
31836.+	trans_to_rock(obj);
31837. 	obj->oattached = OATTACHED_NOTHING;
31838. 	if (obj->where == OBJ_FLOOR) {
31839. 		obj_extract_self(obj);		/* move rocks back on top */
31840.@@ -3785,6 +3933,20 @@ register struct obj *obj;		   /* no text
31841. 	}
31842. }
31843. 
31844.+void
31845.+trans_to_rock(obj)
31846.+register struct obj *obj;
31847.+{
31848.+	obj->otyp = (get_material(obj) == MINERAL) ? ROCK : LAST_GEM + 1;
31849.+	obj->quan = (long) rn1(60, 7);
31850.+	obj->owt = weight(obj);
31851.+	obj->oclass = GEM_CLASS;
31852.+	obj->known = FALSE;
31853.+	obj->bknown = FALSE;
31854.+	obj->onamelth = 0;		/* no names */
31855.+	obj->oxlth = 0;			/* no extra data */
31856.+}
31857.+
31858. /* handle statue hit by striking/force bolt/pick-axe */
31859. boolean
31860. break_statue(obj)
31861.@@ -3793,7 +3955,10 @@ register struct obj *obj;
31862. 	/* [obj is assumed to be on floor, so no get_obj_location() needed] */
31863. 	struct trap *trap = t_at(obj->ox, obj->oy);
31864. 	struct obj *item;
31865.+	int mat = get_material(obj);
31866. 
31867.+	if (mat != MINERAL && mat != GLASS) return FALSE;	/* do not shatter */
31868.+
31869. 	if (trap && trap->ttyp == STATUE_TRAP &&
31870. 		activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
31871. 	    return FALSE;
31872.@@ -3830,6 +3995,10 @@ register int osym, dmgtyp;
31873. 	register int dindx;
31874. 	const char *mult;
31875. 
31876.+	if (dmgtyp == AD_FIRE && is_full_resist(FIRE_RES)) return;
31877.+	if (dmgtyp == AD_COLD && is_full_resist(COLD_RES)) return;
31878.+	if (dmgtyp == AD_ELEC && is_full_resist(SHOCK_RES)) return;
31879.+
31880. 	for(obj = invent; obj; obj = obj2) {
31881. 	    obj2 = obj->nobj;
31882. 	    if(obj->oclass != osym) continue; /* test only objs of type osym */
31883.@@ -3873,6 +4042,20 @@ register int osym, dmgtyp;
31884. 			    dindx = 3;
31885. 			    dmg = 1;
31886. 			    break;
31887.+			case TOOL_CLASS:
31888.+			    if (get_material(obj) == CLOTH) {
31889.+				dindx = 3;
31890.+				dmg = 0;
31891.+				if (!objects[obj->otyp].oc_merge &&
31892.+				    obj->oeroded < MAX_ERODE) {
31893.+				    skip++;
31894.+				    if (!rn2(3+(obj->blessed*2))) {
31895.+					obj->oeroded++;
31896.+					pline("Your %s catches fire and smoulders!", xname(obj));
31897.+				    }
31898.+				}
31899.+			    } else skip++;
31900.+			    break;
31901. 			default:
31902. 			    skip++;
31903. 			    break;
31904.@@ -3927,6 +4110,25 @@ register int osym, dmgtyp;
31905. 			setnotworn(obj);
31906. 		}
31907. 		if (obj == current_wand) current_wand = 0;	/* destroyed */
31908.+		if (Is_container(obj) && Has_contents(obj)) {
31909.+		    struct obj *otmp;
31910.+		    long ccnt;
31911.+		    schar typ = levl[u.ux][u.uy].typ;
31912.+		    for (ccnt = 0, otmp = obj->cobj; otmp; otmp = otmp->nobj)
31913.+			ccnt += otmp->quan;
31914.+		    if (ccnt) pline_The("content%s of %s fall%s %sto the %s!",
31915.+					(ccnt > 1) ? "s" : "", the(xname(obj)),
31916.+					(ccnt == 1) ? "s" : "",
31917.+					(IS_SOFT(typ) || IS_FOUNTAIN(typ) ||
31918.+					 typ == LAVAPOOL) ? "in" : "",
31919.+					surface(u.ux, u.uy));
31920.+		    while (obj->cobj) {
31921.+			otmp = obj->cobj;
31922.+			obj_extract_self(otmp);
31923.+			place_object(otmp, u.ux, u.uy);
31924.+			stackobj(otmp);
31925.+		    }
31926.+		}
31927. 		for (i = 0; i < cnt; i++)
31928. 		    useup(obj);
31929. 		if(dmg) {
31930.@@ -3945,6 +4147,29 @@ register int osym, dmgtyp;
31931. 	return;
31932. }
31933. 
31934.+void
31935.+destroy_items(dmgtyp)
31936.+register int dmgtyp;
31937.+{
31938.+	switch (dmgtyp) {
31939.+	    case AD_FIRE:
31940.+		destroy_item(SCROLL_CLASS, AD_FIRE);
31941.+		destroy_item(POTION_CLASS, AD_FIRE);
31942.+		if (rn2(5) < 3) destroy_item(SPBOOK_CLASS, AD_FIRE);
31943.+		destroy_item(TOOL_CLASS, AD_FIRE);
31944.+		break;
31945.+	    case AD_COLD:
31946.+		destroy_item(POTION_CLASS, AD_COLD);
31947.+		break;
31948.+	    case AD_ELEC:
31949.+		destroy_item(WAND_CLASS, AD_ELEC);
31950.+		destroy_item(RING_CLASS, AD_ELEC);
31951.+		break;
31952.+	    default:
31953.+		break;
31954.+	}
31955.+}
31956.+
31957. int
31958. destroy_mitem(mtmp, osym, dmgtyp)
31959. struct monst *mtmp;
31960.@@ -4142,5 +4367,169 @@ retry:
31961. }
31962. 
31963. #endif /*OVL2*/
31964.+
31965.+
31966.+
31967.+
31968.+struct resiobj {
31969.+	long	mask;
31970.+	struct obj **objp;
31971.+	uchar	objclass;
31972.+	uchar	objsubc;
31973.+};
31974.+
31975.+const struct resiobj resiobjtbl[] = {
31976.+	/* reversed order */
31977.+	{ W_ARMF,    &uarmf,	ARMOR_CLASS,  ARM_BOOTS  },
31978.+	{ W_ARMG,    &uarmg,	ARMOR_CLASS,  ARM_GLOVES },
31979.+	{ W_ARMH,    &uarmh,	ARMOR_CLASS,  ARM_HELM   },
31980.+	{ W_ARM,     &uarm,	ARMOR_CLASS,  ARM_SUIT   },
31981.+//	{ W_SWAPWEP, &uswapwep,	WEAPON_CLASS, 2          },
31982.+	{ W_WEP,     &uwep,	WEAPON_CLASS, 1          },
31983.+	{ W_ARMC,    &uarmc,	ARMOR_CLASS,  ARM_CLOAK  },
31984.+	{ W_ARMS,    &uarms,	ARMOR_CLASS,  ARM_SHIELD },
31985.+	{ W_RINGR,   &uright,	RING_CLASS,   2          },
31986.+	{ W_RINGL,   &uleft,	RING_CLASS,   1          },
31987.+	{ W_AMUL,    &uamul,	AMULET_CLASS, 0          },
31988.+	{ 0, 0, 0, 0 }
31989.+};
31990.+
31991.+void
31992.+damage_resistant_obj(prop, damval)
31993.+uchar prop;
31994.+int damval;
31995.+{
31996.+	long e = u.uprops[prop].extrinsic;
31997.+	int oc1 = 0, oc2 = 0;
31998.+	int oldtmp, newtmp = 0;
31999.+	const struct resiobj *tbl;
32000.+	struct obj *otmp;
32001.+
32002.+	if (e & (W_ART|W_ARTI)) return;	/* artifacts */
32003.+
32004.+	for ( tbl = resiobjtbl; tbl->mask; tbl++ ) {
32005.+		if ( e & tbl->mask ) {
32006.+			/* artifacts do not get damaged */
32007.+			if ((*(tbl->objp))->oartifact) return;
32008.+			oc1 = tbl->objclass;
32009.+			oc2 = tbl->objsubc;
32010.+			break;
32011.+		}
32012.+	}
32013.+	if ( !oc1 ) return;	/* there is no object to get damaged */
32014.+	if ( oc1 == WEAPON_CLASS && oc2 == 2 && !u.twoweap ) return;	/* do not count unwield weapon */
32015.+
32016.+	switch (oc1) {
32017.+	    case AMULET_CLASS:
32018.+		if (prop != ANTIMAGIC && prop != REFLECTING ) break;
32019.+		if (uamul) {
32020.+			if (uamul->oartifact) break;
32021.+			oldtmp = uamul->odamaged;
32022.+			newtmp = oldtmp + damval;
32023.+			if ( newtmp>100 ) {
32024.+				if (Blind) You_feel("your medallion breaks in pieces!");
32025.+				else Your("medallion glows brightly, and breaks in pieces!");
32026.+				otmp = uamul;
32027.+				Amulet_off();
32028.+				useup(otmp);
32029.+				break;
32030.+			} else if ( /*oldtmp<90 &&*/ newtmp>=90 )
32031.+				if (!Blind) Your("medallion gives a faint glimmer of light!");
32032.+				else Your("medallion vibrates violently!");
32033.+			else if ( oldtmp<75 && newtmp>=75 )
32034.+				Your("medallion vibrates unexpectedly.");
32035.+			uamul->odamaged = newtmp;
32036.+		}
32037.+		break;
32038.+	    case ARMOR_CLASS:
32039.+		switch (oc2) {
32040.+		    case ARM_CLOAK:
32041.+			if (uarmc) {
32042.+				if (uarmc->oartifact) break;
32043.+				oldtmp = uarmc->odamaged;
32044.+				newtmp = oldtmp + damval;
32045.+				if ( newtmp>100 ) {
32046.+					if (Blind)
32047.+					    You_feel("your %s is gone away!", cloak_simple_name(uarmc));
32048.+					else
32049.+					    Your("%s crumbles and turns to dust!", cloak_simple_name(uarmc));
32050.+					otmp = uarmc;
32051.+	       				(void) Cloak_off();
32052.+					useup(otmp);
32053.+					break;
32054.+				} else if ( /*oldtmp<90 &&*/ newtmp>=90 )
32055.+					Your("%s is about to come apart!", cloak_simple_name(uarmc));
32056.+				else if ( oldtmp<75 && newtmp>=75 )
32057.+					Your("%s becomes slightly shabby.", cloak_simple_name(uarmc));
32058.+				uarmc->odamaged = newtmp;
32059.+			}
32060.+			break;
32061.+		    case ARM_SHIELD:
32062.+			if (uarms && uarms->oartifact) break;
32063.+			if (uarms && prop == REFLECTING) {	/* shield of reflection */
32064.+				oldtmp = uarms->odamaged;
32065.+				newtmp = oldtmp + damval;
32066.+				if ( newtmp>100 ) {
32067.+					if (!Blind) Your("shield is completely tarnished.");
32068.+					else You_feel("your shield is somewhat helpless.");
32069.+					otmp = uarms;
32070.+					Shield_off();
32071.+					otmp->otyp = SHIELD;
32072.+					otmp->odamaged = 0;
32073.+					change_material(otmp, SILVER);	/* mere silver shield */
32074.+					setworn(otmp, W_ARMS);
32075.+					break;
32076.+				} else if ( /*oldtmp<90 &&*/ newtmp>=90 ) {
32077.+				    if (!Blind) Your("shield looks much duller!");
32078.+				    else Your("shield shivers!");
32079.+				} else if ( oldtmp<75 && newtmp>=75 ) {
32080.+				    if (!Blind) Your("shield looks slightly dull.");
32081.+				    else Your("shield shivers slightly.");
32082.+				}
32083.+				uarms->odamaged = newtmp;
32084.+			}
32085.+			break;
32086.+		    case ARM_SUIT:
32087.+			if (uarm && uarm->oartifact) break;
32088.+			if (prop != ANTIMAGIC && prop != REFLECTING ) break;
32089.+			if (uarm && Is_dragon_armor(uarm)) {	/* gray or silver dragon */
32090.+				char buf[BUFSZ];
32091.+				int isdm = Is_dragon_mail(uarm);
32092.+				oldtmp = uarm->odamaged;
32093.+				newtmp = oldtmp + damval;
32094.+				Sprintf(buf, "dragon scale%s", isdm ? " mail" : "s");
32095.+				if ( newtmp>100 ) {
32096.+				    if (isdm) {
32097.+					Your("%s seems to lose its power.", buf);
32098.+					otmp = uarm;
32099.+					Armor_off();
32100.+					otmp->otyp = PLAIN_DRAGON_SCALE_MAIL;	/* mere scale mail */
32101.+					otmp->odamaged = 0;
32102.+					setworn(otmp, W_ARM);
32103.+				    } else {
32104.+					Your("%s crumble and fall apart!", buf);
32105.+					otmp = uarm;
32106.+					Armor_off();
32107.+					useup(otmp);
32108.+				    }
32109.+				    break;
32110.+				} else if ( /*oldtmp<90 &&*/ newtmp>=90 )
32111.+				    Your("%s shiver%s!", buf, isdm ? "s" : "");
32112.+				else if ( oldtmp<75 && newtmp>=75 )
32113.+				    Your("%s shiver%s slightly.", buf, isdm ? "s" : "");
32114.+				uarm->odamaged = newtmp;
32115.+			}
32116.+			break;
32117.+		    default:
32118.+			break;
32119.+		}
32120.+		break;
32121.+	    default:
32122.+		/*impossible("Damage to strange object???")*/;
32123.+	}
32124.+	if (wizard) pline("[%d%]", newtmp);
32125.+	return;
32126.+}
32127.+
32128. 
32129. /*zap.c*/

You may want to give your attention to the above code that controls gradual wear to items that provide magic resistance or reflection. The damage_resistant_obj function applies damage to an object. As the object resists magic or reflects ray, its damage points will increase.

Note in line 32006 that artifacts are immune to damage.