From d67442dc495498423875030985ba3c498e2d19c4 Mon Sep 17 00:00:00 2001 From: Henrique Santiago Date: Thu, 29 Dec 2011 15:45:59 -0200 Subject: [PATCH] introduce statictext --- src/framework/const.h | 3 +- src/framework/util/color.h | 2 + src/otclient/CMakeLists.txt | 1 + src/otclient/core/animatedtext.cpp | 1 - src/otclient/core/animatedtext.h | 1 - src/otclient/core/declarations.h | 2 + src/otclient/core/map.cpp | 39 ++++++++- src/otclient/core/map.h | 1 + src/otclient/core/statictext.cpp | 117 +++++++++++++++++++++++++ src/otclient/core/statictext.h | 60 +++++++++++++ src/otclient/core/thing.h | 1 + src/otclient/core/tile.cpp | 1 - src/otclient/net/protocolgameparse.cpp | 17 ++-- 13 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 src/otclient/core/statictext.cpp create mode 100644 src/otclient/core/statictext.h diff --git a/src/framework/const.h b/src/framework/const.h index 4f6a275e..5ae9e70c 100644 --- a/src/framework/const.h +++ b/src/framework/const.h @@ -51,7 +51,8 @@ namespace Fw darkTeal = 0xff808000, gray = 0xffa0a0a0, darkGray = 0xff808080, - lightGray = 0xffc0c0c0 + lightGray = 0xffc0c0c0, + orange = 0xffff8c00 }; enum Key : uint8 { diff --git a/src/framework/util/color.h b/src/framework/util/color.h index 35d341d6..7e44496c 100644 --- a/src/framework/util/color.h +++ b/src/framework/util/color.h @@ -153,6 +153,8 @@ inline std::istream& operator>>(std::istream& in, Color& color) color = Fw::darkGray; } else if(tmp == "lightGray") { color = Fw::lightGray; + } else if(tmp == "orange") { + color = Fw::orange; } else { in.seekg(-tmp.length(), ios_base::cur); } diff --git a/src/otclient/CMakeLists.txt b/src/otclient/CMakeLists.txt index 7d46925a..2465e5f8 100644 --- a/src/otclient/CMakeLists.txt +++ b/src/otclient/CMakeLists.txt @@ -30,6 +30,7 @@ SET(otclient_SOURCES ${otclient_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/core/localplayer.cpp ${CMAKE_CURRENT_LIST_DIR}/core/outfit.cpp ${CMAKE_CURRENT_LIST_DIR}/core/animatedtext.cpp + ${CMAKE_CURRENT_LIST_DIR}/core/statictext.cpp # otclient ui ${CMAKE_CURRENT_LIST_DIR}/ui/uiitem.cpp diff --git a/src/otclient/core/animatedtext.cpp b/src/otclient/core/animatedtext.cpp index ec95a264..b092aec4 100644 --- a/src/otclient/core/animatedtext.cpp +++ b/src/otclient/core/animatedtext.cpp @@ -21,7 +21,6 @@ */ #include "animatedtext.h" -#include "outfit.h" #include "map.h" #include #include diff --git a/src/otclient/core/animatedtext.h b/src/otclient/core/animatedtext.h index 67e7e29d..96b3ae6d 100644 --- a/src/otclient/core/animatedtext.h +++ b/src/otclient/core/animatedtext.h @@ -51,5 +51,4 @@ private: double m_startTime; }; - #endif diff --git a/src/otclient/core/declarations.h b/src/otclient/core/declarations.h index 3331293b..4b130a1f 100644 --- a/src/otclient/core/declarations.h +++ b/src/otclient/core/declarations.h @@ -34,6 +34,7 @@ class Missile; class Player; class LocalPlayer; class AnimatedText; +class StaticText; typedef std::shared_ptr TilePtr; typedef std::shared_ptr ThingPtr; @@ -44,6 +45,7 @@ typedef std::shared_ptr MissilePtr; typedef std::shared_ptr PlayerPtr; typedef std::shared_ptr LocalPlayerPtr; typedef std::shared_ptr AnimatedTextPtr; +typedef std::shared_ptr StaticTextPtr; typedef std::vector ThingList; diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index 52538a14..2a6cc2fd 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -26,6 +26,7 @@ #include "tile.h" #include "item.h" #include "missile.h" +#include "statictext.h" #include #include #include @@ -135,6 +136,14 @@ void Map::draw(const Rect& rect) pos.y *= verticalStretchFactor; (*it)->draw(rect.topLeft() + pos); } + + // draw static text + for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) { + Point pos = positionTo2D((*it)->getPosition()) - m_drawOffset; + pos.x *= horizontalStretchFactor; + pos.y *= verticalStretchFactor; + (*it)->draw(rect.topLeft() + pos); + } } void Map::clean() @@ -240,18 +249,36 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) } else if(MissilePtr shot = thing->asMissile()) { m_missilesAtFloor[shot->getPosition().z].push_back(shot); - return; } else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) { - animatedText->start(); m_animatedTexts.push_back(animatedText); - return; + } + else if(StaticTextPtr staticText = thing->asStaticText()) { + bool mustAdd = true; + for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) { + StaticTextPtr cStaticText = *it; + if(cStaticText->getPosition() == pos) { + // try to combine messages + if(cStaticText->addMessage(staticText->getName(), staticText->getMessageType(), staticText->getFirstMessage())) { + mustAdd = false; + break; + } + else { + // must add another message and rearrenge current + } + } + + } + + if(mustAdd) + m_staticTexts.push_back(staticText); } else { tile->addThing(thing, stackPos); } thing->start(); + thing->setPosition(pos); } ThingPtr Map::getThing(const Position& pos, int stackPos) @@ -285,6 +312,12 @@ void Map::removeThing(const ThingPtr& thing) m_animatedTexts.erase(it); return; } + else if(StaticTextPtr staticText = thing->asStaticText()) { + auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText); + if(it != m_staticTexts.end()) + m_staticTexts.erase(it); + return; + } if(TilePtr& tile = m_tiles[thing->getPosition()]) tile->removeThing(thing); diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index 1f36e915..8a3269dc 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -79,6 +79,7 @@ private: std::map m_creatures; std::array, MAX_Z> m_missilesAtFloor; std::vector m_animatedTexts; + std::vector m_staticTexts; Light m_light; Position m_centralPosition; diff --git a/src/otclient/core/statictext.cpp b/src/otclient/core/statictext.cpp new file mode 100644 index 00000000..937019a7 --- /dev/null +++ b/src/otclient/core/statictext.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010-2011 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "statictext.h" +#include "map.h" +#include +#include +#include + +StaticText::StaticText() +{ + m_font = g_fonts.getFont("verdana-11px-rounded"); +} + +void StaticText::draw(const Point& p) +{ + if(m_font) + m_font->renderText(m_text, Rect(p - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize), Fw::AlignCenter, m_color); +} + +bool StaticText::addMessage(const std::string& name, int type, const std::string& message) +{ + // First message + if(m_messages.size() == 0) { + m_name = name; + m_type = type; + } + else { + // we can only add another message if it follows these conditions + if(m_name != name || m_type != type) + return false; + } + + m_messages.push_back(message); + compose(); + + auto self = asStaticText(); + g_dispatcher.scheduleEvent([self]() { + self->removeMessage(); + }, DURATION); + + return true; +} + +void StaticText::removeMessage() +{ + m_messages.erase(m_messages.begin()); + + if(m_messages.empty()) { + // schedule removal + auto self = asStaticText(); + g_dispatcher.scheduleEvent([self]() { + g_map.removeThing(self); + }, 0); + } + else + compose(); +} + +void StaticText::compose() +{ + m_text.clear(); + + if(m_type == Otc::SpeakSay) { + m_text += m_name; + m_text += " says:\n"; + m_color = Fw::yellow; + } + else if(m_type == Otc::SpeakWhisper) { + m_text += m_name; + m_text += " whispers:\n"; + m_color = Fw::yellow; + } + else if(m_type == Otc::SpeakYell) { + m_text += m_name; + m_text += " yells:\n"; + m_color = Fw::yellow; + } + else if(m_type == Otc::SpeakMonsterSay || m_type == Otc::SpeakMonsterYell) { + m_color = Fw::orange; + } + else if(m_type == Otc::SpeakPrivateNpcToPlayer) { + m_text += m_name; + m_text += " says:\n"; + m_color = Fw::blue; + } + + // Todo: add break lines + for(uint i = 0; i < m_messages.size(); ++i) { + m_text += m_messages[i]; + + if(i < m_messages.size() - 1) + m_text += "\n"; + } + + if(m_font) + m_textSize = m_font->calculateTextRectSize(m_text); +} diff --git a/src/otclient/core/statictext.h b/src/otclient/core/statictext.h new file mode 100644 index 00000000..bdd76a91 --- /dev/null +++ b/src/otclient/core/statictext.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010-2011 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STATICTEXT_H +#define STATICTEXT_H + +#include "thing.h" +#include + +class StaticText : public Thing +{ +public: + enum { + DURATION = 3000 + }; + + StaticText(); + + void draw(const Point& p); + + std::string getName() { return m_name; } + int getMessageType() { return m_type; } + std::string getFirstMessage() { return m_messages[0]; } + + bool addMessage(const std::string& name, int type, const std::string& message); + void removeMessage(); + + StaticTextPtr asStaticText() { return std::static_pointer_cast(shared_from_this()); } + +private: + void compose(); + + FontPtr m_font; + Size m_textSize; + std::vector m_messages; + std::string m_name, m_text; + int m_type; + Color m_color; +}; + +#endif diff --git a/src/otclient/core/thing.h b/src/otclient/core/thing.h index 58e55b90..f3234a4c 100644 --- a/src/otclient/core/thing.h +++ b/src/otclient/core/thing.h @@ -64,6 +64,7 @@ public: virtual PlayerPtr asPlayer() { return nullptr; } virtual LocalPlayerPtr asLocalPlayer() { return nullptr; } virtual AnimatedTextPtr asAnimatedText() { return nullptr; } + virtual StaticTextPtr asStaticText() { return nullptr; } protected: void internalDraw(const Point& p, int layer); diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index dd9ce625..91da5138 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -132,7 +132,6 @@ ThingPtr Tile::addThing(const ThingPtr& thing, int stackPos) if(stackPos < (int)m_things.size()) oldObject = m_things[stackPos]; m_things.insert(m_things.begin() + stackPos, thing); - thing->setPosition(m_position); return oldObject; } diff --git a/src/otclient/net/protocolgameparse.cpp b/src/otclient/net/protocolgameparse.cpp index e40a8824..04741dc4 100644 --- a/src/otclient/net/protocolgameparse.cpp +++ b/src/otclient/net/protocolgameparse.cpp @@ -33,6 +33,7 @@ #include #include #include +#include void ProtocolGame::parseMessage(InputMessage& msg) { @@ -746,8 +747,8 @@ void ProtocolGame::parsePlayerCancelAttack(InputMessage& msg) void ProtocolGame::parseCreatureSpeak(InputMessage& msg) { msg.getU32(); // unkSpeak - std::string name = msg.getString(); // name - int level = msg.getU16(); // level + std::string name = msg.getString(); + int level = msg.getU16(); int type = msg.getU8(); int channelId = 0; Position creaturePos; @@ -759,13 +760,13 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg) case Otc::SpeakMonsterSay: case Otc::SpeakMonsterYell: case Otc::SpeakPrivateNpcToPlayer: - creaturePos = parsePosition(msg); // creaturePos + creaturePos = parsePosition(msg); break; case Otc::SpeakChannelRed: case Otc::SpeakChannelOrange: case Otc::SpeakChannelYellow: case Otc::SpeakChannelWhite: - channelId = msg.getU16(); // channelId + channelId = msg.getU16(); break; case Otc::SpeakPrivate: case Otc::SpeakPrivatePlayerToNpc: @@ -777,11 +778,17 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg) break; } - std::string message = msg.getString(); // message + std::string message = msg.getString(); g_dispatcher.addEvent([=] { g_lua.callGlobalField("Game", "onCreatureSpeak", name, level, type, message, channelId, creaturePos); }); + + if(creaturePos.isValid()) { + StaticTextPtr staticText = StaticTextPtr(new StaticText); + staticText->addMessage(name, type, message); + g_map.addThing(staticText, creaturePos); + } } void ProtocolGame::parseChannelList(InputMessage& msg)