diff --git a/data/textures/heart.png b/data/textures/heart.png index c25b62b..206e70f 100644 Binary files a/data/textures/heart.png and b/data/textures/heart.png differ diff --git a/data/textures/progress_ring.png b/data/textures/progress_ring.png new file mode 100644 index 0000000..f79b29a Binary files /dev/null and b/data/textures/progress_ring.png differ diff --git a/data/textures/ringbg.png b/data/textures/ringbg.png index c34c5d7..57064e2 100644 Binary files a/data/textures/ringbg.png and b/data/textures/ringbg.png differ diff --git a/src/client.cpp b/src/client.cpp index 5af0671..84c8ee2 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1049,13 +1049,16 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) { std::string datastring((char*)&data[2], datasize-2); std::istringstream is(datastring, std::ios_base::binary); - Player *player = m_env.getLocalPlayer(); + LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); u8 hp = readU8(is); u8 air = readU8(is); u8 hunger = readU8(is); - if (m_server_damage) + if (m_server_damage) { + if (!player->hp) + player->setEnergy(hp); player->hp = hp; + } if (m_server_suffocation) player->air = air; if (m_server_hunger) @@ -2167,24 +2170,35 @@ u32 Client::getDayNightRatio() u16 Client::getHP() { Player *player = m_env.getLocalPlayer(); - assert(player != NULL); + if (!player) + return 0; return player->hp; } u16 Client::getAir() { Player *player = m_env.getLocalPlayer(); - assert(player != NULL); + if (!player) + return 0; return player->air; } u16 Client::getHunger() { Player *player = m_env.getLocalPlayer(); - assert(player != NULL); + if (!player) + return 0; return player->hunger; } +float Client::getEnergy() +{ + LocalPlayer *player = m_env.getLocalPlayer(); + if (!player) + return 0.0; + return player->getEnergy(); +} + void Client::setTempMod(v3s16 p, NodeMod mod) { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out diff --git a/src/client.h b/src/client.h index bfc64af..d69e091 100644 --- a/src/client.h +++ b/src/client.h @@ -269,6 +269,7 @@ public: u16 getHP(); u16 getAir(); u16 getHunger(); + float getEnergy(); void setTempMod(v3s16 p, NodeMod mod); void clearTempMod(v3s16 p); diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 813ec6c..0a1b69e 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -43,12 +43,15 @@ void set_default_settings(Settings *settings) settings->setDefault("keymap_jump", "KEY_SPACE"); settings->setDefault("keymap_sneak", "KEY_LSHIFT"); settings->setDefault("keymap_inventory", "KEY_KEY_I"); - settings->setDefault("keymap_special1", "KEY_KEY_E"); + settings->setDefault("keymap_examine", "KEY_KEY_Q"); + settings->setDefault("keymap_use", "KEY_KEY_H"); settings->setDefault("keymap_chat", "KEY_KEY_T"); settings->setDefault("keymap_cmd", "/"); - settings->setDefault("keymap_rangeselect", "KEY_KEY_R"); + settings->setDefault("keymap_rangeselect", "KEY_KEY_O"); settings->setDefault("keymap_freemove", "KEY_KEY_K"); - settings->setDefault("keymap_fastmove", "KEY_KEY_J"); + settings->setDefault("keymap_up", "KEY_KEY_R"); + settings->setDefault("keymap_down", "KEY_KEY_F"); + settings->setDefault("keymap_run", "KEY_KEY_E"); settings->setDefault("keymap_screenshot", "KEY_F12"); settings->setDefault("keymap_toggle_hud", "KEY_F1"); settings->setDefault("keymap_toggle_chat", "KEY_F2"); diff --git a/src/environment.cpp b/src/environment.cpp index daec48e..5fd9872 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -3974,6 +3974,9 @@ void ClientEnvironment::step(float dtime) pressure_per_second = MYMAX(pressure_per_second, content_features(legs).pressure_per_second); pressure_per_second = MYMAX(pressure_per_second, content_features(torso).pressure_per_second); pressure_per_second = MYMAX(pressure_per_second, content_features(head).pressure_per_second); + // energy + if (lplayer->getEnergy() < 0.0) + damage_per_second = MYMAX(damage_per_second, 1); // cold zone if (warmth_per_second == 0 && pp.Y > 60 && myrand()%10 == 0) { if (pp.Y < 1024) { diff --git a/src/game.cpp b/src/game.cpp index f35c160..3ec8324 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -354,6 +354,201 @@ void draw_old_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font, font->draw(selected.c_str(), rect2, video::SColor(255,255,255,255), false, false, NULL); } } +void draw_progress_ring( + video::IVideoDriver *driver, + v2s32 screensize, + core::position2d pos, + s32 radius, + s16 value, + video::SColor color +) +{ + if (!value) + return; + const video::SColor colors[] = {color,color,color,color}; + video::ITexture *texture = driver->getTexture(getTexturePath("progress_ring.png").c_str()); + core::rect rect(pos.X-radius,pos.Y-radius,pos.X+radius,pos.Y+radius); + if (value >= 25) { + if (value >= 50) { + { + core::rect drect(rect); + drect.LowerRightCorner.X -= radius; + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + srect.LowerRightCorner.X /= 2; + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + if (value >= 75) { + if (value > 99) { + { + core::rect drect(rect); + drect.UpperLeftCorner.X += radius; + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + srect.UpperLeftCorner.X += srect.LowerRightCorner.X/2; + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + }else{ // top right corner + { + core::rect drect(rect); + drect.UpperLeftCorner.X += radius; + drect.UpperLeftCorner.Y += radius; + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + srect.UpperLeftCorner.X += srect.LowerRightCorner.X/2; + srect.UpperLeftCorner.Y += srect.LowerRightCorner.Y/2; + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + { + float os = (float)((value%25)*4)/100.0; + core::rect drect(rect);; + drect.UpperLeftCorner.X += radius+(radius-((float)radius*os)); + drect.UpperLeftCorner.Y += (radius-((float)radius*os)); + drect.LowerRightCorner.Y -= radius; + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + float v = srect.LowerRightCorner.X/2; + srect.UpperLeftCorner.X += v+(v-((float)v*os)); + v = srect.LowerRightCorner.Y/2; + srect.UpperLeftCorner.Y += (v-((float)v*os)); + srect.LowerRightCorner.Y -= v; + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + } + }else{ // bottom right corner + { + float os = (float)((value%25)*4)/100.0; + core::rect drect(rect); + drect.UpperLeftCorner.Y += radius+(radius-((float)radius*os)); + drect.UpperLeftCorner.X += radius; + drect.LowerRightCorner.X -= (radius-((float)radius*os)); + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + float v = srect.LowerRightCorner.X/2; + srect.UpperLeftCorner.X += v; + srect.LowerRightCorner.X -= (v-((float)v*os)); + v = srect.LowerRightCorner.Y/2; + srect.UpperLeftCorner.Y += v+(v-((float)v*os)); + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + } + }else{ // bottom left corner + { + core::rect drect(rect); + drect.LowerRightCorner.X -= radius; + drect.LowerRightCorner.Y -= radius; + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + srect.LowerRightCorner.X /= 2; + srect.LowerRightCorner.Y /= 2; + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + { + float os = (float)((value%25)*4)/100.0; + core::rect drect(rect); + drect.UpperLeftCorner.Y += radius; + drect.LowerRightCorner.X -= radius+((radius-(float)radius*os)); + drect.LowerRightCorner.Y -= (radius-((float)radius*os)); + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + float v = srect.LowerRightCorner.X/2; + srect.LowerRightCorner.X -= v+(v-((float)v*os)); + v = srect.LowerRightCorner.Y/2; + srect.UpperLeftCorner.Y += v; + srect.LowerRightCorner.Y -= (v-((float)v*os)); + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + } + }else{ // top left corner + { + float os = (float)((value%25)*4)/100.0; + core::rect drect(rect); + drect.UpperLeftCorner.X += radius-((float)radius*os); + drect.LowerRightCorner.X -= radius; + drect.LowerRightCorner.Y -= radius+(radius-((float)radius*os)); + core::rect srect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ); + float v = srect.LowerRightCorner.X/2; + srect.UpperLeftCorner.X += v-((float)v*os); + srect.LowerRightCorner.X /= 2; + v = srect.LowerRightCorner.Y/2; + srect.LowerRightCorner.Y -= v+(v-((float)v*os)); + driver->draw2DImage( + texture, + drect, + srect, + NULL, + colors, + true + ); + } + } +} void draw_hud( video::IVideoDriver *driver, gui::IGUIFont *font, @@ -367,6 +562,7 @@ void draw_hud( s32 halfbubblecount, bool have_hunger, s32 halfhungercount, + float energy, int crosshair ) { @@ -417,9 +613,30 @@ void draw_hud( content_t type = item->getContent(); if ((type&CONTENT_TOOLITEM_MASK) == CONTENT_TOOLITEM_MASK || (type&CONTENT_CLOTHESITEM_MASK) == CONTENT_CLOTHESITEM_MASK) { float w = item->getWear(); - w = (100.0/65535.0)*w; - txt = itows(100-w); + w = 100.0-((100.0/65535.0)*w); + txt = itows(w); txt += L"%"; + { + + video::SColor bcolor[10] = { + video::SColor(255,255,0,0), + video::SColor(255,255,40,0), + video::SColor(255,255,80,0), + video::SColor(255,255,110,0), + video::SColor(255,255,120,0), + video::SColor(255,255,140,0), + video::SColor(255,255,160,0), + video::SColor(255,170,180,0), + video::SColor(255,50,200,0), + video::SColor(255,0,255,0) + }; + int i = ((int)w)/10; + if (i < 0) + i = 0; + if (i > 9) + i = 9; + draw_progress_ring(driver,screensize,core::position2d(screensize.X-92,screensize.Y-92),40,w,bcolor[i]); + } }else{ txt = itows(item->getCount()); } @@ -559,21 +776,32 @@ void draw_hud( // health if (have_health) { int c = 55+(halfheartcount*10); - const video::SColor color(220,c,c,c); - const video::SColor colors[] = {color,color,color,color}; - video::ITexture *texture = driver->getTexture(getTexturePath("heart.png").c_str()); - core::rect rect(60,screensize.Y-108,108,screensize.Y-60); - driver->draw2DImage( - texture, - rect, - core::rect( - core::position2d(0,0), - core::dimension2di(texture->getOriginalSize()) - ), - NULL, - colors, - true - ); + float e = energy/((float)halfheartcount/100.0); + if (e > 100.0) + e = 100.0; + if (e < 0.0) + e = 0.0; + { + const video::SColor color(255,c,0,0); + draw_progress_ring(driver,screensize,core::position2d(84,screensize.Y-84),30,e,color); + } + { + const video::SColor color(220,c,c,c); + const video::SColor colors[] = {color,color,color,color}; + video::ITexture *texture = driver->getTexture(getTexturePath("heart.png").c_str()); + core::rect rect(60,screensize.Y-108,108,screensize.Y-60); + driver->draw2DImage( + texture, + rect, + core::rect( + core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()) + ), + NULL, + colors, + true + ); + } std::wstring txt = itows(halfheartcount*5); txt += L"%"; @@ -1639,16 +1867,6 @@ void the_game( statustext = wgettext("free_move enabled"); statustext_time = 0; } - }else if(input->wasKeyDown(getKeySetting(VLKC_FASTMOVE))) { - if (fast_move) { - fast_move = false; - statustext = wgettext("fast_move disabled"); - statustext_time = 0; - }else{ - fast_move = true; - statustext = wgettext("fast_move enabled"); - statustext_time = 0; - } }else if(input->wasKeyDown(getKeySetting(VLKC_SCREENSHOT))) { irr::video::IImage* const image = driver->createScreenShot(); if (image) { @@ -1889,31 +2107,38 @@ void the_game( false, false, false, - fast_move, + false, + false, free_move, camera_pitch, camera_yaw ); client.setPlayerControl(control); }else{ - /*bool a_up, - bool a_down, + /* + bool a_fwd, + bool a_back, bool a_left, bool a_right, bool a_jump, - bool a_superspeed, bool a_sneak, + bool a_up, + bool a_down, + bool a_fast, + bool a_free, float a_pitch, - float a_yaw*/ + float a_yaw + */ PlayerControl control( input->isKeyDown(getKeySetting(VLKC_FORWARD)), input->isKeyDown(getKeySetting(VLKC_BACKWARD)), input->isKeyDown(getKeySetting(VLKC_LEFT)), input->isKeyDown(getKeySetting(VLKC_RIGHT)), input->isKeyDown(getKeySetting(VLKC_JUMP)), - input->isKeyDown(getKeySetting(VLKC_USE)), input->isKeyDown(getKeySetting(VLKC_SNEAK)), - fast_move, + input->isKeyDown(getKeySetting(VLKC_UP)), + input->isKeyDown(getKeySetting(VLKC_DOWN)), + input->isKeyDown(getKeySetting(VLKC_RUN)), free_move, camera_pitch, camera_yaw @@ -2222,11 +2447,9 @@ void the_game( } - if (input->getRightClicked()) { - infostream<<"Ground right-clicked"<wasKeyDown(getKeySetting(VLKC_EXAMINE)) && !random_input) { // If metadata provides an inventory view, activate it - if (meta && meta->getDrawSpecString() != "" && !random_input) { + if (meta && meta->getDrawSpecString() != "") { infostream<<"Launching custom inventory view"<getRightClicked()) { + client.groundAction(1, nodepos, neighbourpos, g_selected_item); + camera.setDigging(1); // right click animation + } nodepos_old = nodepos; } @@ -2680,6 +2904,7 @@ void the_game( client.getAir(), client.getServerHunger(), hunger, + client.getEnergy(), crosshair ); } diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp index e5f4ace..bb80a0b 100644 --- a/src/guiKeyChangeMenu.cpp +++ b/src/guiKeyChangeMenu.cpp @@ -392,7 +392,7 @@ void GUIKeyChangeMenu::init_keys() key_cmd = getKeySetting(VLKC_COMMAND); key_range = getKeySetting(VLKC_RANGE); key_fly = getKeySetting(VLKC_FREEMOVE); - key_fast = getKeySetting(VLKC_FASTMOVE); + key_fast = getKeySetting(VLKC_RUN); key_use = getKeySetting(VLKC_USE); key_dump = getKeySetting(VLKC_PRINT_DEBUG); key_next_item = getKeySetting(VLKC_SELECT_NEXT); diff --git a/src/keycode.cpp b/src/keycode.cpp index de09d27..f3a648e 100644 --- a/src/keycode.cpp +++ b/src/keycode.cpp @@ -359,12 +359,15 @@ static const char* keymap_strings[] = { "keymap_jump", "keymap_sneak", "keymap_inventory", - "keymap_special1", + "keymap_use", "keymap_chat", "keymap_cmd", "keymap_rangeselect", "keymap_freemove", - "keymap_fastmove", + "keymap_up", + "keymap_down", + "keymap_run", + "keymap_examine", "keymap_screenshot", "keymap_toggle_hud", "keymap_toggle_chat", diff --git a/src/keycode.h b/src/keycode.h index 81f542e..9e73c51 100644 --- a/src/keycode.h +++ b/src/keycode.h @@ -78,7 +78,10 @@ enum KeyCode { VLKC_COMMAND, VLKC_RANGE, VLKC_FREEMOVE, - VLKC_FASTMOVE, + VLKC_UP, + VLKC_DOWN, + VLKC_RUN, + VLKC_EXAMINE, VLKC_SCREENSHOT, VLKC_TOGGLE_HUD, VLKC_TOGGLE_CHAT, diff --git a/src/player.cpp b/src/player.cpp index 3691aab..ee5f582 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -682,9 +682,8 @@ LocalPlayer::LocalPlayer(): m_sneak_node(32767,32767,32767), m_sneak_node_exists(false) { - // Initialize hp to 0, so that no hearts will be shown if server - // doesn't support health points hp = 0; + m_energy = 0.0; hunger = 0; m_character = g_settings->get("character_definition"); } @@ -929,54 +928,16 @@ void LocalPlayer::applyControl(float dtime) setSpeed(speed); } - // Whether superspeed mode is used or not - bool superspeed = false; - - // If free movement and fast movement, always move fast - if (control.free && control.fast) - superspeed = true; - - // Auxiliary button 1 (E) - if (control.aux1) { - if (control.free) { - // In free movement mode, aux1 descends - v3f speed = getSpeed(); - if (control.fast) { - speed.Y = -20*BS; - }else{ - speed.Y = -walkspeed_max; - } - setSpeed(speed); - }else if (is_climbing) { - v3f speed = getSpeed(); - speed.Y = -3*BS; - setSpeed(speed); - }else{ - // If not free movement but fast is allowed, aux1 is - // "Turbo button" - if (control.fast) - superspeed = true; - } - } - - if (control.up) + if (control.forward) speed += move_direction; - if (control.down) + if (control.backward) speed -= move_direction; if (control.left) speed += move_direction.crossProduct(v3f(0,1,0)); if (control.right) speed += move_direction.crossProduct(v3f(0,-1,0)); if (control.jump) { - if (control.free) { - v3f speed = getSpeed(); - if (control.fast) { - speed.Y = 20*BS; - }else{ - speed.Y = walkspeed_max; - } - setSpeed(speed); - }else if (touching_ground) { + if (touching_ground) { v3f speed = getSpeed(); /* NOTE: The d value in move() affects jump height by @@ -992,20 +953,65 @@ void LocalPlayer::applyControl(float dtime) speed.Y = 1.5*BS; setSpeed(speed); swimming_up = true; - } else if (is_climbing) { + } + } + if (control.up) { + if (control.free) { + v3f speed = getSpeed(); + if (control.fast) { + speed.Y = 20*BS; + }else{ + speed.Y = walkspeed_max; + } + setSpeed(speed); + }else if (in_water) { + // Use the oscillating value for getting out of water + // (so that the player doesn't fly on the surface) + v3f speed = getSpeed(); + speed.Y = 1.5*BS; + setSpeed(speed); + swimming_up = true; + }else if (is_climbing) { v3f speed = getSpeed(); speed.Y = 3*BS; setSpeed(speed); } } + if (control.down) { + if (control.free) { + // In free movement mode, aux1 descends + v3f speed = getSpeed(); + if (control.fast) { + speed.Y = -20*BS; + }else{ + speed.Y = -walkspeed_max; + } + setSpeed(speed); + }else if (is_climbing) { + v3f speed = getSpeed(); + speed.Y = -3*BS; + setSpeed(speed); + }else if (in_water) { + v3f speed = getSpeed(); + speed.Y = -5*BS; + setSpeed(speed); + } + } // The speed of the player (Y is ignored) - if (superspeed) { + if (control.fast) { + m_energy -= dtime; speed = speed.normalize() * walkspeed_max * 5.0; - }else if (control.sneak) { - speed = speed.normalize() * walkspeed_max / 3.0; }else{ - speed = speed.normalize() * walkspeed_max; + if (m_energy < hp) + m_energy += dtime*2; + if (m_energy > hp) + m_energy = hp; + if (control.sneak) { + speed = speed.normalize() * walkspeed_max / 3.0; + }else{ + speed = speed.normalize() * walkspeed_max; + } } f32 inc = walk_acceleration * BS * dtime; diff --git a/src/player.h b/src/player.h index 69b5589..fc0ff95 100644 --- a/src/player.h +++ b/src/player.h @@ -427,51 +427,55 @@ struct PlayerControl { PlayerControl() { - up = false; - down = false; + forward = false; + backward = false; left = false; right = false; jump = false; - aux1 = false; sneak = false; + up = false; + down = false; fast = false; free = false; pitch = 0; yaw = 0; } PlayerControl( - bool a_up, - bool a_down, + bool a_fwd, + bool a_back, bool a_left, bool a_right, bool a_jump, - bool a_aux1, bool a_sneak, + bool a_up, + bool a_down, bool a_fast, bool a_free, float a_pitch, float a_yaw ) { - up = a_up; - down = a_down; + forward = a_fwd; + backward = a_back; left = a_left; right = a_right; jump = a_jump; - aux1 = a_aux1; sneak = a_sneak; + up = a_up; + down = a_down; fast = a_fast; free = a_free; pitch = a_pitch; yaw = a_yaw; } - bool up; - bool down; + bool forward; + bool backward; bool left; bool right; bool jump; - bool aux1; bool sneak; + bool up; + bool down; bool fast; bool free; float pitch; @@ -495,6 +499,9 @@ public: void applyControl(float dtime); + void setEnergy(float e) {m_energy = e;} + float getEnergy() {return m_energy;} + video::ITexture* getTexture(); PlayerControl control; @@ -507,6 +514,7 @@ private: bool m_sneak_node_exists; v3s16 m_old_node_below; content_t m_old_node_below_type; + float m_energy; }; #endif // !SERVER diff --git a/src/utility.h b/src/utility.h index 9bd6b32..d0cbdf6 100644 --- a/src/utility.h +++ b/src/utility.h @@ -926,6 +926,13 @@ inline std::string ftos(float f) return o.str(); } +inline std::wstring ftows(float f) +{ + std::wstringstream o; + o<