mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2026-10-23 09:32:28 +00:00
lineofsight:: first commit
This commit is contained in:
+18
-15
@@ -2904,8 +2904,10 @@ void celldrawer::draw() {
|
||||
|
||||
checkTide(c);
|
||||
|
||||
if(1) {
|
||||
|
||||
int seen = in_line_of_sight_for_player(c);
|
||||
|
||||
if(seen) {
|
||||
|
||||
if(inmirror(c)) {
|
||||
if(inmirrorcount >= 10) return;
|
||||
cellwalker cw(c);
|
||||
@@ -3045,23 +3047,24 @@ void celldrawer::draw() {
|
||||
queuestrn(V, mapfontscale / 100, s, darkenedby(asciicol, darken), 2);
|
||||
}
|
||||
|
||||
draw_grid();
|
||||
|
||||
if(onradar && WDIM == 2 && GDIM == 3) addradar(V, asciichar, darkenedby(asciicol, darken), 0);
|
||||
|
||||
if(WDIM == 2 && GDIM == 3) radar_grid();
|
||||
#endif
|
||||
|
||||
check_rotations();
|
||||
|
||||
#if CAP_EDIT
|
||||
if(!inHighQual) mapeditor::drawGhosts(c, V, c->type);
|
||||
#endif
|
||||
|
||||
#if CAP_MODEL
|
||||
netgen::buildVertexInfo(c, unshift(V));
|
||||
#endif
|
||||
}
|
||||
|
||||
draw_grid();
|
||||
|
||||
if(WDIM == 2 && GDIM == 3) radar_grid();
|
||||
|
||||
check_rotations();
|
||||
|
||||
#if CAP_EDIT
|
||||
if(!inHighQual) mapeditor::drawGhosts(c, V, c->type);
|
||||
#endif
|
||||
|
||||
#if CAP_MODEL
|
||||
netgen::buildVertexInfo(c, unshift(V));
|
||||
#endif
|
||||
}
|
||||
|
||||
void celldrawer::set_towerfloor(const cellfunction& cf) {
|
||||
|
||||
@@ -1672,6 +1672,14 @@ EX void initConfig() {
|
||||
}, "stereo/high-FOV mode", 'm')
|
||||
->set_reaction(reset_all_shaders);
|
||||
|
||||
param_enum(lineofsight, "mode-lineofsight", los::none)
|
||||
->editable({
|
||||
{"OFF", "You see everything in range, but also everything in range sees you!"},
|
||||
{"geodesic", "Graph geodesic: any sequence of tiles is OK for line-of-sight as long as there are no shortcuts"},
|
||||
{"geometric", "Approximations of geometric straight lines."}},
|
||||
"line-of-sight mode", 'v')
|
||||
->set_reaction(switchLOS_quiet);
|
||||
|
||||
param_f(vid.plevel_factor, "plevel_factor", 0.7);
|
||||
|
||||
param_b(nohud, "no-hud", false);
|
||||
|
||||
@@ -238,6 +238,7 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
cellwalker cw1 = cw + j;
|
||||
// printf("i=%d cd=%d\n", i, c->move(i)->cpdist);
|
||||
cell *c2 = cw1.peek();
|
||||
if(!in_line_of_sight(c2)) continue;
|
||||
|
||||
flagtype f = P_MONSTER;
|
||||
if(param == moIvyRoot) f |= P_IVY;
|
||||
@@ -546,6 +547,8 @@ EX void bfs() {
|
||||
for(auto& t: tempmonsters) t.first->monst = t.second;
|
||||
|
||||
buildAirmap();
|
||||
|
||||
create_los();
|
||||
}
|
||||
|
||||
EX void moverefresh(bool turn IS(true)) {
|
||||
@@ -932,4 +935,85 @@ EX bool looped(vector<cell*>& whirlline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-- lineofsight --*/
|
||||
|
||||
#if HDR
|
||||
enum class los { none, geodesic, geometric };
|
||||
#define PURELOS_LEVEL 10
|
||||
#endif
|
||||
|
||||
EX los lineofsight;
|
||||
/** when did we switch the lineofsight mode */
|
||||
EX int lineofsightAt;
|
||||
|
||||
EX map<cell*, int> current_fov; // 1 == seen, 2 = see through
|
||||
|
||||
EX bool blocks_sight(cell *c, cell *last) {
|
||||
if(inmirror(c)) {
|
||||
cellwalker cw(c, neighborId(c, last));
|
||||
auto cw2 = mirror::reflect(cw);
|
||||
return blocks_sight(cw2.at, cw2.cpeek());
|
||||
}
|
||||
if(c->monst == passive_switch) return true;
|
||||
return (isWall(c) && !among(c->wall, waFreshGrave, waAncientGrave, waClosedGate, waMirrorWall)) || thruVine(c, last);
|
||||
}
|
||||
|
||||
EX bool in_line_of_sight(cell *c) {
|
||||
if(lineofsight == los::none) return true;
|
||||
return current_fov[c];
|
||||
}
|
||||
|
||||
EX bool in_line_of_sight_for_player(cell *c) {
|
||||
if(in_line_of_sight(c)) return true;
|
||||
int range = 0;
|
||||
if(items[itOrbAether]) range = 2;
|
||||
if(items[itOrbDash] || items[itOrbFrog] || items[itOrbPhasing]) range = 3;
|
||||
if(items[itOrbInvis]) range = 999999;
|
||||
return c->cpdist <= range;
|
||||
}
|
||||
|
||||
EX void create_los() {
|
||||
current_fov.clear();
|
||||
if(lineofsight == los::none) lineofsight = los::geometric;
|
||||
if(lineofsight == los::geodesic) {
|
||||
for(auto c: dcal) {
|
||||
if(c->cpdist == 0) current_fov[c] |= 3;
|
||||
forCellEx(c1, c) if(c1->cpdist < c->cpdist && (current_fov[c1] & 2))
|
||||
current_fov[c] |= blocks_sight(c, c1) ? 1 : 3;
|
||||
}
|
||||
}
|
||||
if(lineofsight == los::geometric) {
|
||||
|
||||
for(cell *cp: player_positions()) current_fov[cp] = 3;
|
||||
|
||||
for(auto c: dcal) for(auto cp: player_positions()) {
|
||||
hyperpoint h = tC0(currentmap->relative_matrix(c, cp, C0));
|
||||
transmatrix T = spintox(h);
|
||||
cellwalker at = cwt;
|
||||
|
||||
while(true) {
|
||||
int best_i = -1;
|
||||
ld best_y = HUGE_VAL;
|
||||
for(int i=0; i<at.at->type; i++) {
|
||||
cellwalker at1 = at + i;
|
||||
if(at1.cpeek()->cpdist != at.at->cpdist + 1) continue;
|
||||
transmatrix U = T * currentmap->adj(at.at, at1.spin);
|
||||
hyperpoint U0 = tC0(U);
|
||||
hyperpoint T0 = tC0(T);
|
||||
if(U0[0] < T0[0] + 1e-6) continue;
|
||||
ld y;
|
||||
if(GDIM == 3) y = hypot(U0[1], U0[2]); else y = abs(U0[1]) + (U0[1] > 0 ? 1e-6 : 0);
|
||||
if(y < best_y) { best_y = y; best_i = i; }
|
||||
}
|
||||
if(best_i < 0) break;
|
||||
at = at + best_i;
|
||||
T = T * currentmap->adj(at.at, at.spin);
|
||||
at = at + wstep;
|
||||
if(blocks_sight(at.at, at.cpeek())) { current_fov[at.at] |= 1; break; }
|
||||
current_fov[at.at] |= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -500,7 +500,11 @@ EX color_t stdgridcolor = 0x202020FF;
|
||||
EX int gridcolor(cell *c1, cell *c2) {
|
||||
if(cmode & sm::DRAW && !mapeditor::drawing_tool) return Dark(forecolor);
|
||||
if(!c2)
|
||||
return 0x202020 >> darken;
|
||||
return Dark(0x202020);
|
||||
|
||||
if(!in_line_of_sight(c1) || !in_line_of_sight(c2))
|
||||
return Dark(0x808080);
|
||||
|
||||
int rd1 = rosedist(c1), rd2 = rosedist(c2);
|
||||
if(rd1 != rd2) {
|
||||
int r = rd1+rd2;
|
||||
|
||||
@@ -939,6 +939,10 @@ EX void describeMouseover() {
|
||||
cell *c = mousing ? mouseover : playermoved ? NULL : centerover;
|
||||
string& out = mouseovers;
|
||||
if(!c || instat || getcstat != '-') { }
|
||||
else if(!in_line_of_sight_for_player(c)) {
|
||||
out = XLAT("you cannot see this place");
|
||||
help = XLAT("You cannot currently see this tile.\n\nThis also means that your enemies (except ghosts) will not try to reach you through this tile.");
|
||||
}
|
||||
else if(c->wall != waInvisibleFloor) {
|
||||
out = XLAT1(linf[c->land].name);
|
||||
set_help_to(c->land);
|
||||
@@ -1136,13 +1140,16 @@ EX void describeMouseover() {
|
||||
if(isWarped(c) && !isWarpedType(c->land))
|
||||
out += ", warped";
|
||||
|
||||
if(!in_line_of_sight(c))
|
||||
out += " (magical vision)";
|
||||
|
||||
if(isWarped(c)) {
|
||||
appendHelp(string("\n\n") + XLAT(warpdesc));
|
||||
|
||||
if(S7 != 7 || !BITRUNCATED) if(c->item != itOrb37)
|
||||
appendHelp("\n\n" + other_geometry() + forbidden_unmarked());
|
||||
}
|
||||
|
||||
|
||||
if(isElectricLand(c) || isElectricLand(cwt.at->land)) {
|
||||
using namespace elec;
|
||||
eCharge ch = getCharge(c);
|
||||
|
||||
@@ -515,6 +515,8 @@ EX string mode_description() {
|
||||
if(multi::players > 1) md += " P" + its(multi::players);
|
||||
if(pureHardcore()) md += " hardcore";
|
||||
else if(hardcore) md += " partial hardcore";
|
||||
if(lineofsightAt >= PURELOS_LEVEL) md += "partial lineofsight";
|
||||
else if(lineofsight != los::none) md += " lineofsight";
|
||||
if(daily::on) md += " strange";
|
||||
if(bow::crossbow_mode()) md += " b/" + bow::bowName[bow::style];
|
||||
if(land_structure != default_land_structure())
|
||||
|
||||
+1
-1
@@ -1477,7 +1477,7 @@ EX namespace mapstream {
|
||||
if(shmup::on) shmup::init();
|
||||
|
||||
timerstart = time(NULL); turncount = 0; lastexplore = 0;
|
||||
sagephase = 0; hardcoreAt = 0;
|
||||
sagephase = 0; hardcoreAt = 0; lineofsightAt = 0;
|
||||
timerstopped = false;
|
||||
savecount = 0; savetime = 0;
|
||||
cheater = 1;
|
||||
|
||||
@@ -302,6 +302,10 @@ EX void switchHardcore_quiet() {
|
||||
else { hardcore = true; canmove = true; hardcoreAt = turncount; }
|
||||
}
|
||||
|
||||
EX void switchLOS_quiet() {
|
||||
lineofsightAt = turncount;
|
||||
}
|
||||
|
||||
EX void switchHardcore() {
|
||||
switchHardcore_quiet();
|
||||
if(hardcore)
|
||||
@@ -841,7 +845,9 @@ EX void showChangeMode() {
|
||||
#if CAP_RACING
|
||||
dialog::addBoolItem(XLAT("racing mode"), racing::on, 'R');
|
||||
dialog::add_action(racing::configure_race);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
add_edit(lineofsight);
|
||||
|
||||
show_achievement_eligibility();
|
||||
|
||||
|
||||
@@ -1215,6 +1215,8 @@ EX void groupmove(eMonster movtype, flagtype mf) {
|
||||
|
||||
for(int i=0; i<isize(gendfs); i++) {
|
||||
cell *c = gendfs[i];
|
||||
if(!in_line_of_sight(c)) continue;
|
||||
|
||||
vector<int> dirtable;
|
||||
|
||||
forCellIdAll(c2,t,c) dirtable.push_back(t);
|
||||
|
||||
@@ -1402,6 +1402,11 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
addMessage(XLAT("You cannot target that far away!"));
|
||||
return itNone;
|
||||
}
|
||||
if(!in_line_of_sight_for_player(c)) {
|
||||
if(!isWeakCheck(a))
|
||||
addMessage(XLAT("You cannot target what you cannot see!"));
|
||||
return itNone;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> orb_error_messages;
|
||||
|
||||
@@ -61,6 +61,9 @@ int modediff(score *S) {
|
||||
if(S->box[196] != (int) land_structure) diff += 32;
|
||||
if(S->box[119] != shmup::on) diff += 64;
|
||||
if(pureHardcore() && !isHardcore(S)) diff += 128;
|
||||
if((S->box[422] < PURELOS_LEVEL) != (lineofsightAt < PURELOS_LEVEL)) diff += 8;
|
||||
else if(S->box[421] != int(lineofsight)) diff += 8;
|
||||
|
||||
if(g != gNormal && S->box[120] != specialland)
|
||||
diff += 256;
|
||||
if(g != geometry) {
|
||||
@@ -84,6 +87,9 @@ string modedesc(score *S) {
|
||||
if(S->box[197] > 1) s += "/P" + its(S->box[197]);
|
||||
if(S->box[306]) s += "/i";
|
||||
if(isHardcore(S)) s += "/h";
|
||||
if(S->box[421] == 1 && S->box[422] < PURELOS_LEVEL) s += "/l1";
|
||||
if(S->box[421] == 2 && S->box[422] < PURELOS_LEVEL) s += "/l2";
|
||||
if(S->box[422] >= PURELOS_LEVEL) s += "/l?";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -419,7 +419,7 @@ EX void initgame() {
|
||||
timerstart = time(NULL); turncount = 0; lastexplore = 0; rosewave = 0; rosephase = 0;
|
||||
tickstart = ticks;
|
||||
noiseuntil = 0;
|
||||
sagephase = 0; hardcoreAt = 0;
|
||||
sagephase = 0; hardcoreAt = 0; lineofsightAt = 0;
|
||||
timerstopped = false;
|
||||
savecount = 0; savetime = 0;
|
||||
loadcount = 0; current_loadcount = 0; load_branching = 0;
|
||||
@@ -485,7 +485,7 @@ EX namespace scores {
|
||||
/** \brief the amount of boxes reserved for each hr::score item */
|
||||
#define MAXBOX 500
|
||||
/** \brief currently used boxes in hr::score */
|
||||
#define POSSCORE 421
|
||||
#define POSSCORE 423
|
||||
/** \brief a struct to keep local score from an earlier game */
|
||||
struct score {
|
||||
/** \brief version used */
|
||||
@@ -1062,6 +1062,11 @@ EX void applyBoxes() {
|
||||
setprio(bpWeirdStat);
|
||||
applyBoxNum(current_loadcount, "current load count");
|
||||
|
||||
setprio(bpMode);
|
||||
applyBoxEnum(lineofsight, "lineofsight");
|
||||
setprio(bpMode);
|
||||
applyBoxNum(lineofsightAt, "@lineofsightAt");
|
||||
|
||||
if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid);
|
||||
if(isize(invorb)) { println(hlog, "ERROR: Orbs not taken into account"); exit(1); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user