1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2026-03-03 20:29:44 +00:00
This commit is contained in:
Zeno Rogue
2025-10-09 08:40:28 +02:00
18 changed files with 120 additions and 36 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "rogueviz/seuphorica"]
path = rogueviz/seuphorica
url = https://github.com/zenorogue/seuphorica.git

View File

@@ -189,13 +189,13 @@ EX bool petrify(cell *c, eWall walltype, eMonster m) {
if(c->land == laWestWall) return false;
if(do_not_touch_this_wall(c)) return false;
if(isWateryOrBoat(c) && c->land == laWhirlpool) {
c->wall = waSea;
return false;
}
if(c->wall == waRoundTable) return false;
if(walltype == waGargoyle && cellUnstableOrChasm(c))
walltype = waGargoyleFloor;
else if(walltype == waGargoyle && isWatery(c))

View File

@@ -844,16 +844,18 @@ EX bool buildBarrier6(cellwalker cw, eLand m0, eLand m1) {
setland((b[d+1]-2).cpeek(), m1);
setland((b[d+1]+2).cpeek(), m0);
}
int cp = curse_percentage;
if(m0 == laCrossroads6 || m1 == laCrossroads6) {
cp = 25;
if(m0 == laCursed || m1 == laCursed) cp = 100;
}
if(hrand(100) < cp) {
setland(cw.at, laCursed);
cw.at->wall = waRubble;
cw.at->monst = moHexer;
cw.at->item = random_curse();
if(isLandIngame(laCursed)) {
int cp = curse_percentage;
if(m0 == laCrossroads6 || m1 == laCrossroads6) {
cp = 25;
if(m0 == laCursed || m1 == laCursed) cp = 100;
}
if(hrand(100) < cp) {
setland(cw.at, laCursed);
cw.at->wall = waRubble;
cw.at->monst = moHexer;
cw.at->item = random_curse();
}
}
return true;

View File

@@ -2721,7 +2721,7 @@ EX namespace dragon {
c->monst = moNone;
if(checkOrb(who, itOrbUndeath))
c->monst = moFriendlyGhost;
if(checkOrb(who, itOrbStone))
if(!do_not_touch_this_wall(c) && checkOrb(who, itOrbStone))
c->wparam = m, c->wall = waPetrified;
else if(c->wall == waFire) {
if(delay) delay = false;
@@ -2993,13 +2993,13 @@ EX namespace kraken {
if(checkOrb(who, itOrbUndeath)) c->monst = moFriendlyGhost;
if(c->land == laKraken && !c->item) c->item = itKraken;
kills[moKrakenH]++;
if(checkOrb(who, itOrbStone)) c->wall = waNone;
if(!do_not_touch_this_wall(c) && checkOrb(who, itOrbStone)) c->wall = waNone;
forCellEx(c1, c)
if(c1->monst == moKrakenT) {
changes.ccell(c1);
drawParticles(c, minf[moKrakenT].color, 16);
c1->monst = moNone;
if(checkOrb(who, itOrbStone)) {
if(!do_not_touch_this_wall(c1) && checkOrb(who, itOrbStone)) {
if(isWatery(c1))
c1->wall = waNone;
else

View File

@@ -1207,6 +1207,14 @@ EX void initConfig() {
param_b(keybd_subdir_enabled, "keybd_subdir_enabled", 0)->editable("control the pushing direction with TAB", 'P')->help("If set, you control the off-heptagon pushing direction with TAB. Otherwise, you control it by rotating the screen.");
param_str(pinnedglyphs, "pinned_glyphs", "")
->set_standard_editor(true)
->editable("pinned glyphs",
"A list of glyphs to always sort at the front, "
"and reserve space for even when they're not being displayed.",
'p')
->set_reaction(updateglyphpinned);
param_enum(glyphsortorder, parameter_names("glyph_sort", "glyph sort order"), glyphsortorder)
->editable({
{"first on top", ""},
@@ -1224,6 +1232,11 @@ EX void initConfig() {
{"icons", ""},
}, "orb display mode", 'o');
param_b(orb_treasure_gap, "orb_treasure_gap", false)
->editable("gap between orbs and treasures", 'G')
-> help("If set, a gap row will be left between orbs and treasures in the HUD")
-> set_reaction([] { vid.killreduction = 0; });
param_b(less_in_landscape, "less_in_landscape", false)
->editable("less items/kills in landscape", 'L')
-> help("If set, only the important items and kills will be shown")
@@ -2564,6 +2577,7 @@ EX void configureInterface() {
if(hr_hud_enabled) {
add_edit(glyphsortorder);
add_edit(vid.graphglyph);
add_edit(orb_treasure_gap);
add_edit(less_in_landscape);
add_edit(less_in_portrait);
add_edit(display_yasc_codes);
@@ -3522,6 +3536,9 @@ EX int config3 = addHook(hooks_configfile, 100, [] {
->set_sets([] { dialog::bound_low(1); })
->set_reaction([] { if(game_active) { stop_game(); start_game(); } });
param_enum(warn_before_killing_friends, "warn_before_killing_friends", 2)
->editable({{"OFF", "never warn"}, {"TAME_BOMBERBIRDS", "warn only for Tame Bomberbirds"}, {"ON", "always warn"}}, "warn before killing friendly monsters", 'W');
param_i(curse_percentage, "curse_percentage")->editable(0, 100, 1,
"curse percentage",
"The percentage of towers in Cursed Walls mode to be manned by Canyon Hags", 'R')

View File

@@ -123,6 +123,18 @@ vector<cheatkey> cheats = {
kills[moCultist] = qkills;
kills[moTroll] = qkills;
}},
cheatkey{'H', "toggle hold of orb powers", [] {
if(cheat_items_enabled) {
cheat_items_enabled = false;
addMessage(XLAT("Hold of orb powers disabled!"));
}
else {
cheat_items = items;
cheat_items_enabled = true;
cheater++;
addMessage(XLAT("Hold of orb powers enabled!"));
}
}},
cheatkey{'M', "deplete orb powers", [] {
for(int i=0; i<ittypes; i++)
if(itemclass(eItem(i)) == IC_ORB)

View File

@@ -262,10 +262,6 @@ EX bool haveRangedOrb() {
items[itOrbMorph] || items[itOrbPhasing];
}
EX bool isFriendlyGhost(eMonster m) {
return m == moFriendlyGhost || (markEmpathy(itOrbAether) && isFriendly(m));
}
EX bool isGhostAether(eMonster m) {
return isGhost(m) || checkOrb(m, itOrbAether);
}

41
hud.cpp
View File

@@ -58,6 +58,8 @@ enum eGlyphsortorder {
#endif
EX eGlyphsortorder glyphsortorder;
EX string pinnedglyphs;
EX bool glyphpinned[int(ittypes) + int(motypes)];
int zero = 0;
@@ -80,6 +82,27 @@ int glyphorder[glyphs];
int glyphphase[glyphs];
int glyph_lastticks;
EX void updateglyphpinned() {
for(int i=0; i<glyphs; i++) glyphpinned[i] = false;
if(!pinnedglyphs.empty()) {
exp_parser ep;
ep.s = pinnedglyphs;
do {
int i = ep.iparse();
if(i >= 0 && i < glyphs) glyphpinned[i] = true;
} while(ep.eat(","));
}
}
EX void updatepinnedglyphs() {
std::stringstream ss;
for(int i=0; i<glyphs; i++) {
if(glyphpinned[i]) ss << i << ",";
}
pinnedglyphs = ss.str();
if(!pinnedglyphs.empty()) pinnedglyphs.pop_back();
}
void updatesort() {
for(int i=0; i<glyphs; i++) {
int ik = ikmerge(i);
@@ -123,6 +146,8 @@ int glyphcorner(int i) {
}
bool glyphsort(int i, int j) {
if(glyphpinned[i] != glyphpinned[j])
return glyphpinned[i] > glyphpinned[j];
if(subclass(i) != subclass(j))
return subclass(i) < subclass(j);
if(glyphsortorder == gsoFirstTop)
@@ -462,7 +487,7 @@ EX void draw_crosshair() {
return;
}
EX bool less_in_portrait, less_in_landscape;
EX bool less_in_portrait, less_in_landscape, orb_treasure_gap;
EX string mode_description() {
string md;
@@ -560,7 +585,7 @@ EX void drawStats() {
else if(cornermode) {
int bycorner[4];
for(int u=0; u<4; u++) bycorner[u] = 0;
for(int i=0; i<glyphs; i++) if(ikappear(i) && (glyphflags(i) & GLYPH_INSQUARE))
for(int i=0; i<glyphs; i++) if((ikappear(i) || glyphpinned[i]) && (glyphflags(i) & GLYPH_INSQUARE))
bycorner[glyphcorner(i)]++;
updatesort();
stable_sort(glyphorder, glyphorder+glyphs, glyphsort);
@@ -579,7 +604,7 @@ EX void drawStats() {
vector<int> glyphstoshow;
for(int i=0; i<glyphs; i++) {
int g = glyphorder[i];
if(ikappear(g) && (glyphflags(g) & GLYPH_INSQUARE) && glyphcorner(g) == cor)
if((ikappear(g) || glyphpinned[g]) && (glyphflags(g) & GLYPH_INSQUARE) && glyphcorner(g) == cor)
glyphstoshow.push_back(g);
}
for(int u=vid.fsize; u<vid.xres/2-s; u += s)
@@ -592,7 +617,8 @@ EX void drawStats() {
if(cor&1) cx = vid.xres-1-s-cx;
if(cor&2) cy = vid.yres-1-cy;
displayglyph2(cx, cy, s, glyphstoshow[next++]);
int g = glyphstoshow[next++];
if(ikappear(g)) displayglyph2(cx, cy, s, g);
}
break;
}
@@ -616,7 +642,7 @@ EX void drawStats() {
flagtype flag = portrait ? GLYPH_INPORTRAIT : GLYPH_INLANDSCAPE;
for(int i=0; i<glyphs; i++) if(ikappear(i))
for(int i=0; i<glyphs; i++) if(ikappear(i) || glyphpinned[i])
if(glyphflags(i) & flag)
maxbyclass[glyphclass(i)]++;
int buttonsize;
@@ -629,6 +655,7 @@ EX void drawStats() {
rows = rowspace / buttonsize; if(!rows) return;
int coltaken = 0;
for(int z=0; z<4; z++) {
if(z == 1 && orb_treasure_gap) coltaken++;
if(z == 2 && !portrait) {
if(coltaken > columns) { vid.killreduction++; continue; }
coltaken = 0;
@@ -651,7 +678,7 @@ EX void drawStats() {
for(int i0=0; i0<glyphs; i0++) {
int i = glyphorder[i0];
if(!ikappear(i)) continue;
if(!ikappear(i) && !glyphpinned[i]) continue;
int z = glyphclass(i);
int imp = glyphflags(i);
if(!(imp & flag)) continue;
@@ -667,7 +694,7 @@ EX void drawStats() {
rowid[z]++; if(rowid[z] >= rows) rowid[z] = 0, colid[z]++;
displayglyph2(cx, cy, buttonsize, i);
if(ikappear(i)) displayglyph2(cx, cy, buttonsize, i);
}
}
}

View File

@@ -14,6 +14,9 @@ EX int currentLocalTreasure;
/** for treasures, the number collected; for orbs, the number of charges */
EX array<int, ittypes> items;
EX array<int, ittypes> cheat_items;
EX bool cheat_items_enabled;
EX map<modecode_t, array<int, ittypes> > hiitems;
EX bool pickable_from_water(eItem it) {
@@ -30,6 +33,8 @@ EX bool canPickupItemWithMagnetism(cell *c, cell *from) {
return false;
if(c->item == itCompass && from->item)
return false;
if(saved_tortoise_on(c))
return false;
return true;
}
@@ -41,7 +46,7 @@ EX bool doPickupItemsWithMagnetism(cell *c) {
cw += wstep;
for(int j=1; j<c3->type; j++) {
cell *c4 = (cw+j).peek();
if(!isNeighbor(c, c4) && c3->item && !c4->item && passable(c4, c3, ZERO)) {
if(!isNeighbor(c, c4) && c3->item && !c4->item && !saved_tortoise_on(c3) && passable(c4, c3, ZERO)) {
changes.ccell(c3);
changes.ccell(c4);
moveItem(c3, c4, false);

View File

@@ -221,11 +221,15 @@ EX bool landUnlockedRPM(eLand n) {
}
EX int lands_for_hell() {
return casual ? 40 : 9;
int desired = casual ? 40 : 9;
int available = std::count_if(land_over.begin(), land_over.end(), [] (eLand l) { return !among(l, laHell, laCocytus, laPower) && !isCrossroads(l) && isLandIngame(l); });
return min(desired, available);
}
EX int lands_for_cr3() {
return casual ? 20 : 9;
int desired = casual ? 20 : 9;
int available = std::count_if(land_over.begin(), land_over.end(), [] (eLand l) { return !isCrossroads(l) && isLandIngame(l); });
return min(desired, available);
}
EX int variant_unlock_value() {

View File

@@ -1096,7 +1096,7 @@ EX namespace mapstream {
if(shmup::on) shmup::init();
timerstart = time(NULL); turncount = 0;
timerstart = time(NULL); turncount = 0; lastexplore = 0;
sagephase = 0; hardcoreAt = 0;
timerstopped = false;
savecount = 0; savetime = 0;

View File

@@ -160,7 +160,7 @@ EX bool earthFloor(cell *c) {
if(c->monst) return false;
if(c->wall == waDeadwall) { c->wall = waDeadfloor; return true; }
if(c->wall == waDune) { c->wall = waNone; return true; }
if(c->wall == waStone && c->land != laTerracotta) { c->wall = waNone; return true; }
if(c->wall == waStone && !among(c->land, laTerracotta, laMercuryRiver, laVariant)) { c->wall = waNone; return true; }
if(c->wall == waAncientGrave || c->wall == waFreshGrave || c->wall == waRuinWall) {
c->wall = waNone;
return true;
@@ -259,11 +259,11 @@ EX bool earthWall(cell *c) {
c->wall = waChasm;
return true;
}
if(c->wall == waNone && c->land == laTerracotta) {
if(c->wall == waNone && among(c->land, laTerracotta, laMercuryRiver)) {
c->wall = waMercury;
return true;
}
if(c->wall == waArrowTrap && c->land == laTerracotta) {
if(c->wall == waArrowTrap && among(c->land, laTerracotta, laMercuryRiver)) {
destroyTrapsOn(c);
c->wall = waMercury;
return true;

View File

@@ -181,6 +181,11 @@ EX void showOverview() {
}
else if(udiv == 2 && umod < ittypes) {
gotoHelp(generateHelpForItem(eItem(umod)));
help_extensions.push_back(help_extension{'p', glyphpinned[umod] ? XLAT("unpin from HUD") : XLAT("pin to HUD"), [umod] () {
glyphpinned[umod] ^= true;
updatepinnedglyphs();
popScreen();
}});
if(cheater) {
dialog::helpToEdit(items[umod], 0, 200, 10, 10);
dialog::get_ne().reaction = [] () {

View File

@@ -50,7 +50,7 @@ EX void useupOrb(eItem it, int qty) {
}
EX void drainOrb(eItem it, int target IS(0)) {
if(items[it] > target) useupOrb(it, items[it] - target);
if(!cheat_items_enabled && items[it] > target) useupOrb(it, items[it] - target);
}
EX void empathyMove(const movei& mi) {
@@ -233,6 +233,14 @@ EX void reduceOrbPowers() {
else
items[itCrossbow]--;
}
if(cheat_items_enabled)
for(int i=0; i<ittypes; i++) {
if(i == itOrbSpeed) {
if(items[i] < cheat_items[i]) items[i] = cheat_items[i] + 1; // Orb of Speed always needs to alternate between an odd and even number to work right
}
else if(itemclass(eItem(i)) == IC_ORB && i != itOrbSafety)
items[i] = cheat_items[i];
}
}
eWall orig_wall;

View File

@@ -1474,7 +1474,10 @@ EX bool warningprotection(const string& s) {
return true;
}
EX int warn_before_killing_friends;
EX bool warningprotection_hit(eMonster m) {
if(warn_before_killing_friends < (m == moTameBomberbird ? 1 : 2)) return false;
if(m && warningprotection(XLAT("Are you sure you want to hit %the1?", m)))
return true;
return false;

1
rogueviz/seuphorica Submodule

Submodule rogueviz/seuphorica added at 1ed348d47e

View File

@@ -184,6 +184,7 @@ EX void reset_cheats() {
cheater = 0;
reptilecheat = false;
shadingcheat = false;
cheat_items_enabled = false;
timerghost = true;
gen_wandering = true;
}
@@ -407,7 +408,7 @@ EX void initgame() {
if(!safety) {
usedSafety = false;
timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0;
timerstart = time(NULL); turncount = 0; lastexplore = 0; rosewave = 0; rosephase = 0;
tickstart = ticks;
noiseuntil = 0;
sagephase = 0; hardcoreAt = 0;

View File

@@ -220,7 +220,7 @@ EX void invoke() {
c->wall = p.first[0];
c->wparam = p.first[0];
forCellEx(c1, c) {
if(c1->wall != waBarrier)
if(c1->wall != waBarrier && c1->land == c->land)
c1->wparam = c1->wall = p.first[idx];
idx++;
}