1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2026-05-08 00:01:24 +00:00

after 3 illegal moves, provide some suggestions regarding possible skip-moves and Orb uses

This commit is contained in:
Zeno Rogue
2026-04-18 14:06:35 +02:00
parent b518948af2
commit a7a3d13b70
14 changed files with 108 additions and 37 deletions

View File

@@ -404,8 +404,10 @@ int yasc_recode(int x) {
return yasc_recode(x / 10) * 100 + (x % 10);
};
EX void checkmove() {
EX cell *bowtarget = nullptr;
EX void checkmove(bool complete) {
if(!complete) { attempts = 0; movehints_ticks = 0; }
if(dual::state == 2) return;
if(shmup::on) return;
@@ -421,7 +423,7 @@ EX void checkmove() {
legalmoves.clear(); legalmoves.resize(cwt.at->type+1, false);
move_issues.clear(); move_issues.resize(cwt.at->type);
canmove = haveRangedTarget();
canmove = haveRangedTarget(complete);
items[itWarning]+=2;
if(movepcto(-1, 0, true))
canmove = legalmoves[cwt.at->type] = true;
@@ -450,7 +452,9 @@ EX void checkmove() {
for(int i=0; i<cwt.at->type; i++)
yasc_code += yasc_recode(move_issues[i].type);
if(!canmove && bow::crossbow_mode() && !items[itCrossbow]) canmove = bow::have_bow_target();
bowtarget = (!canmove || complete) ? bow::have_bow_target() : nullptr;
if(bowtarget) canmove = true;
#if CAP_INV
if(inv::on && !canmove && !inv::incheck) {
@@ -458,7 +462,7 @@ EX void checkmove() {
canmove = true;
else {
inv::check(1);
checkmove();
checkmove(complete);
inv::check(-1);
}
if(canmove)

View File

@@ -4299,7 +4299,7 @@ EX void configureMouse() {
dialog::add_action([] {
dialog::editNumber(vid.mobilecompasssize, 0, 100, 10, 20, XLAT("compass size"), XLAT("0 to disable"));
// we need to check the moves
dialog::get_di().reaction = checkmove;
dialog::get_di().reaction = [] { checkmove(false); };
dialog::bound_low(0);
});

View File

@@ -517,7 +517,10 @@ EX void shoot() {
gen_bowpath_map();
}
EX bool have_bow_target() {
EX cell *have_bow_target() {
if(!bow::crossbow_mode()) return nullptr;
if(items[itCrossbow]) return nullptr;
dynamicval<decltype(bowpath)> bp(bowpath);
dynamicval<decltype(bowpath_map)> bpm(bowpath_map);
@@ -536,9 +539,9 @@ EX bool have_bow_target() {
bool b = pcm.try_shooting(false);
changes.rollback();
if(b) return true;
if(b) return c;
}
return false;
return nullptr;
}
EX void showMenu() {

View File

@@ -901,7 +901,7 @@ EX void monstersTurn() {
checkFreedom(pc);
DEBB(debug_turn, ("check"));
checkmove();
checkmove(false);
if(canmove) elec::checklightningfast();

View File

@@ -215,7 +215,7 @@ EX bool activateRecall() {
if(shmup::on) shmup::recall();
if(multi::players > 1) multi::recall();
bfs();
checkmove();
checkmove(false);
drawSafety();
addMessage(XLAT("You are recalled!"));
return true;

View File

@@ -962,6 +962,20 @@ EX void drawMarkers() {
viewmat();
#endif
if(ticks < movehints_ticks) {
if(legalmoves[cwt.at->type] && !vid.mobilecompasssize) queuecircleat(cwt.at, 0.5 + 0.25 * sintick(75), darkena(0xFFFFFF, 0, 0xFF));
for(auto& p: orb_used_where) if(gmatrix.count(p.second))
queuestr(gmatrix[p.second], mapfontscale/100, "X", gradient(0, iinf[p.first].color, -1, sintick(75), 1));
if(bowtarget && gmatrix.count(bowtarget) && bowtarget->cpdist >= 2) {
auto V = gmatrix[bowtarget];
queuestr(V, mapfontscale/100, "X", gradient(0, iinf[itCrossbow].color, -1, sintick(75), 1));
poly_outline = gradient(0, getcs().bowcolor, -1, sintick(75), 1);
queuepolyat(V, cgi.shCrossbowIcon, 0, PPR::LINE);
poly_outline = gradient(0, getcs().bowcolor2, -1, sintick(75), 1);
queuepolyat(V, cgi.shCrossbowstringIcon, 0, PPR::LINE);
}
}
#if CAP_QUEUE
for(cell *c1: crush_now)
queuecircleat(c1, .8, darkena(minf[moCrusher].color, 0, 0xFF));

View File

@@ -357,6 +357,24 @@ string power_help =
"collected. This also affects the mirrorings which happened before "
"collecting the Powerstones.";
EX string ranged_click_help() {
string s;
#if ISMOBILE
if(vid.shifttarget&2)
s = XLAT("\nRanged Orbs can be targeted by long touching the desired location.");
else
s = XLAT("\nRanged Orbs can be targeted by touching the desired location.");
#else
if(vid.shifttarget&1)
s = XLAT("\nRanged Orbs can be targeted by shift-clicking the desired location. ");
else
s = XLAT("\nRanged Orbs can be targeted by clicking the desired location. ");
if(DEFAULTCONTROL)
s += XLAT("You can also scroll to the desired location and then press 't'.");
#endif
return s;
}
EX string generateHelpForItem(eItem it) {
string help = helptitle(XLATN(iinf[it].name), iinf[it].color);
@@ -401,19 +419,8 @@ EX string generateHelpForItem(eItem it) {
#endif
if(isRangedOrb(it)) {
help += XLAT("\nThis is a ranged Orb. ");
#if ISMOBILE
if(vid.shifttarget&2)
help += XLAT("\nRanged Orbs can be targeted by long touching the desired location.");
else
help += XLAT("\nRanged Orbs can be targeted by touching the desired location.");
#else
if(vid.shifttarget&1)
help += XLAT("\nRanged Orbs can be targeted by shift-clicking the desired location. ");
else
help += XLAT("\nRanged Orbs can be targeted by clicking the desired location. ");
help += XLAT("You can also scroll to the desired location and then press 't'.");
#endif
help += XLAT("\nThis is a ranged Orb. \n");
help += ranged_click_help();
help += XLAT("\nYou can never target cells which are adjacent to the player character, or ones out of the sight range.");
}

View File

@@ -687,7 +687,7 @@ EX namespace inv {
usedForbidden = true;
cwt.at->item = it;
evokeOrb(orbmap[uni]);
checkmove();
checkmove(false);
popScreenAll();
}
}

View File

@@ -200,7 +200,7 @@ EX void showOverview() {
dialog::helpToEdit(items[umod], 0, 200, 10, 10);
dialog::get_ne().reaction = [] () {
if(hardcore) canmove = true;
else checkmove();
else checkmove(false);
cheater++;
};
dialog::bound_low(0);

View File

@@ -1024,7 +1024,7 @@ EX void handleInput(int delta, config &scfg) {
}
if(multi::activePlayers() == 1) {
multi::checkonly = true;
checkmove();
checkmove(false);
multi::checkonly = false;
}
}

View File

@@ -603,15 +603,20 @@ EX void activateLightning() {
// roMouse/roKeyboard:
// return orb type if successful, eItem(-1) if do nothing, 0 otherwise
EX bool haveRangedTarget() {
EX map<eItem, cell*> orb_used_where;
EX bool haveRangedTarget(bool complete) {
orb_used_where.clear();
if(!haveRangedOrb())
return false;
for(int i=0; i<isize(dcal); i++) {
cell *c = dcal[i];
if(targetRangedOrb(c, roCheck)) {
return true;
if(eItem it = targetRangedOrb(c, roCheck)) {
if(complete && !orb_used_where.count(it)) orb_used_where[it] = c;
else return true;
}
}
if(complete) return orb_used_where.size();
return false;
}
@@ -619,7 +624,7 @@ void checkmoveO() {
bow::bowpath_map.clear();
if(multi::players > 1 && multi::activePlayers() == 1)
multi::checklastmove();
if(multi::players == 1) checkmove();
if(multi::players == 1) checkmove(false);
}
int teleportAction() {

View File

@@ -273,6 +273,9 @@ bool pcmove::vmsg(moveissue mi) {
return errormsgs && !checkonly;
}
EX int attempts = 0;
EX int movehints_ticks = 0;
EX bool movepcto(int d, int subdir IS(1), bool checkonly IS(false)) {
checked_move_issue.type = miVALID;
pcmove pcm;
@@ -281,6 +284,40 @@ EX bool movepcto(int d, int subdir IS(1), bool checkonly IS(false)) {
pcm.subdir = subdir;
auto b = pcm.movepcto();
global_pushto = pcm.mip.t;
if(!checkonly && !b && multi::players == 1) {
attempts++;
if(attempts == 3) {
attempts = 0;
checkmove(true);
movehints_ticks = ticks + 1000;
if(legalmoves[cwt.at->type]) {
if(!DEFAULTCONTROL) addMessage(XLAT("You can skip your turn."));
#if ISMOBILE
else if(vid.mobilecompasssize) addMessage(XLAT("Touch the center of the compass to skip your turn."));
#else
else if(vid.mobilecompasssize) addMessage(XLAT("Click the center of the compass to skip your turn."));
#endif
else if(dialog::display_keys == 3) addMessage(XLAT("Press Ⓐ to skip your turn."));
else if(dialog::actual_display_keys()) addMessage(XLAT("Press . or s to skip your turn."));
#if ISMOBILE
else if(true) addMessage(XLAT("Touch the Rogue to skip your turn."));
#endif
else addMessage(XLAT("Click the Rogue to skip your turn."));
if(among(cwt.at->land, laPalace, laCaves, laWarpCoast, laWarpSea))
addMessage(XLAT("Wait about 100 turns to let the ghosts decide your fate."));
}
println(hlog, "orb_used_where = ", orb_used_where);
if(orb_used_where.size() == 1)
addMessage(XLAT("You can use your %1.\n", orb_used_where.begin()->first));
else if(orb_used_where.size() > 1) {
string txt;
for(auto x: orb_used_where) { if(txt != "") txt += ", "; txt += dnameof(x.first); }
addMessage(XLAT("You can use: %1.\n", txt));
}
if(orb_used_where.size()) addMessage(ranged_click_help());
if(bowtarget && bowtarget->cpdist >= 2) addMessage(XLAT("You have a bow target."));
}
}
return b;
}
@@ -322,7 +359,7 @@ bool pcmove::try_shooting(bool auto_target) {
if(checkonly) return true;
if(changes.on) changes.commit();
addMessage(XLAT("(shooting while unstable -- no turn passes)"));
checkmove();
checkmove(false);
return true;
}
@@ -428,7 +465,7 @@ bool pcmove::movepcto() {
if(checkonly) { nextmovetype = lmInstant; return true; }
if(warning_shown || orbProtection(itOrbFlash)) return true;
activateFlash();
checkmove();
checkmove(false);
return true;
}
@@ -436,7 +473,7 @@ bool pcmove::movepcto() {
if(checkonly) { nextmovetype = lmInstant; return true; }
if(warning_shown || orbProtection(itOrbLightning)) return true;
activateLightning();
checkmove();
checkmove(false);
return true;
}
@@ -520,7 +557,7 @@ bool pcmove::after_instant(bool kl) {
bfs();
keepLightning = false;
if(multi::players > 1) { multi::whereto[multi::cpid].d = MD_UNDECIDED; return false; }
checkmove();
checkmove(false);
return true;
}

View File

@@ -455,7 +455,7 @@ EX void initgame() {
lastsafety = gold();
bfs();
checkmove();
checkmove(false);
playermoved = true;
if(quotient || sphere)
@@ -1533,6 +1533,7 @@ EX void stop_game() {
#endif
// items[itGreenStone] = 100;
game_active = false;
movehints_ticks = 0;
clearMemory();
#if CAP_DAILY
if(daily::on)

View File

@@ -414,12 +414,12 @@ EX bool handleKeyTour(int sym, int uni) {
popScreenAll();
if(items[itOrbTeleport]) goto give_aether;
items[itOrbTeleport] = 1;
checkmove();
checkmove(false);
if(!canmove) {
if(items[itOrbAether]) goto give_flash;
give_aether:
items[itOrbAether] = 10;
checkmove();
checkmove(false);
if(!canmove) {
give_flash:
activateFlash();