diff --git a/rogueviz/ru/classes.cpp b/rogueviz/ru/classes.cpp index bd9c0010..af7cd7db 100644 --- a/rogueviz/ru/classes.cpp +++ b/rogueviz/ru/classes.cpp @@ -303,6 +303,27 @@ struct boar : public enemy { string get_help() override { return "Beware their tusks."; } }; +struct snake : public enemy { + int dir; + xy siz() override { return {18, 8}; } + string glyph() override { return "S"; } + color_t color() override { return 0x20D020FF; } + void act() override; + void attacked(int s) override; + string get_name() override { return "snake"; } + string get_help() override { return "A nasty dungeon snake."; } + }; + +struct kestrel : public enemy { + xy siz() override { return {10, 10}; } + string glyph() override { return "K"; } + color_t color() override { return 0xD0A0A0FF; } + void act() override; + void attacked(int s) override; + string get_name() override { return "kestrel"; } + string get_help() override { return "A standard dungeon kestrel."; } + }; + struct hint : public entity { string hint_text; int state; diff --git a/rogueviz/ru/entity.cpp b/rogueviz/ru/entity.cpp index 5b2d5253..7da97f6d 100644 --- a/rogueviz/ru/entity.cpp +++ b/rogueviz/ru/entity.cpp @@ -288,6 +288,26 @@ void boar::attacked(int dmg) { if(on_floor) vel.x = dat.d * dat.modv * s * 2, vel.y = -dat.d * dat.modv * 2.5; } +void snake::act() { + kino(); + if(abs(vel.x) < 1e-6) { + auto dat = get_dat(); + vel.x = zero_vel.x + dat.d * dat.modv * dir; + dir = -dir; + } + if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { + if(m.reduce_hp(25)) addMessage("The snake bites you!"); + } + } + +void snake::attacked(int dmg) { + current_target = this; + reduce_hp(dmg); + if(!existing) addMessage("You kill the snake."); else addMessage("You hit the snake."); + if(where.x < m.where.x) vel.x = -abs(vel.x); + if(where.x > m.where.x) vel.x = +abs(vel.x); + } + void hint::act() { bool cur = intersect(get_pixel_bbox(), m.get_pixel_bbox()); if(cur && !state) { @@ -323,5 +343,60 @@ void moving_platform::act() { where = location_at(gframeid); } +void kestrel::act() { + int loopcount = 0; + again: + loopcount++; + + auto obb = pixel_to_block(get_pixel_bbox()); + auto nbb = pixel_to_block(get_pixel_bbox_at(where + vel)); + auto jbb = join(obb, nbb); + + flagtype blocking = (W_BLOCK | W_BLOCKBIRD); + + if(loopcount >= 100) return; + + 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) { + vel.y = -vel.y; goto again; + } + } + + 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) { + vel.y = -vel.y; goto again; + } + } + + 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) { + vel.x = -vel.x; goto again; + } + } + + 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) { + vel.x = -vel.x; goto again; + } + } + + apply_vel(); + + if(intersect(get_pixel_bbox(), m.get_pixel_bbox())) { + if(m.reduce_hp(15)) addMessage("The kestrel claws you!"); + } + } + +void kestrel::attacked(int dmg) { + current_target = this; + reduce_hp(dmg); + if(!existing) addMessage("You kill the kestrel."); else addMessage("You hit the kestrel."); + if(where.x < m.where.x) vel.x = -abs(vel.x); + if(where.x > m.where.x) vel.x = +abs(vel.x); + } } diff --git a/rogueviz/ru/globals.cpp b/rogueviz/ru/globals.cpp index 0a27d331..719f39cc 100644 --- a/rogueviz/ru/globals.cpp +++ b/rogueviz/ru/globals.cpp @@ -64,6 +64,7 @@ flagtype W_STAIRCASE = 8; flagtype W_PAIN = 16; flagtype W_BOUNCY = 32; flagtype W_FROZEN = 64; +flagtype W_BLOCKBIRD = 128; constexpr int qwall = int(wGUARD); @@ -71,8 +72,8 @@ ruwall walls[qwall] = { {"air", ".", 0x40404080, W_TRANS, "Looks like an empty space, but actually necessary for survival."}, {"wall", "#", 0xFFFFFFFF, W_BLOCK, "These kinds of tough walls can never be destroyed."}, {"bouncy wall", "#", 0x80FF80FF, W_BLOCK | W_BOUNCY, "Like walls, but things bounce off them."}, - {"spike", "^", 0xC08080FF, W_TRANS | W_PAIN, "Dangerous!"}, - {"water", "~", 0x0000FFFF, W_BLOCK | W_TRANS, "Not used yet."}, + {"spike", "^", 0xC08080FF, W_TRANS | W_PAIN | W_BLOCKBIRD, "Dangerous!"}, + {"water", "~", 0x0000FFFF, W_BLOCK | W_TRANS | W_BLOCKBIRD, "Not used yet."}, {"frozen water", "#", 0xC0C0FFFF, W_BLOCK | W_FROZEN, "Water magically turned into a slippery wall."}, {"door", "+", 0xC06000FF, W_BLOCK, "Attack the doors with your weapon to open them."}, {"smashed door", "'", 0xC06000FF, W_TRANS, "This door has been already opened."}, @@ -81,9 +82,9 @@ ruwall walls[qwall] = { {"magic fountain (active)", "!", 0xA0A0FFFF, W_TRANS, "Wow! An active magic fountain!"}, {"blue portal", "=", 0x4040C0FF, W_TRANS, "Blue portal."}, {"orange portal", "=", 0xC08040FF, W_TRANS, "Orange portal."}, - {"platform", "-", 0xFFFFFFFF, W_PLATFORM | W_TRANS, "You can fall down through such platforms."}, + {"platform", "-", 0xFFFFFFFF, W_PLATFORM | W_TRANS | W_BLOCKBIRD, "You can fall down through such platforms."}, {"staircase", "-", 0xFFFF80FF, W_PLATFORM | W_TRANS | W_STAIRCASE, "You can climb staircases and ladders." }, - {"column", "|", 0x40404080, W_TRANS, "A background decoration." }, + {"column", "|", 0x40404080, W_TRANS | W_BLOCKBIRD, "A background decoration." }, {"forge", "&", 0xB0202080, W_TRANS | W_PAIN, "Used by runesmiths."}, }; diff --git a/rogueviz/ru/map.ru b/rogueviz/ru/map.ru index 48e6c5cc..1dfc7dc1 100644 --- a/rogueviz/ru/map.ru +++ b/rogueviz/ru/map.ru @@ -425,6 +425,14 @@ What a shiny crystal ball! ITEM 75 200 20 gold You found 20 gold pieces +KESTREL 85 66 15 15 +KESTREL 527 65 20 10 +KESTREL 309 211 10 20 +KESTREL 100 190 25 5 +KESTREL 561 198 25 5 +SNAKE 111 220 1 +SNAKE 549 234 1 +SNAKE 493 135 1 OK MOVE 2 Dungeon Entrance diff --git a/rogueviz/ru/save.cpp b/rogueviz/ru/save.cpp index 3f735e8a..71655785 100644 --- a/rogueviz/ru/save.cpp +++ b/rogueviz/ru/save.cpp @@ -134,6 +134,19 @@ void load_room(fhstream& f, cell *c) { b->respawn = b->where; r.entities.emplace_back(std::move(b)); } + else if(cap == "KESTREL") { + auto b = std::make_unique(); + sscanf(param.c_str(), "%lf%lf%lf%lf", &b->where.x, &b->where.y, &b->vel.x, &b->vel.y); + b->vel *= xy(block_x, block_y) / game_fps; + b->respawn = b->where; + r.entities.emplace_back(std::move(b)); + } + else if(cap == "SNAKE") { + auto b = std::make_unique(); + sscanf(param.c_str(), "%lf%lf%d", &b->where.x, &b->where.y, &b->dir); + b->respawn = b->where; + r.entities.emplace_back(std::move(b)); + } else if(cap == "FERRIS") { ld cx, cy, radius; int qty; sscanf(param.c_str(), "%lf%lf%lf%d", &cx, &cy, &radius, &qty);