first commit of AdS game

This commit is contained in:
Zeno Rogue 2022-09-11 12:16:50 +02:00
parent ab7ebd3bbc
commit 4eebc5858e
8 changed files with 866 additions and 0 deletions

64
rogueviz/ads/ads-game.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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();
}
}}