diff --git a/checkmove.cpp b/checkmove.cpp index adf742d9..06bce420 100644 --- a/checkmove.cpp +++ b/checkmove.cpp @@ -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; itype; 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) diff --git a/config.cpp b/config.cpp index 1ea5a16e..d7a7dc03 100644 --- a/config.cpp +++ b/config.cpp @@ -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); }); diff --git a/crossbow.cpp b/crossbow.cpp index 5ff530a8..841f5865 100644 --- a/crossbow.cpp +++ b/crossbow.cpp @@ -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 bp(bowpath); dynamicval 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() { diff --git a/environment.cpp b/environment.cpp index 51f3d1c4..b3224b1d 100644 --- a/environment.cpp +++ b/environment.cpp @@ -901,7 +901,7 @@ EX void monstersTurn() { checkFreedom(pc); DEBB(debug_turn, ("check")); - checkmove(); + checkmove(false); if(canmove) elec::checklightningfast(); diff --git a/game.cpp b/game.cpp index 436aa865..7870e957 100644 --- a/game.cpp +++ b/game.cpp @@ -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; diff --git a/graph.cpp b/graph.cpp index 34921d01..f8d93417 100644 --- a/graph.cpp +++ b/graph.cpp @@ -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)); diff --git a/help.cpp b/help.cpp index 6a2879f0..430b6efd 100644 --- a/help.cpp +++ b/help.cpp @@ -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."); } diff --git a/inventory.cpp b/inventory.cpp index 92f39c4c..ac0d23f1 100644 --- a/inventory.cpp +++ b/inventory.cpp @@ -687,7 +687,7 @@ EX namespace inv { usedForbidden = true; cwt.at->item = it; evokeOrb(orbmap[uni]); - checkmove(); + checkmove(false); popScreenAll(); } } diff --git a/menus.cpp b/menus.cpp index 47c00651..91ae4204 100644 --- a/menus.cpp +++ b/menus.cpp @@ -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); diff --git a/multi.cpp b/multi.cpp index 84f1748c..d1614bd5 100644 --- a/multi.cpp +++ b/multi.cpp @@ -1024,7 +1024,7 @@ EX void handleInput(int delta, config &scfg) { } if(multi::activePlayers() == 1) { multi::checkonly = true; - checkmove(); + checkmove(false); multi::checkonly = false; } } diff --git a/orbs.cpp b/orbs.cpp index eb95dd27..b4ad1213 100644 --- a/orbs.cpp +++ b/orbs.cpp @@ -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 orb_used_where; + +EX bool haveRangedTarget(bool complete) { + orb_used_where.clear(); if(!haveRangedOrb()) return false; for(int i=0; i 1 && multi::activePlayers() == 1) multi::checklastmove(); - if(multi::players == 1) checkmove(); + if(multi::players == 1) checkmove(false); } int teleportAction() { diff --git a/pcmove.cpp b/pcmove.cpp index 476623ce..daeb2c76 100644 --- a/pcmove.cpp +++ b/pcmove.cpp @@ -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; } diff --git a/system.cpp b/system.cpp index 298a0cbf..c0b71261 100644 --- a/system.cpp +++ b/system.cpp @@ -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) diff --git a/tour.cpp b/tour.cpp index 2c81f893..ac93a44e 100644 --- a/tour.cpp +++ b/tour.cpp @@ -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();