mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-22 23:17:04 +00:00
first commit of AdS game
This commit is contained in:
parent
ab7ebd3bbc
commit
4eebc5858e
64
rogueviz/ads/ads-game.cpp
Normal file
64
rogueviz/ads/ads-game.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include "../rogueviz.h"
|
||||
|
||||
#include "math.cpp"
|
||||
#include "globals.cpp"
|
||||
#include "shapes.cpp"
|
||||
#include "map.cpp"
|
||||
#include "control.cpp"
|
||||
#include "display.cpp"
|
||||
#include "menu.cpp"
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
void change_default_key(int key, int val) {
|
||||
char* t = multi::scfg.keyaction;
|
||||
t[key] = val;
|
||||
#if CAP_CONFIG
|
||||
set_saver_default(t[key]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void run_ads_game() {
|
||||
|
||||
change_default_key('s', 16 + 0);
|
||||
change_default_key('a', 16 + 1);
|
||||
change_default_key('w', 16 + 2);
|
||||
change_default_key('d', 16 + 3);
|
||||
change_default_key('f', 16 + 4);
|
||||
change_default_key('p', 16 + 5);
|
||||
change_default_key('t', 16 + 6);
|
||||
change_default_key('o', 16 + 7);
|
||||
change_default_key('m', 16 + 8);
|
||||
|
||||
nomap = true;
|
||||
no_find_player = true;
|
||||
vctr = cwt.at;
|
||||
cell *c = hybrid::get_where(vctr).first;
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
gen_terrain(c, ci_at[c], -2);
|
||||
forCellEx(c1, c) ci_at[c1].type = wtNone;
|
||||
ci_at[c].type = wtNone;
|
||||
});
|
||||
vctrV = ads_matrix(Id, 0);
|
||||
rogueviz::rv_hook(hooks_prestats, 100, view_ads_game);
|
||||
rogueviz::rv_hook(hooks_handleKey, 0, handleKey);
|
||||
rogueviz::rv_hook(shmup::hooks_turn, 0, ads_turn);
|
||||
}
|
||||
|
||||
auto shot_hooks =
|
||||
arg::add3("-ads-game", run_ads_game)
|
||||
+ addHook(hooks_configfile, 100, [] {
|
||||
param_f(simspeed, "ads_game_simspeed")
|
||||
-> editable(0, 2*TAU, TAU/4, "game speed", "Controls the speed of the game.", 's');
|
||||
param_f(accel, "ads_game_accel")
|
||||
-> editable(0, 30, 1, "acceleration", "Controls the speed of your ship's acceleration.", 'a');
|
||||
param_b(auto_rotate, "ads_auto_rotate")
|
||||
-> editable("automatically rotate the screen", 'r');
|
||||
param_b(view_proper_times, "ads_display")
|
||||
-> editable("display the proper times", 't');
|
||||
});
|
||||
|
||||
}
|
||||
}
|
160
rogueviz/ads/control.cpp
Normal file
160
rogueviz/ads/control.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
vector<string> move_names = { "acc down", "acc left", "acc up", "acc right", "fire", "pause", "display times", "switch spin", "menu" };
|
||||
|
||||
void fire() {
|
||||
auto g = hybrid::get_where(vctr);
|
||||
auto c = g.first;
|
||||
if(g.second != 0) println(hlog, "WARNING: vctr not zeroed");
|
||||
|
||||
ads_matrix S0 = ads_inverse(current * vctrV) * spin(ang*degree);
|
||||
|
||||
ads_matrix S1 = S0 * lorentz(0, 2, 3); // 0.995c
|
||||
|
||||
auto& ro = ci_at[c].rocks;
|
||||
ro.emplace_back(rockinfo{1, S1, 0xC0C0FFFF });
|
||||
auto& r = ro.back();
|
||||
|
||||
ads_matrix Scell(Id, 0);
|
||||
cell *lcell = vctr;
|
||||
auto wcell = hybrid::get_where(lcell);
|
||||
|
||||
int steps = 0;
|
||||
|
||||
compute_life(vctr, unshift(r.at), [&] (cell *c1, ld t) {
|
||||
if(true) for(int i=0; i<lcell->type; i++) {
|
||||
auto lcell1 = lcell->cmove(i);
|
||||
auto wcell1 = hybrid::get_where(lcell1);
|
||||
if(wcell1.first == c1) {
|
||||
Scell = Scell * currentmap->adj(lcell, i);
|
||||
optimize_shift(Scell);
|
||||
lcell = lcell1;
|
||||
wcell = wcell1;
|
||||
adjust_to_zero(Scell, wcell, cgi.plevel);
|
||||
steps++;
|
||||
lcell = hybrid::get_at(wcell.first, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(true) if(wcell.first != c1) {
|
||||
println(hlog, "warning: got lost after ", steps, " steps");
|
||||
println(hlog, wcell);
|
||||
println(hlog, c1);
|
||||
println(hlog, "their distance is ", PIU(celldistance(wcell.first, c1)));
|
||||
return true;
|
||||
}
|
||||
auto& ci = ci_at[c1];
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
gen_terrain(c1, ci);
|
||||
gen_rocks(c1, ci, 2);
|
||||
});
|
||||
if(among(ci.type, wtSolid, wtDestructible)) {
|
||||
r.life_end = t;
|
||||
|
||||
auto Scell_inv = ads_inverse(Scell);
|
||||
Scell_inv = Scell_inv * r.at;
|
||||
Scell_inv = Scell_inv * ads_matrix(Id, t);
|
||||
optimize_shift(Scell_inv);
|
||||
|
||||
auto X = ads_inverse(Scell);
|
||||
X = X * (r.at * ads_matrix(Id, t));
|
||||
optimize_shift(X);
|
||||
|
||||
ads_matrix prel = ads_inverse(S0) * r.at * ads_matrix(Id, t);
|
||||
|
||||
println(hlog, "crashed: proper time = ", t/TAU, " wall time = ", Scell_inv.shift / TAU, " player time = ", (prel.shift+ship_pt) / TAU, " start = ", ship_pt / TAU);
|
||||
if(abs(X.shift - Scell_inv.shift) > .2) {
|
||||
println(hlog, "INTRANSITIVITY ERROR! ", X.shift, " vs ", Scell_inv.shift);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
bool handleKey(int sym, int uni) {
|
||||
/*
|
||||
if(uni == 'p') paused = !paused;
|
||||
|
||||
if(among(uni, 'a', 'd', 's', 'w')) return true;
|
||||
|
||||
if(uni == 't') { view_proper_times = !view_proper_times; return true; }
|
||||
if(uni == 'o') { auto_rotate = !auto_rotate; return true; }
|
||||
|
||||
if(uni == 'f') fire();
|
||||
*/
|
||||
|
||||
if(sym > 0 && sym < 512 && (cmode & sm::NORMAL)) {
|
||||
char* t = multi::scfg.keyaction;
|
||||
if(t[sym] >= 16 && t[sym] < 32) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void apply_lorentz(transmatrix lor) {
|
||||
current = ads_matrix(lor, 0) * current;
|
||||
}
|
||||
|
||||
bool ads_turn(int idelta) {
|
||||
multi::handleInput(idelta);
|
||||
ld delta = idelta / anims::period;
|
||||
|
||||
if(!(cmode & sm::NORMAL)) return false;
|
||||
|
||||
auto& a = multi::actionspressed;
|
||||
auto& la = multi::lactionpressed;
|
||||
|
||||
vector<int> ap;
|
||||
for(int i=0; i<NUMACT; i++) if(a[i]) ap.push_back(i);
|
||||
|
||||
if(a[16+4] && !la[16+4]) fire();
|
||||
if(a[16+5] && !la[16+5]) paused = !paused;
|
||||
if(a[16+6] && !la[16+6]) view_proper_times = !view_proper_times;
|
||||
if(a[16+7] && !la[16+7]) auto_rotate = !auto_rotate;
|
||||
if(a[16+8] && !la[16+8]) pushScreen(game_menu);
|
||||
|
||||
if(!paused) {
|
||||
dynamicval<eGeometry> g(geometry, geometry == gRotSpace ? geometry : gCubeTiling);
|
||||
|
||||
/* proper time passed */
|
||||
ld pt = delta * simspeed;
|
||||
|
||||
bool left = a[16+1];
|
||||
bool right = a[16+3];
|
||||
bool up = a[16+2];
|
||||
bool down = a[16];
|
||||
|
||||
if(left) apply_lorentz(lorentz(0, 2, delta*accel)), ang = 180;
|
||||
if(right) apply_lorentz(lorentz(0, 2, -delta*accel)), ang = 0;
|
||||
if(up) apply_lorentz(lorentz(1, 2, delta*accel)), ang = 90;
|
||||
if(down) apply_lorentz(lorentz(1, 2, -delta*accel)), ang = 270;
|
||||
|
||||
if(left && up) ang = 135;
|
||||
if(left && down) ang = 225;
|
||||
if(right && up) ang = 45;
|
||||
if(right && down) ang = 315;
|
||||
|
||||
current.T = cspin(3, 2, pt) * current.T;
|
||||
optimize_shift(current);
|
||||
hassert(eqmatrix(chg_shift(current.shift) * current.T, unshift(current)));
|
||||
|
||||
if(auto_rotate)
|
||||
current.T = cspin(1, 0, pt) * current.T;
|
||||
else
|
||||
ang += pt / degree;
|
||||
|
||||
ship_pt += pt;
|
||||
}
|
||||
|
||||
fixmatrix_ads(current.T);
|
||||
fixmatrix_ads(vctrV.T);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
225
rogueviz/ads/display.cpp
Normal file
225
rogueviz/ads/display.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
flatresult findflat(shiftpoint h) {
|
||||
return cross0(current * rgpushxto0(h));
|
||||
}
|
||||
|
||||
void draw_game_cell(cell *cs, ads_matrix V, ld plev) {
|
||||
auto g = PIA( hybrid::get_where(cs) );
|
||||
adjust_to_zero(V, g, plev);
|
||||
auto c = g.first;
|
||||
|
||||
flatresult center;
|
||||
vector<flatresult> hlist;
|
||||
|
||||
hybrid::in_actual([&]{
|
||||
for(int i=0; i<=c->type; i++) {
|
||||
hyperpoint ha = hybrid::get_corner(c, i, 2, 0);
|
||||
hlist.push_back(findflat(V * ha));
|
||||
}
|
||||
center = findflat(V * C0);
|
||||
});
|
||||
|
||||
if(1) {
|
||||
ld d = hdist0(center.h);
|
||||
if(d < vctr_dist) vctr_dist = d, vctr = PIA( hybrid::get_at(c, 0) ), vctrV = V;
|
||||
}
|
||||
|
||||
auto& ci = ci_at[c];
|
||||
if(ci.mpd_terrain > 0) {
|
||||
if(!gen_budget) return;
|
||||
gen_budget--;
|
||||
}
|
||||
gen_terrain(c, ci);
|
||||
gen_rocks(c, ci, 0);
|
||||
|
||||
auto& t = ci.type;
|
||||
|
||||
if(t == wtGate) {
|
||||
ld minv = hlist[0].shift;
|
||||
ld maxv = hlist[0].shift;
|
||||
for(auto& h: hlist) {
|
||||
ld v = h.shift;
|
||||
if(v < minv) minv = v;
|
||||
if(v > maxv) maxv = v;
|
||||
}
|
||||
|
||||
auto draw_slice = [&] (ld a, ld b, color_t col) {
|
||||
vector<hyperpoint> slice;
|
||||
for(int i=0; i<c->type; i++) {
|
||||
if(hlist[i].shift >= a && hlist[i].shift <= b)
|
||||
slice.push_back(hlist[i].h);
|
||||
if((hlist[i].shift < a) ^ (hlist[i+1].shift < a)) {
|
||||
ld p = ilerp(hlist[i].shift, hlist[i+1].shift, a);
|
||||
hyperpoint h1 = lerp(hlist[i].h, hlist[i+1].h, p);
|
||||
slice.push_back(h1);
|
||||
}
|
||||
if((hlist[i].shift > b) ^ (hlist[i+1].shift > b)) {
|
||||
ld p = ilerp(hlist[i].shift, hlist[i+1].shift, b);
|
||||
hyperpoint h1 = lerp(hlist[i].h, hlist[i+1].h, p);
|
||||
slice.push_back(h1);
|
||||
}
|
||||
if(hlist[i+1].shift < a && hlist[i].shift > b)
|
||||
swap((&slice.back())[-1], slice.back());
|
||||
}
|
||||
if(isize(slice) < 3) return;
|
||||
for(auto e: slice) curvepoint(e);
|
||||
curvepoint(slice[0]);
|
||||
queuecurve(shiftless(Id), 0xFFFFFFFF, col, PPR::LINE);
|
||||
};
|
||||
|
||||
for(int v=floor(minv); v<maxv+1; v++) {
|
||||
draw_slice(v, v+1, (v & 3) ? 0x080828FF : 0xA04020FF);
|
||||
}
|
||||
}
|
||||
else {
|
||||
color_t col =
|
||||
t == wtSolid ? 0x603000FF :
|
||||
t == wtDestructible ? 0x301800FF :
|
||||
0x181818FF;
|
||||
|
||||
for(auto h: hlist) curvepoint(h.h);
|
||||
addaura(shiftless(center.h), col >> 8, 0);
|
||||
queuecurve(shiftless(Id), 0x101010FF, col, PPR::WALL);
|
||||
}
|
||||
|
||||
if(view_proper_times) {
|
||||
string str = format(tformat, center.shift / TAU);
|
||||
queuestr(shiftless(rgpushxto0(center.h)), .1, str, 0xFF4040, 8);
|
||||
}
|
||||
|
||||
for(auto& rock: ci.rocks) {
|
||||
|
||||
vector<hyperpoint> pts;
|
||||
|
||||
vector<ld>& shape = rock.type ? shape_missile : shape_rock;
|
||||
|
||||
flatresult fr_main;
|
||||
if(1) hybrid::in_actual([&]{
|
||||
dynamicval<eGeometry> b(geometry, gRotSpace);
|
||||
auto h = V * rock.at;
|
||||
fr_main = cross0(current * h);
|
||||
});
|
||||
if(fr_main.shift < rock.life_start || fr_main.shift > rock.life_end) continue;
|
||||
|
||||
for(int i=0; i<isize(shape); i += 2) {
|
||||
hybrid::in_actual([&]{
|
||||
auto h = V * rock.at * rots::uxpush(shape[i]) * rots::uypush(shape[i+1]);
|
||||
flatresult f = cross0(current * h);
|
||||
pts.push_back(f.h);
|
||||
});
|
||||
}
|
||||
|
||||
for(auto h: pts) curvepoint(h);
|
||||
curvepoint(pts[0]);
|
||||
queuecurve(shiftless(Id), rock.type == 1 ? 0xFF0000FF : 0x000000FF, rock.col, PPR::LINE);
|
||||
|
||||
if(view_proper_times) {
|
||||
string str = format(tformat, fr_main.shift / TAU);
|
||||
queuestr(shiftless(rgpushxto0(fr_main.h)), .1, str, 0xFFFFFF, 8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool view_ads_game() {
|
||||
auto plev = cgi.plevel; /* we are in another CGI so we have no access to that... */
|
||||
gen_budget = 5;
|
||||
|
||||
flatresult base;
|
||||
if(1) {
|
||||
// todo rebase
|
||||
base = findflat(ads_point(C0, 0));
|
||||
// println(hlog, base.h);
|
||||
ld ebase = 0;
|
||||
hybrid::in_underlying_geometry([&]{
|
||||
ebase = hdist0(base.h);
|
||||
// println(hlog, "dist base pre = ", hdist0(base.h), " at ", base.shift);
|
||||
});
|
||||
// println(hlog, base.h[2]*base.h[2] - base.h[1]*base.h[1] - base.h[0] * base.h[0]);
|
||||
|
||||
for(int u=0; u<30; u++) {
|
||||
auto bcurrent = current;
|
||||
|
||||
transmatrix T = spin(12*degree*u) * xpush(0.5);
|
||||
|
||||
current.T = current.T * T;
|
||||
auto base1 = findflat(ads_point(C0, 0));
|
||||
ld ebase1 = 0;
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
ebase1 = hdist0(base1.h);
|
||||
});
|
||||
if(ebase1 < ebase) { vctrV.T = inverse(T) * vctrV.T; }
|
||||
else { current = bcurrent; }
|
||||
}
|
||||
}
|
||||
// current = current * gpushxto0(p);
|
||||
// vctrV = rgpushxto0(p) * vctrV;
|
||||
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
dynamicval<eModel> p(pmodel, mdDisk);
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
cgi.require_shapes();
|
||||
ptds.clear();
|
||||
calcparam();
|
||||
clearaura();
|
||||
make_shape();
|
||||
|
||||
set<cell*> visited;
|
||||
queue<pair<cell*, ads_matrix>> dq;
|
||||
auto visit = [&] (cell *c, const ads_matrix& V) {
|
||||
auto w = hybrid::get_where(c);
|
||||
if(visited.count(w.first)) return;
|
||||
visited.insert(w.first);
|
||||
dq.emplace(c, V);
|
||||
};
|
||||
|
||||
hybrid::in_actual([&] {
|
||||
dynamicval<eGeometry> b(geometry, gRotSpace);
|
||||
visit(vctr, vctrV);
|
||||
vctr_dist = HUGE_VAL;
|
||||
});
|
||||
|
||||
int i = 0;
|
||||
while(!dq.empty()) {
|
||||
i++; if(i > 1000) break;
|
||||
auto& p = dq.front();
|
||||
cell *c = p.first;
|
||||
ads_matrix V = p.second;
|
||||
dq.pop();
|
||||
|
||||
draw_game_cell(c, V, plev);
|
||||
|
||||
hybrid::in_actual([&] {
|
||||
for(int i=0; i<c->type-2; i++) {
|
||||
cell *c2 = c->cmove(i);
|
||||
auto V1 = V * currentmap->adj(c, i);
|
||||
optimize_shift(V1);
|
||||
visit(c2, V1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(true) {
|
||||
poly_outline = 0xFF;
|
||||
queuepolyat(shiftless(spin(ang*degree) * Id), shShip, 0x2020FFFF, PPR::LINE);
|
||||
|
||||
if(view_proper_times) {
|
||||
string str = format(tformat, ship_pt / TAU);
|
||||
queuestr(shiftless(Id), .1, str, 0xFFFFFF, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if(false) queuepolyat(shiftless(rgpushxto0(base.h)), cgi.shGem[0], 0x2020FFFF, PPR::LINE);
|
||||
|
||||
drawqueue();
|
||||
drawaura();
|
||||
});
|
||||
check_cgi();
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
43
rogueviz/ads/globals.cpp
Normal file
43
rogueviz/ads/globals.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
/** simulation speed */
|
||||
ld simspeed = TAU;
|
||||
|
||||
/** by how much do WAS keys accelerate */
|
||||
ld accel = 6;
|
||||
|
||||
/** transform world coordinates to ship coordinates */
|
||||
ads_matrix current;
|
||||
|
||||
/** SL cell closest to the ship */
|
||||
cell *vctr;
|
||||
|
||||
/** world coordinates of vctr -- technically, this is a shiftmatrix */
|
||||
ads_matrix vctrV;
|
||||
|
||||
/** how far is vctr from the ship */
|
||||
ld vctr_dist;
|
||||
|
||||
/** how is the ship shape rotated */
|
||||
ld ang = 0;
|
||||
|
||||
/** ship's current proper time */
|
||||
ld ship_pt;
|
||||
|
||||
/** is the game paused */
|
||||
bool paused;
|
||||
|
||||
/** auto-rotate the screen */
|
||||
bool auto_rotate = false;
|
||||
|
||||
/** should we display the proper times of all objects */
|
||||
bool view_proper_times = false;
|
||||
|
||||
/** format for displaying time */
|
||||
const char *tformat = "%.2f";
|
||||
|
||||
void game_menu();
|
||||
|
||||
}}
|
141
rogueviz/ads/map.cpp
Normal file
141
rogueviz/ads/map.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
struct rockinfo {
|
||||
int type;
|
||||
ads_matrix at;
|
||||
color_t col;
|
||||
|
||||
ld life_start, life_end;
|
||||
|
||||
rockinfo(int t, const ads_matrix& T, color_t _col) : type(t), at(T), col(_col) {
|
||||
life_start = -HUGE_VAL;
|
||||
life_end = HUGE_VAL;
|
||||
}
|
||||
};
|
||||
|
||||
enum eWalltype { wtNone, wtDestructible, wtSolid, wtGate };
|
||||
|
||||
struct cellinfo {
|
||||
int mpd_terrain; /* 0 = fully generated terrain */
|
||||
int rock_dist; /* rocks generated in this radius */
|
||||
vector<rockinfo> rocks;
|
||||
eWalltype type;
|
||||
cellinfo() {
|
||||
mpd_terrain = 4;
|
||||
rock_dist = -1;
|
||||
type = wtNone;
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<cell*, cellinfo> ci_at;
|
||||
|
||||
using worldline_visitor = std::function<bool(cell*, ld)>;
|
||||
|
||||
void compute_life(cell *c, transmatrix S1, const worldline_visitor& wv) {
|
||||
ld t = 0;
|
||||
|
||||
int iter = 0;
|
||||
cell *cur_c = c;
|
||||
auto cur_w = hybrid::get_where(c);
|
||||
while(t < 2 * M_PI) {
|
||||
iter++;
|
||||
auto last_w = cur_w;
|
||||
auto next_w = cur_w;
|
||||
transmatrix next_S1;
|
||||
ld next_t;
|
||||
ld last_time = t;
|
||||
cell *next_c = nullptr;
|
||||
binsearch(t, t+M_PI/2, [&] (ld t1) {
|
||||
S1 = S1 * chg_shift(t1 - last_time);
|
||||
last_time = t1;
|
||||
virtualRebase(cur_c, S1);
|
||||
cur_w = hybrid::get_where(cur_c);
|
||||
if(cur_w.first != last_w.first) {
|
||||
next_c = cur_c;
|
||||
next_w = cur_w;
|
||||
next_S1 = S1;
|
||||
next_t = t1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, 20);
|
||||
if(!next_c) return;
|
||||
S1 = next_S1;
|
||||
cur_w = next_w;
|
||||
t = next_t;
|
||||
cur_c = next_c;
|
||||
if(iter > 1000) {
|
||||
println(hlog, "compute_life c=", cur_c, " w=", cur_w, "t=", t, " S1=", S1);
|
||||
fixmatrix_ads(S1);
|
||||
}
|
||||
if(iter > 1100) break;
|
||||
if(wv(cur_w.first, t)) break;
|
||||
}
|
||||
}
|
||||
|
||||
map<int, int> genstats;
|
||||
|
||||
int gen_budget;
|
||||
|
||||
void gen_terrain(cell *c, cellinfo& ci, int level = 0) {
|
||||
if(level >= ci.mpd_terrain) return;
|
||||
if(ci.mpd_terrain > level + 1) gen_terrain(c, ci, level+1);
|
||||
forCellCM(c1, c) gen_terrain(c1, ci_at[c1], level+1);
|
||||
genstats[level]++;
|
||||
|
||||
if(level == 2) {
|
||||
int r = hrand(100);
|
||||
if(r < 5) {
|
||||
forCellCM(c1, c) if(hrand(100) < 50)
|
||||
forCellCM(c2, c1) if(hrand(100) < 50)
|
||||
if(ci_at[c2].type == wtNone) ci_at[c2].type = wtDestructible;
|
||||
}
|
||||
else if(r < 10) {
|
||||
forCellCM(c1, c) if(hrand(100) < 50)
|
||||
forCellCM(c2, c1) if(hrand(100) < 50)
|
||||
if(ci_at[c2].type < wtSolid)
|
||||
ci_at[c2].type = wtSolid;
|
||||
}
|
||||
else if(r < 12)
|
||||
ci_at[c].type = wtGate;
|
||||
}
|
||||
ci.mpd_terrain = level;
|
||||
}
|
||||
|
||||
void gen_rocks(cell *c, cellinfo& ci, int radius) {
|
||||
if(radius <= ci.rock_dist) return;
|
||||
if(ci.rock_dist < radius - 1) gen_rocks(c, ci, radius-1);
|
||||
forCellCM(c1, c) gen_rocks(c1, ci_at[c1], radius-1);
|
||||
if(geometry != gNormal) { println(hlog, "wrong geometry detected in gen_rocks 1!"); exit(1); }
|
||||
|
||||
if(radius == 0) {
|
||||
hybrid::in_actual([&] {
|
||||
int q = rpoisson(.05);
|
||||
|
||||
auto add_rock = [&] (rockinfo&& r) {
|
||||
if(geometry != gRotSpace) { println(hlog, "wrong geometry detected in gen_rocks 2!"); exit(1); }
|
||||
compute_life(hybrid::get_at(c, 0), unshift(r.at), [&] (cell *c, ld t) {
|
||||
auto& ci = ci_at[c];
|
||||
hybrid::in_underlying_geometry([&] { gen_terrain(c, ci); });
|
||||
ci.type = wtNone;
|
||||
return false;
|
||||
});
|
||||
ci.rocks.emplace_back(r);
|
||||
};
|
||||
|
||||
for(int i=0; i<q; i++) {
|
||||
int kind = hrand(100);
|
||||
if(kind < 50)
|
||||
add_rock(rockinfo(0, ads_matrix(rots::uxpush(randd() * .6 - .3) * rots::uypush(randd() * .6 - .3)), 0xC0C0C0FF));
|
||||
else
|
||||
add_rock(rockinfo(0, ads_matrix(rots::uypush(randd() * .6 - .3) * lorentz(0, 3, 0.5 + randd() * 1)), 0xC04040FF));
|
||||
}
|
||||
});
|
||||
}
|
||||
ci.rock_dist = radius;
|
||||
}
|
||||
|
||||
|
||||
}}
|
163
rogueviz/ads/math.cpp
Normal file
163
rogueviz/ads/math.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
#include "../rogueviz.h"
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
static constexpr auto TAU = 2*M_PI;
|
||||
|
||||
/** hyperpoint represents a point in the SL(2,R)-like AdS, while ads_point represents a point in the universal cover */
|
||||
struct ads_point : shiftpoint {
|
||||
ads_point(hyperpoint _h = C0, ld _s = 0) { h = _h; shift = _s; }
|
||||
ads_point(shiftpoint _s) : shiftpoint(_s) {}
|
||||
};
|
||||
|
||||
/** similarly, ads_matrix represents a transformation of the universal cover space */
|
||||
struct ads_matrix : shiftmatrix {
|
||||
ads_matrix(transmatrix _h = Id, ld _s = 0) { T = _h; shift = _s; }
|
||||
ads_point operator* (ads_point);
|
||||
ads_matrix operator* (ads_matrix);
|
||||
ads_point operator* (hyperpoint h) { return ads_point(T*h, shift); }
|
||||
ads_matrix operator* (transmatrix h) { return ads_matrix(T*h, shift); }
|
||||
ads_matrix(shiftmatrix _s) : shiftmatrix(_s) {}
|
||||
};
|
||||
|
||||
ads_point kz(ads_point x) { x.h = hr::kz(x.h); x.shift = hr::kz(x.shift); return x; }
|
||||
ads_matrix kz(ads_matrix x) { x.T = hr::kz(x.T); x.shift = hr::kz(x.shift); return x; }
|
||||
|
||||
/** Lorentz boost. */
|
||||
transmatrix lorentz(int a, int b, ld v) {
|
||||
transmatrix T = Id;
|
||||
T[a][a] = T[b][b] = cosh(v);
|
||||
T[a][b] = T[b][a] = sinh(v);
|
||||
return T;
|
||||
}
|
||||
|
||||
void fixmatrix_ads(transmatrix& T) {
|
||||
for(int x=0; x<4; x++) for(int y=x; y>=0; y--) {
|
||||
ld dp = 0;
|
||||
for(int z=0; z<4; z++) dp += T[z][x] * T[z][y] * sig(z);
|
||||
|
||||
if(y == x) dp = 1 - sqrt(sig(x)/dp);
|
||||
else dp *= sig(y);
|
||||
|
||||
for(int z=0; z<4; z++) T[z][x] -= dp * T[z][y];
|
||||
}
|
||||
}
|
||||
|
||||
/* get_at(g) is at V; adjust g.second==0 and V accordingly */
|
||||
void adjust_to_zero(ads_matrix& V, pair<cell*, int>& g, ld plev) {
|
||||
V.shift -= plev * g.second;
|
||||
g.second = 0;
|
||||
}
|
||||
|
||||
/** by how many cycles should we shift */
|
||||
ld get_shift_cycles(ld shift) {
|
||||
return floor(shift / TAU + .5) * TAU;
|
||||
}
|
||||
|
||||
/** this is uzpush(-x) */
|
||||
transmatrix chg_shift(ld x) {
|
||||
return cspin(2, 3, x) * cspin(0, 1, x);
|
||||
}
|
||||
|
||||
ads_point ads_matrix::operator*(ads_point h) {
|
||||
auto& T = *this;
|
||||
optimize_shift(h);
|
||||
ld sh = get_shift_cycles(h.shift);
|
||||
h.shift -= sh;
|
||||
auto res0 = T;
|
||||
optimize_shift(res0);
|
||||
auto res1 = res0 * chg_shift(h.shift);
|
||||
optimize_shift(res1);
|
||||
res1.shift += get_shift_cycles(res0.shift - res1.shift);
|
||||
auto res2 = res1 * h.h;
|
||||
optimize_shift(res2);
|
||||
res2.shift += get_shift_cycles(res1.shift - res2.shift);
|
||||
res2.shift += sh;
|
||||
return res2;
|
||||
}
|
||||
|
||||
ads_matrix ads_matrix::operator*(ads_matrix h) {
|
||||
auto& T = *this;
|
||||
optimize_shift(h);
|
||||
ld sh = get_shift_cycles(h.shift);
|
||||
h.shift -= sh;
|
||||
|
||||
auto res0 = T;
|
||||
optimize_shift(res0);
|
||||
auto res1 = res0 * chg_shift(h.shift);
|
||||
optimize_shift(res1);
|
||||
res1.shift += get_shift_cycles(res0.shift - res1.shift);
|
||||
auto res2 = res1 * h.T;
|
||||
optimize_shift(res2);
|
||||
res2.shift += get_shift_cycles(res1.shift - res2.shift);
|
||||
res2.shift += sh;
|
||||
return res2;
|
||||
}
|
||||
|
||||
ads_matrix ads_inverse(const ads_matrix& T) {
|
||||
ads_matrix res(inverse(unshift(T)), 0);
|
||||
ads_matrix m = res * T;
|
||||
optimize_shift(m);
|
||||
res.shift -= m.shift;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct flatresult {
|
||||
hyperpoint h;
|
||||
ld shift;
|
||||
};
|
||||
|
||||
extern ads_matrix current;
|
||||
|
||||
/** T represents a worldline of some object; find when does this worldline cross the time=0 slice.
|
||||
* shift is T's proper time at the point of crossing, and h=(x,y,z) is the Minkowski hyperboloid point where it crosses.
|
||||
**/
|
||||
|
||||
flatresult cross0(ads_matrix hz) {
|
||||
|
||||
transmatrix deg90 = chg_shift(90*degree);
|
||||
hyperpoint uhz = unshift(hz * C0);
|
||||
hyperpoint uhz1 = unshift(hz * deg90 * C0);
|
||||
|
||||
ld cost, sint, tant;
|
||||
ld t;
|
||||
|
||||
if(uhz1[2]) {
|
||||
tant = - uhz[2] / uhz1[2];
|
||||
cost = 1 / sqrt(1 + tant * tant);
|
||||
sint = tant * cost;
|
||||
t = atan2(sint, cost);
|
||||
}
|
||||
else {
|
||||
cost = 0;
|
||||
sint = 1;
|
||||
t = 90*degree;
|
||||
}
|
||||
|
||||
hyperpoint uhzt = unshift(hz * chg_shift(t) * C0);
|
||||
if(uhzt[3] < 0) { t += 180*degree; uhzt = -uhzt; }
|
||||
|
||||
tie(uhzt[2], uhzt[3]) = make_pair(uhzt[3], -uhzt[2]);
|
||||
t += get_shift_cycles(-hz.shift-t);
|
||||
|
||||
return flatresult{uhzt, t};
|
||||
}
|
||||
|
||||
/** sample from Poisson distribution */
|
||||
int rpoisson(ld lambda) {
|
||||
ld prob = randd();
|
||||
ld poisson = exp(-lambda);
|
||||
int cnt = 0;
|
||||
while(cnt < 2*lambda+100) {
|
||||
if(prob < poisson) break;
|
||||
prob -= poisson;
|
||||
cnt++;
|
||||
poisson *= lambda / cnt;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
39
rogueviz/ads/menu.cpp
Normal file
39
rogueviz/ads/menu.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
void game_menu() {
|
||||
dialog::init(XLAT("AdS game settings"), 0xC0C0FFFF, 150, 100);
|
||||
|
||||
add_edit(simspeed);
|
||||
add_edit(accel);
|
||||
add_edit(view_proper_times);
|
||||
add_edit(auto_rotate);
|
||||
|
||||
dialog::addItem("configure keys", 'k');
|
||||
dialog::add_action_push(multi::get_key_configurer(1, move_names, "Nilrider keys"));
|
||||
|
||||
#if CAP_AUDIO
|
||||
add_edit(effvolume);
|
||||
add_edit(musicvolume);
|
||||
#endif
|
||||
|
||||
dialog::addItem("RogueViz settings", 'r');
|
||||
dialog::add_key_action('r', [] {
|
||||
pushScreen(showSettings);
|
||||
});
|
||||
|
||||
#if CAP_FILES && !ISWEB
|
||||
dialog::addItem("save the current config", 's');
|
||||
dialog::add_action([] {
|
||||
dynamicval<eGeometry> g(geometry, gNormal);
|
||||
saveConfig();
|
||||
});
|
||||
#endif
|
||||
|
||||
dialog::addBreak(100);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
}}
|
31
rogueviz/ads/shapes.cpp
Normal file
31
rogueviz/ads/shapes.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
namespace hr {
|
||||
|
||||
namespace ads_game {
|
||||
|
||||
hpcshape shShip;
|
||||
bool made;
|
||||
|
||||
vector<ld> shape_rock = { -0.0176894, 0.0952504, 0.0278998, 0.0966286, 0.0686721, 0.0455547, 0.110983, 0.0122558, 0.0994024, -0.0483395, 0.0517039, -0.0802772, -0.00271848, -0.0706804, -0.0564861, -0.08575, -0.100087, -0.0483411, -0.100031, -0.0102072, -0.0761486, 0.0292356, -0.0639653, 0.077575 };
|
||||
vector<ld> shape_missile = {
|
||||
|
||||
/* 0.201073, 0.00513228, 0.161595, 0.0253201, -0.135796, 0.0245209, -0.194281, 0.0372705,
|
||||
-0.194281, -0.0372705, -0.135796, -0.0245209, 0.161595, -0.0253201, 0.201073, -0.00513228 */
|
||||
0.04, 0, 0.01, 0.02, -0.02, 0.02, -0.02, -0.02, 0.01, -0.02,
|
||||
};
|
||||
|
||||
void make_shape() {
|
||||
if(made) return;
|
||||
made = true;
|
||||
vector<ld> ship = {
|
||||
0.100145, 0.00834541, 0.0810058, 0.0190602, 0.0356926, 0.0237951, 0.0619128, 0.0309564, 0.0631121, 0.0369146, 0.0333191, 0.038079, -0.0333481, 0.0702692, -0.0321308, 0.041651, -0.0380849, 0.0416554, -0.0380749, 0.0261765, -0.0273608, 0.023792
|
||||
};
|
||||
cgi.bshape(shShip, PPR::MONSTER_BODY);
|
||||
int N = isize(ship);
|
||||
for(int i=0; i<N; i += 2) cgi.hpcpush(hpxy(ship[i] - .03, ship[i+1]));
|
||||
for(int i=N-2; i>=0; i-=2) cgi.hpcpush(hpxy(ship[i] - .03, -ship[i+1]));
|
||||
cgi.hpcpush(hpxy(ship[0] - .03, ship[1]));
|
||||
cgi.finishshape();
|
||||
cgi.extra_vertices();
|
||||
}
|
||||
|
||||
}}
|
Loading…
Reference in New Issue
Block a user