If you apply multiple patches to your copy of Nethack, odds are some
will conflict and you'll have to apply them by hand.  This patch tries
to improve this situation.  Simply put, the idea is to make it so that
patches don't conflict by forcing their context lines not to contain
conflicting data.  This is meant to be used by patch authors.  For the
full story see the included README.patchable.

Bones/save compatibility:  This patch doesn't affect saved games or bones
files.

This patch is available at http://www.argon.org/~roderick/nethack/.

Roderick Schertler <roderick@argon.org>


diff -r -X /home/roderick/.diff-exclude -uN base.dist/README.patchable work.patchable/README.patchable
--- base.dist/README.patchable	1969-12-31 19:00:00.000000000 -0500
+++ work.patchable/README.patchable	2003-03-20 22:24:17.000000000 -0500
@@ -0,0 +1,165 @@
+Patchable Nethack
+------------------------------------------------------------------------------
+
+There are a number of lists in the Nethack source code which are
+commonly updated by patches.  If you apply 2 patches which both add an
+item to the same list, the second won't apply cleanly and you'll have to
+add its item to the list by hand.  This patch, which I've been thinking
+of as patchable Nethack, is an attempt to make this better.
+
+This patch is available at http://www.argon.org/~roderick/nethack/.
+
+
+
+For Users (people applying patches and compiling the code)
+------------------------------------------------------------------------------
+
+You'll only want to apply this patch if another patch you want to use is
+based on it.  The description of the patch should tell you that's so.
+
+Apply this patch in the normal manner
+
+    $ cd nethack-3.4.1
+    $ patch -p1 < ../nethack-3.4.1-patchable.1
+
+and then apply the other patches you want to use as you otherwise would
+have.
+
+
+
+For Patch Authors
+------------------------------------------------------------------------------
+
+Here's an example which demonstrates the problem and the fix.  Take this
+section of util/makedefs.c:
+
+    #ifdef ZEROCOMP
+		    "zero-compressed save files",
+    #endif
+		    "basic NetHack features"
+	    };
+
+    static const char *window_opts[] = {
+
+This is the list of compiled-in options you see with the #version
+command.  It's a good idea for patches to add themselves to this list.
+
+Say you had patch.grue which included this hunk:
+
+    --- makedefs.c.orig	2003-03-13 18:55:04.000000000 -0500
+    +++ makedefs.c.grue	2003-03-13 18:56:19.000000000 -0500
+    @@ -1,6 +1,7 @@
+     #ifdef ZEROCOMP
+		    "zero-compressed save files",
+     #endif
+    +		    "patch: GRUE repellant 3.4.1-1",
+		    "basic NetHack features"
+	    };
+
+and patch.froboz-wand which included this one:
+
+    --- makedefs.c.orig	2003-03-13 18:55:04.000000000 -0500
+    +++ makedefs.c.f-w	2003-03-13 18:58:55.000000000 -0500
+    @@ -1,6 +1,9 @@
+     #ifdef ZEROCOMP
+		    "zero-compressed save files",
+     #endif
+    +#ifdef FROBOZ_WAND
+    +		    "patch: the Froboz wand (v1)",
+    +#endif
+		    "basic NetHack features"
+	    };
+
+They conflict, so you'd have to apply one of them by hand.  If instead
+of the regular makedefs.c you started with this:
+
+    #ifdef ZEROCOMP
+                    "zero-compressed save files",
+    #endif
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+                    "basic NetHack features"
+            };
+
+    static const char *window_opts[] = {
+
+The technique is for each patch to add its new code between the 2 blocks
+of comment lines, then duplicate the second block.  Eg, the source
+from the Grue code would look like:
+
+    #ifdef ZEROCOMP
+                    "zero-compressed save files",
+    #endif
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+                    "patch: GRUE repellant 3.4.1-1",
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+                    "basic NetHack features"
+            };
+
+    static const char *window_opts[] = {
+
+When you diff these 2 versions, the only context is the patch point
+comment above and below the new code:
+
+    --- makedefs-patchable.c        2003-03-18 18:29:06.000000000 -0500
+    +++ makedefs-patchable.c.grue   2003-03-18 18:29:40.000000000 -0500
+    @@ -4,6 +4,10 @@
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+    +               "patch: GRUE repellant 3.4.1-1",
+    +               /*
+    +                * patch list patch point; see $top/README.patchable
+    +                */
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+
+When you apply this diff, patch will look for a place in the source which
+has 2 of the patch point comments right next to each other.  There's only
+one place like that, so it updates the code at that point.  Because the
+patch contained a new patch point comment at the end, the resulting code
+still has only 1 place where there are 2 patch point comments right next
+to each other, so if you apply another similar patch, such as
+
+    --- makedefs-patchable.c        2003-03-18 18:29:06.000000000 -0500
+    +++ makedefs-patchable.c.f-w    2003-03-18 18:29:25.000000000 -0500
+    @@ -4,6 +4,12 @@
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+    +#ifdef FROBOZ_WAND
+    +               "patch: the Froboz wand (v1)",
+    +#endif
+    +               /*
+    +                * patch list patch point; see $top/README.patchable
+    +                */
+                    /*
+                     * patch list patch point; see $top/README.patchable
+                     */
+
+it will also apply cleanly.  Any number of patches like this can be
+applied without hand editing.
+
+Suggestions:
+
+  - Add your patch to the patch list patch point in util/makedefs.c.
+    Include a version number.
+
+  - If inclusion of your code is conditional based on a #define, add it
+    to the options patch point in include/config.h.
+
+  - Let me know if you need a new patch point added.
+
+Roderick Schertler <roderick@argon.org>
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/artifact.h work.patchable/include/artifact.h
--- base.dist/include/artifact.h	2003-02-23 09:43:19.000000000 -0500
+++ work.patchable/include/artifact.h	2003-03-20 16:41:57.000000000 -0500
@@ -48,6 +48,12 @@
 	short	    role;	/* character role associated with */
 	short	    race;	/* character race associated with */
 	long        cost;	/* price when sold to hero (default 100 x base cost) */
+	/*
+	 * artifact patch point; see $top/README.patchable
+	 */
+	/*
+	 * artifact patch point; see $top/README.patchable
+	 */
 };
 
 /* invoked properties with special powers */
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/config.h work.patchable/include/config.h
--- base.dist/include/config.h	2003-02-23 09:43:19.000000000 -0500
+++ work.patchable/include/config.h	2003-03-20 16:41:57.000000000 -0500
@@ -354,6 +354,22 @@
 
 /* End of Section 5 */
 
+/*
+ * Section 6:  SETTINGS FOR PATCHES
+ *
+ * Settings in this section are provided by add-on patches you've
+ * applied.  Ignore the "patch point" comments.
+ */
+
+/*
+ * options patch point; see $top/README.patchable
+ */
+/*
+ * options patch point; see $top/README.patchable
+ */
+
+/* End of Section 6 */
+
 #include "global.h"	/* Define everything else according to choices above */
 
 #endif /* CONFIG_H */
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/flag.h work.patchable/include/flag.h
--- base.dist/include/flag.h	2003-02-23 09:43:20.000000000 -0500
+++ work.patchable/include/flag.h	2003-03-20 16:41:57.000000000 -0500
@@ -146,6 +146,13 @@
 	int	 initalign;	/* starting alignment (index into aligns[])  */
 	int	 randomall;	/* randomly assign everything not specified */
 	int	 pantheon;	/* deity selection for priest character */
+
+	/*
+	 * flag patch point; see $top/README.patchable
+	 */
+	/*
+	 * flag patch point; see $top/README.patchable
+	 */
 };
 
 /*
@@ -257,11 +264,24 @@
 
 	boolean  cmdassist;	/* provide detailed assistance for some commands */
 	boolean	 obsolete;	/* obsolete options can point at this, it isn't used */
+	/*
+	 * real instance_flags patch point; see $top/README.patchable
+	 */
+	/*
+	 * real instance_flags patch point; see $top/README.patchable
+	 */
+
 	/* Items which belong in flags, but are here to allow save compatibility */
 	boolean  lootabc;	/* use "a/b/c" rather than "o/i/b" when looting */
 	boolean  showrace;	/* show hero glyph by race rather than by role */
 	boolean  travelcmd;	/* allow travel command */
 	int	 runmode;	/* update screen display during run moves */
+	/*
+	 * compat instance_flags patch point; see $top/README.patchable
+	 */
+	/*
+	 * compat instance_flags patch point; see $top/README.patchable
+	 */
 };
 
 /*
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/monst.h work.patchable/include/monst.h
--- base.dist/include/monst.h	2003-02-23 09:43:21.000000000 -0500
+++ work.patchable/include/monst.h	2003-03-20 16:41:57.000000000 -0500
@@ -110,6 +110,12 @@
 	Bitfield(iswiz,1);	/* is the Wizard of Yendor */
 	Bitfield(wormno,5);	/* at most 31 worms on any level */
 #define MAX_NUM_WORMS	32	/* should be 2^(wormno bitfield size) */
+	/*
+	 * monst bitfield patch point; see $top/README.patchable
+	 */
+	/*
+	 * monst bitfield patch point; see $top/README.patchable
+	 */
 
 	long mstrategy;		/* for monsters with mflag3: current strategy */
 #define STRAT_ARRIVE	0x40000000L	/* just arrived on current level */
@@ -145,6 +151,12 @@
 	   be (or follow) a long int */
 	int meating;		/* monster is eating timeout */
 	long mextra[1]; /* monster dependent info */
+	/*
+	 * monst patch point; see $top/README.patchable
+	 */
+	/*
+	 * monst patch point; see $top/README.patchable
+	 */
 };
 
 /*
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/obj.h work.patchable/include/obj.h
--- base.dist/include/obj.h	2003-02-23 09:43:21.000000000 -0500
+++ work.patchable/include/obj.h	2003-03-20 16:41:57.000000000 -0500
@@ -88,6 +88,12 @@
 	Bitfield(in_use,1);	/* for magic items before useup items */
 	Bitfield(bypass,1);	/* mark this as an object to be skipped by bhito() */
 	/* 6 free bits */
+	/*
+	 * obj bitfield patch point; see $top/README.patchable
+	 */
+	/*
+	 * obj bitfield patch point; see $top/README.patchable
+	 */
 
 	int	corpsenm;	/* type of corpse is mons[corpsenm] */
 #define leashmon  corpsenm	/* gets m_id of attached pet */
@@ -102,6 +108,12 @@
 	long owornmask;
 	long oextra[1];		/* used for name of ordinary objects - length
 				   is flexible; amount for tmp gold objects */
+	/*
+	 * obj patch point; see $top/README.patchable
+	 */
+	/*
+	 * obj patch point; see $top/README.patchable
+	 */
 };
 
 #define newobj(xl)	(struct obj *)alloc((unsigned)(xl) + sizeof(struct obj))
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/objclass.h work.patchable/include/objclass.h
--- base.dist/include/objclass.h	2003-02-23 09:43:21.000000000 -0500
+++ work.patchable/include/objclass.h	2003-03-20 16:41:56.000000000 -0500
@@ -62,6 +62,12 @@
 #define GLASS		19
 #define GEMSTONE	20
 #define MINERAL		21
+	/*
+	 * objclass bitfield patch point; see $top/README.patchable
+	 */
+	/*
+	 * objclass bitfield patch point; see $top/README.patchable
+	 */
 
 #define is_organic(otmp)	(objects[otmp->otyp].oc_material <= WOOD)
 #define is_metallic(otmp)	(objects[otmp->otyp].oc_material >= IRON && \
@@ -107,6 +113,12 @@
 #define oc_level	oc_oc2		/* books: spell level */
 
 	unsigned short	oc_nutrition;	/* food value */
+	/*
+	 * objclass patch point; see $top/README.patchable
+	 */
+	/*
+	 * objclass patch point; see $top/README.patchable
+	 */
 };
 
 struct objdescr {
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/permonst.h work.patchable/include/permonst.h
--- base.dist/include/permonst.h	2003-02-23 09:43:22.000000000 -0500
+++ work.patchable/include/permonst.h	2003-03-20 16:41:56.000000000 -0500
@@ -61,6 +61,12 @@
 # ifdef TEXTCOLOR
 	uchar		mcolor;			/* color to use */
 # endif
+	/*
+	 * permonst patch point; see $top/README.patchable
+	 */
+	/*
+	 * permonst patch point; see $top/README.patchable
+	 */
 };
 
 extern NEARDATA struct permonst
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/prop.h work.patchable/include/prop.h
--- base.dist/include/prop.h	2003-02-23 09:43:22.000000000 -0500
+++ work.patchable/include/prop.h	2003-03-20 16:41:56.000000000 -0500
@@ -125,6 +125,12 @@
 #	define INTRINSIC    (FROMOUTSIDE|FROMRACE|FROMEXPER)
 	/* Control flags */
 #	define I_SPECIAL    0x10000000L /* Property is controllable */
+	/*
+	 * prop patch point; see $top/README.patchable
+	 */
+	/*
+	 * prop patch point; see $top/README.patchable
+	 */
 };
 
 /*** Definitions for backwards compatibility ***/
diff -r -X /home/roderick/.diff-exclude -uN base.dist/include/you.h work.patchable/include/you.h
--- base.dist/include/you.h	2003-02-23 09:43:24.000000000 -0500
+++ work.patchable/include/you.h	2003-03-20 16:41:56.000000000 -0500
@@ -70,6 +70,12 @@
 	long	wishes;		/* used a wish */
 	long	wisharti;	/* wished for an artifact */
 				/* genocides already listed at end of game */
+	/*
+	 * u_conduct patch point; see $top/README.patchable
+	 */
+	/*
+	 * u_conduct patch point; see $top/README.patchable
+	 */
 };
 
 /*** Unified structure containing role information ***/
@@ -124,6 +130,13 @@
 	int spelspec;		/* spell (SPE_) the class excels at */
 	int spelsbon;		/* penalty (-bonus) for that spell */
 
+	/*
+	 * Role patch point; see $top/README.patchable
+	 */
+	/*
+	 * Role patch point; see $top/README.patchable
+	 */
+
 	/*** Properties in variable-length arrays ***/
 	/* intrinsics (see attrib.c) */
 	/* initial inventory (see u_init.c) */
@@ -179,6 +192,13 @@
 	int   xray_range;	/* X-ray vision range */
 #endif
 
+	/*
+	 * Race patch point; see $top/README.patchable
+	 */
+	/*
+	 * Race patch point; see $top/README.patchable
+	 */
+
 	/*** Properties in variable-length arrays ***/
 	/* intrinsics (see attrib.c) */
 
@@ -304,6 +324,12 @@
 	Bitfield(uburied,1);		/* you're buried */
 	Bitfield(uedibility,1);		/* blessed food detection; sense unsafe food */
 	/* 1 free bit! */
+	/*
+	 * you bitfield patch point; see $top/README.patchable
+	 */
+	/*
+	 * you bitfield patch point; see $top/README.patchable
+	 */
 
 	unsigned udg_cnt;		/* how long you have been demigod */
 	struct u_event	uevent;		/* certain events have happened */
@@ -361,6 +387,13 @@
 	struct skills weapon_skills[P_NUM_SKILLS];
 	boolean twoweap;		/* KMH -- Using two-weapon combat */
 
+	/*
+	 * you patch point; see $top/README.patchable
+	 */
+	/*
+	 * you patch point; see $top/README.patchable
+	 */
+
 };	/* end of `struct you' */
 
 #define Upolyd (u.umonnum != u.umonster)
diff -r -X /home/roderick/.diff-exclude -uN base.dist/src/bones.c work.patchable/src/bones.c
--- base.dist/src/bones.c	2003-02-23 09:43:25.000000000 -0500
+++ work.patchable/src/bones.c	2003-03-20 16:41:56.000000000 -0500
@@ -82,6 +82,12 @@
 			otmp->rknown = 0;
 			otmp->invlet = 0;
 			otmp->no_charge = 0;
+			/*
+			 * resetobjs patch point; see $top/README.patchable
+			 */
+			/*
+			 * resetobjs patch point; see $top/README.patchable
+			 */
 
 			if (otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe);
 #ifdef MAIL
diff -r -X /home/roderick/.diff-exclude -uN base.dist/src/options.c work.patchable/src/options.c
--- base.dist/src/options.c	2003-02-23 09:43:28.000000000 -0500
+++ work.patchable/src/options.c	2003-03-18 20:58:07.000000000 -0500
@@ -31,6 +31,10 @@
  *
  *  The order matters.  If an option is a an initial substring of another
  *  option (e.g. time and timed_delay) the shorter one must come first.
+ *
+ *  Because of the ordering problem, and the need to update the opthelp
+ *  and such where formatting matters, I don't see a good way to put a
+ *  patch point here.
  */
 
 static struct Bool_Opt
diff -r -X /home/roderick/.diff-exclude -uN base.dist/util/makedefs.c work.patchable/util/makedefs.c
--- base.dist/util/makedefs.c	2003-02-23 09:43:43.000000000 -0500
+++ work.patchable/util/makedefs.c	2003-03-20 16:41:56.000000000 -0500
@@ -748,6 +748,13 @@
 #ifdef ZEROCOMP
 		"zero-compressed save files",
 #endif
+		"patch: patchable nethack 3.4.1-1",
+		/*
+		 * patch list patch point; see $top/README.patchable
+		 */
+		/*
+		 * patch list patch point; see $top/README.patchable
+		 */
 		"basic NetHack features"
 	};
 
