mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-27 14:37:16 +00:00
Merge branch 'zenorogue:master' into main
This commit is contained in:
commit
6117d626d8
@ -307,7 +307,7 @@ EX void achievement_collection2(eItem it, int q) {
|
||||
if(it == itHolyGrail) {
|
||||
if(q == 1) achievement_gain("GRAIL2");
|
||||
if(PURE && geometry == gNormal)
|
||||
achievement_gain("GRAILH", rg::special_geometry);
|
||||
achievement_gain("GRAILH", rg::special_geometry_nicewalls);
|
||||
#if CAP_CRYSTAL
|
||||
if(PURE && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 4 && !crystal::used_compass_inside)
|
||||
achievement_gain("GRAIL4D", rg::special_geometry);
|
||||
|
18
bigstuff.cpp
18
bigstuff.cpp
@ -24,6 +24,11 @@ EX int newRoundTableRadius() {
|
||||
}
|
||||
|
||||
#if CAP_COMPLEX2
|
||||
/** should we generate 'Castle Anthrax' instead of Camelot (an infinite sequence of horocyclic Camelot-likes */
|
||||
EX bool anthrax() {
|
||||
return ls::single() && hyperbolic && !cryst;
|
||||
}
|
||||
|
||||
EX int getAnthraxData(cell *c, bool b) {
|
||||
int d = celldistAlt(c);
|
||||
int rad = 28 + 3 * camelot::anthraxBonus;
|
||||
@ -62,7 +67,7 @@ EX int celldistAltRelative(cell *c) {
|
||||
return celldist(c) - 3;
|
||||
}
|
||||
#if CAP_COMPLEX2
|
||||
if(ls::single()) return getAnthraxData(c, false);
|
||||
if(anthrax()) return getAnthraxData(c, false);
|
||||
#endif
|
||||
return celldistAlt(c) - roundTableRadius(c);
|
||||
}
|
||||
@ -1777,7 +1782,7 @@ EX eMonster camelot_monster() {
|
||||
|
||||
EX void buildCamelot(cell *c) {
|
||||
int d = celldistAltRelative(c);
|
||||
if(ls::single() || (d <= 14 && roundTableRadius(c) > 20)) {
|
||||
if(anthrax() || (d <= 14 && roundTableRadius(c) > 20)) {
|
||||
gen_alt(c);
|
||||
preventbarriers(c);
|
||||
if(d == 10) {
|
||||
@ -1817,7 +1822,8 @@ EX void buildCamelot(cell *c) {
|
||||
}
|
||||
}
|
||||
if(d == 0) c->wall = waRoundTable;
|
||||
if(celldistAlt(c) == 0 && !ls::single()) c->item = itHolyGrail;
|
||||
if(celldistAlt(c) == 0 && !anthrax()) println(hlog, "placed Holy Grail on ", c);
|
||||
if(celldistAlt(c) == 0 && !anthrax()) c->item = itHolyGrail;
|
||||
if(d < 0 && hrand(7000) <= 10 + items[itHolyGrail] * 5)
|
||||
c->monst = camelot_monster();
|
||||
if(d == 1) {
|
||||
@ -1829,12 +1835,12 @@ EX void buildCamelot(cell *c) {
|
||||
if(c->move(i) && celldistAltRelative(c->move(i)) < d)
|
||||
c->mondir = (i+3) % 6;
|
||||
}
|
||||
if(ls::single() && d >= 2 && d <= 8 && hrand(1000) < 10)
|
||||
if(anthrax() && d >= 2 && d <= 8 && hrand(1000) < 10)
|
||||
c->item = itOrbSafety;
|
||||
if(d == 5 && ls::single())
|
||||
if(d == 5 && anthrax())
|
||||
c->item = itGreenStone;
|
||||
if(d <= 10) c->land = laCamelot;
|
||||
if(d > 10 && !eubinary && !ls::single()) {
|
||||
if(d > 10 && !eubinary && !anthrax()) {
|
||||
setland(c, eLand(altmap::orig_land(c->master->alt->alt)));
|
||||
if(c->land == laNone) printf("Camelot\n"); // NONEDEBUG
|
||||
}
|
||||
|
6
cell.cpp
6
cell.cpp
@ -1293,6 +1293,12 @@ EX vector<cell*> build_shortest_path(cell *c1, cell *c2) {
|
||||
}
|
||||
|
||||
EX void clearCellMemory() {
|
||||
#if MAXMDIM >= 4
|
||||
if(intra::in) {
|
||||
intra::erase_all_maps();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for(int i=0; i<isize(allmaps); i++)
|
||||
if(allmaps[i])
|
||||
delete allmaps[i];
|
||||
|
@ -4553,3 +4553,25 @@ Other:
|
||||
2021-12-13 22:32 Update 12.0j:
|
||||
- fixed the victory leaderboards (turns/time to Orb of Yendor/Hyperstones)
|
||||
- fixed the starting land selection feature for equidistant-based lands
|
||||
|
||||
2022-02-03 01:07 Update 12.0k:
|
||||
Orb-related fixes:
|
||||
- Lazurite Figurines no longer appear immediately after using an Orb of Safety
|
||||
- Orb of Chaos is now forbidden in the Dungeon
|
||||
- Stunning from the Orb of Chaos now destroys birds/shadows just like the other sources of stunning
|
||||
- Shadows are now affected by the Orb of Beauty
|
||||
- Stunning the Shadow now temporarily destroys it
|
||||
- draining Orb of Choice now happens after gaining the Purity extras
|
||||
- Orb of Slaying now works against big trees
|
||||
- draw fishtails on friends with empathy
|
||||
|
||||
Achievement fixes:
|
||||
- fixed racing (official tracks are generated again and acknowledged)
|
||||
- Princess Challenge and Heptagonal Knight achievements should be fixed
|
||||
|
||||
Geometry:
|
||||
- more distinct colors in 'eight domains'
|
||||
- improvements to tree rule generator
|
||||
- Goldberg-Coxeter improvements (larger limits supported, warn if outside of the supported limits, some are fixed)
|
||||
- fixed fat edges in some H3 honeycombs
|
||||
- fixed some bugs with Multi-dimensional Crystal quotient space
|
||||
|
@ -152,6 +152,7 @@ struct int_setting : public setting {
|
||||
void show_edit_option(char key) override;
|
||||
cld get_cld() override { return *value; }
|
||||
int_setting *editable(int min_value, int max_value, ld step, string menu_item_name, string help_text, char key) {
|
||||
this->is_editable = true;
|
||||
this->min_value = min_value;
|
||||
this->max_value = max_value;
|
||||
this->menu_item_name = menu_item_name;
|
||||
@ -2890,7 +2891,7 @@ void list_setting::show_edit_option(char key) {
|
||||
int q = isize(options);
|
||||
for(int i=0; i<q; i++) {
|
||||
dialog::addBoolItem(XLAT(options[i].first), get_value() == i, 'a'+i);
|
||||
dialog::add_action([this, i] { set_value(i); popScreen(); });
|
||||
dialog::add_action([this, i] { set_value(i); if(reaction) reaction(); popScreen(); });
|
||||
dialog::addBreak(100);
|
||||
if(options[i].second != "") {
|
||||
dialog::addHelp(XLAT(options[i].second));
|
||||
|
10
control.cpp
10
control.cpp
@ -392,11 +392,17 @@ EX void full_rotate_camera(int dir, ld val) {
|
||||
else if(GDIM == 3) {
|
||||
val *= camera_rot_speed;
|
||||
if(third_person_rotation) shift_view(ctangent(2, -third_person_rotation)), didsomething = true, playermoved = false;
|
||||
if(keep_vertical()) {
|
||||
ld max_angle = quarter_circle - 1e-4;
|
||||
if(walking::on && dir == 1) {
|
||||
max_angle /= degree;
|
||||
walking::eye_angle += val * walking::eye_angle_scale / degree;
|
||||
if(walking::eye_angle > max_angle) walking::eye_angle = max_angle;
|
||||
if(walking::eye_angle < -max_angle) walking::eye_angle = -max_angle;
|
||||
}
|
||||
else if(keep_vertical()) {
|
||||
hyperpoint vv = vertical_vector();
|
||||
ld alpha = -atan2(vv[2], vv[1]);
|
||||
rotate_view(cspin(2, 1, alpha));
|
||||
ld max_angle = quarter_circle - 1e-4;
|
||||
if(dir == 1 && alpha + val > max_angle)
|
||||
val = max_angle - alpha;
|
||||
if(dir == 1 && alpha + val < -max_angle)
|
||||
|
@ -686,8 +686,8 @@ struct hrmap_crystal : hrmap_standard {
|
||||
}
|
||||
|
||||
transmatrix relative_matrixh(heptagon *h2, heptagon *h1, const hyperpoint& hint) override {
|
||||
if(!crystal3()) return hrmap::relative_matrixh(h2, h1, hint);
|
||||
return relative_matrix(h2->c7, h1->c7, hint);
|
||||
if(!crystal3()) return hrmap_standard::relative_matrixh(h2, h1, hint);
|
||||
return relative_matrixc(h2->c7, h1->c7, hint);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
4
fake.cpp
4
fake.cpp
@ -373,12 +373,16 @@ EX namespace fake {
|
||||
transmatrix ray_iadj(cell *c, int i) override {
|
||||
if(WDIM == 2)
|
||||
return to_other_side(get_corner(c, i), get_corner(c, i+1));
|
||||
#if MAXMDIM >= 4
|
||||
if(PURE) return iadj(c, i);
|
||||
auto& v = get_cellshape(c).faces_local[i];
|
||||
hyperpoint h =
|
||||
project_on_triangle(v[0], v[1], v[2]);
|
||||
transmatrix T = rspintox(h);
|
||||
return T * xpush(-2*hdist0(h)) * spintox(h);
|
||||
#else
|
||||
return Id;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1270,6 +1270,7 @@ int read_geom_args() {
|
||||
PHASEFROM(2);
|
||||
set_variation(eVariation::warped);
|
||||
}
|
||||
#if MAXMDIM >= 4
|
||||
else if(argis("-subcubes")) {
|
||||
PHASEFROM(2);
|
||||
stop_game();
|
||||
@ -1301,6 +1302,7 @@ int read_geom_args() {
|
||||
shift(); reg3::coxeter_param = argi();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if CAP_FIELD
|
||||
else if(argis("-fi")) {
|
||||
fieldpattern::info();
|
||||
|
12
geometry.cpp
12
geometry.cpp
@ -744,10 +744,12 @@ void geometry_information::prepare_basics() {
|
||||
base_distlimit = arb::current.range;
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(is_subcube_based(variation)) {
|
||||
scalefactor /= reg3::subcube_count;
|
||||
orbsize /= reg3::subcube_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(scale_used()) {
|
||||
scalefactor *= vid.creature_scale;
|
||||
@ -1142,8 +1144,10 @@ EX string cgi_string() {
|
||||
|
||||
if(GOLDBERG_INV) V("GP", its(gp::param.first) + "," + its(gp::param.second));
|
||||
if(IRREGULAR) V("IRR", its(irr::irrid));
|
||||
#if MAXMDIM >= 4
|
||||
if(is_subcube_based(variation)) V("SC", its(reg3::subcube_count));
|
||||
if(variation == eVariation::coxeter) V("COX", its(reg3::coxeter_param));
|
||||
#endif
|
||||
|
||||
#if CAP_ARCM
|
||||
if(arcm::in()) V("ARCM", arcm::current.symbol);
|
||||
@ -1198,6 +1202,12 @@ EX string cgi_string() {
|
||||
return s;
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
#define IFINTRA(x,y) x
|
||||
#else
|
||||
#define IFINTRA(x,y) y
|
||||
#endif
|
||||
|
||||
EX void check_cgi() {
|
||||
string s = cgi_string();
|
||||
|
||||
@ -1207,7 +1217,7 @@ EX void check_cgi() {
|
||||
if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp;
|
||||
if(arcm::alt_cgip) arcm::alt_cgip->timestamp = ntimestamp;
|
||||
|
||||
if(isize(cgis) > 4 && intra::data.empty()) {
|
||||
if(isize(cgis) > 4 && IFINTRA(intra::data.empty(), true)) {
|
||||
vector<pair<int, string>> timestamps;
|
||||
for(auto& t: cgis) timestamps.emplace_back(-t.second.timestamp, t.first);
|
||||
sort(timestamps.begin(), timestamps.end());
|
||||
|
@ -1162,6 +1162,7 @@ EX namespace gp {
|
||||
return S3 == 3 ? XLAT("chamfered") : XLAT("expanded");
|
||||
else if(GOLDBERG && param == loc(3, 0) && S3 == 3)
|
||||
return XLAT("2x bitruncated");
|
||||
#if MAXMDIM >= 4
|
||||
else if(variation == eVariation::subcubes)
|
||||
return XLAT("subcubed") + "(" + its(reg3::subcube_count) + ")";
|
||||
else if(variation == eVariation::dual_subcubes)
|
||||
@ -1170,6 +1171,7 @@ EX namespace gp {
|
||||
return XLAT("bitruncated-subcubed") + "(" + its(reg3::subcube_count) + ")";
|
||||
else if(variation == eVariation::coxeter)
|
||||
return XLAT("subdivided") + "(" + its(reg3::coxeter_param) + ")";
|
||||
#endif
|
||||
else {
|
||||
auto p = human_representation(param);
|
||||
string s = "GP(" + its(p.first) + "," + its(p.second) + ")";
|
||||
|
@ -3808,10 +3808,12 @@ EX int get_darkval(cell *c, int d) {
|
||||
const int darkval_kite[12] = {0, 2, 0, 2, 4, 4, 6, 6, 6, 6, 6, 6};
|
||||
const int darkval_nil[8] = {6,6,0,3,6,6,0,3};
|
||||
const int darkval_nih[11] = {0,2,0,2,4,6,6,6,6,6,6};
|
||||
#if MAXMDIM >= 4
|
||||
if(among(variation, eVariation::dual_subcubes, eVariation::bch, eVariation::bch_oct, eVariation::coxeter)) {
|
||||
int v = reg3::get_face_vertex_count(c, d);
|
||||
return v-3;
|
||||
}
|
||||
#endif
|
||||
if(sphere) return darkval_s12[d];
|
||||
if(euclid && S7 == 6) return darkval_e6[d];
|
||||
if(euclid && S7 == 12) return darkval_e12[d];
|
||||
|
4
hyper.h
4
hyper.h
@ -13,8 +13,8 @@
|
||||
#define _HYPER_H_
|
||||
|
||||
// version numbers
|
||||
#define VER "12.0j"
|
||||
#define VERNUM_HEX 0xA90A
|
||||
#define VER "12.0k"
|
||||
#define VERNUM_HEX 0xA90B
|
||||
|
||||
#include "sysconfig.h"
|
||||
|
||||
|
@ -466,8 +466,8 @@ EX transmatrix to_other_side(hyperpoint h1, hyperpoint h2) {
|
||||
|
||||
/** @brief positive for a material vertex, 0 for ideal vertex, negative for ultra-ideal vertex */
|
||||
EX ld material(const hyperpoint& h) {
|
||||
if(sphere) return intval(h, Hypc);
|
||||
else if(hyperbolic) return -intval(h, Hypc);
|
||||
if(sphere || in_s2xe()) return intval(h, Hypc);
|
||||
else if(hyperbolic || in_h2xe()) return -intval(h, Hypc);
|
||||
else if(sl2) return h[2]*h[2] + h[3]*h[3] - h[0]*h[0] - h[1]*h[1];
|
||||
else return h[LDIM];
|
||||
}
|
||||
@ -505,7 +505,7 @@ EX hyperpoint normalize(hyperpoint H) {
|
||||
/** like normalize but makes (ultra)ideal points material */
|
||||
EX hyperpoint ultra_normalize(hyperpoint H) {
|
||||
if(material(H) <= 0) {
|
||||
H[LDIM] = hypot_d(LDIM, H) + 1e-6;
|
||||
H[LDIM] = hypot_d(LDIM, H) + 1e-10;
|
||||
}
|
||||
return normalize(H);
|
||||
}
|
||||
@ -760,7 +760,7 @@ EX hyperpoint parabolic13(hyperpoint h) {
|
||||
EX transmatrix spintoc(const hyperpoint& H, int t, int f) {
|
||||
transmatrix T = Id;
|
||||
ld R = hypot(H[f], H[t]);
|
||||
if(R >= 1e-12) {
|
||||
if(R >= 1e-15) {
|
||||
T[t][t] = +H[t]/R; T[t][f] = +H[f]/R;
|
||||
T[f][t] = -H[f]/R; T[f][f] = +H[t]/R;
|
||||
}
|
||||
@ -774,7 +774,7 @@ EX transmatrix spintoc(const hyperpoint& H, int t, int f) {
|
||||
EX transmatrix rspintoc(const hyperpoint& H, int t, int f) {
|
||||
transmatrix T = Id;
|
||||
ld R = hypot(H[f], H[t]);
|
||||
if(R >= 1e-12) {
|
||||
if(R >= 1e-15) {
|
||||
T[t][t] = +H[t]/R; T[t][f] = -H[f]/R;
|
||||
T[f][t] = +H[f]/R; T[f][f] = +H[t]/R;
|
||||
}
|
||||
@ -853,7 +853,7 @@ EX transmatrix ggpushxto0(const hyperpoint& H, ld co) {
|
||||
return mscale(PIU(ggpushxto0(d.second, co)), d.first * co);
|
||||
}
|
||||
transmatrix res = Id;
|
||||
if(sqhypot_d(GDIM, H) < 1e-12) return res;
|
||||
if(sqhypot_d(GDIM, H) < 1e-16) return res;
|
||||
ld fac = -curvature()/(H[LDIM]+1);
|
||||
for(int i=0; i<GDIM; i++)
|
||||
for(int j=0; j<GDIM; j++)
|
||||
|
12
hypgraph.cpp
12
hypgraph.cpp
@ -213,7 +213,7 @@ ld find_zlev(hyperpoint& H) {
|
||||
|
||||
if(spatial_graphics) {
|
||||
ld zlev = zlevel(H);
|
||||
if(zlev > 1-1e-6 && zlev < 1+1e-6) return 1;
|
||||
if(zlev > 1-1e-9 && zlev < 1+1e-9) return 1;
|
||||
H /= zlev;
|
||||
return zlev;
|
||||
}
|
||||
@ -628,9 +628,9 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
|
||||
ret[0] = -models::osin - H[0];
|
||||
ld height = 0;
|
||||
if(zlev != 1) {
|
||||
if(abs(models::ocos) > 1e-5)
|
||||
if(abs(models::ocos) > 1e-9)
|
||||
height += H[1] * (pow(zlev, models::ocos) - 1);
|
||||
if(abs(models::ocos) > 1e-5 && models::osin)
|
||||
if(abs(models::ocos) > 1e-9 && models::osin)
|
||||
height += H[0] * models::osin * (pow(zlev, models::ocos) - 1) / models::ocos;
|
||||
else if(models::osin)
|
||||
height += H[0] * models::osin * log(zlev);
|
||||
@ -2013,6 +2013,8 @@ EX void optimizeview() {
|
||||
fixmatrix(View);
|
||||
callhooks(hooks_postoptimize);
|
||||
|
||||
walking::handle();
|
||||
|
||||
if(is_boundary(centerover))
|
||||
centerover = c, View = oView;
|
||||
else
|
||||
@ -2756,7 +2758,7 @@ EX bool do_draw(cell *c) {
|
||||
// do not display not fully generated cells, unless changing range allowed
|
||||
if(c->mpdist > 7 && !allowChangeRange()) return false;
|
||||
// in the Yendor Challenge, scrolling back is forbidden
|
||||
if(c->cpdist > 7 && (yendor::on || isHaunted(cwt.at->land)) && !cheater && !autocheat) return false;
|
||||
if(c->cpdist > get_sightrange() && (yendor::on || isHaunted(cwt.at->land)) && !cheater && !autocheat) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2907,7 +2909,9 @@ EX void shift_view(hyperpoint H) {
|
||||
static bool recursive = false;
|
||||
if(!recursive && intra::in) {
|
||||
dynamicval<bool> r(recursive, true);
|
||||
#if MAXMDIM >= 4
|
||||
intra::shift_view_portal(H);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
View = get_shift_view_of(H, View);
|
||||
|
308
intra.cpp
308
intra.cpp
@ -6,6 +6,7 @@ EX namespace intra {
|
||||
|
||||
EX bool in;
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
#if HDR
|
||||
/** information per every space connected with intra-portals */
|
||||
struct intra_data {
|
||||
@ -68,9 +69,9 @@ hyperpoint portal_data::to_poco(hyperpoint h) const {
|
||||
ld z = product_decompose(h).first;
|
||||
h /= exp(z);
|
||||
auto h1 = h;
|
||||
h[0] = asin_auto(h1[1]);
|
||||
h[2] = asin_auto_clamp(h1[0]);
|
||||
h[1] = z;
|
||||
h[2] = asin_auto_clamp(h1[0] / cos_auto(h[0]));
|
||||
h[0] = asin_auto_clamp(h1[1] / cos_auto(h[2]));
|
||||
h[3] = 1;
|
||||
return h;
|
||||
}
|
||||
@ -90,6 +91,10 @@ hyperpoint portal_data::to_poco(hyperpoint h) const {
|
||||
else {
|
||||
h = T * h;
|
||||
h /= h[3];
|
||||
if(sphere)
|
||||
h[2] /= sqrt(1+h[0]*h[0]+h[1]*h[1]);
|
||||
if(hyperbolic)
|
||||
h[2] /= sqrt(1-h[0]*h[0]-h[1]*h[1]);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
@ -108,8 +113,8 @@ hyperpoint portal_data::from_poco(hyperpoint h) const {
|
||||
}
|
||||
else if(prod && kind == 0) {
|
||||
auto h0 = h;
|
||||
h[0] = sin_auto(h0[2]) * cos_auto(h0[0]);
|
||||
h[1] = sin_auto(h0[0]);
|
||||
h[0] = sin_auto(h0[2]);
|
||||
h[1] = sin_auto(h0[0]) * cos_auto(h0[2]);
|
||||
h[2] = cos_auto(h0[0]) * cos_auto(h0[2]);
|
||||
h[3] = 1;
|
||||
return iT * h * exp(h0[1]);
|
||||
@ -125,13 +130,17 @@ hyperpoint portal_data::from_poco(hyperpoint h) const {
|
||||
}
|
||||
else {
|
||||
h[3] = 1;
|
||||
if(sphere)
|
||||
h[2] *= sqrt(1+h[0]*h[0]+h[1]*h[1]);
|
||||
if(hyperbolic)
|
||||
h[2] *= sqrt(1-h[0]*h[0]-h[1]*h[1]);
|
||||
return normalize(iT * h);
|
||||
}
|
||||
}
|
||||
|
||||
EX portal_data make_portal(cellwalker cw, int spin) {
|
||||
if(debug_portal & 33)
|
||||
println(hlog, "working in: ", full_geometry_name());
|
||||
if(debug_portal & 289)
|
||||
println(hlog, "working in: ", full_geometry_name(), " wall no ", cw.spin, "/", cw.at->type);
|
||||
auto& ss = currentmap->get_cellshape(cw.at);
|
||||
auto fac = ss.faces_local[cw.spin];
|
||||
portal_data id;
|
||||
@ -252,6 +261,23 @@ EX portal_data make_portal(cellwalker cw, int spin) {
|
||||
println(hlog, "chosen edge is ", first, "--", second);
|
||||
}
|
||||
|
||||
if(debug_portal & 256) {
|
||||
println(hlog, "portal scale = ", id.scale);
|
||||
auto res = [&] (ld x, ld y, ld z) {
|
||||
hyperpoint h = hyperpoint(x, y, z, 1);
|
||||
return id.from_poco(h);
|
||||
};
|
||||
for(int x=0; x<5; x++) {
|
||||
println(hlog, "horizontal ", x, " = ", hdist(res(x*.1,0,0), res(x*.1+.001,0,0)));
|
||||
println(hlog, "vertical ", x, " = ", hdist(res(x*.1,0,0), res(x*.1,0.001,0)));
|
||||
println(hlog, "deep ", x, " = ", hdist(res(x*.1,0,0), res(x*.1,0,0.001)));
|
||||
}
|
||||
hyperpoint a = hyperpoint(.4, .2, .1, 1);
|
||||
println(hlog, "a = ", a);
|
||||
println(hlog, "b = ", id.from_poco(a));
|
||||
println(hlog, "c = ", id.to_poco(id.from_poco(a)));
|
||||
}
|
||||
|
||||
if(debug_portal & 1) {
|
||||
for(auto p: fac) {
|
||||
auto p2 = id.to_poco(p);
|
||||
@ -497,7 +523,7 @@ EX void shift_view_portal(hyperpoint H) {
|
||||
println(hlog, "maxv = ", maxv);
|
||||
shift_view(H * maxv);
|
||||
check_portal_movement();
|
||||
shift_view(H * (1 - maxv));
|
||||
shift_view_portal(H * (1 - maxv));
|
||||
}
|
||||
|
||||
EX const connection_data* through_portal() {
|
||||
@ -515,11 +541,9 @@ EX const connection_data* through_portal() {
|
||||
|
||||
EX void check_portal_movement() {
|
||||
auto p = through_portal();
|
||||
ld c = camera_speed;
|
||||
|
||||
if(p) {
|
||||
ld eps = 1e-5;
|
||||
c /= p->id1.scale;
|
||||
anims::cycle_length /= p->id1.scale;
|
||||
ld ss = pow(eps, -2);
|
||||
|
||||
array<hyperpoint, 4> ds; /* camera, forward, upward */
|
||||
@ -579,9 +603,17 @@ EX void check_portal_movement() {
|
||||
println(hlog, "goal: at = ", xds[0], " det = ", dsdet(xds), " bt = ", bt::minkowski_to_bt(xds[0]));
|
||||
}
|
||||
|
||||
c *= p->id2.scale;
|
||||
anims::cycle_length *= p->id2.scale;
|
||||
camera_speed = c;
|
||||
ld scale = p->id2.scale / p->id1.scale;
|
||||
|
||||
camera_speed *= scale;
|
||||
anims::cycle_length *= scale;
|
||||
#if CAP_VR
|
||||
vrhr::absolute_unit_in_meters *= scale;
|
||||
#endif
|
||||
if(walking::eye_level != -1) walking::eye_level *= scale;
|
||||
|
||||
walking::floor_dir = -1;
|
||||
walking::on_floor_of = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,7 +627,7 @@ void erase_unconnected(cellwalker cw) {
|
||||
|
||||
int edit_spin;
|
||||
|
||||
void show_portals() {
|
||||
EX void show_portals() {
|
||||
gamescreen(1);
|
||||
|
||||
dialog::init(XLAT("manage portals"));
|
||||
@ -665,6 +697,8 @@ void show_portals() {
|
||||
}
|
||||
}
|
||||
|
||||
walking::add_options();
|
||||
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
@ -729,6 +763,22 @@ EX void kill(int id) {
|
||||
println(hlog, isize(to_remove), " connections and ", isize(to_erase_cell), " cells erased");
|
||||
}
|
||||
|
||||
EX void erase_all_maps() {
|
||||
println(hlog, "erase_all_maps called");
|
||||
data[current].gd.storegame();
|
||||
in = false;
|
||||
for(int i=0; i<isize(data); i++) {
|
||||
current = i;
|
||||
ginf[gProduct] = data[i].gi;
|
||||
data[i].gd.restoregame();
|
||||
clearCellMemory();
|
||||
}
|
||||
intra_id.clear();
|
||||
connections.clear();
|
||||
data.clear();
|
||||
full_sample_list.clear();
|
||||
}
|
||||
|
||||
EX set<cell*> need_to_save;
|
||||
|
||||
EX void prepare_need_to_save() {
|
||||
@ -764,8 +814,232 @@ auto hooks1 =
|
||||
arg::shift(); int i = arg::argi(); be_ratio_edge(i);
|
||||
})
|
||||
+ arg::add3("-debug-portal", [] { arg::shift(); debug_portal = arg::argi(); });
|
||||
|
||||
|
||||
#endif
|
||||
EX }
|
||||
|
||||
}
|
||||
EX namespace walking {
|
||||
|
||||
EX bool on;
|
||||
|
||||
EX bool auto_eyelevel;
|
||||
|
||||
EX int floor_dir = -1;
|
||||
EX cell *on_floor_of = nullptr;
|
||||
EX ld eye_level = 0.2174492;
|
||||
EX ld eye_angle = 0;
|
||||
EX ld eye_angle_scale = 1;
|
||||
|
||||
int ticks_end, ticks_last;
|
||||
|
||||
EX set<color_t> colors_of_floors;
|
||||
|
||||
EX bool isFloor(cell *c) {
|
||||
if(!isWall(c)) return false;
|
||||
if(colors_of_floors.empty()) return true;
|
||||
if(c->wall != waWaxWall) return false;
|
||||
return colors_of_floors.count(c->landparam);
|
||||
}
|
||||
|
||||
EX void handle() {
|
||||
if(!on) return;
|
||||
|
||||
if(floor_dir == -1 || on_floor_of != centerover) {
|
||||
vector<int> choices;
|
||||
for(int i=0; i<centerover->type; i++)
|
||||
if(isFloor(centerover->cmove(i)))
|
||||
choices.push_back(i);
|
||||
|
||||
if(sol && isize(choices) == 2) choices.pop_back();
|
||||
|
||||
if(isize(choices) == 1) {
|
||||
on_floor_of = centerover;
|
||||
floor_dir = choices[0];
|
||||
}
|
||||
else if(colors_of_floors.empty() && sn::in()) {
|
||||
on_floor_of = centerover;
|
||||
auto z = inverse(View) * C0;
|
||||
switch(geometry) {
|
||||
case gSol:
|
||||
floor_dir = (z[2] > 0) ? 2 : 6;
|
||||
return;
|
||||
case gNIH:
|
||||
floor_dir = (z[2] > 0) ? 5 : 4;
|
||||
return;
|
||||
case gSolN:
|
||||
floor_dir = (z[2] > 0) ? 4 : 6;
|
||||
return;
|
||||
default: throw hr_exception("not solnihv");
|
||||
}
|
||||
}
|
||||
else if(colors_of_floors.empty() && hyperbolic && bt::in()) {
|
||||
auto z = bt::minkowski_to_bt(inverse(View) * C0);
|
||||
on_floor_of = centerover;
|
||||
floor_dir = z[2] > 0 ? bt::updir() : 0;
|
||||
println(hlog, "set floor_dir to ", floor_dir);
|
||||
}
|
||||
else {
|
||||
println(hlog, "there are ", isize(choices), " choices for floor_dir");
|
||||
if(!on_floor_of) return;
|
||||
}
|
||||
}
|
||||
|
||||
struct face {
|
||||
hyperpoint h0, hx, hy;
|
||||
};
|
||||
|
||||
transmatrix ToOld = currentmap->relative_matrix(on_floor_of, centerover, C0);
|
||||
auto& csh = currentmap->get_cellshape(on_floor_of);
|
||||
face f;
|
||||
f.h0 = ToOld * csh.faces_local[floor_dir][0];
|
||||
f.hx = ToOld * csh.faces_local[floor_dir][1];
|
||||
f.hy = ToOld * csh.faces_local[floor_dir][2];
|
||||
|
||||
auto find_nearest = [&] (const face& fac, hyperpoint at) {
|
||||
if(sol) { at[2] = fac.h0[2]; return at; }
|
||||
else if(hyperbolic && bt::in()) {
|
||||
auto z = bt::minkowski_to_bt(at);
|
||||
z[2] = bt::minkowski_to_bt(fac.h0)[2];
|
||||
return bt::bt_to_minkowski(z);
|
||||
}
|
||||
else if(prod && bt::in()) {
|
||||
auto dec = product_decompose(at);
|
||||
hyperpoint dep = PIU( deparabolic13(dec.second) );
|
||||
hyperpoint h = product_decompose(fac.h0).second;
|
||||
h = PIU( deparabolic13(h) );
|
||||
dep[0] = h[0];
|
||||
return zshift(PIU(parabolic13(dep)), dec.first);
|
||||
}
|
||||
else {
|
||||
transmatrix M = ray::mirrorize(currentmap->ray_iadj(on_floor_of, floor_dir));
|
||||
M = ToOld * M * inverse(ToOld);
|
||||
return mid(at, M * at);
|
||||
}
|
||||
};
|
||||
|
||||
hyperpoint at = tC0(inverse(View));
|
||||
if(invalid_point(at)) {
|
||||
println(hlog, "at is invalid!");
|
||||
on = false;
|
||||
return;
|
||||
}
|
||||
|
||||
auto wallpt = find_nearest(f, at);
|
||||
|
||||
ld view_eps = 1e-5;
|
||||
|
||||
transmatrix spin_T;
|
||||
bool use_T = false;
|
||||
|
||||
if(eye_angle) use_T = true, spin_T = cspin(1, 2, -eye_angle * degree);
|
||||
#if CAP_VR
|
||||
if(vrhr::active() && !vrhr::first && vrhr::hsm != vrhr::eHeadset::none) {
|
||||
use_T = true;
|
||||
spin_T = vrhr::hmd_ref_at;
|
||||
// print(hlog, "HMD seems to be at altitude ", spin_T[1][3], " depth ", spin_T[2][3], " zeros are ", spin_T[3][1], " and ", spin_T[3][2]);
|
||||
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
||||
spin_T = vrhr::sm * inverse(spin_T);
|
||||
eye_level = -spin_T[1][3] / vrhr::absolute_unit_in_meters;
|
||||
if(eye_level < .001) eye_level = 0.001;
|
||||
vrhr::be_33(spin_T);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(use_T) rotate_view(spin_T);
|
||||
hyperpoint front = inverse(get_shift_view_of(ctangent(2, -view_eps), View)) * C0;
|
||||
hyperpoint up = inverse(get_shift_view_of(ctangent(1, +view_eps), View)) * C0;
|
||||
|
||||
auto fwallpt = find_nearest(f, front);
|
||||
|
||||
transmatrix T = nonisotropic ? nisot::translate(wallpt, -1) : gpushxto0(wallpt);
|
||||
hyperpoint dx = inverse_exp(shiftless(T * at));
|
||||
|
||||
transmatrix Tf = nonisotropic ? nisot::translate(fwallpt, -1) : gpushxto0(fwallpt);
|
||||
hyperpoint dxf = inverse_exp(shiftless(Tf * front));
|
||||
|
||||
if(eye_level == -1) eye_level = hypot_d(3, dx);
|
||||
|
||||
auto smooth = [&] (hyperpoint h1, hyperpoint h2) {
|
||||
if(ticks < ticks_end) {
|
||||
ld last_t = ilerp(ticks_end-1000, ticks_end, ticks_last);
|
||||
ld curr_t = ilerp(ticks_end-1000, ticks_end, ticks);
|
||||
last_t = last_t * last_t * (3-2*last_t);
|
||||
curr_t = curr_t * curr_t * (3-2*curr_t);
|
||||
ld t = ilerp(last_t, 1, curr_t);
|
||||
return lerp(h1, h2, t);
|
||||
}
|
||||
return h2;
|
||||
};
|
||||
|
||||
auto oView = View;
|
||||
set_view(
|
||||
smooth(at, inverse(T) * direct_exp(dx / hypot_d(3, dx) * eye_level)),
|
||||
smooth(front, inverse(Tf) * direct_exp(dxf / hypot_d(3, dxf) * eye_level)),
|
||||
smooth(up, inverse(T) * direct_exp(dx / hypot_d(3, dx) * (eye_level + view_eps)))
|
||||
);
|
||||
if(use_T) rotate_view(inverse(spin_T));
|
||||
playermoved = false;
|
||||
|
||||
auto nat = tC0(inverse(View));
|
||||
if(invalid_point(nat)) {
|
||||
println(hlog, "at is invalid after fixing!");
|
||||
View = oView;
|
||||
return;
|
||||
}
|
||||
|
||||
ticks_last = ticks;
|
||||
}
|
||||
|
||||
EX void add_options() {
|
||||
dialog::addBoolItem("walking mode", on, 'w');
|
||||
dialog::add_action([] {
|
||||
on = !on;
|
||||
if(on && auto_eyelevel) eye_level = -1;
|
||||
floor_dir = -1;
|
||||
on_floor_of = nullptr;
|
||||
ticks_last = ticks;
|
||||
ticks_end = ticks + 1000;
|
||||
});
|
||||
add_edit(eye_level);
|
||||
add_edit(eye_angle);
|
||||
if(point_direction >= 0 && point_direction < centerover->type) {
|
||||
cell *c = centerover->move(point_direction);
|
||||
if(c && c->wall == waWaxWall) {
|
||||
color_t col = c->landparam;
|
||||
dialog::addBoolItem("we are facing floor (color " + format("%06X", col) + ")", colors_of_floors.count(col), 'n');
|
||||
dialog::add_action([col] {
|
||||
if(colors_of_floors.count(col)) colors_of_floors.erase(col);
|
||||
else colors_of_floors.insert(col);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto a = addHook(hooks_configfile, 100, [] {
|
||||
param_b(auto_eyelevel, "auto_eyelevel")
|
||||
-> editable("keep eye level when walking enabled", 'L');
|
||||
param_f(eye_level, "eye_level")
|
||||
-> editable(0, 5, .1, "walking eye level",
|
||||
"Distance from the floor to the eye in the walking mode, in absolute units. In VR this is adjusted automatically.",
|
||||
'e')
|
||||
->set_extra([] { add_edit(auto_eyelevel); });
|
||||
param_f(eye_angle, "eye_angle")
|
||||
-> editable(-90, 90, 15, "walking eye angle",
|
||||
"0 = looking forward, 90 = looking upward. In VR this is adjusted automatically.",
|
||||
'k')
|
||||
->set_extra([] { add_edit(eye_angle_scale); });
|
||||
param_f(eye_angle_scale, "eye_angle_scale")
|
||||
-> editable(-2, 0, 2, "eye angle scale",
|
||||
"1 = the angle can be changed with keyboard or mouse movements, 0 = the angle is fixed",
|
||||
'k');
|
||||
})
|
||||
+ addHook(hooks_clearmemory, 40, [] { on_floor_of = nullptr; floor_dir = -1; })
|
||||
+ arg::add3("-walk-on", [] {
|
||||
on = true;
|
||||
if(auto_eyelevel) eye_level = -1;
|
||||
floor_dir = -1;
|
||||
on_floor_of = nullptr;
|
||||
ticks_last = ticks_end = ticks;
|
||||
});
|
||||
|
||||
EX }
|
||||
}
|
||||
|
@ -2588,7 +2588,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
|
||||
bool locked = true;
|
||||
forCellEx(c1, c) if(!c1->wall) locked = false;
|
||||
if(locked) c->item = itEclectic;
|
||||
if(locked && !safety) c->item = itEclectic;
|
||||
|
||||
if(c->wall == waNone && hrand_monster(2500) < 30 + items[itEclectic] + yendor::hardness() && !safety)
|
||||
gen_eclectic_monster(c);
|
||||
|
@ -253,7 +253,7 @@ EX bool legacy_racing() {
|
||||
|
||||
EX bool rcheck(string which, int qty, int x) {
|
||||
return hrand(qty) < x;
|
||||
};
|
||||
}
|
||||
|
||||
EX int wallchance_legacy(cell *c, bool deepOcean) {
|
||||
eLand l = c->land;
|
||||
|
@ -449,12 +449,14 @@ EX namespace mapstream {
|
||||
f.write(gp::param.second);
|
||||
}
|
||||
#endif
|
||||
#if MAXMDIM >= 4
|
||||
if(variation == eVariation::coxeter) {
|
||||
f.write(reg3::coxeter_param);
|
||||
}
|
||||
if(is_subcube_based(variation )) {
|
||||
f.write(reg3::subcube_count);
|
||||
}
|
||||
#endif
|
||||
#if CAP_FIELD
|
||||
if(geometry == gFieldQuotient) {
|
||||
using namespace fieldpattern;
|
||||
@ -541,12 +543,14 @@ EX namespace mapstream {
|
||||
f.read(gp::param.second);
|
||||
}
|
||||
#endif
|
||||
#if MAXMDIM >= 4
|
||||
if(variation == eVariation::coxeter && vernum >= 0xA908) {
|
||||
f.read(reg3::coxeter_param);
|
||||
}
|
||||
if(is_subcube_based(variation) && vernum >= 0xA908) {
|
||||
f.read(reg3::subcube_count);
|
||||
}
|
||||
#endif
|
||||
#if CAP_CRYSTAL
|
||||
if(cryst && vernum >= 10504) {
|
||||
int sides;
|
||||
@ -702,7 +706,9 @@ EX namespace mapstream {
|
||||
}
|
||||
|
||||
addToQueue(save_start());
|
||||
#if MAXMDIM >= 4
|
||||
if(intra::in) intra::prepare_need_to_save();
|
||||
#endif
|
||||
for(int i=0; i<isize(cellbyid); i++) {
|
||||
cell *c = cellbyid[i];
|
||||
if(i) {
|
||||
@ -745,7 +751,9 @@ EX namespace mapstream {
|
||||
f.write(c->wparam); f.write(c->landparam);
|
||||
f.write_char(c->stuntime); f.write_char(c->hitpoints);
|
||||
bool blocked = false;
|
||||
#if MAXMDIM >= 4
|
||||
if(intra::in && isWall3(c) && !intra::need_to_save.count(c)) blocked = true;
|
||||
#endif
|
||||
if(!blocked)
|
||||
for(int j=0; j<c->type; j++) {
|
||||
cell *c2 = c->move(j);
|
||||
@ -756,6 +764,12 @@ EX namespace mapstream {
|
||||
int32_t n = -1; f.write(n);
|
||||
int32_t id = cellids.count(cwt.at) ? cellids[cwt.at] : -1;
|
||||
f.write(id);
|
||||
|
||||
if(f.vernum >= 0xA90C) {
|
||||
vector<color_t> v;
|
||||
for(auto c: walking::colors_of_floors) v.push_back(c);
|
||||
f.write(v);
|
||||
}
|
||||
|
||||
save_drawing_tool(f);
|
||||
|
||||
@ -771,6 +785,7 @@ EX namespace mapstream {
|
||||
for(int i=0; i<multi::players; i++)
|
||||
f.write(cellids[multi::player[i].at]);
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(intra::in) {
|
||||
for(int i=0; i<isize(intra::portals_to_save); i++) {
|
||||
auto& p = intra::portals_to_save[i];
|
||||
@ -789,6 +804,7 @@ EX namespace mapstream {
|
||||
}
|
||||
f.write<char>(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
callhooks(hooks_savemap, f);
|
||||
f.write<int>(0);
|
||||
@ -970,6 +986,13 @@ EX namespace mapstream {
|
||||
savecount = 0; savetime = 0;
|
||||
cheater = 1;
|
||||
|
||||
if(f.vernum >= 0xA90C) {
|
||||
vector<color_t> v;
|
||||
f.read(v);
|
||||
walking::colors_of_floors.clear();
|
||||
for(auto c: v) walking::colors_of_floors.insert(c);
|
||||
}
|
||||
|
||||
load_drawing_tool(f);
|
||||
|
||||
dynamicval<bool> a3(vid.always3, vid.always3);
|
||||
@ -1002,6 +1025,7 @@ EX namespace mapstream {
|
||||
}
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(intra::in) {
|
||||
while(true) {
|
||||
char k = f.get<char>();
|
||||
@ -1015,6 +1039,7 @@ EX namespace mapstream {
|
||||
cw.spin = fixspin(relspin[id], spin, cw.at->type, f.vernum);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(f.vernum >= 0xA848) {
|
||||
int i;
|
||||
@ -1060,9 +1085,14 @@ EX namespace mapstream {
|
||||
if(!f.f) return false;
|
||||
f.write(f.vernum);
|
||||
f.write(dual::state);
|
||||
#if MAXMDIM >= 4
|
||||
int q = intra::in ? isize(intra::data) : 0;
|
||||
f.write(q);
|
||||
#else
|
||||
int q = 0;
|
||||
#endif
|
||||
if(q) {
|
||||
#if MAXMDIM >= 4
|
||||
intra::prepare_to_save();
|
||||
int qp = isize(intra::portals_to_save);
|
||||
f.write(qp);
|
||||
@ -1072,6 +1102,7 @@ EX namespace mapstream {
|
||||
}
|
||||
intra::resetter ir;
|
||||
for(int i=0; i<q; i++) { intra::switch_to(i); save_only_map(f); }
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// make sure we save in correct order
|
||||
@ -1102,6 +1133,7 @@ EX namespace mapstream {
|
||||
if(q) {
|
||||
int qp;
|
||||
f.read(qp);
|
||||
#if MAXMDIM >= 4
|
||||
intra::portals_to_save.resize(qp);
|
||||
for(auto& ps: intra::portals_to_save) {
|
||||
f.read(ps.spin);
|
||||
@ -1110,12 +1142,14 @@ EX namespace mapstream {
|
||||
}
|
||||
for(int i=0; i<q; i++) {
|
||||
intra::in = true; /* so that it knows to load portals */
|
||||
game_active = false;
|
||||
load_only_map(f);
|
||||
intra::in = false;
|
||||
intra::become();
|
||||
}
|
||||
intra::start();
|
||||
intra::load_saved_portals();
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
dual::split_or_do([&] { load_only_map(f); });
|
||||
|
@ -109,6 +109,22 @@ EX void moveEffect(const movei& mi, eMonster m) {
|
||||
#endif
|
||||
}
|
||||
|
||||
EX void check_beauty(cell *ct, cell *cf, eMonster m) {
|
||||
bool adj = false;
|
||||
if(ct->cpdist == 1 && (items[itOrb37] || !nonAdjacent(cf,ct)) && markOrb(itOrbBeauty) && !isFriendly(ct))
|
||||
adj = true;
|
||||
|
||||
if(!adj && items[itOrbEmpathy] && items[itOrbBeauty] && !isFriendly(ct)) {
|
||||
for(int i=0; i<ct->type; i++) if(ct->move(i) && isFriendly(ct->move(i)))
|
||||
adj = true, markOrb(itOrbEmpathy), markOrb(itOrbBeauty);
|
||||
}
|
||||
|
||||
if(adj && ct->stuntime == 0 && !isMimic(m)) {
|
||||
ct->stuntime = 2;
|
||||
checkStunKill(ct);
|
||||
}
|
||||
}
|
||||
|
||||
EX void moveMonster(const movei& mi) {
|
||||
auto& cf = mi.s;
|
||||
auto& ct = mi.t;
|
||||
@ -254,20 +270,8 @@ EX void moveMonster(const movei& mi) {
|
||||
if(m == moWitchFire) makeflame(cf, 10, false);
|
||||
if(m == moFireElemental) { makeflame(cf, 20, false); if(cf->wparam < 20) cf->wparam = 20; }
|
||||
|
||||
bool adj = false;
|
||||
if(ct->cpdist == 1 && (items[itOrb37] || !nonAdjacent(cf,ct)) && markOrb(itOrbBeauty) && !isFriendly(ct))
|
||||
adj = true;
|
||||
|
||||
if(!adj && items[itOrbEmpathy] && items[itOrbBeauty] && !isFriendly(ct)) {
|
||||
for(int i=0; i<ct->type; i++) if(ct->move(i) && isFriendly(ct->move(i)))
|
||||
adj = true, markOrb(itOrbEmpathy), markOrb(itOrbBeauty);
|
||||
}
|
||||
check_beauty(ct, cf, m);
|
||||
|
||||
if(adj && ct->stuntime == 0 && !isMimic(m)) {
|
||||
ct->stuntime = 2;
|
||||
checkStunKill(ct);
|
||||
}
|
||||
|
||||
if(!cellEdgeUnstable(ct)) {
|
||||
if(isMetalBeast(m)) ct->stuntime += 2;
|
||||
if(m == moTortoise) ct->stuntime += 3;
|
||||
@ -1487,6 +1491,8 @@ EX void moveshadow() {
|
||||
where->stuntime = 0;
|
||||
// the Shadow sets off the mines and stuff
|
||||
moveEffect(movei(where, where, NODIR), moShadow);
|
||||
// Beauty kills the Shadow
|
||||
check_beauty(where, where, moShadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,11 @@ void gamedata_all(gamedata& gd) {
|
||||
gd.store(hybrid::underlying);
|
||||
gd.store(hybrid::csteps);
|
||||
gd.store(hybrid::underlying_cgip);
|
||||
gd.store_ptr(vid);
|
||||
gd.store_ptr(vid.projection_config);
|
||||
gd.store_ptr(vid.rug_config);
|
||||
gd.store(vid.yshift);
|
||||
gd.store(vid.plevel_factor);
|
||||
gd.store(vid.binary_width);
|
||||
gd.store(sightrange_bonus);
|
||||
gd.store(genrange_bonus);
|
||||
gd.store(gamerange_bonus);
|
||||
@ -179,8 +183,7 @@ EX namespace dual {
|
||||
dynamicval<int> dm(dual::state, 2);
|
||||
int cg = currently_loaded;
|
||||
|
||||
bool orbusedbak[ittypes];
|
||||
for(int i=0; i<ittypes; i++) orbusedbak[i] = orbused[i];
|
||||
auto orbusedbak = orbused;
|
||||
|
||||
if(d < 0) {
|
||||
if(d == -2 && items[itGreenStone] < 2) {
|
||||
@ -193,7 +196,7 @@ EX namespace dual {
|
||||
for(int k=0; k<2; k++) {
|
||||
switch_to(k);
|
||||
ok = ok && movepcto(d, subdir, true);
|
||||
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
|
||||
orbused = orbusedbak;
|
||||
}
|
||||
if(ok && checkonly) {
|
||||
switch_to(cg);
|
||||
|
@ -401,7 +401,7 @@ EX eOrbLandRelation getOLR(eItem it, eLand l) {
|
||||
if(l == laDungeon) {
|
||||
if(it == itOrbSafety || it == itOrbFrog ||
|
||||
it == itOrbTeleport || it == itOrbMatter || it == itOrbNature ||
|
||||
it == itOrbAether || it == itOrbSummon || it == itOrbStone)
|
||||
it == itOrbAether || it == itOrbSummon || it == itOrbStone || it == itOrbChaos)
|
||||
return olrForbidden;
|
||||
}
|
||||
|
||||
|
19
orbs.cpp
19
orbs.cpp
@ -6,9 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "hyper.h"
|
||||
|
||||
namespace hr {
|
||||
|
||||
EX bool orbused[ittypes], lastorbused[ittypes];
|
||||
EX array<bool, ittypes> orbused;
|
||||
EX array<bool, ittypes> lastorbused;
|
||||
|
||||
EX bool markOrb(eItem it) {
|
||||
if(!items[it]) return false;
|
||||
@ -314,6 +316,7 @@ EX bool distanceBound(cell *c1, cell *c2, int d) {
|
||||
|
||||
EX void checkFreedom(cell *cf) {
|
||||
manual_celllister cl;
|
||||
dynamicval<decltype(orbused)> d(orbused);
|
||||
cl.add(cf);
|
||||
for(int i=0; i<isize(cl.lst); i++) {
|
||||
cell *c = cl.lst[i];
|
||||
@ -1027,6 +1030,10 @@ EX void checkStunKill(cell *dest) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(dest->monst == moShadow) {
|
||||
addMessage(XLAT("%The1 is destroyed!", dest->monst));
|
||||
killMonster(dest, moNone);
|
||||
}
|
||||
/* if(!isPermanentFlying(dest->monst) && cellEdgeUnstable(dest)) {
|
||||
addMessage(XLAT("%The1 falls!", dest->monst));
|
||||
fallMonster(dest);
|
||||
@ -1598,6 +1605,15 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
return itNone;
|
||||
}
|
||||
|
||||
bool isValentines() {
|
||||
const time_t now = time(NULL);
|
||||
const struct tm *datetime = localtime(&now);
|
||||
|
||||
// 0-indexed tm_mon, 1-indexed tm_mday
|
||||
// So this is February (2nd month), and the 14th day.
|
||||
return datetime->tm_mon == 1 && datetime->tm_mday == 14;
|
||||
}
|
||||
|
||||
EX int orbcharges(eItem it) {
|
||||
switch(it) {
|
||||
case itRevolver: //pickup-key
|
||||
@ -1607,6 +1623,7 @@ EX int orbcharges(eItem it) {
|
||||
case itOrbDiscord:
|
||||
return inv::on ? 46 : 23;
|
||||
case itOrbLove:
|
||||
return isValentines() ? 31 : 30;
|
||||
case itOrbUndeath:
|
||||
case itOrbSpeed: //"pickup-speed");
|
||||
case itOrbInvis:
|
||||
|
13
pcmove.cpp
13
pcmove.cpp
@ -576,6 +576,9 @@ void apply_chaos() {
|
||||
if (cb->wall == waStone) destroyTrapsAround(cb);
|
||||
changes.ccell(ca);
|
||||
changes.ccell(cb);
|
||||
/* needs to be called separately for Shadows */
|
||||
if(ca->monst == moShadow) checkStunKill(ca);
|
||||
if(cb->monst == moShadow) checkStunKill(cb);
|
||||
gcell coa = *ca;
|
||||
gcell cob = *cb;
|
||||
if(ca->monst != cb->monst)
|
||||
@ -588,10 +591,14 @@ void apply_chaos() {
|
||||
copy_metadata(cb, &coa);
|
||||
if(!switch_lhu_in(ca->land)) ca->LHU = coa.LHU;
|
||||
if(!switch_lhu_in(cb->land)) cb->LHU = cob.LHU;
|
||||
if(ca->monst && !(isFriendly(ca) && markOrb(itOrbEmpathy)))
|
||||
if(ca->monst && !(isFriendly(ca) && markOrb(itOrbEmpathy))) {
|
||||
ca->stuntime = min(ca->stuntime + 3, 15), markOrb(itOrbChaos);
|
||||
if(cb->monst && !(isFriendly(cb) && markOrb(itOrbEmpathy)))
|
||||
checkStunKill(ca);
|
||||
}
|
||||
if(cb->monst && !(isFriendly(cb) && markOrb(itOrbEmpathy))) {
|
||||
cb->stuntime = min(cb->stuntime + 3, 15), markOrb(itOrbChaos);
|
||||
checkStunKill(cb);
|
||||
}
|
||||
ca->monmirror = !ca->monmirror;
|
||||
cb->monmirror = !cb->monmirror;
|
||||
ca->mondir = chaos_mirror_dir(ca->mondir, wb, wa);
|
||||
@ -855,7 +862,7 @@ bool pcmove::after_escape() {
|
||||
if(attackable && fmsAttack && !dont_attack && !items[itCurseWeakness]) {
|
||||
if(checkNeedMove(checkonly, true)) return false;
|
||||
nextmovetype = nm ? lmAttack : lmSkip;
|
||||
if(c2->wall == waSmallTree) {
|
||||
if(c2->wall == waSmallTree || (c2->wall == waBigTree && markOrb(itOrbSlaying))) {
|
||||
drawParticles(c2, winf[c2->wall].color, 4);
|
||||
addMessage(XLAT("You chop down the tree."));
|
||||
playSound(c2, "hit-axe" + pick123());
|
||||
|
@ -451,6 +451,7 @@ void raygen::compute_which_and_dist(int flat1, int flat2) {
|
||||
"mediump float zsgn = (Mt > 0. ? -sgn : sgn);\n"
|
||||
"mediump float u = sqrt(b*b-c)*zsgn + b;\n"
|
||||
"mediump float v = -(Mp*u-1.) / Mt;\n"
|
||||
"if(a < 1e-5) v = (1.-Mp*Mp) / (2. * Mt);\n"
|
||||
"mediump float d = asinh(v);\n";
|
||||
if(prod) fmain += "d /= xspeed;\n";
|
||||
fmain +=
|
||||
@ -1575,22 +1576,28 @@ void raygen::add_functions() {
|
||||
|
||||
add_if("to_poco_h3",
|
||||
"mediump vec4 to_poco_h3(mediump vec4 pos) {\n"
|
||||
" return pos / pos[3];\n"
|
||||
" pos = pos / pos[3];\n"
|
||||
" pos[2] /= sqrt(1.-pos.x*pos.x-pos.y*pos.y);\n"
|
||||
" return pos;\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("from_poco_h3",
|
||||
"mediump vec4 from_poco_h3(mediump vec4 pos) {\n"
|
||||
" pos[2] *= sqrt(1.-pos.x*pos.x-pos.y*pos.y);\n"
|
||||
" float s = 1. - dot(pos.xyz, pos.xyz);\n"
|
||||
" return pos / sqrt(s);\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("to_poco_s3",
|
||||
"mediump vec4 to_poco_s3(mediump vec4 pos) {\n"
|
||||
" return pos / pos[3];\n"
|
||||
" pos = pos / pos[3];\n"
|
||||
" pos[2] /= sqrt(1.+pos.x*pos.x+pos.y*pos.y);\n"
|
||||
" return pos;\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("from_poco_s3",
|
||||
"mediump vec4 from_poco_s3(mediump vec4 pos) {\n"
|
||||
" pos[2] *= sqrt(1.+pos.x*pos.x+pos.y*pos.y);\n"
|
||||
" float s = 1. + dot(pos.xyz, pos.xyz);\n"
|
||||
" return pos / sqrt(s);\n"
|
||||
" }\n\n");
|
||||
@ -1623,13 +1630,13 @@ void raygen::add_functions() {
|
||||
|
||||
add_if("from_poco_h2xr_e",
|
||||
"mediump vec4 from_poco_h2xr_e(mediump vec4 pos) {\n"
|
||||
" return vec4(sinh(pos[2]) * cosh(pos[0]), sinh(pos[0]), cosh(pos[0]) * cosh(pos[2]), 0);\n"
|
||||
" return vec4(sinh(pos[2]), sinh(pos[0]) * cosh(pos[2]), cosh(pos[0]) * cosh(pos[2]), 0);\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("to_poco_h2xr_e",
|
||||
"mediump vec4 to_poco_h2xr_e(mediump vec4 pos) {\n"
|
||||
" mediump float x = asinh(pos[1]);\n"
|
||||
" return vec4(x, 0, asinh(pos[0] / cosh(x)), 1);\n"
|
||||
" mediump float x = asinh(pos[0]);\n"
|
||||
" return vec4(asinh(pos[1] / cosh(x)), 0, x, 1);\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("from_poco_s2xr_s",
|
||||
@ -1648,13 +1655,13 @@ void raygen::add_functions() {
|
||||
|
||||
add_if("from_poco_s2xr_e",
|
||||
"mediump vec4 from_poco_s2xr_e(mediump vec4 pos) {\n"
|
||||
" return vec4(sin(pos[2]) * cos(pos[0]), sin(pos[0]), cos(pos[0]) * cos(pos[2]), 0);\n"
|
||||
" return vec4(sin(pos[2]), sin(pos[0]) * cos(pos[2]), cos(pos[0]) * cos(pos[2]), 0);\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("to_poco_s2xr_e",
|
||||
"mediump vec4 to_poco_s2xr_e(mediump vec4 pos) {\n"
|
||||
" mediump float x = asin_clamp(pos[1]);\n"
|
||||
" return vec4(x, 0, asin_clamp(pos[0] / cos(x)), 1);\n"
|
||||
" mediump float x = asin_clamp(pos[0]);\n"
|
||||
" return vec4(asin_clamp(pos[1] / cos(x)), 0, x, 1);\n"
|
||||
" }\n\n");
|
||||
|
||||
add_if("deparabolic12",
|
||||
@ -2059,7 +2066,7 @@ void uniform2(GLint id, array<float, 2> fl) {
|
||||
|
||||
color_t color_out_of_range = 0x0F0800FF;
|
||||
|
||||
transmatrix get_ms(cell *c, int a, bool mirror) {
|
||||
EX transmatrix get_ms(cell *c, int a, bool mirror) {
|
||||
int z = a ? 1 : -1;
|
||||
|
||||
if(c->type == 3) {
|
||||
@ -2089,7 +2096,7 @@ transmatrix get_ms(cell *c, int a, bool mirror) {
|
||||
|
||||
int nesting;
|
||||
|
||||
transmatrix mirrorize(transmatrix T) {
|
||||
EX transmatrix mirrorize(transmatrix T) {
|
||||
T = inverse(T);
|
||||
hyperpoint h = tC0(T);
|
||||
ld d = hdist0(h);
|
||||
@ -2486,24 +2493,27 @@ EX void cast() {
|
||||
|
||||
#if CAP_VR
|
||||
if(o->uEyeShift != -1) {
|
||||
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
||||
transmatrix T = vrhr::eyeshift;
|
||||
if(nonisotropic)
|
||||
T = inverse(NLP) * T;
|
||||
glUniformMatrix4fv(o->uEyeShift, 1, 0, glhr::tmtogl_transpose3(T).as_array());
|
||||
glUniformMatrix4fv(o->uEyeShift, 1, 0, glhr::tmtogl_transpose(T).as_array());
|
||||
glUniform1f(o->uAbsUnit, vrhr::absolute_unit_in_meters);
|
||||
}
|
||||
if(vrhr::rendering_eye()) {
|
||||
glUniformMatrix4fv(o->uProjection, 1, 0, glhr::tmtogl_transpose3(vrhr::eyeproj).as_array());
|
||||
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
||||
glUniformMatrix4fv(o->uProjection, 1, 0, glhr::tmtogl_transpose(vrhr::eyeproj).as_array());
|
||||
}
|
||||
#else
|
||||
if(0) ;
|
||||
#endif
|
||||
else {
|
||||
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
||||
transmatrix proj = Id;
|
||||
proj = eupush(-global_projection * d, 0) * proj;
|
||||
proj = euscale(cd->tanfov / (vid.stereo_mode == sLR ? 2 : 1), cd->tanfov * cd->ysize / cd->xsize) * proj;
|
||||
proj = eupush(-((cd->xcenter-cd->xtop)*2./cd->xsize - 1), -((cd->ycenter-cd->ytop)*2./cd->ysize - 1)) * proj;
|
||||
glUniformMatrix4fv(o->uProjection, 1, 0, glhr::tmtogl_transpose3(proj).as_array());
|
||||
glUniformMatrix4fv(o->uProjection, 1, 0, glhr::tmtogl_transpose(proj).as_array());
|
||||
}
|
||||
|
||||
if(!callhandlers(false, hooks_rayset, o)) {
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <aegis.hpp>
|
||||
#endif
|
||||
|
||||
#include "../hyper.h"
|
||||
#include "rogueviz.h"
|
||||
|
||||
namespace hr {
|
||||
|
||||
@ -44,6 +44,8 @@ int labels_value = 1;
|
||||
|
||||
vector<boarddata> history;
|
||||
|
||||
bool draw_go(cell *c, const shiftmatrix& V);
|
||||
|
||||
void init_go() {
|
||||
ac = currentmap->allcells();
|
||||
current.taken.resize(isize(ac), 2);
|
||||
@ -52,6 +54,7 @@ void init_go() {
|
||||
current.captures[1] = 0;
|
||||
for(int i=0; i<isize(ac); i++)
|
||||
indices[ac[i]] = i;
|
||||
rogueviz::addHook(hooks_drawcell, 100, draw_go);
|
||||
}
|
||||
|
||||
void hwrite(hstream& hs, const boarddata& b) {
|
||||
@ -602,7 +605,6 @@ int rugArgs() {
|
||||
|
||||
auto gobot_hook =
|
||||
addHook(hooks_args, 100, rugArgs) +
|
||||
addHook(hooks_drawcell, 100, draw_go) +
|
||||
addHook(shmup::hooks_turn, 100, [] (int t) {
|
||||
if(shot_state == 1) {
|
||||
shot::take("go-temp.png");
|
||||
|
@ -468,8 +468,62 @@ auto hooks =
|
||||
// generate binary-tiling H2xE with floors to the current scene, runs automatically
|
||||
+ arg::add3("-intra-bxe", create_intra_bxe)
|
||||
// generate Sol with floors to the current scene, runs autimatically
|
||||
+ arg::add3("-intra-sol", create_intra_sol);
|
||||
+ arg::add3("-intra-sol", create_intra_sol)
|
||||
//+ arg::add3("-intra-more", create_intra_more);
|
||||
+ arg::add3("-intra-demo-floors", [] {
|
||||
walking::colors_of_floors = {
|
||||
0xFFFF40, 0xD0D000,
|
||||
0xC0FFC0, 0x80C080,
|
||||
0xC0FFFF, 0x40FFFF,
|
||||
0x8080FF, 0x0000FF,
|
||||
0xFF80FF, 0xFF00FF,
|
||||
0x64BF95, 0xA4FFD5,
|
||||
0xFFFDD0, 0xFFD080
|
||||
};
|
||||
})
|
||||
+ addHook_rvslides(10, ([] (string s, vector<tour::slide>& v) {
|
||||
println(hlog, "called with s='", s, "'");
|
||||
if(s != "portal") return;
|
||||
|
||||
using namespace tour;
|
||||
auto load = [] (string s, ld x, int y) {
|
||||
return [s, x, y] {
|
||||
slide_backup(vid.cells_drawn_limit, 100);
|
||||
slide_backup(smooth_scrolling, true);
|
||||
slide_backup(ray::max_cells, 999999);
|
||||
slide_backup(walking::on, true);
|
||||
slide_backup(walking::eye_level, x);
|
||||
mapstream::loadMap(s);
|
||||
slide_backup(ray::fixed_map, true);
|
||||
slide_backup(ray::max_iter_intra, y);
|
||||
};
|
||||
};
|
||||
|
||||
auto add = [&] (string s, string desc, string youtube, string twitter, reaction_t loader) {
|
||||
v.push_back(tour::slide{
|
||||
s, 10, tour::LEGAL::NONE | tour::QUICKSKIP | tour::QUICKGEO, desc,
|
||||
[=] (tour::presmode mode) {
|
||||
setCanvas(mode, '0');
|
||||
if(youtube != "")
|
||||
slide_url(mode, 'y', "YouTube link", youtube);
|
||||
if(twitter != "")
|
||||
slide_url(mode, 't', "Twitter link", twitter);
|
||||
slide_action(mode, 'r', "run this visualization", loader);
|
||||
if(mode == tour::pmKey) pushScreen(intra::show_portals);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
add("inter-geometric portals",
|
||||
"In this world we can find portals between six different geometries. The camera is in 'walking mode' i.e. restricted to keep close to the floor (this can be disabled with '5').",
|
||||
"https://youtu.be/yqUv2JO2BCs", "https://twitter.com/ZenoRogue/status/1496867204419452935",
|
||||
load("portalscene3.lev", 0.2174492, 600)
|
||||
);
|
||||
add("curved landscape",
|
||||
"Here we create portals between Solv and H3 geometries, resulting in a scene looking a bit like a curved landscape.",
|
||||
"", "https://twitter.com/ZenoRogue/status/1446127100516130826",
|
||||
load("solv-h3-scene.lev", 0.05, 3000));
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
|
@ -1417,6 +1417,85 @@ void nk_launch() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void portal_slideshow(tour::ss::slideshow_callback cb) {
|
||||
|
||||
using namespace rogueviz::pres;
|
||||
using namespace tour;
|
||||
static vector<slide> portal_slides;
|
||||
|
||||
if(portal_slides.empty()) {
|
||||
|
||||
portal_slides.emplace_back(slide{"portal collection", 100, LEGAL::NONE | QUICKSKIP,
|
||||
"This is a collection of portals. We start with knotted portals in Euclidean geometry, "
|
||||
"then we visit portals in other geometries, and finally, we explore portals between different "
|
||||
"geometries.\n\nLoading these may take some time, so you need to press 'r' to run them. In most slides you can also press '5' to change various parameters.",
|
||||
[] (presmode mode) {}
|
||||
});
|
||||
|
||||
auto add = [&] (string s, string text, string youtube, reaction_t act) {
|
||||
|
||||
portal_slides.emplace_back(
|
||||
tour::slide{s, 100, LEGAL::NONE | QUICKGEO | QUICKSKIP, text,
|
||||
[=] (presmode mode) {
|
||||
setCanvas(mode, '0');
|
||||
if(youtube != "")
|
||||
slide_url(mode, 'y', "YouTube link", youtube);
|
||||
slide_action(mode, 'r', "run", [=] {
|
||||
slide_backup(margin);
|
||||
slide_backup(mapeditor::drawplayer);
|
||||
slide_backup(firstland);
|
||||
slide_backup(specialland);
|
||||
slide_backup(ray::max_cells, 600000);
|
||||
slide_backup(smooth_scrolling, 1);
|
||||
slide_backup(camera_speed, 10);
|
||||
slide_backup(ray::exp_decay_poly, 30);
|
||||
slide_backup(ray::fixed_map, true);
|
||||
slide_backup(ray::max_iter_iso, 80);
|
||||
#if CAP_VR
|
||||
slide_backup(vrhr::hsm);
|
||||
slide_backup(vrhr::eyes);
|
||||
slide_backup(vrhr::cscr);
|
||||
slide_backup(vrhr::absolute_unit_in_meters);
|
||||
#endif
|
||||
|
||||
on_restore([] { nilv::set_flags(); asonov::set_flags(); });
|
||||
|
||||
slide_backup(nilv::nilwidth);
|
||||
slide_backup(nilv::nilperiod);
|
||||
|
||||
slide_backup(vid.binary_width);
|
||||
slide_backup(asonov::period_xy);
|
||||
slide_backup(asonov::period_z);
|
||||
|
||||
act();
|
||||
start_game();
|
||||
loop = 2;
|
||||
});
|
||||
|
||||
if(mode == tour::pmKey) pushScreen(show);
|
||||
}});
|
||||
};
|
||||
|
||||
auto launch_euc_with = [] (bool b) {
|
||||
return [b] {
|
||||
self_hiding = b;
|
||||
launch_euc();
|
||||
};
|
||||
};
|
||||
add("knotted portal", "This is a knotted portal in Euclidean space.", "https://www.youtube.com/watch?v=eb2DhCcGH7U", launch_euc_with(false));
|
||||
add("self-hiding portal", "This knotted portal is 'self-hiding'. It appears that the portal enters itself and disappears!", "https://www.youtube.com/watch?v=vFLZ2NGtuGw", launch_euc_with(true));
|
||||
add("non-Euclidean portal in Nil", "A portal in Nil geometry.", "https://www.youtube.com/watch?v=2K-v8tK68AE", launch_nil);
|
||||
add("spherical portal", "A portal in spherical geometry. Such a portal lets us create a space with spherical geometry that has more volume than the sphere.", "https://www.youtube.com/watch?v=PerPeQFu5gw", launch_sphereknot);
|
||||
add("Cat Portal in Solv", "A portal in Solv geometry. The honeycomb is based on the mapping torus of Arnold's cat mapping.", "https://www.youtube.com/watch?v=CGiSxC9B6i0", launch_solv);
|
||||
|
||||
callhooks(rogueviz::pres::hooks_build_rvtour, "portal", portal_slides);
|
||||
|
||||
add_end(portal_slides);
|
||||
}
|
||||
|
||||
cb(XLAT("portal collection"), &portal_slides[0], 'p');
|
||||
}
|
||||
|
||||
auto shot_hooks = addHook(hooks_initialize, 100, create_notknot)
|
||||
+ addHook(hooks_welcome_message, 100, [] {
|
||||
if(geometry == gNotKnot) {
|
||||
@ -1496,59 +1575,9 @@ auto shot_hooks = addHook(hooks_initialize, 100, create_notknot)
|
||||
param_i(loop_any, "nk_loopany");
|
||||
})
|
||||
#ifndef NOTKNOT
|
||||
+ addHook_rvslides(180, [] (string s, vector<tour::slide>& v) {
|
||||
if(s != "mixed") return;
|
||||
v.push_back(tour::slide{
|
||||
"weird portals", 10, tour::LEGAL::NONE | tour::QUICKSKIP,
|
||||
"Some experiments with weird portals. Press '5' to change between available experiments.\n"
|
||||
,
|
||||
[] (tour::presmode mode) {
|
||||
slide_url(mode, 'k', "knotted portal (YouTube)", "https://www.youtube.com/watch?v=eb2DhCcGH7U");
|
||||
slide_url(mode, 'h', "self-hiding knot portal (YouTube)", "https://www.youtube.com/watch?v=vFLZ2NGtuGw");
|
||||
slide_url(mode, 'n', "non-Euclidean portal in Nil (YouTube)", "https://www.youtube.com/watch?v=2K-v8tK68AE");
|
||||
slide_url(mode, 's', "spherical portal (YouTube)", "https://www.youtube.com/watch?v=PerPeQFu5gw");
|
||||
slide_url(mode, 'c', "Cat Portal in Solv (YouTube)", "https://www.youtube.com/watch?v=CGiSxC9B6i0");
|
||||
setCanvas(mode, '0');
|
||||
using namespace tour;
|
||||
if(mode == pmStart) {
|
||||
slide_backup(margin);
|
||||
slide_backup(mapeditor::drawplayer);
|
||||
slide_backup(firstland);
|
||||
slide_backup(specialland);
|
||||
slide_backup(ray::max_cells);
|
||||
slide_backup(smooth_scrolling);
|
||||
slide_backup(camera_speed);
|
||||
slide_backup(ray::exp_decay_poly);
|
||||
slide_backup(ray::fixed_map);
|
||||
slide_backup(ray::max_iter_iso);
|
||||
#if CAP_VR
|
||||
slide_backup(vrhr::hsm);
|
||||
slide_backup(vrhr::eyes);
|
||||
slide_backup(vrhr::cscr);
|
||||
slide_backup(vrhr::absolute_unit_in_meters);
|
||||
#endif
|
||||
|
||||
on_restore([] { nilv::set_flags(); asonov::set_flags(); });
|
||||
|
||||
slide_backup(nilv::nilwidth);
|
||||
slide_backup(nilv::nilperiod);
|
||||
|
||||
slide_backup(vid.binary_width);
|
||||
slide_backup(asonov::period_xy);
|
||||
slide_backup(asonov::period_z);
|
||||
|
||||
nk_launch();
|
||||
start_game();
|
||||
loop = 2;
|
||||
}
|
||||
if(mode == tour::pmKey) {
|
||||
pushScreen(show);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
+ addHook_slideshows(120, portal_slideshow)
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
#ifdef NOTKNOT
|
||||
auto hook1=
|
||||
|
@ -13,6 +13,7 @@ g -- generate the current room (buggy)
|
||||
m -- see the map (toggle)
|
||||
p -- pause (toggle)
|
||||
z -- screenshot menu
|
||||
v -- HyperRogue settings
|
||||
q -- quit
|
||||
s -- save to platformer.lev
|
||||
1 -- place a small block under the mouse
|
||||
@ -151,7 +152,6 @@ struct room {
|
||||
|
||||
void initial() {
|
||||
int ylev = where->master->distance;
|
||||
println(hlog, "ylev = ", ylev);
|
||||
if(ylev <= 0)
|
||||
for(int y=room_y-6; y<room_y; y++)
|
||||
for(int x=0; x<room_x; x++)
|
||||
@ -550,7 +550,7 @@ bool draw_room_on_map(cell *c, const shiftmatrix& V) {
|
||||
p.tinf = &roomtinf;
|
||||
p.offset_texture = 0;
|
||||
p.texture_id = r.room_texture->textureid;
|
||||
println(hlog, "offset = ", p.offset, " texture_offset = ", p.offset_texture);
|
||||
// println(hlog, "offset = ", p.offset, " texture_offset = ", p.offset_texture);
|
||||
|
||||
auto render_at = [&] (GLuint texid, double px0, double py0, double px1, double py1,
|
||||
double tx0, double ty0, double tx1, double ty1) {
|
||||
@ -632,6 +632,7 @@ void render_room(room *r) {
|
||||
template<class R> void render_room_objects(room *r, R render_at) {
|
||||
auto pb = get_pixel_bbox();
|
||||
if(r != current_room) return;
|
||||
create_sprite_texture();
|
||||
render_at(sprite_texture->textureid, pb.minx, pb.miny, pb.maxx, pb.maxy, 0, 0, man_x/256., man_y/256.);
|
||||
}
|
||||
|
||||
@ -704,14 +705,29 @@ void run() {
|
||||
dialog::add_key_action('m', [] {
|
||||
map_on = !map_on;
|
||||
});
|
||||
dialog::add_key_action('v', [] {
|
||||
pushScreen(showSettings);
|
||||
});
|
||||
dialog::add_key_action('p', [] {
|
||||
paused = !paused;
|
||||
});
|
||||
dialog::add_key_action('z', [] {
|
||||
pushScreen(shot::menu);
|
||||
});
|
||||
dialog::add_key_action('q', [] { exit(0); });
|
||||
dialog::add_key_action('s', [] {
|
||||
dialog::add_key_action('q', [] {
|
||||
if(tour::on) tour::next_slide();
|
||||
else exit(0);
|
||||
});
|
||||
dialog::add_key_action('o', [] {
|
||||
if(tour::on) tour::next_slide();
|
||||
});
|
||||
dialog::add_key_action(SDLK_ESCAPE, [] {
|
||||
if(tour::on) tour::next_slide();
|
||||
});
|
||||
dialog::add_key_action(SDLK_F10, [] {
|
||||
if(tour::on) tour::next_slide();
|
||||
});
|
||||
dialog::add_key_action('s', [] {
|
||||
mapstream::saveMap("platformer.lev");
|
||||
});
|
||||
|
||||
@ -801,6 +817,24 @@ void add_platf_hooks() {
|
||||
}
|
||||
|
||||
auto chk = arg::add3("-platformer", enable)
|
||||
+ addHook_rvslides(195, [] (string s, vector<tour::slide>& v) {
|
||||
if(s != "mixed") return;
|
||||
v.push_back(tour::slide{
|
||||
"platformer", 10, tour::LEGAL::NONE | tour::QUICKSKIP | tour::QUICKGEO,
|
||||
"A non-Euclidean platformer.\n\nPress up/left/right to move the guy.\n\nM to see the map\n\nP to pause\n\nV to change HyperRogue settings.\n\nPress Q when you are done.\n"
|
||||
,
|
||||
[] (tour::presmode mode) {
|
||||
slide_url(mode, 'y', "non-Euclidean platformer (YouTube)", "https://www.youtube.com/watch?v=eb2DhCcGH7U");
|
||||
slide_url(mode, 't', "non-Euclidean platformer (Twitter)", "https://twitter.com/ZenoRogue/status/1467233150380089345");
|
||||
slide_url(mode, 'g', "how to edit this", "https://github.com/zenorogue/hyperrogue/blob/master/rogueviz/platformer.cpp");
|
||||
setCanvas(mode, '0');
|
||||
using namespace tour;
|
||||
if(mode == pmStart) {
|
||||
mapstream::loadMap("platformer.lev");
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
+ addHook(mapstream::hooks_loadmap, 100, [] (fhstream& f, int id) {
|
||||
if(id == 66) {
|
||||
println(hlog, "loading platformer");
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "highdim-demo.cpp"
|
||||
#include "horo63.cpp"
|
||||
#include "platformer.cpp"
|
||||
#include "intra-demos.cpp"
|
||||
#include "gobot.cpp"
|
||||
|
||||
#include "kohonen.cpp"
|
||||
|
@ -488,6 +488,7 @@ void launch() {
|
||||
|
||||
showstartmenu = false;
|
||||
mapeditor::drawplayer = false;
|
||||
rv::hook(hooks_drawcell, 100, draw_star);
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
@ -515,7 +516,6 @@ int rugArgs() {
|
||||
|
||||
auto starbattle_hook =
|
||||
addHook(hooks_args, 100, rugArgs) +
|
||||
addHook(hooks_drawcell, 100, draw_star) +
|
||||
addHook(mapstream::hooks_savemap, 100, [] (fhstream& f) {
|
||||
f.write<int>(isize(sdata));
|
||||
for(auto& sd: sdata) {
|
||||
|
37
tour.cpp
37
tour.cpp
@ -103,6 +103,11 @@ EX void slide_url(presmode mode, char key, string text, string url) {
|
||||
}});
|
||||
}
|
||||
|
||||
EX void slide_action(presmode mode, char key, string text, reaction_t act) {
|
||||
if(mode == pmHelpEx)
|
||||
help_extensions.push_back(help_extension{key, text, act});
|
||||
}
|
||||
|
||||
/** \brief an auxiliary function to enable a visualization in the Canvas land */
|
||||
EX void setCanvas(presmode mode, char canv) {
|
||||
if(mode == pmStart) {
|
||||
@ -206,25 +211,29 @@ void return_geometry() {
|
||||
addMessage(XLAT("Returned to your game."));
|
||||
}
|
||||
|
||||
EX bool next_slide() {
|
||||
flagtype flags = slides[currentslide].flags;
|
||||
popScreenAll();
|
||||
if(gamestack::pushed()) {
|
||||
return_geometry();
|
||||
if(!(flags & QUICKGEO)) return true;
|
||||
}
|
||||
if(flags & FINALSLIDE) return true;
|
||||
presentation(pmStop);
|
||||
slide_restore_all();
|
||||
currentslide++;
|
||||
presentation(pmStart);
|
||||
slidehelp();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handleKeyTour(int sym, int uni) {
|
||||
if(!tour::on) return false;
|
||||
if(!(cmode & sm::DOTOUR)) return false;
|
||||
bool inhelp = cmode & sm::HELP;
|
||||
flagtype flags = slides[currentslide].flags;
|
||||
if((sym == SDLK_RETURN || sym == SDLK_KP_ENTER) && (!inhelp || (flags & QUICKSKIP))) {
|
||||
popScreenAll();
|
||||
if(gamestack::pushed()) {
|
||||
return_geometry();
|
||||
if(!(flags & QUICKGEO)) return true;
|
||||
}
|
||||
if(flags & FINALSLIDE) return true;
|
||||
presentation(pmStop);
|
||||
slide_restore_all();
|
||||
currentslide++;
|
||||
presentation(pmStart);
|
||||
slidehelp();
|
||||
return true;
|
||||
}
|
||||
if((sym == SDLK_RETURN || sym == SDLK_KP_ENTER) && (!inhelp || (flags & QUICKSKIP)))
|
||||
return next_slide();
|
||||
if(sym == SDLK_BACKSPACE) {
|
||||
if(gamestack::pushed()) {
|
||||
gamestack::pop();
|
||||
|
5
util.cpp
5
util.cpp
@ -732,6 +732,11 @@ EX void open_url(string s) {
|
||||
|
||||
const char *urlhex = "0123456789ABCDEF";
|
||||
EX void open_wiki(const char *title) {
|
||||
// Since "Crossroads" is ambiguous, we use the direct link to Crossroads I.
|
||||
if (!strcmp(title, "Crossroads")) {
|
||||
title = "Crossroads (Land)";
|
||||
}
|
||||
|
||||
string url = "https://hyperrogue.miraheze.org/wiki/";
|
||||
unsigned char c;
|
||||
for (size_t i = 0; (c = title[i]); ++i) {
|
||||
|
58
vr.cpp
58
vr.cpp
@ -794,6 +794,24 @@ EX void track_actions() {
|
||||
}
|
||||
}
|
||||
|
||||
EX void get_eyes() {
|
||||
for(int a=0; a<2; a++) {
|
||||
auto eye = vr::EVREye(a);
|
||||
E4;
|
||||
vrdata.proj[a] =
|
||||
vr_to_hr(vrdata.vr->GetProjectionMatrix(eye, 0.01, 300));
|
||||
|
||||
vrdata.iproj[a] = MirrorZ * inverse(vrdata.proj[a]);
|
||||
|
||||
// println(hlog, "projection = ", vrdata.proj[a]);
|
||||
|
||||
vrdata.eyepos[a] =
|
||||
vr_to_hr(vrdata.vr->GetEyeToHeadTransform(eye));
|
||||
|
||||
// println(hlog, "eye-to-head = ", vrdata.eyepos[a]);
|
||||
}
|
||||
}
|
||||
|
||||
EX void start_vr() {
|
||||
|
||||
if(true) { sm = Id; sm[1][1] = sm[2][2] = -1; }
|
||||
@ -830,23 +848,12 @@ EX void start_vr() {
|
||||
println(hlog, "recommended size: ", int(vrdata.xsize), " x ", int(vrdata.ysize));
|
||||
|
||||
for(int a=0; a<2; a++) {
|
||||
auto eye = vr::EVREye(a);
|
||||
vrdata.eyes[a] = new vr_framebuffer(vrdata.xsize, vrdata.ysize);
|
||||
println(hlog, "eye ", a, " : ", vrdata.eyes[a]->ok ? "OK" : "Error");
|
||||
|
||||
vrdata.proj[a] =
|
||||
vr_to_hr(vrdata.vr->GetProjectionMatrix(eye, 0.01, 300));
|
||||
|
||||
vrdata.iproj[a] = MirrorZ * inverse(vrdata.proj[a]);
|
||||
|
||||
println(hlog, "projection = ", vrdata.proj[a]);
|
||||
|
||||
vrdata.eyepos[a] =
|
||||
vr_to_hr(vrdata.vr->GetEyeToHeadTransform(eye));
|
||||
|
||||
println(hlog, "eye-to-head = ", vrdata.eyepos[a]);
|
||||
}
|
||||
|
||||
|
||||
get_eyes();
|
||||
|
||||
//CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, leftEyeDesc );
|
||||
//CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, rightEyeDesc );
|
||||
|
||||
@ -1021,7 +1028,8 @@ EX void gen_mv() {
|
||||
EX shiftmatrix master_cview;
|
||||
|
||||
EX void render() {
|
||||
track_poses();
|
||||
track_poses();
|
||||
get_eyes();
|
||||
resetbuffer rb;
|
||||
state = 2;
|
||||
vrhr::frusta.clear();
|
||||
@ -1033,11 +1041,31 @@ EX void render() {
|
||||
if(1) {
|
||||
make_actual_view();
|
||||
master_cview = cview();
|
||||
|
||||
/* unfortunately we need to backup everything that could change by shift_view... */
|
||||
dynamicval<transmatrix> tN(NLP, NLP);
|
||||
dynamicval<transmatrix> tV(View, View);
|
||||
dynamicval<transmatrix> tC(current_display->which_copy, current_display->which_copy);
|
||||
dynamicval<transmatrix> trt(radar_transform);
|
||||
|
||||
/* changed in intra */
|
||||
dynamicval<ld> tcs(camera_speed);
|
||||
dynamicval<ld> tcl(anims::cycle_length);
|
||||
dynamicval<ld> tau(vrhr::absolute_unit_in_meters);
|
||||
dynamicval<ld> tel(walking::eye_level);
|
||||
dynamicval<int> tfd(walking::floor_dir);
|
||||
dynamicval<cell*> tof(walking::on_floor_of);
|
||||
|
||||
int id = intra::current;
|
||||
cell *co = centerover;
|
||||
finalizer fin([&] {
|
||||
if(intra::current != id) {
|
||||
println(hlog, "rendering via portal");
|
||||
intra::switch_to(id);
|
||||
centerover = co;
|
||||
}
|
||||
});
|
||||
|
||||
if(hsm == eHeadset::rotation_only) {
|
||||
transmatrix T = hmd_at;
|
||||
be_33(T);
|
||||
|
Loading…
Reference in New Issue
Block a user