1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-08-29 08:52:19 +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 == laCrossroads4 ? 5000 :
l == laCrossroads6 ? 5000 : l == laCrossroads6 ? 5000 :
l == laMasterCrossroads ? 10000 : l == laMasterCrossroads ? 10000 :
isThematic(l) ? 10000 :
(l == laMirror && !yendor::generating) ? 2500 : (l == laMirror && !yendor::generating) ? 2500 :
tactic::on ? 0 : tactic::on ? 0 :
racing::on ? 0 : racing::on ? 0 :
@ -1829,6 +1830,9 @@ EX void build_walls(cell *c, cell *from) {
return; 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 && 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))) ; buildBarrierNowall(c, getNewLand(laCrossroads4))) ;

View File

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

View File

@ -420,6 +420,9 @@ const char *ruindesc =
const char *rock_description = const char *rock_description =
"Shoot the Space Rocks for score. Large Rocks will split into two smaller rocks."; "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 #if HDR
enum eSlimegroup { sgNone, sgCave, sgWater, sgFloorA, sgFloorB, sgVine, sgTree }; enum eSlimegroup { sgNone, sgCave, sgWater, sgFloorA, sgFloorB, sgVine, sgTree };
#endif #endif

View File

@ -2064,6 +2064,7 @@ EX namespace heat {
EX double absheat(cell *c) { EX double absheat(cell *c) {
if(c->land == laCocytus) return HEAT(c) -.6; 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 == laIce || c->land == laBlizzard || c->land == laEclectic) return HEAT(c) -.4;
if(c->land == laThematicHeat) return HEAT(c) - 0.2;
return 0; return 0;
} }
@ -2167,6 +2168,8 @@ EX namespace heat {
hmod += xrate*.1; hmod += xrate*.1;
if(ct->land == laVolcano) if(ct->land == laVolcano)
hmod += xrate * (ct->wall == waMagma ? .4 : .2); 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) { for(cell* ct: ls) {
@ -2215,7 +2218,7 @@ EX namespace heat {
addMessage(XLAT("%The1 melts away!", c->monst)); addMessage(XLAT("%The1 melts away!", c->monst));
fallMonster(c); 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), drawParticles(c, MELTCOLOR, 4, 60),
c->wall = waNone, kills[0]++; c->wall = waNone, kills[0]++;
if(c->wall == waFrozenLake && HEAT(c) > (c->land == laCocytus ? .6 : .4)) 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) NATIVE(0)
REQ(ITEMS(itCursed, 5)) 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.") LAND( 0xC0B090, "Master Crossroads", laMasterCrossroads, ZERO, itHyperstone, RESERVED, "A crossroads that connects only to other crossroads.")
NATIVE(0) REQ(GOLD(R500)) NATIVE(0) REQ(GOLD(R500))

View File

@ -855,6 +855,13 @@ EX string generateHelpForLand(eLand l) {
} }
#endif #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; return s;
} }

View File

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

View File

@ -2521,13 +2521,27 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
case laCrossroads5: case laCrossroads5:
case laCrossroads6: case laCrossroads6:
case laMasterCrossroads: 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; if(c->wall == waTower) c->land = laCamelot;
ONEMPTY { 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) if(!BITRUNCATED && c->land == laCrossroads5 && hrand(100) < 60)
c->wall = waBarrier; c->wall = waBarrier;
else if(!inv::on && items[itShard] >= 10 && hrand(8000) < 120*orbcrossfun(items[itShard]) && mirror::build(c)) ; 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(hyperstonesUnlocked() && !racing::on && hrand(8000) < 100 * them_abstract && mirror::build(c)) ;
else if(tactic::on && isCrossroads(specialland) && hrand(8000) < 120 && 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) else if(c->land == laCrossroads4 && hrand(24000) < 10 && tactic::on)
c->wall = waRose; c->wall = waRose;
else { else {
@ -2863,7 +2877,7 @@ EX void repairLandgen(cell *c) {
if(c->land == laAlchemist && c->wall != waFloorA && c->wall != waFloorB) if(c->land == laAlchemist && c->wall != waFloorA && c->wall != waFloorB)
c->wall = waFloorA; 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; c->wall = waNone;
if(c->wall == waRed3 && c->land != laRedRock && c->land != laSnakeNest && c->land != laBrownian && c->land != laEclectic) 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) { 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) { EX bool isCrossroadsNM(eLand l) {
@ -61,7 +61,7 @@ EX bool isCrossroadsNM(eLand l) {
} }
EX bool bearsCamelot(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) { 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) { EX bool incompatible1(eLand l1, eLand l2) {
if(l1 == laMasterCrossroads && !isCrossroads(l2)) return true; if(l1 == laMasterCrossroads && !isCrossroads(l2)) return true;
if(isThematic(l1) && which_thematic(l2) != l1) return true;
if(isCrossroadsNM(l1) && isCrossroadsNM(l2)) return true; if(isCrossroadsNM(l1) && isCrossroadsNM(l2)) return true;
if(l1 == laJungle && l2 == laMotion) return true; if(l1 == laJungle && l2 == laMotion) return true;
if(l1 == laMirrorOld && 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 == laWarpSea && l2 == laKraken) return true;
if(l1 == laPrairie && l2 == laCrossroads3) return true; if(l1 == laPrairie && l2 == laCrossroads3) return true;
if(l1 == laPrairie && l2 == laCrossroads4) 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 == laWet && l2 == laDesert) return true;
if(l1 == laFrog && l2 == laMotion) return true; if(l1 == laFrog && l2 == laMotion) return true;
if(l1 == laBull && l2 == laTerracotta) return true; if(l1 == laBull && l2 == laTerracotta) return true;
@ -459,6 +463,14 @@ EX bool all_unlocked = false;
EX vector<eLand> cheatdest_list; 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) { EX eLand getNewLand(eLand old) {
#if CAP_LEGACY #if CAP_LEGACY
@ -571,7 +583,8 @@ EX eLand getNewLand(eLand old) {
laDeadCaves, laRedRock, laVariant, laHell, laCocytus, laPower, laDeadCaves, laRedRock, laVariant, laHell, laCocytus, laPower,
laBull, laTerracotta, laRose, laGraveyard, laHive, laDragon, laTrollheim, laBull, laTerracotta, laRose, laGraveyard, laHive, laDragon, laTrollheim,
laWet, laFrog, laEclectic, laCursed, laDice, laWet, laFrog, laEclectic, laCursed, laDice,
laCrossroads5, laCrossroads6, laMasterCrossroads laCrossroads5, laCrossroads6, laMasterCrossroads,
laThematicNature, laThematicUrban, laThematicDeath, laThematicAbstract, laThematicHeat, laThematicWater, laThematicEarth
}) })
if(landUnlocked(l)) tab[cnt++] = l; if(landUnlocked(l)) tab[cnt++] = l;
@ -742,11 +755,132 @@ EX vector<eLand> land_over = {
laPrairie, laBull, laTerracotta, laRose, laPrairie, laBull, laTerracotta, laRose,
laElementalWall, laTrollheim, laElementalWall, laTrollheim,
laHell, laCrossroads3, laCocytus, laPower, laCrossroads4, laHell, laCrossroads3, laCocytus, laPower, laCrossroads4,
laCrossroads5, laCrossroads6, laMasterCrossroads, laCrossroads5, laCrossroads6, laMasterCrossroads, laThematic,
// EXTRA // EXTRA
laWildWest, laHalloween, laDual, laSnakeNest, laMagnetic, laCA, laAsteroids 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; EX vector<eLand> landlist;
#if HDR #if HDR

View File

@ -599,8 +599,16 @@ EX void placeCrossroadOrbs(cell *c) {
int mul = c->land == laCrossroads5 ? 10 : 1; int mul = c->land == laCrossroads5 ? 10 : 1;
int gch = oi.gchance; int gch = oi.gchance;
if(!inv::on) gch /= orbcrossfun(treas); else gch /= 2; 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(gch) >= mul) continue;
if(hrand(50+items[itHyperstone]) >= 50) continue; if(hrand(50+items[itHyperstone]) >= 50) continue;
c->item = oi.orb; c->item = oi.orb;
if(oi.orb == itOrbWater && c->land != laOcean) c->wall = waStrandedBoat; 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(isHaunted(id)) id = laHaunted;
if(id == laWarpSea) id = laWarpCoast; if(id == laWarpSea) id = laWarpCoast;
if(id == laMercuryRiver) id = laTerracotta; if(id == laMercuryRiver) id = laTerracotta;
if(isThematic(id)) id = laThematic;
return id; return id;
} }

View File

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