mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-06-26 07:02:49 +00:00
implemented the magic fountains (except ghosts and bones mechanics)
This commit is contained in:
parent
1e23eed4e3
commit
2ae913ccfa
@ -25,7 +25,7 @@ struct power {
|
||||
flagtype flags;
|
||||
int random_flavor;
|
||||
void init();
|
||||
hr::function<void(data&)> act, paused_act;
|
||||
hr::function<void(data&)> act, paused_act, dead_act;
|
||||
hr::function<string()> get_name;
|
||||
hr::function<string()> get_desc;
|
||||
hr::function<string()> get_glyph;
|
||||
@ -37,6 +37,7 @@ struct power {
|
||||
power& be_weapon();
|
||||
power& be_resource(string plural);
|
||||
power& while_paused();
|
||||
power& while_dead();
|
||||
power& identified_name(string, string);
|
||||
power& be_wearable(string wear_effect, string remove_effect);
|
||||
power& be_jewelry(string jtype, string desc);
|
||||
@ -44,6 +45,11 @@ struct power {
|
||||
};
|
||||
|
||||
extern vector<power> powers;
|
||||
extern power *extra_life;
|
||||
|
||||
flagtype IDENTIFIED = Flag(1);
|
||||
flagtype ACTIVE = Flag(2);
|
||||
flagtype PARTIAL = Flag(4);
|
||||
|
||||
struct bbox {
|
||||
int minx, miny, maxx, maxy;
|
||||
@ -230,9 +236,10 @@ struct entity {
|
||||
}
|
||||
|
||||
virtual bool reduce_hp(int x) {
|
||||
if(hp < 0) return false;
|
||||
if(gframeid < invinc_end) return false;
|
||||
hp -= x;
|
||||
if(hp < 0) on_kill();
|
||||
if(hp <= 0) on_kill();
|
||||
invinc_end = gframeid + 150;
|
||||
return true;
|
||||
}
|
||||
@ -270,6 +277,8 @@ struct man : public entity {
|
||||
virtual bool hurt_by_spikes() { return true; }
|
||||
string get_name() override { return "alchemist"; }
|
||||
string get_help() override { return "This is you."; }
|
||||
|
||||
void on_kill() override;
|
||||
};
|
||||
|
||||
extern man m;
|
||||
@ -403,6 +412,9 @@ struct item : public entity {
|
||||
kino();
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
addMessage(pickup_message);
|
||||
int q0 = powers[id].qty_filled;
|
||||
int q1 = powers[id].qty_owned;
|
||||
add_revert(death_revert, [this, q0, q1] { existing = true; powers[id].qty_filled = q0; powers[id].qty_owned = q1; });
|
||||
powers[id].picked_up(qty);
|
||||
existing = false;
|
||||
}
|
||||
|
@ -148,4 +148,12 @@ void asciiletter(ld minx, ld miny, ld maxx, ld maxy, const string& ch, color_t c
|
||||
void render_the_map();
|
||||
void shuffle_all();
|
||||
|
||||
using revert_stack = vector<reaction_t>;
|
||||
|
||||
revert_stack death_revert, fountain_revert;
|
||||
|
||||
void add_revert(revert_stack& s, const reaction_t& what);
|
||||
|
||||
void revert_all(revert_stack& s);
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,16 @@ void handle_powers(data& d);
|
||||
|
||||
bool on_fountain;
|
||||
room *fountain_room;
|
||||
xy fountain_where;
|
||||
|
||||
void regenerate_all() {
|
||||
m.hp = m.max_hp();
|
||||
for(auto& p: powers) p.refill();
|
||||
for(auto& r: rooms) for(auto& e: r.second.entities) e->regenerate();
|
||||
revert_all(fountain_revert);
|
||||
current_target = nullptr;
|
||||
shuffle_all();
|
||||
}
|
||||
|
||||
void check_fountains() {
|
||||
bool next_on_fountain = false;
|
||||
@ -14,13 +24,12 @@ void check_fountains() {
|
||||
if(b == wFountain) next_on_fountain = true;
|
||||
}
|
||||
if(next_on_fountain && !on_fountain) {
|
||||
fountain_room = current_room;
|
||||
if(extra_life->flags & ACTIVE) {
|
||||
fountain_room = current_room;
|
||||
fountain_where = m.where;
|
||||
}
|
||||
addMessage("A magic fountain! You feel safe and refill your potions.");
|
||||
m.hp = m.max_hp();
|
||||
for(auto& p: powers) p.refill();
|
||||
for(auto& r: rooms) for(auto& e: r.second.entities) e->regenerate();
|
||||
current_target = nullptr;
|
||||
shuffle_all();
|
||||
regenerate_all();
|
||||
}
|
||||
swap(on_fountain, next_on_fountain);
|
||||
}
|
||||
@ -58,4 +67,20 @@ void man::act() {
|
||||
check_fountains();
|
||||
}
|
||||
|
||||
void man::on_kill() {
|
||||
entity::on_kill();
|
||||
if(extra_life->flags & ACTIVE)
|
||||
addMessage("You die... Press [key:Extra Life] to revive.");
|
||||
else
|
||||
addMessage("You die... permanently. You will have to create a new character. Or just press [key:Extra Life] for a narrative cheat.");
|
||||
}
|
||||
|
||||
void add_revert(revert_stack& s, const reaction_t& what) {
|
||||
s.push_back(what);
|
||||
}
|
||||
|
||||
void revert_all(revert_stack& s) {
|
||||
while(!s.empty()) { s.back()(); s.pop_back(); }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
namespace rogue_unlike {
|
||||
|
||||
flagtype IDENTIFIED = Flag(1);
|
||||
flagtype ACTIVE = Flag(2);
|
||||
flagtype PARTIAL = Flag(4);
|
||||
|
||||
data fakedata;
|
||||
|
||||
power& power::is_starting() { qty_filled = qty_owned = 1; return self; }
|
||||
|
||||
power& power::while_paused() { paused_act = act; return self; }
|
||||
power& power::while_paused() { paused_act = act; dead_act = act; return self; }
|
||||
|
||||
power& power::while_dead() { dead_act = act; return self; }
|
||||
|
||||
power& power::identified_name(string s, string desc) {
|
||||
auto gn = get_name;
|
||||
@ -122,6 +120,7 @@ void power::init() {
|
||||
flags = 0;
|
||||
act = [this] (data& d) { pf(d); };
|
||||
paused_act = [] (data&) {};
|
||||
dead_act = [] (data&) {};
|
||||
get_name = [this] { return name; };
|
||||
get_desc = [this] { return desc; };
|
||||
get_color = [this] { return color; };
|
||||
@ -144,17 +143,47 @@ power& gen_power(int key, string name, string desc, string glyph, color_t color,
|
||||
return p;
|
||||
}
|
||||
|
||||
power *extra_life;
|
||||
|
||||
void gen_powers() {
|
||||
powers.reserve(100);
|
||||
|
||||
gen_power('1', "Extra Life",
|
||||
extra_life = &gen_power('1', "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, when you drink it, "
|
||||
"you drink it automatically whenever you are at a magical fountain.",
|
||||
"!", 0xFFFF00FF,
|
||||
[] (data& d) { d.p->flags |= IDENTIFIED; }
|
||||
).is_starting().be_potion(),
|
||||
[] (data& d) {
|
||||
d.p->flags |= IDENTIFIED;
|
||||
if(d.keystate == 1) {
|
||||
if(!m.existing) {
|
||||
revert_all(death_revert);
|
||||
regenerate_all();
|
||||
if(!(extra_life->flags & ACTIVE)) extra_life->qty_filled = 0;
|
||||
m.existing = true;
|
||||
m.where = fountain_where;
|
||||
current_room = fountain_room;
|
||||
if(d.p->flags & ACTIVE)
|
||||
addMessage("You wake up at the Magic Fountain.");
|
||||
else
|
||||
addMessage("You wake up from a very bad nightmare. Wow, you are really stressed.");
|
||||
}
|
||||
else if(!d.p->qty_filled)
|
||||
addMessage("You need to find a Magic Fountain to prepare this potion.");
|
||||
else if(d.p->flags & ACTIVE)
|
||||
addMessage("This potion is drank automatically whenever you visit a Magic Fountain.");
|
||||
else if(!on_fountain)
|
||||
addMessage("For safety, you can only drink " + d.p->get_name() + " at the Magic Fountain.");
|
||||
else {
|
||||
d.p->flags = ACTIVE;
|
||||
fountain_room = current_room; fountain_where = m.where;
|
||||
addMessage("You drink the " + d.p->get_name() + " and you feel that nothing will stop you now!");
|
||||
}
|
||||
}
|
||||
}
|
||||
).is_starting().be_potion().while_dead();
|
||||
extra_life->qty_filled = 0;
|
||||
|
||||
gen_power('d', "move right",
|
||||
"A special power of human beings, and most other animals, that they earn early in their life.",
|
||||
@ -212,6 +241,8 @@ void gen_powers() {
|
||||
if(b == wDoor) {
|
||||
current_room->replace_block(x, y, wSmashedDoor);
|
||||
addMessage("You smash the door!");
|
||||
auto cr = current_room;
|
||||
add_revert(fountain_revert, [cr, x, y] { cr->replace_block(x, y, wDoor); });
|
||||
}
|
||||
}
|
||||
}).be_weapon(),
|
||||
@ -374,6 +405,7 @@ void handle_powers(data& d) {
|
||||
if(keywasheld(p.key)) d.keystate |= 2;
|
||||
d.p = &p;
|
||||
if(cmode == mode::paused) p.paused_act(d);
|
||||
else if(!m.existing) p.dead_act(d);
|
||||
else p.act(d);
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ void man::draw() {
|
||||
|
||||
void render_room_objects(room *r) {
|
||||
initquickqueue();
|
||||
if(r == current_room && m.visible_inv()) m.draw();
|
||||
if(r == current_room && m.visible_inv() && m.existing) m.draw();
|
||||
for(auto& e: r->entities)
|
||||
if(e->existing && (cmode == mode::editmap || (e->visible(r) && e->visible_inv())))
|
||||
e->draw();
|
||||
|
@ -105,8 +105,9 @@ void load_room(fhstream& f, cell *c) {
|
||||
string cap = s.substr(0, pos);
|
||||
string param = s.substr(pos+1);
|
||||
if(cap == "START") {
|
||||
current_room = &r;
|
||||
fountain_room = current_room = &r;
|
||||
sscanf(param.c_str(), "%lf%lf", &m.where.x, &m.where.y);
|
||||
fountain_where = m.where;
|
||||
}
|
||||
else if(cap == "ITEM") {
|
||||
auto b = std::make_unique<item>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user