variant:: first version

This commit is contained in:
Zeno Rogue 2018-12-17 00:04:59 +01:00
parent 4432b30b2a
commit 724d3516fa
10 changed files with 275 additions and 65 deletions

View File

@ -780,6 +780,7 @@ monstertype minf[motypes] = {
{ '@', 0x0000C0, "Blue Jelly", jellydesc},
{ 'B', 0xE07000, "Brown Bug", NODESCYET},
{ 'B', 0xE07060, "Acid Bird", NODESCYET},
{ 'W', 0xA04060, "Variant Warrior", NODESCYET},
// shmup specials
{ '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."},
@ -1243,6 +1244,8 @@ itemtype iinf[ittypes] = {
{ '*', 0x20C0C0, "Brownie",
"Tasty cookie."
},
{ '*', 0x20C0C0, "West Treasure", NODESCYET},
{ '*', 0xC020C0, "Variant Treasure", NODESCYET}
// { '*', 0x26619C, "Lapis Lazuli", NODESCYET},
};
@ -1424,7 +1427,9 @@ walltype winf[walltypes] = {
{ '=', 0x804000, "dock", "A dock."},
{ '^', 0xFF8000, "burning dock", "A burning dock."},
{ '#', 0xE04030, "ruin wall", ruindesc},
{ '#', 0xA04060, "Brownian generator", NODESC}
{ '#', 0xA04060, "Brownian generator", NODESC},
{ '^', 0xC05000, "fire trap", NODESC},
{ '^', 0xFD692F, "Explosive Barrel", NODESC},
};
// --- land types ---
@ -1621,7 +1626,9 @@ const landtype linf[landtypes] = {
"somehow. In the meantime, its memory has been cleared, since the 'remove faraway cells from the memory'"
" option was on."
},
{ 0xA04060, "Brownian", NODESCYET}
{ 0xA04060, "Brownian", NODESCYET},
{ 0xA04060, "West Wall", NODESCYET},
{ 0xA04060, "Variant", NODESCYET}
};
vector<landtacinfo> land_tac = {

View File

@ -10,7 +10,7 @@ static inline void set_flag(flagtype& f, flagtype which, bool b) {
else f &= ~which;
}
static const int motypes = 164;
static const int motypes = 165;
struct monstertype {
char glyph;
@ -67,7 +67,7 @@ enum eMonster {
moNorthPole, moSouthPole,
moPair, moHexDemon, moAltDemon, moMonk, moCrusher,
moSwitch1, moSwitch2,
moBrownBug, moAcidBird,
moBrownBug, moAcidBird, moVariantWarrior,
// shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball, moCrushball,
// temporary
@ -84,7 +84,7 @@ struct genderswitch_t {
#define NUM_GS 6
static const int ittypes = 131;
static const int ittypes = 133;
struct itemtype {
char glyph;
@ -131,10 +131,10 @@ enum eItem {
itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
itDock, itRuins, itMagnet, itSwitch,
itOrbPhasing, itOrbMagnetism, itOrbSlaying,
itBrownian
itBrownian, itWest, itVarTreasure
};
static const int walltypes = 109;
static const int walltypes = 111;
struct walltype {
char glyph;
@ -175,10 +175,11 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waTempBridgeBlocked,
waTerraWarrior, waBubble,
waArrowTrap, waMercury, waMagma,
waDock, waBurningDock, waRuinWall, waBrownian
waDock, waBurningDock, waRuinWall, waBrownian,
waFireTrap, waExplosiveBarrel
};
static const int landtypes = 85;
static const int landtypes = 87;
struct landtype {
color_t color;
@ -205,7 +206,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laMirrorOld,
laVolcano, laBlizzard, laHunting, laTerracotta, laMercuryRiver,
laDual, laSnakeNest, laDocks, laRuins, laMagnetic,
laSwitch, laMemory, laBrownian
laSwitch, laMemory, laBrownian, laWestWall, laVariant
};
enum eGeometry {

View File

@ -2084,6 +2084,10 @@ namespace heat {
newfires.emplace_back(c2, 12);
else if(cellHalfvine(c2) && last && last->wall == c2->wall)
newfires.emplace_back(c2, 12);
else if(c2->wall == waExplosiveBarrel)
newfires.emplace_back(c2, 12);
else if(c2->wall == waFireTrap)
newfires.emplace_back(c2, 12);
// both halfvines have to be near fire at once
last = c2;
}
@ -2108,13 +2112,26 @@ namespace heat {
}
if(c->wparam == 4) c->wparam = 0;
}
if(c->wall == waFireTrap && c->wparam && !shmup::on) {
c->wparam++;
if(c->wparam == 3) {
c->wall = waNone;
explosion(c, 5, 10);
}
}
}
for(int i=0; i<isize(newfires); i++) {
cell* c = newfires[i].first;
int qty = newfires[i].second;
qty /= 2;
if(c->wall == waBonfireOff) activateActiv(c, false);
if(c->wall == waExplosiveBarrel) explodeBarrel(c);
else if(c->wall == waFireTrap) {
if(c->wparam == 0) c->wparam = 1;
continue;
}
else if(c->wall == waBonfireOff) activateActiv(c, false);
else if(cellHalfvine(c)) destroyHalfvine(c, waPartialFire, 6);
else makeflame(c, qty, false);
if(c->wparam < qty) c->wparam = qty;

View File

@ -360,12 +360,16 @@ bool isWall(cell *w) {
w->wall == waSmallBush || w->wall == waBigBush ||
w->wall == waReptile || w->wall == waReptileBridge || w->wall == waInvisibleFloor ||
w->wall == waSlime1 || w->wall == waSlime2 || w->wall == waArrowTrap || w->wall == waMagma ||
w->wall == waDock)
w->wall == waDock || w->wall == waFireTrap)
return false;
if(isWatery(w) || isChasmy(w) || isFire(w)) return false;
return true;
}
bool isPushable(eWall w) {
return w == waThumperOn || w == waExplosiveBarrel;
}
bool isAngryBird(eMonster m) {
return m == moEagle || m == moAlbatross || m == moBomberbird || m == moGargoyle ||
m == moWindCrow || m == moSparrowhawk ||
@ -412,7 +416,7 @@ bool normalMover(eMonster m) {
m == moHunterGuard || m == moHunterChanging ||
m == moIceGolem ||
m == moSwitch1 || m == moSwitch2 || m == moCrusher || m == moPair ||
m == moBrownBug ||
m == moBrownBug || m == moVariantWarrior ||
isMagneticPole(m) ||
slowMover(m);
}
@ -742,7 +746,7 @@ bool hornStuns(cell *c) {
m == moButterfly || m == moGreater || m == moGreaterM || m == moDraugr ||
m == moHedge || m == moFlailer || m == moVizier || m == moReptile || m == moSalamander ||
m == moPair || m == moAltDemon || m == moHexDemon || m == moMonk || m == moCrusher ||
attackJustStuns(c, AF_NORMAL);
attackJustStuns(c, AF_NORMAL, moNone);
}
// generate all the world first in the quotient geometry

102
game.cpp
View File

@ -971,6 +971,10 @@ bool logical_adjacent(cell *c1, eMonster m1, cell *c2) {
return true;
}
bool arrow_stuns(eMonster m) {
return among(m, moCrusher, moMonk, moAltDemon, moHexDemon, moGreater, moGreaterM, moHedge);
}
bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
// cannot eat worms
@ -984,13 +988,15 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
if(m2 == moPlayer && peace::on) return false;
if((flags & AF_MUSTKILL) && attackJustStuns(c2, flags))
if((flags & AF_MUSTKILL) && attackJustStuns(c2, flags, m1))
return false;
if((flags & AF_ONLY_FRIEND) && m2 != moPlayer && !isFriendly(c2)) return false;
if((flags & AF_ONLY_FBUG) && m2 != moPlayer && !isFriendlyOrBug(c2)) return false;
if((flags & AF_ONLY_ENEMY) && (m2 == moPlayer || isFriendlyOrBug(c2))) return false;
if(m1 == moArrowTrap && arrow_stuns(m2)) return true;
if(among(m2, moAltDemon, moHexDemon, moPair, moCrusher, moNorthPole, moSouthPole, moMonk) && !(flags & (AF_EAT | AF_MAGIC | AF_BULL | AF_CRUSH)))
return false;
@ -1435,10 +1441,11 @@ bool monstersnear(cell *c, cell *nocount, eMonster who, cell *pushto, cell *come
comefrom->wall = w;
c->wall = waBigStatue;
}
else if(who == moPlayer && c->wall == waThumperOn) {
else if(who == moPlayer && isPushable(c->wall)) {
eWall w = c->wall;
c->wall = waNone;
b = monstersnear2();
c->wall = waThumperOn;
c->wall = w;
}
else {
b = monstersnear2();
@ -1532,6 +1539,12 @@ void prespill(cell* c, eWall t, int rad, cell *from) {
c->wall == waBarrowDig || c->wall == waBarrowWall ||
c->wall == waMirrorWall)
return;
if(c->wall == waFireTrap) {
if(c->wparam == 0) c->wparam = 1;
return;
}
if(c->wall == waExplosiveBarrel)
explodeBarrel(c);
destroyTrapsOn(c);
// these walls block further spilling
if(c->wall == waCavewall || cellUnstable(c) || c->wall == waSulphur ||
@ -1788,6 +1801,10 @@ bool makeflame(cell *c, int timeout, bool checkonly) {
if(checkonly) return true;
c->wall = waLake, HEAT(c) += 1;
}
else if(c->wall == waFireTrap) {
if(checkonly) return true;
if(c->wparam == 0) c->wparam = 1;
}
else if(c->wall == waFrozenLake) {
if(checkonly) return true;
drawParticles(c, MELTCOLOR, 8, 8);
@ -1827,16 +1844,12 @@ bool makeflame(cell *c, int timeout, bool checkonly) {
return true;
}
void explodeMine(cell *c) {
if(c->wall != waMineMine)
return;
void explosion(cell *c, int power, int central) {
playSound(c, "explosion");
drawFireParticles(c, 30, 150);
c->wall = waMineOpen;
brownian::dissolve_brownian(c, 2);
makeflame(c, 20, false);
makeflame(c, central, false);
forCellEx(c2, c) {
destroyTrapsOn(c2);
@ -1845,7 +1858,7 @@ void explodeMine(cell *c) {
c2->wall = waRed1;
else if(c2->wall == waDeadTroll || c2->wall == waDeadTroll2 || c2->wall == waPetrified || c2->wall == waGargoyle) {
c2->wall = waNone;
makeflame(c2, 10, false);
makeflame(c2, power/2, false);
}
else if(c2->wall == waPetrifiedBridge || c2->wall == waGargoyleBridge) {
placeWater(c, c);
@ -1853,7 +1866,7 @@ void explodeMine(cell *c) {
else if(c2->wall == waPalace || c2->wall == waOpenGate || c2->wall == waClosedGate ||
c2->wall == waSandstone || c2->wall == waMetal || c2->wall == waSaloon || c2->wall == waRuinWall) {
c2->wall = waNone;
makeflame(c2, 10, false);
makeflame(c2, power/2, false);
}
else if(c2->wall == waTower)
c2->wall = waRubble;
@ -1861,10 +1874,32 @@ void explodeMine(cell *c) {
c2->wall = waBarrowDig;
else if(c2->wall == waBarrowDig)
c2->wall = waNone;
else makeflame(c2, 20, false);
else if(c2->wall == waFireTrap) {
if(c2->wparam == 0)
c2->wparam = 1;
}
else if(c2->wall == waExplosiveBarrel)
explodeBarrel(c2);
else makeflame(c2, power, false);
}
}
void explodeMine(cell *c) {
if(c->wall != waMineMine)
return;
c->wall = waMineOpen;
explosion(c, 20, 20);
}
void explodeBarrel(cell *c) {
if(c->wall != waExplosiveBarrel)
return;
c->wall = waNone;
explosion(c, 20, 20);
}
bool mayExplodeMine(cell *c, eMonster who) {
if(c->wall != waMineMine) return false;
if(ignoresPlates(who)) return false;
@ -1872,7 +1907,7 @@ bool mayExplodeMine(cell *c, eMonster who) {
return true;
}
void stunMonster(cell *c2) {
void stunMonster(cell *c2, eMonster killer, flagtype flags) {
int newtime = (
c2->monst == moFatGuard ? 2 :
c2->monst == moSkeleton && c2->land != laPalace && c2->land != laHalloween ? 7 :
@ -1892,6 +1927,7 @@ void stunMonster(cell *c2) {
c2->monst == moSalamander ? 6 :
c2->monst == moBrownBug ? 3 :
3);
if(killer == moArrowTrap) newtime = min(newtime + 3, 7);
if(!isMetalBeast(c2->monst) && !among(c2->monst, moSkeleton, moReptile, moSalamander, moTortoise, moBrownBug)) {
c2->hitpoints--;
if(c2->monst == moPrincess)
@ -1902,9 +1938,11 @@ void stunMonster(cell *c2) {
checkStunKill(c2);
}
bool attackJustStuns(cell *c2, flagtype f) {
bool attackJustStuns(cell *c2, flagtype f, eMonster attacker) {
if(f & AF_HORNS)
return hornStuns(c2);
else if(attacker == moArrowTrap && arrow_stuns(c2->monst))
return true;
else if((f & AF_SWORD) && c2->monst == moSkeleton)
return false;
else if(f & (AF_CRUSH | AF_MAGIC | AF_FALL | AF_EAT | AF_GUN))
@ -2427,7 +2465,7 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
int tkt = killtypes();
bool dostun = attackJustStuns(c, flags);
bool dostun = attackJustStuns(c, flags, killer);
if((flags & AF_BULL) && c->monst == moVizier && c->hitpoints > 1) {
dostun = true;
@ -2439,7 +2477,7 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
if(flags & AF_MSG) fightmessage(m, killer, dostun, flags);
if(dostun)
stunMonster(c);
stunMonster(c, killer, flags);
else
killMonster(c, killer, flags);
@ -3323,6 +3361,9 @@ void moveEffect(cell *ct, cell *cf, eMonster m, int direction_hint) {
if(ct->wall == waArrowTrap && !ignoresPlates(m))
activateArrowTrap(ct);
if(ct->wall == waFireTrap && !ignoresPlates(m) && ct->wparam == 0)
ct->wparam = 1;
if(cf && isPrincess(m)) princess::move(ct, cf);
@ -3405,6 +3446,9 @@ void playerMoveEffects(cell *c1, cell *c2) {
if(c2->wall == waArrowTrap && c2->wparam == 0 && !markOrb(itOrbAether))
activateArrowTrap(c2);
if(c2->wall == waFireTrap && c2->wparam == 0 && !markOrb(itOrbAether))
c2->wparam = 1;
princess::playernear(c2);
@ -3451,6 +3495,10 @@ void beastcrash(cell *c, cell *beast) {
c->wall = waThumperOn;
c->wparam = 100;
}
else if(c->wall == waExplosiveBarrel) {
addMessage(XLAT("%The1 crashes into %the2!", beast->monst, c->wall));
explodeBarrel(c);
}
else if(isBull(c->monst) || isSwitch(c->monst)) {
addMessage(XLAT("%The1 crashes into %the2!", beast->monst, c->monst));
if(c->monst == moSleepBull) c->monst = moRagingBull, c->stuntime = 3;
@ -4031,6 +4079,10 @@ void beastAttack(cell *c, bool player) {
playSound(c2, "click");
c2->wall = waThumperOn;
}
if(c2->wall == waExplosiveBarrel) {
playSound(c2, "click");
explodeBarrel(c2);
}
if(c2->wall == waThumperOn) {
cellwalker bull (c, d);
int subdir = determinizeBullPush(bull);
@ -4143,6 +4195,7 @@ void explodeAround(cell *c) {
destroyHalfvine(c2);
c2->wall = waNone;
}
if(c2->wall == waExplosiveBarrel) explodeBarrel(c2);
if(c2->wall == waCavewall || c2->wall == waDeadTroll) c2->wall = waCavefloor;
if(c2->wall == waDeadTroll2) c2->wall = waNone;
if(c2->wall == waPetrified) c2->wall = waNone;
@ -4482,7 +4535,7 @@ void moveivy() {
if(isPlayerOn(c->move(j)))
killThePlayerAt(c->monst, c->move(j), 0);
else {
if(attackJustStuns(c->move(j), 0))
if(attackJustStuns(c->move(j), 0, c->monst))
addMessage(XLAT("The ivy attacks %the1!", c->move(j)->monst));
else if(isNonliving(c->move(j)->monst))
addMessage(XLAT("The ivy destroys %the1!", c->move(j)->monst));
@ -7333,24 +7386,29 @@ void pushThumper(cell *th, cell *cto) {
if(th->land == laAlchemist)
th->wall = isAlch(cwt.at) ? cwt.at->wall : cto->wall;
else th->wall = waNone;
int explode = 0;
if(cto->wall == waArrowTrap && w == waExplosiveBarrel ) explode = max<int>(cto->wparam, 1);
if(cto->wall == waFireTrap) explode = max<int>(cto->wparam, 1);
destroyTrapsOn(cto);
if(cto->wall == waOpenPlate || cto->wall == waClosePlate) {
toggleGates(cto, cto->wall);
addMessage(XLAT("%The1 destroys %the2!", waThumperOn, cto->wall));
addMessage(XLAT("%The1 destroys %the2!", w, cto->wall));
}
if(cellUnstable(cto) && cto->land == laMotion) {
addMessage(XLAT("%The1 falls!", waThumperOn));
addMessage(XLAT("%The1 falls!", w));
doesFallSound(cto);
}
else if(cellUnstableOrChasm(cto)) {
addMessage(XLAT("%The1 fills the hole!", waThumperOn));
addMessage(XLAT("%The1 fills the hole!", w));
cto->wall = waTempFloor;
}
else if(isWatery(cto)) {
addMessage(XLAT("%The1 fills the hole!", waThumperOn));
addMessage(XLAT("%The1 fills the hole!", w));
cto->wall = waTempBridge;
}
else
cto->wall = w;
if(explode) cto->wall = waFireTrap, cto->wparam = explode;
}
bool canPushThumperOn(cell *tgt, cell *thumper, cell *player) {
@ -7562,7 +7620,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
return true;
}
if(c2->wall == waThumperOn && !c2->monst && !nonAdjacentPlayer(c2, cwt.at)) {
if(isPushable(c2->wall) && !c2->monst && !nonAdjacentPlayer(c2, cwt.at)) {
int pushdir;
cell *c3 = determinePush(cwt, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, cwt.at); }, pushdir);
if(c3 == c2) {

View File

@ -1302,6 +1302,13 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, color_t col,
}
else if(m == moTerraWarrior)
drawTerraWarrior(V, 7, (where ? where->hitpoints : 7), footphase);
else if(m == moVariantWarrior) {
const transmatrix VBS = VBODY * otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
ShadowV(V, shPBody);
queuepoly(VBS, shPBody, darkena(0xFFD500, 0, 0xF0));
if(!peace::on) queuepoly(VBS, shPSword, 0xFFFF00FF);
queuepoly(VHEAD, shHood, 0x008000FF);
}
else if(m == moDesertman) {
const transmatrix VBS = VBODY * otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
ShadowV(V, shPBody);
@ -2684,7 +2691,7 @@ void drawMovementArrows(cell *c, transmatrix V) {
poly_outline = OUTLINE_DEFAULT;
queuepoly(fixrot * spin(-d * M_PI/4), shArrow, col);
if((c->type & 1) && (isStunnable(c->monst) || c->wall == waThumperOn)) {
if((c->type & 1) && (isStunnable(c->monst) || isPushable(c->wall))) {
transmatrix Centered = rgpushxto0(tC0(cwtV));
int sd = md.subdir;
queuepoly(inverse(Centered) * rgpushxto0(Centered * tC0(V)) * rspintox(Centered*tC0(V)) * spin(-sd * M_PI/S7) * xpush(0.2), shArrow, col);
@ -2830,6 +2837,19 @@ void setcolors(cell *c, color_t& wcol, color_t& fcol) {
case laAlchemist:
fcol = floorcolors[c->land]; break;
case laVariant: {
int b = getBits(c);
fcol = 0x404040;
for(int a=0; a<21; a++)
if((b >> a) & 1)
fcol += variant_features[a].color_change;
if(c->wall == waAncientGrave)
wcol = 0x080808;
else if(c->wall == waFreshGrave)
wcol = 0x202020;
break;
}
case laRuins:
fcol = pseudohept(c) ? 0xC0E0C0 : 0x40A040;
break;
@ -3134,7 +3154,7 @@ void setcolors(cell *c, color_t& wcol, color_t& fcol) {
switch(c->wall) {
case waSulphur: case waSulphurC: case waPlatform: case waMercury: case waDock:
case waAncientGrave: case waFreshGrave: case waThumperOn: case waThumperOff: case waBonfireOff:
case waRoundTable:
case waRoundTable: case waExplosiveBarrel:
// floors become fcol
fcol = wcol;
break;
@ -4525,7 +4545,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
case waClosePlate: case waOpenPlate: {
transmatrix V2 = V;
if(wmescher && geosupport_football() == 2 && pseudohept(c)) V2 = V * spin(M_PI / c->type);
if(wmescher && geosupport_football() == 2 && pseudohept(c) && c->land == laPalace) V2 = V * spin(M_PI / c->type);
draw_floorshape(c, V2, shMFloor, darkena(winf[c->wall].color, 0, 0xFF));
draw_floorshape(c, V2, shMFloor2, (!wmblack) ? darkena(fcol, 1, 0xFF) : darkena(0,1,0xFF));
break;
@ -4586,6 +4606,13 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
if(isCentralTrap(c)) arrowtraps.push_back(c);
break;
case waFireTrap:
draw_floorshape(c, V, shMFloor, darkena(0xC00000, 0, 0xFF));
draw_floorshape(c, V, shMFloor2, darkena(0x600000, 0, 0xFF));
if(c->wparam >= 1)
queuepoly(V, shDisk, darkena(trapcol[c->wparam&3], 0, 0xFF));
break;
case waGiantRug:
queuepoly(V, shBigCarpet1, darkena(0xC09F00, 0, 0xFF));
queuepoly(V, shBigCarpet2, darkena(0x600000, 0, 0xFF));
@ -4650,6 +4677,14 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
poly_outline = OUTLINE_DEFAULT;
}
else if(c->wall == waExplosiveBarrel) {
const int layers = 2 << detaillevel;
for(int z=1; z<=layers; z++) {
double zg = zgrad0(0, geom3::actual_wall_height(), z, layers);
queuepolyat(xyzscale(V, zg, zg), shBarrel, darkena((z&1) ? 0xFF0000 : 0xC00000, 0, 0xFF), PPR(PPR::REDWALLm+z));
}
}
else if(isFire(c) || isThumper(c) || c->wall == waBonfireOff) {
auto V2 = V;
if(hasTimeout(c)) V2 = V2 * spintick(c->land == laPower ? 5000 : 500);
@ -4667,6 +4702,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
else {
if(c->wall == waArrowTrap)
asciicol = trapcol[c->wparam & 3];
if(c->wall == waFireTrap)
asciicol = trapcol[c->wparam & 3];
if(c->wall == waTerraWarrior)
asciicol = terracol[c->landparam & 7];

View File

@ -1726,7 +1726,7 @@ namespace sword {
}
void killThePlayer(eMonster m, int id, flagtype flags);
bool attackJustStuns(cell *c2, flagtype flags);
bool attackJustStuns(cell *c2, flagtype flags, eMonster attacker);
bool isTargetOrAdjacent(cell *c);
bool warningprotection(const string& s);
@ -2079,6 +2079,8 @@ extern eGlyphsortorder glyphsortorder;
void explodeMine(cell *c);
bool mayExplodeMine(cell *c, eMonster who);
void explosion(cell *c, int power, int central);
void explodeBarrel(cell *c);
int gravityLevel(cell *c);
void fullcenter();

View File

@ -105,6 +105,83 @@ eMonster genRuinMonster(cell *c) {
void gen_brownian(cell *c);
void createArrowTrapAt(cell *c, eLand land) {
cellwalker cw(c, hrand(c->type));
cell* cc[5];
cc[2] = c;
cellwalker cw2 = cw;
cw += wstep; cc[3] = cw.at; cw += revstep; cc[4] = cw.at;
cw2 += revstep; cc[1] = cw2.at; cw2 += revstep; cc[0] = cw2.at;
bool ok = true;
for(int i=0; i<5; i++) {
if(cc[i]->land != laNone && cc[i]->land != land) ok = false;
if(cc[i]->bardir != NODIR) ok = false;
}
for(int i=1; i<4; i++) {
forCellEx(c2, cc[i]) if(!among(c2->wall, waNone, waStone)) ok = false;
}
if(ok) {
if(!racing::on) for(int i=1; i<4; i++)
cc[i]->wall = waArrowTrap,
cc[i]->wparam = 0;
for(int i=0; i<5; i++)
cc[i]->bardir = NOBARRIERS;
cc[0]->wall = waStone;
cc[4]->wall = waStone;
}
}
void build_pool(cell *c, bool with_boat) {
bool vacant = true;
if(c->monst || !among(c->wall, waNone, waSea, waBoat)) vacant = false;
forCellCM(c1, c) if(!among(c1->land, laNone, laVariant) || c1->monst || !among(c1->wall, waNone, waSea, waBoat)) vacant = false;
if(vacant) {
c->wall = waSea;
forCellEx(c1, c) if(c1->wall != waBoat) c1->wall = waSea;
if(with_boat) c->move(hrand(c->type))->wall = waBoat;
}
}
struct variant_feature {
color_t color_change;
int rate_change;
void (*build)(cell*);
};
#define VF [] (cell *c)
const array<variant_feature, 21> variant_features {{
variant_feature{(color_t)(-0x202020), 5, VF {
if(hrand(1500) < 20) c->wall = waFreshGrave;
if(hrand(20000) < 10 + items[itVarTreasure])
c->monst = moNecromancer;
}},
{0x000010, 5, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure]) c->monst = moLancer; } },
{0x100008,15, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure]) c->monst = moMonk; } },
{0x080010, 5, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure]) c->monst = moCrusher; } },
{0x181418, 5, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure]) c->monst = moSkeleton, c->hitpoints = 3; } },
{0x180000, 5, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure]) c->monst = moPyroCultist; } },
{0x00000C, 2, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure]) c->monst = moFlailer; } },
{0x1C0800, 1, VF { if(c->wall == waNone && !c->monst && hrand(80000) < 25 + items[itVarTreasure] && VALENCE == 3) c->monst = moHedge; } },
{0x001000,-1, VF { if(hrand(1500) < 30) createArrowTrapAt(c, laVariant); } },
{0x001400,-1, VF { if(hrand(1500) < 50 && c->wall == waNone) c->wall = waTrapdoor; } },
{0x001018,-1, VF { if(hrand(1500) < 30) build_pool(c, true); } },
{0x040C00,-1, VF { if(c->wall == waNone && !c->monst && !c->monst && hrand(1500) < 10) c->wall = waThumperOff; } },
{0x080C00,-1, VF { if(hrand(1500) < 20 && !c->monst && !c->wall) c->wall = waFireTrap; } },
{0x0C0C00, 0, VF { if(c->wall == waNone && !c->monst && hrand(5000) < 100) c->wall = waExplosiveBarrel; } },
{0x061004, 0, VF {
if(c->wall == waNone && !c->monst && pseudohept(c) && hrand(30000) < 25 + items[itVarTreasure])
if(buildIvy(c, 0, c->type) && !peace::on) c->item = itVarTreasure;
}},
{0x000C08, 0, VF { if(c->wall == waNone && !c->monst && hrand(5000) < 100) c->wall = waSmallTree; }},
{0x100C10, 1, VF { if(c->wall == waNone && hrand(10000) < 10 + items[itVarTreasure]) c->monst = moSleepBull, c->hitpoints = 3; }},
{0x00140C, 0, VF { if(c->wall == waNone && !c->monst && hrand(5000) < 100) c->wall = waBigTree; }},
{0x000C28, 1, VF { if(hrand(500) < 10) build_pool(c, false); } },
{0x100C00, 2, VF { if(c->wall == waNone && !c->monst && hrand(40000) < 25 + items[itVarTreasure]) c->monst = moVariantWarrior; }},
{0x100808, 1, VF { if(c->wall == waNone && !c->monst && hrand(50000) < 25 + items[itVarTreasure]) c->monst = moRatling; }}
}};
#undef VF
void giantLandSwitch(cell *c, int d, cell *from) {
switch(c->land) {
@ -940,31 +1017,8 @@ void giantLandSwitch(cell *c, int d, cell *from) {
case laTerracotta:
if(d == 9) {
if(hrand(500) < 15) {
cellwalker cw(c, hrand(c->type));
cell* cc[5];
cc[2] = c;
cellwalker cw2 = cw;
cw += wstep; cc[3] = cw.at; cw += revstep; cc[4] = cw.at;
cw2 += revstep; cc[1] = cw2.at; cw2 += revstep; cc[0] = cw2.at;
bool ok = true;
for(int i=0; i<5; i++) {
if(cc[i]->land != laNone && cc[i]->land != laTerracotta) ok = false;
if(cc[i]->bardir != NODIR) ok = false;
}
for(int i=1; i<4; i++) {
forCellEx(c2, cc[i]) if(c2->wall == waArrowTrap) ok = false;
}
if(ok) {
if(!racing::on) for(int i=1; i<4; i++)
cc[i]->wall = waArrowTrap,
cc[i]->wparam = 0;
for(int i=0; i<5; i++)
cc[i]->bardir = NOBARRIERS;
cc[0]->wall = waStone;
cc[4]->wall = waStone;
}
}
if(hrand(500) < 15)
createArrowTrapAt(c, laTerracotta);
if(pseudohept(c) && hrand(100) < 40 && c->wall == waNone && !racing::on) {
c->wall = waTerraWarrior;
c->landparam = randterra ? 0 : 3 + hrand(3);
@ -2234,6 +2288,24 @@ void giantLandSwitch(cell *c, int d, cell *from) {
}
break;
case laVariant: {
int b = getBits(c);
if(d == 9) {
int treasure_rate = 2;
for(int i=0; i<21; i++) if((b>>i) & 1) {
treasure_rate += variant_features[i].rate_change;
variant_features[i].build(c);
}
if(hrand(2000 - PT(kills[moVariantWarrior] * 5, 250)) < treasure_rate && !c->wall && !c->monst)
c->item = itVarTreasure;
}
if(d == 7 && c->wall == waTrapdoor) {
forCellEx(c1, c) if(among(c1->wall, waSea, waBoat))
c->wall = waNone;
}
break;
}
case laNone:
case laBarrier:
case laOceanWall:

View File

@ -223,6 +223,12 @@ int isNative(eLand l, eMonster m) {
return among(m, moPair, moHexDemon, moAltDemon, moMonk, moCrusher) ? 2 :
m == moSkeleton ? 1 : 0;
case laVariant:
return
m == moVariantWarrior ? 2 :
among(m, moMonk, moCrusher, moSkeleton, moHedge, moLancer, moFlailer, moCultist, moPyroCultist, moNecromancer, moGhost, moZombie, moRatling) ? 1 :
isIvy(m) ? 1 : 0;
case laMagnetic:
return isMagneticPole(m) ? 2 : 0;
}
@ -326,6 +332,8 @@ eItem treasureType(eLand l) {
case laRuins: return itRuins;
case laSwitch: return itSwitch;
case laMagnetic: return itMagnet;
case laVariant: return itVarTreasure;
case laWestWall: return itWest;
case laCA: return itNone;
}

View File

@ -1507,6 +1507,7 @@ hpcshape
shBFloor[2],
shWave[8][2],
shCircleFloor,
shBarrel,
shWall[2], shMineMark[2], shFan,
shZebra[5],
shSwitchDisk,
@ -1892,6 +1893,9 @@ void buildpolys() {
chasmifyPoly(dlow, dhi, k);
}
bshape(shBarrel, PPR::FLOOR);
for(int t=0; t<=S84; t+=2) hpcpush(ddi(t, floorrad1*.5) * C0);
bshape(shCircleFloor, PPR::FLOOR);
for(int t=0; t<=S84; t+=2) hpcpush(ddi(t, floorrad1*.9) * C0);