From 83a0c37d13440a7469aaa23527c9e1acb6fb2c52 Mon Sep 17 00:00:00 2001 From: keni Date: Thu, 16 Jun 2016 13:32:50 -0400 Subject: [PATCH] Conway --- dat/bigroom.des | 86 ++++++++++ dat/dungeon.def | 6 +- doc/makedefs.6 | 7 + include/config.h | 2 + include/decl.h | 26 +-- include/extern.h | 3 + include/global.h | 11 ++ include/rm.h | 3 + include/sp_lev.h | 1 + include/you.h | 2 + src/allmain.c | 8 + src/bones.c | 5 +- src/decl.c | 5 + src/dlb.c | 2 +- src/do.c | 9 + src/makemon.c | 1 + src/mhitm.c | 4 +- src/mklev.c | 3 + src/mkmaze.c | 387 ++++++++++++++++++++++++++++++++++++++++++ src/monst.c | 8 + src/save.c | 3 + src/sp_lev.c | 6 + sys/unix/Makefile.dat | 3 +- util/lev_comp.l | 1 + util/makedefs.c | 16 +- util/mdgrep.h | 19 ++- util/mdgrep.pl | 20 ++- 27 files changed, 613 insertions(+), 34 deletions(-) diff --git a/dat/bigroom.des b/dat/bigroom.des index dcec9854b..e68a54df7 100644 --- a/dat/bigroom.des +++ b/dat/bigroom.des @@ -721,3 +721,89 @@ MAZEWALK:(4, 2), south, false STAIR:(00,00,70,18),(02,03,68,15),up STAIR:random,down +^?CONWAY +# same as bigrm-1, but inhabited by Life (see compile option CONWAY) + +MAZE:"bigrm-11",' ' +FLAGS: conway +GEOMETRY:center,center +MAP +--------------------------------------------------------------------------- +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +|.........................................................................| +--------------------------------------------------------------------------- +ENDMAP +# Dungeon Description +REGION:(01,01,73,16),lit,"ordinary" +# Stairs +STAIR:random,up +STAIR:random,down +# Non diggable walls +NON_DIGGABLE:(00,00,74,17) +# Objects +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +OBJECT:random,random +# Random traps +TRAP:random,random +TRAP:random,random +TRAP:random,random +TRAP:random,random +TRAP:random,random +TRAP:random,random +# Life in random places. +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +MONSTER:"mildew",random +^. diff --git a/dat/dungeon.def b/dat/dungeon.def index d4d61fbaf..2993d3183 100644 --- a/dat/dungeon.def +++ b/dat/dungeon.def @@ -22,7 +22,11 @@ LEVELDESC: roguelike LEVEL: "oracle" "O" @ (5, 5) LEVALIGN: neutral CHAINBRANCH: "Sokoban" "oracle" + (1, 0) up -RNDLEVEL: "bigrm" "B" @ (10, 3) 40 10 +^?CONWAY +RNDLEVEL: "bigrm" "B" @ (10, 3) 40 11 +^: +RNDLEVEL: "bigrm" "B" @ (10, 3) 40 10 +^. CHAINBRANCH: "The Quest" "oracle" + (6, 2) portal BRANCH: "Fort Ludios" @ (18, 4) portal RNDLEVEL: "medusa" "none" @ (-5, 4) 4 diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 7b55de3e4..822e445f3 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -188,6 +188,13 @@ to be "undefined." .I Symbol must already be known to .BR makedefs . +.br +.TP +.BI --grep-test " symbol" +Test if the +.I symbol +is defined. Exit silently (unless an error occurs) with status EXIT_SUCCESS if defined, +otherwise with status EXIT_FAILURE. .SH MDGREP FUNCTIONS The .B --grep diff --git a/include/config.h b/include/config.h index 47b2951cc..3d9e5c8ea 100644 --- a/include/config.h +++ b/include/config.h @@ -513,6 +513,8 @@ typedef unsigned char uchar; but it isn't necessary for successful operation of the program */ #define FREE_ALL_MEMORY /* free all memory at exit */ +#define CONWAY /* Conway's Life level */ + /* End of Section 4 */ #ifdef TTY_TILES_ESCCODES diff --git a/include/decl.h b/include/decl.h index 7898d17ce..31804a3ca 100644 --- a/include/decl.h +++ b/include/decl.h @@ -360,17 +360,17 @@ E const char *const monexplain[], invisexplain[], *const oclass_names[]; * provides all the subclasses that seem reasonable, and sets up for all * prefixes being null. Port code can set those that it wants. */ -#define HACKPREFIX 0 -#define LEVELPREFIX 1 -#define SAVEPREFIX 2 -#define BONESPREFIX 3 -#define DATAPREFIX 4 /* this one must match hardcoded value in dlb.c */ -#define SCOREPREFIX 5 -#define LOCKPREFIX 6 -#define SYSCONFPREFIX 7 -#define CONFIGPREFIX 8 -#define TROUBLEPREFIX 9 -#define PREFIX_COUNT 10 +#define HACKPREFIX 0 /* shared, RO */ +#define LEVELPREFIX 1 /* per-user, RW */ +#define SAVEPREFIX 2 /* per-user, RW */ +#define BONESPREFIX 3 /* shared, RW */ +#define DATAPREFIX 4 /* dungeon/dlb; must match value in dlb.c */ +#define SCOREPREFIX 5 /* shared, RW */ +#define LOCKPREFIX 6 /* shared, RW */ +#define SYSCONFPREFIX 7 /* shared, RO */ +#define CONFIGPREFIX 8 +#define TROUBLEPREFIX 9 /* shared or per-user, RW (append-only) */ +#define PREFIX_COUNT 10 /* used in files.c; xxconf.h can override if needed */ #ifndef FQN_MAX_FILENAME #define FQN_MAX_FILENAME 512 @@ -417,6 +417,10 @@ E struct plinemsg_type *plinemsg_types; E char *ARGV0; #endif +#ifdef DROPLEVEL +E void NDECL((*dropleveltempsfn)); +#endif + #undef E #endif /* DECL_H */ diff --git a/include/extern.h b/include/extern.h index 3d9c6c5f4..31be6f177 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1132,6 +1132,7 @@ E int FDECL(sleep_monst, (struct monst *, int, int)); E void FDECL(slept_monst, (struct monst *)); E void FDECL(xdrainenergym, (struct monst *, BOOLEAN_P)); E long FDECL(attk_protection, (int)); +E int FDECL(mdamagem, (struct monst *, struct monst *, struct attack *)); E void FDECL(rustm, (struct monst *, struct obj *)); /* ### mhitu.c ### */ @@ -1219,6 +1220,8 @@ E void NDECL(water_friction); E void FDECL(save_waterlevel, (int, int)); E void FDECL(restore_waterlevel, (int)); E const char *FDECL(waterbody_name, (XCHAR_P, XCHAR_P)); +E void NDECL(conway_update); +E void NDECL(conway_restore); /* ### mkobj.c ### */ diff --git a/include/global.h b/include/global.h index 0a4c76ac5..977d0aa58 100644 --- a/include/global.h +++ b/include/global.h @@ -350,4 +350,15 @@ struct savefile_info { #define PANICTRACE_GDB #endif +/* Only CONWAY requires this at the moment, but it should be generally useful. */ +#ifdef CONWAY +# define DROPLEVEL +#endif + +#ifdef DROPLEVEL +# define DROPLEVEL_WINDUP(fn) dropleveltempsfn = &fn; +# define DROPLEVEL_UNWIND(held) \ + dropleveltempsfn = held; held=0; if(dropleveltempsfn)(*dropleveltempsfn)(); +#endif + #endif /* GLOBAL_H */ diff --git a/include/rm.h b/include/rm.h index 5e7104898..d0bb36db3 100644 --- a/include/rm.h +++ b/include/rm.h @@ -560,6 +560,9 @@ struct levelflags { normal mode descendant of such) */ Bitfield(corrmaze, 1); /* Whether corridors are used for the maze rather than ROOM */ +#ifdef CONWAY + Bitfield(conway, 1); +#endif }; typedef struct { diff --git a/include/sp_lev.h b/include/sp_lev.h index 6c42d9aff..df2ca6bbd 100644 --- a/include/sp_lev.h +++ b/include/sp_lev.h @@ -32,6 +32,7 @@ #define CORRMAZE 0x00000800L /* for maze levels only */ #define CHECK_INACCESSIBLES 0x00001000L /* check for inaccessible areas and generate ways to escape from them */ +#define FLAG_CONWAY 0x00002000L /* avoid confusion with the value of CONWAY */ /* different level layout initializers */ #define LVLINIT_NONE 0 diff --git a/include/you.h b/include/you.h index 78a3a1334..59e782c1e 100644 --- a/include/you.h +++ b/include/you.h @@ -386,5 +386,7 @@ struct you { }; /* end of `struct you' */ #define Upolyd (u.umonnum != u.umonster) +/* something like MON_AT (rm.h) */ +#define HERO_AT(x,y) ((x)==u.ux && (y)==u.uy) #endif /* YOU_H */ diff --git a/src/allmain.c b/src/allmain.c index 33afd9927..90cbdb7ce 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -338,6 +338,9 @@ boolean resuming; } } restore_attrib(); +/* XXX This should be recoded to use something like regions - a list of + * things that are active and need to be handled that is dynamically + * maintained and not a list of special cases. */ /* underwater and waterlevel vision are done here */ if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) movebubbles(); @@ -348,6 +351,11 @@ boolean resuming; /* vision while buried done here */ else if (u.uburied) under_ground(0); +#ifdef CONWAY + if (level.flags.conway){ + conway_update(); + } +#endif /* when immobile, count is in turns */ if (multi < 0) { diff --git a/src/bones.c b/src/bones.c index 6784259c6..a0ebc4d49 100644 --- a/src/bones.c +++ b/src/bones.c @@ -19,7 +19,7 @@ STATIC_OVL boolean no_bones_level(lev) d_level *lev; { - extern d_level save_dlevel; /* in do.c */ + extern d_level save_dlevel; /* in do.c XXX */ s_level *sptr; if (ledger_no(&save_dlevel)) @@ -31,6 +31,9 @@ d_level *lev; in any dungeon (level 1 isn't multiway) */ || Is_botlevel(lev) || (Is_branchlev(lev) && lev->dlevel > 1) +#ifdef CONWAY + || level.flags.conway +#endif /* no bones in the invocation level */ || (In_hell(lev) && lev->dlevel == dunlevs_in_dungeon(lev) - 1)); diff --git a/src/decl.c b/src/decl.c index 479c075aa..962367e7b 100644 --- a/src/decl.c +++ b/src/decl.c @@ -336,6 +336,11 @@ struct plinemsg_type *plinemsg_types = (struct plinemsg_type *) 0; char *ARGV0; #endif +/* XXX see comment in save.c */ +#ifdef CONWAY +void NDECL((*dropleveltempsfn)) = 0; +#endif + /* support for lint.h */ unsigned nhUse_dummy = 0; diff --git a/src/dlb.c b/src/dlb.c index a0b675246..0f28b8b6f 100644 --- a/src/dlb.c +++ b/src/dlb.c @@ -9,7 +9,7 @@ #include #endif -#define DATAPREFIX 4 +#define DATAPREFIX 4 /* see decl.h */ #if defined(OVERLAY) #define STATIC_DCL extern diff --git a/src/do.c b/src/do.c index 5efa0da87..365079a0c 100644 --- a/src/do.c +++ b/src/do.c @@ -1284,6 +1284,11 @@ boolean at_stairs, falling, portal; getlev(fd, hackpid, new_ledger, FALSE); (void) nhclose(fd); oinit(); /* reassign level dependent obj probabilities */ +#ifdef CONWAY + if(level.flags.conway){ + conway_restore(); + } +#endif } reglyph_darkroom(); /* do this prior to level-change pline messages */ @@ -1505,6 +1510,10 @@ boolean at_stairs, falling, portal; } else { if (new && Is_rogue_level(&u.uz)) You("enter what seems to be an older, more primitive world."); +#ifdef CONWAY + if (level.flags.conway) + You("feel the rules of Life are different here."); +#endif /* main dungeon message from your quest leader */ if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && !(u.uevent.qcompleted || u.uevent.qexpelled diff --git a/src/makemon.c b/src/makemon.c index b38f64fa4..2edaf974d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1678,6 +1678,7 @@ struct monst *mtmp, *victim; /* monster died after killing enemy but before calling this function */ /* currently possible if killing a gas spore */ + /* Also used to abort processing for CONWAYS's mildew temp monsters. */ if (mtmp->mhp <= 0) return (struct permonst *) 0; diff --git a/src/mhitm.c b/src/mhitm.c index b52c6f226..5b9cbf9c2 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -23,8 +23,6 @@ STATIC_DCL int FDECL(gulpmm, (struct monst *, struct monst *, struct attack *)); STATIC_DCL int FDECL(explmm, (struct monst *, struct monst *, struct attack *)); -STATIC_DCL int FDECL(mdamagem, (struct monst *, struct monst *, - struct attack *)); STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *)); STATIC_DCL void FDECL(noises, (struct monst *, struct attack *)); @@ -724,7 +722,7 @@ struct attack *mattk; /* * See comment at top of mattackm(), for return values. */ -STATIC_OVL int +int mdamagem(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; diff --git a/src/mklev.c b/src/mklev.c index 6fd50f7fe..75942be37 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -625,6 +625,9 @@ clear_level_structures() level.flags.arboreal = 0; level.flags.wizard_bones = 0; level.flags.corrmaze = 0; +#ifdef CONWAY + level.flags.conway = 0; +#endif nroom = 0; rooms[0].hx = -1; diff --git a/src/mkmaze.c b/src/mkmaze.c index 130d5c7df..2f3f5eaf2 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -25,6 +25,10 @@ STATIC_DCL void NDECL(baalz_fixup); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); +#ifdef CONWAY +STATIC_DCL void NDECL(conway_setup); +#endif + /* adjust a coordinate one step in the specified direction */ #define mz_move(X, Y, dir) \ do { \ @@ -612,6 +616,11 @@ fixup_special() /* custom wallify the "beetle" potion of the level */ baalz_fixup(); } +#ifdef CONWAY + if(level.flags.conway){ + conway_setup(); + } +#endif if (lregions) free((genericptr_t) lregions), lregions = 0; @@ -1606,4 +1615,382 @@ register boolean ini; } } +#ifdef CONWAY +/* Hero has just stumbled into Conway's game of Life - which in NH is a + * rather dangerous place. I hope. */ + +/* Temp storage for the next generation. The normal game state is always used + * for the current generation since it changes outside of life's control. */ +static char (*ls)[COLNO][ROWNO]; /* life state */ +static int (*lslev)[COLNO][ROWNO]; /* total level of surrounding life */ + +/* Conway's Life was binary: alive or dead. Here it's a little more complex. */ +static int +conway_islive(lvlp, x, y) + int *lvlp; + int x,y; +{ + struct monst *mhere; + /* Hero's levels don't count here since it's likely to be + * much larger than the surrounding life. */ + if(u.ux == x && u.uy == y){ + if(Upolyd && nonliving(youmonst.data)) return 0; + return 1; + } + + mhere = m_at(x,y); + if(!mhere) return 0; + if(nonliving(mhere->data)) return 0; + if(lvlp) *lvlp += mhere->m_lev; + return 1; +} + +static struct lifelimits { + int xmin,xmax; + int ymin,ymax; +} lls; + +/* Find the bounds of the rectangular area where we will play life. */ +static void +conway_findactive(){ + lls.xmin = 0; + lls.ymin = 0; + lls.xmax = COLNO-1; + lls.ymax = ROWNO-1; +/* XXX is this test correct? */ +/* #define CONWAY_WALL(x,y) IS_ROCK(levl[x][y].typ) */ +#define CONWAY_WALL(x,y) (levl[x][y].wall_info & W_NONDIGGABLE) + while(CONWAY_WALL(lls.xmin, ROWNO/2) && lls.xmin < COLNO/2) + lls.xmin++; + while(CONWAY_WALL(COLNO/2, lls.ymin) && lls.ymin < ROWNO/2) + lls.ymin++; + while(CONWAY_WALL(lls.xmax, ROWNO/2) && lls.xmax > COLNO/2) + lls.xmax--; + while(CONWAY_WALL(COLNO/2, lls.ymax) && lls.ymax > ROWNO/2) + lls.ymax--; +#undef CONWAY_WALL + if(lls.xmin > COLNO/2 || lls.ymin > ROWNO/2 || + lls.xmax < COLNO/2 || lls.ymax < ROWNO/2) + panic("can't find active area in level"); +} + +static void NDECL((*helddroplevel)) = 0; + +/* Leaving the level - get rid of our scratchpad. */ +static void +conway_cleanup(){ + if(ls){ + free(ls); + } + if(lslev){ + free(lslev); + } + DROPLEVEL_UNWIND(helddroplevel); +} + +/* Entering / reentering the level. */ +void +conway_restore(){ + DROPLEVEL_WINDUP(conway_cleanup); + ls = (char(*)[COLNO][ROWNO])alloc(sizeof(char[COLNO][ROWNO])); + lslev = (int(*)[COLNO][ROWNO])alloc(sizeof(int[COLNO][ROWNO])); + conway_findactive(); +} + +/* First entry into the level. */ +void +conway_setup(){ + int cnt; + int subtype = rn2(3); + char *force = nh_getenv("SPLEVTYPE2"); + conway_restore(); + if(force){ + int tmp = atoi(force); + if(tmp>=0 && tmp <=2) subtype = tmp; + } + switch(subtype){ + case 0: /* just the normal bigroom population */ + break; + case 1: /* extra mildews to start */ + /* TUNE ME! */ + cnt = (lls.xmax-lls.xmin+1) * (lls.ymax-lls.ymin+1) / 32; + + while(cnt--){ + /* XXX is flags correct? */ + (void) makemon(&mons[PM_MILDEW], 0, 0, MM_NOCOUNTBIRTH); + } + break; + case 2: /* a glider */ + /* XXX need to add to this - pick multiple of multiple known + * configurations in multiple orientations - later */ + { + int x = 3 + rn2(lls.xmax-lls.xmin - 5); /* prevent wrapping */ + int y = 3 + rn2(lls.ymax-lls.ymin - 5); + (void)makemon(&mons[PM_MILDEW], x, y+2, MM_NOCOUNTBIRTH); + (void)makemon(&mons[PM_MILDEW], x+1,y+2, MM_NOCOUNTBIRTH); + (void)makemon(&mons[PM_MILDEW], x+2,y+2, MM_NOCOUNTBIRTH); + (void)makemon(&mons[PM_MILDEW], x+1, y, MM_NOCOUNTBIRTH); + (void)makemon(&mons[PM_MILDEW], x+2,y+1, MM_NOCOUNTBIRTH); + } + break; + } +} + +static int +LIMIT(n, lbound, ubound) + int n; + int lbound, ubound; +{ + int rv; + if(nubound){ + rv = lbound; + } else { + rv = n; + } + } + return rv; +} + +static int +conway_islive_wrap(lvlp, x, y) + int *lvlp; + int x; + int y; +{ + return conway_islive(lvlp, + LIMIT(x, lls.xmin, lls.xmax), + LIMIT(y, lls.ymin, lls.ymax)); +} + +static struct monst * +conway_random_neighbor(x,y) + int x,y; +{ +#define LRN(a,b) if(conway_islive_wrap(NULL, a, b))return m_at(a,b); + int mutation[8]; + int ndx; + int last=8; + for(ndx=0;ndx<8;ndx++)mutation[ndx] = ndx; + for(ndx=0;ndx<8;ndx++){ + int entry = rn2(last); + int pick = mutation[entry]; + last--; + mutation[entry] = mutation[last]; + switch(pick){ + case 0: LRN(x-1, y-1); break; + case 1: LRN(x, y-1); break; + case 2: LRN(x+1, y-1); break; + case 3: LRN(x-1, y ); break; + case 4: LRN(x+1, y ); break; + case 5: LRN(x-1, y+1); break; + case 6: LRN(x, y+1); break; + case 7: LRN(x+1, y+1); break; + default: impossible("no neighbor in a crowd"); + } + } + return NULL; +#undef LRN +} + +/* +Implement the normal Conway algorithm. Undead are not alive. Anything lower +level than the sum of the life monsters around it is absorbed (ala The Borg/The +Blob) and not just continued into the next generation. This of course includes +the hero. +*/ +void +conway_update(){ + int x, y; + + /* Be unpredictable: Life updates about half of the time, but not on + alternate moves. */ + if(monstermoves % 16 < 5) return; + if(rn2(11) < 3) return; + /* first, figure out what changes are needed for the next generation */ + for(x=lls.xmin; x<=lls.xmax; x++){ + for(y=lls.ymin; y<=lls.ymax; y++){ + *lslev[x][y] = 0; /* total levels of live neighbors */ +#ifdef notyet +/* +This isn't needed unless there are interior wall features or other places +we don't want to put a monster. + if( this is not a legal position for a monster){ + ls[x][y] = 99; /* flag for no action */ + continue; + } +*/ +#endif + + /* count neighbors (and their levels) */ + *ls[x][y] = + conway_islive_wrap(&*lslev[x][y], x-1, y-1) + + conway_islive_wrap(&*lslev[x][y], x, y-1) + + conway_islive_wrap(&*lslev[x][y], x+1, y-1) + + conway_islive_wrap(&*lslev[x][y], x-1, y ) + + conway_islive_wrap(&*lslev[x][y], x+1, y ) + + conway_islive_wrap(&*lslev[x][y], x-1, y+1) + + conway_islive_wrap(&*lslev[x][y], x, y+1) + + conway_islive_wrap(&*lslev[x][y], x+1, y+1); + /*pline("R(%d %d)=%d(%d) ",x,y,ls[x][y],lslev[x][y]);*/ + } + } + + /* now apply the changes to the game state */ +/*#define LDEBUG*/ +#ifdef LDEBUG + int counts[10]={0,0,0,0,0,0,0,0,0}; + /*pline("bounds: (%d,%d)-(%d,%d)", lls.xmin,lls.ymin,lls.xmax,lls.ymax); + (void) makemon(&mons[PM_GRID_BUG], lls.xmin, lls.ymin, MM_NOCOUNTBIRTH); + (void) makemon(&mons[PM_GRID_BUG], lls.xmax, lls.ymax, MM_NOCOUNTBIRTH);*/ +#endif + +#define DO_DIE_NOTHING 0 +#define DO_DIE_LONELY 1 +#define DO_DIE_CROWD 2 +#define DO_LIVE 3 + + for(x=lls.xmin; x<=lls.xmax; x++){ + for(y=lls.ymin; y<=lls.ymax; y++){ + struct monst *mhere; + int action = DO_DIE_NOTHING; +#ifdef LDEBUG + counts[ls[x][y]]++; +#endif + switch(*ls[x][y]){ +#ifdef notyet + case 99: /* special case: forced no action */ + break; +#endif + /* die of loneliness */ + case 0: + case 1: + action = DO_DIE_LONELY; + break; + /* make/continue life */ + case 2: + case 3: + action = DO_LIVE; + break; + /* die of overcrowding */ + case 4: + case 5: + case 6: + case 7: + case 8: + action = DO_DIE_CROWD; + break; + default: + panic("bad neighbor count"); + } + + switch(action){ + case DO_DIE_NOTHING: + break; + case DO_DIE_LONELY: + case DO_DIE_CROWD: + if(MON_AT(x,y)){ + struct monst *mp = m_at(x,y); + if(mp->data == &mons[PM_MILDEW]){ + /* mildew: just play life */ + monkilled(mp, NULL, AD_ANY); + } else { + /* others get drained first */ + struct monst *dummy_m; + struct attack dummy_a = { AT_ANY, AD_DRLI, 0, 0 }; + if(action == DO_DIE_CROWD){ + dummy_m = conway_random_neighbor(x,y); + } else { + dummy_m = newmonst(); + (void) memset( (genericptr_t)dummy_m, 0, sizeof(*dummy_m)); + dummy_m->data = &mons[PM_MILDEW]; + } + (void)mdamagem(dummy_m, mp, &dummy_a); + if(action != DO_DIE_CROWD){ + free(dummy_m); + } + } + } else { + if(HERO_AT(x,y)){ + /* hero takes damage - modified drain level + * from mhitu.c:hitmu(): */ + if (rn2(100) < 10 && !Drain_resistance) { + if(action == DO_DIE_CROWD){ +/* XXX these messages could be expanded */ + if(Hallucination){ + if(Role_if(PM_SAMURAI)) + pline("This is just like the Tokyo subway."); + else + pline("You are too near the madding crowd."); + } else { + pline("You feel crowded here."); + } + } else { + if(Hallucination){ + pline("I feel so lonely, I could die."); /* Elvis */ + } else { + pline("It seems lonely here."); + } + } + losexp("Life drainage"); + } + } + } + break; + case DO_LIVE: + /* continue(2/3) or create(3) */ + mhere = m_at(x,y); + if(mhere){ +/* +Check the level of the surrounding monsters that are life vs the level +of the monster at this point (which may be the hero). If the current +monster is lower level, get absorbed by the borg else (maybe) gain level. +*/ + if(mhere->data != &mons[PM_MILDEW]){ + /* The only justification for this intrinsic + * polymorph resistance is to avoid + * insta-death for pets. */ + if(*lslev[x][y] > mhere->m_lev && rn2(100) < 20){ + newcham(mhere, &mons[PM_MILDEW], FALSE, TRUE); + } + } else { + /* Use rn2() instead of keeping track of + * the age of each mildew. */ + if(rn2(100) < 40) grow_up(mhere, NULL); + } + } else { + if(HERO_AT(x,y) && !Upolyd && (u.umonnum != PM_MILDEW)){ + if(*lslev[x][y] > u.ulevel){ + if( (Unchanging && rn2(3)) || (rn2(100) < 50) + ){ + pline("You resist the urge to regress."); + } else { + polymon(PM_MILDEW); + /* polymorph will always time out so hero + * isn't stuck if sitting in a stable life + * configuration */ + } + } + } else { + /* Nothing is here - birth. */ + if(*ls[x][y] == 3) + (void) makemon(&mons[PM_MILDEW], x, y, MM_NOCOUNTBIRTH); + } + } + break; + default: + impossible("conway action"); + } + } + } +#ifdef LDEBUG + pline("[%d %d %d %d %d %d %d %d %d %d] ", + counts[0], counts[1], counts[2], counts[3], counts[4], + counts[5], counts[6], counts[7], counts[8], counts[9]); +#endif +} +#endif + /*mkmaze.c*/ diff --git a/src/monst.c b/src/monst.c index 7839b06cc..8a4ce63f1 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1296,6 +1296,14 @@ NEARDATA struct permonst mons[] = { M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_BRIGHT_GREEN), + /* mildew: M1_NOEYES - should be blind but doesn't play well */ + MON("mildew", S_FUNGUS, + LVL(2, 1, 9, 0, 0), (G_NOGEN|G_NOCORPSE), + A(ATTK(AT_NONE, AD_STCK, 1, 2), /*ATTK(AT_TUCH, AD_STCK, 0, 0),*/ + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), + SIZ(20, 200, MS_SILENT, MZ_SMALL), 0, 0, + M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE|M1_REGEN|M1_OMNIVORE, + M2_HOSTILE|M2_NEUTER|M2_NASTY, 0, CLR_GRAY), MON("brown mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO | 1), A(ATTK(AT_NONE, AD_COLD, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), diff --git a/src/save.c b/src/save.c index 93b0d06c5..dc87151bf 100644 --- a/src/save.c +++ b/src/save.c @@ -545,6 +545,9 @@ skip_lots: save_regions(fd, mode); if (mode != FREE_SAVE) bflush(fd); +#ifdef DROPLEVEL + if(dropleveltempsfn) (*dropleveltempsfn)(); +#endif } STATIC_OVL void diff --git a/src/sp_lev.c b/src/sp_lev.c index 6f0445bd5..9fa5a095a 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2458,6 +2458,8 @@ region *tmpregion; } } +/* initialization common to all special levels */ +/* XXX dup name in mkmap.c */ void wallify_map(x1, y1, x2, y2) int x1, y1, x2, y2; @@ -3204,6 +3206,10 @@ struct sp_coder *coder; coder->solidify = TRUE; if (lflags & CORRMAZE) level.flags.corrmaze = TRUE; +#ifdef CONWAY + if (lflags & FLAG_CONWAY) + level.flags.conway = 1; +#endif if (lflags & CHECK_INACCESSIBLES) coder->check_inaccessibles = TRUE; diff --git a/sys/unix/Makefile.dat b/sys/unix/Makefile.dat index f0566650c..cd35a29c5 100644 --- a/sys/unix/Makefile.dat +++ b/sys/unix/Makefile.dat @@ -120,7 +120,8 @@ options: ../util/makedefs 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 bigroom.des + # This is the only file that needs preprocessing at the moment: + ../util/makedefs --input bigroom.des --output - --grep | ../util/lev_comp ../util/lev_comp castle.des ../util/lev_comp endgame.des ../util/lev_comp gehennom.des diff --git a/util/lev_comp.l b/util/lev_comp.l index d6ae1472e..fcaaf34af 100644 --- a/util/lev_comp.l +++ b/util/lev_comp.l @@ -297,6 +297,7 @@ hardfloor { savetoken(yytext); yylval.i=HARDFLOOR; return FLAG_TYPE; } nommap { savetoken(yytext); yylval.i=NOMMAP; return FLAG_TYPE; } arboreal { savetoken(yytext); yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */ shortsighted { savetoken(yytext); yylval.i=SHORTSIGHTED; return FLAG_TYPE; } +conway { savetoken(yytext); yylval.i=FLAG_CONWAY; return FLAG_TYPE; } mazelevel { savetoken(yytext); yylval.i=MAZELEVEL; return FLAG_TYPE; } premapped { savetoken(yytext); yylval.i=PREMAPPED; return FLAG_TYPE; } shroud { savetoken(yytext); yylval.i=SHROUD; return FLAG_TYPE; } diff --git a/util/makedefs.c b/util/makedefs.c index 6ae0cefc9..45a2bb6c2 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -548,6 +548,18 @@ do_ext_makedefs(int argc, char **argv) } CONTINUE; } + IS_OPTION("grep-test"){ + struct grep_var *p; + CONSUME; + p = grepsearch(argv[0]); + if(p && p->is_defined){ + exit(EXIT_SUCCESS); + } else { + exit(EXIT_FAILURE); + } + CONTINUE; /* NOTREACHED */ + } + #ifdef notyet IS_OPTION("help") { } @@ -611,6 +623,7 @@ do_ext_makedefs(int argc, char **argv) #define GREP_STACK_SIZE 100 #ifdef notyet static int grep_rewrite = 0; /* need to (possibly) rewrite lines */ +static char rewrite_stack[GREP_STACK_SIZE] = {GREP_MAGIC}; #endif static int grep_writing = 1; /* need to copy lines to output */ static int grep_errors = 0; @@ -748,6 +761,7 @@ char *buf; break; #if defined(notyet) case '(': /* start of expression */ + case '@': /* substitution facility: @[ @] */ #endif case GREP_MAGIC: /* ^^ -> ^ */ return buf0; @@ -1422,7 +1436,7 @@ static const char *build_opts[] = { #ifdef COM_COMPL "command line completion", #endif -#ifdef LIFE +#ifdef CONWAY "Conway's Game of Life", #endif #ifdef COMPRESS diff --git a/util/mdgrep.h b/util/mdgrep.h index 382da338c..cf2ca6cbd 100644 --- a/util/mdgrep.h +++ b/util/mdgrep.h @@ -1,12 +1,13 @@ /* - * NetHack 3.6 mdgrep.h $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ + * NetHack 3.6 mdgrep.h $NHDT-Date: 1423877529 2015/02/14 01:32:09 $ $NHDT-Branch$:$NHDT-Revision: 1.7 $ * Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008 * NetHack may be freely redistributed. See license for details. * * This file generated by mdgrep.pl version 1.7. * DO NOT EDIT! Your changes will be lost. */ -static struct grep_var grep_vars[] = { { "0", 0 }, +static struct grep_var grep_vars[] = { + { "0", 0 }, { "1", 1 }, #if defined(ALLDOCS) { "ALLDOCS", 1 }, @@ -48,6 +49,11 @@ static struct grep_var grep_vars[] = { { "0", 0 }, #else { "COMPRESS", 0 }, #endif +#if defined(CONWAY) + { "CONWAY", 1 }, +#else + { "CONWAY", 0 }, +#endif #if defined(DLB) { "DLB", 1 }, #else @@ -74,11 +80,6 @@ static struct grep_var grep_vars[] = { { "0", 0 }, #else { "INSURANCE", 0 }, #endif -#if defined(LIFE) - { "LIFE", 1 }, -#else - { "LIFE", 0 }, -#endif #if defined(MAC) { "MAC", 1 }, #else @@ -255,7 +256,6 @@ static struct grep_var grep_vars[] = { { "0", 0 }, #else { "WIN_CE_SMARTPHONE", 0 }, #endif - { "WIZARD", 1 }, #if defined(X11_GRAPHICS) { "X11_GRAPHICS", 1 }, #else @@ -276,7 +276,8 @@ static struct grep_var grep_vars[] = { { "0", 0 }, #else { "__BEOS__", 0 }, #endif - { 0, 0 } }; + { 0, 0 } +}; /* Command ids */ #define TODO_GREP 1 diff --git a/util/mdgrep.pl b/util/mdgrep.pl index 429c87374..c23cb0adb 100644 --- a/util/mdgrep.pl +++ b/util/mdgrep.pl @@ -3,6 +3,14 @@ # Copyright (c) Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. +### +### NOTE: We do not require Perl at build time, so if you change this file +### you MUST rebuild mdgrep.h with: +### cd util; make mdgreph +### BUT: Makefile.dat only makes sure makedefs exists, it doesn't assure it +### is up to date, so as a practical matter you should make clean. XXX +### + # MAKEDEFS: @commands = qw/grep/; @@ -22,7 +30,7 @@ SAFERHANGUP MFLOPPY NOCWD_ASSUMPTIONS VAR_PLAYGROUND DLB SHELL SUSPEND NOSAVEONHANGUP HANGUPHANDLING BSD_JOB_CONTROL MAIL POSIX_JOB_CONTROL INSURANCE - UNICODE_DRAWING UNICODE_WIDEWINPORT UNICODE_PLAYERTEXT + UNICODE_DRAWING UNICODE_WIDEWINPORT UNICODE_PLAYERTEXT CONWAY /; # Miscellaneous @@ -89,23 +97,23 @@ sub gen_magic { # NB: Do NOT make grep_vars const - it needs to be writable for some debugging # options. sub gen_file { - print OUT "static struct grep_var grep_vars[]={\n"; + print OUT "static struct grep_var grep_vars[] = {\n"; foreach(@_){ if(defined $magic{$_}){ print OUT <