diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index 13775987..16e842b3 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -250,6 +250,9 @@ struct entity { int hp; int invinc_end; + entity *hallucinated = nullptr; + virtual bool can_be_hallucinated() { return true; } + virtual int max_hp() { return 100; } virtual bool visible(room *r); @@ -340,6 +343,8 @@ struct entity { virtual void on_fountain(); virtual void on_reset_all() {} + + entity *hal(); }; struct statdata { @@ -724,6 +729,7 @@ struct hint : public located_entity { void act() override; bool have_help() { return false; } string get_name() override { return ""; } + bool can_be_hallucinated() override { return false; } }; struct item : public located_entity { diff --git a/rogueviz/ru/entity.cpp b/rogueviz/ru/entity.cpp index 6597e5f1..284ce7ab 100644 --- a/rogueviz/ru/entity.cpp +++ b/rogueviz/ru/entity.cpp @@ -111,7 +111,7 @@ void entity::apply_walls() { if(b == wRogueWallHidden && is_disarmer()) { current_room->replace_block_frev(x, y, wRogueWall); if(current_room->fov[y][x]) - addMessage("Your hairsnake exposes a fake wall!"); + addMessage("Your " + hal()->get_name() + " exposes a fake wall!"); } }; @@ -362,7 +362,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 wild boar gores you!"); + if(m.reduce_hp(15)) 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; @@ -382,7 +382,7 @@ void boar::act() { void enemy::attacked(int dmg) { current_target = this; if(reduce_hp(dmg)) { - if(!existing) addMessage("You kill the " + get_name() + "."); else addMessage("You hit the " + get_name() + "."); + if(!existing) addMessage("You kill the " + hal()->get_name() + "."); else addMessage("You hit the " + hal()->get_name() + "."); } } @@ -586,14 +586,14 @@ void kestrel::act() { apply_vel(); if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { - if(m.reduce_hp(15)) addMessage("The kestrel claws you!"); + if(m.reduce_hp(15)) addMessage("The " + hal()->get_name() + " claws you!"); } } void gridbug::act() { if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { - if(m.reduce_hp(15)) addMessage("The grid bug zaps you!"); + if(m.reduce_hp(15)) addMessage("The " + hal()->get_name() + " zaps you!"); } if(gframeid < next_move || !visible(current_room) || gframeid < invinc_end) return; @@ -669,7 +669,7 @@ void bat::act() { apply_vel(); if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { - if(m.reduce_hp(15)) addMessage("The bat bites you!"); + if(m.reduce_hp(15)) addMessage("The " + hal()->get_name() + " bites you!"); } } @@ -726,7 +726,7 @@ void guineapig::act() { where = nonblocked(ca = gmod(ca+j-3, 8), s).first; if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { if(m.reduce_hp(15)) { - addMessage("The guinea pig bites you!"); + addMessage("The " + hal()->get_name() + " bites you!"); spindir *= -1; } } @@ -756,7 +756,7 @@ void vtrap::act() { apply_vel(); if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { - if(m.reduce_hp(200)) addMessage("The trap zaps you!"); + if(m.reduce_hp(200)) addMessage("The " + hal()->get_name() + " zaps you!"); } } @@ -783,7 +783,7 @@ void disnake::act() { kill_off_screen(); for(auto& e: current_room->entities) if(e->hidden() && e->existing && intersect(e->get_pixel_bbox(), get_pixel_bbox())) { - addMessage("Your hear a sound of a " + e->get_name() + " colliding with a hairsnake."); + addMessage("Your hear a sound of the " + e->hal()->get_name() + " colliding with the " + hal()->get_name() + "."); e->existing = false; destroyed = true; } @@ -816,7 +816,7 @@ void icicle::act() { } if(state != 0) { if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { - if(m.reduce_hp(50)) addMessage("An icicle falls on you!"); + if(m.reduce_hp(50)) addMessage("The " + hal()->get_name() + " falls on you!"); } } } diff --git a/rogueviz/ru/hallucinate.cpp b/rogueviz/ru/hallucinate.cpp new file mode 100644 index 00000000..3444637b --- /dev/null +++ b/rogueviz/ru/hallucinate.cpp @@ -0,0 +1,23 @@ +namespace rogue_unlike { + +void prepare_hallucination() { + set names_seen; + vector visions; + for(auto& [c, r]: rooms) for(auto& e: r.entities) { + if(!e->can_be_hallucinated()) continue; + string s = e->get_name(); + if(names_seen.count(s)) continue; + names_seen.insert(s); + visions.push_back(&*e); + } + + for(auto& [c, r]: rooms) for(auto& e: r.entities) { + e->hallucinated = hrand_elt(visions); + } + } + +entity *entity::hal() { + return (m.current.hallucinating && hallucinated) ? hallucinated : this; + } + +} diff --git a/rogueviz/ru/man.cpp b/rogueviz/ru/man.cpp index 4211463f..62525834 100644 --- a/rogueviz/ru/man.cpp +++ b/rogueviz/ru/man.cpp @@ -111,6 +111,9 @@ void man::act() { handle_powers(dat); + if(next.hallucinating && !current.hallucinating) + prepare_hallucination(); + if((on_floor || current.jump_control || wallhug) && !on_ice) { vel.x = zero_vel.x + dat.dx * dat.d * dat.modv * 2.5; } @@ -182,7 +185,7 @@ void man::launch_attack(power *p, int fac, boxfun f) { if(m == mod::freezing) { e->invinc_end = sav; e->attacked(qty); } if(m == mod::disarming && e->hidden()) { e->existing = false; - addMessage("You have disarmed a "+e->get_name()+"."); + addMessage("You have disarmed a "+e->hal()->get_name()+"."); } } } diff --git a/rogueviz/ru/randeff.cpp b/rogueviz/ru/randeff.cpp index d45addd0..b2cdc14f 100644 --- a/rogueviz/ru/randeff.cpp +++ b/rogueviz/ru/randeff.cpp @@ -183,7 +183,7 @@ void assign_potion_powers() { using relist = vector; find_power("health").randeffs = relist{ pick(&health_heal, &health_regen, &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("polymorph").randeffs = relist{ pick(&morph_cat, &morph_capy), random_powers[2], &hallux }; find_power("reach").randeffs = relist{ pick(&jump_double, &jump_high, &jump_bubble, &jump_light), random_powers[3] }; find_power("fire").randeffs = relist{ pick(&fire_spit, &fire_weapon), random_powers[4] }; find_power("mystery").randeffs = relist{ random_powers[5], random_powers[6], random_powers[7] }; diff --git a/rogueviz/ru/render.cpp b/rogueviz/ru/render.cpp index a65d1568..cc8784a3 100644 --- a/rogueviz/ru/render.cpp +++ b/rogueviz/ru/render.cpp @@ -237,7 +237,8 @@ void entity::draw() { ld maxx = max(where.x, gwhere.x) + si.x * d / 2; ld maxy = max(where.y, gwhere.y) + si.y * d / 2; - asciiletter(minx, miny, maxx, maxy, glyph(), color()); + auto h = hal(); + asciiletter(minx, miny, maxx, maxy, h->glyph(), h->color()); } void man::draw() { diff --git a/rogueviz/ru/ru.cpp b/rogueviz/ru/ru.cpp index 01cac77b..fe41a892 100644 --- a/rogueviz/ru/ru.cpp +++ b/rogueviz/ru/ru.cpp @@ -29,6 +29,7 @@ Have fun! #include "staters.cpp" #include "geometry.cpp" #include "entity.cpp" +#include "hallucinate.cpp" #include "man.cpp" #include "room.cpp" #include "render.cpp" @@ -301,8 +302,8 @@ void run() { help_entity = &*e; if(help_entity) { - mouseovers = help_entity->get_name(); - helpstr = help_entity->get_help(); + mouseovers = help_entity->hal()->get_name(); + helpstr = help_entity->hal()->get_help(); } int x = mousepx / block_x, y = mousepy / block_y;