diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index 09dce64b..768e37df 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -635,6 +635,23 @@ struct bat : public enemy { int max_hp() { return 10; } }; +struct guineapig : public enemy { + int ca; + bool falling; + int spindir, respawn_spindir; + ld pigvel; + xy siz() override { return {10, 10}; } + string glyph() override { return "G"; } + color_t color() override { return 0xD0A0A0FF; } + void act() override; + void attacked(int s) override; + string get_name() override { return "guinea pig"; } + string get_help() override { return "A standard dungeon guinea pig."; } + void regenerate() override { enemy::regenerate(); falling = true; spindir = respawn_spindir; } + int base_xp() { return 30; } + int max_hp() { return 300; } + }; + struct hint : public entity { string hint_text; int state; diff --git a/rogueviz/ru/entity.cpp b/rogueviz/ru/entity.cpp index 23ea52e5..8f39fa22 100644 --- a/rogueviz/ru/entity.cpp +++ b/rogueviz/ru/entity.cpp @@ -670,6 +670,78 @@ void bat::act() { } } +void guineapig::act() { + + if(falling) { + stay_on_screen(); + kino(); + if(on_floor) { ca = 0; falling = false; } + return; + } + + auto nonblocked = [this] (int angle, int mul) { + auto w1 = from_hyper(eupush(to_hyper(where)) * xspinpush0(angle * 45._deg * spindir, pigvel * mul)); + + auto obb = pixel_to_block(get_pixel_bbox()); + auto nbb = pixel_to_block(get_pixel_bbox_at(w1)); + auto jbb = join(obb, nbb); + + flagtype blocking = (W_BLOCK | W_BLOCKBIRD); + + bool ok = true; + + if(w1.x < 0 || w1.x > screen_x || w1.y < 0 || w1.y > screen_y) ok = false; + + for(int x = obb.minx; x < obb.maxx; x++) for(int y = obb.maxy; y < jbb.maxy; y++) { + eWall b = current_room->at(x, y); + if(walls[b].flags & blocking) ok = false; + } + + for(int x = obb.minx; x < obb.maxx; x++) for(int y = jbb.miny; y < obb.miny; y++) { + eWall b = current_room->at(x, y); + if(walls[b].flags & blocking) ok = false; + } + + for(int x = nbb.minx; x < nbb.maxx; x++) for(int y = jbb.miny; y < jbb.maxy; y++) { + eWall b = current_room->at(x, y); + if(walls[b].flags & blocking) ok = false; + } + + for(int x = obb.maxx; x < jbb.maxx; x++) for(int y = jbb.miny; y < jbb.maxy; y++) { + eWall b = current_room->at(x, y); + if(walls[b].flags & blocking) ok = false; + } + + return pair(w1, ok); + }; + + for(int s: {1, 2, 3}) { + for(int i=0; i<8; i++) { + if(!nonblocked(ca+i-3, s).second) { + for(int j=i+1; jrespawn = b->where; b->postfix(); r.entities.emplace_back(std::move(b)); } + else if(cap == "GUINEAPIG") { + auto b = std::make_unique(); + sscanf(param.c_str(), "%lf%lf%lf%d", &b->where.x, &b->where.y, &b->pigvel, &b->spindir); + b->pigvel /= game_fps; b->falling = true; b->vel = xy{0,0}; + b->respawn = b->where; b->respawn_spindir = b->spindir; b->postfix(); + r.entities.emplace_back(std::move(b)); + } else if(cap == "VTRAP") { auto b = std::make_unique(); sscanf(param.c_str(), "%lf%lf", &b->where.x, &b->where.y);