diff --git a/modules/core_widgets/tooltip/tooltip.lua b/modules/core_widgets/tooltip/tooltip.lua index b890e925..5637a3c0 100644 --- a/modules/core_widgets/tooltip/tooltip.lua +++ b/modules/core_widgets/tooltip/tooltip.lua @@ -13,7 +13,7 @@ local function moveToolTip(tooltip) else pos.x = pos.x + 10 end - tooltip:setPos(pos) + tooltip:setPosition(pos) end -- public functions diff --git a/modules/game/map.lua b/modules/game/map.lua index 33b5cf24..25b6ee74 100644 --- a/modules/game/map.lua +++ b/modules/game/map.lua @@ -36,10 +36,10 @@ function UIMap:onDrop(widget, mousePos) spinbox:setCurrentIndex(data) local okButton = moveWindow:getChildById('buttonOk') - okButton.onClick = function() Game.move(widget.currentDragThing, tile:getPos(), spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end + okButton.onClick = function() Game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end moveWindow.onEnter = okButton.onClick else - Game.move(widget.currentDragThing, tile:getPos(), 1) + Game.move(widget.currentDragThing, tile:getPosition(), 1) end return true diff --git a/modules/game/thing.lua b/modules/game/thing.lua index e96c7b1b..8cea5aa6 100644 --- a/modules/game/thing.lua +++ b/modules/game/thing.lua @@ -1,11 +1,11 @@ function Thing:isInsideContainer() - local pos = self:getPos() + local pos = self:getPosition() return (pos and pos.x == 65535 and pos.y >= 64) end function Thing:getContainerId() - local pos = self:getPos() + local pos = self:getPosition() if not pos then return 0 end return pos.y - 64 end diff --git a/modules/game_containers/containers.lua b/modules/game_containers/containers.lua index 59698924..55fcabd4 100644 --- a/modules/game_containers/containers.lua +++ b/modules/game_containers/containers.lua @@ -46,7 +46,7 @@ function Containers.onContainerOpen(containerId, itemId, name, capacity, hasPare if i <= #items then local item = items[i] - item:setPos(itemWidget.position) + item:setPosition(itemWidget.position) itemWidget:setItem(item) end end @@ -76,7 +76,7 @@ function Containers.onContainerAddItem(containerId, item) local swapItem = itemWidget:getItem() if swapItem then - swapItem:setPos(nextItemWidget.position) + swapItem:setPosition(nextItemWidget.position) nextItemWidget:setItem(swapItem) end @@ -85,7 +85,7 @@ function Containers.onContainerAddItem(containerId, item) local itemWidget = container:getChildByIndex(1) if not itemWidget then return end - item:setPos(itemWidget.position) + item:setPosition(itemWidget.position) itemWidget:setItem(item) container.itemCount = container.itemCount + 1 @@ -98,7 +98,7 @@ function Containers.onContainerUpdateItem(containerId, slot, item) local itemWidget = container:getChildByIndex(slot + 1) if not itemWidget then return end itemWidget:setItem(item) - item:setPos(itemWidget.position) + item:setPosition(itemWidget.position) end function Containers.onContainerRemoveItem(containerId, slot) @@ -117,9 +117,9 @@ function Containers.onContainerRemoveItem(containerId, slot) if not nextItemWidget then return end local item = nextItemWidget:getItem() - local pos = item:getPos() + local pos = item:getPosition() pos.z = pos.z - 1 - item:setPos(pos) + item:setPosition(pos) itemWidget:setItem(item) nextItemWidget:setItem(nil) diff --git a/src/framework/graphics/framebuffer.cpp b/src/framework/graphics/framebuffer.cpp index 0622f570..8ead7420 100644 --- a/src/framework/graphics/framebuffer.cpp +++ b/src/framework/graphics/framebuffer.cpp @@ -26,6 +26,15 @@ uint FrameBuffer::boundFbo = 0; +FrameBuffer::FrameBuffer() +{ + m_clearColor = Fw::alpha; + + glGenFramebuffers(1, &m_fbo); + if(!m_fbo) + logFatal("Unable to create framebuffer object"); +} + FrameBuffer::FrameBuffer(const Size& size) { m_clearColor = Fw::alpha; @@ -44,6 +53,9 @@ FrameBuffer::~FrameBuffer() void FrameBuffer::resize(const Size& size) { + if(!size.isValid()) + return; + if(m_texture && m_texture->getSize() == size) return; @@ -88,6 +100,11 @@ void FrameBuffer::generateMipmaps() m_texture->generateMipmaps(); } +void FrameBuffer::draw(const Rect& dest, const Rect& src) +{ + g_painter.drawTexturedRect(dest, m_texture, src); +} + void FrameBuffer::draw(const Rect& dest) { g_painter.drawTexturedRect(dest, m_texture); diff --git a/src/framework/graphics/framebuffer.h b/src/framework/graphics/framebuffer.h index 2f242db5..321350b3 100644 --- a/src/framework/graphics/framebuffer.h +++ b/src/framework/graphics/framebuffer.h @@ -24,10 +24,12 @@ #define FRAMEBUFFER_H #include "declarations.h" +#include "texture.h" class FrameBuffer { public: + FrameBuffer(); FrameBuffer(const Size& size); virtual ~FrameBuffer(); @@ -36,10 +38,12 @@ public: void release(); void generateMipmaps(); void draw(const Rect& dest); + void draw(const Rect& dest, const Rect& src); void setClearColor(const Color& color) { m_clearColor = color; } TexturePtr getTexture() { return m_texture; } + const Size& getSize() { return m_texture->getSize(); } private: void internalBind(); diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index d4e26986..35951227 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -106,3 +106,10 @@ void Graphics::setViewportSize(const Size& size) m_viewportSize = size; } +int Graphics::getMaxTextureSize() +{ + static GLint maxTexSize = -1; + if(maxTexSize == -1) + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); + return maxTexSize; +} diff --git a/src/framework/graphics/graphics.h b/src/framework/graphics/graphics.h index 4e5adf8c..b811bb7e 100644 --- a/src/framework/graphics/graphics.h +++ b/src/framework/graphics/graphics.h @@ -40,6 +40,7 @@ public: void setViewportSize(const Size& size); + int getMaxTextureSize(); const Size& getViewportSize() { return m_viewportSize; } TexturePtr getEmptyTexture() { return m_emptyTexture; } diff --git a/src/framework/graphics/particle.cpp b/src/framework/graphics/particle.cpp index 972dd791..91f8700a 100644 --- a/src/framework/graphics/particle.cpp +++ b/src/framework/graphics/particle.cpp @@ -29,7 +29,7 @@ Particle::Particle(const Point& pos, const Size& startSize, const Size& finalSiz m_colors = colors; m_colorsStops = colorsStops; - m_pos = PointF(pos.x, pos.y); + m_position = PointF(pos.x, pos.y); m_startSize = startSize; m_finalSize = finalSize; m_velocity = velocity; @@ -80,18 +80,18 @@ void Particle::updatePosition(double elapsedTime) PointF delta = m_velocity * elapsedTime; delta.y *= -1; // painter orientate Y axis in the inverse direction - PointF position = m_pos + delta; + PointF position = m_position + delta; - if(m_pos != position) { + if(m_position != position) { mustRedraw = true; - m_pos += delta; + m_position += delta; } // update acceleration m_velocity += m_acceleration * elapsedTime; } - m_rect.move((int)m_pos.x - m_size.width() / 2, (int)m_pos.y - m_size.height() / 2); + m_rect.move((int)m_position.x - m_size.width() / 2, (int)m_position.y - m_size.height() / 2); } void Particle::updateSize() diff --git a/src/framework/graphics/particle.h b/src/framework/graphics/particle.h index 692f4131..305cf1d9 100644 --- a/src/framework/graphics/particle.h +++ b/src/framework/graphics/particle.h @@ -36,10 +36,10 @@ public: bool hasFinished() { return m_finished; } - PointF getPos() { return m_pos; } + PointF getPosition() { return m_position; } PointF getVelocity() { return m_velocity; } - void setPos(const PointF& position) { m_pos = position; } + void setPosition(const PointF& position) { m_position = position; } void setVelocity(const PointF& velocity) { m_velocity = velocity; } private: @@ -51,7 +51,7 @@ private: std::vector m_colors; std::vector m_colorsStops; TexturePtr m_texture; - PointF m_pos; + PointF m_position; PointF m_velocity; PointF m_acceleration; Size m_size, m_startSize, m_finalSize; diff --git a/src/framework/graphics/particleaffector.cpp b/src/framework/graphics/particleaffector.cpp index 1576ca67..0596e6a2 100644 --- a/src/framework/graphics/particleaffector.cpp +++ b/src/framework/graphics/particleaffector.cpp @@ -115,7 +115,7 @@ bool AttractionAffector::load(const OTMLNodePtr& node) for(const OTMLNodePtr& childNode : node->children()) { if(childNode->tag() == "position") - m_pos = childNode->value(); + m_position = childNode->value(); else if(childNode->tag() == "acceleration") m_acceleration = childNode->value(); else if(childNode->tag() == "velocity-reduction-percent") @@ -131,8 +131,8 @@ void AttractionAffector::updateParticle(const ParticlePtr& particle, double elap if(!m_active) return; - PointF pPosition = particle->getPos(); - PointF d = PointF(m_pos.x - pPosition.x, pPosition.y - m_pos.y); + PointF pPosition = particle->getPosition(); + PointF d = PointF(m_position.x - pPosition.x, pPosition.y - m_position.y); if(d.length() == 0) return; diff --git a/src/framework/graphics/particleaffector.h b/src/framework/graphics/particleaffector.h index 3f72116f..dbfd2f2c 100644 --- a/src/framework/graphics/particleaffector.h +++ b/src/framework/graphics/particleaffector.h @@ -57,7 +57,7 @@ public: void updateParticle(const ParticlePtr& particle, double elapsedTime); private: - Point m_pos; + Point m_position; float m_acceleration, m_reduction; bool m_repelish; }; diff --git a/src/framework/graphics/particleemitter.cpp b/src/framework/graphics/particleemitter.cpp index 2b5c18fd..8111291a 100644 --- a/src/framework/graphics/particleemitter.cpp +++ b/src/framework/graphics/particleemitter.cpp @@ -31,7 +31,7 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent) { m_parent = parent; - m_pos = Point(0, 0); + m_position = Point(0, 0); m_duration = -1; m_delay = 0; m_burstRate = 1; m_burstCount = 32; @@ -65,7 +65,7 @@ bool ParticleEmitter::load(const OTMLNodePtr& node) for(const OTMLNodePtr& childNode : node->children()) { // self related if(childNode->tag() == "position") - m_pos = childNode->value(); + m_position = childNode->value(); else if(childNode->tag() == "duration") m_duration = childNode->value(); else if(childNode->tag() == "delay") @@ -199,7 +199,7 @@ void ParticleEmitter::update(double elapsedTime) float pRadius = Fw::randomRange(m_pMinPositionRadius, m_pMaxPositionRadius); float pAngle = Fw::randomRange(m_pMinPositionAngle, m_pMaxPositionAngle); - Point pPosition = m_pos + Point(pRadius * cos(pAngle), pRadius * sin(pAngle)); + Point pPosition = m_position + Point(pRadius * cos(pAngle), pRadius * sin(pAngle)); for(int p = 0; p < m_burstCount; ++p) { diff --git a/src/framework/graphics/particleemitter.h b/src/framework/graphics/particleemitter.h index 12e88ef0..402a96e4 100644 --- a/src/framework/graphics/particleemitter.h +++ b/src/framework/graphics/particleemitter.h @@ -44,7 +44,7 @@ private: ParticleSystemWeakPtr m_parent; // self related - Point m_pos; + Point m_position; float m_duration, m_delay; double m_elapsedTime; bool m_finished, m_active; diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index b6ff7b23..cb97145e 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -128,6 +128,70 @@ std::vector Texture::getPixels() return pixels; } +void Texture::generateBilinearMipmaps() +{ + std::vector inPixels = getPixels(); + + bind(); + + if(!m_useMipmaps) { + m_useMipmaps = true; + setupFilters(); + } + + Size inSize = getSize(); + Size outSize = inSize / 2; + std::vector outPixels(outSize.area()*4); + + int mipmap = 1; + while(true) { + for(int x=0;x 0) + outPixel[i] = pixelsSum[i] / usedPixels; + else + outPixel[i] = 0; + } + + outPixel[3] = pixelsSum[3]/4; + } + } + + glTexImage2D(GL_TEXTURE_2D, mipmap++, GL_RGBA, outSize.width(), outSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, &outPixels[0]); + + if(inSize.width() == 1 || inSize.height() == 1) + break; + + inPixels = outPixels; + inSize /= 2; + outSize /= 2; + } +} + void Texture::setupFilters() { GLint minFilter; diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index 9d0ed6e5..e410434b 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -35,6 +35,7 @@ public: void bind() { glBindTexture(GL_TEXTURE_2D, m_textureId); } void generateMipmaps(); + void generateBilinearMipmaps(); void setSmooth(bool smooth); GLuint getId() { return m_textureId; } diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 24397901..243366a6 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -154,7 +154,7 @@ void Application::registerLuaFunctions() g_lua.bindClassMemberFunction("setWidth", &UIWidget::setWidth); g_lua.bindClassMemberFunction("setHeight", &UIWidget::setHeight); g_lua.bindClassMemberFunction("setSize", &UIWidget::setSize); - g_lua.bindClassMemberFunction("setPos", &UIWidget::setPos); + g_lua.bindClassMemberFunction("setPosition", &UIWidget::setPosition); g_lua.bindClassMemberFunction("setColor", &UIWidget::setColor); g_lua.bindClassMemberFunction("setBackgroundColor", &UIWidget::setBackgroundColor); g_lua.bindClassMemberFunction("setBackgroundOffsetX", &UIWidget::setBackgroundOffsetX); @@ -192,7 +192,7 @@ void Application::registerLuaFunctions() g_lua.bindClassMemberFunction("setOpacity", &UIWidget::setOpacity); g_lua.bindClassMemberFunction("getX", &UIWidget::getX); g_lua.bindClassMemberFunction("getY", &UIWidget::getY); - g_lua.bindClassMemberFunction("getPos", &UIWidget::getPos); + g_lua.bindClassMemberFunction("getPosition", &UIWidget::getPosition); g_lua.bindClassMemberFunction("getWidth", &UIWidget::getWidth); g_lua.bindClassMemberFunction("getHeight", &UIWidget::getHeight); g_lua.bindClassMemberFunction("getSize", &UIWidget::getSize); @@ -409,7 +409,7 @@ void Application::registerLuaFunctions() g_lua.bindClassStaticFunction("g_window", "getWidth", std::bind(&PlatformWindow::getWidth, &g_window)); g_lua.bindClassStaticFunction("g_window", "getHeight", std::bind(&PlatformWindow::getHeight, &g_window)); g_lua.bindClassStaticFunction("g_window", "getUnmaximizedPos", std::bind(&PlatformWindow::getUnmaximizedPos, &g_window)); - g_lua.bindClassStaticFunction("g_window", "getPos", std::bind(&PlatformWindow::getPos, &g_window)); + g_lua.bindClassStaticFunction("g_window", "getPosition", std::bind(&PlatformWindow::getPosition, &g_window)); g_lua.bindClassStaticFunction("g_window", "getX", std::bind(&PlatformWindow::getX, &g_window)); g_lua.bindClassStaticFunction("g_window", "getY", std::bind(&PlatformWindow::getY, &g_window)); g_lua.bindClassStaticFunction("g_window", "getMousePos", std::bind(&PlatformWindow::getMousePos, &g_window)); diff --git a/src/framework/math/point.h b/src/framework/math/point.h index c17bd598..adcc1747 100644 --- a/src/framework/math/point.h +++ b/src/framework/math/point.h @@ -56,10 +56,10 @@ public: TPoint& operator+=(T other) { x+=other; y+=other; return *this; } TPoint operator-(T other) const { return TPoint(x - other, y - other); } TPoint& operator-=(T other) { x-=other; y-=other; return *this; } - TPoint operator*(const T v) const { return TPoint(x*v, y*v); } - TPoint& operator*=(const T v) { x*=v; y*=v; return *this; } - TPoint operator/(const T v) const { return TPoint(x/v, y/v); } - TPoint& operator/=(const T v) { x/=v; y/=v; return *this; } + TPoint operator*(float v) const { return TPoint(x*v, y*v); } + TPoint& operator*=(float v) { x*=v; y*=v; return *this; } + TPoint operator/(float v) const { return TPoint(x/v, y/v); } + TPoint& operator/=(float v) { x/=v; y/=v; return *this; } bool operator<=(const TPoint&other) const { return x<=other.x && y<=other.y; } bool operator>=(const TPoint&other) const { return x>=other.x && y>=other.y; } diff --git a/src/framework/math/size.h b/src/framework/math/size.h index a89085b2..f87523ea 100644 --- a/src/framework/math/size.h +++ b/src/framework/math/size.h @@ -52,10 +52,14 @@ public: TSize& operator+=(const TSize& other) { wd+=other.wd; ht+=other.ht; return *this; } TSize operator-(const TSize& other) const { return TSize(wd - other.wd, ht - other.ht); } TSize& operator-=(const TSize& other) { wd-=other.wd; ht-=other.ht; return *this; } + TSize operator*(const TSize& other) const { return TSize((T)other.wd*wd, (T)ht*other.ht); } + TSize& operator*=(const TSize& other) { wd=(T)other.wd*wd; ht=(T)ht*other.ht; return *this; } + TSize operator/(const TSize& other) const { return TSize((T)wd/other.wd, (T)ht/other.ht); } + TSize& operator/=(const TSize& other) { (T)wd/=other.wd; (T)ht/=other.ht; return *this; } TSize operator*(const float v) const { return TSize((T)v*wd, (T)ht*v); } TSize& operator*=(const float v) { wd=(T)v*wd; ht=(T)ht*v; return *this; } TSize operator/(const float v) const { return TSize((T)wd/v, (T)ht/v); } - TSize& operator/=(const float v) { (T)wd/=v; (T)ht/=v; return *this; } + TSize& operator/=(const float v) { wd/=v; ht/=v; return *this; } bool operator<=(const TSize&other) const { return wd<=other.wd || ht<=other.ht; } bool operator>=(const TSize&other) const { return wd>=other.wd || ht>=other.ht; } diff --git a/src/framework/net/inputmessage.h b/src/framework/net/inputmessage.h index 31fa13d9..7ec65af9 100644 --- a/src/framework/net/inputmessage.h +++ b/src/framework/net/inputmessage.h @@ -33,7 +33,7 @@ public: BUFFER_MAXSIZE = 16384, HEADER_POS = 0, HEADER_LENGTH = 2, - CHECKSUM_POS = 2, + CHECKSUm_position = 2, CHECKSUM_LENGTH = 4, DATA_POS = 6, UNENCRYPTED_DATA_POS = 8 diff --git a/src/framework/net/outputmessage.h b/src/framework/net/outputmessage.h index bdc72309..5ce61de4 100644 --- a/src/framework/net/outputmessage.h +++ b/src/framework/net/outputmessage.h @@ -36,7 +36,7 @@ public: BUFFER_MAXSIZE = 1024, HEADER_POS = 0, HEADER_LENGTH = 2, - CHECKSUM_POS = 2, + CHECKSUm_position = 2, CHECKSUM_LENGTH = 4, DATA_POS = 6 }; diff --git a/src/framework/net/protocol.cpp b/src/framework/net/protocol.cpp index e17471ee..0c20b765 100644 --- a/src/framework/net/protocol.cpp +++ b/src/framework/net/protocol.cpp @@ -71,7 +71,7 @@ void Protocol::send(OutputMessage& outputMessage) // set checksum uint32 checksum = getAdlerChecksum(outputMessage.getBuffer() + OutputMessage::DATA_POS, outputMessage.getMessageSize()); - outputMessage.setWritePos(OutputMessage::CHECKSUM_POS); + outputMessage.setWritePos(OutputMessage::CHECKSUm_position); outputMessage.addU32(checksum); // set size @@ -107,7 +107,7 @@ void Protocol::internalRecvHeader(uint8* buffer, uint16 size) void Protocol::internalRecvData(uint8* buffer, uint16 size) { - memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUM_POS, buffer, size); + memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUm_position, buffer, size); if(m_checksumEnabled) { uint32 checksum = getAdlerChecksum(m_inputMessage.getBuffer() + InputMessage::DATA_POS, m_inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH); diff --git a/src/framework/platform/platformwindow.cpp b/src/framework/platform/platformwindow.cpp index 05c2cde8..af3c4bed 100644 --- a/src/framework/platform/platformwindow.cpp +++ b/src/framework/platform/platformwindow.cpp @@ -38,7 +38,7 @@ PlatformWindow& g_window = window; void PlatformWindow::updateUnmaximizedCoords() { if(!isMaximized() && !isFullscreen()) { - m_unmaximizedPos = m_pos; + m_unmaximizedPos = m_position; m_unmaximizedSize = m_size; } } diff --git a/src/framework/platform/platformwindow.h b/src/framework/platform/platformwindow.h index dd3d92f0..21b32fdb 100644 --- a/src/framework/platform/platformwindow.h +++ b/src/framework/platform/platformwindow.h @@ -73,9 +73,9 @@ public: int getWidth() { return m_size.width(); } int getHeight() { return m_size.height(); } Point getUnmaximizedPos() { return m_unmaximizedPos; } - Point getPos() { return m_pos; } - int getX() { return m_pos.x; } - int getY() { return m_pos.y; } + Point getPosition() { return m_position; } + int getX() { return m_position.x; } + int getY() { return m_position.y; } Point getMousePos() { return m_inputEvent.mousePos; } int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; } bool isKeyPressed(Fw::Key keyCode) { return m_keysState[keyCode]; } @@ -104,7 +104,7 @@ protected: Timer m_keyPressTimer; Size m_size; - Point m_pos; + Point m_position; Size m_unmaximizedSize; Point m_unmaximizedPos; InputEvent m_inputEvent; diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index ab866e22..4e160abd 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -278,7 +278,7 @@ void WIN32Window::internalCreateWindow() DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; DWORD dwStyle = WS_OVERLAPPEDWINDOW; - RECT windowRect = {m_pos.x, m_pos.y, m_pos.x + m_size.width(), m_pos.y + m_size.height()}; + RECT windowRect = {m_position.x, m_position.y, m_position.x + m_size.width(), m_position.y + m_size.height()}; AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); updateUnmaximizedCoords(); @@ -361,14 +361,14 @@ void *WIN32Window::getExtensionProcAddress(const char *ext) void WIN32Window::move(const Point& pos) { - RECT windowRect = {pos.x, pos.y, m_pos.x + m_size.width(), m_pos.y + m_size.height()}; + RECT windowRect = {pos.x, pos.y, m_position.x + m_size.width(), m_position.y + m_size.height()}; AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE); } void WIN32Window::resize(const Size& size) { - RECT windowRect = {m_pos.x, m_pos.y, m_pos.x + size.width(), m_pos.y + size.height()}; + RECT windowRect = {m_position.x, m_position.y, m_position.x + size.width(), m_position.y + size.height()}; AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE); } @@ -503,8 +503,8 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar break; } case WM_MOVE: { - m_pos.x = LOWORD(lParam); - m_pos.y = HIWORD(lParam); + m_position.x = LOWORD(lParam); + m_position.y = HIWORD(lParam); break; } case WM_SIZE: { diff --git a/src/framework/platform/x11window.cpp b/src/framework/platform/x11window.cpp index aa274957..24059ea9 100644 --- a/src/framework/platform/x11window.cpp +++ b/src/framework/platform/x11window.cpp @@ -284,7 +284,7 @@ void X11Window::internalCreateWindow() updateUnmaximizedCoords(); m_window = XCreateWindow(m_display, m_rootWindow, - m_pos.x, m_pos.y, m_size.width(), m_size.height(), + m_position.x, m_position.y, m_size.width(), m_size.height(), 0, depth, InputOutput, @@ -300,7 +300,7 @@ void X11Window::internalCreateWindow() XSetWMHints(m_display, m_window, &hints); // ensure window position - XMoveWindow(m_display, m_window, m_pos.x, m_pos.y); + XMoveWindow(m_display, m_window, m_position.x, m_position.y); // handle wm_delete events m_wmDelete = XInternAtom(m_display, "WM_DELETE_WINDOW", True); @@ -580,7 +580,7 @@ void X11Window::poll() } // updates window pos - m_pos = newPos; + m_position = newPos; updateUnmaximizedCoords(); break; } diff --git a/src/framework/ui/uiwidget.cpp b/src/framework/ui/uiwidget.cpp index 8586e978..660bbf44 100644 --- a/src/framework/ui/uiwidget.cpp +++ b/src/framework/ui/uiwidget.cpp @@ -90,7 +90,7 @@ void UIWidget::drawChildren() g_painter.setColor(Fw::green); g_painter.drawBoundingRect(child->getRect()); } - //g_fonts.getDefaultFont()->renderText(child->getId(), child->getPos() + Point(2, 0), Fw::red); + //g_fonts.getDefaultFont()->renderText(child->getId(), child->getPosition() + Point(2, 0), Fw::red); g_painter.setOpacity(oldOpacity); } diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index 06ffd3d9..163a801c 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -189,7 +189,7 @@ protected: // function shortcuts public: - void resize(int width, int height) { setRect(Rect(getPos(), Size(width, height))); } + void resize(int width, int height) { setRect(Rect(getPosition(), Size(width, height))); } void move(int x, int y) { setRect(Rect(x, y, getSize())); } void hide() { setVisible(false); } void show() { setVisible(true); } @@ -262,7 +262,7 @@ public: void setWidth(int width) { resize(width, getHeight()); } void setHeight(int height) { resize(getWidth(), height); } void setSize(const Size& size) { resize(size.width(), size.height()); } - void setPos(const Point& pos) { move(pos.x, pos.y); } + void setPosition(const Point& pos) { move(pos.x, pos.y); } void setColor(const Color& color) { m_color = color; } void setBackgroundColor(const Color& color) { m_backgroundColor = color; } void setBackgroundOffsetX(int x) { m_backgroundRect.setX(x); } @@ -309,7 +309,7 @@ public: int getX() { return m_rect.x(); } int getY() { return m_rect.y(); } - Point getPos() { return m_rect.topLeft(); } + Point getPosition() { return m_rect.topLeft(); } int getWidth() { return m_rect.width(); } int getHeight() { return m_rect.height(); } Size getSize() { return m_rect.size(); } diff --git a/src/framework/ui/uiwidgetbasestyle.cpp b/src/framework/ui/uiwidgetbasestyle.cpp index 11bf5aba..65a00841 100644 --- a/src/framework/ui/uiwidgetbasestyle.cpp +++ b/src/framework/ui/uiwidgetbasestyle.cpp @@ -55,7 +55,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode) else if(node->tag() == "y") setY(node->value()); else if(node->tag() == "pos") - setPos(node->value()); + setPosition(node->value()); else if(node->tag() == "width") setWidth(node->value()); else if(node->tag() == "height") diff --git a/src/otclient/CMakeLists.txt b/src/otclient/CMakeLists.txt index eb653cc3..2c3ed0b5 100644 --- a/src/otclient/CMakeLists.txt +++ b/src/otclient/CMakeLists.txt @@ -27,6 +27,7 @@ SET(otclient_SOURCES ${otclient_SOURCES} # otclient core ${CMAKE_CURRENT_LIST_DIR}/core/game.cpp ${CMAKE_CURRENT_LIST_DIR}/core/map.cpp + ${CMAKE_CURRENT_LIST_DIR}/core/mapview.cpp ${CMAKE_CURRENT_LIST_DIR}/core/thingstype.cpp ${CMAKE_CURRENT_LIST_DIR}/core/spritemanager.cpp ${CMAKE_CURRENT_LIST_DIR}/core/item.cpp diff --git a/src/otclient/const.h b/src/otclient/const.h index 632355ae..69a7b049 100644 --- a/src/otclient/const.h +++ b/src/otclient/const.h @@ -31,6 +31,36 @@ namespace Otc static const char* AppCompactName = "otclient"; static const char* AppVersion = "0.4.0"; + enum { + TILE_PIXELS = 32, + SEA_LEVEL = 7, + MAX_Z = 15, + VISIBLE_X_TILES = 15, + VISIBLE_Y_TILES = 11, + MAX_ELEVATION = 24, + EFFECT_TICKS_PER_FRAME = 75, + ITEM_TICKS_PER_FRAME = 500, + ANIMATED_TEXT_DURATION = 1000, + STATIC_DURATION_PER_CHARACTER = 75, + MIN_STATIC_TEXT_DURATION = 3000, + MAX_STATIC_TEXT_WIDTH = 200, + }; + + enum MapDrawFlags { + MapDrawNonMoveableItems = 1, + MapDrawMoveableItems = 2, + MapDrawCreatures = 4, + MapDrawCreaturesInformation = 8, + MapDrawStaticTexts = 16, + MapDrawAnimatedTexts = 32, + MapDrawEffects = 64, + MapDrawMissiles = 128, + MapDrawEverything = MapDrawNonMoveableItems | MapDrawMoveableItems | + MapDrawCreatures | MapDrawCreaturesInformation | + MapDrawStaticTexts | MapDrawAnimatedTexts | + MapDrawEffects | MapDrawMissiles + }; + enum DatOpts { DatGround = 0, DatGroundClip, diff --git a/src/otclient/core/animatedtext.cpp b/src/otclient/core/animatedtext.cpp index 0eac7c0f..e9b35709 100644 --- a/src/otclient/core/animatedtext.cpp +++ b/src/otclient/core/animatedtext.cpp @@ -31,25 +31,26 @@ AnimatedText::AnimatedText() m_font = g_fonts.getFont("verdana-11px-rounded"); } -void AnimatedText::start() +void AnimatedText::draw(const Point& dest, const Rect& visibleRect) { - m_startTime = g_clock.time(); + Point p = dest; + p.x += 20 - m_textSize.width() / 2; + p.y += (-20 * m_animationTimer.ticksElapsed()) / Otc::ANIMATED_TEXT_DURATION; + Rect rect(p, m_textSize); - auto self = asAnimatedText(); - - // schedule removal - g_dispatcher.scheduleEvent([self]() { - g_map.removeThing(self); - }, DURATION); + if(visibleRect.contains(rect)) { + //TODO: cache into a framebuffer + m_font->renderText(m_text, rect, Fw::AlignLeft, m_color); + } } -void AnimatedText::draw(const Point& p, const Rect& visibleRect) +void AnimatedText::startAnimation() { - if(m_font) { - Rect rect = Rect(p + Point(20 - m_textSize.width() / 2, -20.0 * g_clock.timeElapsed(m_startTime) / (DURATION / 1000)), m_textSize); - if(visibleRect.contains(rect)) - m_font->renderText(m_text, rect, Fw::AlignLeft, m_color); - } + m_animationTimer.restart(); + + // schedule removal + auto self = asAnimatedText(); + g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, Otc::ANIMATED_TEXT_DURATION); } void AnimatedText::setColor(int color) @@ -59,7 +60,6 @@ void AnimatedText::setColor(int color) void AnimatedText::setText(const std::string& text) { - if(m_font) - m_textSize = m_font->calculateTextRectSize(text); + m_textSize = m_font->calculateTextRectSize(text); m_text = text; } diff --git a/src/otclient/core/animatedtext.h b/src/otclient/core/animatedtext.h index 8e019d74..cb32d3a8 100644 --- a/src/otclient/core/animatedtext.h +++ b/src/otclient/core/animatedtext.h @@ -25,18 +25,15 @@ #include "thing.h" #include +#include class AnimatedText : public Thing { public: - enum { - DURATION = 1000 - }; - AnimatedText(); - void start(); - void draw(const Point& p, const Rect& visibleRect); + void draw(const Point& dest, const Rect& visibleRect); + void startAnimation(); void setColor(int color); void setText(const std::string& text); @@ -48,7 +45,7 @@ private: Size m_textSize; std::string m_text; Color m_color; - double m_startTime; + Timer m_animationTimer; }; #endif diff --git a/src/otclient/core/creature.cpp b/src/otclient/core/creature.cpp index 93d2edda..98e0dad3 100644 --- a/src/otclient/core/creature.cpp +++ b/src/otclient/core/creature.cpp @@ -63,16 +63,19 @@ int LEGS_COLOR_UNIFORM = 12; int FEET_COLOR_UNIFORM = 13; int MASK_TEXTURE_UNIFORM = 14; -void Creature::draw(const Point& p, const Rect&) +void Creature::draw(const Point& dest, float scaleFactor) { + int scaledTileSize = Otc::TILE_PIXELS * scaleFactor; + Point scaledWalkOffset = m_walkOffset * scaleFactor; + if(m_showVolatileSquare) { g_painter.setColor(m_volatileSquareColor); - g_painter.drawBoundingRect(Rect(p + m_walkOffset - Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]) + 3, Size(28, 28)), 2); + g_painter.drawBoundingRect(Rect(dest + scaledWalkOffset - (getDisplacement() + 3)*scaleFactor, Size(28*scaleFactor, 28*scaleFactor)), 2*scaleFactor); } if(m_showStaticSquare) { g_painter.setColor(m_staticSquareColor); - g_painter.drawBoundingRect(Rect(p + m_walkOffset - Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]) + 1, Size(32, 32)), 2); + g_painter.drawBoundingRect(Rect(dest + scaledWalkOffset - (getDisplacement() + 1)*scaleFactor, Size(scaledTileSize, scaledTileSize)), 2*scaleFactor); } g_painter.setColor(Fw::white); @@ -90,7 +93,7 @@ void Creature::draw(const Point& p, const Rect&) // Render creature if(m_outfit.getCategory() == ThingsType::Creature) { - for(m_yPattern = 0; m_yPattern < m_type->dimensions[ThingType::PatternY]; m_yPattern++) { + for(m_yPattern = 0; m_yPattern < getNumPatternsY(); m_yPattern++) { // continue if we dont have this addon. if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1)))) @@ -104,24 +107,24 @@ void Creature::draw(const Point& p, const Rect&) outfitProgram->setUniformValue(LEGS_COLOR_UNIFORM, m_outfit.getLegsColor()); outfitProgram->setUniformValue(FEET_COLOR_UNIFORM, m_outfit.getFeetColor()); - for(int h = 0; h < m_type->dimensions[ThingType::Height]; h++) { - for(int w = 0; w < m_type->dimensions[ThingType::Width]; w++) { - int spriteId = m_type->getSpriteId(w, h, 0, m_xPattern, m_yPattern, m_zPattern, m_animation); + for(int h = 0; h < getDimensionHeight(); h++) { + for(int w = 0; w < getDimensionWidth(); w++) { + int spriteId = getSpriteId(w, h, 0, m_xPattern, m_yPattern, m_zPattern, m_animation); if(!spriteId) continue; TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId); if(!spriteTex) continue; - if(m_type->dimensions[ThingType::Layers] > 1) { - int maskId = m_type->getSpriteId(w, h, 1, m_xPattern, m_yPattern, m_zPattern, m_animation); + if(getLayers() > 1) { + int maskId = getSpriteId(w, h, 1, m_xPattern, m_yPattern, m_zPattern, m_animation); TexturePtr maskTex = g_sprites.getSpriteTexture(maskId); outfitProgram->setUniformTexture(MASK_TEXTURE_UNIFORM, maskTex, 1); } - Rect drawRect(((p + m_walkOffset).x - w*32) - m_type->parameters[ThingType::DisplacementX], - ((p + m_walkOffset).y - h*32) - m_type->parameters[ThingType::DisplacementY], - 32, 32); + Rect drawRect((dest.x + scaledWalkOffset.x - w*scaledTileSize) - getDisplacementX()*scaleFactor, + (dest.y + scaledWalkOffset.y - h*scaledTileSize) - getDisplacementY()*scaleFactor, + scaledTileSize, scaledTileSize); g_painter.drawTexturedRect(drawRect, spriteTex); } } @@ -130,14 +133,14 @@ void Creature::draw(const Point& p, const Rect&) } } else if(m_outfit.getCategory() == ThingsType::Item) { - for(int l = 0; l < m_type->dimensions[ThingType::Layers]; l++) - internalDraw(p + m_walkOffset, l); + for(int l = 0; l < getLayers(); l++) + internalDraw(dest + scaledWalkOffset, scaleFactor, l); } else if(m_outfit.getCategory() == ThingsType::Effect) - internalDraw(p + m_walkOffset, 0); + internalDraw(dest + scaledWalkOffset, scaleFactor, 0); } -void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRect) +void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect) { Color fillColor = Color(96, 96, 96); @@ -145,16 +148,16 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe fillColor = m_informationColor; // calculate main rects - Rect backgroundRect = Rect(x-(13.5), y, 27, 4); - backgroundRect.bind(visibleRect); + Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4); + backgroundRect.bind(parentRect); - Rect textRect = Rect(x - m_nameSize.width() / 2.0, y-12, m_nameSize); - textRect.bind(visibleRect); + Rect textRect = Rect(point.x - m_nameSize.width() / 2.0, point.y-12, m_nameSize); + textRect.bind(parentRect); // distance them - if(textRect.top() == visibleRect.top()) + if(textRect.top() == parentRect.top()) backgroundRect.moveTop(textRect.top() + 12); - if(backgroundRect.bottom() == visibleRect.bottom()) + if(backgroundRect.bottom() == parentRect.bottom()) textRect.moveTop(backgroundRect.top() - 12); // health rect is based on background rect, so no worries @@ -173,15 +176,15 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe if(m_skull != Otc::SkullNone && m_skullTexture) { g_painter.setColor(Fw::white); - g_painter.drawTexturedRect(Rect(x + 12, y + 5, m_skullTexture->getSize()), m_skullTexture); + g_painter.drawTexturedRect(Rect(point.x + 12, point.y + 5, m_skullTexture->getSize()), m_skullTexture); } if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) { g_painter.setColor(Fw::white); - g_painter.drawTexturedRect(Rect(x, y + 5, m_shieldTexture->getSize()), m_shieldTexture); + g_painter.drawTexturedRect(Rect(point.x, point.y + 5, m_shieldTexture->getSize()), m_shieldTexture); } if(m_emblem != Otc::EmblemNone && m_emblemTexture) { g_painter.setColor(Fw::white); - g_painter.drawTexturedRect(Rect(x + 12, y + 16, m_emblemTexture->getSize()), m_emblemTexture); + g_painter.drawTexturedRect(Rect(point.x + 12, point.y + 16, m_emblemTexture->getSize()), m_emblemTexture); } } @@ -209,7 +212,12 @@ void Creature::walk(const Position& oldPos, const Position& newPos) // calculates walk interval float interval = 1000; - int groundSpeed = g_map.getTile(oldPos)->getGroundSpeed(); + int groundSpeed = 0; + + TilePtr oldTile = g_map.getTile(oldPos); + if(oldTile) + groundSpeed = oldTile->getGroundSpeed(); + if(groundSpeed != 0) interval = (1000.0f * groundSpeed) / m_speed; @@ -248,10 +256,10 @@ void Creature::updateWalkAnimation(int totalPixelsWalked) if(m_outfit.getCategory() != ThingsType::Creature) return; - if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || m_type->dimensions[ThingType::AnimationPhases] <= 1) + if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || getAnimationPhases() <= 1) m_animation = 0; - else if(m_type->dimensions[ThingType::AnimationPhases] > 1) - m_animation = 1 + ((totalPixelsWalked * 4) / Map::NUM_TILE_PIXELS) % (m_type->dimensions[ThingType::AnimationPhases] - 1); + else if(getAnimationPhases() > 1) + m_animation = 1 + ((totalPixelsWalked * 4) / Otc::TILE_PIXELS) % (getAnimationPhases() - 1); } void Creature::updateWalkOffset(int totalPixelsWalked) @@ -375,7 +383,7 @@ void Creature::setDirection(Otc::Direction direction) void Creature::setOutfit(const Outfit& outfit) { m_outfit = outfit; - m_type = getType(); + updateType(); m_animation = 0; if(m_outfit.getCategory() == ThingsType::Effect) { @@ -389,7 +397,7 @@ void Creature::setOutfit(const Outfit& outfit) m_yPattern = 0; } - if(m_outfit.getCategory() == ThingsType::Creature && m_type->dimensions[ThingType::Layers] == 1) { + if(m_outfit.getCategory() == ThingsType::Creature && getLayers() == 1) { m_outfit.resetClothes(); } } @@ -483,8 +491,5 @@ void Creature::updateShield() m_showShieldTexture = true; } -ThingType *Creature::getType() -{ - return g_thingsType.getThingType(m_outfit.getId(), m_outfit.getCategory()); -} + diff --git a/src/otclient/core/creature.h b/src/otclient/core/creature.h index 3b63bcf7..250d53c6 100644 --- a/src/otclient/core/creature.h +++ b/src/otclient/core/creature.h @@ -41,8 +41,8 @@ public: Creature(); virtual ~Creature() { } - virtual void draw(const Point& p, const Rect&); - void drawInformation(int x, int y, bool useGray, const Rect& visibleRect); + virtual void draw(const Point& dest, float scaleFactor); + void drawInformation(const Point& point, bool useGray, const Rect& parentRect); void setName(const std::string& name); void setHealthPercent(uint8 healthPercent); diff --git a/src/otclient/core/declarations.h b/src/otclient/core/declarations.h index b2375c70..a3e29eeb 100644 --- a/src/otclient/core/declarations.h +++ b/src/otclient/core/declarations.h @@ -25,6 +25,8 @@ #include +class Map; +class MapView; class Tile; class Thing; class Item; @@ -38,6 +40,7 @@ class Missile; class AnimatedText; class StaticText; +typedef std::shared_ptr MapViewPtr; typedef std::shared_ptr TilePtr; typedef std::shared_ptr ThingPtr; typedef std::shared_ptr ItemPtr; diff --git a/src/otclient/core/effect.cpp b/src/otclient/core/effect.cpp index 3f6eff8e..77ac24bc 100644 --- a/src/otclient/core/effect.cpp +++ b/src/otclient/core/effect.cpp @@ -27,51 +27,35 @@ #include #include -Effect::Effect() : Thing() +void Effect::draw(const Point& dest, float scaleFactor) { - m_animationStartTicks = 0; + internalDraw(dest, scaleFactor, 0); } -void Effect::start() +void Effect::startAnimation() { - m_animationStartTicks = g_clock.ticks(); + m_animationTimer.restart(); auto self = asEffect(); - // schedule update - if(getAnimationPhases() > 1) { - g_dispatcher.scheduleEvent([self]() { - self->updateAnimation(); - }, TICKS_PER_FRAME); - } + // schedule next animation update + if(getAnimationPhases() > 1) + g_dispatcher.scheduleEvent([self]() { self->updateAnimation(); }, Otc::EFFECT_TICKS_PER_FRAME); // schedule removal - g_dispatcher.scheduleEvent([self]() { - g_map.removeThing(self); - }, TICKS_PER_FRAME * getAnimationPhases()); -} - -void Effect::draw(const Point& p, const Rect&) -{ - internalDraw(p, 0); + g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, Otc::EFFECT_TICKS_PER_FRAME * getAnimationPhases()); } void Effect::updateAnimation() { - int animationPhase = (g_clock.ticks() - m_animationStartTicks) / TICKS_PER_FRAME; + int animationPhase = m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME; if(animationPhase < getAnimationPhases()) m_animation = animationPhase; if(animationPhase < getAnimationPhases() - 1) { + //schedule next animation update auto self = asEffect(); - g_dispatcher.scheduleEvent([self]() { - self->updateAnimation(); - }, TICKS_PER_FRAME); + g_dispatcher.scheduleEvent([self]() { self->updateAnimation(); }, Otc::EFFECT_TICKS_PER_FRAME); } } - -ThingType *Effect::getType() -{ - return g_thingsType.getThingType(m_id, ThingsType::Effect); -} diff --git a/src/otclient/core/effect.h b/src/otclient/core/effect.h index d305f55d..ae2d663e 100644 --- a/src/otclient/core/effect.h +++ b/src/otclient/core/effect.h @@ -24,28 +24,21 @@ #define EFFECT_H #include +#include #include "thing.h" class Effect : public Thing { public: - enum { - TICKS_PER_FRAME = 75 - }; + void draw(const Point& dest, float scaleFactor); - Effect(); - - void draw(const Point& p, const Rect&); - - void start(); + void startAnimation(); void updateAnimation(); - ThingType *getType(); - EffectPtr asEffect() { return std::static_pointer_cast(shared_from_this()); } private: - ticks_t m_animationStartTicks; + Timer m_animationTimer; }; #endif diff --git a/src/otclient/core/game.cpp b/src/otclient/core/game.cpp index cd08b1b7..06226ec0 100644 --- a/src/otclient/core/game.cpp +++ b/src/otclient/core/game.cpp @@ -186,7 +186,7 @@ void Game::processCreatureSpeak(const std::string& name, int level, const std::s void Game::processContainerAddItem(int containerId, const ItemPtr& item) { if(item) - item->setPos(Position(65535, containerId + 0x40, 0)); + item->setPosition(Position(65535, containerId + 0x40, 0)); g_lua.callGlobalField("Game", "onContainerAddItem", containerId, item); } @@ -194,7 +194,7 @@ void Game::processContainerAddItem(int containerId, const ItemPtr& item) void Game::processInventoryChange(int slot, const ItemPtr& item) { if(item) - item->setPos(Position(65535, slot, 0)); + item->setPosition(Position(65535, slot, 0)); g_lua.callGlobalField("Game","onInventoryChange", slot, item); } @@ -246,7 +246,7 @@ void Game::walk(Otc::Direction direction) }*/ // only do prewalk to walkable tiles - TilePtr toTile = g_map.getTile(m_localPlayer->getPos() + Position::getPosFromDirection(direction)); + TilePtr toTile = g_map.getTile(m_localPlayer->getPosition() + Position::getPositionFromDirection(direction)); if(toTile && toTile->isWalkable()) m_localPlayer->preWalk(direction); else @@ -316,7 +316,7 @@ void Game::look(const ThingPtr& thing) int stackpos = getThingStackpos(thing); if(stackpos != -1) - m_protocolGame->sendLookAt(thing->getPos(), thing->getId(), stackpos); + m_protocolGame->sendLookAt(thing->getPosition(), thing->getId(), stackpos); } void Game::open(const ThingPtr& thing, int containerId) @@ -326,7 +326,7 @@ void Game::open(const ThingPtr& thing, int containerId) int stackpos = getThingStackpos(thing); if(stackpos != -1) - m_protocolGame->sendUseItem(thing->getPos(), thing->getId(), stackpos, containerId); + m_protocolGame->sendUseItem(thing->getPosition(), thing->getId(), stackpos, containerId); } void Game::use(const ThingPtr& thing) @@ -338,7 +338,7 @@ void Game::use(const ThingPtr& thing) int stackpos = getThingStackpos(thing); if(stackpos != -1) - m_protocolGame->sendUseItem(thing->getPos(), thing->getId(), stackpos, 0); + m_protocolGame->sendUseItem(thing->getPosition(), thing->getId(), stackpos, 0); } void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing) @@ -346,7 +346,7 @@ void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing) if(!isOnline() || !fromThing || !toThing || !checkBotProtection()) return; - Position pos = fromThing->getPos(); + Position pos = fromThing->getPosition(); int fromStackpos = getThingStackpos(fromThing); if(fromStackpos == -1) return; @@ -360,7 +360,7 @@ void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing) if(toStackpos == -1) return; - m_protocolGame->sendUseItemEx(pos, fromThing->getId(), fromStackpos, toThing->getPos(), toThing->getId(), toStackpos); + m_protocolGame->sendUseItemEx(pos, fromThing->getId(), fromStackpos, toThing->getPosition(), toThing->getId(), toStackpos); } } @@ -379,13 +379,13 @@ void Game::useInventoryItem(int itemId, const ThingPtr& toThing) if(CreaturePtr creature = toThing->asCreature()) { m_protocolGame->sendUseOnCreature(pos, itemId, 0, creature->getId()); } else { - m_protocolGame->sendUseItemEx(pos, itemId, 0, toThing->getPos(), toThing->getId(), toStackpos); + m_protocolGame->sendUseItemEx(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toStackpos); } } void Game::move(const ThingPtr& thing, const Position& toPos, int count) { - if(!isOnline() || !thing || !checkBotProtection() || thing->getPos() == toPos || count <= 0) + if(!isOnline() || !thing || !checkBotProtection() || thing->getPosition() == toPos || count <= 0) return; m_localPlayer->lockWalk(); @@ -394,7 +394,7 @@ void Game::move(const ThingPtr& thing, const Position& toPos, int count) if(stackpos == -1) return; - m_protocolGame->sendThrow(thing->getPos(), thing->getId(), stackpos, toPos, count); + m_protocolGame->sendThrow(thing->getPosition(), thing->getId(), stackpos, toPos, count); } void Game::attack(const CreaturePtr& creature) @@ -433,6 +433,9 @@ void Game::follow(const CreaturePtr& creature) void Game::cancelFollow() { + if(!isOnline() || !checkBotProtection()) + return; + m_localPlayer->setFollowingCreature(nullptr); m_protocolGame->sendFollow(0); } @@ -444,16 +447,15 @@ void Game::rotate(const ThingPtr& thing) int stackpos = getThingStackpos(thing); if(stackpos != -1) - m_protocolGame->sendRotateItem(thing->getPos(), thing->getId(), stackpos); + m_protocolGame->sendRotateItem(thing->getPosition(), thing->getId(), stackpos); } //TODO: move this to Thing class int Game::getThingStackpos(const ThingPtr& thing) { // thing is at map - if(thing->getPos().x != 65535) { - TilePtr tile = g_map.getTile(thing->getPos()); - if(tile) + if(thing->getPosition().x != 65535) { + if(TilePtr tile = g_map.getTile(thing->getPosition())) return tile->getThingStackpos(thing); else { logError("could not get tile"); diff --git a/src/otclient/core/item.cpp b/src/otclient/core/item.cpp index a2ca17a8..e45f1870 100644 --- a/src/otclient/core/item.cpp +++ b/src/otclient/core/item.cpp @@ -26,6 +26,9 @@ #include "thing.h" #include #include +#include +#include +#include Item::Item() : Thing() { @@ -39,29 +42,40 @@ ItemPtr Item::create(int id) return item; } -void Item::draw(const Point& p, const Rect&) +PainterShaderProgramPtr itemProgram; + +void Item::draw(const Point& dest, float scaleFactor) { - if(m_type->dimensions[ThingType::AnimationPhases] > 1) - m_animation = (g_clock.ticks() % (TICKS_PER_FRAME * m_type->dimensions[ThingType::AnimationPhases])) / TICKS_PER_FRAME; + if(getAnimationPhases() > 1) + m_animation = (g_clock.ticks() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME; + + if(!itemProgram) { + itemProgram = PainterShaderProgramPtr(new PainterShaderProgram); + itemProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); + itemProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/item.frag"); + assert(itemProgram->link()); + } + g_painter.setCustomProgram(itemProgram); - for(int l = 0; l < m_type->dimensions[ThingType::Layers]; l++) - internalDraw(p, l); + for(int layer = 0; layer < getLayers(); layer++) + internalDraw(dest, scaleFactor, layer); + g_painter.releaseCustomProgram(); } -void Item::setPos(const Position& position) +void Item::setPosition(const Position& position) { - if(m_type->properties[ThingType::IsGround]) { - m_xPattern = position.x % m_type->dimensions[ThingType::PatternX]; - m_yPattern = position.y % m_type->dimensions[ThingType::PatternY]; - m_zPattern = position.z % m_type->dimensions[ThingType::PatternZ]; + if(isGround()) { + m_xPattern = position.x % getNumPatternsX(); + m_yPattern = position.y % getNumPatternsY(); + m_zPattern = position.z % getNumPatternsZ(); } - Thing::setPos(position); + Thing::setPosition(position); } void Item::setData(int data) { - if(m_type->properties[ThingType::IsStackable] && m_type->dimensions[ThingType::PatternX] == 4 && m_type->dimensions[ThingType::PatternY] == 2) { + if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) { if(data < 5) { m_xPattern = data-1; m_yPattern = 0; @@ -83,15 +97,15 @@ void Item::setData(int data) m_yPattern = 1; } } - else if(m_type->properties[ThingType::IsHangable]) { - if(m_type->properties[ThingType::HookSouth]) { - m_xPattern = m_type->dimensions[ThingType::PatternX] >= 2 ? 1 : 0; + else if(isHangable()) { + if(isHookSouth()) { + m_xPattern = getNumPatternsX() >= 2 ? 1 : 0; } - else if(m_type->properties[ThingType::HookEast]) { - m_xPattern = m_type->dimensions[ThingType::PatternX] >= 3 ? 2 : 0; + else if(isHookEast()) { + m_xPattern = getNumPatternsX() >= 3 ? 2 : 0; } } - else if(m_type->properties[ThingType::IsFluid] || m_type->properties[ThingType::IsFluidContainer]) { + else if(isFluid() || isFluidContainer()) { int color = Otc::FluidTransparent; switch(data) { case Otc::FluidNone: @@ -153,14 +167,9 @@ void Item::setData(int data) break; } - m_xPattern = (color % 4) % m_type->dimensions[ThingType::PatternX]; - m_yPattern = (color / 4) % m_type->dimensions[ThingType::PatternY]; + m_xPattern = (color % 4) % getNumPatternsX(); + m_yPattern = (color / 4) % getNumPatternsY(); } m_data = data; } - -ThingType *Item::getType() -{ - return g_thingsType.getThingType(m_id, ThingsType::Item); -} diff --git a/src/otclient/core/item.h b/src/otclient/core/item.h index 70a2c288..7635e2f0 100644 --- a/src/otclient/core/item.h +++ b/src/otclient/core/item.h @@ -33,17 +33,12 @@ public: static ItemPtr create(int id); - enum { - TICKS_PER_FRAME = 500 - }; + void draw(const Point& dest, float scaleFactor); - void draw(const Point& p, const Rect&); - - void setPos(const Position &position); + void setPosition(const Position &position); void setData(int data); int getData() { return m_data; } - ThingType *getType(); ItemPtr asItem() { return std::static_pointer_cast(shared_from_this()); } diff --git a/src/otclient/core/localplayer.cpp b/src/otclient/core/localplayer.cpp index 38835ee9..9f6336a3 100644 --- a/src/otclient/core/localplayer.cpp +++ b/src/otclient/core/localplayer.cpp @@ -70,11 +70,11 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos) void LocalPlayer::preWalk(Otc::Direction direction) { // start walking to direction - Position newPos = m_pos + Position::getPosFromDirection(direction); + Position newPos = m_position + Position::getPositionFromDirection(direction); m_preWalking = true; m_lastPrewalkDone = false; m_lastPrewalkDestionation = newPos; - Creature::walk(m_pos, newPos); + Creature::walk(m_position, newPos); } bool LocalPlayer::canWalk(Otc::Direction direction) diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index b269faea..f22dc294 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -28,254 +28,69 @@ #include "missile.h" #include "statictext.h" -#include -#include -#include -#include -#include +#include +#include "mapview.h" Map g_map; -Map::Map() +void Map::addMapView(const MapViewPtr& mapView) { - setVisibleSize(Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT)); + m_mapViews.push_back(mapView); } -void Map::draw(const Rect& rect) +void Map::removeMapView(const MapViewPtr& mapView) { - if(!m_framebuffer) { - Size fboSize(m_visibleSize.width() * NUM_TILE_PIXELS, m_visibleSize.height() * NUM_TILE_PIXELS); - m_framebuffer = FrameBufferPtr(new FrameBuffer(fboSize)); - m_framebuffer->setClearColor(Fw::black); - - - m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram); - m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); - m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag"); - assert(m_shaderProgram->link()); - } - - g_painter.setColor(Fw::white); - m_framebuffer->bind(); - - // draw offsets - LocalPlayerPtr localPlayer = g_game.getLocalPlayer(); - if(localPlayer) - m_drawOffset = localPlayer->getWalkOffset(); - - //TODO: cache first/last visible floor - // draw from bottom floors to top floors - int firstFloor = getFirstVisibleFloor(); - const int lastFloor = MAX_Z-1; - for(int iz = lastFloor; iz >= firstFloor; --iz) { - // draw tiles like linus pauling's rule order - const int numDiagonals = m_size.width() + m_size.height() - 1; - for(int diagonal = 0; diagonal < numDiagonals; ++diagonal) { - // loop through / diagonal tiles - for(int ix = std::min(diagonal, m_size.width() - 1), iy = std::max(diagonal - m_size.width(), 0); ix >= 0 && iy < m_size.height(); --ix, ++iy) { - // position on current floor - Position tilePos(m_centralPosition.x + (ix - m_centralOffset.x), m_centralPosition.y + (iy - m_centralOffset.y), m_centralPosition.z); - // adjust tilePos to the wanted floor - tilePos.perspectiveUp(m_centralPosition.z - iz); - //TODO: cache visible tiles, m_tiles[] has a high cost (50% fps decrease) - if(const TilePtr& tile = m_tiles[tilePos]) { - // skip tiles that are behind another tile - //if(isCompletlyCovered(tilePos, firstFloor)) - // continue; - tile->draw(positionTo2D(tilePos) - m_drawOffset, rect); - } - } - } - - // after drawing all tiles, draw shots - for(const MissilePtr& shot : m_missilesAtFloor[iz]) { - Position missilePos = shot->getPos(); - shot->draw(positionTo2D(missilePos) - m_drawOffset, rect); - } - } - - m_framebuffer->release(); - - - g_painter.setCustomProgram(m_shaderProgram); - g_painter.setColor(Fw::white); - m_framebuffer->draw(rect); - g_painter.releaseCustomProgram(); - - // calculate stretch factor - float horizontalStretchFactor = rect.width() / (float)(m_visibleSize.width() * NUM_TILE_PIXELS); - float verticalStretchFactor = rect.height() / (float)(m_visibleSize.height() * NUM_TILE_PIXELS); - - // draw player names and health bars - //TODO: this must be cached with creature walks - for(int x = 0; x < m_visibleSize.width(); ++x) { - for(int y = 0; y < m_visibleSize.height(); ++y) { - Position tilePos = Position(m_centralPosition.x + (x - m_centralOffset.x + 1), m_centralPosition.y + (y - m_centralOffset.y + 1), m_centralPosition.z); - if(const TilePtr& tile = m_tiles[tilePos]) { - auto creatures = tile->getCreatures(); - - if(creatures.size() == 0) - continue; - - for(const CreaturePtr& creature : creatures) { - Point p((m_centralOffset.x - 1 + (tilePos.x - m_centralPosition.x))*NUM_TILE_PIXELS + 10 - tile->getDrawElevation(), - (m_centralOffset.y - 1 + (tilePos.y - m_centralPosition.y))*NUM_TILE_PIXELS - 10 - tile->getDrawElevation()); - - if(creature != localPlayer) { - p += creature->getWalkOffset() - m_drawOffset; - } - - creature->drawInformation(rect.x() + p.x*horizontalStretchFactor, rect.y() + p.y*verticalStretchFactor, isCovered(tilePos, firstFloor), rect); - } - } - } - } - - // draw static text - for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) { - Point pos = positionTo2D((*it)->getPos()) - m_drawOffset; - pos.x *= horizontalStretchFactor; - pos.y *= verticalStretchFactor; - (*it)->draw(rect.topLeft() + pos, rect); - } + auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView); + if(it != m_mapViews.end()) + m_mapViews.erase(it); +} - // draw animated text - for(auto it = m_animatedTexts.begin(), end = m_animatedTexts.end(); it != end; ++it) { - Point pos = positionTo2D((*it)->getPos()) - m_drawOffset; - pos.x *= horizontalStretchFactor; - pos.y *= verticalStretchFactor; - (*it)->draw(rect.topLeft() + pos, rect); - } +void Map::notificateTileUpdateToMapViews(const Position& pos) +{ + for(const MapViewPtr& mapView : m_mapViews) + mapView->onTileUpdate(pos); } void Map::clean() { m_tiles.clear(); - m_creatures.clear(); - for(int i=0;i= firstFloor) { - if(TilePtr tile = m_tiles[upperPos]) { - if(ThingPtr firstThing = tile->getThing(0)) { - ThingType *type = firstThing->getType(); - if((type->properties[ThingType::IsGround] || type->properties[ThingType::IsOnBottom]) && !type->properties[ThingType::DontHide]) { - firstFloor = upperPos.z + 1; - break; - } - } - } - if(TilePtr tile = m_tiles[perspectivePos]) { - if(ThingPtr firstThing = tile->getThing(0)) { - ThingType *type = firstThing->getType(); - if((type->properties[ThingType::IsGround] || type->properties[ThingType::IsOnBottom]) && !type->properties[ThingType::DontHide]) { - firstFloor = perspectivePos.z + 1; - break; - } - } - } - perspectivePos.perspectiveUp(); - upperPos.up(); - } - } - } - } - return firstFloor; -} - -bool Map::isLookPossible(const Position& pos) -{ - TilePtr tile = m_tiles[pos]; - if(tile) - return tile->isLookPossible(); - return true; -} - -bool Map::isCovered(const Position& pos, int firstFloor) -{ - Position tilePos = pos; - tilePos.perspectiveUp(); - while(tilePos.z >= firstFloor) { - TilePtr tile = m_tiles[tilePos]; - if(tile && tile->isFullGround()) - return true; - tilePos.perspectiveUp(); - } - return false; -} - -bool Map::isCompletlyCovered(const Position& pos, int firstFloor) -{ - Position tilePos = pos; - tilePos.perspectiveUp(); - while(tilePos.z >= firstFloor) { - bool covered = true; - for(int x=0;x<2;++x) { - for(int y=0;y<2;++y) { - TilePtr tile = m_tiles[tilePos + Position(-x, -y, 0)]; - if(!tile || !tile->isFullyOpaque()) { - covered = false; - break; - } - } - } - if(covered) - return true; - tilePos.perspectiveUp(); - } - return false; -} - void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) { if(!thing) return; - Position oldPos = thing->getPos(); - bool teleport = false; - if(oldPos.isValid() && !oldPos.isInRange(pos,1,1,0)) - teleport = true; - TilePtr tile = getTile(pos); + if(!tile) + tile = createTile(pos); if(CreaturePtr creature = thing->asCreature()) { + Position oldPos = thing->getPosition(); tile->addThing(thing, stackPos); - m_creatures[creature->getId()] = creature; - if(teleport) + // creature teleported + if(oldPos.isValid() && !oldPos.isInRange(pos,1,1,0)) g_game.processCreatureTeleport(creature); - } - else if(MissilePtr shot = thing->asMissile()) { - m_missilesAtFloor[shot->getPos().z].push_back(shot); - } - else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) { + } else if(MissilePtr missile = thing->asMissile()) { + m_floorMissiles[pos.z].push_back(missile); + } else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) { m_animatedTexts.push_back(animatedText); - } - else if(StaticTextPtr staticText = thing->asStaticText()) { + } 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->getPos() == pos) { + if(cStaticText->getPosition() == pos) { // try to combine messages if(cStaticText->addMessage(staticText->getName(), staticText->getMessageType(), staticText->getFirstMessage())) { mustAdd = false; break; - } - else { + } else { // must add another message and rearrenge current } } @@ -284,113 +99,173 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) if(mustAdd) m_staticTexts.push_back(staticText); - } - else { + } else { tile->addThing(thing, stackPos); } - thing->start(); - thing->setPos(pos); + thing->startAnimation(); + thing->setPosition(pos); + + notificateTileUpdateToMapViews(pos); } ThingPtr Map::getThing(const Position& pos, int stackPos) { - if(const TilePtr& tile = m_tiles[pos]) + if(TilePtr tile = getTile(pos)) return tile->getThing(stackPos); return nullptr; } -void Map::removeThingByPos(const Position& pos, int stackPos) -{ - if(TilePtr& tile = m_tiles[pos]) - tile->removeThingByStackpos(stackPos); -} - -void Map::removeThing(const ThingPtr& thing) +bool Map::removeThing(const ThingPtr& thing) { - if(!thing) - return; - - if(MissilePtr shot = thing->asMissile()) { - auto it = std::find(m_missilesAtFloor[shot->getPos().z].begin(), m_missilesAtFloor[shot->getPos().z].end(), shot); - if(it != m_missilesAtFloor[shot->getPos().z].end()) { - m_missilesAtFloor[shot->getPos().z].erase(it); + if(!thing) { + return false; + } else if(MissilePtr missile = thing->asMissile()) { + auto it = std::find(m_floorMissiles[missile->getPosition().z].begin(), m_floorMissiles[missile->getPosition().z].end(), missile); + if(it != m_floorMissiles[missile->getPosition().z].end()) { + m_floorMissiles[missile->getPosition().z].erase(it); + return true; } - return; - } - else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) { + } else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) { auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText); - if(it != m_animatedTexts.end()) + if(it != m_animatedTexts.end()) { m_animatedTexts.erase(it); - return; - } - else if(StaticTextPtr staticText = thing->asStaticText()) { + return true; + } + } else if(StaticTextPtr staticText = thing->asStaticText()) { auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText); - if(it != m_staticTexts.end()) + if(it != m_staticTexts.end()) { m_staticTexts.erase(it); - return; - } + return true; + } + } else if(TilePtr tile = getTile(thing->getPosition())) + return tile->removeThing(thing); - if(TilePtr& tile = m_tiles[thing->getPos()]) - tile->removeThing(thing); + notificateTileUpdateToMapViews(thing->getPosition()); + + return false; } -TilePtr Map::getTile(const Position& pos) +bool Map::removeThingByPos(const Position& pos, int stackPos) { - if(!pos.isValid()) - return nullptr; + if(TilePtr tile = getTile(pos)) + return removeThing(tile->getThing(stackPos)); + return false; +} - TilePtr& tile = m_tiles[pos]; - if(!tile) - tile = TilePtr(new Tile(pos)); +TilePtr Map::createTile(const Position& pos) +{ + TilePtr tile = TilePtr(new Tile(pos)); + m_tiles[pos] = tile; return tile; } void Map::cleanTile(const Position& pos) { - if(TilePtr& tile = m_tiles[pos]) + if(TilePtr tile = getTile(pos)) { tile->clean(); + + notificateTileUpdateToMapViews(pos); + } } void Map::addCreature(const CreaturePtr& creature) { - m_creatures[creature->getId()] = creature; + m_knownCreatures[creature->getId()] = creature; } CreaturePtr Map::getCreatureById(uint32 id) { - if(g_game.getLocalPlayer() && (uint32)g_game.getLocalPlayer()->getId() == id) - return g_game.getLocalPlayer(); - return m_creatures[id]; + LocalPlayerPtr localPlayer = g_game.getLocalPlayer(); + if(localPlayer && localPlayer->getId() == id) + return localPlayer; + return m_knownCreatures[id]; } void Map::removeCreatureById(uint32 id) { - m_creatures.erase(id); + if(id == 0) + return; + m_knownCreatures.erase(id); +} + +std::vector Map::getSpectators(const Position& centerPos, bool multiFloor) +{ + return getSpectatorsInRange(centerPos, multiFloor, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2); } -void Map::setCentralPosition(const Position& centralPosition) +std::vector Map::getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange) { - m_centralPosition = centralPosition; + return getSpectatorsInRangeEx(centerPos, multiFloor, xRange, xRange, yRange, yRange); } -void Map::setVisibleSize(const Size& visibleSize) +std::vector Map::getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange) { - m_visibleSize = visibleSize; + int minZRange = 0; + int maxZRange = 0; + std::vector creatures; - if(m_visibleSize.width() > MAX_WIDTH || m_visibleSize.height() > MAX_HEIGHT) - m_visibleSize = Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT); + if(multiFloor) { + minZRange = 0; + maxZRange = Otc::MAX_Z; + } + + for(int iz=-minZRange; iz<=maxZRange; ++iz) { + for(int iy=-minYRange; iy<=maxYRange; ++iy) { + for(int ix=-minXRange; ix<=maxXRange; ++ix) { + TilePtr tile = getTile(centerPos + Position(ix,iy,iz)); + if(!tile) + continue; + + auto tileCreatures = tile->getCreatures(); + creatures.insert(creatures.end(), tileCreatures.begin(), tileCreatures.end()); + } + } + } + + return creatures; +} - m_centralOffset = Point(std::ceil(m_visibleSize.width() / 2.0), std::ceil(m_visibleSize.height() / 2.0)); - m_size = m_visibleSize + Size(3, 3); +bool Map::isLookPossible(const Position& pos) +{ + TilePtr tile = getTile(pos); + return tile && tile->isLookPossible(); +} - if(m_framebuffer) { - m_framebuffer->resize(Size(m_visibleSize.width() * NUM_TILE_PIXELS, m_visibleSize.height() * NUM_TILE_PIXELS)); +bool Map::isCovered(const Position& pos, int firstFloor) +{ + // check for tiles on top of the postion + Position tilePos = pos; + tilePos.coveredUp(); + while(tilePos.z >= firstFloor) { + TilePtr tile = getTile(tilePos); + // the below tile is covered when the above tile has a full ground + if(tile && tile->isFullGround()) + return true; + tilePos.coveredUp(); } + return false; } -Point Map::positionTo2D(const Position& position) +bool Map::isCompletelyCovered(const Position& pos, int firstFloor) { - return Point((m_centralOffset.x - 1 + (position.x - m_centralPosition.x) - (m_centralPosition.z - position.z)) * NUM_TILE_PIXELS, - (m_centralOffset.y - 1 + (position.y - m_centralPosition.y) - (m_centralPosition.z - position.z)) * NUM_TILE_PIXELS); + Position tilePos = pos; + tilePos.coveredUp(); + while(tilePos.z >= firstFloor) { + bool covered = true; + // check in 2x2 range tiles that has no transparent pixels + for(int x=0;x<2;++x) { + for(int y=0;y<2;++y) { + TilePtr tile = m_tiles[tilePos + Position(-x, -y, 0)]; + if(!tile || !tile->isFullyOpaque()) { + covered = false; + break; + } + } + } + if(covered) + return true; + tilePos.coveredUp(); + } + return false; } diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index 1782e555..bae49bda 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -26,70 +26,59 @@ #include "creature.h" #include "animatedtext.h" #include -#include class Map { public: - enum { - MAP_VISIBLE_WIDTH = 15, - MAP_VISIBLE_HEIGHT = 11, - MAP_SIZE_Z = 8, - MAX_WIDTH = 24, - MAX_HEIGHT = 24, - MAX_Z = 16, - NUM_TILE_PIXELS = 32 - }; - - Map(); - - void draw(const Rect& rect); - void clean(); + void addMapView(const MapViewPtr& mapView); + void removeMapView(const MapViewPtr& mapView); + void notificateTileUpdateToMapViews(const Position& pos); - int getFirstVisibleFloor(); - bool isLookPossible(const Position& pos); - bool isCovered(const Position& pos, int firstFloor = 0); - bool isCompletlyCovered(const Position& pos, int firstFloor = 0); + void clean(); + // thing related void addThing(const ThingPtr& thing, const Position& pos, int stackPos = -1); ThingPtr getThing(const Position& pos, int stackPos); - void removeThingByPos(const Position& pos, int stackPos); - void removeThing(const ThingPtr& thing); - void cleanTile(const Position& pos); - TilePtr getTile(const Position& pos); + bool removeThingByPos(const Position& pos, int stackPos); - void setLight(const Light& light) { m_light = light; } - Light getLight() { return m_light; } - - void setCentralPosition(const Position& centralPosition); - Position getCentralPosition() { return m_centralPosition; } + // tile related + TilePtr createTile(const Position& pos); + const TilePtr& getTile(const Position& pos) { return m_tiles[pos]; } + void cleanTile(const Position& pos); + bool removeThing(const ThingPtr& thing); + // known creature related void addCreature(const CreaturePtr& creature); CreaturePtr getCreatureById(uint32 id); void removeCreatureById(uint32 id); + std::vector getSpectators(const Position& centerPos, bool multiFloor); + std::vector getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange); + std::vector getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange); - void setVisibleSize(const Size& visibleSize); - Size getVibibleSize() { return m_visibleSize; } - Point getCentralOffset() { return m_centralOffset; } + void setLight(const Light& light) { m_light = light; } + void setCentralPosition(const Position& centralPosition) { m_centralPosition = centralPosition; } - Point positionTo2D(const Position& position); + bool isLookPossible(const Position& pos); + bool isCovered(const Position& pos, int firstFloor = 0); + bool isCompletelyCovered(const Position& pos, int firstFloor = 0); + + Light getLight() { return m_light; } + Position getCentralPosition() { return m_centralPosition; } + + + std::vector getAnimatedTexts() { return m_animatedTexts; } + std::vector getStaticTexts() { return m_staticTexts; } private: std::unordered_map m_tiles; - std::map m_creatures; - std::array, MAX_Z> m_missilesAtFloor; + std::map m_knownCreatures; + std::array, Otc::MAX_Z+1> m_floorMissiles; std::vector m_animatedTexts; std::vector m_staticTexts; + std::vector m_mapViews; Light m_light; Position m_centralPosition; - Size m_size; - Size m_visibleSize; - Point m_centralOffset; - Point m_drawOffset; - - FrameBufferPtr m_framebuffer; - PainterShaderProgramPtr m_shaderProgram; }; extern Map g_map; diff --git a/src/otclient/core/mapview.cpp b/src/otclient/core/mapview.cpp new file mode 100644 index 00000000..f5d1035e --- /dev/null +++ b/src/otclient/core/mapview.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2010-2012 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 "mapview.h" + +#include +#include +#include +#include +#include "creature.h" +#include "map.h" +#include "tile.h" +#include "statictext.h" +#include "animatedtext.h" + +MapView::MapView() +{ + int frameBufferSize = std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_SIZE); + + m_framebuffer = FrameBufferPtr(new FrameBuffer(Size(frameBufferSize, frameBufferSize))); + m_framebuffer->setClearColor(Fw::black); + m_lockedFirstVisibleFloor = -1; + setVisibleDimension(Size(15, 11)); + + m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram); + m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); + m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag"); + assert(m_shaderProgram->link()); +} + +void MapView::draw(const Rect& rect) +{ + // update visible tiles cache when needed + bool updated = updateVisibleTilesCache(); + + float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS; + + if(updated || m_animated) { + m_framebuffer->bind(); + for(const TilePtr& tile : m_cachedVisibleTiles) { + tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor); + //TODO: restore missiles + } + m_framebuffer->generateMipmaps(); + + m_framebuffer->release(); + } + + g_painter.setCustomProgram(m_shaderProgram); + g_painter.setColor(Fw::white); + + Point drawOffset(m_tileSize, m_tileSize); + if(m_followingCreature) + drawOffset += m_followingCreature->getWalkOffset() * scaleFactor; + Rect srcRect = Rect(drawOffset, m_visibleDimension * m_tileSize); + m_framebuffer->draw(rect, srcRect); + + g_painter.releaseCustomProgram(); + + float horizontalStretchFactor = rect.width() / (float)(m_visibleDimension.width() * m_tileSize); + float verticalStretchFactor = rect.height() / (float)(m_visibleDimension.height() * m_tileSize); + Size tileStretchedSize = Size(m_tileSize * horizontalStretchFactor, m_tileSize * verticalStretchFactor); + + // avoid drawing texts on map in far zoom outs + if(tileStretchedSize.width() >= 24) { + for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) { + const TilePtr& tile = creature->getCurrentTile(); + Position pos = tile->getPosition(); + + Point p = transformPositionTo2D(pos) - drawOffset; + p += (creature->getWalkOffset()-tile->getDrawElevation() + Point(8, -8)) * scaleFactor; + p.x = p.x * horizontalStretchFactor; + p.y = p.y * verticalStretchFactor; + p += rect.topLeft(); + + creature->drawInformation(p, g_map.isCovered(pos, m_cachedFirstVisibleFloor), rect); + } + + for(const StaticTextPtr& staticText : g_map.getStaticTexts()) { + Position pos = staticText->getPosition(); + + // ony draw static texts from current camera floor, unless yells + if(pos.z != getCameraPosition().z && !staticText->isYell()) + continue; + + Point p = transformPositionTo2D(pos) - drawOffset; + p.x = p.x * horizontalStretchFactor; + p.y = p.y * verticalStretchFactor; + p += rect.topLeft(); + staticText->draw(p, rect); + } + + for(const AnimatedTextPtr& animatedText : g_map.getAnimatedTexts()) { + Position pos = animatedText->getPosition(); + + // only draw animated texts from visible floors + if(pos.z < m_cachedFirstVisibleFloor || pos.z > m_cachedLastVisibleFloor) + continue; + + Point p = transformPositionTo2D(pos) - drawOffset; + p.x = p.x * horizontalStretchFactor; + p.y = p.y * verticalStretchFactor; + p += rect.topLeft(); + animatedText->draw(p, rect); + } + } +} + +bool MapView::updateVisibleTilesCache() +{ + // update only when needed + if(!m_mustUpdateVisibleTilesCache) + return false; + + int firstFloor = getFirstVisibleFloor(); + int lastFloor = getLastVisibleFloor(); + m_cachedFirstVisibleFloor = firstFloor; + m_cachedLastVisibleFloor = lastFloor; + Position cameraPosition = getCameraPosition(); + + // clear current visible tiles cache + m_cachedVisibleTiles.clear(); + + // cache visible tiles in draw order + // draw from last floor (the lower) to first floor (the higher) + for(int iz = m_cachedLastVisibleFloor; iz >= m_cachedFirstVisibleFloor; --iz) { + // draw tiles like linus pauling's rule order + const int numDiagonals = m_drawDimension.width() + m_drawDimension.height() - 1; + for(int diagonal = 0; diagonal < numDiagonals; ++diagonal) { + // loop through / diagonal tiles + for(int ix = std::min(diagonal, m_drawDimension.width() - 1), iy = std::max(diagonal - m_drawDimension.width() + 1, 0); ix >= 0 && iy < m_drawDimension.height(); --ix, ++iy) { + // position on current floor + Position tilePos(cameraPosition.x + (ix - m_virtualCenterOffset.x), cameraPosition.y + (iy - m_virtualCenterOffset.y), cameraPosition.z); + // adjust tilePos to the wanted floor + tilePos.coveredUp(cameraPosition.z - iz); + if(TilePtr tile = g_map.getTile(tilePos)) { + // skip tiles that have nothing + if(tile->getThingCount() == 0) + continue; + // skip tiles that are completely behind another tile + if(g_map.isCompletelyCovered(tilePos, firstFloor)) + continue; + m_cachedVisibleTiles.push_back(tile); + } + } + } + } + + m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false); + + m_mustUpdateVisibleTilesCache = false; + return true; +} + +void MapView::recalculateTileSize() +{ + int possiblesTileSizes[] = {32,16,8,4,2,1}; + + int foundSize = 0; + for(int candidateTileSize : possiblesTileSizes) { + Size candidateFramebufferSize = m_drawDimension * candidateTileSize; + + // found a valid size + if(candidateFramebufferSize.width() <= m_framebuffer->getSize().width() && candidateFramebufferSize.height() <= m_framebuffer->getSize().height()) { + foundSize = candidateTileSize; + break; + } + } + + assert(foundSize > 0); + m_tileSize = foundSize; +} + +void MapView::onTileUpdate(const Position& pos) +{ + requestVisibleTilesCacheUpdate(); +} + +void MapView::lockFirstVisibleFloor(int firstVisibleFloor) +{ + m_lockedFirstVisibleFloor = firstVisibleFloor; + requestVisibleTilesCacheUpdate(); +} + +void MapView::unlockFirstVisibleFloor() +{ + m_lockedFirstVisibleFloor = -1; + requestVisibleTilesCacheUpdate(); +} + +void MapView::followCreature(const CreaturePtr& creature) +{ + m_followingCreature = creature; + m_customCameraPosition = Position(); + requestVisibleTilesCacheUpdate(); +} + +void MapView::setCameraPosition(const Position& pos) +{ + m_customCameraPosition = pos; + m_followingCreature = nullptr; + requestVisibleTilesCacheUpdate(); +} + +void MapView::setVisibleDimension(const Size& visibleDimension) +{ + if(visibleDimension.width() % 2 != 1 || visibleDimension.height() % 2 != 1) { + logTraceError("visible dimension must be odd"); + return; + } + + if(visibleDimension.width() <= 3 || visibleDimension.height() <= 3) { + logTraceError("cannot render less than 3x3 tiles"); + return; + } + + m_visibleDimension = visibleDimension; + m_drawDimension = visibleDimension + Size(3,3); + m_virtualCenterOffset = (m_drawDimension/2 - Size(1,1)).toPoint(); + recalculateTileSize(); + + dump << m_framebuffer->getSize(); + dump << visibleDimension * m_tileSize; + requestVisibleTilesCacheUpdate(); +} + +int MapView::getFirstVisibleFloor() +{ + // return forced first visible floor + if(m_lockedFirstVisibleFloor != -1) + return m_lockedFirstVisibleFloor; + + // if nothing is limiting the view, the first visible floor is 0 + int firstFloor = 0; + Position cameraPosition = getCameraPosition(); + + // limits to underground floors while under sea level + if(cameraPosition.z > Otc::SEA_LEVEL) + firstFloor = Otc::SEA_LEVEL+1; + + // loop in 3x3 tiles around the camera + for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) { + for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) { + Position pos(cameraPosition.x + ix, cameraPosition.y + iy, cameraPosition.z); + + // process tiles that we can look through, e.g. windows, doors + if((ix == 0 && iy == 0) || g_map.isLookPossible(pos)) { + Position upperPos = pos; + Position coveredPos = pos; + + coveredPos.coveredUp(); + upperPos.up(); + + while(upperPos.z >= firstFloor) { + // check tiles physically above + TilePtr tile = g_map.getTile(upperPos); + if(tile && tile->limitsFloorsView()) { + firstFloor = upperPos.z + 1; + break; + } + + // check tiles geometrically above + tile = g_map.getTile(coveredPos); + if(tile && tile->limitsFloorsView()) { + firstFloor = coveredPos.z + 1; + break; + } + + coveredPos.coveredUp(); + upperPos.up(); + } + } + } + } + + return firstFloor; +} + +int MapView::getLastVisibleFloor() +{ + Position cameraPosition = getCameraPosition(); + + // view only underground floors when below sea level + if(cameraPosition.z > Otc::SEA_LEVEL) + return Otc::MAX_Z; + else + return Otc::SEA_LEVEL; +} + +Position MapView::getCameraPosition() +{ + if(m_followingCreature) + return m_followingCreature->getPosition(); + return m_customCameraPosition; +} + +Point MapView::transformPositionTo2D(const Position& position) +{ + Position cameraPosition = getCameraPosition(); + return Point((m_virtualCenterOffset.x + (position.x - cameraPosition.x) - (cameraPosition.z - position.z)) * m_tileSize, + (m_virtualCenterOffset.y + (position.y - cameraPosition.y) - (cameraPosition.z - position.z)) * m_tileSize); +} diff --git a/src/otclient/core/mapview.h b/src/otclient/core/mapview.h new file mode 100644 index 00000000..8c493c08 --- /dev/null +++ b/src/otclient/core/mapview.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010-2012 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 MAPVIEW_H +#define MAPVIEW_H + +#include "declarations.h" +#include +#include + +class MapView : public LuaObject +{ + enum { + DEFAULT_FRAMBUFFER_SIZE = 2048 + }; + +public: + MapView(); + + void draw(const Rect& rect); + +private: + void recalculateTileSize(); + bool updateVisibleTilesCache(); + void requestVisibleTilesCacheUpdate() { m_mustUpdateVisibleTilesCache = true; } + +protected: + void onTileUpdate(const Position& pos); + + friend class Map; + +public: + void lockFirstVisibleFloor(int firstVisibleFloor); + void unlockFirstVisibleFloor(); + void followCreature(const CreaturePtr& creature); + + void setCameraPosition(const Position& pos); + void setVisibleDimension(const Size& visibleDimension); + void setAnimated(bool animated) { m_animated = animated; } + + //void zoomIn(float factor); + //void zoomOut(float factor); + + bool isFollowingCreature() { return !!m_followingCreature; } + + int getFirstVisibleFloor(); + int getLastVisibleFloor(); + Position getCameraPosition(); + Size getVisibleDimension() { return m_visibleDimension; } + Size getVisibleSize() { return m_visibleDimension * m_tileSize; } + CreaturePtr getFollowingCreature() { return m_followingCreature; } + + bool isAnimated() { return m_animated; } + + Point transformPositionTo2D(const Position& position); + + MapViewPtr asMapView() { return std::static_pointer_cast(shared_from_this()); } + +private: + int m_drawFlags; + int m_lockedFirstVisibleFloor; + int m_cachedFirstVisibleFloor; + int m_cachedLastVisibleFloor; + int m_tileSize; + Size m_drawDimension; + Size m_visibleDimension; + Point m_virtualCenterOffset; + Position m_customCameraPosition; + Boolean m_mustUpdateVisibleTilesCache; + Boolean m_animated; + std::vector m_cachedVisibleTiles; + std::vector m_cachedFloorVisibleCreatures; + CreaturePtr m_followingCreature; + FrameBufferPtr m_framebuffer; + PainterShaderProgramPtr m_shaderProgram; +}; + +#endif diff --git a/src/otclient/core/missile.cpp b/src/otclient/core/missile.cpp index d765050f..255161ac 100644 --- a/src/otclient/core/missile.cpp +++ b/src/otclient/core/missile.cpp @@ -35,7 +35,7 @@ Missile::Missile() : Thing() void Missile::draw(const Point& p, const Rect&) { float time = (g_clock.ticks() - m_startTicks) / m_duration; - internalDraw(p + Point(m_posDelta.x * time, m_posDelta.y * time), 0); + //internalDraw(p + Point(m_positionDelta.x * time, m_positionDelta.y * time), 0); } void Missile::setPath(const Position& fromPosition, const Position& toPosition) @@ -79,18 +79,16 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition) m_yPattern = 1; } - m_pos = fromPosition; - m_posDelta = toPosition - fromPosition; + m_position = fromPosition; + m_positionDelta = toPosition - fromPosition; m_startTicks = g_clock.ticks(); - m_duration = 150 * std::sqrt(Point(m_posDelta.x, m_posDelta.y).length()); - m_posDelta.x *= Map::NUM_TILE_PIXELS; - m_posDelta.y *= Map::NUM_TILE_PIXELS; + m_duration = 150 * std::sqrt(Point(m_positionDelta.x, m_positionDelta.y).length()); + m_positionDelta.x *= Otc::TILE_PIXELS; + m_positionDelta.y *= Otc::TILE_PIXELS; // schedule removal auto self = asMissile(); - g_dispatcher.scheduleEvent([self]() { - g_map.removeThing(self); - }, m_duration); + g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, m_duration); } ThingType *Missile::getType() diff --git a/src/otclient/core/missile.h b/src/otclient/core/missile.h index 331b3cc3..1cd67e40 100644 --- a/src/otclient/core/missile.h +++ b/src/otclient/core/missile.h @@ -47,7 +47,7 @@ public: private: ticks_t m_startTicks; - Position m_posDelta; + Position m_positionDelta; float m_duration; }; diff --git a/src/otclient/core/spritemanager.cpp b/src/otclient/core/spritemanager.cpp index 7c3ecd1a..d317503d 100644 --- a/src/otclient/core/spritemanager.cpp +++ b/src/otclient/core/spritemanager.cpp @@ -116,7 +116,10 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) writePos += 4; } - return TexturePtr(new Texture(32, 32, 4, pixels)); + TexturePtr spriteTex(new Texture(32, 32, 4, pixels)); + spriteTex->setSmooth(true); + spriteTex->generateBilinearMipmaps(); + return spriteTex; } TexturePtr SpriteManager::getSpriteTexture(int id) diff --git a/src/otclient/core/statictext.cpp b/src/otclient/core/statictext.cpp index bb5f6255..311bd6f6 100644 --- a/src/otclient/core/statictext.cpp +++ b/src/otclient/core/statictext.cpp @@ -31,17 +31,21 @@ StaticText::StaticText() m_font = g_fonts.getFont("verdana-11px-rounded"); } -void StaticText::draw(const Point& p, const Rect& visibleRect) +void StaticText::draw(const Point& dest, const Rect& parentRect) { - Rect rect = Rect(p - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize); + Rect rect = Rect(dest - 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) + boundRect.bind(parentRect); + + if((boundRect.center() - rect.center()).length() < parentRect.width() / 15) { + //TODO: cache into a framebuffer 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) { + //TODO: this could be moved to lua // First message if(m_messages.size() == 0) { m_name = name; @@ -59,7 +63,11 @@ bool StaticText::addMessage(const std::string& name, const std::string& type, co auto self = asStaticText(); g_dispatcher.scheduleEvent([self]() { self->removeMessage(); - }, std::max(DURATION_PER_CHARACTER * message.length(), MIN_DURATION)); + }, std::max(Otc::STATIC_DURATION_PER_CHARACTER * message.length(), Otc::MIN_STATIC_TEXT_DURATION)); + + + if(type == "yell" || type == "monsterYell") + m_yell = true; return true; } @@ -72,40 +80,34 @@ void StaticText::removeMessage() // schedule removal auto self = asStaticText(); g_dispatcher.addEvent([self]() { g_map.removeThing(self); }); - } - else + } else compose(); } void StaticText::compose() { + //TODO: this could be moved to lua std::string text; - text.clear(); if(m_messageType == "say") { text += m_name; text += " says:\n"; m_color = Color(239, 239, 0); - } - else if(m_messageType == "whisper") { + } else if(m_messageType == "whisper") { text += m_name; text += " whispers:\n"; m_color = Color(239, 239, 0); - } - else if(m_messageType == "yell") { + } else if(m_messageType == "yell") { text += m_name; text += " yells:\n"; 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); - } - else if(m_messageType == "npcToPlayer") { + } else if(m_messageType == "npcToPlayer") { text += m_name; text += " says:\n"; m_color = Color(95, 247, 247); - } - else { + } else { logWarning("unknown speak type: ", m_messageType); } @@ -116,6 +118,6 @@ void StaticText::compose() text += "\n"; } - m_text = m_font->wrapText(text, 200); + m_text = m_font->wrapText(text, Otc::MAX_STATIC_TEXT_WIDTH); m_textSize = m_font->calculateTextRectSize(m_text); } diff --git a/src/otclient/core/statictext.h b/src/otclient/core/statictext.h index 8a753b3c..f812fa51 100644 --- a/src/otclient/core/statictext.h +++ b/src/otclient/core/statictext.h @@ -29,19 +29,16 @@ class StaticText : public Thing { public: - enum { - DURATION_PER_CHARACTER = 75, - MIN_DURATION = 3000 - }; - StaticText(); - void draw(const Point& p, const Rect& visibleRect); + void draw(const Point& dest, const Rect& parentRect); std::string getName() { return m_name; } std::string getMessageType() { return m_messageType; } std::string getFirstMessage() { return m_messages[0]; } + bool isYell() { return m_yell; } + bool addMessage(const std::string& name, const std::string& type, const std::string& message); void removeMessage(); @@ -52,6 +49,7 @@ private: FontPtr m_font; Size m_textSize; + Boolean m_yell; std::vector m_messages; std::string m_name, m_text; std::string m_messageType; diff --git a/src/otclient/core/thing.cpp b/src/otclient/core/thing.cpp index a5908c6f..be5e97ad 100644 --- a/src/otclient/core/thing.cpp +++ b/src/otclient/core/thing.cpp @@ -24,6 +24,7 @@ #include "spritemanager.h" #include "thingstype.h" #include +#include "map.h" Thing::Thing() { @@ -32,51 +33,65 @@ Thing::Thing() m_yPattern = 0; m_zPattern = 0; m_animation = 0; - m_type = getType(); -} - -void Thing::internalDraw(const Point& p, int layer) -{ - for(int h = 0; h < m_type->dimensions[ThingType::Height]; h++) { - for(int w = 0; w < m_type->dimensions[ThingType::Width]; w++) { - int spriteId = m_type->getSpriteId(w, h, layer, m_xPattern, m_yPattern, m_zPattern, m_animation); - if(!spriteId) - continue; - - TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId); - - Rect drawRect((p.x - w*32) - m_type->parameters[ThingType::DisplacementX], - (p.y - h*32) - m_type->parameters[ThingType::DisplacementY], - 32, 32); - g_painter.drawTexturedRect(drawRect, spriteTex); - } - } + m_type = g_thingsType.getEmptyThingType(); } void Thing::setId(uint32 id) { m_id = id; - m_type = getType(); + updateType(); } int Thing::getStackPriority() { - if(m_type->properties[ThingType::IsGround]) + if(isGround()) return 0; - else if(m_type->properties[ThingType::IsGroundBorder]) + else if(isGroundBorder()) return 1; - else if(m_type->properties[ThingType::IsOnBottom]) + else if(isOnBottom()) return 2; - else if(m_type->properties[ThingType::IsOnTop]) + else if(isOnTop()) return 3; else if(asCreature()) return 4; - return 5; + else // common items + return 5; } -ThingType *Thing::getType() +const TilePtr& Thing::getCurrentTile() { - return g_thingsType.getEmptyThingType(); + return g_map.getTile(m_position); } +void Thing::internalDraw(const Point& dest, float scaleFactor, int layer) +{ + int scaledSize = Otc::TILE_PIXELS * scaleFactor; + for(int h = 0; h < getDimensionHeight(); h++) { + for(int w = 0; w < getDimensionWidth(); w++) { + int spriteId = getSpriteId(w, h, layer, m_xPattern, m_yPattern, m_zPattern, m_animation); + if(!spriteId) + continue; + + TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId); + Rect drawRect((dest.x - w*scaledSize) - getDisplacementX()*scaleFactor, + (dest.y - h*scaledSize) - getDisplacementY()*scaleFactor, + scaledSize, scaledSize); + g_painter.drawTexturedRect(drawRect, spriteTex); + } + } +} + +void Thing::updateType() +{ + if(CreaturePtr creature = asCreature()) + m_type = g_thingsType.getThingType(creature->getOutfit().getId(), creature->getOutfit().getCategory()); + else if(asItem()) + m_type = g_thingsType.getThingType(m_id, ThingsType::Item); + else if(asMissile()) + m_type = g_thingsType.getThingType(m_id, ThingsType::Missile); + else if(asEffect()) + m_type = g_thingsType.getThingType(m_id, ThingsType::Effect); + else + m_type = g_thingsType.getEmptyThingType(); +} diff --git a/src/otclient/core/thing.h b/src/otclient/core/thing.h index 6c83e6d3..b7b3c67b 100644 --- a/src/otclient/core/thing.h +++ b/src/otclient/core/thing.h @@ -24,7 +24,7 @@ #define THING_H #include "declarations.h" -#include "thingtype.h" +#include "thingstype.h" #include struct Light @@ -39,19 +39,16 @@ public: Thing(); virtual ~Thing() { } - virtual void start() {} + virtual void startAnimation() { } + virtual void draw(const Point& dest, float scaleFactor) { } - virtual void draw(const Point& p, const Rect&) = 0; + virtual void setId(uint32 id); + virtual void setPosition(const Position& position) { m_position = position; } - void setId(uint32 id); - virtual void setPos(const Position& position) { m_pos = position; } - - uint32 getId() const { return m_id; } - Position getPos() const { return m_pos; } + uint32 getId() { return m_id; } + Position getPosition() { return m_position; } int getStackPriority(); - virtual ThingType *getType(); - int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; } - int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; } + const TilePtr& getCurrentTile(); void setXPattern(int xPattern) { m_xPattern = xPattern; } void setYPattern(int yPattern) { m_yPattern = yPattern; } @@ -69,29 +66,53 @@ public: virtual AnimatedTextPtr asAnimatedText() { return nullptr; } virtual StaticTextPtr asStaticText() { return nullptr; } + // type related bool isGround() { return m_type->properties[ThingType::IsGround]; } + bool isFullGround() { return m_type->properties[ThingType::IsFullGround]; } bool isGroundBorder() { return m_type->properties[ThingType::IsGroundBorder]; } bool isOnBottom() { return m_type->properties[ThingType::IsOnBottom]; } bool isOnTop() { return m_type->properties[ThingType::IsOnTop]; } + bool isDontHide() { return m_type->properties[ThingType::DontHide]; } bool isContainer() { return m_type->properties[ThingType::IsContainer]; } bool isForceUse() { return m_type->properties[ThingType::IsForceUse]; } bool isMultiUse() { return m_type->properties[ThingType::IsMultiUse]; } bool isRotateable() { return m_type->properties[ThingType::IsRotateable]; } bool isNotMoveable() { return m_type->properties[ThingType::IsNotMovable]; } + bool isNotWalkable() { return m_type->properties[ThingType::NotWalkable]; } bool isPickupable() { return m_type->properties[ThingType::IsPickupable]; } - bool ignoreLook() { return m_type->properties[ThingType::IgnoreLook]; } + bool isIgnoreLook() { return m_type->properties[ThingType::IgnoreLook]; } + bool isHangable() { return m_type->properties[ThingType::IsHangable]; } + bool isHookSouth() { return m_type->properties[ThingType::HookSouth]; } + bool isHookEast() { return m_type->properties[ThingType::HookEast]; } bool isStackable() { return m_type->properties[ThingType::IsStackable]; } + bool blocksProjectile() { return m_type->properties[ThingType::BlockProjectile]; } bool isFluid() { return m_type->properties[ThingType::IsFluid]; } bool isFluidContainer() { return m_type->properties[ThingType::IsFluidContainer]; } + Size getDimension() { return Size(m_type->dimensions[ThingType::Width], m_type->dimensions[ThingType::Height]); } + int getDimensionWidth() { return m_type->dimensions[ThingType::Width]; } + int getDimensionHeight() { return m_type->dimensions[ThingType::Height]; } + Point getDisplacement() { return Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]); } + int getNumPatternsX() { return m_type->dimensions[ThingType::PatternX]; } + int getNumPatternsY() { return m_type->dimensions[ThingType::PatternY]; } + int getNumPatternsZ() { return m_type->dimensions[ThingType::PatternZ]; } + int getDisplacementX() { return m_type->parameters[ThingType::DisplacementX]; } + int getDisplacementY() { return m_type->parameters[ThingType::DisplacementY]; } + int getLayers() { return m_type->dimensions[ThingType::Layers]; } + int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; } + int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; } + int getElevation() { return m_type->parameters[ThingType::Elevation]; } + int getSpriteId(int w = 0, int h = 0, int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animation = 0) { return m_type->getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animation); } protected: - void internalDraw(const Point& p, int layer); + void internalDraw(const Point& dest, float scaleFactor, int layer); + void updateType(); uint32 m_id; - Position m_pos; - ThingType *m_type; - + Position m_position; int m_xPattern, m_yPattern, m_zPattern, m_animation; + +private: + ThingType *m_type; }; #endif diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index c6d38a05..4ece2213 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -33,49 +33,53 @@ Tile::Tile(const Position& position) { m_drawElevation = 0; - m_pos = position; + m_position = position; } -void Tile::draw(const Point& p, const Rect& visibleRect) +void Tile::draw(const Point& dest, float scaleFactor) { m_drawElevation = 0; // first bottom items for(const ThingPtr& thing : m_things) { - ThingType *type = thing->getType(); - if(!type->properties[ThingType::IsGround] && !type->properties[ThingType::IsGroundBorder] && !type->properties[ThingType::IsOnBottom]) + if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom()) break; - thing->draw(p - m_drawElevation, visibleRect); - m_drawElevation += type->parameters[ThingType::Elevation]; - if(m_drawElevation > MAX_DRAW_ELEVATION) - m_drawElevation = MAX_DRAW_ELEVATION; + thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor); + + m_drawElevation += thing->getElevation(); + if(m_drawElevation > Otc::MAX_ELEVATION) + m_drawElevation = Otc::MAX_ELEVATION; } - // now common items + // now common items in reverse order for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) { const ThingPtr& thing = *it; - ThingType *type = thing->getType(); - if(thing->asCreature() || type->properties[ThingType::IsOnTop] || type->properties[ThingType::IsOnBottom] || type->properties[ThingType::IsGroundBorder] || type->properties[ThingType::IsGround]) + if(thing->asCreature() || thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround()) break; - thing->draw(p - m_drawElevation, visibleRect); - m_drawElevation += type->parameters[ThingType::Elevation]; - if(m_drawElevation > MAX_DRAW_ELEVATION) - m_drawElevation = MAX_DRAW_ELEVATION; + thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor); + + m_drawElevation += thing->getElevation(); + if(m_drawElevation > Otc::MAX_ELEVATION) + m_drawElevation = Otc::MAX_ELEVATION; } // we can render creatures in 3x3 range - //TODO: this algorithm is slowing down render too much, but it could be cached to improve framerate - //NOTE: looping for 9 tiles is a dirty way to render walking creatures, must change this later for(int xi = -1; xi <= 1; ++xi) { for(int yi = -1; yi <= 1; ++yi) { - for(CreaturePtr creature : g_map.getTile(m_pos + Position(xi, yi, 0))->getCreatures()) { - ThingType *type = creature->getType(); - Rect creatureRect(p.x + xi*32 + creature->getWalkOffset().x - type->parameters[ThingType::DisplacementX], p.y + yi*32 + creature->getWalkOffset().y - type->parameters[ThingType::DisplacementY], 32, 32); - Rect thisTileRect(p.x, p.y, 32, 32); + const TilePtr& tile = g_map.getTile(m_position + Position(xi, yi, 0)); + if(!tile) + continue; + for(const CreaturePtr& creature : tile->getCreatures()) { + int tileSize = Otc::TILE_PIXELS * scaleFactor; + Rect creatureRect(dest.x + xi*tileSize + (creature->getWalkOffset().x - creature->getDisplacementX())*scaleFactor, + dest.y + yi*tileSize + (creature->getWalkOffset().y - creature->getDisplacementY())*scaleFactor, + tileSize, tileSize); + Rect thisTileRect(dest.x, dest.y, tileSize, tileSize); // only render creatures where bottom right is inside our rect if(thisTileRect.contains(creatureRect.bottomRight())) { - creature->draw(Point(p.x + xi*32 - m_drawElevation, p.y + yi*32 - m_drawElevation), visibleRect); + creature->draw(Point(dest.x + xi*tileSize - m_drawElevation*scaleFactor, + dest.y + yi*tileSize - m_drawElevation*scaleFactor), scaleFactor); } } } @@ -83,13 +87,12 @@ void Tile::draw(const Point& p, const Rect& visibleRect) // effects for(const EffectPtr& effect : m_effects) - effect->draw(p - m_drawElevation, visibleRect); + effect->draw(dest, scaleFactor); // top items for(const ThingPtr& thing : m_things) { - ThingType *type = thing->getType(); - if(type->properties[ThingType::IsOnTop]) - thing->draw(p, visibleRect); + if(thing->isOnTop()) + thing->draw(dest - m_drawElevation, scaleFactor); } } @@ -104,6 +107,8 @@ ThingPtr Tile::addThing(const ThingPtr& thing, int stackPos) if(!thing) return nullptr; + thing->setPosition(m_position); + if(EffectPtr effect = thing->asEffect()) { m_effects.push_back(effect); return nullptr; @@ -124,9 +129,40 @@ 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); + return oldObject; } +bool Tile::removeThing(const ThingPtr& thing) +{ + if(!thing) + return false; + + bool removed = false; + + if(EffectPtr effect = thing->asEffect()) { + auto it = std::find(m_effects.begin(), m_effects.end(), effect); + if(it != m_effects.end()) { + m_effects.erase(it); + removed = true; + } + } else { + auto it = std::find(m_things.begin(), m_things.end(), thing); + if(it != m_things.end()) { + m_things.erase(it); + removed = true; + } + } + + // reset values managed by this tile + if(removed) { + //thing->setDrawOffset(0); + //thing->setStackpos(0); + } + + return removed; +} + ThingPtr Tile::getThing(int stackPos) { if(stackPos >= 0 && stackPos < (int)m_things.size()) @@ -150,33 +186,6 @@ ThingPtr Tile::getTopThing() return m_things[m_things.size() - 1]; } -ThingPtr Tile::removeThingByStackpos(int stackPos) -{ - ThingPtr oldThing; - if(stackPos >= 0 && stackPos < (int)m_things.size()) { - oldThing = m_things[stackPos]; - m_things.erase(m_things.begin() + stackPos); - } - return oldThing; -} - -ThingPtr Tile::removeThing(const ThingPtr& thing) -{ - if(EffectPtr effect = thing->asEffect()) { - auto it = std::find(m_effects.begin(), m_effects.end(), effect); - if(it != m_effects.end()) - m_effects.erase(it); - return thing; - } - ThingPtr oldThing; - auto it = std::find(m_things.begin(), m_things.end(), thing); - if(it != m_things.end()) { - oldThing = *it; - m_things.erase(it); - } - return oldThing; -} - std::vector Tile::getCreatures() { std::vector creatures; @@ -192,8 +201,7 @@ ItemPtr Tile::getGround() ThingPtr firstObject = getThing(0); if(!firstObject) return nullptr; - ThingType *type = firstObject->getType(); - if(type->properties[ThingType::IsGround]) + if(firstObject->isGround()) return firstObject->asItem(); return nullptr; } @@ -213,7 +221,7 @@ ThingPtr Tile::getTopLookThing() for(uint i = 0; i < m_things.size(); ++i) { ThingPtr thing = m_things[i]; - if(!thing->ignoreLook() && (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) + if(!thing->isIgnoreLook() && (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) return thing; } @@ -239,7 +247,7 @@ CreaturePtr Tile::getTopCreature() CreaturePtr creature; for(uint i = 0; i < m_things.size(); ++i) { ThingPtr thing = m_things[i]; - if(thing->asLocalPlayer()) // return local player if there aint no other creature. + if(thing->asLocalPlayer()) // return local player if there is no other creature creature = thing->asCreature(); else if(thing->asCreature() && !thing->asLocalPlayer()) return thing->asCreature(); @@ -288,8 +296,7 @@ bool Tile::isWalkable() return false; for(const ThingPtr& thing : m_things) { - ThingType *type = thing->getType(); - if(type->properties[ThingType::NotWalkable]) + if(thing->isNotWalkable()) return false; if(CreaturePtr creature = thing->asCreature()) { @@ -302,11 +309,8 @@ bool Tile::isWalkable() bool Tile::isFullGround() { - ThingPtr ground = getThing(0); - if(!ground) - return false; - ThingType *type = ground->getType(); - if(type->properties[ThingType::IsGround] && type->properties[ThingType::IsFullGround]) + ItemPtr ground = getGround(); + if(ground && ground->isFullGround()) return true; return false; } @@ -314,19 +318,13 @@ bool Tile::isFullGround() bool Tile::isFullyOpaque() { ThingPtr firstObject = getThing(0); - if(firstObject) { - ThingType *type = firstObject->getType(); - if(type->properties[ThingType::IsFullGround]) - return true; - } - return false; + return firstObject && firstObject->isFullGround(); } bool Tile::isLookPossible() { for(const ThingPtr& thing : m_things) { - ThingType *type = thing->getType(); - if(type->properties[ThingType::BlockProjectile]) + if(thing->blocksProjectile()) return false; } return true; @@ -334,14 +332,15 @@ bool Tile::isLookPossible() bool Tile::isClickable() { - bool hasGround = false, hasOnBottom = false, hasIgnoreLook = false; + bool hasGround = false; + bool hasOnBottom = false; + bool hasIgnoreLook = false; for(const ThingPtr& thing : m_things) { - ThingType *type = thing->getType(); - if(type->properties[ThingType::IsGround]) + if(thing->isGround()) hasGround = true; - if(type->properties[ThingType::IsOnBottom]) + if(thing->isOnBottom()) hasOnBottom = true; - if(type->properties[ThingType::IgnoreLook]) + if(thing->isIgnoreLook()) hasIgnoreLook = true; if((hasGround || hasOnBottom) && !hasIgnoreLook) @@ -350,6 +349,11 @@ bool Tile::isClickable() return false; } +bool Tile::isEmpty() +{ + return m_things.size() == 0; +} + bool Tile::hasCreature() { for(const ThingPtr& thing : m_things) @@ -358,7 +362,11 @@ bool Tile::hasCreature() return false; } -bool Tile::isEmpty() +bool Tile::limitsFloorsView() { - return m_things.size() == 0; + // ground and walls limits the view + ThingPtr firstThing = getThing(0); + if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom())) + return true; + return false; } diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 4aec1107..0404bb45 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -28,21 +28,25 @@ class Tile : public LuaObject { - enum { - MAX_DRAW_ELEVATION = 24 - }; public: Tile(const Position& position); - void draw(const Point& p, const Rect& visibleRect); + void draw(const Point& dest, float scaleFactor); + +private: + void updateVisibleItemsCache(); + +public: void clean(); ThingPtr addThing(const ThingPtr& thing, int stackPos = -1); + bool removeThing(const ThingPtr& thing); ThingPtr getThing(int stackPos); int getThingStackpos(const ThingPtr& thing); ThingPtr getTopThing(); - ThingPtr removeThingByStackpos(int stackPos); - ThingPtr removeThing(const ThingPtr& thing); + + void addWalkingCreature(const CreaturePtr& creature); + void removeWalkingCreature(const CreaturePtr& creature); ThingPtr getTopLookThing(); @@ -51,7 +55,7 @@ public: ThingPtr getTopMoveThing(); ThingPtr getTopMultiUseThing(); - const Position& getPos() { return m_pos; } + const Position& getPosition() { return m_position; } int getDrawElevation() { return m_drawElevation; } std::vector getCreatures(); ItemPtr getGround(); @@ -60,16 +64,19 @@ public: bool isFullGround(); bool isFullyOpaque(); bool isLookPossible(); - bool hasCreature(); - bool isEmpty(); bool isClickable(); + bool isEmpty(); + bool hasCreature(); + bool limitsFloorsView(); + int getThingCount() { return m_things.size() + m_effects.size(); } TilePtr asTile() { return std::static_pointer_cast(shared_from_this()); } private: - std::vector m_effects; // Leave this outside m_things because it has no stackpos. + std::vector m_walkingCreatures; + std::vector m_effects; // leave this outside m_things because it has no stackpos. std::vector m_things; - Position m_pos; + Position m_position; int m_drawElevation; }; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 3571b58f..0459938e 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -60,10 +60,9 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("g_sprites", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites)); g_lua.registerStaticClass("g_map"); - g_lua.bindClassStaticFunction("g_map", "getFirstVisibleFloor", std::bind(&Map::getFirstVisibleFloor, &g_map)); g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, _1)); g_lua.bindClassStaticFunction("g_map", "isCovered", std::bind(&Map::isCovered, &g_map, _1, _2)); - g_lua.bindClassStaticFunction("g_map", "isCompletlyCovered", std::bind(&Map::isCompletlyCovered, &g_map, _1, _2)); + g_lua.bindClassStaticFunction("g_map", "isCompletelyCovered", std::bind(&Map::isCompletelyCovered, &g_map, _1, _2)); g_lua.bindClassStaticFunction("g_map", "addThing", std::bind(&Map::addThing, &g_map, _1, _2, _3)); g_lua.bindClassStaticFunction("g_map", "getThing", std::bind(&Map::getThing, &g_map, _1, _2)); g_lua.bindClassStaticFunction("g_map", "removeThingByPos", std::bind(&Map::removeThingByPos, &g_map, _1, _2)); @@ -72,13 +71,8 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("g_map", "getTile", std::bind(&Map::getTile, &g_map, _1)); g_lua.bindClassStaticFunction("g_map", "setCentralPosition", std::bind(&Map::setCentralPosition, &g_map, _1)); g_lua.bindClassStaticFunction("g_map", "getCentralPosition", std::bind(&Map::getCentralPosition, &g_map)); - g_lua.bindClassStaticFunction("g_map", "addCreature", std::bind(&Map::addCreature, &g_map, _1)); g_lua.bindClassStaticFunction("g_map", "getCreatureById", std::bind(&Map::getCreatureById, &g_map, _1)); g_lua.bindClassStaticFunction("g_map", "removeCreatureById", std::bind(&Map::removeCreatureById, &g_map, _1)); - g_lua.bindClassStaticFunction("g_map", "setVisibleSize", std::bind(&Map::setVisibleSize, &g_map, _1)); - g_lua.bindClassStaticFunction("g_map", "getVibibleSize", std::bind(&Map::getVibibleSize, &g_map)); - g_lua.bindClassStaticFunction("g_map", "getCentralOffset", std::bind(&Map::getCentralOffset, &g_map)); - g_lua.bindClassStaticFunction("g_map", "positionTo2D", std::bind(&Map::positionTo2D, &g_map, _1)); g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor); @@ -91,9 +85,9 @@ void OTClient::registerLuaFunctions() g_lua.registerClass(); g_lua.bindClassMemberFunction("setId", &Thing::setId); - g_lua.bindClassMemberFunction("setPos", &Thing::setPos); + g_lua.bindClassMemberFunction("setPosition", &Thing::setPosition); g_lua.bindClassMemberFunction("getId", &Thing::getId); - g_lua.bindClassMemberFunction("getPos", &Thing::getPos); + g_lua.bindClassMemberFunction("getPosition", &Thing::getPosition); g_lua.bindClassMemberFunction("getStackPriority", &Thing::getStackPriority); g_lua.bindClassMemberFunction("getAnimationPhases", &Thing::getAnimationPhases); g_lua.bindClassMemberFunction("setXPattern", &Thing::setXPattern); @@ -118,7 +112,7 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("isRotateable", &Thing::isRotateable); g_lua.bindClassMemberFunction("isNotMoveable", &Thing::isNotMoveable); g_lua.bindClassMemberFunction("isPickupable", &Thing::isPickupable); - g_lua.bindClassMemberFunction("ignoreLook", &Thing::ignoreLook); + g_lua.bindClassMemberFunction("isIgnoreLook", &Thing::isIgnoreLook); g_lua.bindClassMemberFunction("isStackable", &Thing::isStackable); g_lua.registerClass(); @@ -165,14 +159,13 @@ void OTClient::registerLuaFunctions() g_lua.bindClassMemberFunction("getThing", &Tile::getThing); g_lua.bindClassMemberFunction("getThingStackpos", &Tile::getThingStackpos); g_lua.bindClassMemberFunction("getTopThing", &Tile::getTopThing); - g_lua.bindClassMemberFunction("removeThingByStackpos", &Tile::removeThingByStackpos); g_lua.bindClassMemberFunction("removeThing", &Tile::removeThing); g_lua.bindClassMemberFunction("getTopLookThing", &Tile::getTopLookThing); g_lua.bindClassMemberFunction("getTopUseThing", &Tile::getTopUseThing); g_lua.bindClassMemberFunction("getTopCreature", &Tile::getTopCreature); g_lua.bindClassMemberFunction("getTopMoveThing", &Tile::getTopMoveThing); g_lua.bindClassMemberFunction("getTopMultiUseThing", &Tile::getTopMultiUseThing); - g_lua.bindClassMemberFunction("getPos", &Tile::getPos); + g_lua.bindClassMemberFunction("getPosition", &Tile::getPosition); g_lua.bindClassMemberFunction("getDrawElevation", &Tile::getDrawElevation); g_lua.bindClassMemberFunction("getCreatures", &Tile::getCreatures); g_lua.bindClassMemberFunction("getGround", &Tile::getGround); @@ -238,6 +231,8 @@ void OTClient::registerLuaFunctions() g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return UIMapPtr(new UIMap); } ); g_lua.bindClassMemberFunction("getTile", &UIMap::getTile); + g_lua.bindClassMemberFunction("zoomIn", &UIMap::zoomIn); + g_lua.bindClassMemberFunction("zoomOut", &UIMap::zoomOut); g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return UIGamePtr(new UIGame); } ); diff --git a/src/otclient/net/protocolgameparse.cpp b/src/otclient/net/protocolgameparse.cpp index aed1c6a3..ed05b3c8 100644 --- a/src/otclient/net/protocolgameparse.cpp +++ b/src/otclient/net/protocolgameparse.cpp @@ -407,7 +407,7 @@ void ProtocolGame::parseCreatureMove(InputMessage& msg) int oldStackpos = msg.getU8(); Position newPos = parsePosition(msg); - ThingPtr thing = g_map.getTile(oldPos)->getThing(oldStackpos); + ThingPtr thing = g_map.getThing(oldPos, oldStackpos); if(!thing) { logTraceError("could not get thing"); return; @@ -566,10 +566,10 @@ void ProtocolGame::parseDistanceMissile(InputMessage& msg) Position toPos = parsePosition(msg); int shotId = msg.getU8(); - MissilePtr shot = MissilePtr(new Missile()); - shot->setId(shotId); - shot->setPath(fromPos, toPos); - g_map.addThing(shot, fromPos); + MissilePtr missile = MissilePtr(new Missile()); + missile->setId(shotId); + missile->setPath(fromPos, toPos); + g_map.addThing(missile, fromPos); } void ProtocolGame::parseCreatureSquare(InputMessage& msg) @@ -866,7 +866,7 @@ void ProtocolGame::parseOutfitWindow(InputMessage& msg) } CreaturePtr creature = CreaturePtr(new Creature); - creature->setXPattern(2); + creature->setDirection(Otc::South); creature->setOutfit(outfit); g_lua.callGlobalField("Game", "onOpenOutfitWindow", creature, outfitList); @@ -1041,7 +1041,7 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg) if(knownCreature) creature = knownCreature; else - logTraceError("server says creature is known, but its not on creatures list"); + logTraceError("server said that a creature is known, but it's not"); } else if(thingId == 0x0061) { //creature is not known uint removeId = msg.getU32(); uint id = msg.getU32(); @@ -1065,6 +1065,8 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg) creature->setId(id); creature->setName(name); + + g_map.addCreature(creature); } uint8 healthPercent = msg.getU8(); diff --git a/src/otclient/ui/uicreature.cpp b/src/otclient/ui/uicreature.cpp index 4b6debf2..c21f85ff 100644 --- a/src/otclient/ui/uicreature.cpp +++ b/src/otclient/ui/uicreature.cpp @@ -30,7 +30,7 @@ void UICreature::draw() if(m_creature) { g_painter.setColor(Fw::white); - m_creature->draw(m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top), m_rect); + m_creature->draw(m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top), 1); } drawChildren(); diff --git a/src/otclient/ui/uiitem.cpp b/src/otclient/ui/uiitem.cpp index 2eff3049..bc3cbe64 100644 --- a/src/otclient/ui/uiitem.cpp +++ b/src/otclient/ui/uiitem.cpp @@ -38,7 +38,7 @@ void UIItem::draw() Point topLeft = m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top); g_painter.setColor(Fw::white); - m_item->draw(topLeft, m_rect); + m_item->draw(topLeft, 1); if(m_font && m_item->isStackable() && m_item->getData() > 1) { std::string count = Fw::tostring(m_item->getData()); diff --git a/src/otclient/ui/uimap.cpp b/src/otclient/ui/uimap.cpp index 45ca39d3..45044f83 100644 --- a/src/otclient/ui/uimap.cpp +++ b/src/otclient/ui/uimap.cpp @@ -23,6 +23,7 @@ #include "uimap.h" #include #include +#include #include #include #include @@ -30,21 +31,56 @@ UIMap::UIMap() { m_dragable = true; + m_mapView = MapViewPtr(new MapView); + g_map.addMapView(m_mapView); + m_mapView->followCreature(g_game.getLocalPlayer()); +} + +UIMap::~UIMap() +{ + g_map.removeMapView(m_mapView); } void UIMap::draw() { drawSelf(); + // draw black brounding border g_painter.setColor(Fw::black); g_painter.drawBoundingRect(m_mapRect.expanded(1)); - g_map.draw(m_mapRect); + + m_mapView->draw(m_mapRect); drawChildren(); } +void UIMap::zoomIn() +{ + m_mapView->setVisibleDimension(m_mapView->getVisibleDimension() + Size(2,2)); + + Rect mapRect = getChildrenRect().expanded(-1); + Size mapSize = m_mapView->getVisibleSize(); + mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); + + m_mapRect.resize(mapSize); + m_mapRect.moveCenter(m_rect.center()); +} + +void UIMap::zoomOut() +{ + m_mapView->setVisibleDimension(m_mapView->getVisibleDimension() - Size(2,2)); + + Rect mapRect = getChildrenRect().expanded(-1); + Size mapSize = m_mapView->getVisibleSize(); + mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); + + m_mapRect.resize(mapSize); + m_mapRect.moveCenter(m_rect.center()); +} + TilePtr UIMap::getTile(const Point& mousePos) { + /* if(!m_mapRect.contains(mousePos)) return nullptr; @@ -55,12 +91,12 @@ TilePtr UIMap::getTile(const Point& mousePos) if(localPlayer) relativeStretchMousePos += localPlayer->getWalkOffset(); - Size mapSize(g_map.getVibibleSize().width() * Map::NUM_TILE_PIXELS, g_map.getVibibleSize().height() * Map::NUM_TILE_PIXELS); + Size mapSize(g_map.getVibibleSize().width() * Otc::TILE_PIXELS, g_map.getVibibleSize().height() * Otc::TILE_PIXELS); PointF stretchFactor(m_mapRect.width() / (float)mapSize.width(), m_mapRect.height() / (float)mapSize.height()); PointF relativeMousePos = PointF(relativeStretchMousePos.x, relativeStretchMousePos.y) / stretchFactor; - PointF tilePosF = relativeMousePos / Map::NUM_TILE_PIXELS; + PointF tilePosF = relativeMousePos / Otc::TILE_PIXELS; Position tilePos = Position(1 + (int)tilePosF.x - g_map.getCentralOffset().x, 1 + (int)tilePosF.y - g_map.getCentralOffset().y, 0) + g_map.getCentralPosition(); if(!tilePos.isValid()) return nullptr; @@ -70,7 +106,7 @@ TilePtr UIMap::getTile(const Point& mousePos) // We must check every floor, from top to bottom to check for a clickable tile int firstFloor = g_map.getFirstVisibleFloor(); - tilePos.perspectiveUp(tilePos.z - firstFloor); + tilePos.coveredUp(tilePos.z - firstFloor); for(int i = firstFloor; i <= Map::MAX_Z; i++) { tile = g_map.getTile(tilePos); if(tile && tile->isClickable()) @@ -84,12 +120,14 @@ TilePtr UIMap::getTile(const Point& mousePos) return nullptr; return tile; + */ + return nullptr; } void UIMap::onGeometryChange(const Rect& oldRect, const Rect& newRect) { Rect mapRect = getChildrenRect().expanded(-1); - Size mapSize(g_map.getVibibleSize().width() * Map::NUM_TILE_PIXELS, g_map.getVibibleSize().height() * Map::NUM_TILE_PIXELS); + Size mapSize = m_mapView->getVisibleSize(); mapSize.scale(mapRect.size(), Fw::KeepAspectRatio); m_mapRect.resize(mapSize); diff --git a/src/otclient/ui/uimap.h b/src/otclient/ui/uimap.h index 4e0f6ab1..836ed40d 100644 --- a/src/otclient/ui/uimap.h +++ b/src/otclient/ui/uimap.h @@ -31,14 +31,20 @@ class UIMap : public UIWidget { public: UIMap(); + ~UIMap(); + void draw(); + void zoomIn(); + void zoomOut(); + TilePtr getTile(const Point& mousePos); protected: virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect); private: + MapViewPtr m_mapView; Rect m_mapRect; }; diff --git a/src/otclient/util/position.h b/src/otclient/util/position.h index bcbdd50d..9ff18853 100644 --- a/src/otclient/util/position.h +++ b/src/otclient/util/position.h @@ -33,7 +33,7 @@ public: Position() : x(-1), y(-1), z(-1) { } Position(int x, int y, int z) : x(x), y(y), z(z) { } - static Position getPosFromDirection(Otc::Direction direction) { + static Position getPositionFromDirection(Otc::Direction direction) { switch(direction) { case Otc::North: return Position( 0, -1, 0); @@ -116,7 +116,7 @@ public: void up(int n = 1) { z-=n; } void down(int n = 1) { z+=n; } - void perspectiveUp(int n = 1) { x+=n; y+=n; z-=n; } + void coveredUp(int n = 1) { x+=n; y+=n; z-=n; } void coveredDown(int n = 1) { x-=n; y-=n; z+=n; } int x;