mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2026-10-13 21:01:43 +00:00
ru:: armor actually works now
This commit is contained in:
+12
-3
@@ -249,6 +249,10 @@ struct stater {
|
||||
virtual stater& only_full() { return self; }
|
||||
};
|
||||
|
||||
/* reduce_hp flags */
|
||||
constexpr flagtype NON_DODGEABLE = 1;
|
||||
constexpr flagtype SPIKES = 2;
|
||||
|
||||
struct entity {
|
||||
string id;
|
||||
virtual ~entity() {}
|
||||
@@ -330,7 +334,7 @@ struct entity {
|
||||
virtual void attacked(int s, power *p) {}
|
||||
|
||||
virtual void spiked() {
|
||||
reduce_hp(10);
|
||||
reduce_hp(10, nullptr, NON_DODGEABLE);
|
||||
spike_message();
|
||||
}
|
||||
|
||||
@@ -354,7 +358,7 @@ struct entity {
|
||||
|
||||
virtual int invinc_time() { return 150; }
|
||||
|
||||
virtual bool reduce_hp(int x) {
|
||||
virtual bool reduce_hp(int x, entity *attacker = nullptr, flagtype flags = 0) {
|
||||
if(hp < 0) return false;
|
||||
if(gframeid < invinc_end) return false;
|
||||
hp -= x;
|
||||
@@ -390,6 +394,7 @@ struct statdata {
|
||||
statarray<ld> stats;
|
||||
int jump_control, coyote_time, hallucinating;
|
||||
ld detect_area, detect_cross, rough_detect;
|
||||
int heavy_armor, spikes, max_mageshield, stealth_bonus, dodge_value;
|
||||
void reset();
|
||||
vector<weaponmod> mods;
|
||||
vector<hr::function<void(int&)>> on_hit;
|
||||
@@ -428,6 +433,8 @@ struct man : public entity {
|
||||
|
||||
virtual int max_hp() { return 10 * current.stats[stat::con]; }
|
||||
|
||||
int current_mageshield, mageshield_recharge_time;
|
||||
|
||||
void handle_morph(entity *m);
|
||||
bool can_see(entity& e);
|
||||
man();
|
||||
@@ -457,7 +464,9 @@ struct man : public entity {
|
||||
addMessage("OUCH! These spikes hurt!");
|
||||
}
|
||||
|
||||
bool reduce_hp(int x) override;
|
||||
double stealth_ratio() { return 3 / (3. + current.stealth_bonus); }
|
||||
|
||||
bool reduce_hp(int x, entity *attacker = nullptr, flagtype flags = 0) override;
|
||||
|
||||
void launch_attack(power *p, int fac, boxfun f);
|
||||
|
||||
|
||||
+23
-22
@@ -228,7 +228,7 @@ void entity::apply_walls() {
|
||||
for(int x = jbb.minx; x < jbb.maxx; x++) for(int y = obb.maxy; y < jbb.maxy; y++) {
|
||||
eWall b = current_room->at(x, y);
|
||||
if((walls[b].flags & W_PAIN_DOWN) && hurt_by_spikes()) {
|
||||
reduce_hp(40); spike_message();
|
||||
reduce_hp(40, nullptr, NON_DODGEABLE); spike_message();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ void boar::act() {
|
||||
kino();
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
int s = where.x < m.where.x ? -1 : 1;
|
||||
if(m.reduce_hp(15)) addMessage("The " + hal()->get_name() + " gores you!");
|
||||
if(m.reduce_hp(15, this)) addMessage("The " + hal()->get_name() + " gores you!");
|
||||
auto dat = get_dat();
|
||||
auto mdat = m.get_dat();
|
||||
if(m.on_floor) m.vel.x = mdat.d * mdat.modv * -s * 1.5, m.vel.y = -mdat.d * mdat.modv * 2;
|
||||
@@ -462,15 +462,15 @@ void boar::act() {
|
||||
if(vel.x > 0) vel.x = max<ld>(vel.x - dat.d * dat.moda * 0.05, 0);
|
||||
if(vel.x < 0) vel.x = min<ld>(vel.x + dat.d * dat.moda * 0.05, 0);
|
||||
if(gframeid > invinc_end) {
|
||||
if(intersect(extend(get_pixel_bbox(), 60 * dat.d, 0, 0, 0), m.get_pixel_bbox())) vel.x -= dat.d * dat.moda * 0.2;
|
||||
if(intersect(extend(get_pixel_bbox(), 0, 60 * dat.d, 0, 0), m.get_pixel_bbox())) vel.x += dat.d * dat.moda * 0.2;
|
||||
if(intersect(extend(get_pixel_bbox(), 60 * dat.d * m.stealth_ratio(), 0, 0, 0), m.get_pixel_bbox())) vel.x -= dat.d * dat.moda * 0.2;
|
||||
if(intersect(extend(get_pixel_bbox(), 0, 60 * dat.d * m.stealth_ratio(), 0, 0), m.get_pixel_bbox())) vel.x += dat.d * dat.moda * 0.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enemy::attacked(int dmg, power *p) {
|
||||
current_target = this;
|
||||
if(reduce_hp(dmg)) {
|
||||
if(reduce_hp(dmg, &m)) {
|
||||
if(!existing) addMessage("You kill the " + hal()->get_name() + "."); else addMessage("You hit the " + hal()->get_name() + ".");
|
||||
}
|
||||
}
|
||||
@@ -487,7 +487,7 @@ void frog::act() {
|
||||
kino();
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
int s = where.x < m.where.x ? -1 : 1;
|
||||
if(m.reduce_hp(20)) addMessage("The giant frog crushes you!");
|
||||
if(m.reduce_hp(20, this)) addMessage("The giant frog crushes you!");
|
||||
auto dat = get_dat();
|
||||
auto mdat = m.get_dat();
|
||||
if(m.on_floor) m.vel.x = mdat.d * mdat.modv * -s * 1.5, m.vel.y = -mdat.d * mdat.modv * 2;
|
||||
@@ -497,7 +497,8 @@ void frog::act() {
|
||||
vel.x = 0;
|
||||
if(gframeid > invinc_end) {
|
||||
auto dat = get_dat();
|
||||
if(jphase == 0 && gframeid >= jump_at && intersect(extend(get_pixel_bbox(), 100 * dat.d, 100 * dat.d, 20 * dat.d, 20 * dat.d), m.get_pixel_bbox())) {
|
||||
ld f = m.stealth_ratio();
|
||||
if(jphase == 0 && gframeid >= jump_at && intersect(extend(get_pixel_bbox(), 100 * dat.d * f, 100 * dat.d * f, 20 * dat.d * f, 20 * dat.d * f), m.get_pixel_bbox())) {
|
||||
vel.y = -2 * dat.modv;
|
||||
jphase = 1;
|
||||
}
|
||||
@@ -550,7 +551,7 @@ void ghost::act() {
|
||||
apply_vel();
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
invinc_end = gframeid + 200;
|
||||
if(m.reduce_hp(20)) addMessage("The " + hal()->get_name() + " passes through you!");
|
||||
if(m.reduce_hp(20, this)) addMessage("The " + hal()->get_name() + " passes through you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,7 +566,7 @@ void snake::act() {
|
||||
vel.x = zero_vel.x + dat.d * dat.modv * dir;
|
||||
}
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
if(m.reduce_hp(bite())) addMessage("The " + hal()->get_name() + " bites you!");
|
||||
if(m.reduce_hp(bite(), this)) addMessage("The " + hal()->get_name() + " bites you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,11 +590,11 @@ void naga_warrior::act() {
|
||||
if(gmod(gframeid, 100) == 0) {
|
||||
bbox b = get_pixel_bbox_at(xy{where.x + dir * dsiz().x, where.y});
|
||||
if(intersect(b, m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
if(m.reduce_hp(chop())) addMessage("The " + hal()->get_name() + " chops you!");
|
||||
if(m.reduce_hp(chop(), this)) addMessage("The " + hal()->get_name() + " chops you!");
|
||||
}
|
||||
}
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
if(m.reduce_hp(bite())) addMessage("The " + hal()->get_name() + " bites you!");
|
||||
if(m.reduce_hp(bite(), this)) addMessage("The " + hal()->get_name() + " bites you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +733,7 @@ void saw::act() {
|
||||
where = base->location_at(gframeid);
|
||||
auto bb = get_pixel_bbox();
|
||||
if(intersect(bb, m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(40)) addMessage("The " + get_name() + " shreds you!");
|
||||
if(m.reduce_hp(40, this)) addMessage("The " + get_name() + " shreds you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,7 +819,7 @@ void kestrel::act() {
|
||||
apply_vel();
|
||||
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(chop())) addMessage("The " + hal()->get_name() + " claws you!");
|
||||
if(m.reduce_hp(chop(), this)) addMessage("The " + hal()->get_name() + " claws you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,7 +839,7 @@ void healthbubble::act() {
|
||||
void gridbug::act() {
|
||||
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(15)) addMessage("The " + hal()->get_name() + " zaps you!");
|
||||
if(m.reduce_hp(15, this)) addMessage("The " + hal()->get_name() + " zaps you!");
|
||||
}
|
||||
|
||||
if(gframeid < next_move || !visible(current_room) || gframeid < invinc_end) return;
|
||||
@@ -914,7 +915,7 @@ void bat::act() {
|
||||
apply_vel();
|
||||
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(15)) addMessage("The " + hal()->get_name() + " bites you!");
|
||||
if(m.reduce_hp(15, this)) addMessage("The " + hal()->get_name() + " bites you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,7 +971,7 @@ void guineapig::act() {
|
||||
if(nonblocked(ca+j-3, s).second) {
|
||||
where = nonblocked(ca = gmod(ca+j-3, 8), s).first;
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(15)) {
|
||||
if(m.reduce_hp(15, this)) {
|
||||
addMessage("The " + hal()->get_name() + " bites you!");
|
||||
spindir *= -1;
|
||||
}
|
||||
@@ -1001,7 +1002,7 @@ void vtrap::act() {
|
||||
apply_vel();
|
||||
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(200)) addMessage("The " + hal()->get_name() + " zaps you!");
|
||||
if(m.reduce_hp(200, this)) addMessage("The " + hal()->get_name() + " zaps you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,7 +1063,7 @@ void icicle::act() {
|
||||
}
|
||||
if(state != 0) {
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) {
|
||||
if(m.reduce_hp(50)) addMessage("The " + hal()->get_name() + " falls on you!");
|
||||
if(m.reduce_hp(50, this)) addMessage("The " + hal()->get_name() + " falls on you!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1101,7 +1102,7 @@ void rollingsaw::act() {
|
||||
vel.x = zero_vel.x + dat.d * dat.modv * dir;
|
||||
}
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
if(m.reduce_hp(60)) addMessage("The " + hal()->get_name() + " shreds you!");
|
||||
if(m.reduce_hp(60, this)) addMessage("The " + hal()->get_name() + " shreds you!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1146,7 +1147,7 @@ void fight_trader::attacked(int dmg, power *p) {
|
||||
if(p->flags & WEAPON_AXE) {
|
||||
angered = true;
|
||||
current_target = this;
|
||||
if(reduce_hp(dmg)) {
|
||||
if(reduce_hp(dmg, this)) {
|
||||
if(!existing) addMessage("You kill the " + hal()->get_name() + "."); else addMessage("You hit the " + hal()->get_name() + ".");
|
||||
if(!existing) {
|
||||
walls[wShopDoor].glyph = '\'';
|
||||
@@ -1173,11 +1174,11 @@ void fight_trader::act() {
|
||||
if(gmod(gframeid, 100) == 0) {
|
||||
bbox b = get_pixel_bbox_at(xy{where.x + dir * dsiz().x, where.y});
|
||||
if(intersect(b, m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
if(m.reduce_hp(30)) addMessage("The " + hal()->get_name() + " chops you!");
|
||||
if(m.reduce_hp(30, this)) addMessage("The " + hal()->get_name() + " chops you!");
|
||||
}
|
||||
}
|
||||
if(intersect(get_pixel_bbox(), m.get_pixel_bbox()) && gframeid > invinc_end) {
|
||||
if(m.reduce_hp(20)) addMessage("The " + hal()->get_name() + " slaps you!");
|
||||
if(m.reduce_hp(20, this)) addMessage("The " + hal()->get_name() + " slaps you!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-4
@@ -44,6 +44,12 @@ void statdata::reset() {
|
||||
detect_area = 0;
|
||||
detect_cross = 0;
|
||||
rough_detect = 0;
|
||||
|
||||
heavy_armor = 0;
|
||||
spikes = 0;
|
||||
max_mageshield = 0;
|
||||
stealth_bonus = 0;
|
||||
dodge_value = 0;
|
||||
hallucinating = false;
|
||||
mods.clear();
|
||||
on_hit.clear();
|
||||
@@ -66,7 +72,9 @@ void man::hs(stater& s) {
|
||||
.act("xp", experience, 0)
|
||||
.act("last_action", last_action, 0)
|
||||
.act("gameseed", gameseed, 0)
|
||||
.act("dresstime", dresstime, 0);
|
||||
.act("dresstime", dresstime, 0)
|
||||
.act("current_mageshield", current_mageshield, 0)
|
||||
.act("mageshield_recharge_time", mageshield_recharge_time, 0);
|
||||
sact(s1, "hair", hair);
|
||||
sact(s1, "eyes", eye);
|
||||
string z = unspace(backstory);
|
||||
@@ -83,6 +91,12 @@ void man::hs(stater& s) {
|
||||
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);
|
||||
|
||||
s1.act(prefix + "heavy_armor", sd.heavy_armor, 0);
|
||||
s1.act(prefix + "spikes", sd.spikes, 0);
|
||||
s1.act(prefix + "max_mageshield", sd.max_mageshield, 0);
|
||||
s1.act(prefix + "stealth_bonus", sd.stealth_bonus, 0);
|
||||
s1.act(prefix + "dodge_value", sd.dodge_value, 0);
|
||||
};
|
||||
|
||||
sdata(current, "curr.");
|
||||
@@ -110,9 +124,14 @@ void man::act() {
|
||||
|
||||
if(dresstime) {
|
||||
dresstime--;
|
||||
if(dresstime == 0) addMessage("You finish redressing.");
|
||||
if(dresstime == 0) { addMessage("You finish redressing."); mageshield_recharge_time = game_fps * 5; }
|
||||
}
|
||||
|
||||
if(current_mageshield > current.max_mageshield) current.max_mageshield = 0;
|
||||
|
||||
if(mageshield_recharge_time) mageshield_recharge_time--;
|
||||
else if(current_mageshield < current.max_mageshield) current_mageshield++;
|
||||
|
||||
if(on_floor) on_floor_when = gframeid;
|
||||
|
||||
fallthru = false;
|
||||
@@ -139,11 +158,15 @@ void man::act() {
|
||||
check_fountains();
|
||||
}
|
||||
|
||||
bool man::reduce_hp(int x) {
|
||||
bool man::reduce_hp(int x, entity *attacker, flagtype flags) {
|
||||
if(m.current.dodge_value > 0 && rand() % 100 < m.current.dodge_value && !(flags & NON_DODGEABLE)) { x = 1; }
|
||||
if(m.current_mageshield > 0) { int q = min(m.current_mageshield, x); x -= q; m.current_mageshield -= q; m.mageshield_recharge_time = game_fps * 5; }
|
||||
if(m.current.heavy_armor > 0) { x = max((x+4)/5, x - m.current.heavy_armor); }
|
||||
if(attacker && m.current.spikes > 0 && !(flags & SPIKES)) attacker->reduce_hp(m.current.spikes, this, SPIKES);
|
||||
if(gframeid >= invinc_end)
|
||||
for(auto& f: m.current.on_hit)
|
||||
f(x);
|
||||
return entity::reduce_hp(x);
|
||||
return entity::reduce_hp(x, attacker, flags);
|
||||
}
|
||||
|
||||
bool man::can_see(entity& e) {
|
||||
|
||||
+23
-6
@@ -424,24 +424,41 @@ void gen_powers() {
|
||||
gen_power('a', 1, "heavy armor",
|
||||
"This kind of armor reduces the amount of damage you take from hits.",
|
||||
"]", 0xC0C0C0FF,
|
||||
[] (data& d) {}).be_armor({{"a chain shirt", "plate armor"}, {"an iron cap", "an iron helmet"}, {"an iron gorget"}, {"bracers"}, {"gauntlets"}, {"iron-shod boots"}, {"greaves"}}),
|
||||
[] (data& d) {
|
||||
if(d.p->flags & ACTIVE) if(!m.dresstime) {
|
||||
m.next.heavy_armor += 2 * d.p->qty_filled;
|
||||
}
|
||||
}).be_armor({{"a chain shirt", "plate armor"}, {"an iron cap", "an iron helmet"}, {"an iron gorget"}, {"bracers"}, {"gauntlets"}, {"iron-shod boots"}, {"greaves"}}),
|
||||
|
||||
thief_power = &gen_power('t', 1, "thief garments",
|
||||
"This outfit makes it harder for enemies to notice or hit you.",
|
||||
"]", 0xC08000FF,
|
||||
[] (data& d) {}).be_armor({{"a leather vest"}, {"a hood"}, {"comfortable boots", "muffled boots", "boots of dodging"}, {"a cloak", "chameleon cloak"}, {"leather gloves"}, {"leather pants"}}),
|
||||
[] (data& d) {
|
||||
if(d.p->flags & ACTIVE) if(!m.dresstime) {
|
||||
m.next.dodge_value += m.current.stats[stat::dex] + 5 * d.p->qty_filled;
|
||||
m.next.stealth_bonus += d.p->qty_filled;
|
||||
}
|
||||
}).be_armor({{"a leather vest"}, {"a hood"}, {"comfortable boots", "muffled boots", "boots of dodging"}, {"a cloak", "chameleon cloak"}, {"leather gloves"}, {"leather pants"}}),
|
||||
|
||||
gen_power('w', 1, "wizard attire",
|
||||
"This outfit provides a magical aura that prevents you from taking damage. However, eventually, "
|
||||
"with lots of attacks, the aura will lose its power. You need to spend some time without being attacked to "
|
||||
"regenerate it.",
|
||||
"]", 0x0080C0FF,
|
||||
[] (data& d) {}).be_armor({{"a simple magic robe", "embroidered robe"}, {"a wizard hat"}, {"runed boots", "silk runed boots"}, {"runed gloves", "silk runed gloves"}, {"a silver circlet", "a golden circlet"}}),
|
||||
[] (data& d) {
|
||||
if(d.p->flags & ACTIVE) if(!m.dresstime) {
|
||||
m.next.max_mageshield += 5 * d.p->qty_filled;
|
||||
}
|
||||
}).be_armor({{"a simple magic robe", "embroidered robe"}, {"a wizard hat"}, {"runed boots", "silk runed boots"}, {"runed gloves", "silk runed gloves"}, {"a silver circlet", "a golden circlet"}}),
|
||||
|
||||
gen_power('d', 1, "druid outfit",
|
||||
"This outfit reduces the damage you take from hits, makes it harder for enemies to hit you, and also provides some magical aura protection.",
|
||||
gen_power('r', 1, "druid outfit",
|
||||
"This outfit has nasty spikes that damages those who attack you.",
|
||||
"]", 0x40C040FF,
|
||||
[] (data& d) {}).be_armor({{"a light fur", "a heavy fur"}, {"a horned cap", "a horned helmet"}, {"enchanted cloak"}, {"furry gloves", "beast gloves"}, {"furry boots"}, {"bracers"}}),
|
||||
[] (data& d) {
|
||||
if(d.p->flags & ACTIVE) if(!m.dresstime) {
|
||||
m.next.spikes += 5 + 3 * d.p->qty_filled;
|
||||
}
|
||||
}).be_armor({{"a light fur", "a heavy fur"}, {"a horned cap", "a horned helmet"}, {"enchanted cloak"}, {"furry gloves", "beast gloves"}, {"furry boots"}, {"bracers"}}),
|
||||
|
||||
gen_power(' ', 0, "dagger",
|
||||
"This sharp dagger is very useful during the preparation of alchemical ingredients, but it works as a basic weapon too.",
|
||||
|
||||
@@ -308,6 +308,10 @@ void run() {
|
||||
shstream ss;
|
||||
print(ss, "HP ", m.hp, "/", m.max_hp());
|
||||
for(auto& sts: m.current.status_strings) sts(ss);
|
||||
if(m.current.max_mageshield) print(ss, " SH ", m.current_mageshield, "/", m.current.max_mageshield);
|
||||
if(m.current.dodge_value) print(ss, " DV ", m.current.dodge_value, "%");
|
||||
if(m.current.heavy_armor) print(ss, " PV ", m.current.heavy_armor, "%");
|
||||
if(m.current.spikes) print(ss, " SP ", m.current.spikes);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user