From 7629b89245be96365d5deb3b650591b962699620 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 18 Apr 2025 15:05:21 +0200 Subject: [PATCH] ru:: first commit --- rogueviz/ru/classes.cpp | 202 ++++++++++++++++++ rogueviz/ru/entity.cpp | 170 +++++++++++++++ rogueviz/ru/geometry.cpp | 121 +++++++++++ rogueviz/ru/globals.cpp | 138 ++++++++++++ rogueviz/ru/man.cpp | 30 +++ rogueviz/ru/map.ru | 438 +++++++++++++++++++++++++++++++++++++++ rogueviz/ru/portals.cpp | 101 +++++++++ rogueviz/ru/powers.cpp | 125 +++++++++++ rogueviz/ru/render.cpp | 288 +++++++++++++++++++++++++ rogueviz/ru/room.cpp | 144 +++++++++++++ rogueviz/ru/ru.cpp | 381 ++++++++++++++++++++++++++++++++++ rogueviz/ru/save.cpp | 142 +++++++++++++ 12 files changed, 2280 insertions(+) create mode 100644 rogueviz/ru/classes.cpp create mode 100644 rogueviz/ru/entity.cpp create mode 100644 rogueviz/ru/geometry.cpp create mode 100644 rogueviz/ru/globals.cpp create mode 100644 rogueviz/ru/man.cpp create mode 100644 rogueviz/ru/map.ru create mode 100644 rogueviz/ru/portals.cpp create mode 100644 rogueviz/ru/powers.cpp create mode 100644 rogueviz/ru/render.cpp create mode 100644 rogueviz/ru/room.cpp create mode 100644 rogueviz/ru/ru.cpp create mode 100644 rogueviz/ru/save.cpp diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp new file mode 100644 index 00000000..f6417101 --- /dev/null +++ b/rogueviz/ru/classes.cpp @@ -0,0 +1,202 @@ +namespace rogue_unlike { + +struct data { + int keystate; + double d; + ld modv; + ld moda; + int dx; + }; + +using powerfun = hr::function; + +struct power { + int key; + string name; + string desc; + string glyph; + color_t color; + flagtype flags; + powerfun pf; + power(int key, string name, string desc, string glyph, color_t color, flagtype f, powerfun pf) : key(key), name(name), desc(desc), glyph(glyph), color(color), flags(f), pf(pf) { + } + }; + +extern vector powers; + +struct bbox { + int minx, miny, maxx, maxy; + bool operator != (bbox& a) { return minx != a.minx || miny != a.miny || maxx != a.maxx || maxy != a.maxy; } + }; + +bool intersect(bbox a, bbox b); + +struct room { + // texture::texture_data *room_texture; + string roomname; + renderbuffer *rbuf; + cell *where; + char block_at[room_y][room_x]; + bool fov[room_y][room_x]; + bool which_map_rendered; + bool infile, need_rerender; + + vector> entities; + + eWall at(int x, int y) { + return eWall(block_at[y][x] >> 3); + } + + void clear() { + for(int y=0; ymaster->distance; + if(ylev <= 0) + for(int y=room_y-6; yat(x, y); + if(walls[b].flags & blocking) { + on_floor = true; + if(b == wFrozen) on_ice = true; + vel_y /= 2; + if(abs(vel_y) < 1e-6) vel_y = 0; + if(freezing()) { + if(b == wWater) current_room->replace_block(x, y, wFrozen); + else if(b != wFrozen) hit_wall(); + } + if(pixel_to_block(get_pixel_bbox_at(where_x + vel_x, where_y + vel_y)).maxy <= y) where_y += vel_y; + goto again; + } + } + + for(int x = obb.minx; x < obb.maxx; x++) for(int y = jbb.miny; y < obb.miny; y++) { + eWall b = current_room->at(x, y); + if(walls[b].flags & W_BLOCK) { + vel_y /= 2; + if(abs(vel_y) < 1e-6) vel_y = 0; + if(pixel_to_block(get_pixel_bbox_at(where_x + vel_x, where_y + vel_y)).miny > y) where_y += vel_y; + goto again; + } + } + + if(!fallthru) for(int x = nbb.minx; x < nbb.maxx; x++) for(int y = jbb.maxy-1; y < jbb.maxy; y++) { + eWall b = current_room->at(x, y); + if(walls[b].flags & W_STAIRCASE) { + on_floor = true; + if(vel_y > 0) { vel_y = 0; goto again; } + } + } + + for(int x = obb.maxx; x < jbb.maxx; x++) for(int y = jbb.miny; y < jbb.maxy; y++) { + eWall b = current_room->at(x, y); + if(b == wFountain0) { + current_room->replace_block(x, y, wFountain1); + addMessage("A magic fountain! You feel safe and refill your potions."); + } + if(walls[b].flags & W_BLOCK) { + if(freezing()) { hit_wall(); } + vel_x = (vel_x - max(vel_y, 0)/10) / 2; + goto again; + } + } + + for(int x = jbb.minx; x < obb.minx; x++) for(int y = jbb.miny; y < jbb.maxy; y++) { + eWall b = current_room->at(x, y); + if(b == wFountain0) { + current_room->replace_block(x, y, wFountain1); + addMessage("A magic fountain! You feel safe and refill your potions."); + } + if(walls[b].flags & W_BLOCK) { + if(freezing()) { hit_wall(); } + vel_x = (vel_x + max(vel_y, 0)/10) / 2; + goto again; + } + } + + int bx0 = floor(where_x / block_x); + int by0 = floor(where_y / block_y); + where_x += vel_x; + where_y += vel_y; + + int bx1 = floor(where_x / block_x); + int by1 = floor(where_y / block_y); + + if(non_hyperbolic) { + auto& loc = all_locations[by0][bx0]; + if(bx1 > bx0) { + auto& loc1 = loc.get(0); + where_x += block_x * (loc1.x - (loc.x + 1)); + where_y += block_y * (loc1.y - loc.y); + } + if(bx1 < bx0) { + auto& loc1 = loc.get(2); + where_x += block_x * (loc1.x - (loc.x - 1)); + where_y += block_x * (loc1.y - loc.y); + } + if(by1 < by0) { + auto& loc1 = loc.get(1); + where_x += block_x * (loc1.x - loc.x); + where_y += block_x * (loc1.y - (loc.y - 1)); + } + if(by1 > by0) { + auto& loc1 = loc.get(3); + where_x += block_x * (loc1.x - loc.x); + where_y += block_x * (loc1.y - (loc.y + 1)); + } + } + + // ld test_x, test_y; + // tie(test_x, test_y) = from_hyper(h_at); + + /*println(hlog, tie(where_x, where_y), " TO ", h_at, " TO ", tie(test_x, test_y)); + exit(1); */ + + if(true || !non_hyperbolic) { + hyperpoint h_at = to_hyper(where_x, where_y); + hyperpoint h_was = to_hyper(where_x - vel_x, where_y - vel_y); + hyperpoint h_willbe = rgpushxto0(h_at) * MirrorX * MirrorY * gpushxto0(h_at) * h_was; + ld next_x, next_y; + tie(next_x, next_y) = from_hyper(h_willbe); + vel_x = next_x - where_x; + vel_y = next_y - where_y; + } + + apply_grav(); + + gwhere_x += gvel_x; + gwhere_y += gvel_y; + + ld delta = 1/60.; + if((where_x - gwhere_x) * (gvel_x - vel_x) + (where_y - gwhere_y) * (gvel_y - vel_y) < 0) delta *= 2; + ld ndelta = 1-delta; + gvel_x = ndelta * gvel_x + delta * (where_x - gwhere_x); + gvel_y = ndelta * gvel_y + delta * (where_y - gwhere_y); + } + +void missile::act() { + kino(); + if(where_x > screen_x || where_x < 0 || where_y < 0 || where_y > screen_y) destroyed = true; + } + +} diff --git a/rogueviz/ru/geometry.cpp b/rogueviz/ru/geometry.cpp new file mode 100644 index 00000000..9f8ead50 --- /dev/null +++ b/rogueviz/ru/geometry.cpp @@ -0,0 +1,121 @@ +namespace rogue_unlike { + +hyperpoint to_hyper(ld x, ld y) { + if(non_hyperbolic) return hyperpoint(x, y, 1, 1); + y -= t_margin_at; + y += actual_screen_y; + x -= xctr; + + y /= mscale; + x /= mscale; + + y += .5; + ld d = x*x + y*y; + x /= d; + y /= d; + y -= 1; + hyperpoint h; + h[0] = -x; h[1] = y; h[2] = 1; + h = spin270() * h; + return perspective_to_space(h, 1, gcHyperbolic); + } + +pair from_hyper(hyperpoint h) { + if(non_hyperbolic) return {h[0], h[1]}; + h = spin90() * h; h[0] = -h[0]; + h[2] += 1; + h /= h[2]; + + h[1] += 1; + ld d = h[0]*h[0] + h[1]*h[1]; + h /= d; + h[1] -= .5; + + double x = h[0], y = h[1]; + + y *= mscale; + x *= mscale; + + y -= actual_screen_y; + y += t_margin_at; + x += xctr; + + return {x, y}; + } + +// room connections + +void switch_to_room(room *r) { + current_room->need_rerender = true; + current_room = r; + current_room->need_rerender = true; + } + +bool is_right(room *r) { + cell *c = r->where; + c->cmove(3); + return c->c.spin(3) == 0; + } + +room *get_adjacent(room *r, int i) { + cell *c = r->where; + c->cmove(i); + c = c->cmove(i); + return get_room_at(c); + } + +void switch_to_adjacent_room(int i) { + switch_to_room(get_adjacent(current_room, i)); + } + +ld get_scale_at(ld y) { + if(non_hyperbolic) return 1; + return (actual_screen_y + (y - t_margin_at)) / (actual_screen_y * 3/2.); + } + +bbox pixel_to_block(bbox b) { + b.minx /= block_x; + b.miny /= block_y; + b.maxx = (b.maxx + block_x-1) / block_x; + b.maxy = (b.maxy + block_y-1) / block_y; + if(b.minx < 0) b.minx = 0; + if(b.miny < 0) b.miny = 0; + if(b.maxx >= room_x) b.maxx = room_x; + if(b.maxy >= room_y) b.maxy = room_y; + return b; + } + +bbox join(bbox a, bbox b) { + bbox r; + r.minx = min(a.minx, b.minx); + r.miny = min(a.miny, b.miny); + r.maxx = max(a.maxx, b.maxx); + r.maxy = max(a.maxy, b.maxy); + return r; + } + +bool intersect(bbox a, bbox b) { + return max(a.minx, b.minx) < min(a.maxx, b.maxx) && max(a.miny, b.miny) < min(a.maxy, b.maxy); + } + +void print(hstream& hs, const bbox& b) { + print(hs, "[", b.minx,",",b.miny, ",",b.maxx,",",b.maxy,"]"); + } + +hyperpoint rupf(ld x, ld y) { + return hyperpoint(x, y, 1, 0); + } + +shiftmatrix asp(ld x, ld y, ld scale, ld scalex, ld scaley) { + transmatrix V = Id; + + V[0][2] = (x - screen_x/2) * scale; + V[1][2] = (y - screen_y/2) * scale; + V[0][0] = 2 * cgi.hcrossf / cgi.crossf * scale * scalex; + V[1][1] = 2 * cgi.hcrossf / cgi.crossf * scale * scaley; + V[2][2] = 1; + + return shiftless(V); + } + + } diff --git a/rogueviz/ru/globals.cpp b/rogueviz/ru/globals.cpp new file mode 100644 index 00000000..bf5f6f78 --- /dev/null +++ b/rogueviz/ru/globals.cpp @@ -0,0 +1,138 @@ +namespace rogue_unlike { + +using namespace hr; + +/* the size of a block, in pixels */ +constexpr int block_x = 8; +constexpr int block_y = 8; + +/* the size of a room (screen), in blocks */ +constexpr int room_x = 80; +constexpr int room_y = 40; + +/* the size of a room, in pixels */ +constexpr int screen_x = block_x * room_x; +constexpr int screen_y = block_y * room_y; + +/* the size of the area shared between right/left blocks */ +constexpr int lr_margin = 4; + +/* the size of the area shared with the block above */ +constexpr int t_margin = 2; + +/* the size of the area shared with the block below */ +constexpr int b_margin = 2 * t_margin; + +/* the position of margins in pixels */ +constexpr int l_margin_at = lr_margin * block_x / 2; +constexpr int r_margin_at = screen_x - block_x * lr_margin / 2; +constexpr int t_margin_at = t_margin * block_y / 2; +constexpr int b_margin_at = screen_y - b_margin * block_y / 2; + +/* between the margins */ +constexpr int actual_screen_x = r_margin_at - l_margin_at; +constexpr int actual_screen_y = b_margin_at - t_margin_at; + +int game_fps = 300; +bool bottom = 1; + +constexpr auto yctr = (t_margin_at + b_margin_at) / 2.; +constexpr auto xctr = (l_margin_at + r_margin_at) / 2.; + +double mscale = 100; + +bool non_hyperbolic; +bool one_room; + +struct ruwall { + string name; + string glyph; + color_t color; + flagtype flags; + }; + +enum eWall { wAir, wWall, wBouncy, wSpike, wWater, wFrozen, wDoor, wSmashedDoor, wFountain0, wFountain1, wBluePortal, wOrangePortal, wPlatform }; + +flagtype W_BLOCK = 1; +flagtype W_TRANS = 2; +flagtype W_PLATFORM = 4; +flagtype W_STAIRCASE = 8; +flagtype W_PAIN = 16; + +constexpr int qwall = 14; + +ruwall walls[qwall] = { + {"air", ".", 0x40404080, W_TRANS}, + {"wall", "#", 0xFFFFFFFF, W_BLOCK}, + {"bouncy wall", "#", 0x80FF80FF, W_BLOCK}, + {"spike", "^", 0xC08080FF, W_BLOCK | W_TRANS}, + {"water", "~", 0x0000FFFF, W_BLOCK | W_TRANS}, + {"frozen water", "#", 0xC0C0FFFF, W_BLOCK}, + {"door", "+", 0xC06000FF, W_BLOCK}, + {"smashed door", "'", 0xC06000FF, W_TRANS}, + {"magic fountain", "!", 0x8080C0FF, W_TRANS}, + {"magic fountain (active)", "!", 0xA0A0FFFF, W_TRANS}, + {"blue portal", "=", 0x4040C0FF, W_TRANS}, + {"orange portal", "=", 0xC08040FF, W_TRANS}, + {"platform", "-", 0xFFFFFFFF, W_PLATFORM | W_TRANS }, + {"staircase", "-", 0xFFFF80FF, W_PLATFORM | W_TRANS | W_STAIRCASE }, + }; + +int sel = 1; + +bool hallucinating; + +template bool in_range(T val, T minv, T maxv) { return val >= minv && val <= maxv; } + +map rooms; + +struct room *current_room; + +basic_textureinfo roomtinf; +hpcshape roomshape, roomshape_big; + +bool is_right(struct room *r); +struct room *get_adjacent(struct room *r, int i); + +ld get_scale_at(ld y); +room *get_room_at(cell *c); + +// gravity portals + +extern bool gravision; + +struct location { + int x, y; + char ch; + bool fixed; + ld potential; + array neighbors; + location& get(int id) { return neighbors[id][0]; } + }; + +extern array, 256> all_locations; + +enum class mapmode { standard, poincare, klein }; + +enum class mode { editmap, menu, playing, paused, inventory }; + +mode cmode = mode::playing; + +mapmode cmapmode = mapmode::standard; +void switch_mapmode_to(mapmode m); + +bool should_apply_fov() { return among(cmode, mode::playing, mode::paused, mode::inventory); } + +void enable(); + +void update_keystate(); +bool keyheld(int id); +bool keywasheld(int id); +bool keypressed(int id); + +void sync_map(); + +void render_room_objects(room *r); + + +} diff --git a/rogueviz/ru/man.cpp b/rogueviz/ru/man.cpp new file mode 100644 index 00000000..3da883aa --- /dev/null +++ b/rogueviz/ru/man.cpp @@ -0,0 +1,30 @@ +namespace rogue_unlike { + +void handle_powers(data& d); + +void man::act() { + kino(); + + data dat; + dat.d = get_scale(); + dat.modv = 60. / game_fps; + dat.moda = dat.modv * dat.modv; + dat.dx = 0; + + fallthru = false; + + handle_powers(dat); + + if(on_floor && !on_ice) { + vel_x = dat.dx * dat.d * dat.modv * 2.5; + } + else { + vel_x += dat.dx * dat.d * .05 * dat.moda; + } + + if(dat.dx) facing = dat.dx; + + current_room->fov_from(where_x / block_x, where_y / block_y); + } + +} diff --git a/rogueviz/ru/map.ru b/rogueviz/ru/map.ru new file mode 100644 index 00000000..6614dc7b --- /dev/null +++ b/rogueviz/ru/map.ru @@ -0,0 +1,438 @@ +ROOM Red Rooster Inn +# wall ++ door +- platform +s staircase +. air +MAP +...................##.............................+-...-+..---...##............. +..................##################################----############............ +.................##.....................#.............s.......#....##........... +................##......................#............s........#.....##.......... +...............##.......................#...........s.........#......##......... +..............##........................#..........s..........#.......##........ +.............##.........................#.........s...........#........##....... +............##..........................+........s............+.........##...... +...........##...........................+.......s.............+..........##..... +..........############################################----##################.... +.........###........................................##.s............##....##.... +..........#b........................................#b..s...........#b....#b.... +..........##........................................##...s..........##....##.... +..........#b....---------..----------..----------...#b....s.........#b....#b.... +..........##........................................##.....s........##....##.... +..........#b........................................#b......s.......#b....#b.... +..........##........................................##.......s......##....##.... +..........#b....---------..----------..----------...#b........s.....#b....#b.... +..........##........................................##.........s....##....##.... +..........#b........................................#b..........s...#b....#b.... +..........##........................................##...........s..+.....##.... +..........#b........................................#b............s.+.....#b.... +..........##....---------..----------..----------...##...........s##########.... +..........#b........................................#b..........s...#b....#b.... +..........##........................................##.........s....##....##.... +..........#b........................................#b........s.....#b....#b.... +..........##....---------..----------..----------...##.......s......##....##.... +..........#b........................................#b......s.......#b....#b.... +..........##........................................##.....s........##....##.... +..........#b........................................#b....s.........#b....#b.... +..........++....---------..----------..----------...++...s..........##....##.... +..........+b........................................+b..s...........#b....#b.... +..........++........................................++.s............++....##.... +..........+b........................................+bs.............+b....#b.... +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +OK + +MOVE 0 Red Rooster Inn +ROOM Red Rooster Inn, guest rooms +# wall ++ door +- platform +. air +MAP +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +#####################################........................................... +................##..........##...#####.......................................... +................#b..........#b....#b#b#......................................... +................##..........##.....#####........................................ +................#b..........#b......#b#b#....................................... +................##..........##.......#####...................................... +................#b..........#b........#b#b#..................................... +................++..........++.........#####.................................... +................+b..........+b..........#b#b#................................... +................++..........++...........#####.................................. +................+b..........+b............#b#b#................................. +########################--######################................................ +......................#b-b........#b........#b#b#............................... +......................##--........##.........#####.............................. +......................#b-b........#b..........#b#b#............................. +......................##--........##...........#####............................ +......................#b-b........#b............#b#b#........................... +......................++--........++.............#####.......................... +......................+b-b........+b..............#b#b#......................... +......................++--......--++....------......####........................ +......................+b-b......-b+b....-b-b-b......#b#b........................ +##########################--------########################...................... +#b#b#b#b#b#b#b#b#b#b#b#b#b-b-b-b-b#b#b#b#b#b#b#b#b#b#b#b#b...................... +START 344 274 +ITEM 382 287 +dagger +OK + +MOVE 1 Red Rooster Inn +ROOM Red Rooster Inn, host rooms +# wall +. air +MAP +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................##.............. +................................................................#b.............. +................................................................##.............. +................................................................#b.............. +................................................................##.............. +.......................................................##########b############## +......................................................#####..................... +.....................................................##b#b...................... +....................................................#####....................... +...................................................##b#b........................ +..................................................#####......................... +.................................................##b#b.......................... +................................................#####........................... +...............................................##b#b............................ +..............................................#####............................. +.............................................##b#b.............................. +............................................#################################### +...........................................##b#b................................ +..........................................#####................................. +.........................................##b#b.................................. +........................................#####................................... +.......................................##b#b.................................... +......................................#####..................................... +.....................................##b#b...................................... +....................................####........................................ +....................................#b#b........................................ +..................................############################################## +..................................#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +OK + +MOVE 2 Red Rooster Inn +ROOM Forest Path +# wall +- platform +. air +^ spike +x air +MAP +................................................................................ +................................................................................ +................................................................................ +....^........................................................................... +....^........................................................................... +....^........................................................................... +....^........................................................................... +....^........................................................................... +....^........................................................................... +....^.......^.......^........^...............^.....^.......^.................... +....^....----------------------------------------------------------............. +....^....^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.##.^...............................##--.. +....^..................................##.................................##.... +....^..................................##.................................##.... +....^--...............................-##-................................##.... +....^..................................##.............................----##.... +....^..................................##.................................##.... +....^..................................##-................................##--.. +....^.....^...........................-##.................^........^......##.... +....^--------------......----------....##.......--------------------------##.... +....^.^.^.^.^.^.^.^.......^.^.^.^.^....##.................................##.... +....^..................................##-................................##.... +....^...............^...^..............##...--.................................. +......................^...............###....................................... +.......................................##....................................... +.......................................###...................................... +..................................--...##....................................... +.......................................##....................................... +......................................^##....................................... +..............................--.......##^....--................................ +.......................................xx....................................... +.......................................xx....................................... +......................................x#x#...................................... +................^.....................#b#b...................^.................. +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +OK + +MOVE 2 Forest Path +ROOM Climbing the Hill +# wall +. air +MAP +################................................................................ +#################............................................................... +##################.............................................................. +#b#b#b#b#b#b#b#b#b#............................................................. +####################............................................................ +#b#b#b#b#b#b#b#b#b#b#........................................................... +######################.......................................................... +#b#b#b#b#b###b#b#b#b##.......................................................... +#######################......................................................... +#b#b#b#b#b#b#b#b#b#b###......................................................... +########################........................................................ +#b#b#b#b#b#b#b#b#b#b#b#b........................................................ +#########################....................................................... +#b#b#b#b#b#b#b#b#b#b#b#b#....................................................... +##########################...................................................... +#b#b#b#b#b#b#b#b#b#b#b#b#b#..................................................... +############################.................................................... +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#................................................... +##############################.................................................. +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#................................................. +################################................................................ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#............................................... +##################################.............................................. +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b##............................................ +######################################.......................................... +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b##........................................ +##########################################...................................... +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b###................................... +################################################................................ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b####............................ +########################################################........................ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#####................... +################################################################................ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#######......... +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +################################################################################ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +OK + +MOVE 1 Climbing the Hill +ROOM Dungeon Entrance +# wall ++ door +. air +^ spike +MAP +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +................................................................................ +#............................................................................... +##.............................................................................. +###............................................................................. +####............................................................................ +#####........................................................................... +######.......................................................................... +#######......................................................................... +########........................................................................ +#########....................................................................... +##########...................................................................... +###########..................................................................... +############.................................................................... +#############................................................................... +##############.................................................................. +##################.............................................................. +#####################.^......................................................... +######################^......................................................... +#######################......................................................... +..................++............................................................ +..................+b............................................................ +..................++............................................................ +..................+b............................................................ +###########################..................................................... +#############################................................................... +##############################.................................................. +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b.................................................. +################################................................................ +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b................................................ +OK + +MOVE 2 Climbing the Hill +ROOM Will be Hard to Return +# wall +. air +MAP +########################################################....#################### +########################################################....#################### +########################################################....#################### +#b###############################b#b#b#b#b#b#b#########b....#b###############b#b +########################################################....#################### +#b#######################b#b#b#b#b#b#b#######b#b#######b....#b###############b#b +########################################################....#################### +#b###########b#b#b#b#b#b#b#############b###########b###b....#b###b#b#####b###b#b +########################################################....#################### +#b#######b#b#b#b###########b#b#b#b#b#b#b#b#b#######b###b....#b#####b#b#b#b###b#b +########################################################....#################### +#b#####b#b###############b#b###############b#b#b#b#b###b....#b#######b#b#####b#b +########################################################....#################### +#b#####b###################################b###########b....#b#######b#b#####b#b +########################################################....#################### +#b###b#####################################b###########b....#b###b#b###b#####b#b +########################################################....#################### +#b###b#b###################b#b#b###########b###########b....#b###b#######b###b#b +########################################################....#################### +#b#####b#####b#b#b#b#b#b#b#b#####b#b#####b#############b....#b###b#b#####b###b#b +########################################################....#################### +#b#####b#b#b#b###b#################b#b###b###########b#b....#b#####b#b###b###b#b +########################################################....#################### +#b#######b#b#####b#################b#b#####b#########b#b....#b#######b###b#b#b#b +########################################################....#################### +#b#########b###b#######b#b###b#b#b#b#######b#########b#b....#b#####b#b#####b#b#b +########################################################....#################### +#b###########b###########b#b#b#########################b....#b#####b#######b#b#b +########################################################....#################### +#b###########b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#########b....#b###########b#b#b#b +########################################################....#################### +#b###################################b#b###############b....#b#######b###b###b#b +########################################################....#################### +#b#####################################################b....#b#####b#b#b#b###b#b +########################################################....#################### +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b....#b#b#b#b#b#b#b#b#b#b +########################################################....#################### +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b....#b#b#b#b#b#b#b#b#b#b +########################################################....#################### +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b....#b#b#b#b#b#b#b#b#b#b +OK + +MOVE 3 Climbing the Hill +ROOM Dungeons of Doom +# wall ++ door +- staircase +. air +A platform +MAP +#############################..################################################# +#############################..################################################# +########################..............########################################## +########################..............####################..............######## +####............########..............########..........++..............######## +####............########..............########..........+b..............######## +####............++....++..............++........##########..............######## +####............+b....+b..............+b........##########..............######## +####............########..............####################-.............######## +####............########..............####################-.............######## +####...........-########..............####################-.............######## +####...........-##########################################-.............######## +####...........-##########################..........######-.............######## +##########AA##############################..........#################AA######### +##########..##############################..........#################..######### +##########AA##############################..........#################AA######### +##########.......#########################..........++.................######### +##########.......#########################..........+b.................######### +###############..#########################..........###########--############### +###############--##############################################--############### +########.......--...###########################################--############### +########.......--...##########################################.--........####### +########.......--...############............##################.--........####### +########.......--...############............##################.--........####### +########.......--...++........++............##################.--........####### +########.......--...+b........+b............##################.--........####### +########.......--...############............##################.--........####### +########............############............##################.--........####### +########............############............++..............++.--........####### +################################............+b..............+b.--........####### +################################...........A##################...........####### +################################............##################...........####### +####################################AAAA######################...........####### +####################################AbAb######################################## +####################################..--######################################## +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b..-b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +####################################..--######################################## +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b..-b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +####################################..--######################################## +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b..-b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +OK + +MOVE 2 Dungeon Entrance +ROOM Dark Passage +# wall +. air +MAP +########################################################################........ +########################################################################........ +#########################################################################....... +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#############b#b#####b#....... +##########################################################################...... +#b#####b#b#b#b#b#b#b#b#b#b###################b#b#b#b#b#############b######...... +###########################################################################..... +#b#############b#b###################b#b#b#b###############################..... +###########################################################################..... +#b###########b#b###############b#b#b#b######################################.... +############################################################################.... +#b#########b#b#############b#b#b###################b#b#b#b#b#b#b#b##########.... +#############################################################################... +#b#######b#############b#b#################b#b#b#b############################.. +###############################################################################. +#b#####b#b#########b#b#b#############b#b#b###################################### +################################################################################ +#b#####b#########b#b#############b#b#b#########################b#b############## +################################################################################ +#b###b#b#######b#b###########b#b#b#####################b#b#b#b###b###########b## +################################################################################ +#b###########b#b###########b#b#################b#b#b#b###############b#b#b#b#b## +################################################################################ +#b###########b#########b#b#b#############b#b#b#b###############b#b#b#b########## +################################################################################ +#b###########b#######b#b###############b#b#################b#b################## +################################################################################ +#b###########b################################################################## +################################################################################ +#b###############b#########b#################################################### +##################################.............................................. +#b#########b#b#b#######b#b#######b.............................................. +##################################.............................................. +#b#######b###########b#b#########b.............................................. +##################################..........#################################### +#b###############################b..........#...#######.....................#### +##################################........###################################### +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b........#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +##################################........###################################### +#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b........#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b#b +OK + diff --git a/rogueviz/ru/portals.cpp b/rogueviz/ru/portals.cpp new file mode 100644 index 00000000..f9bb4061 --- /dev/null +++ b/rogueviz/ru/portals.cpp @@ -0,0 +1,101 @@ +// an experiment on potential-correct gravity + +namespace rogue_unlike { + +bool gravision; + +array, 256> all_locations; + +void entity::apply_portal_grav() { + ld modv = 60. / game_fps; + ld moda = modv * modv; + auto d = get_scale(); + int bx0 = floor(where_x / block_x); + int by0 = floor(where_y / block_y); + auto& loc = all_locations[by0][bx0]; + auto px = (loc.get(0).potential - loc.get(2).potential) * 255 / 2; + auto py = (loc.get(3).potential - loc.get(1).potential) * 255 / 2; + vel_x += d * grav() * moda * px; + vel_y += d * grav() * moda * py; + } + +void load_nonhyperbolic() { + enable(); + non_hyperbolic = true; + one_room = true; + fhstream f("rogueviz/ru/rumap.txt", "rt"); + vector rumap; + for(int y=0; y(f)); + println(hlog, rumap); + + auto& cr = *current_room; + for(int y=0; y= 'a' && rumap[y][x] <= 'z' ? 10*8 : + rumap[y][x] >= 'A' && rumap[y][x] <= 'Z' ? 11*8 : + 1; + + for(int y=0; y where_is; + for(int y=0; y powers = { + power('1', "Potion of Extra Life", + "You are really proud of this potion, which, after you die, will let you return to the moment of time when you drank it. " + "Unfortunately it still requires an ingredient found only in the magical fountains of the Dungeons of Alchemy.\n\n" + "You can only drink this potion when at a magical fountain. To protect yourself from dying permanently, it is drank " + "automatically whenever you are at a magical fountain.", + "!", 0xFFFF00FF, STARTING, + [] (data& d) { } + ), + + power('d', "move right", + "A special power of human beings, and most other animals, that they earn early in their life.", + ">", 0xFF0000FF, STARTING, + [] (data& d) { if(d.keystate & 1) d.dx += 1; } + ), + + power('a', "move left", + "Moving to the right was a mistake? If so, this special power can be used to ignore the consequences. In most cases, at least...", + "<", 0xFF0000FF, STARTING, + [] (data& d) { if(d.keystate & 1) d.dx -= 1; } + ), + + power('w', "jump", + "This power can be used to reach higher parts of the world. Its power is quite limited compared to move left and right, but " + "you expect to find some ways to make it more powerful.", + "^", 0xFF0000FF, STARTING, + [] (data& d) { + if((d.keystate & 1) && m.on_floor) m.vel_y = -(non_hyperbolic ? 3 : 5) * d.d * d.modv; + } + ), + + power('s', "fall", + "If you are on a platform, this ability can be used to drop down.", + "v", 0xFF0000FF, STARTING, + [] (data& d) { + m.fallthru = (d.keystate & 1); + } + ), + + power('p', "pause", + "Becoming an alchemist requires intelligence: thinking quickly to react to surprising effects of experiments. " + "To reflect this, you can use this power at any time to give yourself more time to think about the situation.", + "-", 0xFF0000FF, STARTING | WHILE_PAUSED, + [] (data& d) { + if(d.keystate == 1) cmode = mode::paused; + }), + + power(' ', "dagger", + "This sharp dagger is very useful during the preparation of alchemical ingredients, but it works as a basic weapon too.", + ")", 0xFFFFFFFF, 0, + [] (data& d) { + if(d.keystate != 1) return; + m.attack_facing = m.facing; m.attack_when = gframeid; + auto bb = pixel_to_block(m.get_pixel_bbox_at(m.where_x + m.attack_facing * m.dsx(), m.where_y)); + for(int y=bb.miny; yat(x, y); + if(b == wDoor) { + current_room->replace_block(x, y, wSmashedDoor); + addMessage("You smash the door!"); + } + } + }), + + power('o', "Poincaré's Crystal Ball", + "This crystal ball will not let you predict the future or see things elsewhere, but will let you easily map the " + "parts of the world you have seen so far. This artifact is rumored to have been actually created by Beltrami, but " + "it was bought and presented to people by the famous wizard Poincaré, and people thought it was Poincaré's creation.", + "o", 0x00FF00FF, WHILE_PAUSED, + [] (data& d) { + if(d.keystate != 1) return; + switch_mapmode_to(cmapmode == mapmode::poincare ? mapmode::standard : mapmode::poincare); + } + ), + + power('b', "Beltrami's Crystal Ball", + "Created by the ancient wizard Beltrami, this crystal ball will not let you predict the future or see things elsewhere, " + "but will let you easily map the parts of the world you have seen so far. Contrary to Poincaré's ball, straight lines are " + "mapped faithfully.", + "o", 0x00FFFFFF, WHILE_PAUSED, + [] (data& d) { + if(d.keystate != 1) return; + switch_mapmode_to(cmapmode == mapmode::klein ? mapmode::standard : mapmode::klein); + } + ), + + }; + +void handle_powers(data& d) { + for(auto& p: powers) { + if(cmode == mode::paused && !(p.flags & WHILE_PAUSED)) continue; + d.keystate = 0; + if(keyheld(p.key)) d.keystate |= 1; + if(keywasheld(p.key)) d.keystate |= 2; + p.pf(d); + } + } + +void draw_inventory() { + initquickqueue(); + for(int a: {0, 1, 3, 2, 0}) + curvepoint(hyperpoint((a&1)?16:screen_x-16, (a&2)?16:screen_y-16, 1, 0)); + queuecurve(scrm, 0xFFFFFFFF, 0x000000E0, PPR::LINE); + quickqueue(); + int sy = 200 * vid.yres / 1440; + int sx = 100 * vid.xres / 2560; + auto st = vid.fsize * 1.2; + displaystr(sx, sy, 0, vid.fsize, "Your inventory:", 0xC0C0C0, 0); + int lineid = 2; + for(auto& p: powers) { + string s = ""; s += dialog::keyname(p.key); + s += " "; + s += p.glyph; + s += " "; + s += p.name; + displaystr(sx, sy + st * (lineid++), 0, vid.fsize, s, p.color >> 8, 0); + } + } + +} diff --git a/rogueviz/ru/render.cpp b/rogueviz/ru/render.cpp new file mode 100644 index 00000000..5c2316fe --- /dev/null +++ b/rogueviz/ru/render.cpp @@ -0,0 +1,288 @@ +namespace rogue_unlike { + +shiftmatrix scrm; + +void prepare_tinf() { + + auto add_vertex = [&] (double bx, double by) { + roomtinf.tvertices.push_back(glhr::makevertex(bx / screen_x, 1 - by / screen_y, 0)); + cgi.hpc.push_back(to_hyper(bx, by)); + }; + + cgi.bshape(roomshape, PPR::WALL); + for(int by=t_margin_at; byflags |= POLY_TRIANGLES; + cgi.last->tinf = &roomtinf; + cgi.last->texture_offset = 0; + + int q = isize(roomtinf.tvertices); + + cgi.bshape(roomshape_big, PPR::WALL_TOP); + for(int by=0; byflags |= POLY_TRIANGLES; + cgi.last->tinf = &roomtinf; + cgi.last->texture_offset = q; + + cgi.finishshape(); + cgi.extra_vertices(); + + println(hlog, "sizes: ", tuple(roomshape_big.e - roomshape_big.s, roomshape.e - roomshape.s)); + } + +void room::create_texture() { + /* if(room_texture) return; + room_texture = new texture::texture_data; + + auto& tex = *room_texture; + + tex.twidth = tex.theight = 256; + + tex.tx = screen_x; + tex.ty = screen_y; + tex.stretched = false; + tex.strx = tex.tx; + tex.stry = tex.ty; + tex.base_x = 0; + tex.base_y = (tex.theight - tex.ty) / 2; */ + + if(rbuf) return; + rbuf = new renderbuffer(screen_x, screen_y, true); + } + +struct dqi_poly_tex : dqi_poly { + int texture_id; + void draw() override { if(tinf) tinf->texture_id = texture_id; dqi_poly::draw(); } + }; + +basic_textureinfo sprite_vertices; + +void render_room(room *r); + +bool draw_room_on_map(cell *c, const shiftmatrix& V) { + hr::addaura(tC0(V), pconf.alpha == 1 ? 0xFF00FF00 : 0xFF00FFFF, 0); + if(!rooms.count(c)) { + c->landparam = 0x101010; + get_room_at(c); + return false; + } + auto& r = rooms[c]; + if(!r.rbuf || &r == current_room || r.which_map_rendered != should_apply_fov() || r.need_rerender) { + vector> alt_ptds; + swap(ptds, alt_ptds); + render_room(&r); + swap(ptds, alt_ptds); + calcparam(); + } + if(!r.rbuf) return false; + + bool big = (&r == current_room); + auto& sh = big ? roomshape_big : roomshape; + auto& p = queuea (sh.prio); + p.V = V; + p.offset = sh.s; + p.cnt = sh.e - sh.s; + p.color = 0xFFFFFFFF; + p.tab = &cgi.ourshape; + p.flags = sh.flags; + p.tinf = &roomtinf; + p.tinf->texture_id = r.rbuf->renderedTexture; + p.offset_texture = sh.texture_offset; + p.texture_id = r.rbuf->renderedTexture; + + if(big || cmode == mode::editmap) { + dynamicval po(poly_outline, 0x80FF80FF); + queuepolyat(V, cgi.shFullFloor.b[0], 0, PPR::LINE); + } + + // render_room_objects(&r, render_at); + return true; + } + +void asciiletter(ld minx, ld miny, ld maxx, ld maxy, const string& ch, color_t col); + +void compute_scrm() { + ld tx = screen_x; + ld ty = screen_y; + ld scalex = (vid.xres/2) / (current_display->radius * tx); + ld scaley = (vid.yres/2) / (current_display->radius * ty); + ld scale = min(scalex, scaley); + scale *= 4; + + scrm = shiftless(Id); + scrm.T[0][2] = (- screen_x/2) * scale; + scrm.T[1][2] = (- screen_y/2) * scale; + scrm.T[0][0] = scale; + scrm.T[1][1] = scale; + scrm.T[2][2] = 1; + } + +void render_room_walls(room *r) { + initquickqueue(); + bool af = should_apply_fov(); + for(int y=0; yfov[y][x]) continue; + char c = r->block_at[y][x]; + + // ld sx = 1.5; + // ld sy = 1.3; + + int cc = c >> 3; + + if((c & 7) == 0) + asciiletter(x*block_x, y*block_y, (x+1)*block_x, (y+1)*block_y, walls[cc].glyph, walls[cc].color); + + if((c & 7) == 4) + asciiletter(x*block_x, y*block_y, (x+2)*block_x, (y+2)*block_y, walls[cc].glyph, walls[cc].color); + + if(gravision) { + int minx = x*block_x, maxx = (x+1)*block_x; + int miny = y*block_y, maxy = (y+1)*block_y; + for(int a: {0, 1, 3, 2, 0}) + curvepoint(hyperpoint((a&1)?minx:maxx, (a&2)?miny:maxy, 1, 0)); + color_t r = rainbow_color(1, all_locations[y][x].potential * 30); + r <<= 8; + queuecurve(scrm, r | 0xFF, r | 0x80, PPR::LINE); + } + } + quickqueue(); + } + +void render_room(room *r) { + r->create_texture(); + + resetbuffer rb; + r->rbuf->enable(); + + dynamicval v(vid, vid); + vid.xres = r->rbuf->tx; + vid.yres = r->rbuf->ty; + calcparam(); + + current_display->set_viewport(0); + r->rbuf->clear(0xFF000000); + + flat_model_enabler fme; + compute_scrm(); + + render_room_walls(r); + render_room_objects(r); + + rb.reset(); + r->which_map_rendered = should_apply_fov(); + r->need_rerender = false; + GLERR("render_room"); + } + +transmatrix letterscales[128]; + +void init_scales() { + for(int i=0; i<128; i++) letterscales[i] = Id; + letterscales['#'] = euscale(1.5, 1.2); + letterscales['*'] = eupush(0, 0.4) * euscale(1.5, 2); + letterscales['~'] = eupush(0, -0.4) * euscale(1.5, 1.2); + letterscales[')'] = euscale(2.5, 1); + letterscales['('] = euscale(2.5, 1); + } + +void asciiletter(ld minx, ld miny, ld maxx, ld maxy, const string& ch, color_t col) { + ld medx = (minx + maxx) / 2; + ld medy = (miny + maxy) / 2; + write_in_space(scrm * eupush(medx, medy) * euscale(maxx-minx, maxy-miny) * letterscales[int(ch[0])], + max_glfont_size, 2, ch, col, 0, 8, PPR::TEXT, rupf); + + if(anyshiftclick) { + for(int a: {0, 1, 3, 2, 0}) + curvepoint(hyperpoint((a&1)?minx:maxx, (a&2)?miny:maxy, 1, 0)); + queuecurve(scrm, 0xFF0000FF, 0xFF000080, PPR::LINE); + } + } + +void entity::draw() { + + double d = get_scale(); + + gwhere_x = where_x; gwhere_y = where_y; + + ld minx = min(where_x, gwhere_x) - sx() * d / 2; + ld miny = min(where_y, gwhere_y) - sy() * d / 2; + ld maxx = max(where_x, gwhere_x) + sx() * d / 2; + ld maxy = max(where_y, gwhere_y) + sy() * d / 2; + + asciiletter(minx, miny, maxx, maxy, glyph(), color()); + } + +void man::draw() { + entity::draw(); + + ld t = gframeid - attack_when; + if(t < 50) { + auto af = attack_facing * (1 - t * 0.01); + asciiletter( + where_x + af * dsx() - dsx()/2, where_y - dsy()/2, + where_x + af * dsx() + dsx()/2, where_y + dsy()/2, + attack_facing == -1 ? "(" : ")", 0xFFFFFF00 + (255 - t * 5) + ); + } + } + +void render_room_objects(room *r) { + initquickqueue(); + if(r == current_room) m.draw(); + for(auto& e: r->entities) e->draw(); + quickqueue(); + } + +int mousepx, mousepy; + +void draw_room() { + flat_model_enabler fme; + + compute_scrm(); + + if(false) { + basic_textureinfo bti; + bti.texture_id = current_room->rbuf->renderedTexture; + + ld cx[6] = {1,0,0,0,1,1}; + ld cy[6] = {1,1,0,0,0,1}; + + for(int i=0; i<6; i++) { + bti.tvertices.emplace_back(glhr::makevertex(cx[i], 1 - cy[i], 0)); + curvepoint(eupoint(cx[i] * screen_x, cy[i] * screen_y)); + } + + initquickqueue(); + auto& q = queuecurve(scrm, 0xFFFFFFFF, 0xFFFFFFFF, PPR::LINE); + q.tinf = &bti; q.flags |= POLY_TRIANGLES; q.offset_texture = 0; + quickqueue(); + } + if(true) { + render_room_walls(current_room); + } + + render_room_objects(current_room); + + ld& scale = scrm.T[0][0]; + + mousepx = (mousex - current_display->xcenter) * 2 / scale / current_display->radius + screen_x/2; + mousepy = (mousey - current_display->ycenter) * 2 / scale / current_display->radius + screen_y/2; + } + +} diff --git a/rogueviz/ru/room.cpp b/rogueviz/ru/room.cpp new file mode 100644 index 00000000..2fb5d85a --- /dev/null +++ b/rogueviz/ru/room.cpp @@ -0,0 +1,144 @@ +namespace rogue_unlike { + +void room::place_block_full(int x, int y, int b) { + need_rerender = true; + indenter ind(2); + infile = true; + + if(x < 0 || y < 0 || x >= room_x || y >= room_y) return; + if(b < 8) b = 0; + if((b & 4) && (x&1) != (b&1)) x--; + if((b & 4) && (2*(y&1)) != (b&2)) y--; + if(y < t_margin && (b&4)) return; + if(y > room_y - b_margin && !(b&4) && b) return; + if(block_at[y][x] == b) return; + + block_at[y][x] = b; + if(b & 4) { + place_block_full(x^1, y, b^1); + place_block_full(x, y^1, b^2); + } + else { + if(block_at[y][x^1] & 4) + place_block_full(x^1, y, 0); + if(block_at[y^1][x] & 4) + place_block_full(x, y^1, 0); + } + + auto& nonh = non_hyperbolic; + if(x < lr_margin) + get_adjacent(this, nonh ? 2 : 2)->place_block_full(x + room_x - lr_margin, y, b); + if(x >= room_x - lr_margin) + get_adjacent(this, nonh ? 0 : 4)->place_block_full(x - room_x + lr_margin, y, b); + if(y < t_margin) { + if(nonh) { + get_adjacent(this, 1)->place_block_full(x, y - room_y + t_margin, b); + } + else if(x < room_x / 2) { + get_adjacent(this, 1)->place_block_full((x - lr_margin/2) * 2 + lr_margin/2, room_y - b_margin + 2*y, b^4); + } + else { + get_adjacent(this, 0)->place_block_full((x - room_x/2) * 2 + lr_margin/2, room_y - b_margin + 2*y, b^4); + } + } + + if(y >= room_y - b_margin && !nonh) { + bool r = is_right(this); + x -= lr_margin/2; + x /= 2; + x += (r ? room_x/2 : lr_margin/2); + y = y - room_y + b_margin; + y /= 2; + b &= ~3; + get_adjacent(this, 3)->place_block_full(x, y, b ^ 4); + } + + if(y >= room_y - t_margin && nonh) { + get_adjacent(this, 1)->place_block_full(x, y + room_y - t_margin, b); + } + } + +void room::generate() { + clear(); + place_small(0, 0); + place_small(room_x/2-1, 0); + place_small(room_x/2, 0); + place_small(room_x-1, 0); + place_big(0, room_y-2); + place_big(room_x-2, room_y-2); + + /* + for(int x=0; x= room_x || cy >= room_y) return; + fov[cy][cx] = 1; + auto b = block_at[cy][cx]; + if(b & 4) { + if(b&1) cx--; + if(b&2) cy--; + fov[cy][cx+1] = fov[cy+1][cx] = fov[cy+1][cx+1] = fov[cy][cx] = true; + } + } + +void room::reveal_around(int cx, int cy) { + for(int dx: {-1, 0, 1}) for(int dy: {-1, 0, 1}) reveal(cx+dx, cy+dy); + } + +void room::fov_from(int sx, int sy) { + for(int y=0; y= room_x || cy >= room_y) break; + if(!(walls[at(cx, cy)].flags & W_TRANS)) break; + reveal_around(cx, cy); + } + } + } + +room *get_room_at(cell *c) { + bool create = !rooms.count(c); + auto& r = rooms[c]; + if(create) { + r.where = c; + r.clear(); + r.initial(); + c->wall = waNone; + c->land = laCanvas; + } + return &r; + } + + } diff --git a/rogueviz/ru/ru.cpp b/rogueviz/ru/ru.cpp new file mode 100644 index 00000000..8735975c --- /dev/null +++ b/rogueviz/ru/ru.cpp @@ -0,0 +1,381 @@ +#include "../../rogueviz/rogueviz.h" + +/** \brief Hyperbolic platformer. +The implementation of the platformer from https://twitter.com/ZenoRogue/status/1467233150380089345 +To play, load platformer.lev (e.g. `-load platformer.lev`) +Or create a new map by running with options: + `-noscr -canvas B -geo dbin -platformer` + +Keys: +up/left/right -- move the guy +c -- clear the current room (buggy, does not clear parts of the adjacent rooms) +g -- generate the current room (buggy) +m -- see the map (toggle) +p -- pause (toggle) +z -- screenshot menu +v -- HyperRogue settings +q -- quit +s -- save to platformer.lev +1 -- place a small block under the mouse +2 -- place a big block under the mouse +3 -- delete the block under the mouse + +Have fun! +*/ + +#include "globals.cpp" +#include "classes.cpp" +#include "geometry.cpp" +#include "entity.cpp" +#include "man.cpp" +#include "room.cpp" +#include "render.cpp" +#include "portals.cpp" +#include "powers.cpp" +#include "save.cpp" + +namespace rogue_unlike { + +static double gtime = 0; + +bool last_mkey = false; + +extern int mousepx, mousepy; + +void floodfill(int x, int y) { + if(x < 0 || y < 0 || x >= room_x || y >= room_y) return; + if(current_room->block_at[y][x] != 0) return; + current_room->place_block_full(x, y, 8 * sel); + floodfill(x+1, y); + floodfill(x-1, y); + floodfill(x, y+1); + floodfill(x, y-1); + } + +bool last_keystate[KEYSTATES], cur_keystate[KEYSTATES]; + +bool keyheld(int id) { return cur_keystate[id]; } +bool keywasheld(int id) { return last_keystate[id]; } +bool keypressed(int id) { return cur_keystate[id] && !last_keystate[id]; } + +void update_keystate() { + const Uint8 *keystate = SDL12_GetKeyState(NULL); + for(int i=0; iplace_block_full(mousepx / block_x, mousepy / block_y, 8*sel); + if(keyheld('2')) + current_room->place_block_full(mousepx / block_x, mousepy / block_y, 8*sel+4); + if(keyheld('3')) + current_room->place_block_full(mousepx / block_x, mousepy / block_y, 0); + if(keypressed('4')) pushScreen([] { + dialog::init(); + dialog::addTitle("what to add", 0x4040C0, 150); + for(int i=1; ientities; + + for(auto& e: ents) e->act(); + + auto mb = ents.begin(); + for(auto& e: ents) if(!e->destroyed) *(mb++) = std::move(e); + ents.resize(mb - ents.begin()); + + auto& nonh = non_hyperbolic; + if(one_room) return; + + if(m.where_x < l_margin_at) { + m.where_x += actual_screen_x; + switch_to_adjacent_room(2); + m.clearg(); + } + if(m.where_x > r_margin_at) { + m.where_x -= actual_screen_x; + switch_to_adjacent_room(nonh ? 0 : 4); + m.clearg(); + } + + if(m.where_y < t_margin_at && !nonh) { + m.where_y = (m.where_y - t_margin_at) * 2 + b_margin_at; + m.where_x -= l_margin_at; + m.where_x = 2 * m.where_x; + if(m.where_x > actual_screen_x) { + m.where_x -= actual_screen_x; + switch_to_adjacent_room(0); + } + else + switch_to_adjacent_room(1); + m.where_x += l_margin_at; + m.vel_x *= 2; m.vel_y *= 2; + m.clearg(); + } + if(m.where_y > b_margin_at && !nonh) { + m.where_x -= l_margin_at; + m.where_y -= b_margin_at; + m.where_y /= 2; + m.where_y += t_margin_at; + if(is_right(current_room)) + m.where_x += actual_screen_x; + switch_to_adjacent_room(3); + m.where_x /= 2; + m.where_x += l_margin_at; + m.vel_x /= 2; m.vel_y /= 2; + m.clearg(); + } + } + +void sync_map() { + for(auto& p: rooms) + if(&p.second == current_room) + centerover = p.first; + View = cspin90(1, 0); + // if(cmode == mode::playing) View = View * inverse(parabolic13_at(to_hyper(m.where_x, m.where_y))); + if(cmode == mode::playing) { + hyperpoint p = to_hyper(m.where_x, m.where_y); + transmatrix T = iso_inverse(parabolic13_at(deparabolic13(p))); + View = View * T; + } + } + +void switch_mapmode_to(mapmode m) { + cmapmode = m; + switch(cmapmode) { + case mapmode::standard: + nomap = true; + break; + case mapmode::poincare: + case mapmode::klein: + sync_map(); + pconf.scale = 0.95; + pconf.alpha = cmapmode == mapmode::poincare ? 1 : 0; + pmodel = mdDisk; + nomap = false; + break; + } + } + +void render_the_map() { + switch(cmapmode) { + case mapmode::standard: + emptyscreen(); + render_room(current_room); + draw_room(); + drawmessages(); + nomsg = false; + dialog::add_key_action('v', [] { cmode = mode::menu; }); + break; + case mapmode::poincare: + case mapmode::klein: + gamescreen(); + if(cmode == mode::editmap) { + getcstat = '-'; + dialog::add_key_action('-', [] { if(!mouseover) return; current_room = &rooms[mouseover]; switch_mapmode_to(mapmode::standard); }); + } + break; + } + } + +void run() { + // clearMessages(); + dialog::init(); + + switch(cmode) { + case mode::editmap: + case mode::playing: + case mode::paused: + if(cmode == mode::playing) sync_map(); + render_the_map(); + if(cmode == mode::editmap) dialog::add_key_action('p', [] { println(hlog, "p pressed"); switch_mapmode_to(mapmode::poincare); }); + if(cmode == mode::editmap) mouseovers = format("coordinates: %d %d", mousepx, mousepy); + break; + + case mode::inventory: + render_the_map(); + draw_inventory(); + dialog::add_key_action('v', [] { cmode = mode::menu; }); + break; + + case mode::menu: + nomap = true; + emptyscreen(); + dialog::init(); + dialog::addTitle("Fountains of Alchemy", 0x4040C0, 150); + dialog::addItem("return to game", 'v'); + dialog::add_action([] { cmode = mode::playing; }); + + dialog::addItem("inventory", 'i'); + dialog::add_action([] { cmode = mode::inventory; }); + + dialog::addItem("map editor", 'e'); + dialog::add_action([] { cmode = mode::editmap; }); + + dialog::addItem("screenshot", 'z'); + dialog::add_action([] { pushScreen(shot::menu); }); + + dialog::addItem("save to editmap.ru", 's'); + dialog::add_key_action('s', [] { + save_map("rogueviz/ru/editmap.ru"); + }); + + dialog::display(); + break; + } + + keyhandler = [] (int sym, int uni) { + if(among(cmode, mode::paused, mode::editmap) && cmapmode != mapmode::standard) + handlePanning(sym, uni); + dialog::handleNavigation(sym, uni); + }; + } + +void add_platf_hooks(); + +void set_sval() { + + ld s_min = 10, s_max = 1200; + + for(int it=0; it<100; it++) { + mscale = sqrt(s_min * s_max); + hyperpoint atop = deparabolic13(to_hyper(0, t_margin_at)); + if(atop[0] < -log(2)/2) s_max = mscale; + else s_min = mscale; + } + } + +void enable() { + + stop_game(); + + set_sval(); + init_scales(); + + hyperpoint aleft = deparabolic13(to_hyper(l_margin_at, yctr)); + hyperpoint aright = deparabolic13(to_hyper(r_margin_at, yctr)); + + vid.binary_width = abs(aright[1] - aleft[1]) / log(2); + + start_game(); + cgi.prepare_shapes(); + + current_room = get_room_at(cwt.at); + + prepare_tinf(); + + add_platf_hooks(); + load_map("rogueviz/ru/map.ru"); + switch_mapmode_to(mapmode::standard); + } + +void add_platf_hooks() { + + rogueviz::rv_hook(hooks_prestats, 90, [=] { + + if(nomap) + draw_room(); + else + render_room(current_room); + + return true; + }); + + rogueviz::rv_hook(hooks_resetGL, 90, [=] { + for(auto& [w, r]: rooms) if(r.rbuf) { delete r.rbuf; r.rbuf = nullptr; } + }); + + rogueviz::rv_hook(shmup::hooks_turn, 90, [=] (int d) { + gtime += d; + while(gtime > 1000. / game_fps) { + gtime -= 1000. / game_fps; + + gframeid++; + update_keystate(); + + switch(cmode) { + case mode::editmap: + editmap_frame(); + break; + + case mode::playing: + playing_frame(); + break; + + case mode::paused: + data d; + handle_powers(d); + break; + + default: ; + } + } + return true; + }); + + rogueviz::rv_hook(hooks_drawcell, 90, draw_room_on_map); + + rogueviz::rv_hook(mapstream::hooks_savemap, 100, [] (hstream& f) { + f.write(67); + for(auto& p: rooms) { + f.write(mapstream::cellids[p.first]); + for(int y=0; y(0); + } + f.write(-1); + f.write(mapstream::cellids[current_room->where]); + f.write(m.where_x); + f.write(m.where_y); + f.write(m.vel_x); + f.write(m.vel_y); + }); + + pushScreen(run); + } + +auto chk = arg::add3("-ru", enable) + + addHook(mapstream::hooks_loadmap, 100, [] (hstream& f, int id) { + if(id == 67) { + println(hlog, "loading platformer"); + while(true) { + int i = f.get(); + if(i == -1) break; + auto r = get_room_at(mapstream::cellbyid[i]); + for(int y=0; yblock_at[y][x]); + r->clearfov(); + r->infile = true; + f.get(); + } + int id = f.get(); + current_room = get_room_at(mapstream::cellbyid[id]); + f.read(m.where_x); + f.read(m.where_y); + f.read(m.vel_x); + f.read(m.vel_y); + add_platf_hooks(); + println(hlog, "done"); + set_sval(); + + cgi.prepare_shapes(); + prepare_tinf(); + init_scales(); + + cmode = mode::playing; + println(hlog, "set mode to playing"); + } + }); + +} diff --git a/rogueviz/ru/save.cpp b/rogueviz/ru/save.cpp new file mode 100644 index 00000000..3765f391 --- /dev/null +++ b/rogueviz/ru/save.cpp @@ -0,0 +1,142 @@ +namespace rogue_unlike { + +map in_queue; + +queue q; + +void visit(cell *c, int d) { + if(in_queue.count(c)) return; + in_queue[c] = d; + q.push(c); + } + +void save_map(string fname) { + in_queue.clear(); + q = {}; + visit(currentmap->gamestart(), -1); + + fhstream f(fname, "w"); + + while(!q.empty()) { + auto c = q.front(); + q.pop(); + auto& r = rooms[c]; + if(!r.infile) continue; + auto inq = in_queue[c]; + if(inq != -1) { + println(f, "MOVE ", c->c.spin(inq), " ", rooms[c->move(inq)].roomname); + } + println(f, "ROOM ", r.roomname); + + map code_for; + map code_used; + char next_code = 'A'; + + for(int y=0; y> 3; + auto& c = code_for[i]; + if(c == 0 && !code_used.count(walls[i].glyph[0])) c = walls[i].glyph[0]; + if(c == 0) c = next_code++; + code_used[c] = i; + } + + for(auto [key, id]: code_used) println(f, format("%c", key), " ", walls[id].name); + + println(f, "MAP"); + + for(int y=0; y>3])); + } + println(f); + } + + println(f, "OK\n"); + + for(int i=0; itype; i++) visit(c->cmove(i), c->c.spin(i)); + } + } + +void err(string s, string context) { + println(hlog, "while: ", context, " reading: ", s); + throw hr_exception("ru read error"); + } + +void load_room(fhstream& f, cell *c) { + setdist(c, 7, nullptr); + auto& r = *get_room_at(c); + string s = scanline_noblank(f); + if(s.substr(0, 5) == "ROOM ") r.roomname = s.substr(5); + else err("load_room name ", s); + println(hlog, "loading room named: ", r.roomname); + map codes; + while(true) { + string s = scanline_noblank(f); + if(s == "") continue; + if(s == "MAP") break; + string t = s.substr(2); + if(s.size() < 3 || s[1] != ' ') err("load codes", s); + for(int i=0; i bmap; + for(int y=0; y(); + sscanf(param.c_str(), "%lf%lf", &b->where_x, &b->where_y); + s = scanline_noblank(f); + b->id = -1; + for(int i=0; iid = i; + if(b->id == -1) println(hlog, "error: unknown item name ", s), b->id = 0; + r.entities.emplace_back(std::move(b)); + } + else println(hlog, "unknown mapline ", s); + } + else println(hlog, "unknown mapline ", s); + } + } + +void load_map(string fname) { + fhstream f(fname, "r"); + load_room(f, currentmap->gamestart()); + while(!feof(f.f)) { + string s = scanline_noblank(f); + if(s == "") continue; + if(s.substr(0, 4) == "MOVE") { + int i = s[5] - '0'; + string roomname = s.substr(7); + for(auto& [c,r]: rooms) if(r.roomname == roomname) load_room(f, c->move(i)); + } + else err("load_map", s); + } + } + + +}