1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2026-01-01 18:09:04 +00:00

implemented three more health powers

This commit is contained in:
Zeno Rogue
2025-12-23 18:09:34 +01:00
parent 0eba87676e
commit da166fdd3e
7 changed files with 91 additions and 11 deletions

View File

@@ -28,7 +28,7 @@ struct randeff {
void hs(struct stater& s);
};
enum class mod { burning, freezing, disarming };
enum class mod { burning, freezing, disarming, vampire };
struct power {
int key;
@@ -379,6 +379,8 @@ struct man : public entity {
entity *morphed = nullptr;
vector<effect> effects;
int vampire, protection, healbubble;
int last_action;
int experience;
@@ -420,6 +422,8 @@ struct man : public entity {
addMessage("OUCH! These spikes hurt!");
}
bool reduce_hp(int x) override;
void launch_attack(power *p, int fac, boxfun f);
virtual void hs(stater& s);
@@ -688,6 +692,17 @@ struct kestrel : public enemy {
xy default_vel() override { return respawn_vel; }
};
struct healthbubble : public entity {
ld power;
xy siz() override { return {10, 10}; }
string glyph() override { return "o"; }
color_t color() override { return 0xA04040FF; }
void act() override;
string get_name() override { return "health bubble"; }
string get_help() override { return "Can be catched to replenish your health."; }
virtual void hs(stater& s) override { entity::hs(s); s.act("power", power, 0); }
};
struct gridbug : public enemy {
int next_move;
xy siz() override { return {10, 10}; }

View File

@@ -691,6 +691,19 @@ void kestrel::act() {
}
}
void healthbubble::act() {
stay_on_screen();
apply_walls_reflect();
apply_vel();
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid >= invinc_end) {
addMessage("The " + hal()->get_name() + " heals you!");
m.hp += power;
existing = false;
if(m.hp > m.max_hp()) m.hp = m.max_hp();
}
}
void gridbug::act() {
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {

View File

@@ -189,6 +189,8 @@ extern shiftmatrix scrm;
struct hr_name_error : hr_exception { hr_name_error(const char *s) : hr_exception(s) {} };
extern vector<unique_ptr<struct entity>> new_entities;
string unspace(const string& s);
string respace(const string& s);

View File

@@ -86,6 +86,9 @@ void man::hs(stater& s) {
sdata(next, "next.");
entity::hs(s);
s.act("protection", protection, 0);
s.act("vampire", vampire, 0);
s.act("healbubble", healbubble, 0);
}
void man::act() {
@@ -131,6 +134,32 @@ void man::act() {
check_fountains();
}
bool man::reduce_hp(int x) {
if(protection && gframeid >= invinc_end) {
ld fraction = 1 - 100 / (protection + 100);
int take = ceil(x * fraction);
if(take > protection) take = protection;
protection -= take;
x -= protection;
}
if(healbubble && gframeid >= invinc_end) {
int take = x;
if(take > healbubble) take = healbubble;
healbubble -= take;
auto d = m.get_dat();
auto mi = std::make_unique<healthbubble>();
mi->id = "HEALBUBBLE";
ld r = (rand() % 360) * degree;
mi->hs(fountain_resetter);
mi->power = take * 2;
mi->where = m.where;
mi->vel = { cos(r) * d.modv * 3, sin(r) * d.modv * 3 };
mi->invinc_end = gframeid + 300;
new_entities.emplace_back(std::move(mi));
}
return entity::reduce_hp(x);
}
bool man::can_see(entity& e) {
if(m.current.detect_area) {
ld d = hdist(to_hyper(m.where), to_hyper(e.where));
@@ -179,11 +208,16 @@ void man::launch_attack(power *p, int fac, boxfun f) {
for(auto& e: current_room->entities)
if(e->existing && intersect(e->get_pixel_bbox(), pb)) {
int sav = e->invinc_end;
e->attacked((m.current.stats[stat::str] + 1) * 3 / 2);
for(auto& [m, qty]: p->mods) {
if(m == mod::burning) { e->invinc_end = sav; e->attacked(qty); }
if(m == mod::freezing) { e->invinc_end = sav; e->attacked(qty); }
if(m == mod::disarming && e->hidden()) {
int dam = (m.current.stats[stat::str] + 1) * 3 / 2;
e->attacked(dam);
for(auto& [md, qty]: p->mods) {
if(md == mod::burning) { e->invinc_end = sav; e->attacked(qty); }
if(md == mod::freezing) { e->invinc_end = sav; e->attacked(qty); }
if(md == mod::vampire) {
int dam1 = min(dam, m.vampire);
hp += dam1; m.vampire -= dam1;
}
if(md == mod::disarming && e->hidden()) {
e->existing = false;
addMessage("You have disarmed a "+e->hal()->get_name()+".");
}

View File

@@ -32,12 +32,14 @@ power& power::be_weapon() {
if(m == mod::burning) s = "flaming " + s;
if(m == mod::freezing) s = "freezing " + s;
if(m == mod::disarming) s = "disarming " + s;
if(m == mod::vampire) s = "vampiric " + s;
}
return s;
};
auto gc = get_color; get_color = [gc, this] {
auto col = gc();
for(auto& [m, qty]: mods) {
if(m == mod::vampire) col = 0x802020FF;
if(m == mod::disarming) col = 0x4040C0FF;
if(m == mod::burning) col = gradient(0xFFFF00FF, 0xFF0000FF, -1, sin(ticks/100), 1);
if(m == mod::freezing) col = 0x8080FFFF;

View File

@@ -103,13 +103,17 @@ randeff health_regen("Regeneration", "Heals you over a period of time.", "You fe
}
});
randeff health_protect("Protection", "Makes you more resistant to damage.", "You feel protected!", [] (data &d) {
// m.protection += 3 * m.current.stats[stat::wis] + m.hp * m.current.stats[stat::wis] * 2 / 100;
m.protection += 3 * m.current.stats[stat::wis] + m.hp * m.current.stats[stat::wis] * 2 / 100;
});
randeff health_vampire("Vampirism", "Attacks with your [weapon] restore your health.", "Your [weapon] wants blood!", [] (data &d) {
// m.vampire += 4 * m.current.stats[stat::wis] + m.max_hp() * m.current.stats[stat::wis] * 3 / 100;
if(d.mode == rev::start)
m.vampire += 4 * m.current.stats[stat::wis] + m.max_hp() * m.current.stats[stat::wis] * 3 / 100;
if(d.mode == rev::active && m.vampire)
m.next.mods.emplace_back(d.re->which_weapon, mod::vampire, 2 * m.current.stats[stat::wis] + 1e-6);
});
randeff health_bubbles("Bubbles", "When you are attacked, you produce red bubbles that you can collect to heal yourself back.", "You feel something bouncy growing inside you!", [] (data &d) {
// m.healbubbles += 4 * m.current.stats[stat::wis] + m.max_hp() * m.current.stats[stat::wis] * 3 / 100;
if(d.mode == rev::start)
m.healbubble += 4 * m.current.stats[stat::wis] + m.max_hp() * m.current.stats[stat::wis] * 3 / 100;
});
// fire powers
@@ -181,7 +185,7 @@ void assign_potion_powers() {
fire_weapon.which_weapon = wpn[0];
trap_disarm.which_weapon = wpn[1];
using relist = vector<randeff*>;
find_power("health").randeffs = relist{ pick(&health_heal, &health_regen, &health_protect), random_powers[0] };
find_power("health").randeffs = relist{ pick(&health_heal, &health_regen, &health_protect, &health_vampire, &health_bubbles, &health_protect), random_powers[0] };
find_power("the thief").randeffs = relist{ pick(&trap_detect, &trap_snake, &trap_disarm, &trap_detect_cross), random_powers[1] };
find_power("polymorph").randeffs = relist{ pick(&morph_cat, &morph_capy), random_powers[2] };
find_power("reach").randeffs = relist{ pick(&jump_double, &jump_high, &jump_bubble, &jump_light), random_powers[3] };

View File

@@ -145,6 +145,8 @@ tuple<xy, ld, int> get_next_room(xy w, room *r, int which) {
return {w, 1, -1};
}
vector<unique_ptr<struct entity>> new_entities;
void playing_frame() {
m.act();
@@ -156,6 +158,9 @@ void playing_frame() {
for(auto& e: ents) if(!e->destroyed) *(mb++) = std::move(e);
ents.resize(mb - ents.begin());
for(auto &e: new_entities) ents.push_back(std::move(e));
new_entities.clear();
if(one_room) return;
auto [w1, vmul, cr] = get_next_room(m.where, current_room);
@@ -283,7 +288,12 @@ void run() {
if(cmode == mode::playing) {
titlecolor = 0xFFFFFF;
mouseovers = current_room->roomname;
displayfr(vid.fsize, vid.fsize, 2, vid.fsize, "HP " + its(m.hp) + "/" + its(m.max_hp()), titlecolor, 0);
shstream ss;
print(ss, "HP ", m.hp, "/", m.max_hp());
if(m.vampire) print(ss, " V");
if(m.healbubble) print(ss, " B");
if(m.protection) print(ss, " P");
displayfr(vid.fsize, vid.fsize, 2, vid.fsize, ss.s, titlecolor, 0);
if(current_target && current_target->existing)
displayfr(vid.xres - vid.fsize, vid.fsize, 2, vid.fsize, "HP " + its(current_target->hp) + "/" + its(current_target->max_hp()) + " " + current_target->get_name(), titlecolor, 16);
}