mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2026-07-04 17:32:43 +00:00
ru:: loading saved games is now available
This commit is contained in:
@@ -94,7 +94,7 @@ struct room {
|
||||
string id, roomname;
|
||||
renderbuffer *rbuf;
|
||||
cell *where;
|
||||
short block_at[room_y][room_x];
|
||||
array<array<short, room_x>, room_y> block_at, orig_block_at;
|
||||
bool fov[room_y][room_x];
|
||||
bool which_map_rendered;
|
||||
|
||||
@@ -338,6 +338,8 @@ struct entity {
|
||||
virtual bool hit_by_missile(missile *m) { return false; }
|
||||
|
||||
virtual void on_fountain();
|
||||
|
||||
virtual void on_reset_all() {}
|
||||
};
|
||||
|
||||
struct statdata {
|
||||
@@ -605,6 +607,7 @@ struct ghost : public enemy {
|
||||
s.act("extra_invinc", extra_invinc, 2 * game_fps).
|
||||
only_full().act("flipped", flipped, false).act("xp", ghost_xp, 50).act("hp", ghost_hp, 100).act("where", where, {0, 0});
|
||||
}
|
||||
void on_reset_all() override { destroyed = true; }
|
||||
};
|
||||
|
||||
struct snake : public enemy {
|
||||
@@ -633,6 +636,7 @@ struct disnake : public snake {
|
||||
void unact() override { destroyed = true; }
|
||||
int bite() override { return 5; }
|
||||
void on_fountain() override { destroyed = true; }
|
||||
void on_reset_all() override { destroyed = true; }
|
||||
virtual void hs(stater& s) override { snake::hs(s); s.act("respawn", respawn, {0, 0}); }
|
||||
};
|
||||
|
||||
@@ -788,6 +792,7 @@ struct loot : public item {
|
||||
|
||||
struct ghost_item : public item {
|
||||
virtual void hs(stater& s) override { item::hs(s); s.act("respawn", respawn, {0, 0}).act("qty", qty, 0); }
|
||||
void on_reset_all() override { destroyed = true; }
|
||||
};
|
||||
|
||||
struct missile : public entity {
|
||||
@@ -801,6 +806,7 @@ struct missile : public entity {
|
||||
struct missile* as_missile() override { return this; }
|
||||
virtual void hs(stater& s) override { entity::hs(s); s.act("power", power, 0).act("where", where, {0, 0}); }
|
||||
void on_fountain() override { destroyed = true; }
|
||||
void on_reset_all() override { destroyed = true; }
|
||||
};
|
||||
|
||||
struct ice_missile : public missile {
|
||||
|
||||
@@ -331,6 +331,7 @@ void load_map(string fname) {
|
||||
else err("load_map", s);
|
||||
}
|
||||
for(auto& [c,r]: rooms) {
|
||||
r.orig_block_at = r.block_at;
|
||||
for(auto& e: r.entities) {
|
||||
e->hs(resetter);
|
||||
if(e->id != "") {
|
||||
|
||||
+18
-16
@@ -10,7 +10,7 @@ room *stable_room;
|
||||
xy stable_where;
|
||||
|
||||
void regenerate_all() {
|
||||
m.hs(fountain_resetter);
|
||||
m.hp = m.max_hp();
|
||||
for(auto& p: powers) p.refill();
|
||||
for(auto& r: rooms) for(auto& e: r.second.entities) e->on_fountain();
|
||||
revert_all(fountain_revert);
|
||||
@@ -57,33 +57,35 @@ man::man() {
|
||||
}
|
||||
|
||||
void man::hs(stater& s) {
|
||||
entity::hs(s);
|
||||
s.act("facing", facing, 1)
|
||||
auto& s1 = s.only_full();
|
||||
s1.act("facing", facing, 1)
|
||||
.act("attack_facing", attack_facing, 1)
|
||||
.act("attack_when", attack_when, 0)
|
||||
.act("on_floor_when", on_floor_when, 0)
|
||||
.act("xp", experience, 0)
|
||||
.act("last_action", last_action, 0);
|
||||
sact(s, "hair", hair);
|
||||
sact(s, "eyes", eye);
|
||||
sact(s1, "hair", hair);
|
||||
sact(s1, "eyes", eye);
|
||||
string z = unspace(backstory);
|
||||
s.act("backstory", z, "");
|
||||
s1.act("backstory", z, "");
|
||||
backstory = respace(z);
|
||||
int prof = (int) profession; s.act("profession", prof, -1); profession = (stat) prof;
|
||||
for(auto st: allstats) s.act(statinfos[st].name, base_stats[st], 10);
|
||||
int prof = (int) profession; s1.act("profession", prof, -1); profession = (stat) prof;
|
||||
for(auto st: allstats) s1.act(statinfos[st].name, base_stats[st], 10);
|
||||
|
||||
auto sdata = [&s] (statdata& sd, string prefix) {
|
||||
for(auto st: allstats) s.act(prefix + statinfos[st].name, sd.stats[st], 10);
|
||||
s.act(prefix + "jump_control", sd.jump_control, 0);
|
||||
s.act(prefix + "coyote_time", sd.coyote_time, 0);
|
||||
s.act(prefix + "hallucinating", sd.hallucinating, 0);
|
||||
s.act(prefix + "detect_area", sd.detect_area, 0);
|
||||
s.act(prefix + "detect_cross", sd.detect_cross, 0);
|
||||
s.act(prefix + "rough_detect", sd.rough_detect, 0);
|
||||
auto sdata = [&s1] (statdata& sd, string prefix) {
|
||||
for(auto st: allstats) s1.act(prefix + statinfos[st].name, sd.stats[st], 10);
|
||||
s1.act(prefix + "jump_control", sd.jump_control, 0);
|
||||
s1.act(prefix + "coyote_time", sd.coyote_time, 0);
|
||||
s1.act(prefix + "hallucinating", sd.hallucinating, 0);
|
||||
s1.act(prefix + "detect_area", sd.detect_area, 0);
|
||||
s1.act(prefix + "detect_cross", sd.detect_cross, 0);
|
||||
s1.act(prefix + "rough_detect", sd.rough_detect, 0);
|
||||
};
|
||||
|
||||
sdata(current, "curr.");
|
||||
sdata(next, "next.");
|
||||
|
||||
entity::hs(s);
|
||||
}
|
||||
|
||||
void man::act() {
|
||||
|
||||
@@ -142,6 +142,7 @@ randeff morph_cat("Cat", "Turns you into a cat.", "You turn into a cat!", [] (da
|
||||
}
|
||||
else {
|
||||
auto mcat = new cat;
|
||||
mcat->id = "cat";
|
||||
mcat->col = morph_cat_color;
|
||||
m.morphed = mcat;
|
||||
addMessage("You morph into a " + m.morphed->get_name() + "!");
|
||||
@@ -156,6 +157,7 @@ randeff morph_capy("Capybara", "Turns you into a capybara.", "You turn into a ca
|
||||
}
|
||||
else {
|
||||
m.morphed = new capybara;
|
||||
m.morphed->id = "capy";
|
||||
addMessage("You morph into a lovely capybara!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,6 +393,7 @@ void enable() {
|
||||
geometry = gBinary4;
|
||||
showstartmenu = false;
|
||||
|
||||
init_stats();
|
||||
set_sval();
|
||||
init_scales();
|
||||
gen_powers();
|
||||
@@ -496,6 +497,7 @@ void start_new_game() {
|
||||
|
||||
auto chk = arg::add3("-ru", enable)
|
||||
+ arg::add3("-ru-start", start_new_game)
|
||||
+ arg::add3("-ru-load", [] { arg::shift(); enable(); load_from(arg::args()); })
|
||||
+ arg::add3("-ru-cheat", [] { arg::shift(); load_cheat(arg::args()); })
|
||||
+ addHook(mapstream::hooks_loadmap, 100, [] (hstream& f, int id) {
|
||||
if(id == 67) {
|
||||
|
||||
+152
-6
@@ -33,8 +33,10 @@ template<class T> void save_via_stater(fhstream& f, T& t, string cat, bool alway
|
||||
}
|
||||
}
|
||||
|
||||
void save() {
|
||||
fhstream f(save_name, "wt");
|
||||
void save_as(string fname) {
|
||||
fhstream f(fname, "wt");
|
||||
|
||||
println(f, "TIME ", gframeid);
|
||||
|
||||
save_via_stater(f, m, "MAN", false);
|
||||
|
||||
@@ -55,11 +57,17 @@ void save() {
|
||||
|
||||
if(!seen_count) continue;
|
||||
|
||||
println(f, "ROOM ", r.roomname);
|
||||
shstream ss;
|
||||
println(f, "ROOM ", r.id);
|
||||
string code;
|
||||
for(int y=0; y<room_y; y++)
|
||||
for(int x=0; x<room_y; x++) println(ss, r.fov[y][x] ? '1' : '0');
|
||||
println(f, as_hexstring(compress_string(ss.s)));
|
||||
for(int x=0; x<room_y; x++) code += (r.fov[y][x] ? '1' : '0');
|
||||
println(f, as_hexstring(compress_string(code)));
|
||||
|
||||
if(&r == current_room) println(f, "HERE");
|
||||
|
||||
for(int y=0; y<room_y; y++)
|
||||
for(int x=0; x<room_y; x++) if(r.block_at[y][x] != r.orig_block_at[y][x])
|
||||
println(f, "AT ", y, " ", x, " ", r.block_at[y][x]);
|
||||
|
||||
for(auto& e: r.entities) save_via_stater(f, *e, "ENTITY");
|
||||
println(f);
|
||||
@@ -78,4 +86,142 @@ void save() {
|
||||
}
|
||||
}
|
||||
|
||||
void save() {
|
||||
save_as(save_name);
|
||||
}
|
||||
|
||||
void reset_all() {
|
||||
m.hs(resetter);
|
||||
for(auto& p: powers) p.hs(resetter);
|
||||
for(auto r: *all_effects) r.second->hs(resetter);
|
||||
fountain_revert.clear();
|
||||
death_revert.clear();
|
||||
|
||||
for(auto& [c,r]: rooms) {
|
||||
for(auto& e: r.entities) { e->on_reset_all(); e->hs(resetter); }
|
||||
|
||||
for(int y=0; y<room_y; y++)
|
||||
for(int x=0; x<room_y; x++) {
|
||||
r.fov[y][x] = false;
|
||||
}
|
||||
r.block_at = r.orig_block_at;
|
||||
}
|
||||
}
|
||||
|
||||
void load_reverts(fhstream& f, revert_stack& stack) {
|
||||
string s;
|
||||
while(true) {
|
||||
s = scanline_noblank(f);
|
||||
if(s == "") return;
|
||||
s += " ";
|
||||
revert_type rev;
|
||||
string cur = "";
|
||||
for(char c: s) if(c == ' ') rev.push_back(cur), cur = ""; else cur += c;
|
||||
stack.push_back(rev);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> void load_hs(fhstream &f, T& t) {
|
||||
string s;
|
||||
while(true) {
|
||||
s = scanline_noblank(f);
|
||||
if(s == "") return;
|
||||
auto pos = s.find("=");
|
||||
if(pos == string::npos) { println(hlog, "warning: incorrect HS line: ", s); return; }
|
||||
loader l;
|
||||
l.name = s.substr(0, pos);
|
||||
l.value = s.substr(pos + 1);
|
||||
t.hs(l);
|
||||
if(!l.loaded) println(hlog, "warning: could not read hs: ", s, " for entity with ID: ", t.id);
|
||||
}
|
||||
}
|
||||
|
||||
void load_from(string fname) {
|
||||
reset_all();
|
||||
fhstream f(fname, "rt");
|
||||
|
||||
room *current_room = nullptr;
|
||||
power *current_power = nullptr;
|
||||
entity* current_entity = nullptr;
|
||||
|
||||
string s;
|
||||
while(!feof(f.f)) {
|
||||
s = scanline_noblank(f);
|
||||
if(s == "") continue;
|
||||
auto pos = s.find(" ");
|
||||
if(pos == string::npos) {
|
||||
if(s == "HERE") { if(!current_room) { println(hlog, "warning: no current room"); continue; } rogue_unlike::current_room = current_room; }
|
||||
else if(s == "FOUNTAINS")
|
||||
load_reverts(f, fountain_revert);
|
||||
else if(s == "DEATH")
|
||||
load_reverts(f, death_revert);
|
||||
else
|
||||
println(hlog, "warning: ill-formed string in save: ", s); continue;
|
||||
}
|
||||
string cap = s.substr(0, pos);
|
||||
string param = s.substr(pos+1);
|
||||
if(cap == "TIME") {
|
||||
sscanf(param.c_str(), "%d", &gframeid);
|
||||
}
|
||||
else if(cap == "ROOM") {
|
||||
try {
|
||||
current_room = find_room_by_id(param);
|
||||
string code = decompress_string(from_hexstring(scanline_noblank(f)));
|
||||
int pos = 0;
|
||||
for(int y=0; y<room_y; y++) for(int x=0; x<room_y; x++) current_room->fov[y][x] = code[pos++] == '1';
|
||||
}
|
||||
catch(hr_name_error& e) {
|
||||
println(hlog, "warning: could not find room: ", param);
|
||||
}
|
||||
}
|
||||
else if(cap == "AT") {
|
||||
if(!current_room) { println(hlog, "warning: no current room"); continue; }
|
||||
int x, y, c;
|
||||
sscanf(param.c_str(), "%d%d%d", &x, &y, &c);
|
||||
current_room->block_at[y][x] = c;
|
||||
}
|
||||
else if(cap == "ENTITY") {
|
||||
if(!current_room) { println(hlog, "warning: no current room"); continue; }
|
||||
auto add = [&] (std::unique_ptr<entity>&& e) { current_room->entities.emplace_back(std::move(e)); current_entity = &*(current_room->entities.back()); };
|
||||
if(param == "GHOST") add(std::make_unique<ghost>());
|
||||
else if(param == "BONES") add(std::make_unique<ghost_item>());
|
||||
else if(param == "FIREMISSILE") add(std::make_unique<fire_missile>());
|
||||
else if(param == "DISNAKE") add(std::make_unique<disnake>());
|
||||
else try { current_entity = find_entity_by_id(param); } catch(hr_name_error& e) { current_entity = nullptr; continue; }
|
||||
load_hs(f, *current_entity);
|
||||
}
|
||||
else if(cap == "MORPH") {
|
||||
if(param == "cat") { m.morphed = new cat; load_hs(f, *m.morphed); }
|
||||
else if(param == "capy") { m.morphed = new capybara; load_hs(f, *m.morphed); }
|
||||
}
|
||||
else if(cap == "MAN") {
|
||||
load_hs(f, m);
|
||||
}
|
||||
else if(cap == "POWER") {
|
||||
current_power = nullptr;
|
||||
try {
|
||||
current_power = &find_power_by_id(param);
|
||||
load_hs(f, *current_power);
|
||||
current_power->randeffs = {};
|
||||
}
|
||||
catch(hr_name_error& e) {
|
||||
println(hlog, "warning: unknown power: ", param);
|
||||
}
|
||||
}
|
||||
else if(cap == "EFFECT") {
|
||||
if(!all_effects->count(param)) {
|
||||
println(hlog, "warning: unknown effect: ", param);
|
||||
}
|
||||
else {
|
||||
randeff* current_effect = (*all_effects)[param];
|
||||
if(current_power) current_power->randeffs.push_back(current_effect);
|
||||
load_hs(f, *current_effect);
|
||||
}
|
||||
}
|
||||
else {
|
||||
println(hlog, "warning: could not understand save line: ", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,8 +91,7 @@ statarray<statinfo> profdata;
|
||||
|
||||
vector<string> professions = { "Warrior", "Morpher", "Sorcerer", "Rogue" };
|
||||
|
||||
void stat_screen(bool editable) {
|
||||
|
||||
void init_stats() {
|
||||
statinfos[stat::str] = {'s', "Strength", "Affects the strength of your physical attacks."};
|
||||
statinfos[stat::con] = {'t', "Toughness", "Affects the amount of hitpoints you have."};
|
||||
statinfos[stat::wis] = {'w', "Wisdom", "Affects the power of your alchemy."};
|
||||
@@ -102,6 +101,9 @@ void stat_screen(bool editable) {
|
||||
profdata[stat::con] = {'m', "Morpher", "Morpher start with an ability to transform into small animals."};
|
||||
profdata[stat::wis] = {'s', "Sorcerer", "Sorcerers start with an ability to cast fire spells."};
|
||||
profdata[stat::dex] = {'r', "Rogue", "Rogues start with an ability to detect hidden passages and traps."};
|
||||
}
|
||||
|
||||
void stat_screen(bool editable) {
|
||||
|
||||
render_the_map();
|
||||
draw_inventory_frame();
|
||||
|
||||
Reference in New Issue
Block a user