From cfcc3fd428564e9bce73d94123a172bfd21375c8 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Wed, 25 Jan 2012 12:56:17 -0200 Subject: [PATCH] fix death issues, improve text messages --- TODO | 1 + modules/game/game.lua | 1 - modules/game/game.otui | 4 +- modules/game_textmessage/textmessage.lua | 82 +++++++++++++++--------- src/framework/math/rect.h | 2 +- src/framework/ui/uiwidget.cpp | 2 +- src/otclient/core/creature.cpp | 4 +- src/otclient/core/game.cpp | 80 ++++++++++++++++++++--- src/otclient/core/game.h | 7 +- src/otclient/core/localplayer.h | 1 + src/otclient/core/statictext.cpp | 44 ++++++------- src/otclient/core/statictext.h | 3 +- src/otclient/net/protocolgameparse.cpp | 49 +------------- 13 files changed, 161 insertions(+), 119 deletions(-) diff --git a/TODO b/TODO index aee91c45..2a94f07c 100644 --- a/TODO +++ b/TODO @@ -68,6 +68,7 @@ port to MacOs and iphone [bart] review style apply system rework widgets rendering order cache or preload otui files to avoid freezes from hd +change Align/Anchors lua API from enum to text == Client make possible to reload modules diff --git a/modules/game/game.lua b/modules/game/game.lua index 26be96fd..6574e10b 100644 --- a/modules/game/game.lua +++ b/modules/game/game.lua @@ -101,7 +101,6 @@ function Game.onConnectionError(message) end local function onApplicationClose() - print('close app') if Game.isOnline() then Game.logout(true) else diff --git a/modules/game/game.otui b/modules/game/game.otui index 3a357bfc..461c7b5d 100644 --- a/modules/game/game.otui +++ b/modules/game/game.otui @@ -28,4 +28,6 @@ UIGame UIWidget id: mouseGrabber - focusable: false \ No newline at end of file + focusable: false + visible: false + phantom: true \ No newline at end of file diff --git a/modules/game_textmessage/textmessage.lua b/modules/game_textmessage/textmessage.lua index d25ba262..ba3f28c0 100644 --- a/modules/game_textmessage/textmessage.lua +++ b/modules/game_textmessage/textmessage.lua @@ -5,21 +5,19 @@ importStyle 'textmessage.otui' -- private variables local MessageTypes = { - consoleRed = { color = '#F55E5E', consoleTab = 'Default' }, -- 18 - consoleOrange = { color = '#FE6500', consoleTab = 'Default' }, -- 19/20 - consoleBlue = { color = '#9F9DFD', consoleTab = 'Default' }, -- 27 - warning = { color = '#F55E5E', consoleTab = 'Server Log', windowLocation = 'center' }, -- 21 - infoDescription = { color = '#00EB00', consoleTab = 'Server Log', windowLocation = 'center', consoleOption = 'showInfoMessagesInConsole' }, -- 25 - eventAdvance = { color = '#FFFFFF', consoleTab = 'Server Log', windowLocation = 'center', consoleOption = 'showEventMessagesInConsole' }, -- 22 - eventDefault = { color = '#FFFFFF', consoleTab = 'Server Log', windowLocation = 'bottom', consoleOption = 'showEventMessagesInConsole' }, -- 23 - statusDefault = { color = '#FFFFFF', consoleTab = 'Server Log', windowLocation = 'bottom', consoleOption = 'showStatusMessagesInConsole' }, -- 24 - statusSmall = { color = '#FFFFFF', windowLocation = 'bottom' }, -- 26 + consoleRed = { color = '#F55E5E', consoleTab = 'Default' }, + consoleOrange = { color = '#FE6500', consoleTab = 'Default' }, + consoleBlue = { color = '#9F9DFD', consoleTab = 'Default' }, + warning = { color = '#F55E5E', consoleTab = 'Server Log', labelId = 'centerWarning', wrap = true }, + infoDescription = { color = '#00EB00', consoleTab = 'Server Log', labelId = 'centerInfo', consoleOption = 'showInfoMessagesInConsole', wrap = true }, + eventAdvance = { color = '#FFFFFF', consoleTab = 'Server Log', labelId = 'centerAdvance', consoleOption = 'showEventMessagesInConsole', wrap = true }, + eventDefault = { color = '#FFFFFF', consoleTab = 'Server Log', labelId = 'bottomStatus', consoleOption = 'showEventMessagesInConsole' }, + statusDefault = { color = '#FFFFFF', consoleTab = 'Server Log', labelId = 'bottomStatus', consoleOption = 'showStatusMessagesInConsole' }, + statusSmall = { color = '#FFFFFF', windowLocation = 'bottomStatus' }, } -local bottomLabelWidget -local centerLabelWidget -local bottomLabelHideEvent -local centerLabelHideEvent +local centerTextMessagePanel +local centerLabel -- private functions local function displayMessage(msgtype, msg, time) @@ -31,28 +29,22 @@ local function displayMessage(msgtype, msg, time) end end - if msgtype.windowLocation then - local label - local style - if msgtype.windowLocation == 'bottom' then - label = bottomLabelWidget - style = 'BottomLabel' - elseif msgtype.windowLocation == 'center' then - label = centerLabelWidget - style = 'CenterLabel' - end + if msgtype.labelId then + local label = Game.gameMapPanel:recursiveGetChildById(msgtype.labelId) label:setVisible(true) label:setText(msg) - label:setStyle(style) label:setColor(msgtype.color) + label:resizeToText() - if msgtype.windowLocation == 'center' then + if msgtype.wrap then + label:setWidth(label:getParent():getWidth()) label:wrapText() + label:setHeight(label:getTextSize().height) end if not time then - time = math.max(#msg * 75, 3000) + time = math.max(#msg * 100, 5000) else time = time * 1000 end @@ -61,10 +53,36 @@ local function displayMessage(msgtype, msg, time) end end +local function createTextMessageLabel(id, parent) + local label = createWidget('UILabel', parent) + label:setFont('verdana-11px-rounded') + label:setTextAlign(AlignCenter) + label:setId(id) + label:setMarginBottom(2) + label:setVisible(false) + return label +end + -- public functions + function TextMessage.create() - bottomLabelWidget = createWidget('UILabel', Game.gameMapPanel) - centerLabelWidget = createWidget('UILabel', Game.gameMapPanel) + centerTextMessagePanel = createWidget('Panel', Game.gameMapPanel) + centerTextMessagePanel:setId('centerTextMessagePanel') + local layout = UIVerticalLayout.create(centerTextMessagePanel) + layout:setFitChildren(true) + centerTextMessagePanel:setLayout(layout) + centerTextMessagePanel:setWidth(360) + centerTextMessagePanel:centerIn('parent') + + createTextMessageLabel('centerWarning', centerTextMessagePanel) + createTextMessageLabel('centerAdvance', centerTextMessagePanel) + createTextMessageLabel('centerInfo', centerTextMessagePanel) + + bottomStatusLabel = createTextMessageLabel('bottomStatus', Game.gameMapPanel) + bottomStatusLabel:setHeight(16) + bottomStatusLabel:addAnchor(AnchorBottom, 'parent', AnchorBottom) + bottomStatusLabel:addAnchor(AnchorLeft, 'parent', AnchorLeft) + bottomStatusLabel:addAnchor(AnchorRight, 'parent', AnchorRight) end function TextMessage.displayStatus(msg, time) @@ -84,11 +102,13 @@ end -- hooked events local function onGameDeath() - TextMessage.displayEventAdvance('You are dead.', 60) + local advanceLabel = Game.gameMapPanel:recursiveGetChildById('centerAdvance') + if advanceLabel:isVisible() then return end + TextMessage.displayEventAdvance('You are dead.') end -local function onGameTextMessage(msgtype, msg) - TextMessage.display(msgtype, msg) +local function onGameTextMessage(msgtypedesc, msg) + TextMessage.display(msgtypedesc, msg) end connect(Game, { onLogin = TextMessage.create, diff --git a/src/framework/math/rect.h b/src/framework/math/rect.h index 98c90075..1de40c29 100644 --- a/src/framework/math/rect.h +++ b/src/framework/math/rect.h @@ -261,7 +261,7 @@ public: return tmp; } - void bound(const TRect &r) { + void bind(const TRect &r) { if(isNull() || r.isNull()) return; diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index 472d00b4..8586e978 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -487,7 +487,7 @@ void UIWidget::bindRectToParent() UIWidgetPtr parent = getParent(); if(parent) { Rect parentRect = parent->getRect(); - boundRect.bound(parentRect); + boundRect.bind(parentRect); } setRect(boundRect); diff --git a/src/otclient/core/creature.cpp b/src/otclient/core/creature.cpp index 17e4ae22..93d2edda 100644 --- a/src/otclient/core/creature.cpp +++ b/src/otclient/core/creature.cpp @@ -146,10 +146,10 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe // calculate main rects Rect backgroundRect = Rect(x-(13.5), y, 27, 4); - backgroundRect.bound(visibleRect); + backgroundRect.bind(visibleRect); Rect textRect = Rect(x - m_nameSize.width() / 2.0, y-12, m_nameSize); - textRect.bound(visibleRect); + textRect.bind(visibleRect); // distance them if(textRect.top() == visibleRect.top()) diff --git a/src/otclient/core/game.cpp b/src/otclient/core/game.cpp index ee890d96..3434cd47 100644 --- a/src/otclient/core/game.cpp +++ b/src/otclient/core/game.cpp @@ -100,9 +100,78 @@ void Game::processLogout() void Game::processDeath() { m_dead = true; + m_localPlayer->stopWalk(); g_lua.callGlobalField("Game","onDeath"); } +void Game::processPlayerStats(double health, double maxHealth, + double freeCapacity, double experience, + double level, double levelPercent, + double mana, double maxMana, + double magicLevel, double magicLevelPercent, + double soul, double stamina) +{ + if(m_localPlayer->getHealth() != health || + m_localPlayer->getMaxHealth() != maxHealth) { + m_localPlayer->setStatistic(Otc::Health, health); + m_localPlayer->setStatistic(Otc::MaxHealth, maxHealth); + g_lua.callGlobalField("Game", "onHealthChange", health, maxHealth); + + // cannot walk while dying + if(health == 0) { + if(m_localPlayer->isPreWalking()) + m_localPlayer->stopWalk(); + m_localPlayer->lockWalk(); + } + } + + if(m_localPlayer->getStatistic(Otc::FreeCapacity) != freeCapacity) { + m_localPlayer->setStatistic(Otc::FreeCapacity, freeCapacity); + g_lua.callGlobalField("Game", "onFreeCapacityChange", freeCapacity); + } + + if(m_localPlayer->getStatistic(Otc::Experience) != experience) { + m_localPlayer->setStatistic(Otc::Experience, experience); + g_lua.callGlobalField("Game", "onExperienceChange", experience); + } + + if(m_localPlayer->getStatistic(Otc::Level) != level || + m_localPlayer->getStatistic(Otc::LevelPercent) != levelPercent) { + m_localPlayer->setStatistic(Otc::Level, level); + m_localPlayer->setStatistic(Otc::LevelPercent, levelPercent); + g_lua.callGlobalField("Game", "onLevelChange", level, levelPercent); + } + + if(m_localPlayer->getStatistic(Otc::Mana) != mana || + m_localPlayer->getStatistic(Otc::MaxMana) != maxMana) { + m_localPlayer->setStatistic(Otc::Mana, mana); + m_localPlayer->setStatistic(Otc::MaxMana, maxMana); + g_lua.callGlobalField("Game", "onManaChange", mana, maxMana); + } + + if(m_localPlayer->getStatistic(Otc::MagicLevel) != magicLevel || + m_localPlayer->getStatistic(Otc::MagicLevelPercent) != magicLevelPercent) { + m_localPlayer->setStatistic(Otc::MagicLevel, magicLevel); + m_localPlayer->setStatistic(Otc::MagicLevelPercent, magicLevelPercent); + g_lua.callGlobalField("Game", "onMagicLevelChange", magicLevel, magicLevelPercent); + } + + if(m_localPlayer->getStatistic(Otc::Soul) != soul) { + m_localPlayer->setStatistic(Otc::Soul, soul); + g_lua.callGlobalField("Game", "onSoulChange", soul); + } + + if(m_localPlayer->getStatistic(Otc::Stamina) != stamina) { + m_localPlayer->setStatistic(Otc::Stamina, stamina); + g_lua.callGlobalField("Game", "onStaminaChange", stamina); + } +} + +void Game::processTextMessage(const std::string& type, const std::string& message) +{ + g_lua.callGlobalField("Game","onTextMessage", type, message); +} + void Game::processCreatureSpeak(const std::string& name, int level, const std::string& type, const std::string& message, int channelId, const Position& creaturePos) { if(creaturePos.isValid() && (type == "say" || type == "whisper" || type == "yell" || type == "monsterSay" || type == "monsterYell")) { @@ -114,11 +183,6 @@ void Game::processCreatureSpeak(const std::string& name, int level, const std::s g_lua.callGlobalField("Game", "onCreatureSpeak", name, level, type, message, channelId, creaturePos); } -void Game::processTextMessage(const std::string& type, const std::string& message) -{ - g_lua.callGlobalField("Game","onTextMessage", type, message); -} - void Game::processContainerAddItem(int containerId, const ItemPtr& item) { if(item) @@ -137,11 +201,9 @@ void Game::processInventoryChange(int slot, const ItemPtr& item) void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos) { - if(!oldPos.isInRange(newPos, 1, 1, 0)) - logError("unexpected creature move"); - // animate walk - creature->walk(oldPos, newPos); + if(oldPos.isInRange(newPos, 1, 1, 0)) + creature->walk(oldPos, newPos); } void Game::processCreatureTeleport(const CreaturePtr& creature) diff --git a/src/otclient/core/game.h b/src/otclient/core/game.h index 58451d5b..718dbb7f 100644 --- a/src/otclient/core/game.h +++ b/src/otclient/core/game.h @@ -45,7 +45,12 @@ public: void processLogin(const LocalPlayerPtr& localPlayer, int serverBeat); void processLogout(); void processDeath(); - + void processPlayerStats(double health, double maxHealth, + double freeCapacity, double experience, + double level, double levelPercent, + double mana, double maxMana, + double magicLevel, double magicLevelPercent, + double soul, double stamina); void processTextMessage(const std::string& type, const std::string& message); void processCreatureSpeak(const std::string& name, int level, const std::string& type, const std::string& message, int channelId, const Position& creaturePos); void processContainerAddItem(int containerId, const ItemPtr& item); diff --git a/src/otclient/core/localplayer.h b/src/otclient/core/localplayer.h index e84a8e60..ac925b7e 100644 --- a/src/otclient/core/localplayer.h +++ b/src/otclient/core/localplayer.h @@ -52,6 +52,7 @@ public: bool isKnown() { return m_known; } bool isAttacking() { return m_attackingCreature != nullptr; } bool isFollowing() { return m_followingCreature != nullptr; } + bool isPreWalking() { return m_preWalking; } void unlockWalk() { m_walkLocked = false; } void lockWalk(); diff --git a/src/otclient/core/statictext.cpp b/src/otclient/core/statictext.cpp index 6daf9c0f..bb5f6255 100644 --- a/src/otclient/core/statictext.cpp +++ b/src/otclient/core/statictext.cpp @@ -33,11 +33,11 @@ StaticText::StaticText() void StaticText::draw(const Point& p, const Rect& visibleRect) { - if(m_font) { - Rect rect = Rect(p - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize); - if(visibleRect.contains(rect)) - m_font->renderText(m_text, rect, Fw::AlignCenter, m_color); - } + Rect rect = Rect(p - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize); + Rect boundRect = rect; + boundRect.bind(visibleRect); + if((boundRect.center() - rect.center()).length() < visibleRect.width() / 15) + m_font->renderText(m_text, boundRect, Fw::AlignCenter, m_color); } bool StaticText::addMessage(const std::string& name, const std::string& type, const std::string& message) @@ -59,7 +59,7 @@ bool StaticText::addMessage(const std::string& name, const std::string& type, co auto self = asStaticText(); g_dispatcher.scheduleEvent([self]() { self->removeMessage(); - }, DURATION); + }, std::max(DURATION_PER_CHARACTER * message.length(), MIN_DURATION)); return true; } @@ -71,9 +71,7 @@ void StaticText::removeMessage() if(m_messages.empty()) { // schedule removal auto self = asStaticText(); - g_dispatcher.scheduleEvent([self]() { - g_map.removeThing(self); - }, 0); + g_dispatcher.addEvent([self]() { g_map.removeThing(self); }); } else compose(); @@ -81,43 +79,43 @@ void StaticText::removeMessage() void StaticText::compose() { - m_text.clear(); + std::string text; + text.clear(); if(m_messageType == "say") { - m_text += m_name; - m_text += " says:\n"; + text += m_name; + text += " says:\n"; m_color = Color(239, 239, 0); } else if(m_messageType == "whisper") { - m_text += m_name; - m_text += " whispers:\n"; + text += m_name; + text += " whispers:\n"; m_color = Color(239, 239, 0); } else if(m_messageType == "yell") { - m_text += m_name; - m_text += " yells:\n"; + text += m_name; + text += " yells:\n"; m_color = Color(239, 239, 0); } else if(m_messageType == "monsterSay" || m_messageType == "monsterYell") { m_color = Color(254, 101, 0); } else if(m_messageType == "npcToPlayer") { - m_text += m_name; - m_text += " says:\n"; + text += m_name; + text += " says:\n"; m_color = Color(95, 247, 247); } else { logWarning("unknown speak type: ", m_messageType); } - // Todo: add break lines for(uint i = 0; i < m_messages.size(); ++i) { - m_text += m_messages[i]; + text += m_messages[i]; if(i < m_messages.size() - 1) - m_text += "\n"; + text += "\n"; } - if(m_font) - m_textSize = m_font->calculateTextRectSize(m_text); + m_text = m_font->wrapText(text, 200); + m_textSize = m_font->calculateTextRectSize(m_text); } diff --git a/src/otclient/core/statictext.h b/src/otclient/core/statictext.h index 88a86572..8a753b3c 100644 --- a/src/otclient/core/statictext.h +++ b/src/otclient/core/statictext.h @@ -30,7 +30,8 @@ class StaticText : public Thing { public: enum { - DURATION = 3000 + DURATION_PER_CHARACTER = 75, + MIN_DURATION = 3000 }; StaticText(); diff --git a/src/otclient/net/protocolgameparse.cpp b/src/otclient/net/protocolgameparse.cpp index e743ec8f..aed1c6a3 100644 --- a/src/otclient/net/protocolgameparse.cpp +++ b/src/otclient/net/protocolgameparse.cpp @@ -687,54 +687,7 @@ void ProtocolGame::parsePlayerStats(InputMessage& msg) double soul = msg.getU8(); double stamina = msg.getU16(); - //TODO: move to game - if(m_localPlayer->getStatistic(Otc::Health) != health || - m_localPlayer->getStatistic(Otc::MaxHealth) != maxHealth) { - m_localPlayer->setStatistic(Otc::Health, health); - m_localPlayer->setStatistic(Otc::MaxHealth, maxHealth); - g_lua.callGlobalField("Game", "onHealthChange", health, maxHealth); - } - - if(m_localPlayer->getStatistic(Otc::FreeCapacity) != freeCapacity) { - m_localPlayer->setStatistic(Otc::FreeCapacity, freeCapacity); - g_lua.callGlobalField("Game", "onFreeCapacityChange", freeCapacity); - } - - if(m_localPlayer->getStatistic(Otc::Experience) != experience) { - m_localPlayer->setStatistic(Otc::Experience, experience); - g_lua.callGlobalField("Game", "onExperienceChange", experience); - } - - if(m_localPlayer->getStatistic(Otc::Level) != level || - m_localPlayer->getStatistic(Otc::LevelPercent) != levelPercent) { - m_localPlayer->setStatistic(Otc::Level, level); - m_localPlayer->setStatistic(Otc::LevelPercent, levelPercent); - g_lua.callGlobalField("Game", "onLevelChange", level, levelPercent); - } - - if(m_localPlayer->getStatistic(Otc::Mana) != mana || - m_localPlayer->getStatistic(Otc::MaxMana) != maxMana) { - m_localPlayer->setStatistic(Otc::Mana, mana); - m_localPlayer->setStatistic(Otc::MaxMana, maxMana); - g_lua.callGlobalField("Game", "onManaChange", mana, maxMana); - } - - if(m_localPlayer->getStatistic(Otc::MagicLevel) != magicLevel || - m_localPlayer->getStatistic(Otc::MagicLevelPercent) != magicLevelPercent) { - m_localPlayer->setStatistic(Otc::MagicLevel, magicLevel); - m_localPlayer->setStatistic(Otc::MagicLevelPercent, magicLevelPercent); - g_lua.callGlobalField("Game", "onMagicLevelChange", magicLevel, magicLevelPercent); - } - - if(m_localPlayer->getStatistic(Otc::Soul) != soul) { - m_localPlayer->setStatistic(Otc::Soul, soul); - g_lua.callGlobalField("Game", "onSoulChange", soul); - } - - if(m_localPlayer->getStatistic(Otc::Stamina) != stamina) { - m_localPlayer->setStatistic(Otc::Stamina, stamina); - g_lua.callGlobalField("Game", "onStaminaChange", stamina); - } + g_game.processPlayerStats(health, maxHealth, freeCapacity, experience, level, levelPercent, mana, maxMana, magicLevel, magicLevelPercent, soul, stamina); } void ProtocolGame::parsePlayerSkills(InputMessage& msg)