merge revgraphics
This commit is contained in:
commit
7bb828faee
|
@ -173,6 +173,11 @@ end
|
|||
|
||||
function Terminal.executeCommand(command)
|
||||
if command == nil or #command == 0 then return end
|
||||
|
||||
logLocked = true
|
||||
Logger.log(LogInfo, '>> ' .. command)
|
||||
logLocked = false
|
||||
|
||||
-- detect and convert commands with simple syntax
|
||||
local realCommand
|
||||
if commandEnv[command] then
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit dd648e1431171bffe091b748744395780df7eba1
|
||||
Subproject commit 9beb17daaeb170c127c39c5a5e4feb9d95ebed92
|
|
@ -298,3 +298,18 @@ KeyCodeDescs = {
|
|||
[KeyNumpad8] = 'Numpad8',
|
||||
[KeyNumpad9] = 'Numpad9'
|
||||
}
|
||||
|
||||
SpeakSay = 1
|
||||
SpeakWhisper = 2
|
||||
SpeakYell = 3
|
||||
SpeakBroadcast = 4
|
||||
SpeakPrivate = 5
|
||||
SpeakPrivateRed = 6
|
||||
SpeakPrivatePlayerToNpc = 7
|
||||
SpeakPrivateNpcToPlayer = 8
|
||||
SpeakChannelYellow = 9
|
||||
SpeakChannelWhite = 10
|
||||
SpeakChannelRed = 11
|
||||
SpeakChannelOrange = 12
|
||||
SpeakMonsterSay = 13
|
||||
SpeakMonsterYell = 14
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
Settings = {}
|
||||
|
||||
Settings.exists = g_configs.exists
|
||||
Settings.setNode = g_configs.setNode
|
||||
Settings.addNode = g_configs.addNode
|
||||
Settings.getNode = g_configs.getNode
|
||||
Settings.remove = g_configs.remove
|
||||
Settings.setList = g_configs.setList
|
||||
Settings.getList = g_configs.getList
|
||||
|
||||
local function convertSettingValue(value)
|
||||
if type(value) == 'table' then
|
||||
if value.x and value.width then
|
||||
|
@ -20,21 +28,10 @@ local function convertSettingValue(value)
|
|||
end
|
||||
end
|
||||
|
||||
function Settings.exists(key)
|
||||
return g_configs.exists(key)
|
||||
end
|
||||
|
||||
function Settings.remove(key)
|
||||
g_configs.remove(key)
|
||||
end
|
||||
|
||||
function Settings.set(key, value)
|
||||
g_configs.set(key, convertSettingValue(value))
|
||||
end
|
||||
|
||||
function Settings.setList(key, list)
|
||||
g_configs.setList(key, list)
|
||||
end
|
||||
|
||||
function Settings.setDefault(key, value)
|
||||
if Settings.exists(key) then return false end
|
||||
|
@ -49,10 +46,6 @@ function Settings.get(key, default)
|
|||
return g_configs.get(key)
|
||||
end
|
||||
|
||||
function Settings.getList(key)
|
||||
return g_configs.getList(key)
|
||||
end
|
||||
|
||||
function Settings.getString(key, default)
|
||||
return Settings.get(key, default)
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ local function moveToolTip(tooltip)
|
|||
else
|
||||
pos.x = pos.x + 10
|
||||
end
|
||||
tooltip:setPos(pos)
|
||||
tooltip:setPosition(pos)
|
||||
end
|
||||
|
||||
-- public functions
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
function UIItem:onDragEnter(mousePos)
|
||||
if self:isVirtual() then return false end
|
||||
|
||||
local item = self:getItem()
|
||||
if not item then return false end
|
||||
if not item then return true end
|
||||
|
||||
self:setBorderWidth(1)
|
||||
|
||||
|
@ -11,28 +13,32 @@ function UIItem:onDragEnter(mousePos)
|
|||
end
|
||||
|
||||
function UIItem:onDragLeave(widget, mousePos)
|
||||
if self:isVirtual() then return false end
|
||||
|
||||
if not self.parsed then
|
||||
self.currentDragThing = nil
|
||||
end
|
||||
|
||||
|
||||
restoreCursor()
|
||||
self:setBorderWidth(0)
|
||||
return true
|
||||
end
|
||||
|
||||
function UIItem:onDrop(widget, mousePos)
|
||||
if not widget or not widget.currentDragThing then return false end
|
||||
if self:isVirtual() then return false end
|
||||
|
||||
if not widget or not widget.currentDragThing then return true end
|
||||
|
||||
local pos = self.position
|
||||
local data = widget.currentDragThing:getData()
|
||||
if widget.currentDragThing:isStackable() and data > 1 then
|
||||
local count = widget.currentDragThing:getCount()
|
||||
if widget.currentDragThing:isStackable() and count > 1 then
|
||||
widget.parsed = true
|
||||
local moveWindow = displayUI('/game/movewindow.otui')
|
||||
local spinbox = moveWindow:getChildById('spinbox')
|
||||
spinbox:setMaximum(data)
|
||||
spinbox:setMaximum(count)
|
||||
spinbox:setMinimum(1)
|
||||
spinbox:setCurrentIndex(data)
|
||||
|
||||
spinbox:setCurrentIndex(count)
|
||||
|
||||
local okButton = moveWindow:getChildById('buttonOk')
|
||||
okButton.onClick = function() Game.move(widget.currentDragThing, pos, spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end
|
||||
moveWindow.onEnter = okButton.onClick
|
||||
|
@ -45,6 +51,8 @@ function UIItem:onDrop(widget, mousePos)
|
|||
end
|
||||
|
||||
function UIItem:onHoverChange(hovered)
|
||||
if self:isVirtual() then return end
|
||||
|
||||
if g_ui.getDraggingWidget() and self ~= g_ui.getDraggingWidget() then
|
||||
if hovered then
|
||||
self:setBorderWidth(1)
|
||||
|
@ -55,6 +63,8 @@ function UIItem:onHoverChange(hovered)
|
|||
end
|
||||
|
||||
function UIItem:onMouseRelease(mousePosition, mouseButton)
|
||||
if self:isVirtual() then return false end
|
||||
|
||||
local item = self:getItem()
|
||||
if not item or not self:containsPoint(mousePosition) then return false end
|
||||
return Game.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, item)
|
||||
|
|
|
@ -65,7 +65,7 @@ function UIPopupMenu:onKeyPress(keyCode, keyboardModifiers, wouldFilter)
|
|||
return false
|
||||
end
|
||||
|
||||
-- close all menus when the window is resized
|
||||
-- close all menus when the window is resized
|
||||
local function onRootGeometryUpdate()
|
||||
for i,menu in ipairs(displayedMenuList) do
|
||||
menu:destroy()
|
||||
|
|
|
@ -21,12 +21,12 @@ local function onUseWithMouseRelease(self, mousePosition, mouseButton)
|
|||
if mouseButton == MouseLeftButton then
|
||||
local clickedWidget = Game.gameUi:recursiveGetChildByPos(mousePosition)
|
||||
if clickedWidget then
|
||||
if clickedWidget.getTile then
|
||||
if clickedWidget:getClassName() == 'UIMap' then
|
||||
local tile = clickedWidget:getTile(mousePosition)
|
||||
if tile then
|
||||
Game.useWith(Game.selectedThing, tile:getTopMultiUseThing())
|
||||
end
|
||||
elseif clickedWidget.getItem then
|
||||
elseif clickedWidget:getClassName() == 'UIItem' and not clickedWidget:isVirtual() then
|
||||
Game.useWith(Game.selectedThing, clickedWidget:getItem())
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ function UIMap:onDragLeave(widget, mousePos)
|
|||
if not self.parsed then
|
||||
self.currentDragThing = nil
|
||||
end
|
||||
|
||||
|
||||
restoreCursor()
|
||||
return true
|
||||
end
|
||||
|
@ -25,21 +25,21 @@ function UIMap:onDrop(widget, mousePos)
|
|||
|
||||
local tile = self:getTile(mousePos)
|
||||
if not tile then return false end
|
||||
|
||||
local data = widget.currentDragThing:getData()
|
||||
|
||||
local count = widget.currentDragThing:getCount()
|
||||
if widget.currentDragThing:isStackable() and data > 1 then
|
||||
widget.parsed = true
|
||||
local moveWindow = displayUI('/game/movewindow.otui')
|
||||
local spinbox = moveWindow:getChildById('spinbox')
|
||||
spinbox:setMaximum(data)
|
||||
spinbox:setMaximum(count)
|
||||
spinbox:setMinimum(1)
|
||||
spinbox:setCurrentIndex(data)
|
||||
|
||||
spinbox:setCurrentIndex(count)
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
uniform float opacity; // painter opacity
|
||||
uniform vec4 color; // painter color
|
||||
uniform float time; // time in seconds since shader linkage
|
||||
uniform sampler2D texture; // map texture
|
||||
varying vec2 textureCoords; // map texture coords
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(texture, textureCoords) * opacity;
|
||||
}
|
|
@ -11,24 +11,19 @@ uniform vec4 bodyColor;
|
|||
uniform vec4 legsColor;
|
||||
uniform vec4 feetColor;
|
||||
|
||||
const vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);
|
||||
const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
const vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);
|
||||
|
||||
vec4 calcOutfitPixel()
|
||||
{
|
||||
vec4 pixel = texture2D(texture, textureCoords);
|
||||
vec4 maskColor = texture2D(maskTexture, textureCoords);
|
||||
|
||||
vec4 outColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
if(maskColor == yellow)
|
||||
if(maskColor.r > 0.1 && maskColor.g > 0.1)
|
||||
outColor = headColor;
|
||||
else if(maskColor == red)
|
||||
else if(maskColor.r > 0.1)
|
||||
outColor = bodyColor;
|
||||
else if(maskColor == green)
|
||||
else if(maskColor.g > 0.1)
|
||||
outColor = legsColor;
|
||||
else if(maskColor == blue)
|
||||
else if(maskColor.b > 0.1)
|
||||
outColor = feetColor;
|
||||
|
||||
return pixel * outColor;
|
||||
|
|
|
@ -112,3 +112,22 @@ void ConfigManager::remove(const std::string& key)
|
|||
if(child)
|
||||
m_confsDoc->removeChild(child);
|
||||
}
|
||||
|
||||
void ConfigManager::setNode(const std::string& key, const OTMLNodePtr& node)
|
||||
{
|
||||
remove(key);
|
||||
addNode(key, node);
|
||||
}
|
||||
|
||||
void ConfigManager::addNode(const std::string& key, const OTMLNodePtr& node)
|
||||
{
|
||||
OTMLNodePtr clone = node->clone();
|
||||
node->setTag(key);
|
||||
node->setUnique(true);
|
||||
m_confsDoc->addChild(node);
|
||||
}
|
||||
|
||||
OTMLNodePtr ConfigManager::getNode(const std::string& key)
|
||||
{
|
||||
return m_confsDoc->get(key);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,11 @@ public:
|
|||
void setList(const std::string& key, const std::vector<std::string>& list);
|
||||
std::string get(const std::string& key);
|
||||
std::vector<std::string> getList(const std::string& key);
|
||||
|
||||
void setNode(const std::string& key, const OTMLNodePtr& node);
|
||||
void addNode(const std::string& key, const OTMLNodePtr& node);
|
||||
OTMLNodePtr getNode(const std::string& key);
|
||||
|
||||
bool exists(const std::string& key);
|
||||
void remove(const std::string& key);
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ EventDispatcher g_dispatcher;
|
|||
|
||||
void EventDispatcher::flush()
|
||||
{
|
||||
poll();
|
||||
while(!m_eventList.empty())
|
||||
poll();
|
||||
|
||||
while(!m_scheduledEventList.empty())
|
||||
m_scheduledEventList.pop();
|
||||
|
@ -44,7 +45,8 @@ void EventDispatcher::poll()
|
|||
scheduledEvent->execute();
|
||||
}
|
||||
|
||||
while(!m_eventList.empty()) {
|
||||
int maxEvents = m_eventList.size();
|
||||
for(int i=0;i<maxEvents;++i) {
|
||||
EventPtr event = m_eventList.front();
|
||||
m_eventList.pop_front();
|
||||
event->execute();
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
Event(const SimpleCallback& callback) : m_callback(callback), m_canceled(false), m_executed(false) { }
|
||||
|
||||
void execute() {
|
||||
if(!m_canceled) {
|
||||
if(!m_canceled && !m_executed) {
|
||||
m_callback();
|
||||
m_executed = true;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ bool ResourceManager::saveFile(const std::string& fileName, const uchar* data, u
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ResourceManager::saveFile(const std::string& fileName, std::istream& in)
|
||||
bool ResourceManager::saveFile(const std::string& fileName, std::iostream& in)
|
||||
{
|
||||
std::streampos oldPos = in.tellg();
|
||||
in.seekg(0, std::ios::end);
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
|
||||
bool saveFile(const std::string& fileName, const uchar* data, uint size);
|
||||
bool saveFile(const std::string& fileName, const std::string& data);
|
||||
bool saveFile(const std::string& fileName, std::istream& in);
|
||||
bool saveFile(const std::string& fileName, std::iostream& in);
|
||||
|
||||
bool deleteFile(const std::string& fileName);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -83,6 +95,16 @@ void FrameBuffer::release()
|
|||
g_graphics.setViewportSize(m_oldViewportSize);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -24,21 +24,26 @@
|
|||
#define FRAMEBUFFER_H
|
||||
|
||||
#include "declarations.h"
|
||||
#include "texture.h"
|
||||
|
||||
class FrameBuffer
|
||||
{
|
||||
public:
|
||||
FrameBuffer();
|
||||
FrameBuffer(const Size& size);
|
||||
virtual ~FrameBuffer();
|
||||
|
||||
void resize(const Size& size);
|
||||
void bind(bool clear = true);
|
||||
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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
|
||||
void setViewportSize(const Size& size);
|
||||
|
||||
int getMaxTextureSize();
|
||||
const Size& getViewportSize() { return m_viewportSize; }
|
||||
TexturePtr getEmptyTexture() { return m_emptyTexture; }
|
||||
|
||||
|
|
|
@ -60,8 +60,8 @@ void Painter::drawProgram(const PainterShaderProgramPtr& program, CoordsBuffer&
|
|||
return;
|
||||
|
||||
program->setProjectionMatrix(m_projectionMatrix);
|
||||
program->setOpacity(m_currentOpacity);
|
||||
program->setColor(m_currentColor);
|
||||
program->setOpacity(m_opacity);
|
||||
program->setColor(m_color);
|
||||
program->draw(coordsBuffer, drawMode);
|
||||
}
|
||||
|
||||
|
@ -141,4 +141,32 @@ void Painter::setCompositionMode(Painter::CompositionMode compositionMode)
|
|||
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
|
||||
break;
|
||||
}
|
||||
m_compostionMode = compositionMode;
|
||||
}
|
||||
|
||||
void Painter::saveAndResetState()
|
||||
{
|
||||
m_oldCustomProgram = m_customProgram;
|
||||
m_oldProjectionMatrix = m_projectionMatrix;
|
||||
m_oldColor = m_color;
|
||||
m_oldOpacity = m_opacity;
|
||||
m_oldCompostionMode = m_compostionMode;
|
||||
|
||||
releaseCustomProgram();
|
||||
setColor(Fw::white);
|
||||
setOpacity(1);
|
||||
setCompositionMode(CompositionMode_Normal);
|
||||
}
|
||||
|
||||
void Painter::restoreSavedState()
|
||||
{
|
||||
setCustomProgram(m_oldCustomProgram);
|
||||
setColor(m_oldColor);
|
||||
setOpacity(m_oldOpacity);
|
||||
setCompositionMode(m_oldCompostionMode);
|
||||
|
||||
m_oldCustomProgram = nullptr;
|
||||
m_oldColor = Fw::white;
|
||||
m_oldOpacity = 1;
|
||||
m_oldCompostionMode = CompositionMode_Normal;
|
||||
}
|
||||
|
|
|
@ -50,11 +50,11 @@ public:
|
|||
void drawFilledRect(const Rect& dest);
|
||||
void drawBoundingRect(const Rect& dest, int innerLineWidth = 1);
|
||||
|
||||
void setColor(const Color& color) { m_currentColor = color; }
|
||||
Color getColor() { return m_currentColor; }
|
||||
void setColor(const Color& color) { m_color = color; }
|
||||
Color getColor() { return m_color; }
|
||||
|
||||
void setOpacity(float opacity) { m_currentOpacity = opacity; }
|
||||
float getOpacity() { return m_currentOpacity; }
|
||||
void setOpacity(float opacity) { m_opacity = opacity; }
|
||||
float getOpacity() { return m_opacity; }
|
||||
|
||||
void setCustomProgram(PainterShaderProgramPtr program);
|
||||
void releaseCustomProgram() { m_customProgram = nullptr; }
|
||||
|
@ -64,14 +64,24 @@ public:
|
|||
void setProjectionMatrix(const Matrix3& projectionMatrix) { m_projectionMatrix = projectionMatrix; }
|
||||
Matrix3 getProjectionMatrix() { return m_projectionMatrix; }
|
||||
|
||||
void saveAndResetState();
|
||||
void restoreSavedState();
|
||||
|
||||
private:
|
||||
PainterShaderProgramPtr m_drawTexturedProgram;
|
||||
PainterShaderProgramPtr m_drawSolidColorProgram;
|
||||
PainterShaderProgramPtr m_customProgram;
|
||||
Matrix3 m_projectionMatrix;
|
||||
Color m_currentColor;
|
||||
float m_currentOpacity;
|
||||
Color m_color;
|
||||
float m_opacity;
|
||||
CompositionMode m_compostionMode;
|
||||
CoordsBuffer m_coordsBuffer;
|
||||
|
||||
PainterShaderProgramPtr m_oldCustomProgram;
|
||||
Matrix3 m_oldProjectionMatrix;
|
||||
Color m_oldColor;
|
||||
float m_oldOpacity;
|
||||
CompositionMode m_oldCompostionMode;
|
||||
};
|
||||
|
||||
extern Painter g_painter;
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
#include "texturemanager.h"
|
||||
#include <framework/core/clock.h>
|
||||
|
||||
PainterShaderProgram::PainterShaderProgram()
|
||||
{
|
||||
m_textures.fill(std::make_tuple(-1, 0));
|
||||
}
|
||||
|
||||
bool PainterShaderProgram::link()
|
||||
{
|
||||
bindAttributeLocation(VERTEX_COORDS_ATTR, "vertexCoord");
|
||||
|
@ -63,12 +68,9 @@ void PainterShaderProgram::setOpacity(float opacity)
|
|||
|
||||
void PainterShaderProgram::setUniformTexture(int location, const TexturePtr& texture, int index)
|
||||
{
|
||||
if(index > 0)
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
glBindTexture(GL_TEXTURE_2D, texture ? texture->getId() : 0);
|
||||
if(index > 0)
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
setUniformValue(location, index);
|
||||
assert(index >= 0 && index <= 1);
|
||||
|
||||
m_textures[index] = std::make_tuple(location, texture ? texture->getId() : 0);
|
||||
}
|
||||
|
||||
void PainterShaderProgram::setTexture(const TexturePtr& texture)
|
||||
|
@ -112,6 +114,18 @@ void PainterShaderProgram::draw(const CoordsBuffer& coordsBuffer, DrawMode drawM
|
|||
mustDisableTexCoordsArray = true;
|
||||
}
|
||||
|
||||
for(int i=0;i<(int)m_textures.size();++i) {
|
||||
int location = std::get<0>(m_textures[i]);
|
||||
if(location == -1)
|
||||
break;
|
||||
int id = std::get<1>(m_textures[i]);
|
||||
setUniformValue(location, i);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+i);
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glDrawArrays(drawMode, 0, numVertices);
|
||||
|
||||
if(mustDisableVertexArray)
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
TriangleStrip = GL_TRIANGLE_STRIP
|
||||
};
|
||||
|
||||
PainterShaderProgram();
|
||||
|
||||
bool link();
|
||||
|
||||
void setProjectionMatrix(const Matrix3& projectionMatrix);
|
||||
|
@ -57,6 +59,7 @@ public:
|
|||
private:
|
||||
DrawMode m_drawMode;
|
||||
Timer m_startTimer;
|
||||
std::array<std::tuple<int, int>, 4> m_textures;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<Color> m_colors;
|
||||
std::vector<float> m_colorsStops;
|
||||
TexturePtr m_texture;
|
||||
PointF m_pos;
|
||||
PointF m_position;
|
||||
PointF m_velocity;
|
||||
PointF m_acceleration;
|
||||
Size m_size, m_startSize, m_finalSize;
|
||||
|
|
|
@ -115,7 +115,7 @@ bool AttractionAffector::load(const OTMLNodePtr& node)
|
|||
|
||||
for(const OTMLNodePtr& childNode : node->children()) {
|
||||
if(childNode->tag() == "position")
|
||||
m_pos = childNode->value<Point>();
|
||||
m_position = childNode->value<Point>();
|
||||
else if(childNode->tag() == "acceleration")
|
||||
m_acceleration = childNode->value<float>();
|
||||
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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<Point>();
|
||||
m_position = childNode->value<Point>();
|
||||
else if(childNode->tag() == "duration")
|
||||
m_duration = childNode->value<float>();
|
||||
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) {
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -89,39 +89,127 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
// nearest filtering (non smooth)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
setupFilters();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void Texture::generateMipmaps()
|
||||
{
|
||||
bind();
|
||||
|
||||
if(!m_useMipmaps) {
|
||||
m_useMipmaps = true;
|
||||
setupFilters();
|
||||
}
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void Texture::setSmooth(bool smooth)
|
||||
{
|
||||
if(smooth == m_smooth)
|
||||
return;
|
||||
|
||||
if(smooth) {
|
||||
// enable smooth texture
|
||||
glBindTexture(GL_TEXTURE_2D, m_textureId);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
} else {
|
||||
// nearest filtering (non smooth)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
m_smooth = true;
|
||||
m_smooth = smooth;
|
||||
bind();
|
||||
setupFilters();
|
||||
}
|
||||
|
||||
std::vector<uint8> Texture::getPixels()
|
||||
{
|
||||
// hack to copy pixels from opengl memory
|
||||
FrameBufferPtr fb(new FrameBuffer(m_size));
|
||||
std::vector<uint8> pixels(m_size.area()*4, 0);
|
||||
#ifdef OPENGL_ES
|
||||
// hack to copy pixels from opengl memory in opengl es
|
||||
// NOTE: this can be slow, but its the only way to get pixels from a texture in OpenGL ES
|
||||
FrameBufferPtr fb(new FrameBuffer(m_size));
|
||||
fb->bind();
|
||||
g_painter.saveAndResetState();
|
||||
g_painter.drawTexturedRect(Rect(0,0,m_size), shared_from_this());
|
||||
glReadPixels(0, 0, m_size.width(), m_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
|
||||
g_painter.restoreSavedState();
|
||||
fb->release();
|
||||
#else
|
||||
// copy pixels from opengl memory
|
||||
glBindTexture(GL_TEXTURE_2D, m_textureId);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
|
||||
#endif
|
||||
return pixels;
|
||||
}
|
||||
|
||||
void Texture::generateBilinearMipmaps(std::vector<uint8> inPixels)
|
||||
{
|
||||
bind();
|
||||
|
||||
if(!m_useMipmaps) {
|
||||
m_useMipmaps = true;
|
||||
setupFilters();
|
||||
}
|
||||
|
||||
Size inSize = getSize();
|
||||
Size outSize = inSize / 2;
|
||||
std::vector<uint8> outPixels(outSize.area()*4);
|
||||
|
||||
int mipmap = 1;
|
||||
while(true) {
|
||||
for(int x=0;x<outSize.width();++x) {
|
||||
for(int y=0;y<outSize.height();++y) {
|
||||
uint8 *inPixel[4];
|
||||
inPixel[0] = &inPixels[((y*2)*inSize.width() + (x*2))*4];
|
||||
inPixel[1] = &inPixels[((y*2)*inSize.width() + (x*2)+1)*4];
|
||||
inPixel[2] = &inPixels[((y*2+1)*inSize.width() + (x*2))*4];
|
||||
inPixel[3] = &inPixels[((y*2+1)*inSize.width() + (x*2)+1)*4];
|
||||
uint8 *outPixel = &outPixels[(y*outSize.width() + x)*4];
|
||||
|
||||
int pixelsSum[4];
|
||||
for(int i=0;i<4;++i)
|
||||
pixelsSum[i] = 0;
|
||||
|
||||
int usedPixels = 0;
|
||||
for(int j=0;j<4;++j) {
|
||||
// ignore colors of complete alpha pixels
|
||||
if(inPixel[j][3] < 16)
|
||||
continue;
|
||||
|
||||
for(int i=0;i<4;++i)
|
||||
pixelsSum[i] += inPixel[j][i];
|
||||
|
||||
usedPixels++;
|
||||
}
|
||||
|
||||
for(int i=0;i<4;++i) {
|
||||
if(usedPixels > 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 = std::move(outPixels);
|
||||
inSize /= 2;
|
||||
outSize /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::setupFilters()
|
||||
{
|
||||
GLint minFilter;
|
||||
GLint magFilter;
|
||||
if(m_smooth) {
|
||||
minFilter = m_useMipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
|
||||
magFilter = GL_LINEAR;
|
||||
} else {
|
||||
minFilter = m_useMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
|
||||
magFilter = GL_NEAREST;
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,14 @@ public:
|
|||
Texture(int width, int height, int channels, uchar* pixels = NULL);
|
||||
virtual ~Texture();
|
||||
|
||||
virtual void setSmooth(bool smooth);
|
||||
void bind() { glBindTexture(GL_TEXTURE_2D, m_textureId); }
|
||||
|
||||
void generateMipmaps();
|
||||
|
||||
// generate bilinear mipmaps optimized for alpha textures
|
||||
void generateBilinearMipmaps(std::vector<uint8> inPixels);
|
||||
|
||||
void setSmooth(bool smooth);
|
||||
GLuint getId() { return m_textureId; }
|
||||
|
||||
std::vector<uint8> getPixels();
|
||||
|
@ -44,10 +51,12 @@ public:
|
|||
bool isEmpty() const { return m_textureId == 0; }
|
||||
|
||||
protected:
|
||||
void setupFilters();
|
||||
GLuint internalLoadGLTexture(uchar* pixels, int channels, int w, int h);
|
||||
|
||||
GLuint m_textureId;
|
||||
Size m_size;
|
||||
Boolean<false> m_useMipmaps;
|
||||
Boolean<false> m_smooth;
|
||||
};
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<UIWidget>("setWidth", &UIWidget::setWidth);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setHeight", &UIWidget::setHeight);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setSize", &UIWidget::setSize);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setPos", &UIWidget::setPos);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setPosition", &UIWidget::setPosition);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setColor", &UIWidget::setColor);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setBackgroundColor", &UIWidget::setBackgroundColor);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("setBackgroundOffsetX", &UIWidget::setBackgroundOffsetX);
|
||||
|
@ -192,7 +192,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<UIWidget>("setOpacity", &UIWidget::setOpacity);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getX", &UIWidget::getX);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getY", &UIWidget::getY);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getPos", &UIWidget::getPos);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getPosition", &UIWidget::getPosition);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getWidth", &UIWidget::getWidth);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getHeight", &UIWidget::getHeight);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getSize", &UIWidget::getSize);
|
||||
|
@ -381,6 +381,9 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction("g_configs", "getList", std::bind(&ConfigManager::getList, &g_configs, _1));
|
||||
g_lua.bindClassStaticFunction("g_configs", "exists", std::bind(&ConfigManager::exists, &g_configs, _1));
|
||||
g_lua.bindClassStaticFunction("g_configs", "remove", std::bind(&ConfigManager::remove, &g_configs, _1));
|
||||
g_lua.bindClassStaticFunction("g_configs", "setNode", std::bind(&ConfigManager::setNode, &g_configs, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_configs", "addNode", std::bind(&ConfigManager::addNode, &g_configs, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_configs", "getNode", std::bind(&ConfigManager::getNode, &g_configs, _1));
|
||||
|
||||
// PlatformWindow
|
||||
g_lua.registerStaticClass("g_window");
|
||||
|
@ -409,7 +412,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));
|
||||
|
|
|
@ -48,7 +48,8 @@ void LuaInterface::init()
|
|||
|
||||
// register LuaObject, the base of all other objects
|
||||
registerClass<LuaObject>();
|
||||
bindClassMemberGetField<LuaObject>("use_count", &LuaObject::getUseCount);
|
||||
bindClassMemberFunction<LuaObject>("getUseCount", &LuaObject::getUseCount);
|
||||
bindClassMemberFunction<LuaObject>("getClassName", &LuaObject::getClassName);
|
||||
}
|
||||
|
||||
void LuaInterface::terminate()
|
||||
|
@ -958,7 +959,7 @@ void LuaInterface::pushObject(const LuaObjectPtr& obj)
|
|||
new(newUserdata(sizeof(LuaObjectPtr))) LuaObjectPtr(obj);
|
||||
|
||||
// set the userdata metatable
|
||||
getGlobal(Fw::mkstr(obj->getLuaObjectName(), "_mt"));
|
||||
getGlobal(Fw::mkstr(obj->getClassName(), "_mt"));
|
||||
assert(!isNil());
|
||||
setMetatable();
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ public:
|
|||
/// @note each userdata of this object on lua counts as a reference
|
||||
int getUseCount();
|
||||
|
||||
/// Returns the class name used in Lua
|
||||
virtual std::string getLuaObjectName() const {
|
||||
/// Returns the derived class name, its the same name used in Lua
|
||||
virtual std::string getClassName() const {
|
||||
// TODO: this could be cached for more performance
|
||||
return Fw::demangleName(typeid(*this).name());
|
||||
}
|
||||
|
|
|
@ -215,7 +215,11 @@ bool luavalue_cast(int index, Size& size)
|
|||
void push_otml_subnode_luavalue(const OTMLNodePtr& node)
|
||||
{
|
||||
if(node->hasValue()) {
|
||||
g_lua.pushString(node->value());
|
||||
// convert boolean types
|
||||
if(node->value() == "true" || node->value() == "false")
|
||||
g_lua.pushBoolean(node->value<bool>());
|
||||
else
|
||||
g_lua.pushString(node->value());
|
||||
} else if(node->hasChildren()) {
|
||||
g_lua.newTable();
|
||||
bool pushedChild = false;
|
||||
|
@ -225,6 +229,7 @@ void push_otml_subnode_luavalue(const OTMLNodePtr& node)
|
|||
if(!g_lua.isNil()) {
|
||||
if(cnode->isUnique()) {
|
||||
g_lua.pushString(cnode->tag());
|
||||
g_lua.insert(-2);
|
||||
g_lua.rawSet();
|
||||
} else
|
||||
g_lua.rawSeti(currentIndex++);
|
||||
|
@ -242,16 +247,18 @@ void push_otml_subnode_luavalue(const OTMLNodePtr& node)
|
|||
|
||||
void push_luavalue(const OTMLNodePtr& node)
|
||||
{
|
||||
g_lua.newTable();
|
||||
for(const OTMLNodePtr& cnode : node->children()) {
|
||||
if(cnode->isUnique()) {
|
||||
if(node) {
|
||||
g_lua.newTable();
|
||||
int currentIndex = 1;
|
||||
for(const OTMLNodePtr& cnode : node->children()) {
|
||||
push_otml_subnode_luavalue(cnode);
|
||||
if(!g_lua.isNil()) {
|
||||
if(cnode->isUnique()) {
|
||||
g_lua.setField(cnode->tag());
|
||||
} else
|
||||
g_lua.pop();
|
||||
g_lua.rawSeti(currentIndex++);
|
||||
}
|
||||
}
|
||||
} else
|
||||
g_lua.pushNil();
|
||||
}
|
||||
|
||||
bool luavalue_cast(int index, OTMLNodePtr& node)
|
||||
|
@ -261,15 +268,29 @@ bool luavalue_cast(int index, OTMLNodePtr& node)
|
|||
if(g_lua.isTable(index)) {
|
||||
g_lua.pushNil();
|
||||
while(g_lua.next(index < 0 ? index-1 : index)) {
|
||||
std::string cnodeName = g_lua.toString(-2);
|
||||
std::string cnodeName;
|
||||
if(!g_lua.isNumber(-2))
|
||||
cnodeName = g_lua.toString(-2);
|
||||
if(g_lua.isTable()) {
|
||||
OTMLNodePtr cnode;
|
||||
if(luavalue_cast(-1, node)) {
|
||||
cnode->setTag(cnodeName);
|
||||
if(luavalue_cast(-1, cnode)) {
|
||||
if(cnodeName.empty())
|
||||
node->setUnique(false);
|
||||
else
|
||||
cnode->setTag(cnodeName);
|
||||
node->addChild(cnode);
|
||||
}
|
||||
} else
|
||||
node->writeAt(cnodeName, g_lua.toString());
|
||||
} else {
|
||||
std::string value;
|
||||
if(g_lua.isBoolean())
|
||||
value = Fw::unsafeCast<std::string>(g_lua.toBoolean());
|
||||
else
|
||||
value = g_lua.toString();
|
||||
if(cnodeName.empty())
|
||||
node->writeIn(value);
|
||||
else
|
||||
node->writeAt(cnodeName, value);
|
||||
}
|
||||
g_lua.pop();
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -56,10 +56,10 @@ public:
|
|||
TPoint<T>& operator+=(T other) { x+=other; y+=other; return *this; }
|
||||
TPoint<T> operator-(T other) const { return TPoint<T>(x - other, y - other); }
|
||||
TPoint<T>& operator-=(T other) { x-=other; y-=other; return *this; }
|
||||
TPoint<T> operator*(const T v) const { return TPoint<T>(x*v, y*v); }
|
||||
TPoint<T>& operator*=(const T v) { x*=v; y*=v; return *this; }
|
||||
TPoint<T> operator/(const T v) const { return TPoint<T>(x/v, y/v); }
|
||||
TPoint<T>& operator/=(const T v) { x/=v; y/=v; return *this; }
|
||||
TPoint<T> operator*(float v) const { return TPoint<T>(x*v, y*v); }
|
||||
TPoint<T>& operator*=(float v) { x*=v; y*=v; return *this; }
|
||||
TPoint<T> operator/(float v) const { return TPoint<T>(x/v, y/v); }
|
||||
TPoint<T>& operator/=(float v) { x/=v; y/=v; return *this; }
|
||||
|
||||
bool operator<=(const TPoint<T>&other) const { return x<=other.x && y<=other.y; }
|
||||
bool operator>=(const TPoint<T>&other) const { return x>=other.x && y>=other.y; }
|
||||
|
|
|
@ -52,15 +52,19 @@ public:
|
|||
TSize<T>& operator+=(const TSize<T>& other) { wd+=other.wd; ht+=other.ht; return *this; }
|
||||
TSize<T> operator-(const TSize<T>& other) const { return TSize<T>(wd - other.wd, ht - other.ht); }
|
||||
TSize<T>& operator-=(const TSize<T>& other) { wd-=other.wd; ht-=other.ht; return *this; }
|
||||
TSize<T> operator*(const TSize<T>& other) const { return TSize<T>((T)other.wd*wd, (T)ht*other.ht); }
|
||||
TSize<T>& operator*=(const TSize<T>& other) { wd=(T)other.wd*wd; ht=(T)ht*other.ht; return *this; }
|
||||
TSize<T> operator/(const TSize<T>& other) const { return TSize<T>((T)wd/other.wd, (T)ht/other.ht); }
|
||||
TSize<T>& operator/=(const TSize<T>& other) { (T)wd/=other.wd; (T)ht/=other.ht; return *this; }
|
||||
TSize<T> operator*(const float v) const { return TSize<T>((T)v*wd, (T)ht*v); }
|
||||
TSize<T>& operator*=(const float v) { wd=(T)v*wd; ht=(T)ht*v; return *this; }
|
||||
TSize<T> operator/(const float v) const { return TSize<T>((T)wd/v, (T)ht/v); }
|
||||
TSize<T>& operator/=(const float v) { (T)wd/=v; (T)ht/=v; return *this; }
|
||||
TSize<T>& operator/=(const float v) { wd/=v; ht/=v; return *this; }
|
||||
|
||||
bool operator<=(const TSize<T>&other) const { return wd<=other.wd || ht<=other.ht; }
|
||||
bool operator>=(const TSize<T>&other) const { return wd>=other.wd || ht>=other.ht; }
|
||||
bool operator<(const TSize<T>&other) const { return wd<other.wd || ht<other.ht; }
|
||||
bool operator>(const TSize<T>&other) const { return wd>other.wd || ht>other.ht; }
|
||||
bool operator<=(const TSize<T>&other) const { return wd<=other.wd && ht<=other.ht; }
|
||||
bool operator>=(const TSize<T>&other) const { return wd>=other.wd && ht>=other.ht; }
|
||||
bool operator<(const TSize<T>&other) const { return wd<other.wd && ht<other.ht; }
|
||||
bool operator>(const TSize<T>&other) const { return wd>other.wd && ht>other.ht; }
|
||||
|
||||
TSize<T>& operator=(const TSize<T>& other) { wd = other.wd; ht = other.ht; return *this; }
|
||||
bool operator==(const TSize<T>& other) const { return other.wd==wd && other.ht==ht; }
|
||||
|
|
|
@ -35,6 +35,7 @@ Connection::Connection() :
|
|||
{
|
||||
m_connected = false;
|
||||
m_connecting = false;
|
||||
m_sendBufferSize = 0;
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
|
@ -57,6 +58,7 @@ void Connection::connect(const std::string& host, uint16 port, const SimpleCallb
|
|||
{
|
||||
m_connected = false;
|
||||
m_connecting = true;
|
||||
m_error.clear();
|
||||
m_connectCallback = connectCallback;
|
||||
|
||||
asio::ip::tcp::resolver::query query(host, Fw::unsafeCast<std::string>(port));
|
||||
|
@ -85,6 +87,10 @@ void Connection::close()
|
|||
if(!m_connected && !m_connecting)
|
||||
return;
|
||||
|
||||
// flush send data before disconnecting on clean connections
|
||||
if(m_connected && !m_error && m_sendBufferSize > 0 && m_sendEvent)
|
||||
m_sendEvent->execute();
|
||||
|
||||
m_connecting = false;
|
||||
m_connected = false;
|
||||
m_connectCallback = nullptr;
|
||||
|
@ -104,17 +110,34 @@ void Connection::close()
|
|||
|
||||
void Connection::write(uint8* buffer, uint16 size)
|
||||
{
|
||||
m_writeTimer.cancel();
|
||||
|
||||
if(!m_connected)
|
||||
return;
|
||||
|
||||
asio::async_write(m_socket,
|
||||
asio::buffer(buffer, size),
|
||||
std::bind(&Connection::onWrite, shared_from_this(), _1, _2));
|
||||
// send old buffer if we can't add more data
|
||||
if(m_sendBufferSize + size >= SEND_BUFFER_SIZE && m_sendEvent)
|
||||
m_sendEvent->execute();
|
||||
|
||||
m_writeTimer.expires_from_now(boost::posix_time::seconds(WRITE_TIMEOUT));
|
||||
m_writeTimer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), _1));
|
||||
// we can't send the data right away, otherwise we could create tcp congestion
|
||||
memcpy(m_sendBuffer + m_sendBufferSize, buffer, size);
|
||||
m_sendBufferSize += size;
|
||||
|
||||
if(!m_sendEvent || m_sendEvent->isExecuted() || m_sendEvent->isCanceled()) {
|
||||
auto weakSelf = ConnectionWeakPtr(shared_from_this());
|
||||
m_sendEvent = g_dispatcher.scheduleEvent([=] {
|
||||
if(!weakSelf.lock())
|
||||
return;
|
||||
//m_writeTimer.cancel();
|
||||
|
||||
asio::async_write(m_socket,
|
||||
asio::buffer(m_sendBuffer, m_sendBufferSize),
|
||||
std::bind(&Connection::onWrite, shared_from_this(), _1, _2));
|
||||
|
||||
m_writeTimer.expires_from_now(boost::posix_time::seconds(WRITE_TIMEOUT));
|
||||
m_writeTimer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), _1));
|
||||
|
||||
m_sendBufferSize = 0;
|
||||
}, SEND_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::read(uint16 bytes, const RecvCallback& callback)
|
||||
|
@ -157,7 +180,7 @@ void Connection::onConnect(const boost::system::error_code& error)
|
|||
if(!error) {
|
||||
m_connected = true;
|
||||
|
||||
// disable nagle's algorithm
|
||||
// disable nagle's algorithm, this make the game play smoother
|
||||
boost::asio::ip::tcp::no_delay option(true);
|
||||
m_socket.set_option(option);
|
||||
|
||||
|
@ -203,6 +226,7 @@ void Connection::onTimeout(const boost::system::error_code& error)
|
|||
void Connection::handleError(const boost::system::error_code& error)
|
||||
{
|
||||
if(error != asio::error::operation_aborted) {
|
||||
m_error = error;
|
||||
if(m_errorCallback)
|
||||
m_errorCallback(error);
|
||||
if(m_connected || m_connecting)
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "declarations.h"
|
||||
#include <boost/asio.hpp>
|
||||
#include <framework/core/timer.h>
|
||||
#include <framework/core/declarations.h>
|
||||
|
||||
class Connection : public std::enable_shared_from_this<Connection>, boost::noncopyable
|
||||
{
|
||||
|
@ -34,6 +36,8 @@ class Connection : public std::enable_shared_from_this<Connection>, boost::nonco
|
|||
enum {
|
||||
READ_TIMEOUT = 30,
|
||||
WRITE_TIMEOUT = 30,
|
||||
SEND_INTERVAL = 10,
|
||||
SEND_BUFFER_SIZE = 65536,
|
||||
RECV_BUFFER_SIZE = 65536
|
||||
};
|
||||
|
||||
|
@ -53,6 +57,7 @@ public:
|
|||
|
||||
void setErrorCallback(const ErrorCallback& errorCallback) { m_errorCallback = errorCallback; }
|
||||
|
||||
boost::system::error_code getError() const { return m_error; }
|
||||
bool isConnecting() const { return m_connecting; }
|
||||
bool isConnected() const { return m_connected; }
|
||||
|
||||
|
@ -72,9 +77,14 @@ protected:
|
|||
asio::ip::tcp::resolver m_resolver;
|
||||
asio::ip::tcp::socket m_socket;
|
||||
|
||||
uint8 m_sendBuffer[SEND_BUFFER_SIZE];
|
||||
uint8 m_recvBuffer[RECV_BUFFER_SIZE];
|
||||
bool m_connected;
|
||||
bool m_connecting;
|
||||
boost::system::error_code m_error;
|
||||
int m_sendBufferSize;
|
||||
Timer m_sendTimer;
|
||||
ScheduledEventPtr m_sendEvent;
|
||||
|
||||
friend class Server;
|
||||
};
|
||||
|
|
|
@ -147,6 +147,7 @@ void OTMLNode::write(const T& v) {
|
|||
template<typename T>
|
||||
void OTMLNode::writeAt(const std::string& childTag, const T& v) {
|
||||
OTMLNodePtr child = OTMLNode::create(childTag);
|
||||
child->setUnique(true);
|
||||
child->write<T>(v);
|
||||
addChild(child);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -55,7 +55,7 @@ void UIWidget::parseBaseStyle(const OTMLNodePtr& styleNode)
|
|||
else if(node->tag() == "y")
|
||||
setY(node->value<int>());
|
||||
else if(node->tag() == "pos")
|
||||
setPos(node->value<Point>());
|
||||
setPosition(node->value<Point>());
|
||||
else if(node->tag() == "width")
|
||||
setWidth(node->value<int>());
|
||||
else if(node->tag() == "height")
|
||||
|
|
|
@ -31,5 +31,3 @@ int main(int argc, const char* argv[])
|
|||
app.terminate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// for freenode: fk39HHDJJF
|
|
@ -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
|
||||
|
|
|
@ -31,6 +31,51 @@ namespace Otc
|
|||
static const char* AppCompactName = "otclient";
|
||||
static const char* AppVersion = "0.4.0";
|
||||
|
||||
enum {
|
||||
TILE_PIXELS = 32,
|
||||
MAX_ELEVATION = 24,
|
||||
|
||||
SEA_FLOOR = 7,
|
||||
MAX_Z = 15,
|
||||
UNDERGROUND_FLOOR = SEA_FLOOR+1,
|
||||
VISIBLE_X_TILES = 15,
|
||||
VISIBLE_Y_TILES = 11,
|
||||
AWARE_UNDEGROUND_FLOOR_RANGE = 2,
|
||||
AWARE_X_TILES = VISIBLE_X_TILES + 3,
|
||||
AWARE_Y_TILES = VISIBLE_Y_TILES + 3,
|
||||
AWARE_X_LEFT_TILES = AWARE_X_TILES/2 - 1,
|
||||
AWARE_X_RIGHT_TILES = AWARE_X_TILES/2,
|
||||
AWARE_Y_TOP_TILES = AWARE_Y_TILES/2 - 1,
|
||||
AWARE_Y_BOTTOM_TILES = AWARE_Y_TILES/2,
|
||||
|
||||
EFFECT_TICKS_PER_FRAME = 75,
|
||||
INVISIBLE_TICKS_PER_FRAME = 500,
|
||||
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 DrawFlags {
|
||||
DrawGround = 1,
|
||||
DrawGroundBorders = 2,
|
||||
DrawOnBottom = 4,
|
||||
DrawOnTop = 8,
|
||||
DrawItems = 16,
|
||||
DrawCreatures = 32,
|
||||
DrawEffects = 64,
|
||||
DrawMissiles = 128,
|
||||
DrawCreaturesInformation = 256,
|
||||
DrawStaticTexts = 512,
|
||||
DrawAnimatedTexts = 1024,
|
||||
DrawAnimations = 2048,
|
||||
DrawWalls = DrawOnBottom | DrawOnTop,
|
||||
DrawEverything = DrawGround | DrawGroundBorders | DrawWalls | DrawItems |
|
||||
DrawCreatures | DrawEffects | DrawMissiles |
|
||||
DrawCreaturesInformation | DrawStaticTexts | DrawAnimatedTexts | DrawAnimations
|
||||
};
|
||||
|
||||
enum DatOpts {
|
||||
DatGround = 0,
|
||||
DatGroundClip,
|
||||
|
@ -219,6 +264,23 @@ namespace Otc
|
|||
IconPzBlock = 8192,
|
||||
IconPz = 16384
|
||||
};
|
||||
|
||||
enum SpeakType {
|
||||
SpeakSay = 1,
|
||||
SpeakWhisper,
|
||||
SpeakYell,
|
||||
SpeakBroadcast,
|
||||
SpeakPrivate,
|
||||
SpeakPrivateRed,
|
||||
SpeakPrivatePlayerToNpc,
|
||||
SpeakPrivateNpcToPlayer,
|
||||
SpeakChannelYellow,
|
||||
SpeakChannelWhite,
|
||||
SpeakChannelRed,
|
||||
SpeakChannelOrange,
|
||||
SpeakMonsterSay,
|
||||
SpeakMonsterYell
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -25,18 +25,15 @@
|
|||
|
||||
#include "thing.h"
|
||||
#include <framework/graphics/fontmanager.h>
|
||||
#include <framework/core/timer.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -44,6 +44,7 @@ Creature::Creature() : Thing()
|
|||
m_showVolatileSquare = false;
|
||||
m_showStaticSquare = false;
|
||||
m_direction = Otc::South;
|
||||
m_walkAnimationPhase = 0;
|
||||
m_walking = false;
|
||||
m_walkInterval = 0;
|
||||
m_walkAnimationInterval = 0;
|
||||
|
@ -63,16 +64,18 @@ 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, bool animate)
|
||||
{
|
||||
if(m_showVolatileSquare) {
|
||||
Point animationOffset = animate ? m_walkOffset : Point(0,0);
|
||||
|
||||
if(m_showVolatileSquare && animate) {
|
||||
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 + (animationOffset - getDisplacement() + 3)*scaleFactor, Size(28, 28)*scaleFactor), std::max((int)(2*scaleFactor), 1));
|
||||
}
|
||||
|
||||
if(m_showStaticSquare) {
|
||||
if(m_showStaticSquare && animate) {
|
||||
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 + (animationOffset - getDisplacement() + 1)*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor), std::max((int)(2*scaleFactor), 1));
|
||||
}
|
||||
|
||||
g_painter.setColor(Fw::white);
|
||||
|
@ -88,12 +91,29 @@ void Creature::draw(const Point& p, const Rect&)
|
|||
outfitProgram->bindUniformLocation(MASK_TEXTURE_UNIFORM, "maskTexture");
|
||||
}
|
||||
|
||||
// Render creature
|
||||
int xPattern = 0, yPattern = 0, zPattern = 0;
|
||||
|
||||
// outfit is a real creature
|
||||
if(m_outfit.getCategory() == ThingsType::Creature) {
|
||||
for(m_yPattern = 0; m_yPattern < m_type->dimensions[ThingType::PatternY]; m_yPattern++) {
|
||||
int animationPhase = animate ? m_walkAnimationPhase : 0;
|
||||
if(isAnimateAlways()) {
|
||||
int ticksPerFrame = 1000 / getAnimationPhases();
|
||||
animationPhase = (g_clock.ticks() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
|
||||
}
|
||||
|
||||
// xPattern => creature direction
|
||||
if(m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
|
||||
xPattern = Otc::East;
|
||||
else if(m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
|
||||
xPattern = Otc::West;
|
||||
else
|
||||
xPattern = m_direction;
|
||||
|
||||
// yPattern => creature addon
|
||||
for(yPattern = 0; yPattern < getNumPatternsY(); yPattern++) {
|
||||
|
||||
// continue if we dont have this addon.
|
||||
if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1))))
|
||||
if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
|
||||
continue;
|
||||
|
||||
g_painter.setCustomProgram(outfitProgram);
|
||||
|
@ -104,40 +124,51 @@ 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);
|
||||
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);
|
||||
TexturePtr maskTex = g_sprites.getSpriteTexture(maskId);
|
||||
outfitProgram->setUniformTexture(MASK_TEXTURE_UNIFORM, maskTex, 1);
|
||||
for(int h = 0; h < getDimensionHeight(); h++) {
|
||||
for(int w = 0; w < getDimensionWidth(); w++) {
|
||||
// setup texture outfit mask
|
||||
TexturePtr maskTex;
|
||||
if(getLayers() > 1) {
|
||||
int maskId = getSpriteId(w, h, 1, xPattern, yPattern, zPattern, m_walkAnimationPhase);
|
||||
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);
|
||||
g_painter.drawTexturedRect(drawRect, spriteTex);
|
||||
internalDraw(dest + (animationOffset - Point(w,h)*Otc::TILE_PIXELS)*scaleFactor,
|
||||
scaleFactor, w, h, xPattern, yPattern, zPattern, 0, animationPhase);
|
||||
}
|
||||
}
|
||||
|
||||
g_painter.releaseCustomProgram();
|
||||
}
|
||||
// outfit is a creature imitating an item or the invisible effect
|
||||
} else {
|
||||
int animationPhase = 0;
|
||||
int animationPhases = getAnimationPhases();
|
||||
int animateTicks = Otc::ITEM_TICKS_PER_FRAME;
|
||||
|
||||
// when creature is an effect we cant render the first and last animation phase,
|
||||
// instead we should loop in the phases between
|
||||
if(m_outfit.getCategory() == ThingsType::Effect) {
|
||||
animationPhases = std::max(1, animationPhases-2);
|
||||
animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
|
||||
}
|
||||
|
||||
if(animationPhases > 1) {
|
||||
if(animate)
|
||||
animationPhase = (g_clock.ticks() % (animateTicks * animationPhases)) / animateTicks;
|
||||
else
|
||||
animationPhase = animationPhases-1;
|
||||
}
|
||||
|
||||
if(m_outfit.getCategory() == ThingsType::Effect)
|
||||
animationPhase = std::min(animationPhase+1, getAnimationPhases());
|
||||
|
||||
internalDraw(dest + animationOffset*scaleFactor, scaleFactor, 0, 0, 0, animationPhase);
|
||||
}
|
||||
else if(m_outfit.getCategory() == ThingsType::Item) {
|
||||
for(int l = 0; l < m_type->dimensions[ThingType::Layers]; l++)
|
||||
internalDraw(p + m_walkOffset, l);
|
||||
}
|
||||
else if(m_outfit.getCategory() == ThingsType::Effect)
|
||||
internalDraw(p + m_walkOffset, 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 +176,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 +204,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 +240,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;
|
||||
|
||||
|
@ -236,7 +272,7 @@ void Creature::stopWalk()
|
|||
|
||||
// reset walk animation states
|
||||
m_walkOffset = Point(0,0);
|
||||
m_animation = 0;
|
||||
m_walkAnimationPhase = 0;
|
||||
|
||||
// stops the walk right away
|
||||
terminateWalk();
|
||||
|
@ -248,10 +284,10 @@ void Creature::updateWalkAnimation(int totalPixelsWalked)
|
|||
if(m_outfit.getCategory() != ThingsType::Creature)
|
||||
return;
|
||||
|
||||
if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || m_type->dimensions[ThingType::AnimationPhases] <= 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);
|
||||
if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || getAnimationPhases() <= 1)
|
||||
m_walkAnimationPhase = 0;
|
||||
else if(getAnimationPhases() > 1)
|
||||
m_walkAnimationPhase = 1 + ((totalPixelsWalked * 4) / Otc::TILE_PIXELS) % (getAnimationPhases() - 1);
|
||||
}
|
||||
|
||||
void Creature::updateWalkOffset(int totalPixelsWalked)
|
||||
|
@ -268,6 +304,36 @@ void Creature::updateWalkOffset(int totalPixelsWalked)
|
|||
m_walkOffset.x = 32 - totalPixelsWalked;
|
||||
}
|
||||
|
||||
void Creature::updateWalkingTile()
|
||||
{
|
||||
// determine new walking tile
|
||||
TilePtr newWalkingTile;
|
||||
Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
|
||||
Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
|
||||
Otc::TILE_PIXELS, Otc::TILE_PIXELS);
|
||||
for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
|
||||
for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
|
||||
Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);
|
||||
|
||||
// only render creatures where bottom right is inside tile rect
|
||||
if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
|
||||
const TilePtr& tile = g_map.getTile(m_position.translated(xi, yi, 0));
|
||||
if(!tile)
|
||||
continue;
|
||||
newWalkingTile = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(newWalkingTile != m_walkingTile) {
|
||||
if(m_walkingTile)
|
||||
m_walkingTile->removeWalkingCreature(asCreature());
|
||||
if(newWalkingTile)
|
||||
newWalkingTile->addWalkingCreature(asCreature());
|
||||
m_walkingTile = newWalkingTile;
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::nextWalkUpdate()
|
||||
{
|
||||
// remove any previous scheduled walk updates
|
||||
|
@ -295,6 +361,7 @@ void Creature::updateWalk()
|
|||
// update walk animation and offsets
|
||||
updateWalkAnimation(totalPixelsWalked);
|
||||
updateWalkOffset(totalPixelsWalked);
|
||||
updateWalkingTile();
|
||||
|
||||
// terminate walk
|
||||
if(m_walking && m_walkTimer.ticksElapsed() >= m_walkInterval)
|
||||
|
@ -315,6 +382,11 @@ void Creature::terminateWalk()
|
|||
m_walkTurnDirection = Otc::InvalidDirection;
|
||||
}
|
||||
|
||||
if(m_walkingTile) {
|
||||
m_walkingTile->removeWalkingCreature(asCreature());
|
||||
m_walkingTile = nullptr;
|
||||
}
|
||||
|
||||
m_walking = false;
|
||||
}
|
||||
|
||||
|
@ -358,40 +430,13 @@ void Creature::setHealthPercent(uint8 healthPercent)
|
|||
|
||||
void Creature::setDirection(Otc::Direction direction)
|
||||
{
|
||||
if(m_outfit.getCategory() == ThingsType::Creature) {
|
||||
if(direction == Otc::NorthEast || direction == Otc::SouthEast)
|
||||
m_xPattern = Otc::East;
|
||||
else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
|
||||
m_xPattern = Otc::West;
|
||||
else
|
||||
m_xPattern = direction;
|
||||
} else {
|
||||
m_xPattern = 0;
|
||||
}
|
||||
|
||||
m_direction = direction;
|
||||
}
|
||||
|
||||
void Creature::setOutfit(const Outfit& outfit)
|
||||
{
|
||||
m_outfit = outfit;
|
||||
m_type = getType();
|
||||
m_animation = 0;
|
||||
|
||||
if(m_outfit.getCategory() == ThingsType::Effect) {
|
||||
updateInvisibleAnimation();
|
||||
|
||||
m_xPattern = 0;
|
||||
m_yPattern = 0;
|
||||
}
|
||||
if(m_outfit.getCategory() == ThingsType::Item) {
|
||||
m_xPattern = 0;
|
||||
m_yPattern = 0;
|
||||
}
|
||||
|
||||
if(m_outfit.getCategory() == ThingsType::Creature && m_type->dimensions[ThingType::Layers] == 1) {
|
||||
m_outfit.resetClothes();
|
||||
}
|
||||
m_type = g_thingsType.getThingType(outfit.getId(), outfit.getCategory());
|
||||
}
|
||||
|
||||
void Creature::setSkull(uint8 skull)
|
||||
|
@ -449,26 +494,6 @@ void Creature::addVolatileSquare(uint8 color)
|
|||
}, VOLATILE_SQUARE_DURATION);
|
||||
}
|
||||
|
||||
void Creature::updateInvisibleAnimation()
|
||||
{
|
||||
if(!g_game.isOnline() || m_outfit.getCategory() != ThingsType::Effect)
|
||||
return;
|
||||
|
||||
if(m_animation == 1)
|
||||
m_animation = 2;
|
||||
else if(m_animation == 2)
|
||||
m_animation = 3;
|
||||
else if(m_animation == 3)
|
||||
m_animation = 1;
|
||||
else
|
||||
m_animation = 1;
|
||||
|
||||
auto self = asCreature();
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->updateInvisibleAnimation();
|
||||
}, INVISIBLE_TICKS);
|
||||
}
|
||||
|
||||
void Creature::updateShield()
|
||||
{
|
||||
m_showShieldTexture = !m_showShieldTexture;
|
||||
|
@ -483,8 +508,17 @@ void Creature::updateShield()
|
|||
m_showShieldTexture = true;
|
||||
}
|
||||
|
||||
ThingType *Creature::getType()
|
||||
Point Creature::getDrawOffset()
|
||||
{
|
||||
return g_thingsType.getThingType(m_outfit.getId(), m_outfit.getCategory());
|
||||
Point drawOffset;
|
||||
if(m_walking) {
|
||||
if(m_walkingTile)
|
||||
drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
|
||||
drawOffset += m_walkOffset;
|
||||
} else {
|
||||
const TilePtr& tile = getTile();
|
||||
if(tile)
|
||||
drawOffset -= Point(1,1) * tile->getDrawElevation();
|
||||
}
|
||||
return drawOffset;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,16 +34,16 @@ class Creature : public Thing
|
|||
public:
|
||||
enum {
|
||||
SHIELD_BLINK_TICKS = 500,
|
||||
INVISIBLE_TICKS = 500,
|
||||
VOLATILE_SQUARE_DURATION = 1000
|
||||
};
|
||||
|
||||
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, bool animate);
|
||||
void drawInformation(const Point& point, bool useGray, const Rect& parentRect);
|
||||
|
||||
void setId(uint32 id) { m_id = id; }
|
||||
void setName(const std::string& name);
|
||||
void setHealthPercent(uint8 healthPercent);
|
||||
void setDirection(Otc::Direction direction);
|
||||
|
@ -64,6 +64,7 @@ public:
|
|||
void showStaticSquare(const Color& color) { m_showStaticSquare = true; m_staticSquareColor = color; }
|
||||
void hideStaticSquare() { m_showStaticSquare = false; }
|
||||
|
||||
uint32 getId() { return m_id; }
|
||||
std::string getName() { return m_name; }
|
||||
uint8 getHealthPercent() { return m_healthPercent; }
|
||||
Otc::Direction getDirection() { return m_direction; }
|
||||
|
@ -74,17 +75,15 @@ public:
|
|||
uint8 getShield() { return m_shield; }
|
||||
uint8 getEmblem() { return m_emblem; }
|
||||
bool getPassable() { return m_passable; }
|
||||
Point getDrawOffset();
|
||||
Point getWalkOffset() { return m_walkOffset; }
|
||||
|
||||
void updateInvisibleAnimation();
|
||||
void updateShield();
|
||||
|
||||
ThingType *getType();
|
||||
|
||||
// walk related
|
||||
void turn(Otc::Direction direction);
|
||||
virtual void walk(const Position& oldPos, const Position& newPos);
|
||||
virtual void stopWalk();
|
||||
Point getWalkOffset() { return m_walkOffset; }
|
||||
|
||||
bool isWalking() { return m_walking; }
|
||||
|
||||
|
@ -93,10 +92,12 @@ public:
|
|||
protected:
|
||||
virtual void updateWalkAnimation(int totalPixelsWalked);
|
||||
virtual void updateWalkOffset(int totalPixelsWalked);
|
||||
void updateWalkingTile();
|
||||
virtual void nextWalkUpdate();
|
||||
virtual void updateWalk();
|
||||
virtual void terminateWalk();
|
||||
|
||||
uint32 m_id;
|
||||
std::string m_name;
|
||||
Size m_nameSize;
|
||||
uint8 m_healthPercent;
|
||||
|
@ -115,7 +116,9 @@ protected:
|
|||
Color m_informationColor;
|
||||
|
||||
// walk related
|
||||
int m_walkAnimationPhase;
|
||||
Timer m_walkTimer;
|
||||
TilePtr m_walkingTile;
|
||||
int m_walkInterval;
|
||||
int m_walkAnimationInterval;
|
||||
bool m_walking;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <otclient/global.h>
|
||||
|
||||
class Map;
|
||||
class MapView;
|
||||
class Tile;
|
||||
class Thing;
|
||||
class Item;
|
||||
|
@ -38,6 +40,7 @@ class Missile;
|
|||
class AnimatedText;
|
||||
class StaticText;
|
||||
|
||||
typedef std::shared_ptr<MapView> MapViewPtr;
|
||||
typedef std::shared_ptr<Tile> TilePtr;
|
||||
typedef std::shared_ptr<Thing> ThingPtr;
|
||||
typedef std::shared_ptr<Item> ItemPtr;
|
||||
|
|
|
@ -27,51 +27,28 @@
|
|||
#include <framework/core/clock.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
|
||||
Effect::Effect() : Thing()
|
||||
void Effect::draw(const Point& dest, float scaleFactor, bool animate)
|
||||
{
|
||||
m_animationStartTicks = 0;
|
||||
if(m_id == 0)
|
||||
return;
|
||||
|
||||
int animationPhase = 0;
|
||||
if(animate)
|
||||
animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME), getAnimationPhases() - 1);
|
||||
internalDraw(dest, scaleFactor, 0, 0, 0, animationPhase);
|
||||
}
|
||||
|
||||
void Effect::start()
|
||||
void Effect::startAnimation()
|
||||
{
|
||||
m_animationStartTicks = g_clock.ticks();
|
||||
|
||||
auto self = asEffect();
|
||||
|
||||
// schedule update
|
||||
if(getAnimationPhases() > 1) {
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->updateAnimation();
|
||||
}, TICKS_PER_FRAME);
|
||||
}
|
||||
m_animationTimer.restart();
|
||||
|
||||
// schedule removal
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
g_map.removeThing(self);
|
||||
}, TICKS_PER_FRAME * getAnimationPhases());
|
||||
auto self = asEffect();
|
||||
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, Otc::EFFECT_TICKS_PER_FRAME * getAnimationPhases());
|
||||
}
|
||||
|
||||
void Effect::draw(const Point& p, const Rect&)
|
||||
void Effect::setId(uint32 id)
|
||||
{
|
||||
internalDraw(p, 0);
|
||||
}
|
||||
|
||||
void Effect::updateAnimation()
|
||||
{
|
||||
int animationPhase = (g_clock.ticks() - m_animationStartTicks) / TICKS_PER_FRAME;
|
||||
|
||||
if(animationPhase < getAnimationPhases())
|
||||
m_animation = animationPhase;
|
||||
|
||||
if(animationPhase < getAnimationPhases() - 1) {
|
||||
auto self = asEffect();
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->updateAnimation();
|
||||
}, TICKS_PER_FRAME);
|
||||
}
|
||||
}
|
||||
|
||||
ThingType *Effect::getType()
|
||||
{
|
||||
return g_thingsType.getThingType(m_id, ThingsType::Effect);
|
||||
m_id = id;
|
||||
m_type = g_thingsType.getThingType(m_id, ThingsType::Effect);
|
||||
}
|
||||
|
|
|
@ -24,28 +24,23 @@
|
|||
#define EFFECT_H
|
||||
|
||||
#include <framework/global.h>
|
||||
#include <framework/core/timer.h>
|
||||
#include "thing.h"
|
||||
|
||||
class Effect : public Thing
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
TICKS_PER_FRAME = 75
|
||||
};
|
||||
void draw(const Point& dest, float scaleFactor, bool animate);
|
||||
|
||||
Effect();
|
||||
|
||||
void draw(const Point& p, const Rect&);
|
||||
|
||||
void start();
|
||||
void updateAnimation();
|
||||
|
||||
ThingType *getType();
|
||||
void setId(uint32 id);
|
||||
void startAnimation();
|
||||
|
||||
uint32 getId() { return m_id; }
|
||||
EffectPtr asEffect() { return std::static_pointer_cast<Effect>(shared_from_this()); }
|
||||
|
||||
private:
|
||||
ticks_t m_animationStartTicks;
|
||||
Timer m_animationTimer;
|
||||
uint16 m_id;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -94,7 +94,7 @@ void Game::processLogout()
|
|||
m_protocolGame = nullptr;
|
||||
}
|
||||
|
||||
g_map.clean();
|
||||
g_map.save();
|
||||
}
|
||||
|
||||
void Game::processDeath()
|
||||
|
@ -172,9 +172,9 @@ void Game::processTextMessage(const std::string& type, const std::string& messag
|
|||
g_lua.callGlobalField("Game","onTextMessage", type, message);
|
||||
}
|
||||
|
||||
void Game::processCreatureSpeak(const std::string& name, int level, const std::string& type, const std::string& message, int channelId, const Position& creaturePos)
|
||||
void Game::processCreatureSpeak(const std::string& name, int level, Otc::SpeakType type, const std::string& message, int channelId, const Position& creaturePos)
|
||||
{
|
||||
if(creaturePos.isValid() && (type == "say" || type == "whisper" || type == "yell" || type == "monsterSay" || type == "monsterYell")) {
|
||||
if(creaturePos.isValid() && (type == Otc::SpeakSay || type == Otc::SpeakWhisper || type == Otc::SpeakYell || type == Otc::SpeakMonsterSay || type == Otc::SpeakMonsterYell)) {
|
||||
StaticTextPtr staticText = StaticTextPtr(new StaticText);
|
||||
staticText->addMessage(name, type, message);
|
||||
g_map.addThing(staticText, creaturePos);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ void Game::processInventoryChange(int slot, const ItemPtr& item)
|
|||
void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos)
|
||||
{
|
||||
// animate walk
|
||||
if(oldPos.isInRange(newPos, 1, 1, 0))
|
||||
if(oldPos.isInRange(newPos, 1, 1))
|
||||
creature->walk(oldPos, newPos);
|
||||
}
|
||||
|
||||
|
@ -237,16 +237,8 @@ void Game::walk(Otc::Direction direction)
|
|||
if(!m_localPlayer->canWalk(direction))
|
||||
return;
|
||||
|
||||
|
||||
// TODO: restore check for blockable tiles
|
||||
/*
|
||||
if(toTile && !toTile->isWalkable() && !fromTile->getElevation() >= 3) {
|
||||
g_game.processTextMessage("statusSmall", "Sorry, not possible.");
|
||||
return false;
|
||||
}*/
|
||||
|
||||
// only do prewalk to walkable tiles
|
||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPos() + Position::getPosFromDirection(direction));
|
||||
// only do prewalks to walkable tiles
|
||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
|
||||
if(toTile && toTile->isWalkable())
|
||||
m_localPlayer->preWalk(direction);
|
||||
else
|
||||
|
@ -316,7 +308,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 +318,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 +330,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 +338,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 +352,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 +371,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 +386,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 +425,9 @@ void Game::follow(const CreaturePtr& creature)
|
|||
|
||||
void Game::cancelFollow()
|
||||
{
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
|
||||
m_localPlayer->setFollowingCreature(nullptr);
|
||||
m_protocolGame->sendFollow(0);
|
||||
}
|
||||
|
@ -444,16 +439,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");
|
||||
|
@ -467,21 +461,28 @@ int Game::getThingStackpos(const ThingPtr& thing)
|
|||
|
||||
void Game::talk(const std::string& message)
|
||||
{
|
||||
talkChannel("say", 0, message);
|
||||
talkChannel(Otc::SpeakSay, 0, message);
|
||||
}
|
||||
|
||||
void Game::talkChannel(const std::string& speakTypeDesc, int channelId, const std::string& message)
|
||||
void Game::talkChannel(Otc::SpeakType speakType, int channelId, const std::string& message)
|
||||
{
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendTalk(speakTypeDesc, channelId, "", message);
|
||||
m_protocolGame->sendTalk(speakType, channelId, "", message);
|
||||
}
|
||||
|
||||
void Game::talkPrivate(const std::string& speakTypeDesc, const std::string& receiver, const std::string& message)
|
||||
void Game::talkPrivate(Otc::SpeakType speakType, const std::string& receiver, const std::string& message)
|
||||
{
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendTalk(speakTypeDesc, 0, receiver, message);
|
||||
m_protocolGame->sendTalk(speakType, 0, receiver, message);
|
||||
}
|
||||
|
||||
void Game::openPrivateChannel(const std::string& receiver)
|
||||
{
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendOpenPrivateChannel(receiver);
|
||||
}
|
||||
|
||||
void Game::requestChannels()
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
double magicLevel, double magicLevelPercent,
|
||||
double soul, double stamina);
|
||||
void processTextMessage(const std::string& type, const std::string& message);
|
||||
void processCreatureSpeak(const std::string& name, int level, const std::string& type, const std::string& message, int channelId, const Position& creaturePos);
|
||||
void processCreatureSpeak(const std::string& name, int level, Otc::SpeakType type, const std::string& message, int channelId, const Position& creaturePos);
|
||||
void processContainerAddItem(int containerId, const ItemPtr& item);
|
||||
void processInventoryChange(int slot, const ItemPtr& item);
|
||||
void processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos);
|
||||
|
@ -82,8 +82,9 @@ public:
|
|||
|
||||
// talk related
|
||||
void talk(const std::string& message);
|
||||
void talkChannel(const std::string& speakTypeDesc, int channelId, const std::string& message);
|
||||
void talkPrivate(const std::string& speakTypeDesc, const std::string& receiver, const std::string& message);
|
||||
void talkChannel(Otc::SpeakType speakType, int channelId, const std::string& message);
|
||||
void talkPrivate(Otc::SpeakType speakType, const std::string& receiver, const std::string& message);
|
||||
void openPrivateChannel(const std::string& receiver);
|
||||
void requestChannels();
|
||||
void joinChannel(int channelId);
|
||||
void leaveChannel(int channelId);
|
||||
|
|
|
@ -24,143 +24,181 @@
|
|||
#include "thingstype.h"
|
||||
#include "spritemanager.h"
|
||||
#include "thing.h"
|
||||
#include "tile.h"
|
||||
#include <framework/core/clock.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/paintershaderprogram.h>
|
||||
#include <framework/graphics/paintershadersources.h>
|
||||
|
||||
Item::Item() : Thing()
|
||||
{
|
||||
m_data = 1;
|
||||
m_id = 0;
|
||||
m_countOrSubType = 0;
|
||||
}
|
||||
|
||||
ItemPtr Item::create(int id)
|
||||
{
|
||||
if(id < g_thingsType.getFirstItemId() || id > g_thingsType.getMaxItemid()) {
|
||||
logTraceError("invalid item id ", id);
|
||||
return nullptr;
|
||||
}
|
||||
ItemPtr item = ItemPtr(new Item);
|
||||
item->setId(id);
|
||||
return item;
|
||||
}
|
||||
|
||||
void Item::draw(const Point& p, const Rect&)
|
||||
{
|
||||
if(m_type->dimensions[ThingType::AnimationPhases] > 1)
|
||||
m_animation = (g_clock.ticks() % (TICKS_PER_FRAME * m_type->dimensions[ThingType::AnimationPhases])) / TICKS_PER_FRAME;
|
||||
PainterShaderProgramPtr itemProgram;
|
||||
|
||||
for(int l = 0; l < m_type->dimensions[ThingType::Layers]; l++)
|
||||
internalDraw(p, l);
|
||||
}
|
||||
|
||||
void Item::setPos(const Position& position)
|
||||
void Item::draw(const Point& dest, float scaleFactor, bool animate)
|
||||
{
|
||||
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(m_id == 0)
|
||||
return;
|
||||
|
||||
// determine animation phase
|
||||
int animationPhase = 0;
|
||||
if(getAnimationPhases() > 1) {
|
||||
if(animate)
|
||||
animationPhase = (g_clock.ticks() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
|
||||
else
|
||||
animationPhase = getAnimationPhases()-1;
|
||||
}
|
||||
|
||||
Thing::setPos(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(data < 5) {
|
||||
m_xPattern = data-1;
|
||||
m_yPattern = 0;
|
||||
// determine x,y,z patterns
|
||||
int xPattern = 0, yPattern = 0, zPattern = 0;
|
||||
if(isGround()) {
|
||||
xPattern = m_position.x % getNumPatternsX();
|
||||
yPattern = m_position.y % getNumPatternsY();
|
||||
zPattern = m_position.z % getNumPatternsZ();
|
||||
} else if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
|
||||
if(m_countOrSubType < 5) {
|
||||
xPattern = m_countOrSubType-1;
|
||||
yPattern = 0;
|
||||
} else if(m_countOrSubType < 10) {
|
||||
xPattern = 0;
|
||||
yPattern = 1;
|
||||
} else if(m_countOrSubType < 25) {
|
||||
xPattern = 1;
|
||||
yPattern = 1;
|
||||
} else if(m_countOrSubType < 50) {
|
||||
xPattern = 2;
|
||||
yPattern = 1;
|
||||
} else if(m_countOrSubType <= 100) {
|
||||
xPattern = 3;
|
||||
yPattern = 1;
|
||||
}
|
||||
else if(data < 10) {
|
||||
m_xPattern = 0;
|
||||
m_yPattern = 1;
|
||||
} else if(isHangable()) {
|
||||
const TilePtr& tile = getTile();
|
||||
if(tile) {
|
||||
if(tile->mustHookSouth())
|
||||
xPattern = getNumPatternsX() >= 2 ? 1 : 0;
|
||||
else if(tile->mustHookSouth())
|
||||
xPattern = getNumPatternsX() >= 3 ? 2 : 0;
|
||||
}
|
||||
else if(data < 25) {
|
||||
m_xPattern = 1;
|
||||
m_yPattern = 1;
|
||||
}
|
||||
else if(data < 50) {
|
||||
m_xPattern = 2;
|
||||
m_yPattern = 1;
|
||||
}
|
||||
else if(data <= 100) {
|
||||
m_xPattern = 3;
|
||||
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(m_type->properties[ThingType::HookEast]) {
|
||||
m_xPattern = m_type->dimensions[ThingType::PatternX] >= 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:
|
||||
color = Otc::FluidTransparent;
|
||||
break;
|
||||
case Otc::FluidWater:
|
||||
color = Otc::FluidBlue;
|
||||
break;
|
||||
case Otc::FluidMana:
|
||||
color = Otc::FluidPurple;
|
||||
break;
|
||||
case Otc::FluidBeer:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidOil:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidBlood:
|
||||
color = Otc::FluidRed;
|
||||
break;
|
||||
case Otc::FluidSlime:
|
||||
color = Otc::FluidGreen;
|
||||
break;
|
||||
case Otc::FluidMud:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidLemonade:
|
||||
color = Otc::FluidYellow;
|
||||
break;
|
||||
case Otc::FluidMilk:
|
||||
color = Otc::FluidWhite;
|
||||
break;
|
||||
case Otc::FluidWine:
|
||||
color = Otc::FluidPurple;
|
||||
break;
|
||||
case Otc::FluidHealth:
|
||||
color = Otc::FluidRed;
|
||||
break;
|
||||
case Otc::FluidUrine:
|
||||
color = Otc::FluidYellow;
|
||||
break;
|
||||
case Otc::FluidRum:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidFruidJuice:
|
||||
color = Otc::FluidYellow;
|
||||
break;
|
||||
case Otc::FluidCoconutMilk:
|
||||
color = Otc::FluidWhite;
|
||||
break;
|
||||
case Otc::FluidTea:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidMead:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
default:
|
||||
color = Otc::FluidTransparent;
|
||||
break;
|
||||
switch(m_countOrSubType) {
|
||||
case Otc::FluidNone:
|
||||
color = Otc::FluidTransparent;
|
||||
break;
|
||||
case Otc::FluidWater:
|
||||
color = Otc::FluidBlue;
|
||||
break;
|
||||
case Otc::FluidMana:
|
||||
color = Otc::FluidPurple;
|
||||
break;
|
||||
case Otc::FluidBeer:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidOil:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidBlood:
|
||||
color = Otc::FluidRed;
|
||||
break;
|
||||
case Otc::FluidSlime:
|
||||
color = Otc::FluidGreen;
|
||||
break;
|
||||
case Otc::FluidMud:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidLemonade:
|
||||
color = Otc::FluidYellow;
|
||||
break;
|
||||
case Otc::FluidMilk:
|
||||
color = Otc::FluidWhite;
|
||||
break;
|
||||
case Otc::FluidWine:
|
||||
color = Otc::FluidPurple;
|
||||
break;
|
||||
case Otc::FluidHealth:
|
||||
color = Otc::FluidRed;
|
||||
break;
|
||||
case Otc::FluidUrine:
|
||||
color = Otc::FluidYellow;
|
||||
break;
|
||||
case Otc::FluidRum:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidFruidJuice:
|
||||
color = Otc::FluidYellow;
|
||||
break;
|
||||
case Otc::FluidCoconutMilk:
|
||||
color = Otc::FluidWhite;
|
||||
break;
|
||||
case Otc::FluidTea:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
case Otc::FluidMead:
|
||||
color = Otc::FluidBrown;
|
||||
break;
|
||||
default:
|
||||
color = Otc::FluidTransparent;
|
||||
break;
|
||||
}
|
||||
|
||||
m_xPattern = (color % 4) % m_type->dimensions[ThingType::PatternX];
|
||||
m_yPattern = (color / 4) % m_type->dimensions[ThingType::PatternY];
|
||||
xPattern = (color % 4) % getNumPatternsX();
|
||||
yPattern = (color / 4) % getNumPatternsY();
|
||||
}
|
||||
|
||||
m_data = data;
|
||||
// setup item drawing shader
|
||||
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);
|
||||
|
||||
// now we can draw the item
|
||||
internalDraw(dest, scaleFactor, xPattern, yPattern, zPattern, animationPhase);
|
||||
|
||||
// release draw shader
|
||||
g_painter.releaseCustomProgram();
|
||||
}
|
||||
|
||||
ThingType *Item::getType()
|
||||
void Item::setId(uint32 id)
|
||||
{
|
||||
return g_thingsType.getThingType(m_id, ThingsType::Item);
|
||||
if(id < g_thingsType.getFirstItemId() || id > g_thingsType.getMaxItemid()) {
|
||||
logTraceError("invalid item id ", id);
|
||||
return;
|
||||
}
|
||||
m_id = id;
|
||||
m_type = g_thingsType.getThingType(m_id, ThingsType::Item);
|
||||
}
|
||||
|
||||
int Item::getCount()
|
||||
{
|
||||
if(isStackable())
|
||||
return m_countOrSubType;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Item::getSubType()
|
||||
{
|
||||
if(isFluid() || isFluidContainer())
|
||||
return m_countOrSubType;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,22 +33,23 @@ public:
|
|||
|
||||
static ItemPtr create(int id);
|
||||
|
||||
enum {
|
||||
TICKS_PER_FRAME = 500
|
||||
};
|
||||
void draw(const Point& dest, float scaleFactor, bool animate);
|
||||
|
||||
void draw(const Point& p, const Rect&);
|
||||
void setId(uint32 id);
|
||||
void setCountOrSubType(uint8 value) { m_countOrSubType = value; }
|
||||
void setCount(int count) { setCountOrSubType(count); }
|
||||
void setSubType(int subType) { setCountOrSubType(subType); }
|
||||
|
||||
void setPos(const Position &position);
|
||||
void setData(int data);
|
||||
|
||||
int getData() { return m_data; }
|
||||
ThingType *getType();
|
||||
uint8 getCountOrSubType() { return m_countOrSubType; }
|
||||
int getSubType();
|
||||
int getCount();
|
||||
uint32 getId() { return m_id; }
|
||||
|
||||
ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
|
||||
|
||||
private:
|
||||
int m_data;
|
||||
uint16 m_id;
|
||||
uint8 m_countOrSubType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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.translatedToDirection(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)
|
||||
|
@ -145,6 +145,7 @@ void LocalPlayer::updateWalk()
|
|||
// update walk animation and offsets
|
||||
updateWalkAnimation(totalPixelsWalked);
|
||||
updateWalkOffset(totalPixelsWalked);
|
||||
updateWalkingTile();
|
||||
|
||||
// terminate walk only when client and server side walk are complated
|
||||
if(m_walking && !m_preWalking && m_walkTimer.ticksElapsed() >= m_walkInterval)
|
||||
|
|
|
@ -28,254 +28,122 @@
|
|||
#include "missile.h"
|
||||
#include "statictext.h"
|
||||
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/framebuffer.h>
|
||||
#include <framework/graphics/paintershaderprogram.h>
|
||||
#include <framework/graphics/paintershadersources.h>
|
||||
#include <framework/graphics/texture.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include "mapview.h"
|
||||
#include <framework/core/resourcemanager.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);
|
||||
auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView);
|
||||
if(it != m_mapViews.end())
|
||||
m_mapViews.erase(it);
|
||||
}
|
||||
|
||||
void Map::notificateTileUpdateToMapViews(const Position& pos)
|
||||
{
|
||||
for(const MapViewPtr& mapView : m_mapViews)
|
||||
mapView->onTileUpdate(pos);
|
||||
}
|
||||
|
||||
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 Map::load()
|
||||
{
|
||||
if(!g_resources.fileExists("/map.otcmap"))
|
||||
return;
|
||||
|
||||
std::stringstream in;
|
||||
g_resources.loadFile("/map.otcmap", in);
|
||||
|
||||
while(!in.eof()) {
|
||||
Position pos;
|
||||
in.read((char*)&pos, sizeof(pos));
|
||||
|
||||
uint16 id;
|
||||
in.read((char*)&id, sizeof(id));
|
||||
while(id != 0xFFFF) {
|
||||
ItemPtr item = Item::create(id);
|
||||
if(item->isStackable() || item->isFluidContainer() || item->isFluid()) {
|
||||
uint8 countOrSubType;
|
||||
in.read((char*)&countOrSubType, sizeof(countOrSubType));
|
||||
item->setCountOrSubType(countOrSubType);
|
||||
}
|
||||
addThing(item, pos, 255);
|
||||
in.read((char*)&id, sizeof(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_painter.setColor(Fw::white);
|
||||
m_framebuffer->bind();
|
||||
void Map::save()
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
// 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);
|
||||
for(auto& pair : m_tiles) {
|
||||
Position pos = pair.first;
|
||||
TilePtr tile = pair.second;
|
||||
if(!tile || tile->isEmpty())
|
||||
continue;
|
||||
out.write((char*)&pos, sizeof(pos));
|
||||
uint16 id;
|
||||
for(const ThingPtr& thing : tile->getThings()) {
|
||||
if(ItemPtr item = thing->asItem()) {
|
||||
id = item->getId();
|
||||
out.write((char*)&id, sizeof(id));
|
||||
if(item->isStackable() || item->isFluidContainer() || item->isFluid()) {
|
||||
uint8 countOrSubType = item->getCountOrSubType();
|
||||
out.write((char*)&countOrSubType, sizeof(countOrSubType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// after drawing all tiles, draw shots
|
||||
for(const MissilePtr& shot : m_missilesAtFloor[iz]) {
|
||||
Position missilePos = shot->getPos();
|
||||
shot->draw(positionTo2D(missilePos) - m_drawOffset, rect);
|
||||
}
|
||||
id = 0xFFFF;
|
||||
out.write((char*)&id, sizeof(id));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
g_resources.saveFile("/map.otcmap", out);
|
||||
}
|
||||
|
||||
void Map::clean()
|
||||
{
|
||||
m_tiles.clear();
|
||||
m_creatures.clear();
|
||||
for(int i=0;i<MAX_Z-1;++i)
|
||||
m_missilesAtFloor[i].clear();
|
||||
m_knownCreatures.clear();
|
||||
for(int i=0;i<=Otc::MAX_Z;++i)
|
||||
m_floorMissiles[i].clear();
|
||||
m_animatedTexts.clear();
|
||||
m_staticTexts.clear();
|
||||
}
|
||||
|
||||
int Map::getFirstVisibleFloor()
|
||||
{
|
||||
int firstFloor = 0;
|
||||
for(int ix = -1; ix <= 1 && firstFloor < m_centralPosition.z; ++ix) {
|
||||
for(int iy = -1; iy <= 1 && firstFloor < m_centralPosition.z; ++iy) {
|
||||
Position currentPos(m_centralPosition.x + ix, m_centralPosition.y + iy, m_centralPosition.z);
|
||||
if((ix == 0 && iy == 0) || isLookPossible(currentPos)) {
|
||||
Position upperPos = currentPos;
|
||||
Position perspectivePos = currentPos;
|
||||
perspectivePos.perspectiveUp();
|
||||
upperPos.up();
|
||||
while(upperPos.z >= 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);
|
||||
TilePtr tile = getOrCreateTile(pos);
|
||||
|
||||
if(CreaturePtr creature = thing->asCreature()) {
|
||||
Position oldPos = thing->getPosition();
|
||||
tile->addThing(thing, stackPos);
|
||||
m_creatures[creature->getId()] = creature;
|
||||
|
||||
if(teleport)
|
||||
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1))
|
||||
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 +152,249 @@ 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;
|
||||
return false;
|
||||
|
||||
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(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 = thing->getTile())
|
||||
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;
|
||||
}
|
||||
|
||||
const TilePtr& Map::getTile(const Position& pos)
|
||||
{
|
||||
auto it = m_tiles.find(pos);
|
||||
if(it != m_tiles.end())
|
||||
return it->second;
|
||||
static TilePtr nulltile;
|
||||
return nulltile;
|
||||
}
|
||||
|
||||
TilePtr Map::getOrCreateTile(const Position& pos)
|
||||
{
|
||||
const TilePtr& tile = getTile(pos);
|
||||
if(tile)
|
||||
return tile;
|
||||
else
|
||||
return createTile(pos);
|
||||
}
|
||||
|
||||
void Map::cleanTile(const Position& pos)
|
||||
{
|
||||
if(TilePtr& tile = m_tiles[pos])
|
||||
if(TilePtr tile = getTile(pos)) {
|
||||
tile->clean();
|
||||
if(tile->canErase())
|
||||
m_tiles.erase(m_tiles.find(pos));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Map::setCentralPosition(const Position& centralPosition)
|
||||
{
|
||||
bool teleported = !m_centralPosition.isInRange(centralPosition, 1,1);
|
||||
m_centralPosition = centralPosition;
|
||||
}
|
||||
|
||||
void Map::setVisibleSize(const Size& visibleSize)
|
||||
{
|
||||
m_visibleSize = visibleSize;
|
||||
|
||||
if(m_visibleSize.width() > MAX_WIDTH || m_visibleSize.height() > MAX_HEIGHT)
|
||||
m_visibleSize = Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT);
|
||||
|
||||
m_centralOffset = Point(std::ceil(m_visibleSize.width() / 2.0), std::ceil(m_visibleSize.height() / 2.0));
|
||||
m_size = m_visibleSize + Size(3, 3);
|
||||
|
||||
if(m_framebuffer) {
|
||||
m_framebuffer->resize(Size(m_visibleSize.width() * NUM_TILE_PIXELS, m_visibleSize.height() * NUM_TILE_PIXELS));
|
||||
// remove all creatures when teleporting, the server will resend them again
|
||||
if(teleported) {
|
||||
for(const auto& pair : m_knownCreatures) {
|
||||
const CreaturePtr& creature = pair.second;
|
||||
removeThing(creature);
|
||||
}
|
||||
// remove creatures from tiles that we are not aware anymore
|
||||
} else {
|
||||
for(const auto& pair : m_knownCreatures) {
|
||||
const CreaturePtr& creature = pair.second;
|
||||
if(!isAwareOfPosition(creature->getPosition())) {
|
||||
removeThing(creature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Point Map::positionTo2D(const Position& position)
|
||||
std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
|
||||
{
|
||||
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);
|
||||
return getSpectatorsInRange(centerPos, multiFloor, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
|
||||
}
|
||||
|
||||
std::vector<CreaturePtr> Map::getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange)
|
||||
{
|
||||
return getSpectatorsInRangeEx(centerPos, multiFloor, xRange, xRange, yRange, yRange);
|
||||
}
|
||||
|
||||
std::vector<CreaturePtr> Map::getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange)
|
||||
{
|
||||
int minZRange = 0;
|
||||
int maxZRange = 0;
|
||||
std::vector<CreaturePtr> creatures;
|
||||
|
||||
if(multiFloor) {
|
||||
minZRange = 0;
|
||||
maxZRange = Otc::MAX_Z;
|
||||
}
|
||||
|
||||
//TODO: get creatures from other floors corretly
|
||||
//TODO: delivery creatures in distance order
|
||||
|
||||
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.translated(ix,iy,iz));
|
||||
if(!tile)
|
||||
continue;
|
||||
|
||||
auto tileCreatures = tile->getCreatures();
|
||||
creatures.insert(creatures.end(), tileCreatures.rbegin(), tileCreatures.rend());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return creatures;
|
||||
}
|
||||
|
||||
bool Map::isLookPossible(const Position& pos)
|
||||
{
|
||||
TilePtr tile = getTile(pos);
|
||||
return tile && tile->isLookPossible();
|
||||
}
|
||||
|
||||
bool Map::isCovered(const Position& pos, int firstFloor)
|
||||
{
|
||||
// check for tiles on top of the postion
|
||||
Position tilePos = pos;
|
||||
while(tilePos.coveredUp() && 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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
||||
{
|
||||
Position tilePos = pos;
|
||||
while(tilePos.coveredUp() && 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) {
|
||||
const TilePtr& tile = getTile(tilePos.translated(-x, -y));
|
||||
if(!tile || !tile->isFullyOpaque()) {
|
||||
covered = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(covered)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Map::isAwareOfPosition(const Position& pos)
|
||||
{
|
||||
if(pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor())
|
||||
return false;
|
||||
|
||||
Position groundedPos = pos;
|
||||
while(groundedPos.z != m_centralPosition.z) {
|
||||
if(groundedPos.z > m_centralPosition.z)
|
||||
groundedPos.coveredUp();
|
||||
else
|
||||
groundedPos.coveredDown();
|
||||
}
|
||||
return m_centralPosition.isInRange(groundedPos, Otc::AWARE_X_LEFT_TILES,
|
||||
Otc::AWARE_X_RIGHT_TILES,
|
||||
Otc::AWARE_Y_TOP_TILES,
|
||||
Otc::AWARE_Y_BOTTOM_TILES);
|
||||
}
|
||||
|
||||
int Map::getFirstAwareFloor()
|
||||
{
|
||||
if(m_centralPosition.z > Otc::SEA_FLOOR)
|
||||
return m_centralPosition.z-Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Map::getLastAwareFloor()
|
||||
{
|
||||
if(m_centralPosition.z > Otc::SEA_FLOOR)
|
||||
return std::min(m_centralPosition.z+Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
|
||||
else
|
||||
return Otc::SEA_FLOOR;
|
||||
}
|
||||
|
|
|
@ -26,70 +26,65 @@
|
|||
#include "creature.h"
|
||||
#include "animatedtext.h"
|
||||
#include <framework/core/clock.h>
|
||||
#include <framework/graphics/declarations.h>
|
||||
|
||||
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
|
||||
};
|
||||
void addMapView(const MapViewPtr& mapView);
|
||||
void removeMapView(const MapViewPtr& mapView);
|
||||
void notificateTileUpdateToMapViews(const Position& pos);
|
||||
|
||||
Map();
|
||||
|
||||
void draw(const Rect& rect);
|
||||
void load();
|
||||
void save();
|
||||
void clean();
|
||||
|
||||
int getFirstVisibleFloor();
|
||||
bool isLookPossible(const Position& pos);
|
||||
bool isCovered(const Position& pos, int firstFloor = 0);
|
||||
bool isCompletlyCovered(const Position& pos, int firstFloor = 0);
|
||||
|
||||
// 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);
|
||||
bool removeThingByPos(const Position& pos, int stackPos);
|
||||
|
||||
// tile related
|
||||
TilePtr createTile(const Position& pos);
|
||||
const TilePtr& getTile(const Position& pos);
|
||||
TilePtr getOrCreateTile(const Position& pos);
|
||||
void cleanTile(const Position& pos);
|
||||
TilePtr getTile(const Position& pos);
|
||||
|
||||
void setLight(const Light& light) { m_light = light; }
|
||||
Light getLight() { return m_light; }
|
||||
|
||||
void setCentralPosition(const Position& centralPosition);
|
||||
Position getCentralPosition() { return m_centralPosition; }
|
||||
bool removeThing(const ThingPtr& thing);
|
||||
|
||||
// known creature related
|
||||
void addCreature(const CreaturePtr& creature);
|
||||
CreaturePtr getCreatureById(uint32 id);
|
||||
void removeCreatureById(uint32 id);
|
||||
std::vector<CreaturePtr> getSpectators(const Position& centerPos, bool multiFloor);
|
||||
std::vector<CreaturePtr> getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange);
|
||||
std::vector<CreaturePtr> 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);
|
||||
|
||||
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);
|
||||
bool isAwareOfPosition(const Position& pos);
|
||||
|
||||
Light getLight() { return m_light; }
|
||||
Position getCentralPosition() { return m_centralPosition; }
|
||||
int getFirstAwareFloor();
|
||||
int getLastAwareFloor();
|
||||
const std::vector<MissilePtr>& getFloorMissiles(int z) { return m_floorMissiles[z]; }
|
||||
|
||||
std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; }
|
||||
std::vector<StaticTextPtr> getStaticTexts() { return m_staticTexts; }
|
||||
|
||||
private:
|
||||
std::unordered_map<Position, TilePtr, PositionHasher> m_tiles;
|
||||
std::map<uint32, CreaturePtr> m_creatures;
|
||||
std::array<std::vector<MissilePtr>, MAX_Z> m_missilesAtFloor;
|
||||
std::map<uint32, CreaturePtr> m_knownCreatures;
|
||||
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
|
||||
std::vector<AnimatedTextPtr> m_animatedTexts;
|
||||
std::vector<StaticTextPtr> m_staticTexts;
|
||||
std::vector<MapViewPtr> 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;
|
||||
|
|
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/framebuffer.h>
|
||||
#include <framework/graphics/paintershaderprogram.h>
|
||||
#include <framework/graphics/paintershadersources.h>
|
||||
#include "creature.h"
|
||||
#include "map.h"
|
||||
#include "tile.h"
|
||||
#include "statictext.h"
|
||||
#include "animatedtext.h"
|
||||
#include "missile.h"
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
|
||||
MapView::MapView()
|
||||
{
|
||||
Size frameBufferSize(std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_WIDTH),
|
||||
std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_HEIGHT));
|
||||
|
||||
m_framebuffer = FrameBufferPtr(new FrameBuffer(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
|
||||
if(m_mustUpdateVisibleTilesCache)
|
||||
updateVisibleTilesCache();
|
||||
|
||||
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
int drawFlags = 0;
|
||||
if(m_viewRange == NEAR_VIEW)
|
||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls |
|
||||
Otc::DrawItems | Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawMissiles | Otc::DrawAnimations;
|
||||
else if(m_viewRange == MID_VIEW)
|
||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems;
|
||||
else if(m_viewRange == FAR_VIEW)
|
||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls;
|
||||
else if(m_tileSize >= 4) // HUGE_VIEW 1
|
||||
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders;
|
||||
else // HUGE_VIEW 2
|
||||
drawFlags = Otc::DrawGround;
|
||||
|
||||
if(m_mustDrawVisibleTilesCache || (drawFlags & Otc::DrawAnimations)) {
|
||||
m_framebuffer->bind(m_mustCleanFramebuffer);
|
||||
|
||||
auto it = m_cachedVisibleTiles.begin();
|
||||
auto end = m_cachedVisibleTiles.end();
|
||||
for(int z=m_cachedLastVisibleFloor;z>=m_cachedFirstVisibleFloor;--z) {
|
||||
while(it != end) {
|
||||
const TilePtr& tile = *it;
|
||||
if(tile->getPosition().z != z)
|
||||
break;
|
||||
else
|
||||
++it;
|
||||
|
||||
tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor, drawFlags);
|
||||
}
|
||||
|
||||
if(drawFlags & Otc::DrawMissiles) {
|
||||
for(const MissilePtr& missile : g_map.getFloorMissiles(z)) {
|
||||
missile->draw(transformPositionTo2D(missile->getPosition()), scaleFactor, drawFlags & Otc::DrawAnimations);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_framebuffer->generateMipmaps();
|
||||
m_framebuffer->release();
|
||||
|
||||
m_mustDrawVisibleTilesCache = false;
|
||||
}
|
||||
|
||||
g_painter.setCustomProgram(m_shaderProgram);
|
||||
g_painter.setColor(Fw::white);
|
||||
|
||||
Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * 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();
|
||||
|
||||
// this could happen if the player position is not known yet
|
||||
if(!cameraPosition.isValid())
|
||||
return;
|
||||
|
||||
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(m_viewRange == NEAR_VIEW) {
|
||||
for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
|
||||
Position pos = creature->getPosition();
|
||||
|
||||
Point p = transformPositionTo2D(pos) - drawOffset;
|
||||
p += (creature->getDrawOffset() + Point(8, -10)) * 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;
|
||||
|
||||
// dont draw animated texts from covered tiles
|
||||
if(pos.z != cameraPosition.z && g_map.isCovered(pos, m_cachedFirstVisibleFloor))
|
||||
continue;
|
||||
|
||||
Point p = transformPositionTo2D(pos) - drawOffset;
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
p.y = p.y * verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
animatedText->draw(p, rect);
|
||||
}
|
||||
} else {
|
||||
// draw a cross in the center instead of our creature
|
||||
Rect vRect(0, 0, 2, 10);
|
||||
Rect hRect(0, 0, 10, 2);
|
||||
vRect.moveCenter(rect.center());
|
||||
hRect.moveCenter(rect.center());
|
||||
g_painter.setColor(Fw::white);
|
||||
g_painter.drawFilledRect(vRect);
|
||||
g_painter.drawFilledRect(hRect);
|
||||
}
|
||||
}
|
||||
|
||||
void MapView::updateVisibleTilesCache(int start)
|
||||
{
|
||||
if(start == 0) {
|
||||
if(m_updateTilesCacheEvent) {
|
||||
m_updateTilesCacheEvent->cancel();
|
||||
m_updateTilesCacheEvent = nullptr;
|
||||
}
|
||||
|
||||
m_cachedFirstVisibleFloor = getFirstVisibleFloor();
|
||||
m_cachedLastVisibleFloor = getLastVisibleFloor();
|
||||
|
||||
if(m_cachedLastVisibleFloor < m_cachedFirstVisibleFloor)
|
||||
m_cachedLastVisibleFloor = m_cachedFirstVisibleFloor;
|
||||
|
||||
m_cachedFloorVisibleCreatures.clear();
|
||||
m_cachedVisibleTiles.clear();
|
||||
|
||||
m_mustCleanFramebuffer = true;
|
||||
m_mustDrawVisibleTilesCache = true;
|
||||
m_mustUpdateVisibleTilesCache = false;
|
||||
} else
|
||||
m_mustCleanFramebuffer = false;
|
||||
|
||||
// there is no tile to render on invalid positions
|
||||
Position cameraPosition = getCameraPosition();
|
||||
if(!cameraPosition.isValid())
|
||||
return;
|
||||
|
||||
int count = 0;
|
||||
bool stop = false;
|
||||
|
||||
// clear current visible tiles cache
|
||||
m_cachedVisibleTiles.clear();
|
||||
m_mustDrawVisibleTilesCache = true;
|
||||
|
||||
// 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 && !stop; --iz) {
|
||||
if(m_viewRange <= FAR_VIEW) {
|
||||
const int numDiagonals = m_drawDimension.width() + m_drawDimension.height() - 1;
|
||||
// loop through / diagonals beginning at top left and going to top right
|
||||
for(int diagonal = 0; diagonal < numDiagonals && !stop; ++diagonal) {
|
||||
// loop current diagonal tiles
|
||||
for(int iy = std::min(diagonal, m_drawDimension.width() - 1), ix = std::max(diagonal - m_drawDimension.width() + 1, 0); iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) {
|
||||
// only start really looking tiles in the desired start
|
||||
if(count < start) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid rendering too much tiles at once on far views
|
||||
if(count - start + 1 > MAX_TILE_UPDATES && m_viewRange >= HUGE_VIEW) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// position on current floor
|
||||
//TODO: check position limits
|
||||
Position tilePos = cameraPosition.translated(ix - m_virtualCenterOffset.x, iy - m_virtualCenterOffset.y);
|
||||
// adjust tilePos to the wanted floor
|
||||
tilePos.coveredUp(cameraPosition.z - iz);
|
||||
if(const TilePtr& tile = g_map.getTile(tilePos)) {
|
||||
// skip tiles that have nothing
|
||||
if(tile->isEmpty())
|
||||
continue;
|
||||
// skip tiles that are completely behind another tile
|
||||
if(g_map.isCompletelyCovered(tilePos, m_cachedFirstVisibleFloor))
|
||||
continue;
|
||||
m_cachedVisibleTiles.push_back(tile);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
static std::vector<Point> points;
|
||||
points.clear();
|
||||
assert(m_drawDimension.width() % 2 == 0 && m_drawDimension.height() % 2 == 0);
|
||||
Point quadTopLeft(m_drawDimension.width()/2 - 1, m_drawDimension.height()/2 - 1);
|
||||
for(int step = 1; !(quadTopLeft.x < 0 && quadTopLeft.y < 0) && !stop; ++step) {
|
||||
int quadWidth = std::min(2*step, m_drawDimension.width());
|
||||
int quadHeight = std::min(2*step, m_drawDimension.height());
|
||||
int fillWidth = (quadTopLeft.x >= 0) ? quadWidth-1 : quadWidth;
|
||||
int fillHeight = (quadTopLeft.x >= 0) ? quadHeight-1 : quadHeight;
|
||||
if(quadTopLeft.y >= 0) {
|
||||
for(int qx=0;qx<fillWidth;++qx) {
|
||||
//TODO: remvoe this repeated code
|
||||
// only start really looking tiles in the desired start
|
||||
if(count < start) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid rendering too much tiles at once on far views
|
||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
points.push_back(Point(std::max(quadTopLeft.x, 0) + qx, quadTopLeft.y));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(quadTopLeft.x >= 0) {
|
||||
for(int qy=0;qy<fillHeight;++qy) {
|
||||
// only start really looking tiles in the desired start
|
||||
if(count < start) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid rendering too much tiles at once on far views
|
||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
points.push_back(Point(quadTopLeft.x + quadWidth-1, std::max(quadTopLeft.y, 0) + qy));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(quadTopLeft.y >= 0) {
|
||||
for(int qx=0;qx<fillWidth;++qx) {
|
||||
// only start really looking tiles in the desired start
|
||||
if(count < start) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid rendering too much tiles at once on far views
|
||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
points.push_back(Point(std::max(quadTopLeft.x, 0) + quadWidth-qx-1, quadTopLeft.y + quadHeight-1));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(quadTopLeft.x >= 0) {
|
||||
for(int qy=0;qy<fillHeight;++qy) {
|
||||
// only start really looking tiles in the desired start
|
||||
if(count < start) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid rendering too much tiles at once on far views
|
||||
if(count - start + 1 > MAX_TILE_UPDATES) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
points.push_back(Point(quadTopLeft.x, std::max(quadTopLeft.y, 0) + quadHeight-qy-1));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
quadTopLeft -= Point(1,1);
|
||||
}
|
||||
|
||||
for(const Point& point : points) {
|
||||
Position tilePos = cameraPosition.translated(point.x - m_virtualCenterOffset.x, point.y - m_virtualCenterOffset.y);
|
||||
// adjust tilePos to the wanted floor
|
||||
tilePos.coveredUp(cameraPosition.z - iz);
|
||||
if(const TilePtr& tile = g_map.getTile(tilePos)) {
|
||||
// skip tiles that have nothing
|
||||
if(tile->isEmpty())
|
||||
continue;
|
||||
m_cachedVisibleTiles.push_back(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(stop) {
|
||||
// schedule next update continuation
|
||||
m_updateTilesCacheEvent = g_dispatcher.addEvent(std::bind(&MapView::updateVisibleTilesCache, asMapView(), count));
|
||||
}
|
||||
if(start == 0)
|
||||
m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false);
|
||||
}
|
||||
|
||||
void MapView::onTileUpdate(const Position& pos)
|
||||
{
|
||||
//if(m_viewRange == NEAR_VIEW)
|
||||
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("reach max zoom in");
|
||||
return;
|
||||
}
|
||||
|
||||
int possiblesTileSizes[] = {32,16,8,4,2,1};
|
||||
int tileSize = 0;
|
||||
Size drawDimension = visibleDimension + Size(3,3);
|
||||
for(int candidateTileSize : possiblesTileSizes) {
|
||||
Size candidateDrawSize = drawDimension * candidateTileSize;
|
||||
|
||||
// found a valid size
|
||||
if(candidateDrawSize <= m_framebuffer->getSize()) {
|
||||
tileSize = candidateTileSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(tileSize == 0) {
|
||||
logTraceError("reached max zoom out");
|
||||
return;
|
||||
}
|
||||
|
||||
Point virtualCenterOffset = (drawDimension/2 - Size(1,1)).toPoint();
|
||||
|
||||
ViewRange viewRange;
|
||||
if(tileSize >= 32 && visibleDimension.area() <= NEAR_VIEW_AREA)
|
||||
viewRange = NEAR_VIEW;
|
||||
else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA)
|
||||
viewRange = MID_VIEW;
|
||||
else if(tileSize >= 8 && visibleDimension.area() <= FAR_VIEW_AREA)
|
||||
viewRange = FAR_VIEW;
|
||||
else
|
||||
viewRange = HUGE_VIEW;
|
||||
|
||||
// draw actually more than what is needed to avoid massive recalculations on far views
|
||||
if(viewRange >= FAR_VIEW) {
|
||||
Size oldDimension = drawDimension;
|
||||
drawDimension = (m_framebuffer->getSize() / tileSize);
|
||||
virtualCenterOffset += (drawDimension - oldDimension).toPoint() / 2;
|
||||
}
|
||||
|
||||
bool mustUpdate = (m_drawDimension != drawDimension ||
|
||||
m_viewRange != viewRange ||
|
||||
m_virtualCenterOffset != virtualCenterOffset ||
|
||||
m_tileSize != tileSize);
|
||||
|
||||
m_visibleDimension = visibleDimension;
|
||||
m_drawDimension = drawDimension;
|
||||
m_tileSize = tileSize;
|
||||
m_viewRange = viewRange;
|
||||
m_virtualCenterOffset = virtualCenterOffset;
|
||||
|
||||
if(mustUpdate)
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
int MapView::getFirstVisibleFloor()
|
||||
{
|
||||
// return forced first visible floor
|
||||
if(m_lockedFirstVisibleFloor != -1)
|
||||
return m_lockedFirstVisibleFloor;
|
||||
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
// avoid rendering multifloors in far views
|
||||
if(m_viewRange >= FAR_VIEW)
|
||||
return cameraPosition.z;
|
||||
|
||||
// if nothing is limiting the view, the first visible floor is 0
|
||||
int firstFloor = 0;
|
||||
|
||||
// limits to underground floors while under sea level
|
||||
if(cameraPosition.z > Otc::SEA_FLOOR)
|
||||
firstFloor = std::max(cameraPosition.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::UNDERGROUND_FLOOR);
|
||||
|
||||
// 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.translated(ix, iy);
|
||||
|
||||
// process tiles that we can look through, e.g. windows, doors
|
||||
if((ix == 0 && iy == 0) || (/*(std::abs(ix) != std::abs(iy)) && */g_map.isLookPossible(pos))) {
|
||||
Position upperPos = pos;
|
||||
Position coveredPos = pos;
|
||||
|
||||
while(coveredPos.coveredUp() && upperPos.up() && 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return firstFloor;
|
||||
}
|
||||
|
||||
int MapView::getLastVisibleFloor()
|
||||
{
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
// avoid rendering multifloors in far views
|
||||
if(m_viewRange >= FAR_VIEW)
|
||||
return cameraPosition.z;
|
||||
|
||||
// view only underground floors when below sea level
|
||||
if(cameraPosition.z > Otc::SEA_FLOOR)
|
||||
return cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
|
||||
else
|
||||
return Otc::SEA_FLOOR;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/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 <framework/graphics/declarations.h>
|
||||
#include <framework/luascript/luaobject.h>
|
||||
#include <framework/core/declarations.h>
|
||||
|
||||
class MapView : public LuaObject
|
||||
{
|
||||
enum {
|
||||
// 3840x2160 => 1080p optimized
|
||||
// 2560x1440 => 720p optimized
|
||||
// 1728x972 => 480p optimized
|
||||
DEFAULT_FRAMBUFFER_WIDTH = 2560,
|
||||
DEFAULT_FRAMBUFFER_HEIGHT = 1440,
|
||||
|
||||
NEAR_VIEW_AREA = 32*32,
|
||||
MID_VIEW_AREA = 64*64,
|
||||
FAR_VIEW_AREA = 128*128,
|
||||
MAX_TILE_UPDATES = NEAR_VIEW_AREA*7
|
||||
};
|
||||
|
||||
enum ViewRange {
|
||||
NEAR_VIEW,
|
||||
MID_VIEW,
|
||||
FAR_VIEW,
|
||||
HUGE_VIEW
|
||||
};
|
||||
|
||||
public:
|
||||
MapView();
|
||||
void draw(const Rect& rect);
|
||||
|
||||
private:
|
||||
void updateVisibleTilesCache(int start = 0);
|
||||
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 getViewRange() { return m_viewRange; }
|
||||
bool isAnimated() { return m_animated; }
|
||||
|
||||
Point transformPositionTo2D(const Position& position);
|
||||
|
||||
MapViewPtr asMapView() { return std::static_pointer_cast<MapView>(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;
|
||||
Position m_framebufferCenterPosition;
|
||||
Boolean<true> m_mustUpdateVisibleTilesCache;
|
||||
Boolean<true> m_mustDrawVisibleTilesCache;
|
||||
Boolean<true> m_mustCleanFramebuffer;
|
||||
Boolean<true> m_animated;
|
||||
std::vector<TilePtr> m_cachedVisibleTiles;
|
||||
std::vector<CreaturePtr> m_cachedFloorVisibleCreatures;
|
||||
EventPtr m_updateTilesCacheEvent;
|
||||
CreaturePtr m_followingCreature;
|
||||
FrameBufferPtr m_framebuffer;
|
||||
PainterShaderProgramPtr m_shaderProgram;
|
||||
ViewRange m_viewRange;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -27,73 +27,62 @@
|
|||
#include <framework/core/clock.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
|
||||
Missile::Missile() : Thing()
|
||||
void Missile::draw(const Point& dest, float scaleFactor, bool animate)
|
||||
{
|
||||
m_startTicks = 0;
|
||||
}
|
||||
if(m_id == 0 || !animate)
|
||||
return;
|
||||
|
||||
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);
|
||||
int xPattern = 0, yPattern = 0;
|
||||
if(m_direction == Otc::NorthWest) {
|
||||
xPattern = 0;
|
||||
yPattern = 0;
|
||||
} else if(m_direction == Otc::North) {
|
||||
xPattern = 1;
|
||||
yPattern = 0;
|
||||
} else if(m_direction == Otc::NorthEast) {
|
||||
xPattern = 2;
|
||||
yPattern = 0;
|
||||
} else if(m_direction == Otc::East) {
|
||||
xPattern = 2;
|
||||
yPattern = 1;
|
||||
} else if(m_direction == Otc::SouthEast) {
|
||||
xPattern = 2;
|
||||
yPattern = 2;
|
||||
} else if(m_direction == Otc::South) {
|
||||
xPattern = 1;
|
||||
yPattern = 2;
|
||||
} else if(m_direction == Otc::SouthWest) {
|
||||
xPattern = 0;
|
||||
yPattern = 2;
|
||||
} else if(m_direction == Otc::West) {
|
||||
xPattern = 0;
|
||||
yPattern = 1;
|
||||
} else {
|
||||
xPattern = 1;
|
||||
yPattern = 1;
|
||||
}
|
||||
|
||||
float fraction = m_animationTimer.ticksElapsed() / m_duration;
|
||||
internalDraw(dest + m_delta * fraction * scaleFactor, scaleFactor, xPattern, yPattern, 0, 0);
|
||||
}
|
||||
|
||||
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
||||
{
|
||||
Otc::Direction direction = fromPosition.getDirectionFromPosition(toPosition);
|
||||
m_direction = fromPosition.getDirectionFromPosition(toPosition);
|
||||
|
||||
if(direction == Otc::NorthWest) {
|
||||
m_xPattern = 0;
|
||||
m_yPattern = 0;
|
||||
}
|
||||
else if(direction == Otc::North) {
|
||||
m_xPattern = 1;
|
||||
m_yPattern = 0;
|
||||
}
|
||||
else if(direction == Otc::NorthEast) {
|
||||
m_xPattern = 2;
|
||||
m_yPattern = 0;
|
||||
}
|
||||
else if(direction == Otc::East) {
|
||||
m_xPattern = 2;
|
||||
m_yPattern = 1;
|
||||
}
|
||||
else if(direction == Otc::SouthEast) {
|
||||
m_xPattern = 2;
|
||||
m_yPattern = 2;
|
||||
}
|
||||
else if(direction == Otc::South) {
|
||||
m_xPattern = 1;
|
||||
m_yPattern = 2;
|
||||
}
|
||||
else if(direction == Otc::SouthWest) {
|
||||
m_xPattern = 0;
|
||||
m_yPattern = 2;
|
||||
}
|
||||
else if(direction == Otc::West) {
|
||||
m_xPattern = 0;
|
||||
m_yPattern = 1;
|
||||
}
|
||||
else {
|
||||
m_xPattern = 1;
|
||||
m_yPattern = 1;
|
||||
}
|
||||
|
||||
m_pos = fromPosition;
|
||||
m_posDelta = 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_position = fromPosition;
|
||||
m_delta = Point(toPosition.x - fromPosition.x, toPosition.y - fromPosition.y);
|
||||
m_duration = 150 * std::sqrt(m_delta.length());
|
||||
m_delta *= Otc::TILE_PIXELS;
|
||||
m_animationTimer.restart();
|
||||
|
||||
// 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()
|
||||
void Missile::setId(uint32 id)
|
||||
{
|
||||
return g_thingsType.getThingType(m_id, ThingsType::Missile);
|
||||
m_id = id;
|
||||
m_type = g_thingsType.getThingType(m_id, ThingsType::Missile);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#define SHOT_H
|
||||
|
||||
#include <framework/global.h>
|
||||
#include <framework/core/timer.h>
|
||||
#include "thing.h"
|
||||
|
||||
class Missile : public Thing
|
||||
|
@ -33,22 +34,23 @@ class Missile : public Thing
|
|||
};
|
||||
|
||||
public:
|
||||
Missile();
|
||||
|
||||
void draw(const Point& p, const Rect&);
|
||||
void draw(const Point& dest, float scaleFactor, bool animate);
|
||||
|
||||
void updateAnimation();
|
||||
|
||||
void setId(uint32 id);
|
||||
void setPath(const Position& fromPosition, const Position& toPosition);
|
||||
|
||||
ThingType *getType();
|
||||
uint32 getId() { return m_id; }
|
||||
|
||||
MissilePtr asMissile() { return std::static_pointer_cast<Missile>(shared_from_this()); }
|
||||
|
||||
private:
|
||||
ticks_t m_startTicks;
|
||||
Position m_posDelta;
|
||||
Timer m_animationTimer;
|
||||
Point m_delta;
|
||||
float m_duration;
|
||||
uint16 m_id;
|
||||
Otc::Direction m_direction;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "spritemanager.h"
|
||||
#include <framework/core/resourcemanager.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/graphics/graphics.h>
|
||||
|
||||
SpriteManager g_sprites;
|
||||
|
@ -54,6 +55,21 @@ void SpriteManager::unload()
|
|||
m_signature = 0;
|
||||
}
|
||||
|
||||
void SpriteManager::preloadSprites()
|
||||
{
|
||||
// preload every 100 sprites, periodically
|
||||
const int burst = 50;
|
||||
const int interval = 10;
|
||||
auto preload = [this](int start) {
|
||||
for(int i=start;i<start+burst && i<=m_spritesCount;++i) {
|
||||
loadSpriteTexture(i);
|
||||
}
|
||||
};
|
||||
|
||||
for(int i=1;i<=m_spritesCount;i+=burst)
|
||||
g_dispatcher.scheduleEvent(std::bind(preload, i), (i/burst) * interval);
|
||||
}
|
||||
|
||||
TexturePtr SpriteManager::loadSpriteTexture(int id)
|
||||
{
|
||||
m_fin.seekg(((id-1) * 4) + 6, std::ios_base::beg);
|
||||
|
@ -74,7 +90,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
|
|||
|
||||
uint16 pixelDataSize = Fw::getU16(m_fin);
|
||||
|
||||
uchar pixels[4096];
|
||||
static std::vector<uint8> pixels(4096);
|
||||
int writePos = 0;
|
||||
int read = 0;
|
||||
|
||||
|
@ -116,7 +132,10 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
|
|||
writePos += 4;
|
||||
}
|
||||
|
||||
return TexturePtr(new Texture(32, 32, 4, pixels));
|
||||
TexturePtr spriteTex(new Texture(32, 32, 4, &pixels[0]));
|
||||
spriteTex->setSmooth(true);
|
||||
spriteTex->generateBilinearMipmaps(pixels);
|
||||
return spriteTex;
|
||||
}
|
||||
|
||||
TexturePtr SpriteManager::getSpriteTexture(int id)
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
|
||||
bool load(const std::string& file);
|
||||
void unload();
|
||||
void preloadSprites();
|
||||
|
||||
uint32 getSignature() { return m_signature; }
|
||||
int getSpritesCount() { return m_spritesCount; }
|
||||
|
@ -45,7 +46,7 @@ private:
|
|||
|
||||
Boolean<false> m_loaded;
|
||||
uint32 m_signature;
|
||||
uint16 m_spritesCount;
|
||||
int m_spritesCount;
|
||||
std::stringstream m_fin;
|
||||
std::vector<TexturePtr> m_sprites;
|
||||
TexturePtr m_transparentSprite;
|
||||
|
|
|
@ -31,17 +31,22 @@ 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);
|
||||
|
||||
// draw only if the real center is not too far from the parent center, or its a yell
|
||||
if((boundRect.center() - rect.center()).length() < parentRect.width() / 15 || isYell()) {
|
||||
//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)
|
||||
bool StaticText::addMessage(const std::string& name, Otc::SpeakType type, const std::string& message)
|
||||
{
|
||||
//TODO: this could be moved to lua
|
||||
// First message
|
||||
if(m_messages.size() == 0) {
|
||||
m_name = name;
|
||||
|
@ -59,7 +64,7 @@ bool StaticText::addMessage(const std::string& name, const std::string& type, co
|
|||
auto self = asStaticText();
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->removeMessage();
|
||||
}, std::max<int>(DURATION_PER_CHARACTER * message.length(), MIN_DURATION));
|
||||
}, std::max<int>(Otc::STATIC_DURATION_PER_CHARACTER * message.length(), Otc::MIN_STATIC_TEXT_DURATION));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -72,40 +77,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") {
|
||||
if(m_messageType == Otc::SpeakSay) {
|
||||
text += m_name;
|
||||
text += " says:\n";
|
||||
m_color = Color(239, 239, 0);
|
||||
}
|
||||
else if(m_messageType == "whisper") {
|
||||
} else if(m_messageType == Otc::SpeakWhisper) {
|
||||
text += m_name;
|
||||
text += " whispers:\n";
|
||||
m_color = Color(239, 239, 0);
|
||||
}
|
||||
else if(m_messageType == "yell") {
|
||||
} else if(m_messageType == Otc::SpeakYell) {
|
||||
text += m_name;
|
||||
text += " yells:\n";
|
||||
m_color = Color(239, 239, 0);
|
||||
}
|
||||
else if(m_messageType == "monsterSay" || m_messageType == "monsterYell") {
|
||||
} else if(m_messageType == Otc::SpeakMonsterSay || m_messageType == Otc::SpeakMonsterYell) {
|
||||
m_color = Color(254, 101, 0);
|
||||
}
|
||||
else if(m_messageType == "npcToPlayer") {
|
||||
} else if(m_messageType == Otc::SpeakPrivateNpcToPlayer) {
|
||||
text += m_name;
|
||||
text += " says:\n";
|
||||
m_color = Color(95, 247, 247);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logWarning("unknown speak type: ", m_messageType);
|
||||
}
|
||||
|
||||
|
@ -116,6 +115,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);
|
||||
}
|
||||
|
|
|
@ -29,20 +29,17 @@
|
|||
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; }
|
||||
Otc::SpeakType getMessageType() { return m_messageType; }
|
||||
std::string getFirstMessage() { return m_messages[0]; }
|
||||
|
||||
bool addMessage(const std::string& name, const std::string& type, const std::string& message);
|
||||
bool isYell() { return m_messageType == Otc::SpeakYell || m_messageType == Otc::SpeakMonsterYell; }
|
||||
|
||||
bool addMessage(const std::string& name, Otc::SpeakType type, const std::string& message);
|
||||
void removeMessage();
|
||||
|
||||
StaticTextPtr asStaticText() { return std::static_pointer_cast<StaticText>(shared_from_this()); }
|
||||
|
@ -52,9 +49,10 @@ private:
|
|||
|
||||
FontPtr m_font;
|
||||
Size m_textSize;
|
||||
Boolean<false> m_yell;
|
||||
std::vector<std::string> m_messages;
|
||||
std::string m_name, m_text;
|
||||
std::string m_messageType;
|
||||
Otc::SpeakType m_messageType;
|
||||
Color m_color;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,59 +24,59 @@
|
|||
#include "spritemanager.h"
|
||||
#include "thingstype.h"
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include "map.h"
|
||||
#include "tile.h"
|
||||
|
||||
Thing::Thing()
|
||||
{
|
||||
m_id = 0;
|
||||
m_xPattern = 0;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thing::setId(uint32 id)
|
||||
{
|
||||
m_id = id;
|
||||
m_type = getType();
|
||||
m_type = g_thingsType.getEmptyThingType();
|
||||
}
|
||||
|
||||
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::getTile()
|
||||
{
|
||||
return g_thingsType.getEmptyThingType();
|
||||
return g_map.getTile(m_position);
|
||||
}
|
||||
|
||||
int Thing::getStackpos()
|
||||
{
|
||||
const TilePtr& tile = getTile();
|
||||
if(tile)
|
||||
return tile->getThingStackpos(asThing());
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Thing::internalDraw(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase)
|
||||
{
|
||||
int scaledSize = Otc::TILE_PIXELS * scaleFactor;
|
||||
|
||||
int spriteId = getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animationPhase);
|
||||
if(spriteId) {
|
||||
Rect drawRect(dest - getDisplacement()*scaleFactor, Size(scaledSize, scaledSize));
|
||||
g_painter.setColor(Fw::white);
|
||||
g_painter.drawTexturedRect(drawRect, g_sprites.getSpriteTexture(spriteId));
|
||||
}
|
||||
}
|
||||
|
||||
void Thing::internalDraw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase)
|
||||
{
|
||||
for(int l = 0; l < getLayers(); ++l)
|
||||
for(int w = 0; w < getDimensionWidth(); ++w)
|
||||
for(int h = 0; h < getDimensionHeight(); ++h)
|
||||
internalDraw(dest - Point(w,h)*Otc::TILE_PIXELS*scaleFactor, scaleFactor, w, h, xPattern, yPattern, zPattern, l, animationPhase);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define THING_H
|
||||
|
||||
#include "declarations.h"
|
||||
#include "thingtype.h"
|
||||
#include "thingstype.h"
|
||||
#include <framework/luascript/luaobject.h>
|
||||
|
||||
struct Light
|
||||
|
@ -39,23 +39,17 @@ public:
|
|||
Thing();
|
||||
virtual ~Thing() { }
|
||||
|
||||
virtual void start() {}
|
||||
virtual void startAnimation() { }
|
||||
virtual void draw(const Point& dest, float scaleFactor, bool animate) { }
|
||||
|
||||
virtual void draw(const Point& p, const Rect&) = 0;
|
||||
virtual void setId(uint32 id) { }
|
||||
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; }
|
||||
virtual uint32 getId() { return 0; }
|
||||
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]; }
|
||||
|
||||
void setXPattern(int xPattern) { m_xPattern = xPattern; }
|
||||
void setYPattern(int yPattern) { m_yPattern = yPattern; }
|
||||
void setZPattern(int zPattern) { m_zPattern = zPattern; }
|
||||
const TilePtr& getTile();
|
||||
int getStackpos();
|
||||
|
||||
ThingPtr asThing() { return std::static_pointer_cast<Thing>(shared_from_this()); }
|
||||
virtual ItemPtr asItem() { return nullptr; }
|
||||
|
@ -69,29 +63,55 @@ 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 isTranslucent() { return m_type->properties[ThingType::IsTranslucent]; }
|
||||
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 isAnimateAlways() { return m_type->properties[ThingType::AnimateAlways]; }
|
||||
bool isLyingCorpse() { return m_type->properties[ThingType::IsLyingCorpse]; }
|
||||
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 w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase);
|
||||
void internalDraw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase);
|
||||
|
||||
uint32 m_id;
|
||||
Position m_pos;
|
||||
Position m_position;
|
||||
ThingType *m_type;
|
||||
|
||||
int m_xPattern, m_yPattern, m_zPattern, m_animation;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -115,11 +115,12 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType)
|
|||
|
||||
ThingType *ThingsType::getThingType(uint16 id, Categories category)
|
||||
{
|
||||
assert(id != 0);
|
||||
if(category == Item)
|
||||
id -= 100;
|
||||
else if(category == Creature || category == Effect || category == Missile)
|
||||
id -= 1;
|
||||
assert(id < m_things[category].size());
|
||||
|
||||
if(id == 0 || id >= m_things[category].size())
|
||||
return &m_emptyThingType;
|
||||
return &m_things[category][id];
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ public:
|
|||
uint32 getSignature() { return m_signature; }
|
||||
bool isLoaded() { return m_loaded; }
|
||||
|
||||
uint16 getFirstItemId() { return 100; }
|
||||
uint16 getMaxItemid() { return m_things[Item].size() + 99; }
|
||||
|
||||
private:
|
||||
uint32 m_signature;
|
||||
Boolean<false> m_loaded;
|
||||
|
|
|
@ -33,70 +33,117 @@
|
|||
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, int drawFlags)
|
||||
{
|
||||
m_drawElevation = 0;
|
||||
bool animate = drawFlags & Otc::DrawAnimations;
|
||||
|
||||
// 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])
|
||||
break;
|
||||
thing->draw(p - m_drawElevation, visibleRect);
|
||||
m_drawElevation += type->parameters[ThingType::Elevation];
|
||||
if(m_drawElevation > MAX_DRAW_ELEVATION)
|
||||
m_drawElevation = MAX_DRAW_ELEVATION;
|
||||
if(drawFlags & (Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawOnBottom)) {
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||
break;
|
||||
|
||||
if((thing->isGround() && drawFlags & Otc::DrawGround) ||
|
||||
(thing->isGroundBorder() && drawFlags & Otc::DrawGroundBorders) ||
|
||||
(thing->isOnBottom() && drawFlags & Otc::DrawOnBottom))
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
|
||||
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
}
|
||||
}
|
||||
|
||||
// now common items
|
||||
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])
|
||||
break;
|
||||
thing->draw(p - m_drawElevation, visibleRect);
|
||||
m_drawElevation += type->parameters[ThingType::Elevation];
|
||||
if(m_drawElevation > MAX_DRAW_ELEVATION)
|
||||
m_drawElevation = MAX_DRAW_ELEVATION;
|
||||
int redrawPreviousTopW = 0;
|
||||
int redrawPreviousTopH = 0;
|
||||
|
||||
if(drawFlags & Otc::DrawItems) {
|
||||
// now common items in reverse order
|
||||
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
||||
const ThingPtr& thing = *it;
|
||||
if(thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround() || thing->asCreature())
|
||||
break;
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
|
||||
|
||||
if(thing->isLyingCorpse()) {
|
||||
redrawPreviousTopW = std::max(thing->getDimensionWidth(), redrawPreviousTopW);
|
||||
redrawPreviousTopH = std::max(thing->getDimensionHeight(), redrawPreviousTopH);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
// after we render 2x2 lying corpses, we must redraw previous creatures/ontop above them
|
||||
if(redrawPreviousTopH > 0 || redrawPreviousTopW > 0) {
|
||||
int topRedrawFlags = drawFlags & (Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawOnTop | Otc::DrawAnimations);
|
||||
if(topRedrawFlags) {
|
||||
for(int y=-redrawPreviousTopH;y<=0;++y) {
|
||||
for(int x=-redrawPreviousTopW;x<=0;++x) {
|
||||
if(x == 0 && y == 0)
|
||||
continue;
|
||||
const TilePtr& tile = g_map.getTile(m_position.translated(x,y));
|
||||
if(tile)
|
||||
tile->draw(dest + Point(x*Otc::TILE_PIXELS, y*Otc::TILE_PIXELS)*scaleFactor, scaleFactor, topRedrawFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creatures
|
||||
if(drawFlags & Otc::DrawCreatures) {
|
||||
if(animate) {
|
||||
for(const CreaturePtr& creature : m_walkingCreatures) {
|
||||
creature->draw(Point(dest.x + ((creature->getPosition().x - m_position.x)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor,
|
||||
dest.y + ((creature->getPosition().y - m_position.y)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor), scaleFactor, animate);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
||||
CreaturePtr creature = (*it)->asCreature();
|
||||
if(creature && (!creature->isWalking() || !animate))
|
||||
creature->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
|
||||
}
|
||||
}
|
||||
|
||||
// effects
|
||||
for(const EffectPtr& effect : m_effects)
|
||||
effect->draw(p - m_drawElevation, visibleRect);
|
||||
if(drawFlags & Otc::DrawEffects) {
|
||||
for(const EffectPtr& effect : m_effects)
|
||||
effect->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate);
|
||||
}
|
||||
|
||||
// top items
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
ThingType *type = thing->getType();
|
||||
if(type->properties[ThingType::IsOnTop])
|
||||
thing->draw(p, visibleRect);
|
||||
if(drawFlags & Otc::DrawOnTop) {
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
if(thing->isOnTop())
|
||||
thing->draw(dest, scaleFactor, animate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tile::clean()
|
||||
{
|
||||
m_things.clear();
|
||||
m_effects.clear();
|
||||
while(!m_things.empty())
|
||||
removeThing(m_things.front());
|
||||
}
|
||||
|
||||
void Tile::addWalkingCreature(const CreaturePtr& creature)
|
||||
{
|
||||
m_walkingCreatures.push_back(creature);
|
||||
}
|
||||
|
||||
void Tile::removeWalkingCreature(const CreaturePtr& creature)
|
||||
{
|
||||
auto it = std::find(m_walkingCreatures.begin(), m_walkingCreatures.end(), creature);
|
||||
if(it != m_walkingCreatures.end())
|
||||
m_walkingCreatures.erase(it);
|
||||
}
|
||||
|
||||
ThingPtr Tile::addThing(const ThingPtr& thing, int stackPos)
|
||||
|
@ -124,9 +171,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(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 +228,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<CreaturePtr> Tile::getCreatures()
|
||||
{
|
||||
std::vector<CreaturePtr> creatures;
|
||||
|
@ -192,8 +243,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 +263,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 +289,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 +338,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 +351,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 +360,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 +374,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 +391,27 @@ bool Tile::isClickable()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Tile::isEmpty()
|
||||
{
|
||||
return m_things.size() == 0;
|
||||
}
|
||||
|
||||
bool Tile::mustHookEast()
|
||||
{
|
||||
for(const ThingPtr& thing : m_things)
|
||||
if(thing->isHookEast())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Tile::mustHookSouth()
|
||||
{
|
||||
for(const ThingPtr& thing : m_things)
|
||||
if(thing->isHookSouth())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Tile::hasCreature()
|
||||
{
|
||||
for(const ThingPtr& thing : m_things)
|
||||
|
@ -358,7 +420,17 @@ 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;
|
||||
}
|
||||
|
||||
bool Tile::canErase()
|
||||
{
|
||||
return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,22 +28,22 @@
|
|||
|
||||
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, int drawFlags);
|
||||
|
||||
public:
|
||||
void clean();
|
||||
|
||||
void addWalkingCreature(const CreaturePtr& creature);
|
||||
void removeWalkingCreature(const CreaturePtr& creature);
|
||||
|
||||
ThingPtr addThing(const ThingPtr& thing, int stackPos = -1);
|
||||
bool removeThing(ThingPtr thing);
|
||||
ThingPtr getThing(int stackPos);
|
||||
int getThingStackpos(const ThingPtr& thing);
|
||||
ThingPtr getTopThing();
|
||||
ThingPtr removeThingByStackpos(int stackPos);
|
||||
ThingPtr removeThing(const ThingPtr& thing);
|
||||
|
||||
|
||||
ThingPtr getTopLookThing();
|
||||
ThingPtr getTopUseThing();
|
||||
|
@ -51,26 +51,33 @@ public:
|
|||
ThingPtr getTopMoveThing();
|
||||
ThingPtr getTopMultiUseThing();
|
||||
|
||||
const Position& getPos() { return m_pos; }
|
||||
const Position& getPosition() { return m_position; }
|
||||
int getDrawElevation() { return m_drawElevation; }
|
||||
std::vector<CreaturePtr> getCreatures();
|
||||
const std::vector<ThingPtr>& getThings() { return m_things; }
|
||||
ItemPtr getGround();
|
||||
int getGroundSpeed();
|
||||
int getThingCount() { return m_things.size() + m_effects.size(); }
|
||||
bool isWalkable();
|
||||
bool isFullGround();
|
||||
bool isFullyOpaque();
|
||||
bool isLookPossible();
|
||||
bool hasCreature();
|
||||
bool isEmpty();
|
||||
bool isClickable();
|
||||
bool isEmpty();
|
||||
bool mustHookSouth();
|
||||
bool mustHookEast();
|
||||
bool hasCreature();
|
||||
bool limitsFloorsView();
|
||||
bool canErase();
|
||||
|
||||
TilePtr asTile() { return std::static_pointer_cast<Tile>(shared_from_this()); }
|
||||
|
||||
private:
|
||||
std::vector<EffectPtr> m_effects; // Leave this outside m_things because it has no stackpos.
|
||||
std::vector<CreaturePtr> m_walkingCreatures;
|
||||
std::vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
|
||||
std::vector<ThingPtr> m_things;
|
||||
Position m_pos;
|
||||
int m_drawElevation;
|
||||
Position m_position;
|
||||
uint8 m_drawElevation;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,12 +58,12 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction("g_sprites", "load", std::bind(&SpriteManager::load, &g_sprites, _1));
|
||||
g_lua.bindClassStaticFunction("g_sprites", "isLoaded", std::bind(&SpriteManager::isLoaded, &g_sprites));
|
||||
g_lua.bindClassStaticFunction("g_sprites", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites));
|
||||
g_lua.bindClassStaticFunction("g_sprites", "preloadSprites", std::bind(&SpriteManager::preloadSprites, &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 +72,9 @@ 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.bindClassStaticFunction("g_map", "getSpectators", std::bind(&Map::getSpectators, &g_map, _1, _2));
|
||||
|
||||
g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor);
|
||||
|
||||
|
@ -91,14 +87,11 @@ void OTClient::registerLuaFunctions()
|
|||
|
||||
g_lua.registerClass<Thing>();
|
||||
g_lua.bindClassMemberFunction<Thing>("setId", &Thing::setId);
|
||||
g_lua.bindClassMemberFunction<Thing>("setPos", &Thing::setPos);
|
||||
g_lua.bindClassMemberFunction<Thing>("setPosition", &Thing::setPosition);
|
||||
g_lua.bindClassMemberFunction<Thing>("getId", &Thing::getId);
|
||||
g_lua.bindClassMemberFunction<Thing>("getPos", &Thing::getPos);
|
||||
g_lua.bindClassMemberFunction<Thing>("getPosition", &Thing::getPosition);
|
||||
g_lua.bindClassMemberFunction<Thing>("getStackPriority", &Thing::getStackPriority);
|
||||
g_lua.bindClassMemberFunction<Thing>("getAnimationPhases", &Thing::getAnimationPhases);
|
||||
g_lua.bindClassMemberFunction<Thing>("setXPattern", &Thing::setXPattern);
|
||||
g_lua.bindClassMemberFunction<Thing>("setYPattern", &Thing::setYPattern);
|
||||
g_lua.bindClassMemberFunction<Thing>("setZPattern", &Thing::setZPattern);
|
||||
g_lua.bindClassMemberFunction<Thing>("asThing", &Thing::asThing);
|
||||
g_lua.bindClassMemberFunction<Thing>("asItem", &Thing::asItem);
|
||||
g_lua.bindClassMemberFunction<Thing>("asCreature", &Thing::asCreature);
|
||||
|
@ -118,8 +111,11 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<Thing>("isRotateable", &Thing::isRotateable);
|
||||
g_lua.bindClassMemberFunction<Thing>("isNotMoveable", &Thing::isNotMoveable);
|
||||
g_lua.bindClassMemberFunction<Thing>("isPickupable", &Thing::isPickupable);
|
||||
g_lua.bindClassMemberFunction<Thing>("ignoreLook", &Thing::ignoreLook);
|
||||
g_lua.bindClassMemberFunction<Thing>("isIgnoreLook", &Thing::isIgnoreLook);
|
||||
g_lua.bindClassMemberFunction<Thing>("isStackable", &Thing::isStackable);
|
||||
g_lua.bindClassMemberFunction<Thing>("isHookSouth", &Thing::isHookSouth);
|
||||
g_lua.bindClassMemberFunction<Thing>("isTranslucent", &Thing::isTranslucent);
|
||||
g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround);
|
||||
|
||||
g_lua.registerClass<Creature, Thing>();
|
||||
g_lua.bindClassMemberFunction<Creature>("getName", &Creature::getName);
|
||||
|
@ -133,7 +129,7 @@ void OTClient::registerLuaFunctions()
|
|||
|
||||
g_lua.registerClass<Item, Thing>();
|
||||
g_lua.bindClassStaticFunction<Item>("create", &Item::create);
|
||||
g_lua.bindClassMemberFunction<Item>("getData", &Item::getData);
|
||||
g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount);
|
||||
|
||||
g_lua.registerClass<Effect, Thing>();
|
||||
g_lua.registerClass<Missile, Thing>();
|
||||
|
@ -141,6 +137,7 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.registerClass<AnimatedText, Thing>();
|
||||
|
||||
g_lua.registerClass<Player, Creature>();
|
||||
g_lua.bindClassMemberFunction<Creature>("isWalking", &Creature::isWalking);
|
||||
g_lua.registerClass<Npc, Creature>();
|
||||
g_lua.registerClass<Monster, Creature>();
|
||||
g_lua.registerClass<LocalPlayer, Player>();
|
||||
|
@ -165,14 +162,13 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<Tile>("getThing", &Tile::getThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("getThingStackpos", &Tile::getThingStackpos);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopThing", &Tile::getTopThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("removeThingByStackpos", &Tile::removeThingByStackpos);
|
||||
g_lua.bindClassMemberFunction<Tile>("removeThing", &Tile::removeThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopLookThing", &Tile::getTopLookThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopUseThing", &Tile::getTopUseThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopCreature", &Tile::getTopCreature);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopMoveThing", &Tile::getTopMoveThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopMultiUseThing", &Tile::getTopMultiUseThing);
|
||||
g_lua.bindClassMemberFunction<Tile>("getPos", &Tile::getPos);
|
||||
g_lua.bindClassMemberFunction<Tile>("getPosition", &Tile::getPosition);
|
||||
g_lua.bindClassMemberFunction<Tile>("getDrawElevation", &Tile::getDrawElevation);
|
||||
g_lua.bindClassMemberFunction<Tile>("getCreatures", &Tile::getCreatures);
|
||||
g_lua.bindClassMemberFunction<Tile>("getGround", &Tile::getGround);
|
||||
|
@ -194,6 +190,9 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction<Game>("requestOutfit", std::bind(&Game::requestOutfit, &g_game));
|
||||
g_lua.bindClassStaticFunction<Game>("requestChannels", std::bind(&Game::requestChannels, &g_game));
|
||||
g_lua.bindClassStaticFunction<Game>("joinChannel", std::bind(&Game::joinChannel, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("leaveChannel", std::bind(&Game::leaveChannel, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("closeNpcChannel", std::bind(&Game::closeNpcChannel, &g_game));
|
||||
g_lua.bindClassStaticFunction<Game>("openPrivateChannel", std::bind(&Game::openPrivateChannel, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("setOutfit", std::bind(&Game::setOutfit, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("look", std::bind(&Game::look, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("open", std::bind(&Game::open, &g_game, _1, _2));
|
||||
|
@ -201,6 +200,7 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction<Game>("useWith", std::bind(&Game::useWith, &g_game, _1, _2));
|
||||
g_lua.bindClassStaticFunction<Game>("move", std::bind(&Game::move, &g_game, _1, _2, _3));
|
||||
g_lua.bindClassStaticFunction<Game>("useInventoryItem", std::bind(&Game::useInventoryItem, &g_game, _1, _2));
|
||||
g_lua.bindClassStaticFunction<Game>("turn", std::bind(&Game::turn, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("walk", std::bind(&Game::walk, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("forceWalk", std::bind(&Game::forceWalk, &g_game, _1));
|
||||
g_lua.bindClassStaticFunction<Game>("attack", std::bind(&Game::attack, &g_game, _1));
|
||||
|
@ -226,9 +226,16 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction<Game>("getProtocolGame", std::bind(&Game::getProtocolGame, &g_game));
|
||||
|
||||
g_lua.registerClass<UIItem, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIItem>("create", []{ return UIItemPtr(new UIItem); } );
|
||||
g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem);
|
||||
g_lua.bindClassStaticFunction<UIItem>("create", []{ return UIItemPtr(new UIItem); });
|
||||
g_lua.bindClassMemberFunction<UIItem>("setItemId", &UIItem::setItemId);
|
||||
g_lua.bindClassMemberFunction<UIItem>("setItemCount", &UIItem::setItemCount);
|
||||
g_lua.bindClassMemberFunction<UIItem>("setItem", &UIItem::setItem);
|
||||
g_lua.bindClassMemberFunction<UIItem>("setVirtual", &UIItem::setVirtual);
|
||||
g_lua.bindClassMemberFunction<UIItem>("getItemId", &UIItem::getItemId);
|
||||
g_lua.bindClassMemberFunction<UIItem>("getItemCount", &UIItem::getItemCount);
|
||||
g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem);
|
||||
g_lua.bindClassMemberFunction<UIItem>("isVirtual", &UIItem::isVirtual);
|
||||
|
||||
|
||||
g_lua.registerClass<UICreature, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UICreature>("create", []{ return UICreaturePtr(new UICreature); } );
|
||||
|
@ -238,6 +245,8 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.registerClass<UIMap, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); } );
|
||||
g_lua.bindClassMemberFunction<UIMap>("getTile", &UIMap::getTile);
|
||||
g_lua.bindClassMemberFunction<UIMap>("zoomIn", &UIMap::zoomIn);
|
||||
g_lua.bindClassMemberFunction<UIMap>("zoomOut", &UIMap::zoomOut);
|
||||
|
||||
g_lua.registerClass<UIGame, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIGame>("create", []{ return UIGamePtr(new UIGame); } );
|
||||
|
|
|
@ -123,7 +123,7 @@ namespace Proto {
|
|||
GameServerTalk = 170,
|
||||
GameServerChannels = 171,
|
||||
GameServerOpenChannel = 172,
|
||||
GameServerPrivateChannel = 173,
|
||||
GameServerOpenPrivateChannel = 173,
|
||||
GameServerRuleViolationChannel = 174, // deprecated in last tibia
|
||||
GameServerRuleViolationRemove = 175, // deprecated in last tibia
|
||||
GameServerRuleViolationCancel = 176, // deprecated in last tibia
|
||||
|
@ -190,7 +190,7 @@ namespace Proto {
|
|||
ClientGetChannels = 151,
|
||||
ClientJoinChannel = 152,
|
||||
ClientLeaveChannel = 153,
|
||||
ClientPrivateChannel = 154,
|
||||
ClientOpenPrivateChannel = 154,
|
||||
ClientCloseNpcChannel = 158,
|
||||
ClientSetTactics = 160,
|
||||
ClientAttack = 161,
|
||||
|
@ -238,29 +238,29 @@ namespace Proto {
|
|||
SpeakMonsterYell,
|
||||
|
||||
// removed
|
||||
SpeakRVRChannel = 255,
|
||||
SpeakRVRAnswer,
|
||||
SpeakRVRContinue,
|
||||
SpeakChannelRed2
|
||||
ServerSpeakRVRChannel = 255,
|
||||
ServerSpeakRVRAnswer,
|
||||
ServerSpeakRVRContinue,
|
||||
ServerSpeakChannelRed2
|
||||
#elif PROTOCOL==860
|
||||
SpeakSay = 1,
|
||||
SpeakWhisper,
|
||||
SpeakYell,
|
||||
SpeakPrivatePlayerToNpc,
|
||||
SpeakPrivateNpcToPlayer,
|
||||
SpeakPrivate,
|
||||
SpeakChannelYellow,
|
||||
SpeakChannelWhite,
|
||||
SpeakRVRChannel,
|
||||
SpeakRVRAnswer,
|
||||
SpeakRVRContinue,
|
||||
SpeakBroadcast,
|
||||
SpeakChannelRed,
|
||||
SpeakPrivateRed,
|
||||
SpeakChannelOrange,
|
||||
SpeakChannelRed2 = 17,
|
||||
SpeakMonsterSay = 19,
|
||||
SpeakMonsterYell
|
||||
ServerSpeakSay = 1,
|
||||
ServerSpeakWhisper,
|
||||
ServerSpeakYell,
|
||||
ServerSpeakPrivatePlayerToNpc,
|
||||
ServerSpeakPrivateNpcToPlayer,
|
||||
ServerSpeakPrivate,
|
||||
ServerSpeakChannelYellow,
|
||||
ServerSpeakChannelWhite,
|
||||
ServerSpeakRVRChannel,
|
||||
ServerSpeakRVRAnswer,
|
||||
ServerSpeakRVRContinue,
|
||||
ServerSpeakBroadcast,
|
||||
ServerSpeakChannelRed,
|
||||
ServerSpeakPrivateRed,
|
||||
ServerSpeakChannelOrange,
|
||||
ServerSpeakChannelRed2 = 17,
|
||||
ServerSpeakMonsterSay = 19,
|
||||
ServerSpeakMonsterYell
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -299,48 +299,48 @@ namespace Proto {
|
|||
NpcEndId = 0xffffffff
|
||||
};
|
||||
|
||||
inline std::string translateSpeakType(int type) {
|
||||
inline Otc::SpeakType translateSpeakTypeFromServer(int type) {
|
||||
switch(type) {
|
||||
case Proto::SpeakSay: return "say";
|
||||
case Proto::SpeakWhisper: return "whisper";
|
||||
case Proto::SpeakYell: return "yell";
|
||||
case Proto::SpeakMonsterSay: return "monsterSay";
|
||||
case Proto::SpeakMonsterYell: return "monsterYell";
|
||||
case Proto::SpeakPrivateNpcToPlayer: return "npcToPlayer";
|
||||
case Proto::SpeakChannelYellow: return "channelYellow";
|
||||
case Proto::SpeakChannelWhite: return "channelWhite";
|
||||
case Proto::SpeakChannelRed: return "channelRed";
|
||||
case Proto::SpeakChannelRed2: return "channelRed";
|
||||
case Proto::SpeakChannelOrange: return "channelOrange";
|
||||
case Proto::SpeakPrivate: return "private";
|
||||
case Proto::SpeakPrivatePlayerToNpc: return "playerToNpc";
|
||||
case Proto::SpeakBroadcast: return "broadcast";
|
||||
case Proto::SpeakPrivateRed: return "privateRed";
|
||||
case Proto::ServerSpeakSay: return Otc::SpeakSay;
|
||||
case Proto::ServerSpeakWhisper: return Otc::SpeakWhisper;
|
||||
case Proto::ServerSpeakYell: return Otc::SpeakYell;
|
||||
case Proto::ServerSpeakMonsterSay: return Otc::SpeakMonsterSay;
|
||||
case Proto::ServerSpeakMonsterYell: return Otc::SpeakMonsterYell;
|
||||
case Proto::ServerSpeakPrivateNpcToPlayer: return Otc::SpeakPrivateNpcToPlayer;
|
||||
case Proto::ServerSpeakChannelYellow: return Otc::SpeakChannelYellow;
|
||||
case Proto::ServerSpeakChannelWhite: return Otc::SpeakChannelWhite;
|
||||
case Proto::ServerSpeakChannelRed: return Otc::SpeakChannelRed;
|
||||
case Proto::ServerSpeakChannelRed2: return Otc::SpeakChannelRed;
|
||||
case Proto::ServerSpeakChannelOrange: return Otc::SpeakChannelOrange;
|
||||
case Proto::ServerSpeakPrivate: return Otc::SpeakPrivate;
|
||||
case Proto::ServerSpeakPrivatePlayerToNpc: return Otc::SpeakPrivate;
|
||||
case Proto::ServerSpeakBroadcast: return Otc::SpeakBroadcast;
|
||||
case Proto::ServerSpeakPrivateRed: return Otc::SpeakPrivateRed;
|
||||
default:
|
||||
logError("unknown protocol speak type ", type);
|
||||
return "unknown";
|
||||
return Otc::SpeakSay;
|
||||
}
|
||||
}
|
||||
|
||||
inline int translateSpeakTypeDesc(const std::string& type) {
|
||||
if(type == "say") return Proto::SpeakSay;
|
||||
else if(type == "whisper") return Proto::SpeakWhisper;
|
||||
else if(type == "yell") return Proto::SpeakYell;
|
||||
else if(type == "monsterSay") return Proto::SpeakMonsterSay;
|
||||
else if(type == "monsterYell") return Proto::SpeakMonsterYell;
|
||||
else if(type == "npcToPlayer") return Proto::SpeakPrivateNpcToPlayer;
|
||||
else if(type == "channelYellow") return Proto::SpeakChannelYellow;
|
||||
else if(type == "channelWhite") return Proto::SpeakChannelWhite;
|
||||
else if(type == "channelRed") return Proto::SpeakChannelRed;
|
||||
else if(type == "channelRed") return Proto::SpeakChannelRed2;
|
||||
else if(type == "channelOrange") return Proto::SpeakChannelOrange;
|
||||
else if(type == "private") return Proto::SpeakPrivate;
|
||||
else if(type == "playerToNpc") return Proto::SpeakPrivatePlayerToNpc;
|
||||
else if(type == "broadcast") return Proto::SpeakBroadcast;
|
||||
else if(type == "privateRed") return Proto::SpeakPrivateRed;
|
||||
else {
|
||||
logError("unknown protocol speak type desc ", type);
|
||||
return 0;
|
||||
inline Proto::ServerSpeakType translateSpeakTypeToServer(int type) {
|
||||
switch(type) {
|
||||
case Otc::SpeakSay: return Proto::ServerSpeakSay;
|
||||
case Otc::SpeakWhisper: return Proto::ServerSpeakWhisper;
|
||||
case Otc::SpeakYell: return Proto::ServerSpeakYell;
|
||||
case Otc::SpeakBroadcast: return Proto::ServerSpeakBroadcast;
|
||||
case Otc::SpeakPrivate: return Proto::ServerSpeakPrivate;
|
||||
case Otc::SpeakPrivateRed: return Proto::ServerSpeakPrivateRed;
|
||||
case Otc::SpeakPrivatePlayerToNpc: return Proto::ServerSpeakPrivatePlayerToNpc;
|
||||
case Otc::SpeakPrivateNpcToPlayer: return Proto::ServerSpeakPrivateNpcToPlayer;
|
||||
case Otc::SpeakChannelYellow: return Proto::ServerSpeakChannelYellow;
|
||||
case Otc::SpeakChannelWhite: return Proto::ServerSpeakChannelWhite;
|
||||
case Otc::SpeakChannelRed: return Proto::ServerSpeakChannelRed;
|
||||
case Otc::SpeakChannelOrange: return Proto::ServerSpeakChannelOrange;
|
||||
case Otc::SpeakMonsterSay: return Proto::ServerSpeakMonsterSay;
|
||||
case Otc::SpeakMonsterYell: return Proto::ServerSpeakMonsterYell;
|
||||
default:
|
||||
logError("unknown protocol speak type desc ", type);
|
||||
return Proto::ServerSpeakSay;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,11 +73,11 @@ public:
|
|||
void sendTextWindow(uint windowTextId, const std::string& text);
|
||||
void sendHouseWindow(int doorId, uint id, const std::string& text);
|
||||
void sendLookAt(const Position& position, int thingId, int stackpos);
|
||||
void sendTalk(const std::string& speakTypeDesc, int channelId, const std::string& receiver, const std::string& message);
|
||||
void sendTalk(Otc::SpeakType speakType, int channelId, const std::string& receiver, const std::string& message);
|
||||
void sendGetChannels();
|
||||
void sendJoinChannel(int channelId);
|
||||
void sendLeaveChannel(int channelId);
|
||||
void sendPrivateChannel(const std::string& receiver);
|
||||
void sendOpenPrivateChannel(const std::string& receiver);
|
||||
void sendCloseNpcChannel();
|
||||
void sendFightTatics(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight);
|
||||
void sendAttack(uint creatureId);
|
||||
|
@ -155,9 +155,9 @@ private:
|
|||
void parseCreatureSpeak(InputMessage& msg);
|
||||
void parseChannelList(InputMessage& msg);
|
||||
void parseOpenChannel(InputMessage& msg);
|
||||
void parseOpenPrivatePlayerChat(InputMessage& msg);
|
||||
void parseCreatePrivateChannel(InputMessage& msg);
|
||||
void parseClosePrivateChannel(InputMessage& msg);
|
||||
void parseOpenPrivateChannel(InputMessage& msg);
|
||||
void parseCreateOwnPrivateChannel(InputMessage& msg);
|
||||
void parseCloseChannel(InputMessage& msg);
|
||||
void parseSafeTradeRequest(InputMessage& msg);
|
||||
void parseSafeTradeClose(InputMessage&);
|
||||
void parseTextMessage(InputMessage& msg);
|
||||
|
|
|
@ -195,8 +195,8 @@ void ProtocolGame::parseMessage(InputMessage& msg)
|
|||
case Proto::GameServerOpenChannel:
|
||||
parseOpenChannel(msg);
|
||||
break;
|
||||
case Proto::GameServerPrivateChannel:
|
||||
parseOpenPrivatePlayerChat(msg);
|
||||
case Proto::GameServerOpenPrivateChannel:
|
||||
parseOpenPrivateChannel(msg);
|
||||
break;
|
||||
case Proto::GameServerRuleViolationChannel:
|
||||
msg.getU16();
|
||||
|
@ -210,10 +210,10 @@ void ProtocolGame::parseMessage(InputMessage& msg)
|
|||
case Proto::GameServerRuleViolationLock:
|
||||
break;
|
||||
case Proto::GameServerOpenOwnChannel:
|
||||
parseCreatePrivateChannel(msg);
|
||||
parseCreateOwnPrivateChannel(msg);
|
||||
break;
|
||||
case Proto::GameServerCloseChannel:
|
||||
parseClosePrivateChannel(msg);
|
||||
parseCloseChannel(msg);
|
||||
break;
|
||||
case Proto::GameServerMessage:
|
||||
parseTextMessage(msg);
|
||||
|
@ -317,7 +317,7 @@ void ProtocolGame::parseMapDescription(InputMessage& msg)
|
|||
{
|
||||
Position pos = parsePosition(msg);
|
||||
g_map.setCentralPosition(pos);
|
||||
setMapDescription(msg, pos.x - 8, pos.y - 6, pos.z, 18, 14);
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseMoveNorth(InputMessage& msg)
|
||||
|
@ -325,7 +325,7 @@ void ProtocolGame::parseMoveNorth(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
pos.y--;
|
||||
|
||||
setMapDescription(msg, pos.x - 8, pos.y - 6, pos.z, 18, 1);
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, 1);
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ void ProtocolGame::parseMoveEast(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
pos.x++;
|
||||
|
||||
setMapDescription(msg, pos.x + 9, pos.y - 6, pos.z, 1, 14);
|
||||
setMapDescription(msg, pos.x + Otc::AWARE_X_RIGHT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ void ProtocolGame::parseMoveSouth(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
pos.y++;
|
||||
|
||||
setMapDescription(msg, pos.x - 8, pos.y + 7, pos.z, 18, 1);
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y + Otc::AWARE_Y_BOTTOM_TILES, pos.z, Otc::AWARE_X_TILES, 1);
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
|
@ -352,7 +352,7 @@ void ProtocolGame::parseMoveWest(InputMessage& msg)
|
|||
Position pos = g_map.getCentralPosition();
|
||||
pos.x--;
|
||||
|
||||
setMapDescription(msg, pos.x - 8, pos.y - 6, pos.z, 1, 14);
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -720,43 +720,43 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg)
|
|||
msg.getU32(); // unkSpeak
|
||||
std::string name = msg.getString();
|
||||
int level = msg.getU16();
|
||||
int type = msg.getU8();
|
||||
int serverType = msg.getU8();
|
||||
int channelId = 0;
|
||||
Position creaturePos;
|
||||
|
||||
switch(type) {
|
||||
case Proto::SpeakSay:
|
||||
case Proto::SpeakWhisper:
|
||||
case Proto::SpeakYell:
|
||||
case Proto::SpeakMonsterSay:
|
||||
case Proto::SpeakMonsterYell:
|
||||
case Proto::SpeakPrivateNpcToPlayer:
|
||||
switch(serverType) {
|
||||
case Proto::ServerSpeakSay:
|
||||
case Proto::ServerSpeakWhisper:
|
||||
case Proto::ServerSpeakYell:
|
||||
case Proto::ServerSpeakMonsterSay:
|
||||
case Proto::ServerSpeakMonsterYell:
|
||||
case Proto::ServerSpeakPrivateNpcToPlayer:
|
||||
creaturePos = parsePosition(msg);
|
||||
break;
|
||||
case Proto::SpeakChannelYellow:
|
||||
case Proto::SpeakChannelWhite:
|
||||
case Proto::SpeakChannelRed:
|
||||
case Proto::SpeakChannelRed2:
|
||||
case Proto::SpeakChannelOrange:
|
||||
case Proto::ServerSpeakChannelYellow:
|
||||
case Proto::ServerSpeakChannelWhite:
|
||||
case Proto::ServerSpeakChannelRed:
|
||||
case Proto::ServerSpeakChannelRed2:
|
||||
case Proto::ServerSpeakChannelOrange:
|
||||
channelId = msg.getU16();
|
||||
break;
|
||||
case Proto::SpeakPrivate:
|
||||
case Proto::SpeakPrivatePlayerToNpc:
|
||||
case Proto::SpeakBroadcast:
|
||||
case Proto::SpeakPrivateRed:
|
||||
case Proto::ServerSpeakPrivate:
|
||||
case Proto::ServerSpeakPrivatePlayerToNpc:
|
||||
case Proto::ServerSpeakBroadcast:
|
||||
case Proto::ServerSpeakPrivateRed:
|
||||
break;
|
||||
case Proto::SpeakRVRChannel:
|
||||
case Proto::ServerSpeakRVRChannel:
|
||||
msg.getU32();
|
||||
break;
|
||||
default:
|
||||
logTraceError("unknown speak type ", type);
|
||||
logTraceError("unknown speak type ", serverType);
|
||||
break;
|
||||
}
|
||||
|
||||
std::string message = msg.getString();
|
||||
std::string typeDesc = Proto::translateSpeakType(type);
|
||||
Otc::SpeakType type = Proto::translateSpeakTypeFromServer(serverType);
|
||||
|
||||
g_game.processCreatureSpeak(name, level, typeDesc, message, channelId, creaturePos);
|
||||
g_game.processCreatureSpeak(name, level, type, message, channelId, creaturePos);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseChannelList(InputMessage& msg)
|
||||
|
@ -780,20 +780,26 @@ void ProtocolGame::parseOpenChannel(InputMessage& msg)
|
|||
g_lua.callGlobalField("Game", "onOpenChannel", channelId, name);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseOpenPrivatePlayerChat(InputMessage& msg)
|
||||
void ProtocolGame::parseOpenPrivateChannel(InputMessage& msg)
|
||||
{
|
||||
msg.getString(); // name
|
||||
std::string name = msg.getString();
|
||||
|
||||
g_lua.callGlobalField("Game", "onOpenPrivateChannel", name);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseCreatePrivateChannel(InputMessage& msg)
|
||||
void ProtocolGame::parseCreateOwnPrivateChannel(InputMessage& msg)
|
||||
{
|
||||
msg.getU16(); // channel id
|
||||
msg.getString(); // channel name
|
||||
int id = msg.getU16(); // channel id
|
||||
std::string name = msg.getString(); // channel name
|
||||
|
||||
g_lua.callGlobalField("Game", "onOpenOwnPrivateChannel", id, name);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseClosePrivateChannel(InputMessage& msg)
|
||||
void ProtocolGame::parseCloseChannel(InputMessage& msg)
|
||||
{
|
||||
msg.getU16(); // channel id
|
||||
int id = msg.getU16(); // channel id
|
||||
|
||||
g_lua.callGlobalField("Game", "onCloseChannel", id);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseTextMessage(InputMessage& msg)
|
||||
|
@ -819,11 +825,11 @@ void ProtocolGame::parseFloorChangeUp(InputMessage& msg)
|
|||
pos.z--;
|
||||
|
||||
int skip = 0;
|
||||
if(pos.z == 7)
|
||||
for(int i = 5; i >= 0; i--)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, i, 18, 14, 8 - i, &skip);
|
||||
else if(pos.z > 7)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, pos.z - 2, 18, 14, 3, &skip);
|
||||
if(pos.z == Otc::SEA_FLOOR)
|
||||
for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
|
||||
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 8 - i, &skip);
|
||||
else if(pos.z > Otc::SEA_FLOOR)
|
||||
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 3, &skip);
|
||||
|
||||
pos.x++;
|
||||
pos.y++;
|
||||
|
@ -836,13 +842,13 @@ void ProtocolGame::parseFloorChangeDown(InputMessage& msg)
|
|||
pos.z++;
|
||||
|
||||
int skip = 0;
|
||||
if(pos.z == 8) {
|
||||
if(pos.z == Otc::UNDERGROUND_FLOOR) {
|
||||
int j, i;
|
||||
for(i = pos.z, j = -1; i < pos.z + 3; ++i, --j)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, i, 18, 14, j, &skip);
|
||||
for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
|
||||
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, j, &skip);
|
||||
}
|
||||
else if(pos.z > 8 && pos.z < 14)
|
||||
setFloorDescription(msg, pos.x - 8, pos.y - 6, pos.z + 2, 18, 14, -3, &skip);
|
||||
else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
|
||||
setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, -3, &skip);
|
||||
|
||||
pos.x--;
|
||||
pos.y--;
|
||||
|
@ -866,7 +872,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);
|
||||
|
@ -931,13 +937,13 @@ void ProtocolGame::setMapDescription(InputMessage& msg, int32 x, int32 y, int32
|
|||
{
|
||||
int startz, endz, zstep, skip = 0;
|
||||
|
||||
if(z > 7) {
|
||||
startz = z - 2;
|
||||
endz = (15 < z+2) ? 15 : z+2;
|
||||
if(z > Otc::SEA_FLOOR) {
|
||||
startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
|
||||
endz = std::min(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
|
||||
zstep = 1;
|
||||
}
|
||||
else {
|
||||
startz = 7;
|
||||
startz = Otc::SEA_FLOOR;
|
||||
endz = 0;
|
||||
zstep = -1;
|
||||
}
|
||||
|
@ -952,13 +958,17 @@ void ProtocolGame::setFloorDescription(InputMessage& msg, int32 x, int32 y, int3
|
|||
|
||||
for(int nx = 0; nx < width; nx++) {
|
||||
for(int ny = 0; ny < height; ny++) {
|
||||
Position tilePos(x + nx + offset, y + ny + offset, z);
|
||||
|
||||
// clean pre stored tiles
|
||||
g_map.cleanTile(tilePos);
|
||||
|
||||
if(skip == 0) {
|
||||
int tileOpt = msg.getU16(true);
|
||||
if(tileOpt >= 0xFF00)
|
||||
skip = (msg.getU16() & 0xFF);
|
||||
else {
|
||||
Position pos(x + nx + offset, y + ny + offset, z);
|
||||
setTileDescription(msg, pos);
|
||||
setTileDescription(msg, tilePos);
|
||||
skip = (msg.getU16() & 0xFF);
|
||||
}
|
||||
}
|
||||
|
@ -1041,7 +1051,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 +1075,8 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
|||
|
||||
creature->setId(id);
|
||||
creature->setName(name);
|
||||
|
||||
g_map.addCreature(creature);
|
||||
}
|
||||
|
||||
uint8 healthPercent = msg.getU8();
|
||||
|
@ -1119,7 +1131,7 @@ ItemPtr ProtocolGame::internalGetItem(InputMessage& msg, int id)
|
|||
|
||||
ItemPtr item = Item::create(id);
|
||||
if(item->isStackable() || item->isFluidContainer() || item->isFluid())
|
||||
item->setData(msg.getU8());
|
||||
item->setCountOrSubType(msg.getU8());
|
||||
|
||||
return item;
|
||||
}
|
||||
|
|
|
@ -341,24 +341,24 @@ void ProtocolGame::sendLookAt(const Position& position, int thingId, int stackpo
|
|||
send(oMsg);
|
||||
}
|
||||
|
||||
void ProtocolGame::sendTalk(const std::string& speakTypeDesc, int channelId, const std::string& receiver, const std::string& message)
|
||||
void ProtocolGame::sendTalk(Otc::SpeakType speakType, int channelId, const std::string& receiver, const std::string& message)
|
||||
{
|
||||
if(message.length() > 255 || message.length() <= 0)
|
||||
return;
|
||||
|
||||
int speakType = Proto::translateSpeakTypeDesc(speakTypeDesc);
|
||||
int serverSpeakType = Proto::translateSpeakTypeToServer(speakType);
|
||||
|
||||
OutputMessage oMsg;
|
||||
oMsg.addU8(Proto::ClientTalk);
|
||||
oMsg.addU8(speakType);
|
||||
oMsg.addU8(serverSpeakType);
|
||||
|
||||
switch(speakType) {
|
||||
case Proto::SpeakPrivate:
|
||||
case Proto::SpeakPrivateRed:
|
||||
switch(serverSpeakType) {
|
||||
case Proto::ServerSpeakPrivate:
|
||||
case Proto::ServerSpeakPrivateRed:
|
||||
oMsg.addString(receiver);
|
||||
break;
|
||||
case Proto::SpeakChannelYellow:
|
||||
case Proto::SpeakChannelRed:
|
||||
case Proto::ServerSpeakChannelYellow:
|
||||
case Proto::ServerSpeakChannelRed:
|
||||
oMsg.addU16(channelId);
|
||||
break;
|
||||
}
|
||||
|
@ -390,10 +390,10 @@ void ProtocolGame::sendLeaveChannel(int channelId)
|
|||
send(oMsg);
|
||||
}
|
||||
|
||||
void ProtocolGame::sendPrivateChannel(const std::string& receiver)
|
||||
void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
|
||||
{
|
||||
OutputMessage oMsg;
|
||||
oMsg.addU8(Proto::ClientPrivateChannel);
|
||||
oMsg.addU8(Proto::ClientOpenPrivateChannel);
|
||||
oMsg.addString(receiver);
|
||||
send(oMsg);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <framework/core/modulemanager.h>
|
||||
#include "core/game.h"
|
||||
#include <framework/core/resourcemanager.h>
|
||||
#include "core/map.h"
|
||||
|
||||
OTClient::OTClient(const std::string& appName) : Application(appName)
|
||||
{
|
||||
|
@ -40,6 +41,8 @@ void OTClient::init(const std::vector<std::string>& args)
|
|||
g_modules.ensureModuleLoaded("client");
|
||||
g_modules.autoLoadModules(1000);
|
||||
|
||||
g_map.load();
|
||||
|
||||
// load otclientrc.lua
|
||||
if(g_resources.fileExists("/otclientrc.lua")) {
|
||||
try {
|
||||
|
|
|
@ -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, false);
|
||||
}
|
||||
|
||||
drawChildren();
|
||||
|
|
|
@ -32,6 +32,7 @@ bool UIGame::onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter)
|
|||
|
||||
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("consoleLineEdit"));
|
||||
|
||||
//TODO: move this whole shit to lua
|
||||
if(keyboardModifiers == Fw::KeyboardNoModifier) {
|
||||
if(keyCode == Fw::KeyUp || keyCode == Fw::KeyNumpad8) {
|
||||
g_game.walk(Otc::North);
|
||||
|
|
|
@ -38,10 +38,10 @@ 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, true);
|
||||
|
||||
if(m_font && m_item->isStackable() && m_item->getData() > 1) {
|
||||
std::string count = Fw::tostring(m_item->getData());
|
||||
if(m_font && m_item->isStackable() && m_item->getCount() > 1) {
|
||||
std::string count = Fw::tostring(m_item->getCount());
|
||||
m_font->renderText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight, Color(231, 231, 231));
|
||||
}
|
||||
|
||||
|
@ -51,3 +51,30 @@ void UIItem::draw()
|
|||
|
||||
drawChildren();
|
||||
}
|
||||
|
||||
void UIItem::setItemId(int id)
|
||||
{
|
||||
if(!m_item)
|
||||
m_item = Item::create(id);
|
||||
else {
|
||||
// remove item
|
||||
if(id == 0)
|
||||
m_item = nullptr;
|
||||
else
|
||||
m_item->setId(id);
|
||||
}
|
||||
}
|
||||
|
||||
void UIItem::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
|
||||
{
|
||||
UIWidget::onStyleApply(styleName, styleNode);
|
||||
|
||||
for(const OTMLNodePtr& node : styleNode->children()) {
|
||||
if(node->tag() == "item-id")
|
||||
setItemId(node->value<int>());
|
||||
else if(node->tag() == "item-count")
|
||||
setItemCount(node->value<int>());
|
||||
else if(node->tag() == "virtual")
|
||||
setVirtual(node->value<bool>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,12 +33,24 @@ public:
|
|||
UIItem();
|
||||
void draw();
|
||||
|
||||
void setItemId(int id);
|
||||
void setItemCount(int count) { if(m_item) m_item->setCount(count); }
|
||||
void setItemSubType(int subType) { if(m_item) m_item->setSubType(subType); }
|
||||
void setItem(const ItemPtr& item) { m_item = item; }
|
||||
void setVirtual(bool virt) { m_virtual = virt; }
|
||||
void clearItem() { setItemId(0); }
|
||||
|
||||
int getItemId() { return m_item ? m_item->getId() : 0; }
|
||||
int getItemCount() { return m_item ? m_item->getCount() : 0; }
|
||||
int getItemSubType() { return m_item ? m_item->getSubType() : 0; }
|
||||
ItemPtr getItem() { return m_item; }
|
||||
bool isVirtual() { return m_virtual; }
|
||||
|
||||
protected:
|
||||
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
|
||||
|
||||
ItemPtr m_item;
|
||||
Boolean<false> m_virtual;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "uimap.h"
|
||||
#include <otclient/core/game.h>
|
||||
#include <otclient/core/map.h>
|
||||
#include <otclient/core/mapview.h>
|
||||
#include <framework/otml/otml.h>
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <otclient/core/localplayer.h>
|
||||
|
@ -30,21 +31,79 @@
|
|||
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 map 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()
|
||||
{
|
||||
int dimensionHeight = m_mapView->getVisibleDimension().height() * 0.99;
|
||||
if(dimensionHeight == m_mapView->getVisibleDimension().height())
|
||||
dimensionHeight -= 1;
|
||||
if(dimensionHeight % 2 == 0)
|
||||
dimensionHeight -= 1;
|
||||
int dimensionWidth = dimensionHeight * getSize().ratio();
|
||||
if(dimensionWidth % 2 == 0)
|
||||
dimensionWidth -= 1;
|
||||
|
||||
m_mapView->setVisibleDimension(Size(dimensionWidth, dimensionHeight));
|
||||
|
||||
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()
|
||||
{
|
||||
int dimensionHeight = m_mapView->getVisibleDimension().height() * 1.01;
|
||||
if(dimensionHeight == m_mapView->getVisibleDimension().height())
|
||||
dimensionHeight += 1;
|
||||
if(dimensionHeight % 2 == 0)
|
||||
dimensionHeight += 1;
|
||||
int dimensionWidth = dimensionHeight * getSize().ratio();
|
||||
if(dimensionWidth % 2 == 0)
|
||||
dimensionWidth += 1;
|
||||
|
||||
m_mapView->setVisibleDimension(Size(dimensionWidth, dimensionHeight));
|
||||
|
||||
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::setCameraPosition(const Position& pos)
|
||||
{
|
||||
m_mapView->setCameraPosition(pos);
|
||||
}
|
||||
|
||||
TilePtr UIMap::getTile(const Point& mousePos)
|
||||
{
|
||||
/*
|
||||
if(!m_mapRect.contains(mousePos))
|
||||
return nullptr;
|
||||
|
||||
|
@ -55,12 +114,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 +129,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 +143,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);
|
||||
|
|
|
@ -31,14 +31,21 @@ class UIMap : public UIWidget
|
|||
{
|
||||
public:
|
||||
UIMap();
|
||||
~UIMap();
|
||||
|
||||
void draw();
|
||||
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
void setCameraPosition(const Position& pos);
|
||||
|
||||
TilePtr getTile(const Point& mousePos);
|
||||
|
||||
protected:
|
||||
virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect);
|
||||
|
||||
private:
|
||||
MapViewPtr m_mapView;
|
||||
Rect m_mapRect;
|
||||
};
|
||||
|
||||
|
|
|
@ -30,51 +30,99 @@
|
|||
class Position
|
||||
{
|
||||
public:
|
||||
Position() : x(-1), y(-1), z(-1) { }
|
||||
Position(int x, int y, int z) : x(x), y(y), z(z) { }
|
||||
Position() : x(65535), y(65535), z(255) { }
|
||||
Position(uint16 x, uint16 y, uint8 z) : x(x), y(y), z(z) { }
|
||||
|
||||
static Position getPosFromDirection(Otc::Direction direction) {
|
||||
Position translatedToDirection(Otc::Direction direction) {
|
||||
Position pos = *this;
|
||||
switch(direction) {
|
||||
case Otc::North:
|
||||
return Position( 0, -1, 0);
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::East:
|
||||
return Position( 1, 0, 0);
|
||||
pos.x++;
|
||||
break;
|
||||
case Otc::South:
|
||||
return Position( 0, 1, 0);
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::West:
|
||||
return Position(-1, 0, 0);
|
||||
pos.x--;
|
||||
break;
|
||||
case Otc::NorthEast:
|
||||
return Position( 1, -1, 0);
|
||||
pos.x++;
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::SouthEast:
|
||||
return Position( 1, 1, 0);
|
||||
pos.x++;
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::SouthWest:
|
||||
return Position(-1, 1, 0);
|
||||
pos.x--;
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::NorthWest:
|
||||
return Position(-1, -1, 0);
|
||||
default:
|
||||
return Position();
|
||||
pos.x--;
|
||||
pos.y--;
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
Position translatedToReverseDirection(Otc::Direction direction) {
|
||||
Position pos = *this;
|
||||
switch(direction) {
|
||||
case Otc::North:
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::East:
|
||||
pos.x--;
|
||||
break;
|
||||
case Otc::South:
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::West:
|
||||
pos.x++;
|
||||
break;
|
||||
case Otc::NorthEast:
|
||||
pos.x--;
|
||||
pos.y++;
|
||||
break;
|
||||
case Otc::SouthEast:
|
||||
pos.x--;
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::SouthWest:
|
||||
pos.x++;
|
||||
pos.y--;
|
||||
break;
|
||||
case Otc::NorthWest:
|
||||
pos.x++;
|
||||
pos.y++;
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
Otc::Direction getDirectionFromPosition(const Position& position) const {
|
||||
Position positionDelta = position - *this;
|
||||
int dx = position.x - x;
|
||||
int dy = position.y - y;
|
||||
|
||||
if(positionDelta.x == 0 && positionDelta.y == 0)
|
||||
if(dx == 0 && dy == 0)
|
||||
return Otc::InvalidDirection;
|
||||
else if(positionDelta.x == 0) {
|
||||
if(positionDelta.y < 0)
|
||||
else if(dx == 0) {
|
||||
if(dy < 0)
|
||||
return Otc::North;
|
||||
else if(positionDelta.y > 0)
|
||||
else if(dy > 0)
|
||||
return Otc::South;
|
||||
}
|
||||
else if(positionDelta.y == 0) {
|
||||
if(positionDelta.x < 0)
|
||||
else if(dy == 0) {
|
||||
if(dx < 0)
|
||||
return Otc::West;
|
||||
else if(positionDelta.x > 0)
|
||||
else if(dx > 0)
|
||||
return Otc::East;
|
||||
}
|
||||
else {
|
||||
float angle = std::atan2(positionDelta.y * -1, positionDelta.x) * RAD_TO_DEC;
|
||||
float angle = std::atan2(dy * -1, dx) * RAD_TO_DEC;
|
||||
if(angle < 0)
|
||||
angle += 360;
|
||||
|
||||
|
@ -98,7 +146,10 @@ public:
|
|||
return Otc::InvalidDirection;
|
||||
}
|
||||
|
||||
bool isValid() const { return x >= 0 && y >= 0 && z >= 0 && x <= 65535 && y <= 65535 && z <= 255; }
|
||||
bool isValid() const { return !(x == 65535 && y == 65535 && z == 255); }
|
||||
|
||||
void translate(int dx, int dy, short dz = 0) { x += dx; y += dy; z += dz; }
|
||||
Position translated(int dx, int dy, short dz = 0) const { Position pos = *this; pos.x += dx; pos.y += dy; pos.z += dz; return pos; }
|
||||
|
||||
Position operator+(const Position& other) const { return Position(x + other.x, y + other.y, z + other.z); }
|
||||
Position& operator+=(const Position& other) { x+=other.x; y+=other.y; z +=other.z; return *this; }
|
||||
|
@ -109,19 +160,50 @@ public:
|
|||
bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }
|
||||
bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; }
|
||||
|
||||
bool isInRange(const Position& pos, int xdif, int ydif, int zdif = 1) const {
|
||||
return std::abs(x-pos.x) <= xdif && std::abs(y-pos.y) <= ydif && std::abs(pos.z-z) <= zdif;
|
||||
bool isInRange(const Position& pos, int xRange, int yRange) const { return std::abs(x-pos.x) <= xRange && std::abs(y-pos.y) <= yRange && z == pos.z; }
|
||||
bool isInRange(const Position& pos, int minXRange, int maxXRange, int minYRange, int maxYRange) const {
|
||||
return (pos.x >= x-minXRange && pos.x <= x+maxXRange && pos.y >= y-minYRange && pos.y <= y+maxYRange && pos.z == z);
|
||||
}
|
||||
|
||||
void up(int n = 1) { z-=n; }
|
||||
void down(int n = 1) { z+=n; }
|
||||
bool up(int n = 1) {
|
||||
int nz = z-n;
|
||||
if(nz >= 0 && nz <= Otc::MAX_Z) {
|
||||
z = nz;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void perspectiveUp(int n = 1) { x+=n; y+=n; z-=n; }
|
||||
void coveredDown(int n = 1) { x-=n; y-=n; z+=n; }
|
||||
bool down(int n = 1) {
|
||||
int nz = z+n;
|
||||
if(nz >= 0 && nz <= Otc::MAX_Z) {
|
||||
z = nz;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
bool coveredUp(int n = 1) {
|
||||
int nx = x+n, ny = y+n, nz = z-n;
|
||||
if(nx >= 0 && nx <= 65535 && ny >= 0 && ny <= 65535 && nz >= 0 && nz <= Otc::MAX_Z) {
|
||||
x = nx; y = ny; z = nz;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool coveredDown(int n = 1) {
|
||||
int nx = x-n, ny = y-n, nz = z+n;
|
||||
if(nx >= 0 && nx <= 65535 && ny >= 0 && ny <= 65535 && nz >= 0 && nz <= Otc::MAX_Z) {
|
||||
x = nx; y = ny; z = nz;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 x;
|
||||
uint16 y;
|
||||
uint8 z;
|
||||
};
|
||||
|
||||
struct PositionHasher : std::unary_function<Position, std::size_t> {
|
||||
|
@ -132,13 +214,17 @@ struct PositionHasher : std::unary_function<Position, std::size_t> {
|
|||
|
||||
inline std::ostream& operator<<(std::ostream& out, const Position& pos)
|
||||
{
|
||||
out << pos.x << " " << pos.y << " " << pos.z;
|
||||
out << (int)pos.x << " " << (int)pos.y << " " << (int)pos.z;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::istream& operator>>(std::istream& in, Position& pos)
|
||||
{
|
||||
in >> pos.x >> pos.y >> pos.z;
|
||||
int x, y, z;
|
||||
in >> x >> y >> z;
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = z;
|
||||
return in;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue