1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-05-10 11:14:07 +00:00

ru:: first commit

This commit is contained in:
Zeno Rogue 2025-04-18 15:05:21 +02:00
parent ff22efaed0
commit 7629b89245
12 changed files with 2280 additions and 0 deletions

202
rogueviz/ru/classes.cpp Normal file
View File

@ -0,0 +1,202 @@
namespace rogue_unlike {
struct data {
int keystate;
double d;
ld modv;
ld moda;
int dx;
};
using powerfun = hr::function<void(data&)>;
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<power> 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<unique_ptr<struct entity>> entities;
eWall at(int x, int y) {
return eWall(block_at[y][x] >> 3);
}
void clear() {
for(int y=0; y<room_y; y++) for(int x=0; x<room_x; x++) block_at[y][x] = 0;
}
void clearfov() {
for(int y=0; y<room_y; y++) for(int x=0; x<room_x; x++) fov[y][x] = false;
}
void initial() {
int ylev = where->master->distance;
if(ylev <= 0)
for(int y=room_y-6; y<room_y; y++)
for(int x=0; x<room_x; x++)
block_at[y][x] = 8 + 4 + (x&1) + (y&1)*2;
if(ylev < 0)
for(int y=0; y<room_y-6; y++)
for(int x=0; x<room_x; x++)
block_at[y][x] = 8;
roomname = "UNNAMED-";
for(int i=0; i<8; i++) roomname += char('A' + rand() % 26);
println(hlog, "generated roomname as ", roomname);
}
void place_small(int x, int y) {
block_at[y][x] = 8;
}
void place_big(int x, int y) {
block_at[y][x] = 8+4;
block_at[y][x+1] = 8+5;
block_at[y+1][x] = 8+6;
block_at[y+1][x+1] = 8+7;
}
void place_block_full(int x, int y, int b);
void replace_block(int x, int y, eWall w) {
int b = 8 * w;
if(block_at[y][x] & 4) b += 4;
place_block_full(x, y, b);
}
void generate();
void reveal(int cx, int cy);
void reveal_around(int cx, int cy);
void fov_from(int sx, int sy);
void create_texture();
};
struct entity {
virtual double sx() = 0;
virtual double sy() = 0;
double where_x, where_y;
double vel_x, vel_y;
ld dsx() { return get_scale() * sx(); }
ld dsy() { return get_scale() * sy(); }
double gwhere_x, gwhere_y;
double gvel_x, gvel_y;
void clearg() {
gwhere_x = where_x;
gwhere_y = where_y;
gvel_x = vel_x;
gvel_y = vel_y;
}
entity() {
where_x = screen_x / 2.;
where_y = screen_y / 2.;
vel_x = 0;
vel_y = 0;
destroyed = false;
clearg();
};
struct bbox get_pixel_bbox_at(double x, double y);
struct bbox get_pixel_bbox() { return get_pixel_bbox_at(where_x, where_y); }
virtual double grav() { return 0.1; }
bool on_floor;
bool fallthru;
bool on_ice;
bool destroyed;
void kino();
void apply_grav();
void apply_portal_grav();
virtual void act() { kino(); }
double get_scale() { return get_scale_at(where_y); }
virtual bool freezing() { return false; }
virtual void hit_wall() {};
virtual void draw();
virtual string glyph() = 0;
virtual color_t color() = 0;
};
struct man : public entity {
int facing;
int attack_facing;
int attack_when;
man() { facing = 1; attack_facing = 1; }
double sx() override { return 12; }
double sy() override { return 12; }
string glyph() override { return hallucinating ? "f" : "@"; }
color_t color() override { return hallucinating ? 0x808080FF : 0xFF8080FF; }
void act() override;
void draw() override;
};
extern man m;
struct sage : public entity {
double sx() override { return 12; }
double sy() override { return 12; }
string glyph() override { return hallucinating ? "D" : "A"; }
color_t color() override { return hallucinating ? 0xFF0000FF : 0x90FF90FF; }
};
struct item : public entity {
int id;
double sx() override { return 12; }
double sy() override { return 12; }
string glyph() override { return powers[id].glyph; }
color_t color() override { return powers[id].color; }
void act() override {
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
addMessage("You pick up the " + powers[id].name + ".");
destroyed = true;
}
}
};
struct missile : public entity {
missile() { destroyed = false; }
double sx() override { return 4; }
double sy() override { return 4; }
string glyph() override { return "*"; }
color_t color() override { return 0x8080FFFF; }
void act() override;
bool freezing() override { return true; }
void hit_wall() override { destroyed = true; }
};
}

170
rogueviz/ru/entity.cpp Normal file
View File

@ -0,0 +1,170 @@
namespace rogue_unlike {
int gframeid = 0;
man m;
bbox entity::get_pixel_bbox_at(double x, double y) {
bbox b;
double d = get_scale_at(y);
double man_x = sx();
double man_y = sy();
b.minx = x - man_x * d / 2;
b.maxx = x + man_x * d / 2 + 1;
b.miny = y - man_y * d / 2;
b.maxy = y + man_y * d / 2 + 1;
return b;
}
void entity::apply_grav() {
if(non_hyperbolic) return apply_portal_grav();
ld modv = 80. / game_fps;
ld moda = modv * modv;
auto d = get_scale();
vel_y += d * grav() * moda;
}
void entity::kino() {
on_floor = false;
on_ice = false;
// ld modv = 60. / game_fps;
apply_grav();
again:
auto obb = pixel_to_block(get_pixel_bbox());
auto nbb = pixel_to_block(get_pixel_bbox_at(where_x + vel_x, where_y + vel_y));
auto jbb = join(obb, nbb);
flagtype blocking = (vel_y < 0 || fallthru) ? W_BLOCK : (W_BLOCK | W_PLATFORM);
for(int x = obb.minx; x < obb.maxx; x++) for(int y = obb.maxy; y < jbb.maxy; y++) {
eWall b = current_room->at(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<ld>(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<ld>(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;
}
}

121
rogueviz/ru/geometry.cpp Normal file
View File

@ -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<ld, ld> 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);
}
}

138
rogueviz/ru/globals.cpp Normal file
View File

@ -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<class T> bool in_range(T val, T minv, T maxv) { return val >= minv && val <= maxv; }
map<cell*, struct room> 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<location*, 4> neighbors;
location& get(int id) { return neighbors[id][0]; }
};
extern array<array<location, 256>, 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);
}

30
rogueviz/ru/man.cpp Normal file
View File

@ -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);
}
}

438
rogueviz/ru/map.ru Normal file
View File

@ -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

101
rogueviz/ru/portals.cpp Normal file
View File

@ -0,0 +1,101 @@
// an experiment on potential-correct gravity
namespace rogue_unlike {
bool gravision;
array<array<location, 256>, 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<string> rumap;
for(int y=0; y<room_y; y++) rumap.push_back(scan<string>(f));
println(hlog, rumap);
auto& cr = *current_room;
for(int y=0; y<room_y; y++)
for(int x=0; x<room_x; x++)
cr.block_at[y][x] =
rumap[y][x] == '#' ? 8 :
rumap[y][x] == '-' ? 12*8 :
rumap[y][x] == '.' ? 0 :
rumap[y][x] >= 'a' && rumap[y][x] <= 'z' ? 10*8 :
rumap[y][x] >= 'A' && rumap[y][x] <= 'Z' ? 11*8 :
1;
for(int y=0; y<room_y; y++)
for(int x=0; x<room_x; x++) cr.fov[y][x] = true;
actual_view_transform = Id;
map<char, location*> where_is;
for(int y=0; y<room_y; y++)
for(int x=0; x<room_x; x++)
where_is[rumap[y][x]] = &all_locations[y][x];
for(int y=0; y<256; y++)
for(int x=0; x<256; x++) {
auto& loc = all_locations[y][x];
loc.x = x;
loc.y = y;
loc.fixed = false;
loc.ch = (y < room_y && x < room_x) ? rumap[y][x] : 0;
loc.neighbors[0] = &all_locations[y][(x+1)&255];
loc.neighbors[1] = &all_locations[(y-1)&255][x];
loc.neighbors[2] = &all_locations[y][(x-1)&255];
loc.neighbors[3] = &all_locations[(y+1)&255][x];
}
for(int y=0; y<256; y++)
for(int x=0; x<256; x++) {
auto& loc = all_locations[y][x];
if(in_range(loc.get(1).ch, 'a', 'z')) {
auto& up_below = loc;
auto& up_above = loc.get(1);
auto& down_below = where_is[loc.get(1).ch ^ 32][0];
auto& down_above = down_below.get(1);
swap(up_below.neighbors[1], down_below.neighbors[1]);
swap(up_above.neighbors[3], down_above.neighbors[3]);
}
}
for(int x=0; x<256; x++) for(int y=0; y<256; y++) {
int flip_y = (y - room_y/2 + 128) & 255;
auto& loc = all_locations[y][x];
loc.potential = flip_y / 255.;
if(flip_y == 0 || flip_y == 255) loc.fixed = true;
}
int it = 0;
while(true) {
ld err = 0;
for(int y=0; y<256; y++) for(int x=0; x<256; x++) {
auto& loc = all_locations[y][x];
if(loc.fixed) continue;
ld pot = (loc.get(0).potential + loc.get(1).potential + loc.get(2).potential + loc.get(3).potential) / 4;
err += abs(pot - loc.potential);
loc.potential = pot;
}
it++;
if(err < 1e-2) break;
}
}
auto portal_chk = arg::add3("-nonh", load_nonhyperbolic);
}

125
rogueviz/ru/powers.cpp Normal file
View File

@ -0,0 +1,125 @@
namespace rogue_unlike {
flagtype STARTING = Flag(1);
flagtype WHILE_PAUSED = Flag(2);
vector<power> 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; y<bb.maxy; y++)
for(int x=bb.minx; x<bb.maxx; x++) {
int b = current_room->at(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);
}
}
}

288
rogueviz/ru/render.cpp Normal file
View File

@ -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; by<b_margin_at; by+=block_y)
for(int bx=l_margin_at; bx<r_margin_at; bx+=block_x) {
add_vertex(bx, by);
add_vertex(bx+block_x, by);
add_vertex(bx+block_x, by+block_y);
add_vertex(bx, by);
add_vertex(bx, by+block_y);
add_vertex(bx+block_x, by+block_y);
}
cgi.last->flags |= 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; by<screen_y; by+=block_y)
for(int bx=0; bx<screen_x; bx+=block_x) {
add_vertex(bx, by);
add_vertex(bx+block_x, by);
add_vertex(bx+block_x, by+block_y);
add_vertex(bx, by);
add_vertex(bx, by+block_y);
add_vertex(bx+block_x, by+block_y);
}
cgi.last->flags |= 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<unique_ptr<drawqueueitem>> 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<dqi_poly_tex> (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<color_t> 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; y<room_y; y++)
for(int x=0; x<room_x; x++) {
if(af && !r->fov[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<videopar> 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;
}
}

144
rogueviz/ru/room.cpp Normal file
View File

@ -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; x+=2)
if(hrand(100) < 10)
place_big(x, room_y-2);
for(int x=0; x<room_x; x++)
if(hrand(100) < 10)
place_small(x, 0); */
for(int y=2; y<room_y-2; y+=2)
for(int x=2; x<room_x-2; x+=2)
if(hrand(room_y * 8) < y)
place_big(x, y);
for(int y=2; y<room_y-2; y++)
for(int x=2; x<room_x-2; x++)
if(block_at[y][x] == 0)
if(hrand((room_y) * 8) < y)
place_small(x, y);
for(int y=room_y/2-2; y<room_y/2+2; y++)
for(int x=room_x/2-2; x<room_x/2+2; x++)
block_at[y][x] = 0;
infile = false;
}
void room::reveal(int cx, int cy) {
if(cx < 0 || cy < 0 || cx >= 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_y; y++)
for(int x=0; x<room_x; x++)
if(x == 0 || y == 0 || x == room_x-1 || y == room_y-1) {
int len = max(abs(x-sx), abs(y - sy)) * 2;
auto sh = to_hyper((sx+0.5)*block_x, (sy+0.5)*block_y);
auto th = to_hyper((x+0.5)*block_x, (y+0.5)*block_y);
for(int l=0; l<len; l++) {
auto h = lerp(sh, th, l * 1. / len);
auto xy = from_hyper(h);
int cx = int(xy.first / block_x);
int cy = int(xy.second / block_y);
if(cx < 0 || cy < 0 || cx >= 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;
}
}

381
rogueviz/ru/ru.cpp Normal file
View File

@ -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; i<KEYSTATES; i++) last_keystate[i] = cur_keystate[i], cur_keystate[i] = keystate[i];
}
void editmap_frame() {
if(keyheld('1'))
current_room->place_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; i<qwall; i++) {
dialog::addItem(walls[i].name, 'a'+i);
dialog::add_action([i] { sel = i; popScreen(); });
}
dialog::display();
});
if(keypressed('f')) floodfill(mousepx / block_x, mousepy / block_y);
}
void playing_frame() {
m.act();
auto& ents = current_room->entities;
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<int>(67);
for(auto& p: rooms) {
f.write(mapstream::cellids[p.first]);
for(int y=0; y<room_y; y++)
for(int x=0; x<room_x; x++)
f.write(p.second.block_at[y][x]);
f.write<int>(0);
}
f.write<int>(-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<int>();
if(i == -1) break;
auto r = get_room_at(mapstream::cellbyid[i]);
for(int y=0; y<room_y; y++)
for(int x=0; x<room_x; x++)
f.read(r->block_at[y][x]);
r->clearfov();
r->infile = true;
f.get<int>();
}
int id = f.get<int>();
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");
}
});
}

142
rogueviz/ru/save.cpp Normal file
View File

@ -0,0 +1,142 @@
namespace rogue_unlike {
map<cell*, int> in_queue;
queue<cell*> 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<int, char> code_for;
map<char, int> code_used;
char next_code = 'A';
for(int y=0; y<room_y; y++)
for(int x=0; x<room_x; x++) {
auto i = r.block_at[y][x] >> 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<room_y; y++) {
for(int x=0; x<room_x; x++) {
auto v = r.block_at[y][x];
print(f, format("%c", (v & 7) == 7 ? 'b' : code_for[v>>3]));
}
println(f);
}
println(f, "OK\n");
for(int i=0; i<c->type; 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<char, int> 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<qwall; i++) if(walls[i].name == t) {
codes[s[0]] = i;
break;
}
}
if(1) {
vector<string> bmap;
for(int y=0; y<room_y; y++) bmap.push_back(scanline_noblank(f));
for(int y=0; y<room_y; y++) for(int x=0; x<room_x; x++) {
if(bmap[y][x] == 'b') ;
else if(y < room_y-1 && bmap[y+1][x] == 'b') ;
else if(x < room_x-1 && bmap[y][x+1] == 'b') ;
else if(y < room_y-1 && x < room_x-1 && bmap[y+1][x+1] == 'b')
r.place_block_full(x, y, 8 * codes.at(bmap[y][x]) + 4);
else
r.place_block_full(x, y, 8 * codes.at(bmap[y][x]));
}
}
while(true) {
s = scanline_noblank(f);
if(s == "OK") break;
println(hlog, "s = ", s);
auto pos = s.find(" ");
if(pos != string::npos) {
string cap = s.substr(0, pos);
string param = s.substr(pos+1);
if(cap == "START") {
current_room = &r;
sscanf(param.c_str(), "%lf%lf", &m.where_x, &m.where_y);
}
else if(cap == "ITEM") {
auto b = std::make_unique<item>();
sscanf(param.c_str(), "%lf%lf", &b->where_x, &b->where_y);
s = scanline_noblank(f);
b->id = -1;
for(int i=0; i<isize(powers); i++) if(powers[i].name == s) b->id = 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);
}
}
}