From 6e1372bd894d955300c40d69e5c882e9cc7d7523 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 May 2020 21:40:45 +0200 Subject: Add support for statbar “off state” icons (#9462) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for optional “off state” icons for statbars. “off state icons” can be used to denote the lack of something, like missing hearts or bubbles. Add "off state" textures to the builtin statbars. Co-authored-by: SmallJoker --- src/client/clientevent.h | 1 + src/client/game.cpp | 7 +++ src/client/hud.cpp | 96 ++++++++++++++++++++++++++++++------- src/client/hud.h | 5 +- src/hud.cpp | 1 + src/hud.h | 2 + src/network/clientpackethandler.cpp | 15 ++---- src/network/networkprotocol.h | 6 ++- src/script/common/c_content.cpp | 8 ++++ src/server.cpp | 3 +- 10 files changed, 113 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/client/clientevent.h b/src/client/clientevent.h index f5689c25b..7f3984b03 100644 --- a/src/client/clientevent.h +++ b/src/client/clientevent.h @@ -136,6 +136,7 @@ struct ClientEvent v3f *world_pos; v2s32 *size; s16 z_index; + std::string *text2; } hudadd; struct { diff --git a/src/client/game.cpp b/src/client/game.cpp index 4d7a85526..422e17d4f 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2672,6 +2672,7 @@ void Game::handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam) delete event->hudadd.offset; delete event->hudadd.world_pos; delete event->hudadd.size; + delete event->hudadd.text2; return; } @@ -2689,6 +2690,7 @@ void Game::handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam) e->world_pos = *event->hudadd.world_pos; e->size = *event->hudadd.size; e->z_index = event->hudadd.z_index; + e->text2 = *event->hudadd.text2; hud_server_to_client[server_id] = player->addHud(e); delete event->hudadd.pos; @@ -2699,6 +2701,7 @@ void Game::handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam) delete event->hudadd.offset; delete event->hudadd.world_pos; delete event->hudadd.size; + delete event->hudadd.text2; } void Game::handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam) @@ -2771,6 +2774,10 @@ void Game::handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *ca case HUD_STAT_Z_INDEX: e->z_index = event->hudchange.data; break; + + case HUD_STAT_TEXT2: + e->text2 = *event->hudchange.sdata; + break; } delete event->hudchange.v3fdata; diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 56763e7e4..f8f712762 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -332,7 +332,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) break; } case HUD_ELEM_STATBAR: { v2s32 offs(e->offset.X, e->offset.Y); - drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size); + drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->text2, + e->number, e->item, offs, e->size); break; } case HUD_ELEM_INVENTORY: { InventoryList *inv = inventory->getList(e->text); @@ -401,8 +402,9 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) } -void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture, - s32 count, v2s32 offset, v2s32 size) +void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, + const std::string &texture, const std::string &bgtexture, + s32 count, s32 maxcount, v2s32 offset, v2s32 size) { const video::SColor color(255, 255, 255, 255); const video::SColor colors[] = {color, color, color, color}; @@ -411,6 +413,11 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &tex if (!stat_texture) return; + video::ITexture *stat_texture_bg = nullptr; + if (!bgtexture.empty()) { + stat_texture_bg = tsrc->getTexture(bgtexture); + } + core::dimension2di srcd(stat_texture->getOriginalSize()); core::dimension2di dstd; if (size == v2s32()) { @@ -430,43 +437,100 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &tex p += offset; v2s32 steppos; - core::rect srchalfrect, dsthalfrect; switch (drawdir) { case HUD_DIR_RIGHT_LEFT: steppos = v2s32(-1, 0); - srchalfrect = core::rect(srcd.Width / 2, 0, srcd.Width, srcd.Height); - dsthalfrect = core::rect(dstd.Width / 2, 0, dstd.Width, dstd.Height); break; case HUD_DIR_TOP_BOTTOM: steppos = v2s32(0, 1); - srchalfrect = core::rect(0, 0, srcd.Width, srcd.Height / 2); - dsthalfrect = core::rect(0, 0, dstd.Width, dstd.Height / 2); break; case HUD_DIR_BOTTOM_TOP: steppos = v2s32(0, -1); - srchalfrect = core::rect(0, srcd.Height / 2, srcd.Width, srcd.Height); - dsthalfrect = core::rect(0, dstd.Height / 2, dstd.Width, dstd.Height); break; default: + // From left to right steppos = v2s32(1, 0); - srchalfrect = core::rect(0, 0, srcd.Width / 2, srcd.Height); - dsthalfrect = core::rect(0, 0, dstd.Width / 2, dstd.Height); + break; + } + + auto calculate_clipping_rect = [] (core::dimension2di src, + v2s32 steppos) -> core::rect { + + // Create basic rectangle + core::rect rect(0, 0, + src.Width - std::abs(steppos.X) * src.Width / 2, + src.Height - std::abs(steppos.Y) * src.Height / 2 + ); + // Move rectangle left or down + if (steppos.X == -1) + rect += v2s32(src.Width / 2, 0); + if (steppos.Y == -1) + rect += v2s32(0, src.Height / 2); + return rect; + }; + // Rectangles for 1/2 the actual value to display + core::rect srchalfrect, dsthalfrect; + // Rectangles for 1/2 the "off state" texture + core::rect srchalfrect2, dsthalfrect2; + + if (count % 2 == 1) { + // Need to draw halves: Calculate rectangles + srchalfrect = calculate_clipping_rect(srcd, steppos); + dsthalfrect = calculate_clipping_rect(dstd, steppos); + srchalfrect2 = calculate_clipping_rect(srcd, steppos * -1); + dsthalfrect2 = calculate_clipping_rect(dstd, steppos * -1); } + steppos.X *= dstd.Width; steppos.Y *= dstd.Height; + // Draw full textures for (s32 i = 0; i < count / 2; i++) { core::rect srcrect(0, 0, srcd.Width, srcd.Height); - core::rect dstrect(0,0, dstd.Width, dstd.Height); + core::rect dstrect(0, 0, dstd.Width, dstd.Height); dstrect += p; - draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true); + draw2DImageFilterScaled(driver, stat_texture, + dstrect, srcrect, NULL, colors, true); p += steppos; } if (count % 2 == 1) { - dsthalfrect += p; - draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true); + // Draw half a texture + draw2DImageFilterScaled(driver, stat_texture, + dsthalfrect + p, srchalfrect, NULL, colors, true); + + if (stat_texture_bg && maxcount > count) { + draw2DImageFilterScaled(driver, stat_texture_bg, + dsthalfrect2 + p, srchalfrect2, + NULL, colors, true); + p += steppos; + } + } + + if (stat_texture_bg && maxcount > count / 2) { + // Draw "off state" textures + s32 start_offset; + if (count % 2 == 1) + start_offset = count / 2 + 1; + else + start_offset = count / 2; + for (s32 i = start_offset; i < maxcount / 2; i++) { + core::rect srcrect(0, 0, srcd.Width, srcd.Height); + core::rect dstrect(0, 0, dstd.Width, dstd.Height); + + dstrect += p; + draw2DImageFilterScaled(driver, stat_texture_bg, + dstrect, srcrect, + NULL, colors, true); + p += steppos; + } + + if (maxcount % 2 == 1) { + draw2DImageFilterScaled(driver, stat_texture_bg, + dsthalfrect + p, srchalfrect, + NULL, colors, true); + } } } diff --git a/src/client/hud.h b/src/client/hud.h index cab115990..6274b1a83 100644 --- a/src/client/hud.h +++ b/src/client/hud.h @@ -82,8 +82,9 @@ public: private: bool calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *pos); - void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture, - s32 count, v2s32 offset, v2s32 size = v2s32()); + void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, + const std::string &texture, const std::string& bgtexture, + s32 count, s32 maxcount, v2s32 offset, v2s32 size = v2s32()); void drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, s32 inv_offset, InventoryList *mainlist, u16 selectitem, diff --git a/src/hud.cpp b/src/hud.cpp index 39625b5fd..3079b5cd8 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -46,6 +46,7 @@ const struct EnumString es_HudElementStat[] = {HUD_STAT_WORLD_POS, "world_pos"}, {HUD_STAT_SIZE, "size"}, {HUD_STAT_Z_INDEX, "z_index"}, + {HUD_STAT_TEXT2, "text2"}, {0, NULL}, }; diff --git a/src/hud.h b/src/hud.h index b0977c6a4..bab420ed2 100644 --- a/src/hud.h +++ b/src/hud.h @@ -77,6 +77,7 @@ enum HudElementStat { HUD_STAT_WORLD_POS, HUD_STAT_SIZE, HUD_STAT_Z_INDEX, + HUD_STAT_TEXT2, }; struct HudElement { @@ -93,6 +94,7 @@ struct HudElement { v3f world_pos; v2s32 size; s16 z_index = 0; + std::string text2; }; extern const EnumString es_HudElementType[]; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 8d0225a3d..7b1b1368c 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1102,22 +1102,16 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) v3f world_pos; v2s32 size; s16 z_index = 0; + std::string text2; *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item >> dir >> align >> offset; try { *pkt >> world_pos; - } - catch(SerializationError &e) {}; - - try { *pkt >> size; - } catch(SerializationError &e) {}; - - try { *pkt >> z_index; - } - catch(PacketError &e) {} + *pkt >> text2; + } catch(PacketError &e) {}; ClientEvent *event = new ClientEvent(); event->type = CE_HUDADD; @@ -1135,6 +1129,7 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) event->hudadd.world_pos = new v3f(world_pos); event->hudadd.size = new v2s32(size); event->hudadd.z_index = z_index; + event->hudadd.text2 = new std::string(text2); m_client_event_queue.push(event); } @@ -1171,7 +1166,7 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) *pkt >> v2fdata; - else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT) + else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT || stat == HUD_STAT_TEXT2) *pkt >> sdata; else if (stat == HUD_STAT_WORLD_POS) *pkt >> v3fdata; diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 527ebba7c..ab924f1db 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -560,10 +560,10 @@ enum ToClientCommand u32 id u8 type v2f1000 pos - u32 len + u16 len u8[len] name v2f1000 scale - u32 len2 + u16 len2 u8[len2] text u32 number u32 item @@ -573,6 +573,8 @@ enum ToClientCommand v3f1000 world_pos v2s32 size s16 z_index + u16 len3 + u8[len3] text2 */ TOCLIENT_HUDRM = 0x4a, diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index dac828316..540b7222f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -1871,6 +1871,7 @@ void read_hud_element(lua_State *L, HudElement *elem) elem->dir = getintfield_default(L, 2, "direction", 0); elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, getintfield_default(L, 2, "z_index", 0))); + elem->text2 = getstringfield_default(L, 2, "text2", ""); // Deprecated, only for compatibility's sake if (elem->dir == 0) @@ -1939,6 +1940,9 @@ void push_hud_element(lua_State *L, HudElement *elem) lua_pushnumber(L, elem->z_index); lua_setfield(L, -2, "z_index"); + + lua_pushstring(L, elem->text2.c_str()); + lua_setfield(L, -2, "text2"); } HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) @@ -2000,6 +2004,10 @@ HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, luaL_checknumber(L, 4))); *value = &elem->z_index; break; + case HUD_STAT_TEXT2: + elem->text2 = luaL_checkstring(L, 4); + *value = &elem->text2; + break; } return stat; } diff --git a/src/server.cpp b/src/server.cpp index 16e026ce2..b28c30e1e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1621,7 +1621,7 @@ void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form) pkt << id << (u8) form->type << form->pos << form->name << form->scale << form->text << form->number << form->item << form->dir << form->align << form->offset << form->world_pos << form->size - << form->z_index; + << form->z_index << form->text2; Send(&pkt); } @@ -1647,6 +1647,7 @@ void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void break; case HUD_STAT_NAME: case HUD_STAT_TEXT: + case HUD_STAT_TEXT2: pkt << *(std::string *) value; break; case HUD_STAT_WORLD_POS: -- cgit v1.2.3