mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-24 05:17:17 +00:00
nilrider:: first commit
This commit is contained in:
parent
e25b8b94c2
commit
920bf96088
312
rogueviz/nilrider/level.cpp
Normal file
312
rogueviz/nilrider/level.cpp
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
void level::init() {
|
||||||
|
if(initialized) return;
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
unil_texture = new texture::texture_data;
|
||||||
|
|
||||||
|
auto& tex = *unil_texture;
|
||||||
|
|
||||||
|
real_minx = HUGE_VAL;
|
||||||
|
real_miny = HUGE_VAL;
|
||||||
|
real_maxx = -HUGE_VAL;
|
||||||
|
real_maxy = -HUGE_VAL;
|
||||||
|
|
||||||
|
if(flags & nrlPolar)
|
||||||
|
scale = 1;
|
||||||
|
else
|
||||||
|
scale = abs(maxx - minx) / isize(map_tiles[0]);
|
||||||
|
|
||||||
|
println(hlog, "SCALE IS ", this->scale);
|
||||||
|
|
||||||
|
int tY = isize(map_tiles);
|
||||||
|
int tX = isize(map_tiles[0]);
|
||||||
|
|
||||||
|
tex.twidth = tex.tx = tX * 64;
|
||||||
|
tex.theight = tex.ty = tY * 64;
|
||||||
|
tex.stretched = false;
|
||||||
|
tex.strx = tex.tx;
|
||||||
|
tex.stry = tex.ty;
|
||||||
|
tex.base_x = 0;
|
||||||
|
tex.base_y = 0;
|
||||||
|
tex.whitetexture();
|
||||||
|
println(hlog, "tX=", tX, " tY=", tY, " tex=", tex.tx, "x", tex.ty);
|
||||||
|
|
||||||
|
for(int y=0; y<tex.ty; y++)
|
||||||
|
for(int x=0; x<tex.tx; x++) {
|
||||||
|
int bx = x / 64;
|
||||||
|
int by = y / 64;
|
||||||
|
char bmch = map_tiles[by][bx];
|
||||||
|
int sx = (x % 64) / 4;
|
||||||
|
int sy = (y % 64) / 4;
|
||||||
|
if(bmch == '!') continue;
|
||||||
|
char smch = submaps[bmch][sy][sx];
|
||||||
|
tex.get_texture_pixel(x, y) = bcols[smch];
|
||||||
|
tex.get_texture_pixel(x, y) |= 0xFF000000;
|
||||||
|
tex.get_texture_pixel(x, y) ^= hrand(0x1000000) & 0xF0F0F;
|
||||||
|
// (x * 256 / TEXSIZE + (((y * 256) / TEXSIZE) << 8)) | 0xFF000000;
|
||||||
|
}
|
||||||
|
tex.loadTextureGL();
|
||||||
|
|
||||||
|
start.where = mappt(startx+.5, starty+.5, 1);
|
||||||
|
start.t = 0;
|
||||||
|
current = start;
|
||||||
|
println(hlog, "start.where = ", start.where);
|
||||||
|
println(hlog, "current.where = ", current.where, " : ", format("%p", ¤t));
|
||||||
|
|
||||||
|
for(int s=0; s<2; s++) {
|
||||||
|
cgi.bshape(s == 0 ? shFloor : shPlanFloor, PPR::WALL);
|
||||||
|
shFloor.flags |= POLY_TRIANGLES;
|
||||||
|
shPlanFloor.flags |= POLY_TRIANGLES;
|
||||||
|
|
||||||
|
auto pt = [&] (int x, int y) {
|
||||||
|
if(s == 0) uniltinf.tvertices.push_back(glhr::makevertex(x * 1. / tX / 16, y * 1. / tY / 16, 0));
|
||||||
|
hyperpoint h = mappt(x, y, 16);
|
||||||
|
real_minx = min(real_minx, h[0]);
|
||||||
|
real_maxx = max(real_maxx, h[0]);
|
||||||
|
real_miny = min(real_miny, h[1]);
|
||||||
|
real_maxy = max(real_maxy, h[1]);
|
||||||
|
if(s == 1) h[2] = h[3] = 1;
|
||||||
|
// h[2] = h[0] * h[1] / 2 + .1;
|
||||||
|
// h[3] = 1;
|
||||||
|
cgi.hpcpush(h);
|
||||||
|
// println(hlog, "entered ", h);
|
||||||
|
// cgi.hpcpush(hyperpoint(rand() % 10 - 5, rand() % 10 - 5, rand() % 10 - 5, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int y=0; y<tY * 16; y++)
|
||||||
|
for(int x=0; x<tX * 16; x++) {
|
||||||
|
char bmch = map_tiles[y/16][x/16];
|
||||||
|
if(bmch == '!') continue;
|
||||||
|
pt(x, y);
|
||||||
|
pt(x, y+1);
|
||||||
|
pt(x+1, y);
|
||||||
|
pt(x+1, y+1);
|
||||||
|
pt(x+1, y);
|
||||||
|
pt(x, y+1);
|
||||||
|
}
|
||||||
|
cgi.finishshape();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(1) {
|
||||||
|
cgi.bshape(shField, PPR::WALL);
|
||||||
|
shField.flags |= POLY_TRIANGLES;
|
||||||
|
|
||||||
|
auto pt = [&] (hyperpoint p) {
|
||||||
|
hyperpoint h = mappt(p[0], p[1], 16);
|
||||||
|
h[2] += p[2];
|
||||||
|
cgi.hpcpush(h);
|
||||||
|
// cgi.hpcpush(hyperpoint(rand() % 10 - 5, rand() % 10 - 5, rand() % 10 - 5, 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int y=0; y<tY * 16; y++)
|
||||||
|
for(int x=0; x<tX * 16; x++) {
|
||||||
|
int bx = x / 16;
|
||||||
|
int by = y / 16;
|
||||||
|
char bmch = map_tiles[by][bx];
|
||||||
|
if(bmch == 'f' && (x&1) && (y&1)) {
|
||||||
|
for(int s=0; s<4; s++) {
|
||||||
|
hyperpoint st = point3(x+.1, y+.1, 0);
|
||||||
|
hyperpoint a = spin(90*degree*s) * point3(.1, .1, 0);
|
||||||
|
hyperpoint b = spin(90*degree*(s+1)) * point3(.1, .1, 0);
|
||||||
|
hyperpoint hi = point3(0, 0, 1);
|
||||||
|
for(int z=0; z<3; z++) {
|
||||||
|
ld z1 = (3-z) / 3.;
|
||||||
|
ld z2 = (2-z) / 3.;
|
||||||
|
pt(st + a * z1 + hi*z);
|
||||||
|
pt(st + b * z1 + hi*z);
|
||||||
|
pt(st + a * z2 + hi*(z+1));
|
||||||
|
pt(st + a * z2 + hi*(z+1));
|
||||||
|
pt(st + b * z1 + hi*z);
|
||||||
|
pt(st + b * z2 + hi*(z+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cgi.finishshape();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(1) {
|
||||||
|
cgi.bshape(shCastle, PPR::WALL);
|
||||||
|
shCastle.flags |= POLY_TRIANGLES;
|
||||||
|
|
||||||
|
for(int y=0; y<tY; y++)
|
||||||
|
for(int x=0; x<tX; x++) {
|
||||||
|
char bmch = map_tiles[y][x];
|
||||||
|
if(bmch == 'r') {
|
||||||
|
for(int s=0; s<4; s++) {
|
||||||
|
hyperpoint ctr = mappt(x+.5, y+.5, 1);
|
||||||
|
ctr[2] += safe_alt(ctr) + .5 * scale;
|
||||||
|
ld need = safe_alt(ctr, -1) / scale / scale;
|
||||||
|
int max_y = need * 2 + 1;
|
||||||
|
|
||||||
|
hyperpoint a = spin(90*degree*s) * point3(1, 0, 0);
|
||||||
|
hyperpoint b = spin(90*degree*s) * point3(0, 1, 0);
|
||||||
|
|
||||||
|
auto pt = [&] (ld af, ld bf, ld yf) {
|
||||||
|
hyperpoint ha = a * af * scale; ha[3] = 1;
|
||||||
|
hyperpoint hb = b * bf * scale; hb[3] = 1;
|
||||||
|
hyperpoint res = rgpushxto0(ctr) * rgpushxto0(ha) * rgpushxto0(hb) * point31(0, 0, yf * scale * scale);
|
||||||
|
cgi.hpcpush(res);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ptf = [&] (ld af, ld bf, ld yf) {
|
||||||
|
pt(af, bf, yf);
|
||||||
|
castle_tinf.tvertices.push_back(glhr::makevertex(bf, yf*4, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ptc = [&] (ld af, ld bf, ld yf, ld xt, ld yt) {
|
||||||
|
pt(af, bf, yf);
|
||||||
|
castle_tinf.tvertices.push_back(glhr::makevertex(xt, yt, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int w=0; w<2; w++)
|
||||||
|
for(int as=0; as<8; as++)
|
||||||
|
for(int y=0; y<max_y; y++) {
|
||||||
|
ld xf = w ? .4 : .5;
|
||||||
|
ld y1 = -y/2.;
|
||||||
|
ld y2 = -(y+1)/2.;
|
||||||
|
ld asd = (as-4) / 8.;
|
||||||
|
ld asd1 = (as-3) / 8.;
|
||||||
|
auto oasd = asd / 4;
|
||||||
|
if(w) asd *= .8, asd1 *= .8, oasd *= .8 * .8;
|
||||||
|
ptf(xf, asd, y1 - oasd);
|
||||||
|
ptf(xf, asd1, y1 - oasd);
|
||||||
|
ptf(xf, asd, y2 - oasd);
|
||||||
|
ptf(xf, asd, y2 - oasd);
|
||||||
|
ptf(xf, asd1, y1 - oasd);
|
||||||
|
ptf(xf, asd1, y2 - oasd);
|
||||||
|
}
|
||||||
|
|
||||||
|
ld x1 = 1/32.;
|
||||||
|
ld x2 = 1/4. + x1;
|
||||||
|
ld y1 = 1/32.;
|
||||||
|
ld y2 = 1/8. + x1;
|
||||||
|
|
||||||
|
for(int as=0; as<8; as++) {
|
||||||
|
ld asd = (as-4) / 8.;
|
||||||
|
ld asd1 = (as-3) / 8.;
|
||||||
|
ld asdw = asd * .8;
|
||||||
|
ld asdw1 = asd1 * .8;
|
||||||
|
ld asd2 = (as-5) / 8.;
|
||||||
|
//ld asdw2 = asd2 * .8;
|
||||||
|
ld oasd = asd / 4;
|
||||||
|
ld oasdw = oasd * .8 * .8;
|
||||||
|
ld oasd2 = asd2 / 4;
|
||||||
|
ld oasdw2 = oasd2 * .8 * .8;
|
||||||
|
/* tops */
|
||||||
|
ptc(.5, asd, -oasd, x1, y1);
|
||||||
|
ptc(.5, asd1, - oasd, x1, y2);
|
||||||
|
ptc(.4, asdw, -oasdw, x2, y1);
|
||||||
|
ptc(.4, asdw, -oasdw, x2, y1);
|
||||||
|
ptc(.5, asd1, - oasd, x1, y2);
|
||||||
|
ptc(.4, asdw1, -oasdw, x2, y2);
|
||||||
|
/* sides */
|
||||||
|
ptc(.5, asd, -oasd, x1, y1);
|
||||||
|
ptc(.5, asd, -oasd2, x1, y2);
|
||||||
|
ptc(.4, asdw, -oasdw, x2, y1);
|
||||||
|
ptc(.4, asdw, -oasdw, x2, y1);
|
||||||
|
ptc(.5, asd, -oasd2, x1, y2);
|
||||||
|
ptc(.4, asdw, -oasdw2, x2, y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bmch == 'o') {
|
||||||
|
hyperpoint h = mappt(x+.5, y+.5, 1);
|
||||||
|
h[2] += safe_alt(h) + 1;
|
||||||
|
statues.emplace_back(statue{rgpushxto0(h), &shBall, 0xFFFFFFFF});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bmch == 'x') {
|
||||||
|
hyperpoint h = mappt(x+.5, y+.5, 1);
|
||||||
|
statues.emplace_back(statue{rgpushxto0(h), &shGeostatue, 0xFFFFFFFF});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cgi.finishshape();
|
||||||
|
// println(hlog, shFloor[i].s, " to ", shFloor[i].e);
|
||||||
|
}
|
||||||
|
|
||||||
|
cgi.extra_vertices();
|
||||||
|
init_plan();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert ASCII map coordinates to Heisenberg coordinates */
|
||||||
|
hyperpoint level::mappt(ld x, ld y, int s) {
|
||||||
|
int tY = isize(map_tiles);
|
||||||
|
int tX = isize(map_tiles[0]);
|
||||||
|
x /= s;
|
||||||
|
y /= s;
|
||||||
|
hyperpoint h;
|
||||||
|
h[0] = lerp(minx, maxx, x / tX);
|
||||||
|
h[1] = lerp(miny, maxy, y / tY);
|
||||||
|
if(flags & nrlPolar)
|
||||||
|
tie(h[0], h[1]) = make_pair(h[1] * sin(h[0]), h[1] * cos(h[0]));
|
||||||
|
h[2] = surface(h);
|
||||||
|
h[3] = 1;
|
||||||
|
return h;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
plan.emplace_back(start.where, hpxy(0, 1));
|
||||||
|
plan.emplace_back(mappt(4.5, 10.5), hpxy(1, 1));
|
||||||
|
plan.emplace_back(mappt(0.01, 3, 1), hpxy(0, -2));
|
||||||
|
plan.emplace_back(mappt(2, 3.99, 1), hpxy(4, 0));
|
||||||
|
plan.emplace_back(mappt(42, 3.99, 1), hpxy(4, 0));
|
||||||
|
*/
|
||||||
|
|
||||||
|
void level::init_plan() {
|
||||||
|
plan.emplace_back(start.where, hpxy(0, -1));
|
||||||
|
plan.emplace_back(mappt(6.8, 10.2, 1), hpxy(1.5, -1.5));
|
||||||
|
plan.emplace_back(mappt(10.5, 10.5, 1), hpxy(1.5, 1.5));
|
||||||
|
plan.emplace_back(mappt(10.5, 4.5, 1), hpxy(-1.5, 1.5));
|
||||||
|
plan.emplace_back(mappt(4.5, 4.5, 1), hpxy(-1.5, 1.5));
|
||||||
|
plan.emplace_back(mappt(4.5, 2, 1), hpxy(1.5, 0.5));
|
||||||
|
plan.emplace_back(mappt(10.5, 2, 1), hpxy(1.5, -0.5));
|
||||||
|
plan.emplace_back(mappt(10.5, 4.5, 1), hpxy(-2, 0));
|
||||||
|
plan.emplace_back(mappt(6.5, 6.5, 1), hpxy(-1.5, -1.5));
|
||||||
|
plan.emplace_back(mappt(4.5, 10.5, 1), hpxy(1.5, -1.5));
|
||||||
|
plan.emplace_back(mappt(10.5, 9.5, 1), hpxy(1.5, 1.5));
|
||||||
|
/* plan.emplace_back(mappt(0.01, 3, 1), hpxy(0, -2));
|
||||||
|
plan.emplace_back(mappt(2, 3.99, 1), hpxy(4, 0));
|
||||||
|
plan.emplace_back(mappt(42, 3.99, 1), hpxy(4, 0));
|
||||||
|
*/
|
||||||
|
current = start;
|
||||||
|
timer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ld level::safe_alt(hyperpoint h, ld mul) {
|
||||||
|
ld maxv = 0;
|
||||||
|
for(int x: {-1, 0, 1})
|
||||||
|
for(int y: {-1, 0, 1}) {
|
||||||
|
hyperpoint c = sym_to_heis(point31(x*.5*scale, y*.5*scale, 0));
|
||||||
|
hyperpoint j = rgpushxto0(h) * c;
|
||||||
|
maxv = max(maxv, mul * (surface(j) - j[2]));
|
||||||
|
}
|
||||||
|
return maxv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void level::draw_level(const shiftmatrix& V) {
|
||||||
|
if(false) for(int i=0; i<6; i++) {
|
||||||
|
auto &poly = queuepoly(V * rgpushxto0(start.where) * cpush(2, 0.3 + 0.3 * sin(ticks / 500.)), shMini[i], 0xFFFF00FF);
|
||||||
|
poly.tinf = &floor_texture_vertices[cgi.shFloor.id];
|
||||||
|
ensure_vertex_number(*poly.tinf, poly.cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(true) {
|
||||||
|
auto& poly = queuepoly(V, shCastle, 0xC02020FF);
|
||||||
|
poly.tinf = &castle_tinf;
|
||||||
|
castle_tinf.texture_id = castle_texture->textureid;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto st: statues) queuepoly(V * st.T, *st.shape, st.color);
|
||||||
|
|
||||||
|
queuepoly(V, shField, 0xFFFF00FF);
|
||||||
|
|
||||||
|
auto& poly = queuepoly(V, shFloor, 0xFFFFFFFF); // 0xFFFFFFFF);
|
||||||
|
poly.tinf = &uniltinf;
|
||||||
|
uniltinf.texture_id = unil_texture->textureid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
430
rogueviz/nilrider/levels.cpp
Normal file
430
rogueviz/nilrider/levels.cpp
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
ld f_heisenberg0(hyperpoint h) { return 0; }
|
||||||
|
|
||||||
|
ld rot_plane(hyperpoint h) {
|
||||||
|
return h[0] * h[1] / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ld f_rot_well(hyperpoint h) {
|
||||||
|
return h[0] * h[1] / 2 + h[0] * h[0] + h[1] * h[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
ld long_x(hyperpoint h) {
|
||||||
|
return h[0] * h[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
ld geodesics_0(hyperpoint h) {
|
||||||
|
ld r = hypot_d(2, h);
|
||||||
|
ld phi = atan2(h[1], h[0]);
|
||||||
|
|
||||||
|
ld z = (phi / 2 / M_PI) * (M_PI * r * r + 2 * M_PI);
|
||||||
|
return z + rot_plane(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
ld geodesics_at_4(hyperpoint h) {
|
||||||
|
ld r = 4;
|
||||||
|
ld phi = atan2(h[1], h[0]);
|
||||||
|
|
||||||
|
ld z = (phi / 2 / M_PI) * (M_PI * r * r + 2 * M_PI);
|
||||||
|
return z + rot_plane(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
map<char, color_t> bcols = {
|
||||||
|
{' ', 0xFF101010},
|
||||||
|
{'W', 0xFFFFFFFF},
|
||||||
|
{'g', 0xFF008000},
|
||||||
|
{'h', 0xFF20A020},
|
||||||
|
{'r', 0xFFFF4040},
|
||||||
|
{'u', 0xFF4040FF},
|
||||||
|
{'b', 0xFF804000},
|
||||||
|
{'l', 0xFF0000C0},
|
||||||
|
{'f', 0xFF603000},
|
||||||
|
{'F', 0xFF804000},
|
||||||
|
{'2', 0xFF404040},
|
||||||
|
{'4', 0xFF808080},
|
||||||
|
{'6', 0xFFC0C0C0},
|
||||||
|
};
|
||||||
|
|
||||||
|
map<char, array<string, 16> > submaps = {
|
||||||
|
{'o', {
|
||||||
|
"WWWWWWWWWWWWWWWW",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222666622222W",
|
||||||
|
"W22266222266222W",
|
||||||
|
"W22622222222622W",
|
||||||
|
"W22622222222622W",
|
||||||
|
"W26222222222262W",
|
||||||
|
"W262222WW222262W",
|
||||||
|
"W262222WW222262W",
|
||||||
|
"W26222222222262W",
|
||||||
|
"W22622222222622W",
|
||||||
|
"W22622222222622W",
|
||||||
|
"W22266222266222W",
|
||||||
|
"W22222666622222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"WWWWWWWWWWWWWWWW"
|
||||||
|
}},
|
||||||
|
{'x', {
|
||||||
|
"WWWWWWWWWWWWWWWW",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222622622222W",
|
||||||
|
"W222222rW222222W",
|
||||||
|
"W222222Wr222222W",
|
||||||
|
"W22222622622222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"W22222222222222W",
|
||||||
|
"WWWWWWWWWWWWWWWW"
|
||||||
|
}},
|
||||||
|
{'b', {
|
||||||
|
" ",
|
||||||
|
" rrr rrr rrr rrr",
|
||||||
|
" ",
|
||||||
|
"rr rrr rrr rrr r",
|
||||||
|
" ",
|
||||||
|
" rrr rrr rrr rrr",
|
||||||
|
" ",
|
||||||
|
"rr rrr rrr rrr r",
|
||||||
|
" ",
|
||||||
|
" rrr rrr rrr rrr",
|
||||||
|
" ",
|
||||||
|
"rr rrr rrr rrr r",
|
||||||
|
" ",
|
||||||
|
" rrr rrr rrr rrr",
|
||||||
|
" ",
|
||||||
|
"rr rrr rrr rrr r",
|
||||||
|
}},
|
||||||
|
{'f', {
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
"FfFfFfFfFfFfFfFf",
|
||||||
|
"fFfFfFfFfFfFfFfF",
|
||||||
|
}},
|
||||||
|
{'l', {
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
"llllllllllllllll",
|
||||||
|
}},
|
||||||
|
{'g', {
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
}},
|
||||||
|
{'G', {
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghWhghg",
|
||||||
|
"ghghrhghghWlWhgh",
|
||||||
|
"hghrWrhghghWhghg",
|
||||||
|
"ghghrhghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghlhghghghg",
|
||||||
|
"ghghghlWlhghghgh",
|
||||||
|
"hghghghlhghghghg",
|
||||||
|
"ghghghghghghgrgh",
|
||||||
|
"hghglghghghgrWrg",
|
||||||
|
"ghglWlghghghgrgh",
|
||||||
|
"hghglghghghghghg",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
}},
|
||||||
|
{'r', {
|
||||||
|
"rrrrrrrrrrrrrrru",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"ubbbbbbbbbbbbbbu",
|
||||||
|
"urrrrrrrrrrrrrrr",
|
||||||
|
}},
|
||||||
|
{'*', {
|
||||||
|
"WWWWWW WW WWWWWW",
|
||||||
|
"W W",
|
||||||
|
"W W",
|
||||||
|
"W W",
|
||||||
|
"W W",
|
||||||
|
"W rr W",
|
||||||
|
" rr ",
|
||||||
|
"W r r W",
|
||||||
|
"W r r W",
|
||||||
|
" r r ",
|
||||||
|
"W r r W",
|
||||||
|
"W rrrrrrrr W",
|
||||||
|
"W W",
|
||||||
|
"W W",
|
||||||
|
"W W",
|
||||||
|
"WWWWWW WW WWWWWW",
|
||||||
|
}},
|
||||||
|
{'+', {
|
||||||
|
"gh WW gh",
|
||||||
|
"hg WW hg",
|
||||||
|
" WW ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" WW ",
|
||||||
|
" WW ",
|
||||||
|
"WWW WWWWWW WWW",
|
||||||
|
"WWW WWWWWW WWW",
|
||||||
|
" WW ",
|
||||||
|
" WW ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" WW ",
|
||||||
|
"gh WW gh",
|
||||||
|
"hg WW hg",
|
||||||
|
}},
|
||||||
|
{'-', {
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"WWW WWWWWW WWW",
|
||||||
|
"WWW WWWWWW WWW",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"ghghghghghghghgh",
|
||||||
|
"hghghghghghghghg",
|
||||||
|
}},
|
||||||
|
{'|', {
|
||||||
|
"gh WW gh",
|
||||||
|
"hg WW hg",
|
||||||
|
"gh WW gh",
|
||||||
|
"hg hg",
|
||||||
|
"gh gh",
|
||||||
|
"hg WW hg",
|
||||||
|
"gh WW gh",
|
||||||
|
"hg WW hg",
|
||||||
|
"gh WW gh",
|
||||||
|
"hg WW hg",
|
||||||
|
"gh WW gh",
|
||||||
|
"hg hg",
|
||||||
|
"gh gh",
|
||||||
|
"hg WW hg",
|
||||||
|
"gh WW gh",
|
||||||
|
"hg WW hg",
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
|
||||||
|
level rotplane(
|
||||||
|
"Trying to be horizontal", 'r', 0,
|
||||||
|
"All the lines going through the center are horizontal.",
|
||||||
|
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.5*dft_block,
|
||||||
|
{
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"ggggggfffgggggg!",
|
||||||
|
"ggggggfffgggggg!",
|
||||||
|
"gggg|ggggg|gggg!",
|
||||||
|
"ggg-+-----+-ggg!",
|
||||||
|
"gggg|ggggf|gggg!",
|
||||||
|
"ggGg|g+ggg|grgG!",
|
||||||
|
"gGgg|g|xgo|gggg!",
|
||||||
|
"ggGg|g|ggg|grgg!",
|
||||||
|
"gggg|g|ggg|gggg!",
|
||||||
|
"gg--+-+---+--gg!",
|
||||||
|
"gggg|ggggg|gggg!",
|
||||||
|
"gggggggGGgggggg!",
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"!!!!!!!!!!!!!!!!"
|
||||||
|
},
|
||||||
|
6, 6,
|
||||||
|
rot_plane
|
||||||
|
);
|
||||||
|
|
||||||
|
level longtrack(
|
||||||
|
"A Long Track", 'l', 0,
|
||||||
|
"The main street is horizontal, as well as the lines orthogonal to it.",
|
||||||
|
0*dft_block, +2.5*dft_block, 64*dft_block, -1.5*dft_block,
|
||||||
|
{
|
||||||
|
"gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg",
|
||||||
|
"gggggggrgggggggrggggggggrGggggggggGGggggGGGgggggGGGGggggggggggGG",
|
||||||
|
"g+------------------------------------------------------------+G",
|
||||||
|
"gggggfffffggggggggggggggggggggggggggggggggggggggggggggggggggggGG"
|
||||||
|
},
|
||||||
|
0, 1,
|
||||||
|
long_x
|
||||||
|
);
|
||||||
|
|
||||||
|
level geodesical(
|
||||||
|
"Roads are Geodesics", 'g', nrlPolar,
|
||||||
|
"All the roads here are helical geodesics.",
|
||||||
|
-45*degree, 3*dft_block, 225*degree, 0,
|
||||||
|
// -8*dft_block, +8*dft_block, +8*dft_block, 0,
|
||||||
|
{
|
||||||
|
"ffffffffffffffff",
|
||||||
|
"----------------",
|
||||||
|
"----------------",
|
||||||
|
"----------------",
|
||||||
|
"----------------",
|
||||||
|
"----------------",
|
||||||
|
"----------------",
|
||||||
|
"bbbbbbbbbbbbbbbb",
|
||||||
|
},
|
||||||
|
0, 6,
|
||||||
|
geodesics_0
|
||||||
|
);
|
||||||
|
|
||||||
|
level geodesical4(
|
||||||
|
"Helical Geodesic", 's', nrlPolar,
|
||||||
|
"The main road here is a helical geodesic. Orthogonal lines are horizontal.",
|
||||||
|
-80*degree, 8.5*dft_block, 260*degree, 0.5*dft_block,
|
||||||
|
// -8*dft_block, +8*dft_block, +8*dft_block, 0,
|
||||||
|
{
|
||||||
|
"!!!!!!!!!!!!!!!!",
|
||||||
|
"ffffffffffffffff",
|
||||||
|
"gggggggggggggggg",
|
||||||
|
"ggGggggggggGgggg",
|
||||||
|
"+--------------+",
|
||||||
|
"gggggGggggGggggg",
|
||||||
|
"gggGgggggGgggggg",
|
||||||
|
"ffffffffffffffff",
|
||||||
|
},
|
||||||
|
0, 5,
|
||||||
|
geodesics_at_4
|
||||||
|
);
|
||||||
|
|
||||||
|
level heisenberg0(
|
||||||
|
"Heisenberg Zero", 'z', 0,
|
||||||
|
"This is the plane z=0 in the Heisenberg group model of Nil. The roads are x=0, y=0 axes.",
|
||||||
|
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.5*dft_block,
|
||||||
|
{
|
||||||
|
"ggggggg|ggggggg!",
|
||||||
|
"grggggg|gggggrg!",
|
||||||
|
"ggggggg|ggggggg!",
|
||||||
|
"gggffgg|ggggggg!",
|
||||||
|
"gggffgg|ggfrggg!",
|
||||||
|
"ggggggg|gggggGg!",
|
||||||
|
"ggggggg|ggggggg!",
|
||||||
|
"-------+-------!",
|
||||||
|
"ggggggg|ggggggg!",
|
||||||
|
"gggGgog|ggggggg!",
|
||||||
|
"ggggggg|ggrgrgg!",
|
||||||
|
"gggGgGg|ggggggg!",
|
||||||
|
"ggggggg|ggggggg!",
|
||||||
|
"grggggg|gggggrg!",
|
||||||
|
"ggggggg|ggggggg!",
|
||||||
|
"!!!!!!!!!!!!!!!!"
|
||||||
|
},
|
||||||
|
8, 8,
|
||||||
|
f_heisenberg0
|
||||||
|
);
|
||||||
|
|
||||||
|
level rotwell(
|
||||||
|
"Deep Well", 'd', 0,
|
||||||
|
"Can you escape this well?",
|
||||||
|
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.5*dft_block,
|
||||||
|
{
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"gogggggggggggog!",
|
||||||
|
"ggggg--*--ggggg!",
|
||||||
|
"gggg*ggggg*gggg!",
|
||||||
|
"ggg*ggGfGgg*ggg!",
|
||||||
|
"gg|ggfgggfgg|gg!",
|
||||||
|
"gg|gGgggggGg|gg!",
|
||||||
|
"gg*gfggxggfg*gg!",
|
||||||
|
"gg|gGgggggGg|gg!",
|
||||||
|
"gg|ggfgggfgg|gg!",
|
||||||
|
"ggg*ggGfGgg*ggg!",
|
||||||
|
"gggg*ggggg*gggg!",
|
||||||
|
"ggggg--*--ggggg!",
|
||||||
|
"gogggggggggggog!",
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"!!!!!!!!!!!!!!!!"
|
||||||
|
},
|
||||||
|
8, 8,
|
||||||
|
f_rot_well
|
||||||
|
);
|
||||||
|
|
||||||
|
level labyrinth(
|
||||||
|
"Labyrinth", 'l', 0,
|
||||||
|
"Go clockwise. The squares of this level have half of their usual length.",
|
||||||
|
-7.5*dft_block/2, 7.5*dft_block/2, 8.5*dft_block/2, -8.5*dft_block/2,
|
||||||
|
{
|
||||||
|
"ogggrfffffffffo!",
|
||||||
|
"g*ggrgggggggggg!",
|
||||||
|
"ggggrgggggggggg!",
|
||||||
|
"ggggrgggggggggg!",
|
||||||
|
"ggggrgggrrggggg!",
|
||||||
|
"ggggrgGGGrrgggg!",
|
||||||
|
"ggggrGgggGrgggg!",
|
||||||
|
"ggggrGgxgGrgggg!",
|
||||||
|
"ggggrGgggGrgggg!",
|
||||||
|
"ggggrrGGGrrgggg!",
|
||||||
|
"gggggrrrrrggggg!",
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"ggggggggggggggg!",
|
||||||
|
"offfffffffffffo!",
|
||||||
|
"!!!!!!!!!!!!!!!!"
|
||||||
|
},
|
||||||
|
8, 8,
|
||||||
|
rot_plane
|
||||||
|
);
|
||||||
|
|
||||||
|
level *curlev = &rotplane;
|
||||||
|
|
||||||
|
vector<level*> all_levels = {
|
||||||
|
&rotplane, &longtrack, &geodesical, &geodesical4, &heisenberg0, &rotwell, &labyrinth
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
290
rogueviz/nilrider/nilrider.cpp
Normal file
290
rogueviz/nilrider/nilrider.cpp
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
#include "nilrider.h"
|
||||||
|
#include "statues.cpp"
|
||||||
|
#include "timestamp.cpp"
|
||||||
|
#include "levels.cpp"
|
||||||
|
#include "level.cpp"
|
||||||
|
#include "planning.cpp"
|
||||||
|
|
||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
/** is the game paused? */
|
||||||
|
bool paused = false;
|
||||||
|
|
||||||
|
bool planning_mode = false;
|
||||||
|
bool view_simulation = false;
|
||||||
|
int simulation_start_tick;
|
||||||
|
|
||||||
|
void frame() {
|
||||||
|
if(planning_mode && !view_simulation) return;
|
||||||
|
|
||||||
|
shiftmatrix V = ggmatrix(cwt.at);
|
||||||
|
|
||||||
|
curlev->draw_level(V);
|
||||||
|
|
||||||
|
curlev->current.draw_unilcycle(V);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool turn(int delta) {
|
||||||
|
if(planning_mode && !view_simulation) return false;
|
||||||
|
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||||
|
if(keystate[SDLK_RIGHT] && !paused) curlev->current.heading_angle -= delta / 1000.;
|
||||||
|
if(keystate[SDLK_LEFT] && !paused) curlev->current.heading_angle += delta / 1000.;
|
||||||
|
|
||||||
|
if(keystate[SDLK_UP] && !paused) min_gfx_slope -= delta / 1000.;
|
||||||
|
if(keystate[SDLK_DOWN] && !paused) min_gfx_slope += delta / 1000.;
|
||||||
|
|
||||||
|
curlev->current.heading_angle += mouseaim_x;
|
||||||
|
min_gfx_slope += mouseaim_y;
|
||||||
|
|
||||||
|
#if CAP_VR
|
||||||
|
if(vrhr::active()) {
|
||||||
|
curlev->current.heading_angle += vrhr::vraim_x * delta / 400;
|
||||||
|
min_gfx_slope -= vrhr::vraim_y * delta / 400;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(min_gfx_slope < -90*degree) min_gfx_slope = -90*degree;
|
||||||
|
if(min_gfx_slope > +90*degree) min_gfx_slope = +90*degree;
|
||||||
|
|
||||||
|
if(!paused && !view_simulation) for(int i=0; i<delta; i++) {
|
||||||
|
curlev->history.push_back(curlev->current);
|
||||||
|
bool b = curlev->current.tick(curlev);
|
||||||
|
if(b) timer += 1. / tps;
|
||||||
|
else curlev->history.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!paused) curlev->current.centerview(curlev);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_menu();
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
cmode = sm::MAP;
|
||||||
|
clearMessages();
|
||||||
|
dialog::init();
|
||||||
|
if(view_simulation && !paused) {
|
||||||
|
int ttick = gmod(ticks - simulation_start_tick, isize(curlev->history));
|
||||||
|
timer = ttick * 1. / tps;
|
||||||
|
curlev->current = curlev->history[ttick];
|
||||||
|
curlev->current.centerview(curlev);
|
||||||
|
}
|
||||||
|
gamescreen(0);
|
||||||
|
if(planning_mode && !view_simulation) {
|
||||||
|
curlev->draw_planning_screen();
|
||||||
|
if(!holdmouse) {
|
||||||
|
auto t0 = SDL_GetTicks();
|
||||||
|
while(SDL_GetTicks() < t0 + 100) {
|
||||||
|
if(!curlev->simulate()) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curlev->current.draw_instruments(timer);
|
||||||
|
|
||||||
|
if(paused && !planning_mode) {
|
||||||
|
displayButton(current_display->xcenter, current_display->ycenter, mousing ? XLAT("paused -- click to unpause") : XLAT("paused -- press p to continue"), 'p', 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = vid.fsize;
|
||||||
|
auto show_button = [&] (char c, string s, color_t col = dialog::dialogcolor) {
|
||||||
|
if(displayButtonS(x, vid.yres - vid.fsize, s, col, 0, vid.fsize))
|
||||||
|
getcstat = c;
|
||||||
|
x += textwidth(vid.fsize, s) + vid.fsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
if(planning_mode && !view_simulation) {
|
||||||
|
for(auto& b: buttons) show_button(b.first, b.second, planmode == b.first ? 0xFFD500 : dialog::dialogcolor);
|
||||||
|
show_button('s', "simulation");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(planning_mode && view_simulation) {
|
||||||
|
show_button('s', "return");
|
||||||
|
show_button('p', "pause", paused ? 0xFF0000 : dialog::dialogcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!planning_mode) {
|
||||||
|
show_button('p', "pause", paused ? 0xFF0000 : dialog::dialogcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_button('v', "menu");
|
||||||
|
|
||||||
|
dialog::add_key_action('v', [] {
|
||||||
|
paused = true;
|
||||||
|
pushScreen(main_menu);
|
||||||
|
});
|
||||||
|
dialog::add_key_action('p', [] {
|
||||||
|
paused = !paused;
|
||||||
|
if(view_simulation && !paused)
|
||||||
|
simulation_start_tick = ticks - timer * tps;
|
||||||
|
});
|
||||||
|
dialog::add_key_action('-', [] {
|
||||||
|
paused = false;
|
||||||
|
});
|
||||||
|
dialog::add_key_action('b', [] {
|
||||||
|
if(planning_mode)
|
||||||
|
simulation_start_tick += 500;
|
||||||
|
else {
|
||||||
|
for(int i=0; i<500; i++) if(!curlev->history.empty()) curlev->history.pop_back();
|
||||||
|
curlev->current = curlev->history.back();
|
||||||
|
timer = isize(curlev->history) * 1. / tps;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(planning_mode) dialog::add_key_action('s', [] {
|
||||||
|
view_simulation = !view_simulation;
|
||||||
|
paused = false;
|
||||||
|
simulation_start_tick = ticks;
|
||||||
|
});
|
||||||
|
dialog::display();
|
||||||
|
|
||||||
|
keyhandler = [] (int sym, int uni) {
|
||||||
|
if(paused) handlePanning(sym, uni);
|
||||||
|
if(planning_mode && !view_simulation && curlev->handle_planning(sym, uni)) return;
|
||||||
|
dialog::handleNavigation(sym, uni);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int speedlimit = 0;
|
||||||
|
vector<string> speedlimit_names = {"none", "yellow", "green", "full"};
|
||||||
|
|
||||||
|
void pick_level() {
|
||||||
|
clearMessages();
|
||||||
|
dialog::init(XLAT("select the track"), 0xC0C0FFFF, 150, 100);
|
||||||
|
for(auto l: all_levels) {
|
||||||
|
dialog::addItem(l->name, l->hotkey);
|
||||||
|
dialog::add_action([l] {
|
||||||
|
curlev = l;
|
||||||
|
recompute_plan_transform = true;
|
||||||
|
l->init();
|
||||||
|
popScreen();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dialog::addBreak(100);
|
||||||
|
dialog::addBack();
|
||||||
|
dialog::display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pick_game() {
|
||||||
|
clearMessages();
|
||||||
|
dialog::init(XLAT("how do you want to play?"), 0xC0C0FFFF, 150, 100);
|
||||||
|
dialog::addSelItem("selected track", curlev->name, 't');
|
||||||
|
dialog::add_action_push(pick_level);
|
||||||
|
dialog::addInfo(curlev->longdesc);
|
||||||
|
dialog::addBreak(100);
|
||||||
|
add_edit(speedlimit);
|
||||||
|
add_edit(planning_mode);
|
||||||
|
dialog::addBreak(100);
|
||||||
|
dialog::addBack();
|
||||||
|
dialog::display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void settings() {
|
||||||
|
dialog::init(XLAT("settings"), 0xC0C0FFFF, 150, 100);
|
||||||
|
dialog::addItem("RogueViz settings", 'r');
|
||||||
|
dialog::add_key_action('r', [] {
|
||||||
|
pushScreen(showSettings);
|
||||||
|
});
|
||||||
|
dialog::addBreak(100);
|
||||||
|
dialog::display();
|
||||||
|
dialog::addBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction_t on_quit = [] { exit(0); };
|
||||||
|
|
||||||
|
void main_menu() {
|
||||||
|
clearMessages();
|
||||||
|
dialog::init(XLAT("Nil Rider"), 0xC0C0FFFF, 150, 100);
|
||||||
|
|
||||||
|
dialog::addItem("continue", 'c');
|
||||||
|
dialog::add_action(popScreen);
|
||||||
|
|
||||||
|
if(!planning_mode) {
|
||||||
|
dialog::addItem("restart", 'r');
|
||||||
|
dialog::add_action([] {
|
||||||
|
curlev->current = curlev->start;
|
||||||
|
timer = 0;
|
||||||
|
paused = false;
|
||||||
|
popScreen();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog::addItem("view the replay", 'v');
|
||||||
|
dialog::add_action([] {
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog::addItem("save the replay", 'e');
|
||||||
|
dialog::add_action([] {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dialog::addItem("save this plan", 's');
|
||||||
|
dialog::add_action([] {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog::addItem("change track or game settings", 't');
|
||||||
|
dialog::add_action_push(pick_game);
|
||||||
|
|
||||||
|
dialog::addItem("change other settings", 'o');
|
||||||
|
dialog::add_action_push(settings);
|
||||||
|
|
||||||
|
dialog::addItem("quit", 'q');
|
||||||
|
dialog::add_action([] {
|
||||||
|
on_quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog::display();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool on;
|
||||||
|
|
||||||
|
void initialize() {
|
||||||
|
|
||||||
|
check_cgi();
|
||||||
|
cgi.prepare_shapes();
|
||||||
|
|
||||||
|
init_statues();
|
||||||
|
|
||||||
|
curlev->init();
|
||||||
|
|
||||||
|
param_enum(planning_mode, "nil_planning", "nil_planning", false)
|
||||||
|
-> editable({{"manual", "control the unicycle manually"}, {"planning", "try to plan the optimal route!"}}, "game mode", 'p');
|
||||||
|
|
||||||
|
param_enum(speedlimit, "nil_speedlimit", "nil_speedlimit", 0)
|
||||||
|
-> editable({
|
||||||
|
{"no limit", "reach the goals as fast as you wan"},
|
||||||
|
{"yellow", "your speed must be in the yellow zone to collect"},
|
||||||
|
{"green", "your speed must be in the green zone to collect"},
|
||||||
|
{"full", "you must fully stop to collect"}
|
||||||
|
}, "speed limit", 's');
|
||||||
|
|
||||||
|
rv_hook(hooks_frame, 100, frame);
|
||||||
|
rv_hook(shmup::hooks_turn, 100, turn);
|
||||||
|
on = true;
|
||||||
|
on_cleanup_or_next([] { on = false; });
|
||||||
|
pushScreen(run);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto celldemo = arg::add3("-unilcycle", initialize) + arg::add3("-unilplan", [] { planning_mode = true; }) + arg::add3("-viewsim", [] { view_simulation = true; })
|
||||||
|
+ arg::add3("-oqc", [] { on_quit = popScreenAll; })
|
||||||
|
+ arg::add3("-fullsim", [] {
|
||||||
|
/* for animations */
|
||||||
|
popScreenAll();
|
||||||
|
rv_hook(anims::hooks_anim, 100, [] {
|
||||||
|
int ttick = ticks % isize(curlev->history);
|
||||||
|
timer = ttick * 1. / tps;
|
||||||
|
curlev->current = curlev->history[ttick];
|
||||||
|
curlev->current.centerview(curlev);
|
||||||
|
anims::moved();
|
||||||
|
});
|
||||||
|
}) + arg::add3("-unillevel", [] {
|
||||||
|
arg::shift();
|
||||||
|
for(auto l: all_levels) if(appears(l->name, arg::args())) curlev = l;
|
||||||
|
if(on) curlev->init();
|
||||||
|
})
|
||||||
|
+ arg::add3("-simplemodel", [] {
|
||||||
|
nisot::geodesic_movement = false;
|
||||||
|
pmodel = mdPerspective;
|
||||||
|
pconf.rotational_nil = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
130
rogueviz/nilrider/nilrider.h
Normal file
130
rogueviz/nilrider/nilrider.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "../rogueviz.h"
|
||||||
|
|
||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
using namespace rogueviz;
|
||||||
|
|
||||||
|
struct level;
|
||||||
|
|
||||||
|
struct timestamp {
|
||||||
|
hyperpoint where; /**< the current position of the unicycle */
|
||||||
|
ld heading_angle; /**< the current heading angle */
|
||||||
|
ld vel; /**< the current velocity in units per second */
|
||||||
|
ld circpos; /**< controls the wheel graphics */
|
||||||
|
ld slope; /**< the current slope */
|
||||||
|
ld t; /**< planning spline parameter */
|
||||||
|
bool tick(level*);/**< one tick of the simulation -- returns false if the unicycle has stopped or crashed */
|
||||||
|
void centerview(level*);
|
||||||
|
void draw_unilcycle(const shiftmatrix&);
|
||||||
|
void draw_instruments(ld t);
|
||||||
|
ld energy_in_squares();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct planpoint {
|
||||||
|
hyperpoint at;
|
||||||
|
hyperpoint vel;
|
||||||
|
planpoint(hyperpoint a, hyperpoint v): at(a), vel(v) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr flagtype nrlPolar = Flag(1);
|
||||||
|
|
||||||
|
struct statue {
|
||||||
|
transmatrix T;
|
||||||
|
hpcshape *shape;
|
||||||
|
color_t color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct level {
|
||||||
|
string name;
|
||||||
|
char hotkey;
|
||||||
|
string longdesc;
|
||||||
|
flagtype flags;
|
||||||
|
ld minx, miny, maxx, maxy;
|
||||||
|
vector<string> map_tiles;
|
||||||
|
ld startx, starty;
|
||||||
|
ld scale;
|
||||||
|
std::function<ld(hyperpoint h)> surface;
|
||||||
|
|
||||||
|
bool initialized;
|
||||||
|
|
||||||
|
level(string name, char hotkey, flagtype flags, string longdesc, ld minx, ld miny, ld maxx, ld maxy, const vector<string>& mt, ld sx, ld sy, const std::function<ld(hyperpoint h)>& surf) :
|
||||||
|
name(name), hotkey(hotkey), longdesc(longdesc), flags(flags), minx(minx), miny(miny), maxx(maxx), maxy(maxy), map_tiles(mt), startx(sx), starty(sy), surface(surf) { initialized = false; }
|
||||||
|
|
||||||
|
ld real_minx, real_miny, real_maxx, real_maxy;
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
hpcshape shFloor; /**< the 3D model of floor */
|
||||||
|
hpcshape shPlanFloor; /**< the 3D model of floor for planning */
|
||||||
|
hpcshape shField; /**< the 3D model of the 'field' */
|
||||||
|
hpcshape shCastle; /**< the 3D model of the 'castle' */
|
||||||
|
|
||||||
|
vector<statue> statues;
|
||||||
|
|
||||||
|
/** the texture data used for the ground */
|
||||||
|
texture::texture_data *unil_texture;
|
||||||
|
|
||||||
|
/** the texture used for the ground */
|
||||||
|
basic_textureinfo uniltinf;
|
||||||
|
|
||||||
|
/** the texture used for the ground */
|
||||||
|
basic_textureinfo castle_tinf;
|
||||||
|
|
||||||
|
/** starting timestamp */
|
||||||
|
timestamp start;
|
||||||
|
|
||||||
|
/** current timestamp */
|
||||||
|
timestamp current;
|
||||||
|
|
||||||
|
/** initialize textures and start */
|
||||||
|
void init();
|
||||||
|
|
||||||
|
vector<timestamp> history;
|
||||||
|
|
||||||
|
/** plan for the planning mode */
|
||||||
|
vector<planpoint> plan;
|
||||||
|
void init_plan();
|
||||||
|
bool simulate();
|
||||||
|
void draw_planning_screen();
|
||||||
|
void draw_level(const shiftmatrix& V);
|
||||||
|
shiftmatrix plan_transform;
|
||||||
|
|
||||||
|
hyperpoint get_spline(ld t);
|
||||||
|
hyperpoint mappt(ld x, ld y, int s);
|
||||||
|
ld safe_alt(hyperpoint h, ld mul = 1);
|
||||||
|
void compute_plan_transform();
|
||||||
|
bool handle_planning(int sym, int uni);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** ticks per second */
|
||||||
|
inline const ld tps = 1000;
|
||||||
|
|
||||||
|
/** wheel radius */
|
||||||
|
inline ld whrad = 0.05;
|
||||||
|
|
||||||
|
/** epsilon used to measure slope */
|
||||||
|
inline ld slope_eps = 0.01;
|
||||||
|
|
||||||
|
/** gravity acceleration constant, in units per second squared */
|
||||||
|
inline ld gravity = 1 / 16.;
|
||||||
|
|
||||||
|
/** the distance of camera from the wheel */
|
||||||
|
inline ld whdist = 0.5;
|
||||||
|
|
||||||
|
/** minimum slope for rendering */
|
||||||
|
inline ld min_gfx_slope = +M_PI/2;
|
||||||
|
|
||||||
|
/** current slope for rendering */
|
||||||
|
inline ld gfx_slope = 0;
|
||||||
|
|
||||||
|
/** the timer */
|
||||||
|
inline ld timer = 0;
|
||||||
|
|
||||||
|
/** default block unit */
|
||||||
|
inline double dft_block = 1;
|
||||||
|
|
||||||
|
extern map<char, color_t> bcols;
|
||||||
|
extern map<char, array<string, 16> > submaps;
|
||||||
|
|
||||||
|
hyperpoint sym_to_heis(hyperpoint H);
|
||||||
|
|
||||||
|
}
|
287
rogueviz/nilrider/planning.cpp
Normal file
287
rogueviz/nilrider/planning.cpp
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
hyperpoint get_spline(ld t);
|
||||||
|
|
||||||
|
bool level::simulate() {
|
||||||
|
if(history.empty())
|
||||||
|
history.push_back(start);
|
||||||
|
auto at = history.back();
|
||||||
|
|
||||||
|
if(at.t >= isize(plan) - 1.001) return false;
|
||||||
|
|
||||||
|
ld goal_t;
|
||||||
|
|
||||||
|
if(1) {
|
||||||
|
int steps = 20;
|
||||||
|
ld min_t, max_t;
|
||||||
|
|
||||||
|
if(isize(history) == 1) {
|
||||||
|
steps = 60;
|
||||||
|
min_t = at.t;
|
||||||
|
max_t = at.t + 0.5;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ld ldiff = history.back().t - history[history.size() - 2].t;
|
||||||
|
min_t = at.t;
|
||||||
|
max_t = min<ld>(at.t + ldiff + .1, isize(plan)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f = [&] (ld t) {
|
||||||
|
hyperpoint h = get_spline(t);
|
||||||
|
auto copy = at;
|
||||||
|
copy.heading_angle = atan2(h[1] - at.where[1], h[0] - at.where[0]);
|
||||||
|
copy.tick(this);
|
||||||
|
return sqhypot_d(2, copy.where-h);
|
||||||
|
};
|
||||||
|
|
||||||
|
string seq = "";
|
||||||
|
|
||||||
|
for(int i=0; i<steps; i++) {
|
||||||
|
ld t1 = min_t * .6 + max_t * .4;
|
||||||
|
ld t2 = min_t * .4 + max_t * .6;
|
||||||
|
auto e1 = f(t1);
|
||||||
|
auto e2 = f(t2);
|
||||||
|
if(e1 < e2) max_t = t2, seq += "B";
|
||||||
|
else min_t = t1, seq += "A";
|
||||||
|
}
|
||||||
|
|
||||||
|
goal_t = (min_t + max_t) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
hyperpoint h = get_spline(goal_t);
|
||||||
|
at.heading_angle = atan2(h[1] - at.where[1], h[0] - at.where[0]);
|
||||||
|
history.back() = at;
|
||||||
|
|
||||||
|
if(!at.tick(this)) return false;
|
||||||
|
at.t = goal_t;
|
||||||
|
history.push_back(at);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
hyperpoint level::get_spline(ld t) {
|
||||||
|
int i = t;
|
||||||
|
if(i == isize(plan) - 1) return plan.back().at;
|
||||||
|
ld tf = t - i;
|
||||||
|
return plan[i].at * (1-tf) * (1-tf) * (1+2*tf) + plan[i+1].at * (tf*tf * (3-2*tf)) + plan[i].vel * tf * (1-tf) * (1-tf) - plan[i+1].vel * tf * tf * (1-tf);
|
||||||
|
}
|
||||||
|
|
||||||
|
hyperpoint mousept;
|
||||||
|
ld box;
|
||||||
|
ld closest_t;
|
||||||
|
|
||||||
|
char planmode = 'p';
|
||||||
|
vector<pair<char, string> > buttons = {
|
||||||
|
{'p', "pan"}, {'a', "add"}, {'m', "move"}, {'i', "insert"}, {'d', "delete"}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool recompute_plan_transform = true;
|
||||||
|
|
||||||
|
void level::compute_plan_transform() {
|
||||||
|
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||||
|
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||||
|
dynamicval<bool> ga(vid.always3, false);
|
||||||
|
dynamicval<geometryinfo1> gi(ginf[gEuclid].g, giEuclid2);
|
||||||
|
auto& cd = current_display;
|
||||||
|
auto sId = shiftless(Id);
|
||||||
|
ld pix = 1 / (2 * cgi.hcrossf / cgi.crossf);
|
||||||
|
ld scale_x = (vid.xres - 2 * vid.fsize) / abs(real_maxx-real_minx);
|
||||||
|
ld scale_y = (vid.yres - 2 * vid.fsize) / abs(real_maxy-real_miny);
|
||||||
|
ld scale = min(scale_x, scale_y);
|
||||||
|
plan_transform = sId * atscreenpos(cd->xcenter, cd->ycenter, pix * scale) * eupush(-(real_minx+real_maxx)/2, (real_miny+real_maxy)/2) * MirrorY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void level::draw_planning_screen() {
|
||||||
|
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||||
|
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||||
|
dynamicval<bool> ga(vid.always3, false);
|
||||||
|
dynamicval<geometryinfo1> gi(ginf[gEuclid].g, giEuclid2);
|
||||||
|
initquickqueue();
|
||||||
|
|
||||||
|
if(recompute_plan_transform) {
|
||||||
|
compute_plan_transform();
|
||||||
|
recompute_plan_transform = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& T = plan_transform;
|
||||||
|
|
||||||
|
auto scr_to_map = [&] (hyperpoint h) {
|
||||||
|
transmatrix mousef = inverse(unshift(T)) * atscreenpos(h[0], h[1], 1);
|
||||||
|
h = mousef * C0;
|
||||||
|
h /= h[2];
|
||||||
|
return h;
|
||||||
|
};
|
||||||
|
|
||||||
|
mousept = scr_to_map(hpxy(mousex, mousey));
|
||||||
|
|
||||||
|
box = scr_to_map(hpxy(mousex + 5, mousey))[0] - mousept[0];
|
||||||
|
|
||||||
|
/* draw the map */
|
||||||
|
auto& p = queuepolyat(T, shPlanFloor, 0xFFFFFFFF, PPR::FLOOR);
|
||||||
|
p.tinf = &uniltinf;
|
||||||
|
uniltinf.texture_id = unil_texture->textureid;
|
||||||
|
|
||||||
|
auto draw_sq = [&] (hyperpoint h, color_t col, PPR prio) {
|
||||||
|
curvepoint(hpxy(h[0]+box, h[1]+box));
|
||||||
|
curvepoint(hpxy(h[0]+box, h[1]-box));
|
||||||
|
curvepoint(hpxy(h[0]-box, h[1]-box));
|
||||||
|
curvepoint(hpxy(h[0]-box, h[1]+box));
|
||||||
|
curvepoint(hpxy(h[0]+box, h[1]+box));
|
||||||
|
queuecurve(T, 0xFF, col, prio);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto draw_line = [&] (hyperpoint h1, hyperpoint h2, color_t col, PPR prio) {
|
||||||
|
curvepoint(hpxy(h1[0], h1[1]));
|
||||||
|
curvepoint(hpxy(h2[0], h2[1]));
|
||||||
|
queuecurve(T, col, 0, prio);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* draw the plan */
|
||||||
|
for(auto& pp: plan) {
|
||||||
|
draw_sq(pp.at - pp.vel, 0xFF8080FF, PPR::ITEM);
|
||||||
|
draw_sq(pp.at + pp.vel, 0x80FF80FF, PPR::ITEM);
|
||||||
|
draw_sq(pp.at, 0xFFFF00FF, PPR::ITEM);
|
||||||
|
draw_line(pp.at - pp.vel, pp.at + pp.vel, 0x80, PPR::BFLOOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool after = false;
|
||||||
|
|
||||||
|
if(history.empty()) history.push_back(start);
|
||||||
|
|
||||||
|
closest_t = history.back().t;
|
||||||
|
ld closest_dist = box * 2;
|
||||||
|
|
||||||
|
vid.linewidth *= 3;
|
||||||
|
int ps = isize(plan);
|
||||||
|
for(int t=0; t<=100*(ps-1); t++) {
|
||||||
|
ld tt = t / 100.;
|
||||||
|
if(tt > history.back().t && !after) {
|
||||||
|
queuecurve(T, 0xFFFFFFC0, 0, PPR::LIZEYE);
|
||||||
|
after = true;
|
||||||
|
}
|
||||||
|
hyperpoint h = get_spline(tt);
|
||||||
|
curvepoint(hpxy(h[0], h[1]));
|
||||||
|
ld dist = sqhypot_d(2, h - mousept);
|
||||||
|
if(dist < closest_dist) closest_dist = dist, closest_t = tt;
|
||||||
|
}
|
||||||
|
queuecurve(T, after ? 0xFF8080C0 : 0xFFFFFFC0, 0, PPR::LIZEYE);
|
||||||
|
vid.linewidth /= 3;
|
||||||
|
|
||||||
|
if(!history.empty()) {
|
||||||
|
int mint = 0, maxt = isize(history)-1;
|
||||||
|
while(mint < maxt) {
|
||||||
|
int t = (mint + maxt + 1) / 2;
|
||||||
|
if(history[t].t > closest_t) maxt = t-1;
|
||||||
|
else mint = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = history[mint];
|
||||||
|
timer = mint * 1. / tps;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_sq(get_spline(closest_t), 0x8080FFFF, PPR::ITEM);
|
||||||
|
draw_sq(current.where, 0xFF8000FF, PPR::ITEM);
|
||||||
|
draw_sq(mousept, 0x8080FFFF, PPR::ITEM);
|
||||||
|
|
||||||
|
quickqueue();
|
||||||
|
|
||||||
|
glflush();
|
||||||
|
getcstat = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
hyperpoint mousept_drag;
|
||||||
|
|
||||||
|
int move_id = -1, move_dir = 0;
|
||||||
|
|
||||||
|
bool level::handle_planning(int sym, int uni) {
|
||||||
|
if(sym == PSEUDOKEY_WHEELUP || sym == SDLK_PAGEUP) {
|
||||||
|
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||||
|
plan_transform.T = atscreenpos(mousex, mousey, 1.2) * inverse(atscreenpos(mousex, mousey, 1)) * plan_transform.T;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(sym == PSEUDOKEY_WHEELDOWN || sym == SDLK_PAGEDOWN) {
|
||||||
|
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||||
|
plan_transform.T = atscreenpos(mousex, mousey, 1) * inverse(atscreenpos(mousex, mousey, 1.2)) * plan_transform.T;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for(auto& b: buttons) if(uni == b.first) { planmode = uni; return true; }
|
||||||
|
auto clean_history_to = [&] (int i) {
|
||||||
|
while(history.size() > 1 && history.back().t > i) history.pop_back();
|
||||||
|
};
|
||||||
|
switch(planmode) {
|
||||||
|
case 'p':
|
||||||
|
if(uni == '-' && !holdmouse) {
|
||||||
|
mousept_drag = mousept;
|
||||||
|
holdmouse = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(uni == '-' && holdmouse) {
|
||||||
|
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||||
|
plan_transform.T = plan_transform.T * eupush(mousept-mousept_drag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case 'a':
|
||||||
|
if(uni == '-' && !holdmouse) {
|
||||||
|
plan.emplace_back(mousept, hpxy(0, 0));
|
||||||
|
holdmouse = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(uni == '-' && holdmouse) {
|
||||||
|
plan.back().vel = mousept - plan.back().at;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case 'm': case 'd': {
|
||||||
|
if(!holdmouse) {
|
||||||
|
ld len = box * 2;
|
||||||
|
move_id = -1;
|
||||||
|
auto check = [&] (hyperpoint h, int id, int dir) {
|
||||||
|
ld d = sqhypot_d(2, h - mousept);
|
||||||
|
if(d < len) { len = d; move_id = id; move_dir = dir; }
|
||||||
|
};
|
||||||
|
int next_id = 0;
|
||||||
|
for(auto p: plan) {
|
||||||
|
check(p.at, next_id, 0);
|
||||||
|
check(p.at + p.vel, next_id, 1);
|
||||||
|
check(p.at - p.vel, next_id, -1);
|
||||||
|
next_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(uni == '-' && planmode == 'd' && move_id > 0) {
|
||||||
|
plan.erase(plan.begin() + move_id);
|
||||||
|
clean_history_to(move_id - 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(uni == '-' && planmode == 'm' && (move_id + move_dir * move_dir > 0) && !holdmouse) {
|
||||||
|
holdmouse = true;
|
||||||
|
println(hlog, "moving ", tie(move_id, move_dir));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(uni == '-' && planmode == 'm' && holdmouse) {
|
||||||
|
println(hlog, "moving further ", tie(move_id, move_dir));
|
||||||
|
if(move_dir == 0) plan[move_id].at = mousept;
|
||||||
|
else plan[move_id].vel = move_dir * (mousept - plan[move_id].at);
|
||||||
|
println(hlog, "set to ", tie(plan[move_id].at, plan[move_id].vel));
|
||||||
|
clean_history_to(move_id - 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case 'i': {
|
||||||
|
if(uni == '-') {
|
||||||
|
planpoint pt(C0, C0);
|
||||||
|
pt.at = get_spline(closest_t);
|
||||||
|
pt.vel = (get_spline(closest_t + 1e-3) - pt.at) / 1e-3;
|
||||||
|
plan.insert(plan.begin() + int(ceil(closest_t)), pt);
|
||||||
|
clean_history_to(int(closest_t));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
148
rogueviz/nilrider/statues.cpp
Normal file
148
rogueviz/nilrider/statues.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
namespace hr {
|
||||||
|
namespace bricks {
|
||||||
|
|
||||||
|
void draw_ro();
|
||||||
|
|
||||||
|
extern void build(bool in_pair);
|
||||||
|
|
||||||
|
struct brick {
|
||||||
|
euc::coord co;
|
||||||
|
color_t col;
|
||||||
|
int walls;
|
||||||
|
hyperpoint location;
|
||||||
|
hpcshape shRotWall[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern vector<brick> bricks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
hpcshape shMini[6];
|
||||||
|
|
||||||
|
void create_minitriangle() {
|
||||||
|
using namespace bricks;
|
||||||
|
hyperpoint ctr = Hypc;
|
||||||
|
for(auto& b: bricks::bricks) ctr += b.location;
|
||||||
|
ctr /= ctr[3];
|
||||||
|
transmatrix B = gpushxto0(ctr);
|
||||||
|
|
||||||
|
ld radius = 0;
|
||||||
|
ld sca = .18;
|
||||||
|
|
||||||
|
for(int f=0; f<6; f++) {
|
||||||
|
cgi.bshape(shMini[f], PPR::WALL);
|
||||||
|
shMini[f].flags |= POLY_TRIANGLES;
|
||||||
|
|
||||||
|
for(auto& b: bricks::bricks) {
|
||||||
|
transmatrix V = eupush(b.location);
|
||||||
|
|
||||||
|
int which = b.walls;
|
||||||
|
if(!((1<<f) & which)) continue;
|
||||||
|
|
||||||
|
auto& sh = b.shRotWall[f];
|
||||||
|
for(int i=sh.s; i<sh.e; i++) {
|
||||||
|
hyperpoint p = B * V * cgi.hpc[i];
|
||||||
|
p[0] *= sca;
|
||||||
|
p[1] *= sca;
|
||||||
|
p[2] *= sca*sca;
|
||||||
|
cgi.hpcpush(p);
|
||||||
|
radius = max(radius, sqhypot_d(2, p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cgi.finishshape();
|
||||||
|
}
|
||||||
|
cgi.extra_vertices();
|
||||||
|
println(hlog, "radius = ", radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** the texture data used for the castle walls */
|
||||||
|
texture::texture_data *castle_texture;
|
||||||
|
|
||||||
|
void create_castle() {
|
||||||
|
if(!castle_texture) {
|
||||||
|
castle_texture = new texture::texture_data;
|
||||||
|
auto& tex = *castle_texture;
|
||||||
|
tex.twidth = 16;
|
||||||
|
tex.theight = 16;
|
||||||
|
tex.stretched = false;
|
||||||
|
tex.strx = tex.tx;
|
||||||
|
tex.stry = tex.ty;
|
||||||
|
tex.base_x = 0;
|
||||||
|
tex.base_y = 0;
|
||||||
|
tex.whitetexture();
|
||||||
|
for(int y=0; y<16; y++)
|
||||||
|
for(int x=0; x<16; x++)
|
||||||
|
tex.get_texture_pixel(x, y) = bcols[submaps['b'][y][x]];
|
||||||
|
tex.loadTextureGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
bricks::build(false);
|
||||||
|
create_minitriangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
hpcshape shBall;
|
||||||
|
|
||||||
|
bool open_grid(int x, int y) {
|
||||||
|
return among(y&3, 1, 2) || among(x&3, 0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool closed_grid(int x, int y) {
|
||||||
|
return among(y&3, 0, 3) || among(x&3, 0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T1, class T2> void add_statue(const T1& grid, const T2& f) {
|
||||||
|
auto pt = [&] (int x, int y) {
|
||||||
|
ld x1 = x * M_PI / 16.;
|
||||||
|
ld y1 = y * M_PI / 32.;
|
||||||
|
cgi.hpcpush(f(x1,y1));
|
||||||
|
};
|
||||||
|
for(int y=-16; y<16; y++)
|
||||||
|
for(int x=-16; x<16; x++) if(grid(x,y)) {
|
||||||
|
pt(x, y);
|
||||||
|
pt(x, y+1);
|
||||||
|
pt(x+1, y);
|
||||||
|
pt(x+1, y);
|
||||||
|
pt(x, y+1);
|
||||||
|
pt(x+1, y+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hpcshape shGeostatue;
|
||||||
|
|
||||||
|
void init_statues() {
|
||||||
|
create_minitriangle();
|
||||||
|
create_castle();
|
||||||
|
|
||||||
|
cgi.bshape(shBall, PPR::WALL);
|
||||||
|
shBall.flags |= POLY_TRIANGLES;
|
||||||
|
add_statue(open_grid, [] (ld lon, ld lat) { return direct_exp(point3(cos(lat)*sin(lon)*.5, cos(lat)*cos(lon)*.5, sin(lat)*.5)); });
|
||||||
|
cgi.finishshape();
|
||||||
|
cgi.extra_vertices();
|
||||||
|
cgi.add_texture(shBall);
|
||||||
|
|
||||||
|
cgi.bshape(shGeostatue, PPR::WALL);
|
||||||
|
shGeostatue.flags |= POLY_TRIANGLES;
|
||||||
|
for(int i=0; i<8; i++) {
|
||||||
|
hyperpoint z = point31(0, 1e-6, 8);
|
||||||
|
hyperpoint ih = inverse_exp(shiftless(z));
|
||||||
|
ih = spin(i * 45 * degree) * ih;
|
||||||
|
add_statue(closed_grid, [&] (ld lon, ld lat) {
|
||||||
|
lat = lat * .75;
|
||||||
|
hyperpoint h = direct_exp(ih * (.5 + lat / M_PI));
|
||||||
|
return rgpushxto0(h) * sym_to_heis(point31(sin(lon)*.1, cos(lon)*.1, 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cgi.finishshape();
|
||||||
|
cgi.extra_vertices();
|
||||||
|
cgi.add_texture(shGeostatue);
|
||||||
|
|
||||||
|
for(ld z: vector<ld> {M_PI/2+1e-2, M_PI+1e-2, M_PI*2+1e-2, 7, 10})
|
||||||
|
for(hyperpoint h: {point31(0, 0, z), point31(1e-3, 0, z), point31(1e-6, 0, z), point31(0, 1e-6, z)}) {
|
||||||
|
hyperpoint i = inverse_exp(shiftless(h));
|
||||||
|
println(hlog, i, " @ ", hypot_d(3, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
244
rogueviz/nilrider/timestamp.cpp
Normal file
244
rogueviz/nilrider/timestamp.cpp
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
namespace nilrider {
|
||||||
|
|
||||||
|
ld timestamp::energy_in_squares() { return vel * vel / (2 * gravity); }
|
||||||
|
|
||||||
|
/** convert rotationally symmetric to Heisenberg model */
|
||||||
|
EX hyperpoint sym_to_heis(hyperpoint H) {
|
||||||
|
if(nil) {
|
||||||
|
H[2] += H[0] * H[1] / 2;
|
||||||
|
}
|
||||||
|
return H;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timestamp::draw_unilcycle(const shiftmatrix& V) {
|
||||||
|
const int points = 60;
|
||||||
|
const int spoke_each = 5;
|
||||||
|
hyperpoint whpoint[points+1];
|
||||||
|
|
||||||
|
transmatrix Ta = cspin(0, 1, -heading_angle);
|
||||||
|
transmatrix Tb = cspin(0, 2, -slope);
|
||||||
|
|
||||||
|
hyperpoint base = Ta * Tb * point31(0, 0, whrad);
|
||||||
|
|
||||||
|
for(int a=0; a<points; a++) {
|
||||||
|
ld beta = 360 * degree * a / points + circpos;
|
||||||
|
whpoint[a] = base + Ta * point3(whrad*sin(beta),0,whrad*cos(beta));
|
||||||
|
}
|
||||||
|
whpoint[points] = whpoint[0];
|
||||||
|
|
||||||
|
hyperpoint hub[2];
|
||||||
|
const ld hublen = whrad / 2;
|
||||||
|
for(int a=0; a<2; a++) {
|
||||||
|
hub[a] = base + Ta * point3(0, hublen*(a?1:-1), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int a=0; a<points; a+=spoke_each) for(int b=0; b<2; b++) {
|
||||||
|
curvepoint(hub[b]);
|
||||||
|
for(int b=0; b<=spoke_each; b++)
|
||||||
|
curvepoint(whpoint[a+b]);
|
||||||
|
curvepoint(hub[b]);
|
||||||
|
if(a&1)
|
||||||
|
queuecurve(V * rgpushxto0(where), 0xFFFFFFFF, 0xFFFF40FF, PPR::WALL);
|
||||||
|
else
|
||||||
|
queuecurve(V * rgpushxto0(where), 0xFFFFFFFF, 0xFF4040FF, PPR::WALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(1) {
|
||||||
|
curvepoint(base + Ta * point3(hublen, 0, whrad+hublen));
|
||||||
|
curvepoint(base + Ta * point3(0, -hublen, whrad+hublen));
|
||||||
|
curvepoint(base + Ta * point3(0, +hublen, whrad+hublen));
|
||||||
|
curvepoint(base + Ta * point3(hublen, 0, whrad+hublen));
|
||||||
|
queuecurve(V * rgpushxto0(where), 0xFF, 0x303030FF, PPR::WALL);
|
||||||
|
|
||||||
|
for(auto& y: {hublen, -hublen}) {
|
||||||
|
curvepoint(base + Ta * point3(hublen * .1, -y, 0));
|
||||||
|
curvepoint(base + Ta * point3(hublen * -.1, -y, 0));
|
||||||
|
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen / 2));
|
||||||
|
curvepoint(base + Ta * point3(hublen * .1, 0, whrad + hublen / 2));
|
||||||
|
curvepoint(base + Ta * point3(hublen * .1, -y, 0));
|
||||||
|
queuecurve(V * rgpushxto0(where), 0xFF, 0x303030FF, PPR::WALL);
|
||||||
|
|
||||||
|
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen / 2));
|
||||||
|
curvepoint(base + Ta * point3(hublen * .1, 0, whrad + hublen / 2));
|
||||||
|
curvepoint(base + Ta * point3(hublen * .1, 0, whrad + hublen));
|
||||||
|
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen));
|
||||||
|
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen / 2));
|
||||||
|
queuecurve(V * rgpushxto0(where), 0xFF, 0x303030FF, PPR::WALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tick_debug = false;
|
||||||
|
|
||||||
|
bool timestamp::tick(level *lev) {
|
||||||
|
|
||||||
|
const ld eps = slope_eps;
|
||||||
|
|
||||||
|
hyperpoint wnext = where;
|
||||||
|
wnext[0] += cos(heading_angle) * eps;
|
||||||
|
wnext[1] += sin(heading_angle) * eps;
|
||||||
|
wnext[2] = lev->surface(wnext);
|
||||||
|
|
||||||
|
wnext = gpushxto0(where) * wnext;
|
||||||
|
slope = atan(wnext[2] / eps);
|
||||||
|
|
||||||
|
auto ovel = vel;
|
||||||
|
|
||||||
|
vel -= sin(slope) * gravity / tps;
|
||||||
|
if(vel < 0) {
|
||||||
|
vel = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mvel = (vel + ovel) / 2;
|
||||||
|
where[0] += cos(heading_angle) * mvel * cos(slope) / tps;
|
||||||
|
where[1] += sin(heading_angle) * mvel * cos(slope) / tps;
|
||||||
|
where[2] = lev->surface(where);
|
||||||
|
circpos += mvel / whrad / tps;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timestamp::centerview(level *lev) {
|
||||||
|
// static bool once = false; if(once) return; once = true;
|
||||||
|
auto w = where;
|
||||||
|
w[2] += 0.2 * lev->scale;
|
||||||
|
hyperpoint front = rgpushxto0(w) * sym_to_heis(hyperpoint(1e-3 * cos(heading_angle), 1e-3*sin(heading_angle), 0, 1));
|
||||||
|
hyperpoint up = w; up[2] += 1e-3;
|
||||||
|
|
||||||
|
set_view(w, front, up);
|
||||||
|
|
||||||
|
transmatrix T = View;
|
||||||
|
|
||||||
|
ld gfx_slope = binsearch(-90*degree, min(slope, min_gfx_slope), [&] (ld slope) {
|
||||||
|
View = T;
|
||||||
|
rotate_view(cspin(1, 2, slope));
|
||||||
|
for(int i=0; i<8; i++) {
|
||||||
|
shift_view(ztangent(whdist * lev->scale / 8.));
|
||||||
|
hyperpoint p = inverse(View) * C0;
|
||||||
|
ld room = p[2] - lev->surface(p);
|
||||||
|
if(room < .1 * lev->scale) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
View = T;
|
||||||
|
rotate_view(cspin(1, 2, gfx_slope));
|
||||||
|
shift_view(ztangent(whdist * lev->scale));
|
||||||
|
centerover = cwt.at;
|
||||||
|
playermoved = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timestamp::draw_instruments(ld t) {
|
||||||
|
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||||
|
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||||
|
dynamicval<bool> ga(vid.always3, false);
|
||||||
|
dynamicval<geometryinfo1> gi(ginf[gEuclid].g, giEuclid2);
|
||||||
|
initquickqueue();
|
||||||
|
|
||||||
|
ld rad = 40;
|
||||||
|
|
||||||
|
ld cx = rad * 2;
|
||||||
|
ld cy = rad * 2;
|
||||||
|
|
||||||
|
auto sId = shiftless(Id);
|
||||||
|
|
||||||
|
ld pix = 1 / (2 * cgi.hcrossf / cgi.crossf);
|
||||||
|
|
||||||
|
// clinometer
|
||||||
|
|
||||||
|
cx += rad * 1.2;
|
||||||
|
|
||||||
|
for(int i=-90; i<=90; i++)
|
||||||
|
curvepoint(atscreenpos(cx+cos(i * degree)*rad, cy-sin(i*degree)*rad, 1) * C0);
|
||||||
|
|
||||||
|
curvepoint(atscreenpos(cx, cy+rad, 1) * C0);
|
||||||
|
queuecurve(sId, 0x000000FF, 0xFFFFFF80, PPR::ZERO);
|
||||||
|
|
||||||
|
curvepoint(hpxy(0, 0));
|
||||||
|
curvepoint(hpxy(rad, 0));
|
||||||
|
/* curvepoint(hpxy(rad/4, 0));
|
||||||
|
curvepoint(hpxy(0, rad));
|
||||||
|
curvepoint(hpxy(-rad/4, 0));
|
||||||
|
curvepoint(hpxy(rad/4, 0)); */
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(min_gfx_slope), 0x40, 0x40, PPR::ZERO);
|
||||||
|
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
curvepoint(hpxy(0, rad));
|
||||||
|
curvepoint(hpxy(-rad/4, 0));
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(90 * degree + slope), 0xFF, 0x40C040FF, PPR::ZERO);
|
||||||
|
|
||||||
|
// compass
|
||||||
|
|
||||||
|
cx -= rad * 1.2;
|
||||||
|
|
||||||
|
for(int i=0; i<360; i++)
|
||||||
|
curvepoint(atscreenpos(cx-cos(i * degree)*rad, cy-sin(i*degree)*rad, 1) * C0);
|
||||||
|
|
||||||
|
queuecurve(sId, 0x000000FF, 0xFFFFFF80, PPR::ZERO);
|
||||||
|
|
||||||
|
for(int d: {1}) {
|
||||||
|
|
||||||
|
// d == +1: direction arrow
|
||||||
|
// d == -1: compass
|
||||||
|
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
curvepoint(hpxy(0, rad));
|
||||||
|
curvepoint(hpxy(-rad/4, 0));
|
||||||
|
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(d * (90*degree + heading_angle)), 0xFF, d > 0 ? 0x0000FFFF : 0xFF0000FF, PPR::ZERO);
|
||||||
|
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
curvepoint(hpxy(0, -rad));
|
||||||
|
curvepoint(hpxy(-rad/4, 0));
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(d * (90*degree + heading_angle)), 0xFF, 0xFFFFFFFF, PPR::ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// speed meter
|
||||||
|
|
||||||
|
cx += rad * 3.4;
|
||||||
|
|
||||||
|
for(int i=0; i<360; i++)
|
||||||
|
curvepoint(atscreenpos(cx-cos(i * degree)*rad, cy-sin(i*degree)*rad, 1) * C0);
|
||||||
|
queuecurve(sId, 0x000000FF, 0xFFFFFF80, PPR::ZERO);
|
||||||
|
|
||||||
|
auto e_to_angle = [] (ld energy) {
|
||||||
|
return 135*degree - 3 * atan(energy/10);
|
||||||
|
};
|
||||||
|
|
||||||
|
vector<ld> short_lines = {2, 3, 4, 6, 7, 8, 9, 30, 40, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
|
||||||
|
|
||||||
|
for(auto h: short_lines) {
|
||||||
|
auto a = e_to_angle(h);
|
||||||
|
curvepoint(hpxy(-sin(a)*rad*.95, -cos(a)*rad*.95));
|
||||||
|
curvepoint(hpxy(-sin(a)*rad*.85, -cos(a)*rad*.85));
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix), 0xFF, 0, PPR::ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<ld> long_lines = {0, 1, 5, 10, 20, 50};
|
||||||
|
|
||||||
|
for(auto h: long_lines) {
|
||||||
|
auto a = e_to_angle(h);
|
||||||
|
curvepoint(hpxy(-sin(a)*rad*.95, -cos(a)*rad*.95));
|
||||||
|
curvepoint(hpxy(-sin(a)*rad*.75, -cos(a)*rad*.75));
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix), 0xFF, 0, PPR::ZERO);
|
||||||
|
displaystr(cx -sin(a)*rad*.65, cy -cos(a)*rad*.65, 0, 8, its(h), 0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
curvepoint(hpxy(0, -rad));
|
||||||
|
curvepoint(hpxy(-rad/4, 0));
|
||||||
|
curvepoint(hpxy(rad/4, 0));
|
||||||
|
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(e_to_angle(energy_in_squares())), 0xFF, 0xFF8080FF, PPR::ZERO);
|
||||||
|
|
||||||
|
quickqueue();
|
||||||
|
glflush();
|
||||||
|
|
||||||
|
string s = format("%d:%02d.%02d", int(t / 60), int(t) % 60, int(frac(t) * 100));
|
||||||
|
|
||||||
|
displaystr(vid.xres - vid.fsize, vid.fsize*2, 0, vid.fsize * 2, s, 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user