fix death issues, improve text messages

This commit is contained in:
Eduardo Bart 2012-01-25 12:56:17 -02:00
parent 29f99ee9b3
commit cfcc3fd428
13 changed files with 161 additions and 119 deletions

1
TODO
View File

@ -68,6 +68,7 @@ port to MacOs and iphone
[bart] review style apply system [bart] review style apply system
rework widgets rendering order rework widgets rendering order
cache or preload otui files to avoid freezes from hd cache or preload otui files to avoid freezes from hd
change Align/Anchors lua API from enum to text
== Client == Client
make possible to reload modules make possible to reload modules

View File

@ -101,7 +101,6 @@ function Game.onConnectionError(message)
end end
local function onApplicationClose() local function onApplicationClose()
print('close app')
if Game.isOnline() then if Game.isOnline() then
Game.logout(true) Game.logout(true)
else else

View File

@ -29,3 +29,5 @@ UIGame
UIWidget UIWidget
id: mouseGrabber id: mouseGrabber
focusable: false focusable: false
visible: false
phantom: true

View File

@ -5,21 +5,19 @@ importStyle 'textmessage.otui'
-- private variables -- private variables
local MessageTypes = { local MessageTypes = {
consoleRed = { color = '#F55E5E', consoleTab = 'Default' }, -- 18 consoleRed = { color = '#F55E5E', consoleTab = 'Default' },
consoleOrange = { color = '#FE6500', consoleTab = 'Default' }, -- 19/20 consoleOrange = { color = '#FE6500', consoleTab = 'Default' },
consoleBlue = { color = '#9F9DFD', consoleTab = 'Default' }, -- 27 consoleBlue = { color = '#9F9DFD', consoleTab = 'Default' },
warning = { color = '#F55E5E', consoleTab = 'Server Log', windowLocation = 'center' }, -- 21 warning = { color = '#F55E5E', consoleTab = 'Server Log', labelId = 'centerWarning', wrap = true },
infoDescription = { color = '#00EB00', consoleTab = 'Server Log', windowLocation = 'center', consoleOption = 'showInfoMessagesInConsole' }, -- 25 infoDescription = { color = '#00EB00', consoleTab = 'Server Log', labelId = 'centerInfo', consoleOption = 'showInfoMessagesInConsole', wrap = true },
eventAdvance = { color = '#FFFFFF', consoleTab = 'Server Log', windowLocation = 'center', consoleOption = 'showEventMessagesInConsole' }, -- 22 eventAdvance = { color = '#FFFFFF', consoleTab = 'Server Log', labelId = 'centerAdvance', consoleOption = 'showEventMessagesInConsole', wrap = true },
eventDefault = { color = '#FFFFFF', consoleTab = 'Server Log', windowLocation = 'bottom', consoleOption = 'showEventMessagesInConsole' }, -- 23 eventDefault = { color = '#FFFFFF', consoleTab = 'Server Log', labelId = 'bottomStatus', consoleOption = 'showEventMessagesInConsole' },
statusDefault = { color = '#FFFFFF', consoleTab = 'Server Log', windowLocation = 'bottom', consoleOption = 'showStatusMessagesInConsole' }, -- 24 statusDefault = { color = '#FFFFFF', consoleTab = 'Server Log', labelId = 'bottomStatus', consoleOption = 'showStatusMessagesInConsole' },
statusSmall = { color = '#FFFFFF', windowLocation = 'bottom' }, -- 26 statusSmall = { color = '#FFFFFF', windowLocation = 'bottomStatus' },
} }
local bottomLabelWidget local centerTextMessagePanel
local centerLabelWidget local centerLabel
local bottomLabelHideEvent
local centerLabelHideEvent
-- private functions -- private functions
local function displayMessage(msgtype, msg, time) local function displayMessage(msgtype, msg, time)
@ -31,28 +29,22 @@ local function displayMessage(msgtype, msg, time)
end end
end end
if msgtype.windowLocation then if msgtype.labelId then
local label local label = Game.gameMapPanel:recursiveGetChildById(msgtype.labelId)
local style
if msgtype.windowLocation == 'bottom' then
label = bottomLabelWidget
style = 'BottomLabel'
elseif msgtype.windowLocation == 'center' then
label = centerLabelWidget
style = 'CenterLabel'
end
label:setVisible(true) label:setVisible(true)
label:setText(msg) label:setText(msg)
label:setStyle(style)
label:setColor(msgtype.color) label:setColor(msgtype.color)
label:resizeToText()
if msgtype.windowLocation == 'center' then if msgtype.wrap then
label:setWidth(label:getParent():getWidth())
label:wrapText() label:wrapText()
label:setHeight(label:getTextSize().height)
end end
if not time then if not time then
time = math.max(#msg * 75, 3000) time = math.max(#msg * 100, 5000)
else else
time = time * 1000 time = time * 1000
end end
@ -61,10 +53,36 @@ local function displayMessage(msgtype, msg, time)
end end
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 -- public functions
function TextMessage.create() function TextMessage.create()
bottomLabelWidget = createWidget('UILabel', Game.gameMapPanel) centerTextMessagePanel = createWidget('Panel', Game.gameMapPanel)
centerLabelWidget = createWidget('UILabel', 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 end
function TextMessage.displayStatus(msg, time) function TextMessage.displayStatus(msg, time)
@ -84,11 +102,13 @@ end
-- hooked events -- hooked events
local function onGameDeath() 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 end
local function onGameTextMessage(msgtype, msg) local function onGameTextMessage(msgtypedesc, msg)
TextMessage.display(msgtype, msg) TextMessage.display(msgtypedesc, msg)
end end
connect(Game, { onLogin = TextMessage.create, connect(Game, { onLogin = TextMessage.create,

View File

@ -261,7 +261,7 @@ public:
return tmp; return tmp;
} }
void bound(const TRect<T> &r) { void bind(const TRect<T> &r) {
if(isNull() || r.isNull()) if(isNull() || r.isNull())
return; return;

View File

@ -487,7 +487,7 @@ void UIWidget::bindRectToParent()
UIWidgetPtr parent = getParent(); UIWidgetPtr parent = getParent();
if(parent) { if(parent) {
Rect parentRect = parent->getRect(); Rect parentRect = parent->getRect();
boundRect.bound(parentRect); boundRect.bind(parentRect);
} }
setRect(boundRect); setRect(boundRect);

View File

@ -146,10 +146,10 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe
// calculate main rects // calculate main rects
Rect backgroundRect = Rect(x-(13.5), y, 27, 4); 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); Rect textRect = Rect(x - m_nameSize.width() / 2.0, y-12, m_nameSize);
textRect.bound(visibleRect); textRect.bind(visibleRect);
// distance them // distance them
if(textRect.top() == visibleRect.top()) if(textRect.top() == visibleRect.top())

View File

@ -100,9 +100,78 @@ void Game::processLogout()
void Game::processDeath() void Game::processDeath()
{ {
m_dead = true; m_dead = true;
m_localPlayer->stopWalk();
g_lua.callGlobalField("Game","onDeath"); 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) 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")) { 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); 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) void Game::processContainerAddItem(int containerId, const ItemPtr& item)
{ {
if(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) 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 // animate walk
creature->walk(oldPos, newPos); if(oldPos.isInRange(newPos, 1, 1, 0))
creature->walk(oldPos, newPos);
} }
void Game::processCreatureTeleport(const CreaturePtr& creature) void Game::processCreatureTeleport(const CreaturePtr& creature)

View File

@ -45,7 +45,12 @@ public:
void processLogin(const LocalPlayerPtr& localPlayer, int serverBeat); void processLogin(const LocalPlayerPtr& localPlayer, int serverBeat);
void processLogout(); void processLogout();
void processDeath(); 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 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 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); void processContainerAddItem(int containerId, const ItemPtr& item);

View File

@ -52,6 +52,7 @@ public:
bool isKnown() { return m_known; } bool isKnown() { return m_known; }
bool isAttacking() { return m_attackingCreature != nullptr; } bool isAttacking() { return m_attackingCreature != nullptr; }
bool isFollowing() { return m_followingCreature != nullptr; } bool isFollowing() { return m_followingCreature != nullptr; }
bool isPreWalking() { return m_preWalking; }
void unlockWalk() { m_walkLocked = false; } void unlockWalk() { m_walkLocked = false; }
void lockWalk(); void lockWalk();

View File

@ -33,11 +33,11 @@ StaticText::StaticText()
void StaticText::draw(const Point& p, const Rect& visibleRect) 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);
Rect rect = Rect(p - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize); Rect boundRect = rect;
if(visibleRect.contains(rect)) boundRect.bind(visibleRect);
m_font->renderText(m_text, rect, Fw::AlignCenter, m_color); 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) 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(); auto self = asStaticText();
g_dispatcher.scheduleEvent([self]() { g_dispatcher.scheduleEvent([self]() {
self->removeMessage(); self->removeMessage();
}, DURATION); }, std::max<int>(DURATION_PER_CHARACTER * message.length(), MIN_DURATION));
return true; return true;
} }
@ -71,9 +71,7 @@ void StaticText::removeMessage()
if(m_messages.empty()) { if(m_messages.empty()) {
// schedule removal // schedule removal
auto self = asStaticText(); auto self = asStaticText();
g_dispatcher.scheduleEvent([self]() { g_dispatcher.addEvent([self]() { g_map.removeThing(self); });
g_map.removeThing(self);
}, 0);
} }
else else
compose(); compose();
@ -81,43 +79,43 @@ void StaticText::removeMessage()
void StaticText::compose() void StaticText::compose()
{ {
m_text.clear(); std::string text;
text.clear();
if(m_messageType == "say") { if(m_messageType == "say") {
m_text += m_name; text += m_name;
m_text += " says:\n"; text += " says:\n";
m_color = Color(239, 239, 0); m_color = Color(239, 239, 0);
} }
else if(m_messageType == "whisper") { else if(m_messageType == "whisper") {
m_text += m_name; text += m_name;
m_text += " whispers:\n"; text += " whispers:\n";
m_color = Color(239, 239, 0); m_color = Color(239, 239, 0);
} }
else if(m_messageType == "yell") { else if(m_messageType == "yell") {
m_text += m_name; text += m_name;
m_text += " yells:\n"; text += " yells:\n";
m_color = Color(239, 239, 0); m_color = Color(239, 239, 0);
} }
else if(m_messageType == "monsterSay" || m_messageType == "monsterYell") { else if(m_messageType == "monsterSay" || m_messageType == "monsterYell") {
m_color = Color(254, 101, 0); m_color = Color(254, 101, 0);
} }
else if(m_messageType == "npcToPlayer") { else if(m_messageType == "npcToPlayer") {
m_text += m_name; text += m_name;
m_text += " says:\n"; text += " says:\n";
m_color = Color(95, 247, 247); m_color = Color(95, 247, 247);
} }
else { else {
logWarning("unknown speak type: ", m_messageType); logWarning("unknown speak type: ", m_messageType);
} }
// Todo: add break lines
for(uint i = 0; i < m_messages.size(); ++i) { for(uint i = 0; i < m_messages.size(); ++i) {
m_text += m_messages[i]; text += m_messages[i];
if(i < m_messages.size() - 1) if(i < m_messages.size() - 1)
m_text += "\n"; text += "\n";
} }
if(m_font) m_text = m_font->wrapText(text, 200);
m_textSize = m_font->calculateTextRectSize(m_text); m_textSize = m_font->calculateTextRectSize(m_text);
} }

View File

@ -30,7 +30,8 @@ class StaticText : public Thing
{ {
public: public:
enum { enum {
DURATION = 3000 DURATION_PER_CHARACTER = 75,
MIN_DURATION = 3000
}; };
StaticText(); StaticText();

View File

@ -687,54 +687,7 @@ void ProtocolGame::parsePlayerStats(InputMessage& msg)
double soul = msg.getU8(); double soul = msg.getU8();
double stamina = msg.getU16(); double stamina = msg.getU16();
//TODO: move to game g_game.processPlayerStats(health, maxHealth, freeCapacity, experience, level, levelPercent, mana, maxMana, magicLevel, magicLevelPercent, soul, stamina);
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);
}
} }
void ProtocolGame::parsePlayerSkills(InputMessage& msg) void ProtocolGame::parsePlayerSkills(InputMessage& msg)