This commit is contained in:
keni
2016-06-16 13:32:50 -04:00
parent a8e1700f51
commit 83a0c37d13
27 changed files with 613 additions and 34 deletions

View File

@@ -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) {

View File

@@ -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));

View File

@@ -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;

View File

@@ -9,7 +9,7 @@
#include <string.h>
#endif
#define DATAPREFIX 4
#define DATAPREFIX 4 /* see decl.h */
#if defined(OVERLAY)
#define STATIC_DCL extern

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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(n<lbound){
rv = ubound;
} else {
if(n>ubound){
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*/

View File

@@ -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),

View File

@@ -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

View File

@@ -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;