1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-08-28 16:32:18 +00:00

new Crossroads variant: thematic crossroads

This commit is contained in:
Zeno Rogue 2025-07-07 14:00:11 +02:00
parent 0ec3e396d9
commit 0381dc8c84
12 changed files with 211 additions and 9 deletions

View File

@ -1566,6 +1566,7 @@ EX int wallchance(cell *c, bool deepOcean) {
l == laCrossroads4 ? 5000 :
l == laCrossroads6 ? 5000 :
l == laMasterCrossroads ? 10000 :
isThematic(l) ? 10000 :
(l == laMirror && !yendor::generating) ? 2500 :
tactic::on ? 0 :
racing::on ? 0 :
@ -1829,6 +1830,9 @@ EX void build_walls(cell *c, cell *from) {
return;
}
else if(good_for_wall(c) && ls::any_wall() && isThematic(c->land) && hrand(10000) < 1000 && !c->master->alt && !racing::on &&
buildBarrierNowall(c, getNewThematic(c->land))) ;
else if(good_for_wall(c) && ls::any_wall() && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && !c->master->alt && !tactic::on && !racing::on &&
buildBarrierNowall(c, getNewLand(laCrossroads4))) ;

View File

@ -190,6 +190,7 @@ void celldrawer::setcolors() {
case laMotion: case laGraveyard: case laWineyard: case laLivefjord:
case laRlyeh: case laHell: case laCrossroads: case laJungle:
case laAlchemist: case laFrog: case laCursed: case laDice:
case laThematic: case laThematicNature: case laThematicUrban: case laThematicDeath: case laThematicAbstract: case laThematicWater: case laThematicEarth:
fcol = floorcolors[c->land]; break;
case laCA:
@ -443,7 +444,7 @@ void celldrawer::setcolors() {
break;
}
case laIce: case laCocytus: case laBlizzard: case laEclectic:
case laIce: case laCocytus: case laBlizzard: case laEclectic: case laThematicHeat:
if(useHeatColoring(c)) {
float h = HEAT(c);
eLand l = c->land;

View File

@ -420,6 +420,9 @@ const char *ruindesc =
const char *rock_description =
"Shoot the Space Rocks for score. Large Rocks will split into two smaller rocks.";
const char *thematic_crossroads =
"The Thematic Crossroads has various sections that connect to lands with specific theme.";
#if HDR
enum eSlimegroup { sgNone, sgCave, sgWater, sgFloorA, sgFloorB, sgVine, sgTree };
#endif

View File

@ -2064,6 +2064,7 @@ EX namespace heat {
EX double absheat(cell *c) {
if(c->land == laCocytus) return HEAT(c) -.6;
if(c->land == laIce || c->land == laBlizzard || c->land == laEclectic) return HEAT(c) -.4;
if(c->land == laThematicHeat) return HEAT(c) - 0.2;
return 0;
}
@ -2167,6 +2168,8 @@ EX namespace heat {
hmod += xrate*.1;
if(ct->land == laVolcano)
hmod += xrate * (ct->wall == waMagma ? .4 : .2);
else if(c->land == laThematicHeat && !isThematic(ct->land) && !isIcyLand(ct->land) && ct->land != laBarrier)
hmod += xrate * .3;
}
for(cell* ct: ls) {
@ -2215,7 +2218,7 @@ EX namespace heat {
addMessage(XLAT("%The1 melts away!", c->monst));
fallMonster(c);
}
if(c->wall == waIcewall && HEAT(c) > .4)
if(c->wall == waIcewall && HEAT(c) > (c->land == laThematicHeat ? .2 : .4))
drawParticles(c, MELTCOLOR, 4, 60),
c->wall = waNone, kills[0]++;
if(c->wall == waFrozenLake && HEAT(c) > (c->land == laCocytus ? .6 : .4))

View File

@ -1754,6 +1754,30 @@ LAND( 0x7030A0, "Crossroads VI", laCrossroads6, ZERO, itHyperstone, RESERVED, "A
NATIVE(0)
REQ(ITEMS(itCursed, 5))
LAND( 0xC0C0C0, "Thematic Crossroads", laThematic, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0x60C060, "Thematic Crossroads (Nature)", laThematicNature, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0x60C0C0, "Thematic Crossroads (Urban)", laThematicUrban, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0x606060, "Thematic Crossroads (Death)", laThematicDeath, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0xC060C0, "Thematic Crossroads (Abstract)", laThematicAbstract, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0x6060C0, "Thematic Crossroads (Water)", laThematicWater, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0x1030F0, "Thematic Crossroads (Fire/Ice)", laThematicHeat, LF_ICY, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0x505050, "Thematic Crossroads (Earth/Air)", laThematicEarth, ZERO, itHyperstone, RESERVED, thematic_crossroads)
NATIVE(0) REQ(GOLD(R400))
LAND( 0xC0B090, "Master Crossroads", laMasterCrossroads, ZERO, itHyperstone, RESERVED, "A crossroads that connects only to other crossroads.")
NATIVE(0) REQ(GOLD(R500))

View File

@ -855,6 +855,13 @@ EX string generateHelpForLand(eLand l) {
}
#endif
if(isThematic(l)) {
s += XLAT("\n\nThe following lands connect to this part: ");
int qty = 0;
for(eLand l1: land_over) if(isLandIngame(l1) && which_thematic(l1) == l) { if(qty) s += ", "; qty++; s += XLATN(linf[l1].name); }
}
return s;
}

View File

@ -469,6 +469,8 @@ extern videopar vid;
#define R200 (big_unlock ? 800 : 200)
// Crossroads V
#define R300 (big_unlock ? 1200 : 300)
// Thematic Crossroads
#define R400 (big_unlock ? 1600 : 400)
// Master Crossroads
#define R500 (big_unlock ? 2000 : 500)
// kill types for Dragon Chasms

View File

@ -2521,13 +2521,27 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
case laCrossroads5:
case laCrossroads6:
case laMasterCrossroads:
case laThematic: case laThematicNature: case laThematicUrban: case laThematicDeath: case laThematicAbstract: case laThematicWater: case laThematicEarth: case laThematicHeat:
if(c->wall == waTower) c->land = laCamelot;
ONEMPTY {
if(isThematic(c->land) && hrand(100) < 10) switch(c->land) {
case laThematicNature: c->wall = pick(waSmallTree, waBigTree); break;
case laThematicUrban: c->wall = pick(waRuinWall, waPalace); break;
case laThematicDeath: c->wall = pick(waAncientGrave, waFreshGrave); break;
case laThematicAbstract: c->wall = pick(waFloorA, waFloorB, waTrapdoor); break;
case laThematicWater: { c->wall = waShallow; forCellCM(c1, c) if(c1->land == c->land) c1->wall = waShallow; } break;
case laThematicEarth: c->wall = waStone; break;
case laThematicHeat: c->wall = pick(waBonfireOff, waIcewall); break;
default: ;
}
int them_abstract = c->land == laThematicAbstract ? 3 : isThematic(c->land) ? 0 : 1;
if(!BITRUNCATED && c->land == laCrossroads5 && hrand(100) < 60)
c->wall = waBarrier;
else if(!inv::on && items[itShard] >= 10 && hrand(8000) < 120*orbcrossfun(items[itShard]) && mirror::build(c)) ;
else if(hyperstonesUnlocked() && !racing::on && hrand(8000) < 100 && mirror::build(c)) ;
else if(tactic::on && isCrossroads(specialland) && hrand(8000) < 120 && mirror::build(c)) ;
else if(hyperstonesUnlocked() && !racing::on && hrand(8000) < 100 * them_abstract && mirror::build(c)) ;
else if(tactic::on && isCrossroads(specialland) && hrand(8000) < 120 * them_abstract && mirror::build(c)) ;
else if(c->land == laCrossroads4 && hrand(24000) < 10 && tactic::on)
c->wall = waRose;
else {
@ -2863,7 +2877,7 @@ EX void repairLandgen(cell *c) {
if(c->land == laAlchemist && c->wall != waFloorA && c->wall != waFloorB)
c->wall = waFloorA;
if(c->wall == waIcewall && !among(c->land, laIce, laCocytus, laBlizzard, laEclectic))
if(c->wall == waIcewall && !among(c->land, laIce, laCocytus, laBlizzard, laEclectic, laThematicHeat))
c->wall = waNone;
if(c->wall == waRed3 && c->land != laRedRock && c->land != laSnakeNest && c->land != laBrownian && c->land != laEclectic)

View File

@ -53,7 +53,7 @@ EX int landMultiplier(eLand l) {
}
EX bool isCrossroads(eLand l) {
return among(l, laCrossroads, laCrossroads2, laCrossroads3, laCrossroads4, laCrossroads5, laCrossroads6, laMasterCrossroads);
return among(l, laCrossroads, laCrossroads2, laCrossroads3, laCrossroads4, laCrossroads5, laCrossroads6, laMasterCrossroads) || isThematic(l);
}
EX bool isCrossroadsNM(eLand l) {
@ -61,7 +61,7 @@ EX bool isCrossroadsNM(eLand l) {
}
EX bool bearsCamelot(eLand l) {
return isCrossroads(l) && !among(l, laCrossroads2, laCrossroads5, laMasterCrossroads);
return isCrossroads(l) && !among(l, laCrossroads2, laCrossroads5, laMasterCrossroads) && (l == laThematicUrban || !isThematic(l));
}
EX bool inmirror(const cellwalker& cw) {
@ -338,6 +338,9 @@ EX bool voronoi_sea_incompatible(eLand l1, eLand l2) {
EX bool incompatible1(eLand l1, eLand l2) {
if(l1 == laMasterCrossroads && !isCrossroads(l2)) return true;
if(isThematic(l1) && which_thematic(l2) != l1) return true;
if(isCrossroadsNM(l1) && isCrossroadsNM(l2)) return true;
if(l1 == laJungle && l2 == laMotion) return true;
if(l1 == laMirrorOld && l2 == laMotion) return true;
@ -358,6 +361,7 @@ EX bool incompatible1(eLand l1, eLand l2) {
if(l1 == laWarpSea && l2 == laKraken) return true;
if(l1 == laPrairie && l2 == laCrossroads3) return true;
if(l1 == laPrairie && l2 == laCrossroads4) return true;
if(l1 == laPrairie && l2 == laCrossroads6) return true;
if(l1 == laWet && l2 == laDesert) return true;
if(l1 == laFrog && l2 == laMotion) return true;
if(l1 == laBull && l2 == laTerracotta) return true;
@ -459,6 +463,14 @@ EX bool all_unlocked = false;
EX vector<eLand> cheatdest_list;
EX eLand getNewThematic(eLand l) {
for(int it=0; it<100; it++) {
eLand l1 = pick(laThematicNature, laThematicUrban, laThematicDeath, laThematicAbstract, laThematicHeat, laThematicWater, laThematicEarth);
if(l1 != l) return l1;
}
return l;
}
EX eLand getNewLand(eLand old) {
#if CAP_LEGACY
@ -571,7 +583,8 @@ EX eLand getNewLand(eLand old) {
laDeadCaves, laRedRock, laVariant, laHell, laCocytus, laPower,
laBull, laTerracotta, laRose, laGraveyard, laHive, laDragon, laTrollheim,
laWet, laFrog, laEclectic, laCursed, laDice,
laCrossroads5, laCrossroads6, laMasterCrossroads
laCrossroads5, laCrossroads6, laMasterCrossroads,
laThematicNature, laThematicUrban, laThematicDeath, laThematicAbstract, laThematicHeat, laThematicWater, laThematicEarth
})
if(landUnlocked(l)) tab[cnt++] = l;
@ -742,11 +755,132 @@ EX vector<eLand> land_over = {
laPrairie, laBull, laTerracotta, laRose,
laElementalWall, laTrollheim,
laHell, laCrossroads3, laCocytus, laPower, laCrossroads4,
laCrossroads5, laCrossroads6, laMasterCrossroads,
laCrossroads5, laCrossroads6, laMasterCrossroads, laThematic,
// EXTRA
laWildWest, laHalloween, laDual, laSnakeNest, laMagnetic, laCA, laAsteroids
};
EX bool isThematic(eLand l) {
return among(l, laThematic, laThematicNature, laThematicUrban, laThematicDeath, laThematicAbstract, laThematicHeat, laThematicWater, laThematicEarth);
}
EX eLand which_thematic(eLand l) {
// note: even if some lands are not directly accessible from Thematic, they still affect orb generation in it
switch(l) {
case laJungle:
case laEndorian:
case laWineyard:
case laOvergrown:
case laFrog:
case laRose:
case laDryForest:
case laPrairie:
case laBull:
case laMountain: // not via crossroads
case laClearing: // not via crossroads
case laTortoise: // not via crossroads
return laThematicNature;
case laAlchemist:
case laMotion:
case laMirror:
case laMirrorOld:
case laMinefield:
case laSwitch:
case laReptile:
case laZebra:
case laDice:
case laWestWall:
case laHalloween: // not standard
case laDual: // not standard
return laThematicAbstract;
case laIvoryTower:
case laPalace:
case laDungeon:
case laRuins:
case laEclectic:
case laRlyeh:
case laVariant:
case laCamelot: // in
case laTemple: // not via crossroads
case laPrincessQuest: // not via crossroads
case laWildWest: // not standard
return laThematicUrban;
case laHunting:
case laGraveyard:
case laBurial:
case laCursed:
case laDeadCaves:
case laTerracotta:
case laHive:
case laHaunted: case laHauntedWall: case laHauntedBorder: // not via crossroads
return laThematicDeath;
case laIce:
case laVolcano:
case laDragon:
case laHell:
case laCocytus:
case laPower:
case laBlizzard:
case laEFire:
return laThematicHeat;
case laNone:
case laBarrier:
case laOceanWall:
case laCA:
case laCanvas:
case laElementalWall:
case laMercuryRiver:
case laMirrorWall:
case laMirrorWall2:
case laMirrored:
case laMirrored2:
case laMemory:
case landtypes:
return laNone;
case laCrossroads:
case laCrossroads2:
case laCrossroads3:
case laCrossroads4:
case laCrossroads5:
case laCrossroads6:
case laMasterCrossroads:
case laThematic:
case laThematicAbstract:
case laThematicNature:
case laThematicUrban:
case laThematicDeath:
case laThematicHeat:
case laThematicWater:
case laThematicEarth:
case laMagnetic:
case laAsteroids:
return laThematic;
case laOcean:
case laDocks:
case laWet:
case laWarpCoast: case laWarpSea:
case laLivefjord:
case laKraken: // not direct
case laCaribbean: // not direct
case laBrownian: // not direct
case laWhirlpool: // not direct
case laEWater:
return laThematicWater;
case laRedRock:
case laDesert:
case laCaves:
case laStorms:
case laWhirlwind:
case laEmerald:
case laEEarth:
case laEAir:
case laTrollheim:
case laSnakeNest: // not standard
return laThematicEarth;
}
return laThematic;
}
EX vector<eLand> landlist;
#if HDR

View File

@ -599,8 +599,16 @@ EX void placeCrossroadOrbs(cell *c) {
int mul = c->land == laCrossroads5 ? 10 : 1;
int gch = oi.gchance;
if(!inv::on) gch /= orbcrossfun(treas); else gch /= 2;
if(isThematic(c->land)) {
bool local = which_thematic(oi.l) == c->land;
if(!local) continue;
mul *= 7;
}
if(hrand(gch) >= mul) continue;
if(hrand(50+items[itHyperstone]) >= 50) continue;
c->item = oi.orb;
if(oi.orb == itOrbWater && c->land != laOcean) c->wall = waStrandedBoat;
}

View File

@ -32,6 +32,7 @@ EX eLand getCurrentLandForMusic() {
if(isHaunted(id)) id = laHaunted;
if(id == laWarpSea) id = laWarpCoast;
if(id == laMercuryRiver) id = laTerracotta;
if(isThematic(id)) id = laThematic;
return id;
}

View File

@ -241,6 +241,7 @@ EX void initgame() {
splitrocks = 0;
if(firstland == laElementalWall) cwt.at->land = randomElementalLand();
if(firstland == laThematic) cwt.at->land = getNewThematic(firstland);
resetview();
createMov(cwt.at, 0);