diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 85f6ca5a..d3d427d6 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1710,6 +1710,7 @@ Node definition (register_node) liquid_alternative_source = "", -- Source version of flowing liquid liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7) liquid_renewable = true, -- Can new liquid source be created by placing + drowning = true, -- Player will drown in these two or more sources nearly? light_source = 0, -- Amount of light emitted by node damage_per_second = 0, -- If player is inside node, this damage is caused diff --git a/games/minimal/mods/default/textures/bubble.png b/games/minimal/mods/default/textures/bubble.png new file mode 100644 index 00000000..3bca7e11 Binary files /dev/null and b/games/minimal/mods/default/textures/bubble.png differ diff --git a/src/client.cpp b/src/client.cpp index 6b1789fe..5f53e14f 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -2680,6 +2680,13 @@ u16 Client::getHP() return player->hp; } +u16 Client::getBreath() +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + return player->breath; +} + bool Client::getChatMessage(std::wstring &message) { if(m_chat_queue.size() == 0) diff --git a/src/client.h b/src/client.h index f0cc5586..1d231a5a 100644 --- a/src/client.h +++ b/src/client.h @@ -349,6 +349,7 @@ public: void setCrack(int level, v3s16 pos); u16 getHP(); + u16 getBreath(); bool checkPrivilege(const std::string &priv) { return (m_privileges.count(priv) != 0); } diff --git a/src/environment.cpp b/src/environment.cpp index a97a9bd0..99da5190 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2227,7 +2227,45 @@ void ClientEnvironment::step(float dtime) damageLocalPlayer(damage_per_second, true); } } - + + /* + Drowning + */ + if(m_drowning_interval.step(dtime, 2.0)) + { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + + if(c.isLiquid() && c.drowning){ + if(lplayer->breath > 10) + lplayer->breath = 11; + if(lplayer->breath > 0) + lplayer->breath -= 1; + } + + if(lplayer->breath == 0){ + damageLocalPlayer(1, true); + } + } + if(m_breathing_interval.step(dtime, 0.5)) + { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + + if(!c.isLiquid() || !c.drowning){ + if(lplayer->breath <= 10) + lplayer->breath += 1; + } + } + /* Stuff that can be done in an arbitarily large dtime */ diff --git a/src/environment.h b/src/environment.h index a62173a1..ac479999 100644 --- a/src/environment.h +++ b/src/environment.h @@ -494,6 +494,8 @@ private: Queue m_client_event_queue; IntervalLimiter m_active_object_light_update_interval; IntervalLimiter m_lava_hurt_interval; + IntervalLimiter m_drowning_interval; + IntervalLimiter m_breathing_interval; std::list m_player_names; }; diff --git a/src/game.cpp b/src/game.cpp index 30d9c7fa..88be47b3 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3310,7 +3310,7 @@ void the_game( if (show_hud) { hud.drawHotbar(v2s32(displaycenter.X, screensize.Y), - client.getHP(), client.getPlayerItem()); + client.getHP(), client.getPlayerItem(), client.getBreath()); } /* diff --git a/src/hud.cpp b/src/hud.cpp index a3ae38bc..9404ed99 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -278,7 +278,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s } -void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { +void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) { InventoryList *mainlist = inventory->getList("main"); if (mainlist == NULL) { errorstream << "draw_hotbar(): mainlist == NULL" << std::endl; @@ -295,6 +295,9 @@ void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) { if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE) drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT, "heart.png", halfheartcount, v2s32(0, 0)); + if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10) + drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT, + "bubble.png", breath*2, v2s32(0, 0)); } diff --git a/src/hud.h b/src/hud.h index fa9d33f8..c7289f7c 100644 --- a/src/hud.h +++ b/src/hud.h @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define HUD_FLAG_HEALTHBAR_VISIBLE (1 << 1) #define HUD_FLAG_CROSSHAIR_VISIBLE (1 << 2) #define HUD_FLAG_WIELDITEM_VISIBLE (1 << 3) +#define HUD_FLAG_BREATHBAR_VISIBLE (1 << 4) #define HUD_PARAM_HOTBAR_ITEMCOUNT 1 @@ -122,7 +123,7 @@ public: void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset); - void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem); + void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath); void resizeHotbar(); void drawCrosshair(); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index ba3e42e9..7d8ce70d 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -211,6 +211,7 @@ void ContentFeatures::reset() liquid_alternative_source = ""; liquid_viscosity = 0; liquid_renewable = true; + drowning = true; light_source = 0; damage_per_second = 0; node_box = NodeBox(); @@ -279,6 +280,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) writeU8(os, rightclickable); // Stuff below should be moved to correct place in a version that otherwise changes // the protocol version + writeU8(os, drowning); } void ContentFeatures::deSerialize(std::istream &is) @@ -343,6 +345,7 @@ void ContentFeatures::deSerialize(std::istream &is) try{ // Stuff below should be moved to correct place in a version that // otherwise changes the protocol version + drowning = readU8(is); }catch(SerializationError &e) {}; } diff --git a/src/nodedef.h b/src/nodedef.h index 2691aca3..e397d20e 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -219,6 +219,7 @@ struct ContentFeatures u8 liquid_viscosity; // Is liquid renewable (new liquid source will be created between 2 existing) bool liquid_renewable; + bool drowning; // Amount of light the node emits u8 light_source; u32 damage_per_second; diff --git a/src/player.cpp b/src/player.cpp index 4eb5955c..a199c9a6 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -36,6 +36,7 @@ Player::Player(IGameDef *gamedef): camera_barely_in_ceiling(false), inventory(gamedef->idef()), hp(PLAYER_MAX_HP), + breath(-1), peer_id(PEER_ID_INEXISTENT), // protected m_gamedef(gamedef), @@ -80,7 +81,8 @@ Player::Player(IGameDef *gamedef): physics_override_gravity = 1; hud_flags = HUD_FLAG_HOTBAR_VISIBLE | HUD_FLAG_HEALTHBAR_VISIBLE | - HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE; + HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE | + HUD_FLAG_BREATHBAR_VISIBLE; hud_hotbar_itemcount = HUD_HOTBAR_ITEMCOUNT_DEFAULT; } diff --git a/src/player.h b/src/player.h index d3738fd5..517bd354 100644 --- a/src/player.h +++ b/src/player.h @@ -232,6 +232,7 @@ public: float physics_override_gravity; u16 hp; + u16 breath; float hurt_tilt_timer; float hurt_tilt_strength; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index c7966a0b..64c76ef7 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -389,6 +389,7 @@ ContentFeatures read_content_features(lua_State *L, int index) f.liquid_viscosity = getintfield_default(L, index, "liquid_viscosity", f.liquid_viscosity); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); + getboolfield(L, index, "drowning", f.drowning); // Amount of light the node emits f.light_source = getintfield_default(L, index, "light_source", f.light_source); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 1e45610a..f90b5928 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -62,6 +62,7 @@ struct EnumString es_HudBuiltinElement[] = {HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"}, {HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"}, {HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"}, + {HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"}, {0, NULL}, };