diff -wur -N nethack-linux/dat/advcal.des nethack-adventskalender/dat/advcal.des
--- nethack-linux/dat/advcal.des	1970-01-01 01:00:00.000000000 +0100
+++ nethack-adventskalender/dat/advcal.des	2008-10-19 16:55:42.000000000 +0200
@@ -0,0 +1,233 @@
+#	SCCS Id: @(#)advcal.des	3.4	2008/08/12
+#	Copyright (c) 2008 Patric Mueller
+# NetHack may be freely redistributed.  See license for details.
+#
+
+MAZE:"advcal",' '
+FLAGS:noteleport
+GEOMETRY:center,center
+MAP
+...........................................................................
+...---...---...---...---...---...---...---...---...---...---...---...---...
+...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...
+...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...
+...........................................................................
+...........................................................................
+...........................T...............................................
+...........................................................................
+............................................................T..............
+......T....................................................................
+...........................................................................
+...........................................................................
+...........................................................................
+...........................................................................
+.....................T..................................T..................
+...........................................................................
+...........................................................................
+...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...-+-...
+...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...|.|...
+...---...---...---...---...---...---...---...---...---...---...---...---...
+...........................................................................
+ENDMAP
+
+# Dungeon Description
+REGION:(00,00,74,20),lit,"ordinary"
+# Non diggable walls
+NON_DIGGABLE:(00,00,74,20)
+NON_PASSWALL:(00,00,74,20)
+# Doors
+DOOR:locked,(04,03)
+DOOR:locked,(10,03)
+DOOR:locked,(16,03)
+DOOR:locked,(22,03)
+DOOR:locked,(28,03)
+DOOR:locked,(34,03)
+DOOR:locked,(40,03)
+DOOR:locked,(46,03)
+DOOR:locked,(52,03)
+DOOR:locked,(58,03)
+DOOR:locked,(64,03)
+DOOR:locked,(70,03)
+DOOR:locked,(04,17)
+DOOR:locked,(10,17)
+DOOR:locked,(16,17)
+DOOR:locked,(22,17)
+DOOR:locked,(28,17)
+DOOR:locked,(34,17)
+DOOR:locked,(40,17)
+DOOR:locked,(46,17)
+DOOR:locked,(52,17)
+DOOR:locked,(58,17)
+DOOR:locked,(64,17)
+DOOR:locked,(70,17)
+## 64 gems in christmas colors
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+OBJECT:'*',"worthless piece of violet glass",random
+
+OBJECT:'*',"worthless piece of green glass",random
+OBJECT:'*',"worthless piece of green glass",random
+OBJECT:'*',"worthless piece of green glass",random
+OBJECT:'*',"worthless piece of green glass",random
+OBJECT:'*',"worthless piece of green glass",random
+OBJECT:'*',"worthless piece of green glass",random
+OBJECT:'*',"worthless piece of green glass",random
+
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+OBJECT:'*',"worthless piece of red glass",random
+
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+OBJECT:'*',"worthless piece of white glass",random
+
+OBJECT:'*',"worthless piece of yellow glass",random
+OBJECT:'*',"worthless piece of yellow glass",random
+OBJECT:'*',"worthless piece of yellow glass",random
+OBJECT:'*',"worthless piece of yellow glass",random
+OBJECT:'*',"worthless piece of yellowish brown glass",random
+OBJECT:'*',"worthless piece of yellowish brown glass",random
+OBJECT:'*',"worthless piece of yellowish brown glass",random
+OBJECT:'*',"worthless piece of yellowish brown glass",random
+OBJECT:'*',"worthless piece of blue glass",random
+OBJECT:'*',"worthless piece of blue glass",random
+OBJECT:'*',"worthless piece of blue glass",random
+OBJECT:'*',"worthless piece of blue glass",random
+OBJECT:'*',"worthless piece of orange glass",random
+OBJECT:'*',"worthless piece of orange glass",random
+OBJECT:'*',"worthless piece of orange glass",random
+OBJECT:'*',"worthless piece of orange glass",random
+
+OBJECT[40%]:'*',"jade",random
+OBJECT[40%]:'*',"agate",random
+OBJECT[40%]:'*',"fluorite",random
+OBJECT[40%]:'*',"jasper",random
+OBJECT[40%]:'*',"amethyst",random
+OBJECT[40%]:'*',"garnet",random
+OBJECT[40%]:'*',"chrysoberyl",random
+OBJECT[40%]:'*',"opal",random
diff -wur -N nethack-linux/dat/dungeon.def nethack-adventskalender/dat/dungeon.def
--- nethack-linux/dat/dungeon.def	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/dat/dungeon.def	2008-08-07 11:10:37.000000000 +0200
@@ -17,6 +17,7 @@
 DUNGEON:	"The Dungeons of Doom" "D" (25, 5)
 ALIGNMENT:	unaligned
 BRANCH:		"The Gnomish Mines" @ (2, 3)
+BRANCH:		"Advent Calendar" @ (1, 5) portal
 %REINCARNATION LEVEL:		"rogue" "R" @ (15, 4)
 LEVEL:		"oracle" "O" @ (5, 5)
 LEVALIGN:	neutral
@@ -106,7 +107,15 @@
 DESCRIPTION:	mazelike
 ALIGNMENT:	unaligned
 LEVEL:		"knox" "K" @ (-1, 0)
+
+#
+#	The Advent Calendar
 #
+DUNGEON:	"Advent Calendar" "none" (1, 0)
+DESCRIPTION:	mazelike
+ALIGNMENT:	unaligned
+LEVEL:		"advcal" "none" @ (-1, 0)
+
 #	Vlad's Tower
 #
 #	It has been removed from Gehennom, and it is surrounded by stone.
diff -wur -N nethack-linux/include/config.h nethack-adventskalender/include/config.h
--- nethack-linux/include/config.h	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/include/config.h	2008-11-13 21:53:42.000000000 +0100
@@ -351,6 +351,8 @@
 /*#define GOLDOBJ */	/* Gold is kept on obj chains - Helge Hafting */
 /*#define AUTOPICKUP_EXCEPTIONS */ /* exceptions to autopickup */
 
+#define ADVENT_CALENDAR
+
 /* End of Section 5 */
 
 #include "global.h"	/* Define everything else according to choices above */
diff -wur -N nethack-linux/include/decl.h nethack-adventskalender/include/decl.h
--- nethack-linux/include/decl.h	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/include/decl.h	2008-08-07 11:10:37.000000000 +0200
@@ -72,6 +72,9 @@
     xchar	d_mines_dnum, d_quest_dnum;
     d_level	d_qstart_level, d_qlocate_level, d_nemesis_level;
     d_level	d_knox_level;
+#ifdef ADVENT_CALENDAR
+    d_level	d_advcal_level;
+#endif
 } dungeon_topology;
 /* macros for accesing the dungeon levels by their old names */
 #define oracle_level		(dungeon_topology.d_oracle_level)
@@ -104,6 +107,9 @@
 #define qlocate_level		(dungeon_topology.d_qlocate_level)
 #define nemesis_level		(dungeon_topology.d_nemesis_level)
 #define knox_level		(dungeon_topology.d_knox_level)
+#ifdef ADVENT_CALENDAR
+# define advcal_level		(dungeon_topology.d_advcal_level)
+#endif
 
 E NEARDATA stairway dnstair, upstair;		/* stairs up and down */
 #define xdnstair	(dnstair.sx)
diff -wur -N nethack-linux/include/dungeon.h nethack-adventskalender/include/dungeon.h
--- nethack-linux/include/dungeon.h	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/include/dungeon.h	2008-08-07 11:10:37.000000000 +0200
@@ -121,6 +121,9 @@
 #define Is_qlocate(x)		(on_level(x, &qlocate_level))
 #define Is_nemesis(x)		(on_level(x, &nemesis_level))
 #define Is_knox(x)		(on_level(x, &knox_level))
+#ifdef ADVENT_CALENDAR
+#define Is_advent_calendar(x)		(on_level(x, &advcal_level))
+#endif
 
 #define In_sokoban(x)		((x)->dnum == sokoban_dnum)
 #define Inhell			In_hell(&u.uz)	/* now gehennom */
diff -wur -N nethack-linux/include/extern.h nethack-adventskalender/include/extern.h
--- nethack-linux/include/extern.h	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/include/extern.h	2008-11-13 23:15:03.000000000 +0100
@@ -741,6 +741,8 @@
 E boolean FDECL(fuzzymatch, (const char *,const char *,const char *,BOOLEAN_P));
 E void NDECL(setrandom);
 E int NDECL(getyear);
+E int NDECL(getmonth);
+E int NDECL(getmday);
 #if 0
 E char *FDECL(yymmdd, (time_t));
 #endif
@@ -865,6 +867,7 @@
 E boolean FDECL(doorlock, (struct obj *,int,int));
 E int NDECL(doopen);
 E int NDECL(doclose);
+E int FDECL(artifact_door, (int,int));
 
 #ifdef MAC
 /* These declarations are here because the main code calls them. */
@@ -1010,6 +1013,9 @@
 E void FDECL(mktrap, (int,int,struct mkroom *,coord*));
 E void FDECL(mkstairs, (XCHAR_P,XCHAR_P,CHAR_P,struct mkroom *));
 E void NDECL(mkinvokearea);
+#ifdef ADVENT_CALENDAR
+E boolean NDECL(mk_advcal_portal);
+#endif
 
 /* ### mkmap.c ### */
 
@@ -1034,6 +1040,10 @@
 E void FDECL(restore_waterlevel, (int));
 E const char *FDECL(waterbody_name, (XCHAR_P,XCHAR_P));
 
+#ifdef ADVENT_CALENDAR
+E void FDECL(fill_advent_calendar, (boolean));
+#endif
+
 /* ### mkobj.c ### */
 
 E struct obj *FDECL(mkobj_at, (CHAR_P,int,int,BOOLEAN_P));
diff -wur -N nethack-linux/src/dig.c nethack-adventskalender/src/dig.c
--- nethack-linux/src/dig.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/dig.c	2008-11-13 21:28:50.000000000 +0100
@@ -173,6 +173,11 @@
 		if(verbose) pline_The("ladder resists your effort.");
 	    } else if(verbose) pline_The("stairs are too hard to %s.", verb);
 	    return(FALSE);
+	/* ALI - Artifact doors */
+	} else if (IS_DOOR(levl[x][y].typ) && artifact_door(x, y)) {
+	    if(verbose) pline_The("%s here is too hard to dig in.",
+				  surface(x,y));
+	    return(FALSE);
 	} else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) {
 	    if(verbose) pline_The("throne is too hard to break apart.");
 	    return(FALSE);
@@ -232,9 +237,12 @@
 		pline("This tree seems to be petrified.");
 		return(0);
 	    }
+	    /* ALI - Artifact doors */
 	    if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) &&
-			dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) {
-		pline("This wall is too hard to %s.", verb);
+	    		dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK ||
+		    IS_DOOR(lev->typ) && artifact_door(dpx, dpy)) {
+		pline("This %s is too hard to %s.",
+			IS_DOOR(lev->typ) ? "door" : "wall", verb);
 		return(0);
 	    }
 	}
@@ -656,6 +664,8 @@
 	boolean nohole = !Can_dig_down(&u.uz);
 
 	if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) ||
+	   /* ALI - artifact doors */
+	   IS_DOOR(levl[u.ux][u.uy].typ) && artifact_door(u.ux, u.uy) ||
 	   (IS_ROCK(lev->typ) && lev->typ != SDOOR &&
 	    (lev->wall_info & W_NONDIGGABLE) != 0)) {
 		pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy));
@@ -1207,6 +1217,12 @@
 	    tmp_at(zx,zy);
 	    delay_output();	/* wait a little bit */
 	    if (closed_door(zx, zy) || room->typ == SDOOR) {
+		/* ALI - Artifact doors */
+		if (artifact_door(zx, zy)) {
+		    if (cansee(zx, zy))
+			pline_The("door glows then fades.");
+		    break;
+		}
 		if (*in_rooms(zx,zy,SHOPBASE)) {
 		    add_damage(zx, zy, 400L);
 		    shopdoor = TRUE;
diff -wur -N nethack-linux/src/do.c nethack-adventskalender/src/do.c
--- nethack-linux/src/do.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/do.c	2008-11-13 21:56:15.000000000 +0100
@@ -1335,6 +1335,16 @@
 		}
 	}
 
+#ifdef ADVENT_CALENDAR
+	if ((getmonth()==12) && (getmday() < 25)) {
+		if (mk_advcal_portal())
+			You("smell chocolate!");
+	}
+	if (Is_advent_calendar(&u.uz)) {
+		fill_advent_calendar(FALSE);
+	}
+#endif
+
 	/* once Croesus is dead, his alarm doesn't work any more */
 	if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) {
 		You("penetrated a high security area!");
diff -wur -N nethack-linux/src/dokick.c nethack-adventskalender/src/dokick.c
--- nethack-linux/src/dokick.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/dokick.c	2008-11-13 21:26:57.000000000 +0100
@@ -1041,6 +1041,9 @@
 	/* not enough leverage to kick open doors while levitating */
 	if(Levitation) goto ouch;
 
+	/* Ali - artifact doors */
+	if (artifact_door(x, y)) goto ouch;
+
 	exercise(A_DEX, TRUE);
 	/* door is known to be CLOSED or LOCKED */
 	if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
diff -wur -N nethack-linux/src/dungeon.c nethack-adventskalender/src/dungeon.c
--- nethack-linux/src/dungeon.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/dungeon.c	2008-11-13 21:56:55.000000000 +0100
@@ -609,6 +609,7 @@
 	const char *lev_name;
 	d_level *lev_spec;
 } level_map[] = {
+	{ "advcal",	&advcal_level },
 	{ "air",	&air_level },
 	{ "asmodeus",	&asmodeus_level },
 	{ "astral",	&astral_level },
@@ -870,6 +871,22 @@
 				if (br) br->end1.dnum = n_dgns;
 				/* adjust the branch's position on the list */
 				insert_branch(br, TRUE);
+#ifdef ADVENT_CALENDAR
+			} else if (lev_map->lev_spec == &advcal_level) {
+				branch *br;
+				/*
+				 * Kludge to allow floating Knox entrance.  We
+				 * specify a floating entrance by the fact that
+				 * its entrance (end1) has a bogus dnum, namely
+				 * n_dgns.
+				 */
+				for (br = branches; br; br = br->next)
+				    if (on_level(&br->end2, &advcal_level)) break;
+
+				if (br) br->end1.dnum = n_dgns;
+				/* adjust the branch's position on the list */
+				insert_branch(br, TRUE);
+#endif
 			}
 		}
 	}
@@ -1646,7 +1663,11 @@
 		Sprintf(eos(buf), " (tune %s)", tune);
 	    if (bymenu) {
 	    	/* If other floating branches are added, this will need to change */
+#ifdef ADVENT_CALENDAR
+	    	if ((i != advcal_level.dnum) && (i != knox_level.dnum)) {
+#else
 	    	if (i != knox_level.dnum) {
+#endif
 			lchoices.lev[lchoices.idx] = slev->dlevel.dlevel;
 			lchoices.dgn[lchoices.idx] = i;
 		} else {
diff -wur -N nethack-linux/src/hack.c nethack-adventskalender/src/hack.c
--- nethack-linux/src/hack.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/hack.c	2008-11-13 21:31:41.000000000 +0100
@@ -584,6 +584,21 @@
     } else if (IS_DOOR(tmpr->typ)) {
 	if (closed_door(x,y)) {
 	    if (Blind && mode == DO_MOVE) feel_location(x,y);
+	    /* ALI - artifact doors */
+	    if (artifact_door(x, y)) {
+		if (mode == DO_MOVE) {
+		    if (amorphous(youmonst.data))
+			You("try to ooze under the door, but the gap is too small.");
+		    else if (tunnels(youmonst.data) && !needspick(youmonst.data))
+			You("hurt your teeth on the re-enforced door.");
+		    else if (x == u.ux || y == u.uy) {
+			if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) {                            pline("Ouch!  You bump into a heavy door.");
+			    exercise(A_DEX, FALSE);
+			} else pline("That door is closed.");
+		    }
+		}
+		return FALSE;
+	    } else
 	    if (Passes_walls)
 		;	/* do nothing */
 	    else if (can_ooze(&youmonst)) {
diff -wur -N nethack-linux/src/hacklib.c nethack-adventskalender/src/hacklib.c
--- nethack-linux/src/hacklib.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/hacklib.c	2008-10-19 16:09:59.000000000 +0200
@@ -37,6 +37,8 @@
 	boolean		fuzzymatch	(const char *,const char *,const char *,boolean)
 	void		setrandom	(void)
 	int		getyear		(void)
+	int		getmonth	(void)
+	int		getmday		(void)
 	char *		yymmdd		(time_t)
 	long		yyyymmdd	(time_t)
 	int		phase_of_the_moon	(void)
@@ -508,6 +510,21 @@
 	return(1900 + getlt()->tm_year);
 }
 
+/* Returns current month (1-12, 1 = January) */
+int
+getmonth()
+{
+	return(1 + getlt()->tm_mon);
+}
+
+/* Returns current day of month (1-31) */
+int
+getmday()
+{
+	return(getlt()->tm_mday);
+}
+
+
 #if 0
 /* This routine is no longer used since in 2000 it will yield "100mmdd". */
 char *
diff -wur -N nethack-linux/src/lock.c nethack-adventskalender/src/lock.c
--- nethack-linux/src/lock.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/lock.c	2008-11-13 23:24:59.000000000 +0100
@@ -228,6 +228,7 @@
 {
 	int picktyp, c, ch;
 	coord cc;
+	int key;
 	struct rm	*door;
 	struct obj	*otmp;
 	char qbuf[QBUFSZ];
@@ -400,6 +401,8 @@
 			return(0);
 		    }
 #endif
+		    /* ALI - Artifact doors */
+		    key = artifact_door(cc.x, cc.y);
 
 		    Sprintf(qbuf,"%sock it?",
 			(door->doormask & D_LOCKED) ? "Unl" : "L" );
@@ -423,6 +426,20 @@
 		    }
 		    xlock.door = door;
 		    xlock.box = 0;
+
+		    /* ALI - Artifact doors */
+#ifdef ADVENT_CALENDAR
+		    if (key) {
+#else
+		    xlock.key = pick->oartifact;
+		    if (key && xlock.key != key) {
+#endif
+			if (picktyp == SKELETON_KEY) {
+			    Your("key doesn't seem to fit.");
+			    return(0);
+			}
+			else ch = -1;		/* -1 == 0% chance */
+		    }
 	    }
 	}
 	flags.move = 0;
@@ -744,6 +761,7 @@
 	const char *msg = (const char *)0;
 	const char *dustcloud = "A cloud of dust";
 	const char *quickly_dissipates = "quickly dissipates";
+	int key = artifact_door(x, y);		/* ALI - Artifact doors */
 	
 	if (door->typ == SDOOR) {
 	    switch (otmp->otyp) {
@@ -751,8 +769,12 @@
 	    case SPE_KNOCK:
 	    case WAN_STRIKING:
 	    case SPE_FORCE_BOLT:
+		if (key)	/* Artifact doors are revealed only */
+		    cvt_sdoor_to_door(door);
+		else {
 		door->typ = DOOR;
 		door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
+		}
 		newsym(x,y);
 		if (cansee(x,y)) pline("A door appears in the wall!");
 		if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK)
@@ -800,12 +822,21 @@
 
 	    switch (door->doormask & ~D_TRAPPED) {
 	    case D_CLOSED:
+		if (key)
+		    msg = "The door closes!";
+		else
 		msg = "The door locks!";
 		break;
 	    case D_ISOPEN:
+		if (key)
+		    msg = "The door swings shut!";
+		else
 		msg = "The door swings shut, and locks!";
 		break;
 	    case D_BROKEN:
+		if (key)
+		    msg = "The broken door reassembles!";
+		else
 		msg = "The broken door reassembles and locks!";
 		break;
 	    case D_NODOOR:
@@ -817,19 +848,22 @@
 		break;
 	    }
 	    block_point(x, y);
+	    if (key)
+		door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
+	    else
 	    door->doormask = D_LOCKED | (door->doormask & D_TRAPPED);
 	    newsym(x,y);
 	    break;
 	case WAN_OPENING:
 	case SPE_KNOCK:
-	    if (door->doormask & D_LOCKED) {
+	    if (!key && door->doormask & D_LOCKED) {
 		msg = "The door unlocks!";
 		door->doormask = D_CLOSED | (door->doormask & D_TRAPPED);
 	    } else res = FALSE;
 	    break;
 	case WAN_STRIKING:
 	case SPE_FORCE_BOLT:
-	    if (door->doormask & (D_LOCKED | D_CLOSED)) {
+	    if (!key && door->doormask & (D_LOCKED | D_CLOSED)) {
 		if (door->doormask & D_TRAPPED) {
 		    if (MON_AT(x, y))
 			(void) mb_trapped(m_at(x,y));
@@ -916,6 +950,34 @@
 	pline("%s %s!", An(thing), disposition);
 }
 
+/* ALI - Kevin Hugo's artifact doors.
+ * Return the artifact which unlocks the door at (x, y), or
+ * zero if it is an ordinary door.
+ * Note: Not all doors are listed in the doors array (eg., doors
+ * dynamically converted from secret doors). Since only trapped
+ * and artifact doors are needed this isn't a problem. If we ever
+ * implement trapped secret doors we will have to extend this.
+ */
+
+int
+artifact_door(x, y)
+int x, y;
+{
+    int i;
+
+#ifdef ADVENT_CALENDAR
+    /* on the advent calendar level all doors are indestructible */
+    if (Is_advent_calendar(&u.uz)) return A_NONE;
+#endif
+/*
+    for(i = 0; i < doorindex; i++) {
+	if (x == doors[i].x && y == doors[i].y)
+	    return doors[i].arti_key;
+    }
+*/
+    return 0;
+}
+
 #endif /* OVLB */
 
 /*lock.c*/
diff -wur -N nethack-linux/src/mklev.c nethack-adventskalender/src/mklev.c
--- nethack-linux/src/mklev.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/mklev.c	2008-11-13 23:36:33.000000000 +0100
@@ -1589,4 +1589,58 @@
 	place_branch(br, x, y);
 }
 
+#ifdef ADVENT_CALENDAR
+/*
+ * The portal to the Advent Calender is special. 
+ * It does not only lead to a floating branch like knox portal.
+ * It also may appear upon reentering a existing level if it is the
+ * right time of the year.
+ */
+boolean
+mk_advcal_portal()
+{
+	extern int n_dgns;		/* from dungeon.c */
+	d_level *source;
+	branch *br;
+
+	/* made_branch remains unchanged when entering a already created
+	 * level. This leads to the branch inserted in the dungeon level
+	 * list but no portal created, the branch is unreachable.
+	 *
+	 * Technically this is a bug but nobody anticipated a branch
+	 * that could be inserted after level creation.
+	 */
+	if (made_branch) return FALSE;
+
+	br = dungeon_branch("Advent Calendar");
+	if (on_level(&advcal_level, &br->end1)) {
+	    source = &br->end2;
+	} else {
+	    /* disallow branch on a level with one branch already */
+	    if(Is_branchlev(&u.uz))
+		return FALSE;
+	    source = &br->end1;
+	}
+
+	/* Already set. */
+	if (source->dnum < n_dgns) return FALSE;
+
+	if (! (u.uz.dnum == oracle_level.dnum	    /* in main dungeon */
+		&& !at_dgn_entrance("The Quest")    /* but not Quest's entry */
+		&& depth(&u.uz) < depth(&medusa_level))) /* and above Medusa */
+	    return FALSE;
+
+	/* Adjust source to be current level and re-insert branch. */
+	*source = u.uz;
+	insert_branch(br, TRUE);
+
+#ifdef DEBUG
+	pline("Made advent calendar portal.");
+#endif
+	place_branch(br, 0, 0);
+
+	return TRUE;
+}
+#endif
+
 /*mklev.c*/
diff -wur -N nethack-linux/src/mkmaze.c nethack-adventskalender/src/mkmaze.c
--- nethack-linux/src/mkmaze.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/mkmaze.c	2008-11-13 22:51:32.000000000 +0100
@@ -473,6 +473,10 @@
 		    mtmp2 = mtmp->nmon;
 		    if(mtmp->isshk) mongone(mtmp);
 	    }
+#ifdef ADVENT_CALENDAR
+    } else if (Is_advent_calendar(&u.uz)) {
+    	fill_advent_calendar(TRUE);
+#endif
     }
 
     if(lev_message) {
@@ -492,6 +496,71 @@
     num_lregions = 0;
 }
 
+#ifdef ADVENT_CALENDAR
+void
+fill_advent_calendar(init)
+boolean init;
+{
+    int door_nr=1;
+    char buf[4];
+    int x,y;
+    int in_x,in_y,out_x,out_y;
+
+    for(x = 1; x < COLNO; x++) {
+        for(y = 1; y < ROWNO; y++) {
+            if (door_nr < 25 && isok(x,y) && IS_DOOR(levl[x][y].typ)) {
+                if (y < 10) {
+                    out_x = x; out_y = y+1; in_x = x; in_y = y-1;
+                } else {
+                    out_x = x; out_y = y-1; in_x = x; in_y = y+1;
+                }
+                if (init) {
+                    sprintf(buf, "%d", door_nr);
+                    /* place number in front of the door */
+                    make_engr_at(out_x, out_y, buf, 0L, MARK);
+		    if (door_nr == 24) {
+		    	int object = CANDY_BAR;
+		    	/* Christmas present! */
+		    	switch(rn2(15)) {
+				case  0: object = BAG_OF_HOLDING; break;
+				case  1: object = OILSKIN_SACK; break;
+				case  2: object = FIRE_HORN; break;
+				case  3: object = FROST_HORN; break;
+				case  4: object = MAGIC_FLUTE; break;
+				case  5: object = MAGIC_HARP; break;
+				case  6: object = DRUM_OF_EARTHQUAKE; break;
+				case  7: object = MAGIC_WHISTLE; break;
+				case  8: object = MAGIC_LAMP; break;
+				case  9: object = UNICORN_HORN; break;
+				case 10: object = BAG_OF_TRICKS; break;
+				case 11: object = EXPENSIVE_CAMERA; break;
+				case 12: object = HORN_OF_PLENTY; break;
+				case 13: object = STETHOSCOPE; break;
+				case 14: object = TINNING_KIT; break;
+			}
+		    	mksobj_at(object, in_x, in_y, TRUE, TRUE);
+		    } else if (rn2(4)) {
+		    	mksobj_at((rn2(4)) ? CANDY_BAR : FORTUNE_COOKIE, in_x, in_y, FALSE, FALSE);
+		    } else {
+                    	mkobj_at((rn2(4)) ? RING_CLASS : TOOL_CLASS, in_x, in_y, FALSE);
+		    }
+		}
+		if (levl[x][y].doormask & D_LOCKED && getmonth() == 12) {
+		    if (getmday() == 24 && door_nr == 24) {
+		        You_hear("a little bell ringing!");
+		        levl[x][y].doormask = D_CLOSED;
+		    } else if (getmday() == door_nr) {
+			You_hear("a door unlocking!");
+		        levl[x][y].doormask = D_CLOSED;
+		    }
+                }
+	    	door_nr++;
+            }
+        }
+    }
+}
+#endif
+
 void
 makemaz(s)
 register const char *s;
diff -wur -N nethack-linux/src/music.c nethack-adventskalender/src/music.c
--- nethack-linux/src/music.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/music.c	2008-11-13 21:22:02.000000000 +0100
@@ -332,6 +332,8 @@
 		    } else newsym(x,y);
 		    break;
 		  case DOOR : /* Make the door collapse */
+		    /* ALI - artifact doors */
+		    if (artifact_door(x, y))  break;
 		    if (levl[x][y].doormask == D_NODOOR) goto do_pit;
 		    if (cansee(x,y))
 			pline_The("door collapses.");
diff -wur -N nethack-linux/src/trap.c nethack-adventskalender/src/trap.c
--- nethack-linux/src/trap.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/trap.c	2008-11-13 21:25:28.000000000 +0100
@@ -1288,7 +1288,9 @@
 		(struct obj *)0);
 	del_engr_at(trap->tx, trap->ty);
 	wake_nearto(trap->tx, trap->ty, 400);
-	if (IS_DOOR(levl[trap->tx][trap->ty].typ))
+	/* ALI - artifact doors */
+	if (IS_DOOR(levl[trap->tx][trap->ty].typ) &&
+		!artifact_door(trap->tx, trap->ty))
 	    levl[trap->tx][trap->ty].doormask = D_BROKEN;
 	/* TODO: destroy drawbridge if present */
 	/* caller may subsequently fill pit, e.g. with a boulder */
diff -wur -N nethack-linux/src/zap.c nethack-adventskalender/src/zap.c
--- nethack-linux/src/zap.c	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/src/zap.c	2008-11-13 21:24:11.000000000 +0100
@@ -3675,6 +3675,9 @@
 		int new_doormask = -1;
 		const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
 		rangemod = -1000;
+		/* ALI - Artifact doors */
+		if (artifact_door(x, y))
+		    goto def_case;
 		switch(abstype) {
 		case ZT_FIRE:
 		    new_doormask = D_NODOOR;
diff -wur -N nethack-linux/sys/unix/Makefile.dat nethack-adventskalender/sys/unix/Makefile.dat
--- nethack-linux/sys/unix/Makefile.dat	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/sys/unix/Makefile.dat	2008-10-19 16:39:16.000000000 +0200
@@ -102,6 +102,7 @@
 spec_levs: ../util/lev_comp \
 	bigroom.des castle.des endgame.des gehennom.des knox.des medusa.des \
 	mines.des oracle.des sokoban.des tower.des yendor.des
+	../util/lev_comp advcal.des
 	../util/lev_comp bigroom.des
 	../util/lev_comp castle.des
 	../util/lev_comp endgame.des
diff -wur -N nethack-linux/sys/unix/Makefile.top nethack-adventskalender/sys/unix/Makefile.top
--- nethack-linux/sys/unix/Makefile.top	2008-05-26 19:47:02.000000000 +0200
+++ nethack-adventskalender/sys/unix/Makefile.top	2008-10-19 16:30:40.000000000 +0200
@@ -77,6 +77,7 @@
 	juiblex.lev knox.lev medusa-?.lev minend-?.lev minefill.lev \
 	minetn-?.lev oracle.lev orcus.lev sanctum.lev soko?-?.lev \
 	tower?.lev valley.lev wizard?.lev \
+	advcal.lev \
 	astral.lev air.lev earth.lev fire.lev water.lev
 QUEST_LEVS = ???-goal.lev ???-fil?.lev ???-loca.lev ???-strt.lev
 
