From 8109a39de064af310867fbc9e953ab462ec66ec2 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Wed, 3 Sep 2025 00:01:21 -0400 Subject: [PATCH 01/15] Make Orb of Magnetism and Curse of Repulsion leave saved tortoises alone --- items.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/items.cpp b/items.cpp index 6da798ce..d0a18d62 100644 --- a/items.cpp +++ b/items.cpp @@ -30,6 +30,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 +43,7 @@ EX bool doPickupItemsWithMagnetism(cell *c) { cw += wstep; for(int j=1; jtype; 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); From e9629969d289bf3481ca366b20aa8ec9998a07f9 Mon Sep 17 00:00:00 2001 From: bacchelordoh <159671087+ohlordhebacc@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:36:26 -0500 Subject: [PATCH 02/15] fixed OoEarth interactions with mercury river subland and irradiated field more specifically, fixed the orb of earth removing limestone walls in the mercury river subland and irradiated field, and fixed the orb of earth not creating mercury on cells that the player steps off of in the mercury river subland --- mapeffects.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mapeffects.cpp b/mapeffects.cpp index 80c9179e..d7bd56b3 100644 --- a/mapeffects.cpp +++ b/mapeffects.cpp @@ -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; From d0ba5142f148eb08735d6270e576366f7582906a Mon Sep 17 00:00:00 2001 From: bacchelordoh <159671087+ohlordhebacc@users.noreply.github.com> Date: Fri, 12 Sep 2025 22:38:26 -0500 Subject: [PATCH 03/15] forgot a parenthesis --- mapeffects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mapeffects.cpp b/mapeffects.cpp index d7bd56b3..ec56fb01 100644 --- a/mapeffects.cpp +++ b/mapeffects.cpp @@ -259,7 +259,7 @@ EX bool earthWall(cell *c) { c->wall = waChasm; return true; } - if(c->wall == waNone && among(c->land, laTerracotta, laMercuryRiver) { + if(c->wall == waNone && among(c->land, laTerracotta, laMercuryRiver)) { c->wall = waMercury; return true; } From a4267cdfccca037346b5695b59a88f5154252208 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Wed, 17 Sep 2025 22:47:11 -0400 Subject: [PATCH 04/15] Lower the land unlock requirements if they're mathematically impossibly high --- landlock.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/landlock.cpp b/landlock.cpp index fedf0bd7..f5854521 100644 --- a/landlock.cpp +++ b/landlock.cpp @@ -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() { From d2043699fa7af21f56f0e308f556d984d1c0f4fd Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sun, 21 Sep 2025 01:27:15 -0400 Subject: [PATCH 05/15] Stop WFC generation from spilling 1 tile into neighboring lands Hopefully this will stop Rosebushes from appearing right outside Eclectic City --- wfcgen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wfcgen.cpp b/wfcgen.cpp index 8a7ea162..7764e21f 100644 --- a/wfcgen.cpp +++ b/wfcgen.cpp @@ -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++; } From 05cac02a54478f2d1319434b9df245270ae5bc13 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Mon, 22 Sep 2025 00:20:16 -0400 Subject: [PATCH 06/15] Never generate Cursed Canyon in CR6 if it isn't in-game --- barriers.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/barriers.cpp b/barriers.cpp index a9d78a05..64327202 100644 --- a/barriers.cpp +++ b/barriers.cpp @@ -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; From e3401515c182f85fa8f9c49310e6b4eb463c5c0b Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sat, 27 Sep 2025 15:40:09 -0400 Subject: [PATCH 07/15] Add a setting to disable the warning before killing a friendly monster --- config.cpp | 3 +++ pcmove.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/config.cpp b/config.cpp index 5776cb42..34009b6d 100644 --- a/config.cpp +++ b/config.cpp @@ -3522,6 +3522,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') diff --git a/pcmove.cpp b/pcmove.cpp index 9c2807fc..1918bcff 100644 --- a/pcmove.cpp +++ b/pcmove.cpp @@ -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; From 61e859e9af69dc84501e81d655196b6ffbd3fc50 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sun, 28 Sep 2025 14:45:29 -0400 Subject: [PATCH 08/15] Add Seuphorica as a submodule This will let people do recursive git clones to automatically check out Seuphorica in the right place. --- .gitmodules | 3 +++ rogueviz/seuphorica | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 rogueviz/seuphorica diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..2461de6a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "rogueviz/seuphorica"] + path = rogueviz/seuphorica + url = https://github.com/zenorogue/seuphorica.git diff --git a/rogueviz/seuphorica b/rogueviz/seuphorica new file mode 160000 index 00000000..1ed348d4 --- /dev/null +++ b/rogueviz/seuphorica @@ -0,0 +1 @@ +Subproject commit 1ed348d47e6d73e2fe47705bb3561d222305ffee From 09895de0d0aca18222f0e6b2778c3b3761dd68c6 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sun, 28 Sep 2025 15:05:55 -0400 Subject: [PATCH 09/15] Remove unused function isFriendlyGhost It looks like nothing in the repo has ever called this. --- flags.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/flags.cpp b/flags.cpp index 457e4f3b..1b4283ae 100644 --- a/flags.cpp +++ b/flags.cpp @@ -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); } From c4c9379fcb3c2399b9d0eca3bf43df9e59937daa Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Tue, 30 Sep 2025 20:16:58 -0400 Subject: [PATCH 10/15] Add a cheat to hold orb powers at their current level --- debug.cpp | 12 ++++++++++++ items.cpp | 3 +++ orbs.cpp | 10 +++++++++- system.cpp | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/debug.cpp b/debug.cpp index e7b34388..1821474c 100644 --- a/debug.cpp +++ b/debug.cpp @@ -123,6 +123,18 @@ vector 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 items; +EX array cheat_items; +EX bool cheat_items_enabled; + EX map > hiitems; EX bool pickable_from_water(eItem it) { diff --git a/orbs.cpp b/orbs.cpp index af8ed506..15e2f96e 100644 --- a/orbs.cpp +++ b/orbs.cpp @@ -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 Date: Wed, 1 Oct 2025 02:06:06 -0400 Subject: [PATCH 11/15] Fix getting rid of Great Walls by killing Ghosts with OotStone --- attack.cpp | 4 ++-- complex.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/attack.cpp b/attack.cpp index 4d01f20f..a9c447a5 100644 --- a/attack.cpp +++ b/attack.cpp @@ -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)) diff --git a/complex.cpp b/complex.cpp index 3aca2509..3de3bb76 100644 --- a/complex.cpp +++ b/complex.cpp @@ -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 From d9050c9661c89229dd24376ef8f8194a54a9da82 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sun, 5 Oct 2025 13:20:44 -0400 Subject: [PATCH 12/15] Add support for pinning glyphs to a consistent spot in the HUD --- config.cpp | 8 ++++++++ hud.cpp | 38 ++++++++++++++++++++++++++++++++------ menus.cpp | 5 +++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/config.cpp b/config.cpp index 5776cb42..936b3047 100644 --- a/config.cpp +++ b/config.cpp @@ -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", ""}, diff --git a/hud.cpp b/hud.cpp index 1c037035..9b74ef26 100644 --- a/hud.cpp +++ b/hud.cpp @@ -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= 0 && i < glyphs) glyphpinned[i] = true; + } while(ep.eat(",")); + } + } + +EX void updatepinnedglyphs() { + std::stringstream ss; + for(int i=0; i glyphpinned[j]; if(subclass(i) != subclass(j)) return subclass(i) < subclass(j); if(glyphsortorder == gsoFirstTop) @@ -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 glyphstoshow; for(int i=0; i= rows) rowid[z] = 0, colid[z]++; - displayglyph2(cx, cy, buttonsize, i); + if(ikappear(i)) displayglyph2(cx, cy, buttonsize, i); } } } diff --git a/menus.cpp b/menus.cpp index c99bc70f..0f93d480 100644 --- a/menus.cpp +++ b/menus.cpp @@ -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 = [] () { From af8dfe7fa32675cecd09bbdcc6d4109ccc2abbc2 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sun, 5 Oct 2025 19:08:25 -0400 Subject: [PATCH 13/15] Add a setting for a gap between orbs and treasures --- config.cpp | 5 +++++ hud.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/config.cpp b/config.cpp index 5776cb42..7e0cc695 100644 --- a/config.cpp +++ b/config.cpp @@ -1224,6 +1224,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") diff --git a/hud.cpp b/hud.cpp index 1c037035..3e927ef2 100644 --- a/hud.cpp +++ b/hud.cpp @@ -462,7 +462,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; @@ -629,6 +629,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; From 2a716d77ca4f53296c1ea3f68c188a341ded902a Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Sun, 5 Oct 2025 19:12:47 -0400 Subject: [PATCH 14/15] Add the setting to interface settings --- config.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/config.cpp b/config.cpp index 7e0cc695..65d73363 100644 --- a/config.cpp +++ b/config.cpp @@ -2569,6 +2569,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); From 5b2762e90fbb27fd8a64f6b439b5d079fc40e268 Mon Sep 17 00:00:00 2001 From: "Joseph C. Sible" Date: Wed, 8 Oct 2025 22:22:01 -0400 Subject: [PATCH 15/15] Reset lastexplore when resetting turncount --- mapeditor.cpp | 2 +- system.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mapeditor.cpp b/mapeditor.cpp index eb6cddb3..ebf8ae73 100644 --- a/mapeditor.cpp +++ b/mapeditor.cpp @@ -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; diff --git a/system.cpp b/system.cpp index 37d5eea8..91248b1e 100644 --- a/system.cpp +++ b/system.cpp @@ -407,7 +407,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;