1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-27 14:37:16 +00:00

brownian:: more serious work

This commit is contained in:
Zeno Rogue 2018-10-25 02:43:14 +02:00
parent 0a886f6a67
commit 74ad8ea135
13 changed files with 236 additions and 55 deletions

View File

@ -121,7 +121,7 @@ bool grailWasFound(cell *c) {
void generateAlts(heptagon *h, int levs, bool link_cdata) {
if(!h->alt) return;
preventbarriers(h->c7);
for(int i=0; i<S7; i++) preventbarriers(h->c7->move(i));
forCellEx(c2, h->c7) preventbarriers(c2);
if(GOLDBERG)
for(int i=0; i<S7; i++) preventbarriers(createStep(h, i)->c7);
for(int i=0; i<S7; i++)
@ -448,7 +448,7 @@ int coastval(cell *c, eLand base) {
}
else {
if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool ||
c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken || c->land == laDocks)
c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken || c->land == laDocks || c->land == laBrownian)
return 30;
if(c->land != laOcean && !isGravityLand(c->land) && c->land != laHaunted) {
return 0;
@ -1185,6 +1185,12 @@ void buildCamelotWall(cell *c) {
}
}
bool no_barriers_in_radius(cell *c, int rad) {
celllister cl(c, 2, 1000000, NULL);
for(cell *c: cl.lst) if(c->bardir != NODIR) return false;
return true;
}
void buildCamelot(cell *c) {
int d = celldistAltRelative(c);
if(tactic::on || (d <= 14 && roundTableRadius(c) > 20)) {
@ -1273,6 +1279,9 @@ void moreBigStuff(cell *c) {
if(c->land == laCanvas && !eubinary && c->master->alt && !quotient)
generateAlts(c->master);
if(c->land == laOcean && !generatingEquidistant && hrand(10000) < 10 && no_barriers_in_radius(c, 2))
brownian::init(c);
if(c->land == laStorms)
if(!eubinary && !quotient && !sphere) {
if(c->master->alt && c->master->alt->distance <= 2) {
@ -1348,7 +1357,7 @@ void moreBigStuff(cell *c) {
}
}
if(c->land == laOcean || c->land == laWhirlpool) if(!(binarytiling && specialland != laWhirlpool)) {
if(among(c->land, laOcean, laWhirlpool, laBrownian)) if(!(binarytiling && specialland != laWhirlpool)) {
bool fullwhirlpool = false;
if(tactic::on && specialland == laWhirlpool)
fullwhirlpool = true;

View File

@ -778,6 +778,8 @@ monstertype minf[motypes] = {
"for a long time. This attack can destroy other Raiders if it hits them."},
{ '@', 0xC00000, "Red Jelly", jellydesc},
{ '@', 0x0000C0, "Blue Jelly", jellydesc},
{ 'B', 0xE07000, "Brown Bug", NODESCYET},
{ 'B', 0xE07060, "Acid Bird", NODESCYET},
// shmup specials
{ '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."},
@ -1238,6 +1240,9 @@ itemtype iinf[ittypes] = {
{ 'o', 0x202020, "Orb of Slaying",
"This Orb lets you defeat Raiders and other tough single-cell monsters in melee."
},
{ '*', 0x20C0C0, "Brownie",
"Tasty cookie."
},
// { '*', 0x26619C, "Lapis Lazuli", NODESCYET},
};

View File

@ -10,7 +10,7 @@ static inline void set_flag(flagtype& f, flagtype which, bool b) {
else f &= ~which;
}
static const int motypes = 162;
static const int motypes = 164;
struct monstertype {
char glyph;
@ -67,6 +67,7 @@ enum eMonster {
moNorthPole, moSouthPole,
moPair, moHexDemon, moAltDemon, moMonk, moCrusher,
moSwitch1, moSwitch2,
moBrownBug, moAcidBird,
// shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball, moCrushball,
// temporary
@ -83,7 +84,7 @@ struct genderswitch_t {
#define NUM_GS 6
static const int ittypes = 130;
static const int ittypes = 131;
struct itemtype {
char glyph;
@ -129,7 +130,8 @@ enum eItem {
itOrbSide1, itOrbSide2, itOrbSide3,
itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
itDock, itRuins, itMagnet, itSwitch,
itOrbPhasing, itOrbMagnetism, itOrbSlaying
itOrbPhasing, itOrbMagnetism, itOrbSlaying,
itBrownian
};
static const int walltypes = 109;

View File

@ -41,6 +41,9 @@
#include "flags.cpp"
#include "yendor.cpp"
#include "complex.cpp"
#if CAP_COMPLEX2
#include "complex2.cpp"
#endif
#include "savemem.cpp"
#include "game.cpp"
#include "orbgen.cpp"

122
complex2.cpp Normal file
View File

@ -0,0 +1,122 @@
// Hyperbolic Rogue
// namespaces for complex features (whirlwind, whirlpool, elec, princess, clearing,
// mirror, hive, heat + livecaves, etc.)
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
#ifdef CAP_COMPLEX2
namespace hr {
namespace brownian {
map<cell*, vector<pair<cell*, bool >> > futures;
int centersteps = 0;
int totalsteps = 0;
void rise(cell *c, int val) {
if(c->wall == waSea) c->wall = waNone;
if(c->land == laOcean || c->land == laNone) {
c->land = laBrownian;
c->landparam = 0;
}
c->bardir = NOBARRIERS;
forCellCM(c1, c) {
c1->bardir = NOBARRIERS;
if(c1->mpdist > BARLEV) {
setdist(c1, BARLEV, c);
}
if(c1->land == laOcean) {
c1->land = laBrownian;
c1->landparam = 0;
}
}
c->landparam += val;
}
void recurse(cell *c, bool fat) {
while(true) {
totalsteps++;
if(celldist(c) >= (fat ? 30 : 20) + celldist(cwt.at)) {
cell *c1 = c;
while(true) {
cell *c2 = ts::left_parent(c1, celldist);
if(!c2 || c2->mpdist < BARLEV) break;
setdist(c2, BARLEV, c1);
if(c2->land == laOcean) {
c2->land = laBrownian;
c2->landparam = 0;
}
c1 = c2;
}
futures[c1].emplace_back(c, fat);
return;
}
if(c->mpdist <= 7) { centersteps++; return; }
// while(hrand(1000) < 1000 * chance) recurse(c);
if(fat) recurse(c, false);
if(!fat && hrand(100000) == 0) recurse(c, true);
rise(c, fat ? 256 : 1);
c = c->cmove(hrand(c->type));
}
}
void dissolve_brownian(cell *c, int x) {
if(c->land == laBrownian) {
if(among(c->wall, waNone, waStrandedBoat, waMineOpen, waFire)) {
if(c->landparam >= 4 * level) c->landparam = 4 * level - 1;
c->landparam -= level * x;
c->wall = waNone;
if(c->landparam < 0) c->wall = waSea, c->landparam = 0;
if(c->landparam == 0) c->landparam = 1;
}
}
}
void dissolve(cell *c, int x) {
destroyTrapsAround(c);
if(c->land == laBrownian)
dissolve_brownian(c, x);
else if(c->wall == waRed2) c->wall = waRed1;
else if(c->wall == waRed3) c->wall = waRed2;
else if(among(c->wall, waRed1, waDeadfloor2, waRubble, waBoat, waFire, waCIsland, waCIsland2, waBigBush, waSmallBush)) c->wall = waNone;
else if(c->wall == waStrandedBoat) c->wall = waNone;
else if(c->wall == waFrozenLake) c->wall = waLake;
else if(among(c->wall, waReptile, waGargoyleFloor) || cellUnstable(c)) c->wall = waChasm;
else if(among(c->wall, waNone, waDock, waBurningDock, waFloorA, waFloorB, waCavefloor, waDeadfloor, waMineMine, waMineUnknown, waMineOpen, waOpenGate, waClosePlate, waOpenPlate, waGargoyleBridge, waReptileBridge))
c->wall = waSea;
else if(cellHalfvine(c)) destroyHalfvine(c, waNone, 4);
}
void init(cell *c) {
recurse(cwt.at, true);
recurse(cwt.at, true);
}
void build(cell *c, int d) {
if(futures.count(c)) {
for(pair <cell*, bool> p: futures[c])
recurse(p.first, p.second);
futures.erase(c);
printf("centersteps = %d futures = %d totalsteps = %d\n", centersteps, isize(futures), totalsteps);
}
ONEMPTY {
if(hrand(8000) < 50 && c->landparam >= 4 && c->landparam < 24)
c->item = itBrownian;
if(hrand(8000) < 30)
c->monst = moAcidBird;
else if(hrand(8000) < 30)
c->monst = moAlbatross;
else if(hrand(8000) < 30) {
c->monst = moBrownBug;
c->hitpoints = 3;
}
}
}
}
}
#endif

View File

@ -127,10 +127,9 @@ bool isMetalBeast(eMonster m) {
}
bool isStunnable(eMonster m) {
return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) ||
isMetalBeast(m) || m == moTortoise || isDragon(m) ||
m == moReptile || m == moTerraWarrior || m == moSalamander ||
m == moVizier;
return
isMetalBeast(m) || isDragon(m) || isPrincess(m) ||
among(m, moPalace, moFatGuard, moSkeleton, moTortoise, moReptile, moTerraWarrior, moSalamander, moVizier, moBrownBug);
}
bool hasHitpoints(eMonster m) {
@ -338,7 +337,12 @@ int snakelevel(eWall w) {
return 0;
}
int snakelevel(cell *c) { return snakelevel(c->wall); }
int snakelevel(cell *c) {
#if CAP_COMPLEX2
if(c->land == laBrownian && among(c->wall, waNone, waMineMine, waFire)) return min(c->landparam / brownian::level, 3);
#endif
return snakelevel(c->wall);
}
bool isWall(cell *w) {
if(w->wall == waNone || isAlchAny(w) ||
@ -365,7 +369,8 @@ bool isWall(cell *w) {
bool isAngryBird(eMonster m) {
return m == moEagle || m == moAlbatross || m == moBomberbird || m == moGargoyle ||
m == moWindCrow || m == moSparrowhawk ||
m == moVampire || m == moBat || m == moButterfly || m == moGadfly;
m == moVampire || m == moBat || m == moButterfly || m == moGadfly ||
m == moAcidBird;
}
bool isBird(eMonster m) {
@ -407,6 +412,7 @@ bool normalMover(eMonster m) {
m == moHunterGuard || m == moHunterChanging ||
m == moIceGolem ||
m == moSwitch1 || m == moSwitch2 || m == moCrusher || m == moPair ||
m == moBrownBug ||
isMagneticPole(m) ||
slowMover(m);
}

View File

@ -376,6 +376,7 @@ int* killtable[] = {
&kills[moSalamander], &kills[moLavaWolf],
&kills[moSwitch1], &kills[moSwitch2],
&kills[moMonk], &kills[moCrusher], &kills[moHexDemon], &kills[moAltDemon], &kills[moPair],
&kills[moBrownBug], &kills[moAcidBird],
NULL
};
@ -1694,6 +1695,19 @@ bool earthWall(cell *c) {
}
bool snakepile(cell *c, eMonster m) {
if(c->land == laBrownian) {
if(c->wall == waNone) {
#if CAP_COMPLEX2
c->landparam += brownian::level;
#endif
return true;
}
if(c->wall == waSea || c->wall == waBoat) {
c->wall = waNone;
c->landparam++;
return true;
}
}
if(c->item && c->wall != waRed3) c->item = itNone;
if(c->wall == waRed1 || c->wall == waOpenGate) c->wall = waRed2;
else if(c->wall == waRed2) c->wall = waRed3;
@ -1821,11 +1835,12 @@ void explodeMine(cell *c) {
drawFireParticles(c, 30, 150);
c->wall = waMineOpen;
brownian::dissolve_brownian(c, 2);
makeflame(c, 20, false);
for(int i=0; i<c->type; i++) if(c->move(i)) {
cell *c2 = c->move(i);
forCellEx(c2, c) {
destroyTrapsOn(c2);
brownian::dissolve_brownian(c2, 1);
if(c2->wall == waRed2 || c2->wall == waRed3)
c2->wall = waRed1;
else if(c2->wall == waDeadTroll || c2->wall == waDeadTroll2 || c2->wall == waPetrified || c2->wall == waGargoyle) {
@ -1875,9 +1890,9 @@ void stunMonster(cell *c2) {
c2->monst == moHedge ? 1 :
c2->monst == moFlailer ? 1 :
c2->monst == moSalamander ? 6 :
c2->monst == moBrownBug ? 3 :
3);
if(c2->monst != moSkeleton && !isMetalBeast(c2->monst) && c2->monst != moTortoise &&
c2->monst != moReptile && c2->monst != moSalamander) {
if(!isMetalBeast(c2->monst) && !among(c2->monst, moSkeleton, moReptile, moSalamander, moTortoise, moBrownBug)) {
c2->hitpoints--;
if(c2->monst == moPrincess)
playSound(c2, princessgender() ? "hit-princess" : "hit-prince");
@ -2077,9 +2092,11 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
playSound(c, "splash" + pick12());
destroyHalfvine(c);
minerEffect(c);
brownian::dissolve_brownian(c, 1);
for(int i=0; i<c->type; i++) if(passable(c->move(i), c, P_MONSTER | P_MIRROR | P_CLIMBUP | P_CLIMBDOWN)) {
destroyHalfvine(c->move(i));
minerEffect(c->move(i));
brownian::dissolve_brownian(c->move(i), 1);
if(c->move(i)->monst == moSlime || c->move(i)->monst == moSlimeNextTurn)
killMonster(c->move(i), who);
}
@ -2107,6 +2124,13 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
if(m == moVineBeast)
petrify(c, waVinePlant, m), pcount = 0;
if(isBird(m)) moveEffect(c, c, moDeadBird, -1);
if(m == moAcidBird) {
playSound(c, "die-bomberbird");
pcount = 64;
#if CAP_COMPLEX2
brownian::dissolve(c, 1);
#endif
}
if(m == moBomberbird || m == moTameBomberbird) {
pcount = 0;
playSound(c, "die-bomberbird");
@ -2149,6 +2173,10 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
if(doesFall(c)) fallingFloorAnimation(c, waRed1, m), pcount = 0;
else if(snakepile(c, m)) pcount = 0;
}
if(m == moBrownBug) {
if(doesFall(c)) ;
else if(snakepile(c, m)) pcount = 0;
}
if(m == moDarkTroll) {
playSound(c, "die-troll");
if(doesFall(c)) fallingFloorAnimation(c, waDeadwall, m), pcount = 0;
@ -2467,6 +2495,11 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
void pushMonster(cell *ct, cell *cf, int direction_hint) {
moveMonster(ct, cf, direction_hint);
if(ct->monst == moBrownBug) {
int t = snakelevel(ct) - snakelevel(cf);
if(t > 0)
ct->stuntime = min(ct->stuntime + 2 * t, 7);
}
}
bool destroyHalfvine(cell *c, eWall newwall, int tval) {
@ -3579,6 +3612,8 @@ void moveMonster(cell *ct, cell *cf, int direction_hint) {
if(isMetalBeast(m)) ct->stuntime += 2;
if(m == moTortoise) ct->stuntime += 3;
if(m == moDraugr && ct->land != laBurial && ct->land != laHalloween) ct->stuntime += 2;
if(m == moBrownBug && snakelevel(ct) < snakelevel(cf)) ct->stuntime += 2;
if(m == moBrownBug && snakelevel(ct) < snakelevel(cf) - 1) ct->stuntime += 2;
}
if(isWitch(m) && ct->item == itOrbLife && passable(cf, NULL, P_MIRROR)) {
@ -3812,7 +3847,10 @@ int moveval(cell *c1, cell *c2, int d, flagtype mf) {
if((mf & MF_PATHDIST) && !pathlock) printf("using MF_PATHDIST without path\n");
if(hunt && (mf & MF_PATHDIST) && c2->pathdist < c1->pathdist && !peace::on) return 1500; // good move
int bonus = 0;
if(m == moBrownBug && snakelevel(c2) < snakelevel(c1)) bonus = -10;
if(hunt && (mf & MF_PATHDIST) && c2->pathdist < c1->pathdist && !peace::on) return 1500 + bonus; // good move
// prefer straight direction when wandering
int dd = angledist(c1, c1->mondir, d);
@ -5181,9 +5219,7 @@ int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
val =
(m == moPrincessArmed && isPrincess(c2->monst)) ? 14000 : // jealousy!
isActiveEnemy(c2,m) ? 12000 :
(c2->monst == moSkeleton || c2->monst == moMetalBeast ||
c2->monst == moReptile || c2->monst == moTortoise ||
c2->monst == moSalamander || c2->monst == moTerraWarrior) ? -400 :
among(c2->monst, moSkeleton, moMetalBeast, moReptile, moTortoise, moSalamander, moTerraWarrior, moBrownBug) ? -400 :
isIvy(c2) ? 8000 :
isInactiveEnemy(c2,m) ? 1000 :
-500;

View File

@ -1252,7 +1252,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, color_t col,
queuepoly(VFISH, shShark, darkena(col, 0, 0xFF));
else if(m == moEagle || m == moParrot || m == moBomberbird || m == moAlbatross ||
m == moTameBomberbird || m == moWindCrow || m == moTameBomberbirdMoved ||
m == moSandBird) {
m == moSandBird || m == moAcidBird) {
ShadowV(V, shEagle);
queuepoly(VBIRD, shEagle, darkena(col, 0, 0xFF));
}
@ -1695,7 +1695,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, color_t col,
queuepolyat(VBODY * spin(M_PI), shTentacle, 0x000000C0, PPR::TENTACLE1);
queuepolyat(VBODY, shDisk, darkena(col, 0, 0xFF), PPR::MONSTER_BODY);
}
else if(isMetalBeast(m)) {
else if(isMetalBeast(m) || m == moBrownBug) {
ShadowV(V, shTrylobite);
if(!mmspatial)
queuepoly(VABODY, shTrylobite, darkena(col, 1, 0xC0));
@ -2852,6 +2852,7 @@ void setcolors(cell *c, color_t& wcol, color_t& fcol) {
// gradient(0xFF8000, 0xFFF000, 2*level, c->landparam, 3*level-1) :
0xC00000;
break;
}
#endif
case laVolcano: {
@ -3503,6 +3504,7 @@ int getfd(cell *c) {
case laPalace:
case laCA:
case laDual:
case laBrownian:
return 1;
case laTrollheim:
@ -4308,6 +4310,13 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
set_towerfloor(c);
break;
case laBrownian:
if(among(c->wall, waSea, waBoat))
set_floor(shCloudFloor);
else
set_floor(shFloor);
break;
default:
set_floor(shFloor);
}
@ -4524,7 +4533,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
case waFrozenLake: case waLake: case waCamelotMoat:
case waSea: case waOpenGate: case waBubble: case waDock:
case waNone: case waSulphur: case waMercury:
case waSulphur: case waMercury:
break;
case waNone:
if(c->land == laBrownian) goto wa_default;
break;
case waRose: {

View File

@ -4601,7 +4601,7 @@ struct exp_parser {
};
#ifdef CAP_COMPLEX2
#if CAP_COMPLEX2
namespace brownian {
const int level = 5;
void init(cell *c);

View File

@ -101,37 +101,10 @@ eMonster genRuinMonster(cell *c) {
return m;
}
void start_brownian(cell *c, int d) {
while(true) {
if(c->wall == waBrownian) c->wall = waNone;
c->landparam++;
// snakepile(c, moRedTroll);
// c->wall = waSea;
c->bardir = NOBARRIERS;
if(d == 0) {
if(c->mpdist >= BARLEV) {
c->wall = waBrownian;
return;
}
start_brownian(c, 1);
d = 1;
continue;
}
int q = 0;
cell *good = NULL;
forCellCM(c2, c)
if(c2->mpdist > 7 && (c2->land == laBrownian || c2->land == laNone)) {
q++;
if(q==1 || hrand(q) == 0) good = c2;
}
if(!q) break;
d++; if(d == 7) d = 0;
c = good;
}
}
// the giant switch generating most of the lands...
void gen_brownian(cell *c);
void giantLandSwitch(cell *c, int d, cell *from) {
switch(c->land) {
@ -2183,8 +2156,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
break;
case laBrownian:
if(c->wall == waBrownian || (d == 9 && hrand(10000) < 5))
start_brownian(c, 0);
brownian::build(c, d);
break;
case laMirrored:
@ -2405,6 +2377,7 @@ void setdist(cell *c, int d, cell *from) {
if(c->land == laClearing && !tactic::on) setland(c, laOvergrown);
if(c->land == laWhirlpool && !tactic::on && !yendor::on) setland(c, laOcean);
if(c->land == laCamelot && !tactic::on) setland(c, laCrossroads);
if(c->land == laBrownian && !tactic::on && !chaosmode) setland(c, laOcean);
#if CAP_DAILY
if(!daily::on) {

View File

@ -232,6 +232,8 @@ int isNative(eLand l, eMonster m) {
eItem treasureType(eLand l) {
switch(l) {
case laBrownian:
return itBrownian;
case laIce: return itDiamond;
case laJungle: return itRuby;
case laCaves: return itGold;

View File

@ -249,6 +249,14 @@
#define CAP_SHMUP_GOOD (!ISMOBWEB)
#endif
#ifndef CAP_BONUS
#define CAP_BONUS 0
#endif
#ifndef CAP_COMPLEX2
#define CAP_COMPLEX2 CAP_BONUS
#endif
#if ISMOBILE
#define EXTRALICENSE "\n\nHyperRogue soundtrack by Shawn Parrotte (http://www.shawnparrotte.com), under the Creative Commons BY-SA 3.0 license, http://creativecommons.org/licenses/by-sa/3.0/"
#undef XEXTRALICENSE

View File

@ -132,6 +132,8 @@ void initgame() {
cwt.at = currentmap->gamestart(); cwt.spin = 0; cwt.mirrored = false;
cwt.at->land = firstland;
if(firstland == laBrownian) brownian::init(cwt.at);
chaosAchieved = false;
if(firstland == laElementalWall) cwt.at->land = randomElementalLand();