diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index 15c3cff3..59894e8f 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -228,7 +228,7 @@ struct entity { data get_dat(); - struct bbox get_pixel_bbox_at(xy); + struct bbox get_pixel_bbox_at(xy, ld scalex = 1, ld scaley = 1); struct bbox get_pixel_bbox() { return get_pixel_bbox_at(where); } virtual double grav() { return 0.1; } @@ -299,12 +299,22 @@ struct statdata { vector> mods; }; +using boxfun = hr::function; + +struct effect { + power *p; + int attack_facing; + int attack_when; + boxfun f; + }; + struct man : public entity { int facing; int attack_facing; int attack_when; int on_floor_when; entity *morphed = nullptr; + vector effects; int last_action; @@ -349,6 +359,7 @@ struct man : public entity { addMessage("OUCH! These spikes hurt!"); } + void launch_attack(power *p, int fac, boxfun f); }; extern man m; diff --git a/rogueviz/ru/entity.cpp b/rogueviz/ru/entity.cpp index 1d3c3f26..83ce484e 100644 --- a/rogueviz/ru/entity.cpp +++ b/rogueviz/ru/entity.cpp @@ -2,15 +2,18 @@ namespace rogue_unlike { man m; -bbox entity::get_pixel_bbox_at(xy p) { +bbox entity::get_pixel_bbox_at(xy p, ld scalex, ld scaley) { bbox b; double d = get_scale_at(p.y); + ld dx = d * scalex; + ld dy = d * scaley; double man_x = siz().x; double man_y = siz().y; - b.minx = p.x - man_x * d / 2; - b.maxx = p.x + man_x * d / 2 + 1; - b.miny = p.y - man_y * d / 2; - b.maxy = p.y + man_y * d / 2 + 1; + b.minx = p.x - man_x * dx / 2; + b.maxx = p.x + man_x * dx / 2 + 1; + b.miny = p.y - man_y * dy / 2; + b.maxy = p.y + man_y * dy / 2 + 1; + if(ldebug) println(hlog, tie(man_x, man_y, d)); return b; } diff --git a/rogueviz/ru/man.cpp b/rogueviz/ru/man.cpp index 1c4ffef4..298f85da 100644 --- a/rogueviz/ru/man.cpp +++ b/rogueviz/ru/man.cpp @@ -101,4 +101,42 @@ void revert_all(revert_stack& s) { while(!s.empty()) { s.back()(); s.pop_back(); } } +void man::launch_attack(power *p, int fac, boxfun f) { + effects.emplace_back(); + auto& e = effects.back(); + e.p = p; + e.attack_facing = fac; + e.attack_when = gframeid; + e.f = f; + auto pb = f(0); + auto bb = pixel_to_block(pb); + 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); } + } + } + for(int y=bb.miny; yat(x, y); + if(b == wDoor) { + current_room->replace_block_frev(x, y, wSmashedDoor); + addMessage("You smash the door!"); + } + for(auto& [m, qty]: p->mods) { + if(m == mod::burning && b == wWoodWall) { + current_room->replace_block_frev(x, y, wAir); + addMessage("You burn the wall!"); + } + if(m == mod::freezing && b == wWater) { + current_room->replace_block_frev(x, y, wFrozen); + addMessage("You freeze the water!"); + } + } + } + } + } diff --git a/rogueviz/ru/powers.cpp b/rogueviz/ru/powers.cpp index 477d9f89..873f6c4b 100644 --- a/rogueviz/ru/powers.cpp +++ b/rogueviz/ru/powers.cpp @@ -317,36 +317,17 @@ void gen_powers() { ")", 0xFFFFFFFF, [] (data& d) { if(d.keystate != 1) return; - m.attack_facing = m.facing; m.attack_when = gframeid; - auto pb = m.get_pixel_bbox_at(xy{m.where.x + m.attack_facing * m.dsiz().x, m.where.y}); - auto bb = pixel_to_block(pb); - 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]: d.p->mods) { - if(m == mod::burning) { e->invinc_end = sav; e->attacked(qty); } - if(m == mod::freezing) { e->invinc_end = sav; e->attacked(qty); } - } - } - for(int y=bb.miny; yat(x, y); - if(b == wDoor) { - current_room->replace_block_frev(x, y, wSmashedDoor); - addMessage("You smash the door!"); - } - for(auto& [m, qty]: d.p->mods) { - if(m == mod::burning && b == wWoodWall) { - current_room->replace_block_frev(x, y, wAir); - addMessage("You burn the wall!"); - } - if(m == mod::freezing && b == wWater) { - current_room->replace_block_frev(x, y, wFrozen); - addMessage("You freeze the water!"); - } - } - } + for(auto fac: {1, -1}) + m.launch_attack(d.p, fac, [fac] (int t) { return m.get_pixel_bbox_at(xy{m.where.x + fac * (1-0.01 * t) * m.dsiz().x, m.where.y}); }); + }).be_weapon(), + + gen_power('x', "axe", + "This axe is very sharp and strong! It could even destroy heavy doors.", + ")", 0xFFFFFFFF, + [] (data& d) { + if(d.keystate != 1) return; + int fac = m.facing; + m.launch_attack(d.p, fac, [fac] (int t) { return m.get_pixel_bbox_at(xy{m.where.x + fac * (1-0.01 * t) * m.dsiz().x, m.where.y}, 2, 2); }); }).be_weapon(), gen_power('o', "strange blue crystal ball", "You feel an urge to look into it.", diff --git a/rogueviz/ru/render.cpp b/rogueviz/ru/render.cpp index 902e1d1b..cf23208f 100644 --- a/rogueviz/ru/render.cpp +++ b/rogueviz/ru/render.cpp @@ -245,19 +245,24 @@ void entity::draw() { void man::draw() { entity::draw(); - ld t = gframeid - attack_when; - if(t < 50) { - auto af = attack_facing * (1 - t * 0.01); - auto ds = dsiz(); - auto col = find_power("dagger").get_color(); - auto& alpha = part(col, 0); - alpha = max (0, alpha - 5 * t); - asciiletter( - where.x + af * ds.x - ds.x/2, where.y - ds.y/2, - where.x + af * ds.x + ds.x/2, where.y + ds.y/2, - attack_facing == -1 ? "(" : ")", col - ); + auto efs = effects.begin(); + + for(auto& e: effects) { + ld t = gframeid - e.attack_when; + if(t < 50) { + auto col = find_power("dagger").get_color(); + auto& alpha = part(col, 0); + alpha = max (0, alpha - 5 * t); + auto box = e.f(t); + asciiletter( + box.minx, box.miny, // where.x + af * ds.x - ds.x/2, where.y - ds.y/2, + box.maxx, box.maxy, // where.x + af * ds.x + ds.x/2, where.y + ds.y/2, + e.attack_facing == -1 ? "(" : ")", col + ); + *(efs++) = e; + } } + effects.resize(efs - effects.begin()); } void render_room_objects(room *r) { diff --git a/rogueviz/ru/stats.cpp b/rogueviz/ru/stats.cpp index a2c72374..5715310f 100644 --- a/rogueviz/ru/stats.cpp +++ b/rogueviz/ru/stats.cpp @@ -133,7 +133,7 @@ void stat_screen(bool editable) { cmode = mode::playing; switch(m.profession) { case stat::str: - find_power("dagger").gain(1, 1); // no axe yet + find_power("axe").gain(1, 1); break; case stat::con: find_power("polymorph").gain(1, 1).flags |= IDENTIFIED | PARTIAL;