rework map rendering
This commit is contained in:
parent
4276bd680d
commit
9db7bd2602
|
@ -13,7 +13,7 @@ local function moveToolTip(tooltip)
|
|||
else
|
||||
pos.x = pos.x + 10
|
||||
end
|
||||
tooltip:setPos(pos)
|
||||
tooltip:setPosition(pos)
|
||||
end
|
||||
|
||||
-- public functions
|
||||
|
|
|
@ -36,10 +36,10 @@ function UIMap:onDrop(widget, mousePos)
|
|||
spinbox:setCurrentIndex(data)
|
||||
|
||||
local okButton = moveWindow:getChildById('buttonOk')
|
||||
okButton.onClick = function() Game.move(widget.currentDragThing, tile:getPos(), spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end
|
||||
okButton.onClick = function() Game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end
|
||||
moveWindow.onEnter = okButton.onClick
|
||||
else
|
||||
Game.move(widget.currentDragThing, tile:getPos(), 1)
|
||||
Game.move(widget.currentDragThing, tile:getPosition(), 1)
|
||||
end
|
||||
|
||||
return true
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -26,6 +26,15 @@
|
|||
|
||||
uint FrameBuffer::boundFbo = 0;
|
||||
|
||||
FrameBuffer::FrameBuffer()
|
||||
{
|
||||
m_clearColor = Fw::alpha;
|
||||
|
||||
glGenFramebuffers(1, &m_fbo);
|
||||
if(!m_fbo)
|
||||
logFatal("Unable to create framebuffer object");
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(const Size& size)
|
||||
{
|
||||
m_clearColor = Fw::alpha;
|
||||
|
@ -44,6 +53,9 @@ FrameBuffer::~FrameBuffer()
|
|||
|
||||
void FrameBuffer::resize(const Size& size)
|
||||
{
|
||||
if(!size.isValid())
|
||||
return;
|
||||
|
||||
if(m_texture && m_texture->getSize() == size)
|
||||
return;
|
||||
|
||||
|
@ -88,6 +100,11 @@ void FrameBuffer::generateMipmaps()
|
|||
m_texture->generateMipmaps();
|
||||
}
|
||||
|
||||
void FrameBuffer::draw(const Rect& dest, const Rect& src)
|
||||
{
|
||||
g_painter.drawTexturedRect(dest, m_texture, src);
|
||||
}
|
||||
|
||||
void FrameBuffer::draw(const Rect& dest)
|
||||
{
|
||||
g_painter.drawTexturedRect(dest, m_texture);
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
#define FRAMEBUFFER_H
|
||||
|
||||
#include "declarations.h"
|
||||
#include "texture.h"
|
||||
|
||||
class FrameBuffer
|
||||
{
|
||||
public:
|
||||
FrameBuffer();
|
||||
FrameBuffer(const Size& size);
|
||||
virtual ~FrameBuffer();
|
||||
|
||||
|
@ -36,10 +38,12 @@ public:
|
|||
void release();
|
||||
void generateMipmaps();
|
||||
void draw(const Rect& dest);
|
||||
void draw(const Rect& dest, const Rect& src);
|
||||
|
||||
void setClearColor(const Color& color) { m_clearColor = color; }
|
||||
|
||||
TexturePtr getTexture() { return m_texture; }
|
||||
const Size& getSize() { return m_texture->getSize(); }
|
||||
|
||||
private:
|
||||
void internalBind();
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -128,6 +128,70 @@ std::vector<uint8> Texture::getPixels()
|
|||
return pixels;
|
||||
}
|
||||
|
||||
void Texture::generateBilinearMipmaps()
|
||||
{
|
||||
std::vector<uint8> inPixels = getPixels();
|
||||
|
||||
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 = outPixels;
|
||||
inSize /= 2;
|
||||
outSize /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::setupFilters()
|
||||
{
|
||||
GLint minFilter;
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
void bind() { glBindTexture(GL_TEXTURE_2D, m_textureId); }
|
||||
|
||||
void generateMipmaps();
|
||||
void generateBilinearMipmaps();
|
||||
void setSmooth(bool smooth);
|
||||
GLuint getId() { return m_textureId; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -409,7 +409,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction("g_window", "getWidth", std::bind(&PlatformWindow::getWidth, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getHeight", std::bind(&PlatformWindow::getHeight, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getUnmaximizedPos", std::bind(&PlatformWindow::getUnmaximizedPos, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getPos", std::bind(&PlatformWindow::getPos, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getPosition", std::bind(&PlatformWindow::getPosition, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getX", std::bind(&PlatformWindow::getX, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getY", std::bind(&PlatformWindow::getY, &g_window));
|
||||
g_lua.bindClassStaticFunction("g_window", "getMousePos", std::bind(&PlatformWindow::getMousePos, &g_window));
|
||||
|
|
|
@ -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,10 +52,14 @@ 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; }
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
BUFFER_MAXSIZE = 16384,
|
||||
HEADER_POS = 0,
|
||||
HEADER_LENGTH = 2,
|
||||
CHECKSUM_POS = 2,
|
||||
CHECKSUm_position = 2,
|
||||
CHECKSUM_LENGTH = 4,
|
||||
DATA_POS = 6,
|
||||
UNENCRYPTED_DATA_POS = 8
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
BUFFER_MAXSIZE = 1024,
|
||||
HEADER_POS = 0,
|
||||
HEADER_LENGTH = 2,
|
||||
CHECKSUM_POS = 2,
|
||||
CHECKSUm_position = 2,
|
||||
CHECKSUM_LENGTH = 4,
|
||||
DATA_POS = 6
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ void Protocol::send(OutputMessage& outputMessage)
|
|||
|
||||
// set checksum
|
||||
uint32 checksum = getAdlerChecksum(outputMessage.getBuffer() + OutputMessage::DATA_POS, outputMessage.getMessageSize());
|
||||
outputMessage.setWritePos(OutputMessage::CHECKSUM_POS);
|
||||
outputMessage.setWritePos(OutputMessage::CHECKSUm_position);
|
||||
outputMessage.addU32(checksum);
|
||||
|
||||
// set size
|
||||
|
@ -107,7 +107,7 @@ void Protocol::internalRecvHeader(uint8* buffer, uint16 size)
|
|||
|
||||
void Protocol::internalRecvData(uint8* buffer, uint16 size)
|
||||
{
|
||||
memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUM_POS, buffer, size);
|
||||
memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUm_position, buffer, size);
|
||||
|
||||
if(m_checksumEnabled) {
|
||||
uint32 checksum = getAdlerChecksum(m_inputMessage.getBuffer() + InputMessage::DATA_POS, m_inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH);
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,36 @@ namespace Otc
|
|||
static const char* AppCompactName = "otclient";
|
||||
static const char* AppVersion = "0.4.0";
|
||||
|
||||
enum {
|
||||
TILE_PIXELS = 32,
|
||||
SEA_LEVEL = 7,
|
||||
MAX_Z = 15,
|
||||
VISIBLE_X_TILES = 15,
|
||||
VISIBLE_Y_TILES = 11,
|
||||
MAX_ELEVATION = 24,
|
||||
EFFECT_TICKS_PER_FRAME = 75,
|
||||
ITEM_TICKS_PER_FRAME = 500,
|
||||
ANIMATED_TEXT_DURATION = 1000,
|
||||
STATIC_DURATION_PER_CHARACTER = 75,
|
||||
MIN_STATIC_TEXT_DURATION = 3000,
|
||||
MAX_STATIC_TEXT_WIDTH = 200,
|
||||
};
|
||||
|
||||
enum MapDrawFlags {
|
||||
MapDrawNonMoveableItems = 1,
|
||||
MapDrawMoveableItems = 2,
|
||||
MapDrawCreatures = 4,
|
||||
MapDrawCreaturesInformation = 8,
|
||||
MapDrawStaticTexts = 16,
|
||||
MapDrawAnimatedTexts = 32,
|
||||
MapDrawEffects = 64,
|
||||
MapDrawMissiles = 128,
|
||||
MapDrawEverything = MapDrawNonMoveableItems | MapDrawMoveableItems |
|
||||
MapDrawCreatures | MapDrawCreaturesInformation |
|
||||
MapDrawStaticTexts | MapDrawAnimatedTexts |
|
||||
MapDrawEffects | MapDrawMissiles
|
||||
};
|
||||
|
||||
enum DatOpts {
|
||||
DatGround = 0,
|
||||
DatGroundClip,
|
||||
|
|
|
@ -31,27 +31,28 @@ 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);
|
||||
}
|
||||
|
||||
void AnimatedText::draw(const Point& p, const Rect& visibleRect)
|
||||
{
|
||||
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))
|
||||
if(visibleRect.contains(rect)) {
|
||||
//TODO: cache into a framebuffer
|
||||
m_font->renderText(m_text, rect, Fw::AlignLeft, m_color);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatedText::startAnimation()
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_color = Color::from8bit(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_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
|
||||
|
|
|
@ -63,16 +63,19 @@ int LEGS_COLOR_UNIFORM = 12;
|
|||
int FEET_COLOR_UNIFORM = 13;
|
||||
int MASK_TEXTURE_UNIFORM = 14;
|
||||
|
||||
void Creature::draw(const Point& p, const Rect&)
|
||||
void Creature::draw(const Point& dest, float scaleFactor)
|
||||
{
|
||||
int scaledTileSize = Otc::TILE_PIXELS * scaleFactor;
|
||||
Point scaledWalkOffset = m_walkOffset * scaleFactor;
|
||||
|
||||
if(m_showVolatileSquare) {
|
||||
g_painter.setColor(m_volatileSquareColor);
|
||||
g_painter.drawBoundingRect(Rect(p + m_walkOffset - Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]) + 3, Size(28, 28)), 2);
|
||||
g_painter.drawBoundingRect(Rect(dest + scaledWalkOffset - (getDisplacement() + 3)*scaleFactor, Size(28*scaleFactor, 28*scaleFactor)), 2*scaleFactor);
|
||||
}
|
||||
|
||||
if(m_showStaticSquare) {
|
||||
g_painter.setColor(m_staticSquareColor);
|
||||
g_painter.drawBoundingRect(Rect(p + m_walkOffset - Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]) + 1, Size(32, 32)), 2);
|
||||
g_painter.drawBoundingRect(Rect(dest + scaledWalkOffset - (getDisplacement() + 1)*scaleFactor, Size(scaledTileSize, scaledTileSize)), 2*scaleFactor);
|
||||
}
|
||||
|
||||
g_painter.setColor(Fw::white);
|
||||
|
@ -90,7 +93,7 @@ void Creature::draw(const Point& p, const Rect&)
|
|||
|
||||
// Render creature
|
||||
if(m_outfit.getCategory() == ThingsType::Creature) {
|
||||
for(m_yPattern = 0; m_yPattern < m_type->dimensions[ThingType::PatternY]; m_yPattern++) {
|
||||
for(m_yPattern = 0; m_yPattern < getNumPatternsY(); m_yPattern++) {
|
||||
|
||||
// continue if we dont have this addon.
|
||||
if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1))))
|
||||
|
@ -104,24 +107,24 @@ void Creature::draw(const Point& p, const Rect&)
|
|||
outfitProgram->setUniformValue(LEGS_COLOR_UNIFORM, m_outfit.getLegsColor());
|
||||
outfitProgram->setUniformValue(FEET_COLOR_UNIFORM, m_outfit.getFeetColor());
|
||||
|
||||
for(int h = 0; h < m_type->dimensions[ThingType::Height]; h++) {
|
||||
for(int w = 0; w < m_type->dimensions[ThingType::Width]; w++) {
|
||||
int spriteId = m_type->getSpriteId(w, h, 0, m_xPattern, m_yPattern, m_zPattern, m_animation);
|
||||
for(int h = 0; h < getDimensionHeight(); h++) {
|
||||
for(int w = 0; w < getDimensionWidth(); w++) {
|
||||
int spriteId = getSpriteId(w, h, 0, m_xPattern, m_yPattern, m_zPattern, m_animation);
|
||||
if(!spriteId)
|
||||
continue;
|
||||
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
|
||||
if(!spriteTex)
|
||||
continue;
|
||||
|
||||
if(m_type->dimensions[ThingType::Layers] > 1) {
|
||||
int maskId = m_type->getSpriteId(w, h, 1, m_xPattern, m_yPattern, m_zPattern, m_animation);
|
||||
if(getLayers() > 1) {
|
||||
int maskId = getSpriteId(w, h, 1, m_xPattern, m_yPattern, m_zPattern, m_animation);
|
||||
TexturePtr maskTex = g_sprites.getSpriteTexture(maskId);
|
||||
outfitProgram->setUniformTexture(MASK_TEXTURE_UNIFORM, maskTex, 1);
|
||||
}
|
||||
|
||||
Rect drawRect(((p + m_walkOffset).x - w*32) - m_type->parameters[ThingType::DisplacementX],
|
||||
((p + m_walkOffset).y - h*32) - m_type->parameters[ThingType::DisplacementY],
|
||||
32, 32);
|
||||
Rect drawRect((dest.x + scaledWalkOffset.x - w*scaledTileSize) - getDisplacementX()*scaleFactor,
|
||||
(dest.y + scaledWalkOffset.y - h*scaledTileSize) - getDisplacementY()*scaleFactor,
|
||||
scaledTileSize, scaledTileSize);
|
||||
g_painter.drawTexturedRect(drawRect, spriteTex);
|
||||
}
|
||||
}
|
||||
|
@ -130,14 +133,14 @@ void Creature::draw(const Point& p, const Rect&)
|
|||
}
|
||||
}
|
||||
else if(m_outfit.getCategory() == ThingsType::Item) {
|
||||
for(int l = 0; l < m_type->dimensions[ThingType::Layers]; l++)
|
||||
internalDraw(p + m_walkOffset, l);
|
||||
for(int l = 0; l < getLayers(); l++)
|
||||
internalDraw(dest + scaledWalkOffset, scaleFactor, l);
|
||||
}
|
||||
else if(m_outfit.getCategory() == ThingsType::Effect)
|
||||
internalDraw(p + m_walkOffset, 0);
|
||||
internalDraw(dest + scaledWalkOffset, scaleFactor, 0);
|
||||
}
|
||||
|
||||
void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRect)
|
||||
void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect)
|
||||
{
|
||||
Color fillColor = Color(96, 96, 96);
|
||||
|
||||
|
@ -145,16 +148,16 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe
|
|||
fillColor = m_informationColor;
|
||||
|
||||
// calculate main rects
|
||||
Rect backgroundRect = Rect(x-(13.5), y, 27, 4);
|
||||
backgroundRect.bind(visibleRect);
|
||||
Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4);
|
||||
backgroundRect.bind(parentRect);
|
||||
|
||||
Rect textRect = Rect(x - m_nameSize.width() / 2.0, y-12, m_nameSize);
|
||||
textRect.bind(visibleRect);
|
||||
Rect textRect = Rect(point.x - m_nameSize.width() / 2.0, point.y-12, m_nameSize);
|
||||
textRect.bind(parentRect);
|
||||
|
||||
// distance them
|
||||
if(textRect.top() == visibleRect.top())
|
||||
if(textRect.top() == parentRect.top())
|
||||
backgroundRect.moveTop(textRect.top() + 12);
|
||||
if(backgroundRect.bottom() == visibleRect.bottom())
|
||||
if(backgroundRect.bottom() == parentRect.bottom())
|
||||
textRect.moveTop(backgroundRect.top() - 12);
|
||||
|
||||
// health rect is based on background rect, so no worries
|
||||
|
@ -173,15 +176,15 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe
|
|||
|
||||
if(m_skull != Otc::SkullNone && m_skullTexture) {
|
||||
g_painter.setColor(Fw::white);
|
||||
g_painter.drawTexturedRect(Rect(x + 12, y + 5, m_skullTexture->getSize()), m_skullTexture);
|
||||
g_painter.drawTexturedRect(Rect(point.x + 12, point.y + 5, m_skullTexture->getSize()), m_skullTexture);
|
||||
}
|
||||
if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
|
||||
g_painter.setColor(Fw::white);
|
||||
g_painter.drawTexturedRect(Rect(x, y + 5, m_shieldTexture->getSize()), m_shieldTexture);
|
||||
g_painter.drawTexturedRect(Rect(point.x, point.y + 5, m_shieldTexture->getSize()), m_shieldTexture);
|
||||
}
|
||||
if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
|
||||
g_painter.setColor(Fw::white);
|
||||
g_painter.drawTexturedRect(Rect(x + 12, y + 16, m_emblemTexture->getSize()), m_emblemTexture);
|
||||
g_painter.drawTexturedRect(Rect(point.x + 12, point.y + 16, m_emblemTexture->getSize()), m_emblemTexture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +212,12 @@ void Creature::walk(const Position& oldPos, const Position& newPos)
|
|||
|
||||
// calculates walk interval
|
||||
float interval = 1000;
|
||||
int groundSpeed = g_map.getTile(oldPos)->getGroundSpeed();
|
||||
int groundSpeed = 0;
|
||||
|
||||
TilePtr oldTile = g_map.getTile(oldPos);
|
||||
if(oldTile)
|
||||
groundSpeed = oldTile->getGroundSpeed();
|
||||
|
||||
if(groundSpeed != 0)
|
||||
interval = (1000.0f * groundSpeed) / m_speed;
|
||||
|
||||
|
@ -248,10 +256,10 @@ void Creature::updateWalkAnimation(int totalPixelsWalked)
|
|||
if(m_outfit.getCategory() != ThingsType::Creature)
|
||||
return;
|
||||
|
||||
if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || m_type->dimensions[ThingType::AnimationPhases] <= 1)
|
||||
if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || getAnimationPhases() <= 1)
|
||||
m_animation = 0;
|
||||
else if(m_type->dimensions[ThingType::AnimationPhases] > 1)
|
||||
m_animation = 1 + ((totalPixelsWalked * 4) / Map::NUM_TILE_PIXELS) % (m_type->dimensions[ThingType::AnimationPhases] - 1);
|
||||
else if(getAnimationPhases() > 1)
|
||||
m_animation = 1 + ((totalPixelsWalked * 4) / Otc::TILE_PIXELS) % (getAnimationPhases() - 1);
|
||||
}
|
||||
|
||||
void Creature::updateWalkOffset(int totalPixelsWalked)
|
||||
|
@ -375,7 +383,7 @@ void Creature::setDirection(Otc::Direction direction)
|
|||
void Creature::setOutfit(const Outfit& outfit)
|
||||
{
|
||||
m_outfit = outfit;
|
||||
m_type = getType();
|
||||
updateType();
|
||||
m_animation = 0;
|
||||
|
||||
if(m_outfit.getCategory() == ThingsType::Effect) {
|
||||
|
@ -389,7 +397,7 @@ void Creature::setOutfit(const Outfit& outfit)
|
|||
m_yPattern = 0;
|
||||
}
|
||||
|
||||
if(m_outfit.getCategory() == ThingsType::Creature && m_type->dimensions[ThingType::Layers] == 1) {
|
||||
if(m_outfit.getCategory() == ThingsType::Creature && getLayers() == 1) {
|
||||
m_outfit.resetClothes();
|
||||
}
|
||||
}
|
||||
|
@ -483,8 +491,5 @@ void Creature::updateShield()
|
|||
m_showShieldTexture = true;
|
||||
}
|
||||
|
||||
ThingType *Creature::getType()
|
||||
{
|
||||
return g_thingsType.getThingType(m_outfit.getId(), m_outfit.getCategory());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ public:
|
|||
Creature();
|
||||
virtual ~Creature() { }
|
||||
|
||||
virtual void draw(const Point& p, const Rect&);
|
||||
void drawInformation(int x, int y, bool useGray, const Rect& visibleRect);
|
||||
virtual void draw(const Point& dest, float scaleFactor);
|
||||
void drawInformation(const Point& point, bool useGray, const Rect& parentRect);
|
||||
|
||||
void setName(const std::string& name);
|
||||
void setHealthPercent(uint8 healthPercent);
|
||||
|
|
|
@ -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,35 @@
|
|||
#include <framework/core/clock.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
|
||||
Effect::Effect() : Thing()
|
||||
void Effect::draw(const Point& dest, float scaleFactor)
|
||||
{
|
||||
m_animationStartTicks = 0;
|
||||
internalDraw(dest, scaleFactor, 0);
|
||||
}
|
||||
|
||||
void Effect::start()
|
||||
void Effect::startAnimation()
|
||||
{
|
||||
m_animationStartTicks = g_clock.ticks();
|
||||
m_animationTimer.restart();
|
||||
|
||||
auto self = asEffect();
|
||||
|
||||
// schedule update
|
||||
if(getAnimationPhases() > 1) {
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->updateAnimation();
|
||||
}, TICKS_PER_FRAME);
|
||||
}
|
||||
// schedule next animation update
|
||||
if(getAnimationPhases() > 1)
|
||||
g_dispatcher.scheduleEvent([self]() { self->updateAnimation(); }, Otc::EFFECT_TICKS_PER_FRAME);
|
||||
|
||||
// schedule removal
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
g_map.removeThing(self);
|
||||
}, TICKS_PER_FRAME * getAnimationPhases());
|
||||
}
|
||||
|
||||
void Effect::draw(const Point& p, const Rect&)
|
||||
{
|
||||
internalDraw(p, 0);
|
||||
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, Otc::EFFECT_TICKS_PER_FRAME * getAnimationPhases());
|
||||
}
|
||||
|
||||
void Effect::updateAnimation()
|
||||
{
|
||||
int animationPhase = (g_clock.ticks() - m_animationStartTicks) / TICKS_PER_FRAME;
|
||||
int animationPhase = m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME;
|
||||
|
||||
if(animationPhase < getAnimationPhases())
|
||||
m_animation = animationPhase;
|
||||
|
||||
if(animationPhase < getAnimationPhases() - 1) {
|
||||
//schedule next animation update
|
||||
auto self = asEffect();
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->updateAnimation();
|
||||
}, TICKS_PER_FRAME);
|
||||
g_dispatcher.scheduleEvent([self]() { self->updateAnimation(); }, Otc::EFFECT_TICKS_PER_FRAME);
|
||||
}
|
||||
}
|
||||
|
||||
ThingType *Effect::getType()
|
||||
{
|
||||
return g_thingsType.getThingType(m_id, ThingsType::Effect);
|
||||
}
|
||||
|
|
|
@ -24,28 +24,21 @@
|
|||
#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);
|
||||
|
||||
Effect();
|
||||
|
||||
void draw(const Point& p, const Rect&);
|
||||
|
||||
void start();
|
||||
void startAnimation();
|
||||
void updateAnimation();
|
||||
|
||||
ThingType *getType();
|
||||
|
||||
EffectPtr asEffect() { return std::static_pointer_cast<Effect>(shared_from_this()); }
|
||||
|
||||
private:
|
||||
ticks_t m_animationStartTicks;
|
||||
Timer m_animationTimer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -186,7 +186,7 @@ void Game::processCreatureSpeak(const std::string& name, int level, const std::s
|
|||
void Game::processContainerAddItem(int containerId, const ItemPtr& item)
|
||||
{
|
||||
if(item)
|
||||
item->setPos(Position(65535, containerId + 0x40, 0));
|
||||
item->setPosition(Position(65535, containerId + 0x40, 0));
|
||||
|
||||
g_lua.callGlobalField("Game", "onContainerAddItem", containerId, item);
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ void Game::processContainerAddItem(int containerId, const ItemPtr& item)
|
|||
void Game::processInventoryChange(int slot, const ItemPtr& item)
|
||||
{
|
||||
if(item)
|
||||
item->setPos(Position(65535, slot, 0));
|
||||
item->setPosition(Position(65535, slot, 0));
|
||||
|
||||
g_lua.callGlobalField("Game","onInventoryChange", slot, item);
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ void Game::walk(Otc::Direction direction)
|
|||
}*/
|
||||
|
||||
// only do prewalk to walkable tiles
|
||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPos() + Position::getPosFromDirection(direction));
|
||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition() + Position::getPositionFromDirection(direction));
|
||||
if(toTile && toTile->isWalkable())
|
||||
m_localPlayer->preWalk(direction);
|
||||
else
|
||||
|
@ -316,7 +316,7 @@ void Game::look(const ThingPtr& thing)
|
|||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
if(stackpos != -1)
|
||||
m_protocolGame->sendLookAt(thing->getPos(), thing->getId(), stackpos);
|
||||
m_protocolGame->sendLookAt(thing->getPosition(), thing->getId(), stackpos);
|
||||
}
|
||||
|
||||
void Game::open(const ThingPtr& thing, int containerId)
|
||||
|
@ -326,7 +326,7 @@ void Game::open(const ThingPtr& thing, int containerId)
|
|||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
if(stackpos != -1)
|
||||
m_protocolGame->sendUseItem(thing->getPos(), thing->getId(), stackpos, containerId);
|
||||
m_protocolGame->sendUseItem(thing->getPosition(), thing->getId(), stackpos, containerId);
|
||||
}
|
||||
|
||||
void Game::use(const ThingPtr& thing)
|
||||
|
@ -338,7 +338,7 @@ void Game::use(const ThingPtr& thing)
|
|||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
if(stackpos != -1)
|
||||
m_protocolGame->sendUseItem(thing->getPos(), thing->getId(), stackpos, 0);
|
||||
m_protocolGame->sendUseItem(thing->getPosition(), thing->getId(), stackpos, 0);
|
||||
}
|
||||
|
||||
void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing)
|
||||
|
@ -346,7 +346,7 @@ void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing)
|
|||
if(!isOnline() || !fromThing || !toThing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
Position pos = fromThing->getPos();
|
||||
Position pos = fromThing->getPosition();
|
||||
int fromStackpos = getThingStackpos(fromThing);
|
||||
if(fromStackpos == -1)
|
||||
return;
|
||||
|
@ -360,7 +360,7 @@ void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing)
|
|||
if(toStackpos == -1)
|
||||
return;
|
||||
|
||||
m_protocolGame->sendUseItemEx(pos, fromThing->getId(), fromStackpos, toThing->getPos(), toThing->getId(), toStackpos);
|
||||
m_protocolGame->sendUseItemEx(pos, fromThing->getId(), fromStackpos, toThing->getPosition(), toThing->getId(), toStackpos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,13 +379,13 @@ void Game::useInventoryItem(int itemId, const ThingPtr& toThing)
|
|||
if(CreaturePtr creature = toThing->asCreature()) {
|
||||
m_protocolGame->sendUseOnCreature(pos, itemId, 0, creature->getId());
|
||||
} else {
|
||||
m_protocolGame->sendUseItemEx(pos, itemId, 0, toThing->getPos(), toThing->getId(), toStackpos);
|
||||
m_protocolGame->sendUseItemEx(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toStackpos);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::move(const ThingPtr& thing, const Position& toPos, int count)
|
||||
{
|
||||
if(!isOnline() || !thing || !checkBotProtection() || thing->getPos() == toPos || count <= 0)
|
||||
if(!isOnline() || !thing || !checkBotProtection() || thing->getPosition() == toPos || count <= 0)
|
||||
return;
|
||||
|
||||
m_localPlayer->lockWalk();
|
||||
|
@ -394,7 +394,7 @@ void Game::move(const ThingPtr& thing, const Position& toPos, int count)
|
|||
if(stackpos == -1)
|
||||
return;
|
||||
|
||||
m_protocolGame->sendThrow(thing->getPos(), thing->getId(), stackpos, toPos, count);
|
||||
m_protocolGame->sendThrow(thing->getPosition(), thing->getId(), stackpos, toPos, count);
|
||||
}
|
||||
|
||||
void Game::attack(const CreaturePtr& creature)
|
||||
|
@ -433,6 +433,9 @@ void Game::follow(const CreaturePtr& creature)
|
|||
|
||||
void Game::cancelFollow()
|
||||
{
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
|
||||
m_localPlayer->setFollowingCreature(nullptr);
|
||||
m_protocolGame->sendFollow(0);
|
||||
}
|
||||
|
@ -444,16 +447,15 @@ void Game::rotate(const ThingPtr& thing)
|
|||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
if(stackpos != -1)
|
||||
m_protocolGame->sendRotateItem(thing->getPos(), thing->getId(), stackpos);
|
||||
m_protocolGame->sendRotateItem(thing->getPosition(), thing->getId(), stackpos);
|
||||
}
|
||||
|
||||
//TODO: move this to Thing class
|
||||
int Game::getThingStackpos(const ThingPtr& thing)
|
||||
{
|
||||
// thing is at map
|
||||
if(thing->getPos().x != 65535) {
|
||||
TilePtr tile = g_map.getTile(thing->getPos());
|
||||
if(tile)
|
||||
if(thing->getPosition().x != 65535) {
|
||||
if(TilePtr tile = g_map.getTile(thing->getPosition()))
|
||||
return tile->getThingStackpos(thing);
|
||||
else {
|
||||
logError("could not get tile");
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#include "thing.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()
|
||||
{
|
||||
|
@ -39,29 +42,40 @@ ItemPtr Item::create(int 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::draw(const Point& dest, float scaleFactor)
|
||||
{
|
||||
if(getAnimationPhases() > 1)
|
||||
m_animation = (g_clock.ticks() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
|
||||
|
||||
if(!itemProgram) {
|
||||
itemProgram = PainterShaderProgramPtr(new PainterShaderProgram);
|
||||
itemProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
||||
itemProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/item.frag");
|
||||
assert(itemProgram->link());
|
||||
}
|
||||
g_painter.setCustomProgram(itemProgram);
|
||||
|
||||
for(int layer = 0; layer < getLayers(); layer++)
|
||||
internalDraw(dest, scaleFactor, layer);
|
||||
g_painter.releaseCustomProgram();
|
||||
}
|
||||
|
||||
void Item::setPos(const Position& position)
|
||||
void Item::setPosition(const Position& position)
|
||||
{
|
||||
if(m_type->properties[ThingType::IsGround]) {
|
||||
m_xPattern = position.x % m_type->dimensions[ThingType::PatternX];
|
||||
m_yPattern = position.y % m_type->dimensions[ThingType::PatternY];
|
||||
m_zPattern = position.z % m_type->dimensions[ThingType::PatternZ];
|
||||
if(isGround()) {
|
||||
m_xPattern = position.x % getNumPatternsX();
|
||||
m_yPattern = position.y % getNumPatternsY();
|
||||
m_zPattern = position.z % getNumPatternsZ();
|
||||
}
|
||||
|
||||
Thing::setPos(position);
|
||||
Thing::setPosition(position);
|
||||
}
|
||||
|
||||
void Item::setData(int data)
|
||||
{
|
||||
if(m_type->properties[ThingType::IsStackable] && m_type->dimensions[ThingType::PatternX] == 4 && m_type->dimensions[ThingType::PatternY] == 2) {
|
||||
if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
|
||||
if(data < 5) {
|
||||
m_xPattern = data-1;
|
||||
m_yPattern = 0;
|
||||
|
@ -83,15 +97,15 @@ void Item::setData(int data)
|
|||
m_yPattern = 1;
|
||||
}
|
||||
}
|
||||
else if(m_type->properties[ThingType::IsHangable]) {
|
||||
if(m_type->properties[ThingType::HookSouth]) {
|
||||
m_xPattern = m_type->dimensions[ThingType::PatternX] >= 2 ? 1 : 0;
|
||||
else if(isHangable()) {
|
||||
if(isHookSouth()) {
|
||||
m_xPattern = getNumPatternsX() >= 2 ? 1 : 0;
|
||||
}
|
||||
else if(m_type->properties[ThingType::HookEast]) {
|
||||
m_xPattern = m_type->dimensions[ThingType::PatternX] >= 3 ? 2 : 0;
|
||||
else if(isHookEast()) {
|
||||
m_xPattern = getNumPatternsX() >= 3 ? 2 : 0;
|
||||
}
|
||||
}
|
||||
else if(m_type->properties[ThingType::IsFluid] || m_type->properties[ThingType::IsFluidContainer]) {
|
||||
else if(isFluid() || isFluidContainer()) {
|
||||
int color = Otc::FluidTransparent;
|
||||
switch(data) {
|
||||
case Otc::FluidNone:
|
||||
|
@ -153,14 +167,9 @@ void Item::setData(int data)
|
|||
break;
|
||||
}
|
||||
|
||||
m_xPattern = (color % 4) % m_type->dimensions[ThingType::PatternX];
|
||||
m_yPattern = (color / 4) % m_type->dimensions[ThingType::PatternY];
|
||||
m_xPattern = (color % 4) % getNumPatternsX();
|
||||
m_yPattern = (color / 4) % getNumPatternsY();
|
||||
}
|
||||
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
ThingType *Item::getType()
|
||||
{
|
||||
return g_thingsType.getThingType(m_id, ThingsType::Item);
|
||||
}
|
||||
|
|
|
@ -33,17 +33,12 @@ public:
|
|||
|
||||
static ItemPtr create(int id);
|
||||
|
||||
enum {
|
||||
TICKS_PER_FRAME = 500
|
||||
};
|
||||
void draw(const Point& dest, float scaleFactor);
|
||||
|
||||
void draw(const Point& p, const Rect&);
|
||||
|
||||
void setPos(const Position &position);
|
||||
void setPosition(const Position &position);
|
||||
void setData(int data);
|
||||
|
||||
int getData() { return m_data; }
|
||||
ThingType *getType();
|
||||
|
||||
ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
|
||||
|
||||
|
|
|
@ -70,11 +70,11 @@ void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
|
|||
void LocalPlayer::preWalk(Otc::Direction direction)
|
||||
{
|
||||
// start walking to direction
|
||||
Position newPos = m_pos + Position::getPosFromDirection(direction);
|
||||
Position newPos = m_position + Position::getPositionFromDirection(direction);
|
||||
m_preWalking = true;
|
||||
m_lastPrewalkDone = false;
|
||||
m_lastPrewalkDestionation = newPos;
|
||||
Creature::walk(m_pos, newPos);
|
||||
Creature::walk(m_position, newPos);
|
||||
}
|
||||
|
||||
bool LocalPlayer::canWalk(Otc::Direction direction)
|
||||
|
|
|
@ -28,202 +28,232 @@
|
|||
#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"
|
||||
|
||||
Map g_map;
|
||||
|
||||
Map::Map()
|
||||
void Map::addMapView(const MapViewPtr& mapView)
|
||||
{
|
||||
setVisibleSize(Size(MAP_VISIBLE_WIDTH, MAP_VISIBLE_HEIGHT));
|
||||
m_mapViews.push_back(mapView);
|
||||
}
|
||||
|
||||
void Map::draw(const Rect& rect)
|
||||
void Map::removeMapView(const MapViewPtr& mapView)
|
||||
{
|
||||
if(!m_framebuffer) {
|
||||
Size fboSize(m_visibleSize.width() * NUM_TILE_PIXELS, m_visibleSize.height() * NUM_TILE_PIXELS);
|
||||
m_framebuffer = FrameBufferPtr(new FrameBuffer(fboSize));
|
||||
m_framebuffer->setClearColor(Fw::black);
|
||||
|
||||
|
||||
m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram);
|
||||
m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
||||
m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag");
|
||||
assert(m_shaderProgram->link());
|
||||
auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView);
|
||||
if(it != m_mapViews.end())
|
||||
m_mapViews.erase(it);
|
||||
}
|
||||
|
||||
g_painter.setColor(Fw::white);
|
||||
m_framebuffer->bind();
|
||||
|
||||
// draw offsets
|
||||
LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
|
||||
if(localPlayer)
|
||||
m_drawOffset = localPlayer->getWalkOffset();
|
||||
|
||||
//TODO: cache first/last visible floor
|
||||
// draw from bottom floors to top floors
|
||||
int firstFloor = getFirstVisibleFloor();
|
||||
const int lastFloor = MAX_Z-1;
|
||||
for(int iz = lastFloor; iz >= firstFloor; --iz) {
|
||||
// draw tiles like linus pauling's rule order
|
||||
const int numDiagonals = m_size.width() + m_size.height() - 1;
|
||||
for(int diagonal = 0; diagonal < numDiagonals; ++diagonal) {
|
||||
// loop through / diagonal tiles
|
||||
for(int ix = std::min(diagonal, m_size.width() - 1), iy = std::max(diagonal - m_size.width(), 0); ix >= 0 && iy < m_size.height(); --ix, ++iy) {
|
||||
// position on current floor
|
||||
Position tilePos(m_centralPosition.x + (ix - m_centralOffset.x), m_centralPosition.y + (iy - m_centralOffset.y), m_centralPosition.z);
|
||||
// adjust tilePos to the wanted floor
|
||||
tilePos.perspectiveUp(m_centralPosition.z - iz);
|
||||
//TODO: cache visible tiles, m_tiles[] has a high cost (50% fps decrease)
|
||||
if(const TilePtr& tile = m_tiles[tilePos]) {
|
||||
// skip tiles that are behind another tile
|
||||
//if(isCompletlyCovered(tilePos, firstFloor))
|
||||
// continue;
|
||||
tile->draw(positionTo2D(tilePos) - m_drawOffset, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// after drawing all tiles, draw shots
|
||||
for(const MissilePtr& shot : m_missilesAtFloor[iz]) {
|
||||
Position missilePos = shot->getPos();
|
||||
shot->draw(positionTo2D(missilePos) - m_drawOffset, rect);
|
||||
}
|
||||
}
|
||||
|
||||
m_framebuffer->release();
|
||||
|
||||
|
||||
g_painter.setCustomProgram(m_shaderProgram);
|
||||
g_painter.setColor(Fw::white);
|
||||
m_framebuffer->draw(rect);
|
||||
g_painter.releaseCustomProgram();
|
||||
|
||||
// calculate stretch factor
|
||||
float horizontalStretchFactor = rect.width() / (float)(m_visibleSize.width() * NUM_TILE_PIXELS);
|
||||
float verticalStretchFactor = rect.height() / (float)(m_visibleSize.height() * NUM_TILE_PIXELS);
|
||||
|
||||
// draw player names and health bars
|
||||
//TODO: this must be cached with creature walks
|
||||
for(int x = 0; x < m_visibleSize.width(); ++x) {
|
||||
for(int y = 0; y < m_visibleSize.height(); ++y) {
|
||||
Position tilePos = Position(m_centralPosition.x + (x - m_centralOffset.x + 1), m_centralPosition.y + (y - m_centralOffset.y + 1), m_centralPosition.z);
|
||||
if(const TilePtr& tile = m_tiles[tilePos]) {
|
||||
auto creatures = tile->getCreatures();
|
||||
|
||||
if(creatures.size() == 0)
|
||||
continue;
|
||||
|
||||
for(const CreaturePtr& creature : creatures) {
|
||||
Point p((m_centralOffset.x - 1 + (tilePos.x - m_centralPosition.x))*NUM_TILE_PIXELS + 10 - tile->getDrawElevation(),
|
||||
(m_centralOffset.y - 1 + (tilePos.y - m_centralPosition.y))*NUM_TILE_PIXELS - 10 - tile->getDrawElevation());
|
||||
|
||||
if(creature != localPlayer) {
|
||||
p += creature->getWalkOffset() - m_drawOffset;
|
||||
}
|
||||
|
||||
creature->drawInformation(rect.x() + p.x*horizontalStretchFactor, rect.y() + p.y*verticalStretchFactor, isCovered(tilePos, firstFloor), rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw static text
|
||||
for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) {
|
||||
Point pos = positionTo2D((*it)->getPos()) - m_drawOffset;
|
||||
pos.x *= horizontalStretchFactor;
|
||||
pos.y *= verticalStretchFactor;
|
||||
(*it)->draw(rect.topLeft() + pos, rect);
|
||||
}
|
||||
|
||||
// draw animated text
|
||||
for(auto it = m_animatedTexts.begin(), end = m_animatedTexts.end(); it != end; ++it) {
|
||||
Point pos = positionTo2D((*it)->getPos()) - m_drawOffset;
|
||||
pos.x *= horizontalStretchFactor;
|
||||
pos.y *= verticalStretchFactor;
|
||||
(*it)->draw(rect.topLeft() + pos, rect);
|
||||
}
|
||||
void Map::notificateTileUpdateToMapViews(const Position& pos)
|
||||
{
|
||||
for(const MapViewPtr& mapView : m_mapViews)
|
||||
mapView->onTileUpdate(pos);
|
||||
}
|
||||
|
||||
void Map::clean()
|
||||
{
|
||||
m_tiles.clear();
|
||||
m_creatures.clear();
|
||||
for(int i=0;i<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()
|
||||
void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
|
||||
{
|
||||
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;
|
||||
if(!thing)
|
||||
return;
|
||||
|
||||
TilePtr tile = getTile(pos);
|
||||
if(!tile)
|
||||
tile = createTile(pos);
|
||||
|
||||
if(CreaturePtr creature = thing->asCreature()) {
|
||||
Position oldPos = thing->getPosition();
|
||||
tile->addThing(thing, stackPos);
|
||||
|
||||
// creature teleported
|
||||
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1,0))
|
||||
g_game.processCreatureTeleport(creature);
|
||||
} 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()) {
|
||||
bool mustAdd = true;
|
||||
for(auto it = m_staticTexts.begin(), end = m_staticTexts.end(); it != end; ++it) {
|
||||
StaticTextPtr cStaticText = *it;
|
||||
if(cStaticText->getPosition() == pos) {
|
||||
// try to combine messages
|
||||
if(cStaticText->addMessage(staticText->getName(), staticText->getMessageType(), staticText->getFirstMessage())) {
|
||||
mustAdd = false;
|
||||
break;
|
||||
} else {
|
||||
// must add another message and rearrenge current
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(mustAdd)
|
||||
m_staticTexts.push_back(staticText);
|
||||
} else {
|
||||
tile->addThing(thing, stackPos);
|
||||
}
|
||||
|
||||
thing->startAnimation();
|
||||
thing->setPosition(pos);
|
||||
|
||||
notificateTileUpdateToMapViews(pos);
|
||||
}
|
||||
|
||||
ThingPtr Map::getThing(const Position& pos, int stackPos)
|
||||
{
|
||||
if(TilePtr tile = getTile(pos))
|
||||
return tile->getThing(stackPos);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Map::removeThing(const ThingPtr& thing)
|
||||
{
|
||||
if(!thing) {
|
||||
return false;
|
||||
} else if(MissilePtr missile = thing->asMissile()) {
|
||||
auto it = std::find(m_floorMissiles[missile->getPosition().z].begin(), m_floorMissiles[missile->getPosition().z].end(), missile);
|
||||
if(it != m_floorMissiles[missile->getPosition().z].end()) {
|
||||
m_floorMissiles[missile->getPosition().z].erase(it);
|
||||
return true;
|
||||
}
|
||||
} else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) {
|
||||
auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText);
|
||||
if(it != m_animatedTexts.end()) {
|
||||
m_animatedTexts.erase(it);
|
||||
return true;
|
||||
}
|
||||
} else if(StaticTextPtr staticText = thing->asStaticText()) {
|
||||
auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText);
|
||||
if(it != m_staticTexts.end()) {
|
||||
m_staticTexts.erase(it);
|
||||
return true;
|
||||
}
|
||||
} else if(TilePtr tile = getTile(thing->getPosition()))
|
||||
return tile->removeThing(thing);
|
||||
|
||||
notificateTileUpdateToMapViews(thing->getPosition());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Map::removeThingByPos(const Position& pos, int stackPos)
|
||||
{
|
||||
if(TilePtr tile = getTile(pos))
|
||||
return removeThing(tile->getThing(stackPos));
|
||||
return false;
|
||||
}
|
||||
|
||||
TilePtr Map::createTile(const Position& pos)
|
||||
{
|
||||
TilePtr tile = TilePtr(new Tile(pos));
|
||||
m_tiles[pos] = tile;
|
||||
return tile;
|
||||
}
|
||||
|
||||
void Map::cleanTile(const Position& pos)
|
||||
{
|
||||
if(TilePtr tile = getTile(pos)) {
|
||||
tile->clean();
|
||||
|
||||
notificateTileUpdateToMapViews(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::addCreature(const CreaturePtr& creature)
|
||||
{
|
||||
m_knownCreatures[creature->getId()] = creature;
|
||||
}
|
||||
|
||||
CreaturePtr Map::getCreatureById(uint32 id)
|
||||
{
|
||||
LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
|
||||
if(localPlayer && localPlayer->getId() == id)
|
||||
return localPlayer;
|
||||
return m_knownCreatures[id];
|
||||
}
|
||||
|
||||
void Map::removeCreatureById(uint32 id)
|
||||
{
|
||||
if(id == 0)
|
||||
return;
|
||||
m_knownCreatures.erase(id);
|
||||
}
|
||||
|
||||
std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
for(int iz=-minZRange; iz<=maxZRange; ++iz) {
|
||||
for(int iy=-minYRange; iy<=maxYRange; ++iy) {
|
||||
for(int ix=-minXRange; ix<=maxXRange; ++ix) {
|
||||
TilePtr tile = getTile(centerPos + Position(ix,iy,iz));
|
||||
if(!tile)
|
||||
continue;
|
||||
|
||||
auto tileCreatures = tile->getCreatures();
|
||||
creatures.insert(creatures.end(), tileCreatures.begin(), tileCreatures.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
return creatures;
|
||||
}
|
||||
|
||||
bool Map::isLookPossible(const Position& pos)
|
||||
{
|
||||
TilePtr tile = m_tiles[pos];
|
||||
if(tile)
|
||||
return tile->isLookPossible();
|
||||
return true;
|
||||
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;
|
||||
tilePos.perspectiveUp();
|
||||
tilePos.coveredUp();
|
||||
while(tilePos.z >= firstFloor) {
|
||||
TilePtr tile = m_tiles[tilePos];
|
||||
TilePtr tile = getTile(tilePos);
|
||||
// the below tile is covered when the above tile has a full ground
|
||||
if(tile && tile->isFullGround())
|
||||
return true;
|
||||
tilePos.perspectiveUp();
|
||||
tilePos.coveredUp();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Map::isCompletlyCovered(const Position& pos, int firstFloor)
|
||||
bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
|
||||
{
|
||||
Position tilePos = pos;
|
||||
tilePos.perspectiveUp();
|
||||
tilePos.coveredUp();
|
||||
while(tilePos.z >= firstFloor) {
|
||||
bool covered = true;
|
||||
// check in 2x2 range tiles that has no transparent pixels
|
||||
for(int x=0;x<2;++x) {
|
||||
for(int y=0;y<2;++y) {
|
||||
TilePtr tile = m_tiles[tilePos + Position(-x, -y, 0)];
|
||||
|
@ -235,162 +265,7 @@ bool Map::isCompletlyCovered(const Position& pos, int firstFloor)
|
|||
}
|
||||
if(covered)
|
||||
return true;
|
||||
tilePos.perspectiveUp();
|
||||
tilePos.coveredUp();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
|
||||
{
|
||||
if(!thing)
|
||||
return;
|
||||
|
||||
Position oldPos = thing->getPos();
|
||||
bool teleport = false;
|
||||
if(oldPos.isValid() && !oldPos.isInRange(pos,1,1,0))
|
||||
teleport = true;
|
||||
|
||||
TilePtr tile = getTile(pos);
|
||||
|
||||
if(CreaturePtr creature = thing->asCreature()) {
|
||||
tile->addThing(thing, stackPos);
|
||||
m_creatures[creature->getId()] = creature;
|
||||
|
||||
if(teleport)
|
||||
g_game.processCreatureTeleport(creature);
|
||||
}
|
||||
else if(MissilePtr shot = thing->asMissile()) {
|
||||
m_missilesAtFloor[shot->getPos().z].push_back(shot);
|
||||
}
|
||||
else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) {
|
||||
m_animatedTexts.push_back(animatedText);
|
||||
}
|
||||
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) {
|
||||
// try to combine messages
|
||||
if(cStaticText->addMessage(staticText->getName(), staticText->getMessageType(), staticText->getFirstMessage())) {
|
||||
mustAdd = false;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// must add another message and rearrenge current
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(mustAdd)
|
||||
m_staticTexts.push_back(staticText);
|
||||
}
|
||||
else {
|
||||
tile->addThing(thing, stackPos);
|
||||
}
|
||||
|
||||
thing->start();
|
||||
thing->setPos(pos);
|
||||
}
|
||||
|
||||
ThingPtr Map::getThing(const Position& pos, int stackPos)
|
||||
{
|
||||
if(const TilePtr& tile = m_tiles[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)
|
||||
{
|
||||
if(!thing)
|
||||
return;
|
||||
|
||||
if(MissilePtr shot = thing->asMissile()) {
|
||||
auto it = std::find(m_missilesAtFloor[shot->getPos().z].begin(), m_missilesAtFloor[shot->getPos().z].end(), shot);
|
||||
if(it != m_missilesAtFloor[shot->getPos().z].end()) {
|
||||
m_missilesAtFloor[shot->getPos().z].erase(it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(AnimatedTextPtr animatedText = thing->asAnimatedText()) {
|
||||
auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText);
|
||||
if(it != m_animatedTexts.end())
|
||||
m_animatedTexts.erase(it);
|
||||
return;
|
||||
}
|
||||
else if(StaticTextPtr staticText = thing->asStaticText()) {
|
||||
auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText);
|
||||
if(it != m_staticTexts.end())
|
||||
m_staticTexts.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
if(TilePtr& tile = m_tiles[thing->getPos()])
|
||||
tile->removeThing(thing);
|
||||
}
|
||||
|
||||
TilePtr Map::getTile(const Position& pos)
|
||||
{
|
||||
if(!pos.isValid())
|
||||
return nullptr;
|
||||
|
||||
TilePtr& tile = m_tiles[pos];
|
||||
if(!tile)
|
||||
tile = TilePtr(new Tile(pos));
|
||||
return tile;
|
||||
}
|
||||
|
||||
void Map::cleanTile(const Position& pos)
|
||||
{
|
||||
if(TilePtr& tile = m_tiles[pos])
|
||||
tile->clean();
|
||||
}
|
||||
|
||||
void Map::addCreature(const CreaturePtr& creature)
|
||||
{
|
||||
m_creatures[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];
|
||||
}
|
||||
|
||||
void Map::removeCreatureById(uint32 id)
|
||||
{
|
||||
m_creatures.erase(id);
|
||||
}
|
||||
|
||||
void Map::setCentralPosition(const Position& centralPosition)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Point Map::positionTo2D(const Position& position)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -26,70 +26,59 @@
|
|||
#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 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) { return m_tiles[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) { m_centralPosition = centralPosition; }
|
||||
|
||||
Point positionTo2D(const Position& position);
|
||||
bool isLookPossible(const Position& pos);
|
||||
bool isCovered(const Position& pos, int firstFloor = 0);
|
||||
bool isCompletelyCovered(const Position& pos, int firstFloor = 0);
|
||||
|
||||
Light getLight() { return m_light; }
|
||||
Position getCentralPosition() { return m_centralPosition; }
|
||||
|
||||
|
||||
std::vector<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,321 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
MapView::MapView()
|
||||
{
|
||||
int frameBufferSize = std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_SIZE);
|
||||
|
||||
m_framebuffer = FrameBufferPtr(new FrameBuffer(Size(frameBufferSize, frameBufferSize)));
|
||||
m_framebuffer->setClearColor(Fw::black);
|
||||
m_lockedFirstVisibleFloor = -1;
|
||||
setVisibleDimension(Size(15, 11));
|
||||
|
||||
m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram);
|
||||
m_shaderProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
||||
m_shaderProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/map.frag");
|
||||
assert(m_shaderProgram->link());
|
||||
}
|
||||
|
||||
void MapView::draw(const Rect& rect)
|
||||
{
|
||||
// update visible tiles cache when needed
|
||||
bool updated = updateVisibleTilesCache();
|
||||
|
||||
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
|
||||
|
||||
if(updated || m_animated) {
|
||||
m_framebuffer->bind();
|
||||
for(const TilePtr& tile : m_cachedVisibleTiles) {
|
||||
tile->draw(transformPositionTo2D(tile->getPosition()), scaleFactor);
|
||||
//TODO: restore missiles
|
||||
}
|
||||
m_framebuffer->generateMipmaps();
|
||||
|
||||
m_framebuffer->release();
|
||||
}
|
||||
|
||||
g_painter.setCustomProgram(m_shaderProgram);
|
||||
g_painter.setColor(Fw::white);
|
||||
|
||||
Point drawOffset(m_tileSize, m_tileSize);
|
||||
if(m_followingCreature)
|
||||
drawOffset += m_followingCreature->getWalkOffset() * scaleFactor;
|
||||
Rect srcRect = Rect(drawOffset, m_visibleDimension * m_tileSize);
|
||||
m_framebuffer->draw(rect, srcRect);
|
||||
|
||||
g_painter.releaseCustomProgram();
|
||||
|
||||
float horizontalStretchFactor = rect.width() / (float)(m_visibleDimension.width() * m_tileSize);
|
||||
float verticalStretchFactor = rect.height() / (float)(m_visibleDimension.height() * m_tileSize);
|
||||
Size tileStretchedSize = Size(m_tileSize * horizontalStretchFactor, m_tileSize * verticalStretchFactor);
|
||||
|
||||
// avoid drawing texts on map in far zoom outs
|
||||
if(tileStretchedSize.width() >= 24) {
|
||||
for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
|
||||
const TilePtr& tile = creature->getCurrentTile();
|
||||
Position pos = tile->getPosition();
|
||||
|
||||
Point p = transformPositionTo2D(pos) - drawOffset;
|
||||
p += (creature->getWalkOffset()-tile->getDrawElevation() + Point(8, -8)) * scaleFactor;
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
p.y = p.y * verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
|
||||
creature->drawInformation(p, g_map.isCovered(pos, m_cachedFirstVisibleFloor), rect);
|
||||
}
|
||||
|
||||
for(const StaticTextPtr& staticText : g_map.getStaticTexts()) {
|
||||
Position pos = staticText->getPosition();
|
||||
|
||||
// ony draw static texts from current camera floor, unless yells
|
||||
if(pos.z != getCameraPosition().z && !staticText->isYell())
|
||||
continue;
|
||||
|
||||
Point p = transformPositionTo2D(pos) - drawOffset;
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
p.y = p.y * verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
staticText->draw(p, rect);
|
||||
}
|
||||
|
||||
for(const AnimatedTextPtr& animatedText : g_map.getAnimatedTexts()) {
|
||||
Position pos = animatedText->getPosition();
|
||||
|
||||
// only draw animated texts from visible floors
|
||||
if(pos.z < m_cachedFirstVisibleFloor || pos.z > m_cachedLastVisibleFloor)
|
||||
continue;
|
||||
|
||||
Point p = transformPositionTo2D(pos) - drawOffset;
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
p.y = p.y * verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
animatedText->draw(p, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MapView::updateVisibleTilesCache()
|
||||
{
|
||||
// update only when needed
|
||||
if(!m_mustUpdateVisibleTilesCache)
|
||||
return false;
|
||||
|
||||
int firstFloor = getFirstVisibleFloor();
|
||||
int lastFloor = getLastVisibleFloor();
|
||||
m_cachedFirstVisibleFloor = firstFloor;
|
||||
m_cachedLastVisibleFloor = lastFloor;
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
// clear current visible tiles cache
|
||||
m_cachedVisibleTiles.clear();
|
||||
|
||||
// cache visible tiles in draw order
|
||||
// draw from last floor (the lower) to first floor (the higher)
|
||||
for(int iz = m_cachedLastVisibleFloor; iz >= m_cachedFirstVisibleFloor; --iz) {
|
||||
// draw tiles like linus pauling's rule order
|
||||
const int numDiagonals = m_drawDimension.width() + m_drawDimension.height() - 1;
|
||||
for(int diagonal = 0; diagonal < numDiagonals; ++diagonal) {
|
||||
// loop through / diagonal tiles
|
||||
for(int ix = std::min(diagonal, m_drawDimension.width() - 1), iy = std::max(diagonal - m_drawDimension.width() + 1, 0); ix >= 0 && iy < m_drawDimension.height(); --ix, ++iy) {
|
||||
// position on current floor
|
||||
Position tilePos(cameraPosition.x + (ix - m_virtualCenterOffset.x), cameraPosition.y + (iy - m_virtualCenterOffset.y), cameraPosition.z);
|
||||
// adjust tilePos to the wanted floor
|
||||
tilePos.coveredUp(cameraPosition.z - iz);
|
||||
if(TilePtr tile = g_map.getTile(tilePos)) {
|
||||
// skip tiles that have nothing
|
||||
if(tile->getThingCount() == 0)
|
||||
continue;
|
||||
// skip tiles that are completely behind another tile
|
||||
if(g_map.isCompletelyCovered(tilePos, firstFloor))
|
||||
continue;
|
||||
m_cachedVisibleTiles.push_back(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false);
|
||||
|
||||
m_mustUpdateVisibleTilesCache = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapView::recalculateTileSize()
|
||||
{
|
||||
int possiblesTileSizes[] = {32,16,8,4,2,1};
|
||||
|
||||
int foundSize = 0;
|
||||
for(int candidateTileSize : possiblesTileSizes) {
|
||||
Size candidateFramebufferSize = m_drawDimension * candidateTileSize;
|
||||
|
||||
// found a valid size
|
||||
if(candidateFramebufferSize.width() <= m_framebuffer->getSize().width() && candidateFramebufferSize.height() <= m_framebuffer->getSize().height()) {
|
||||
foundSize = candidateTileSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(foundSize > 0);
|
||||
m_tileSize = foundSize;
|
||||
}
|
||||
|
||||
void MapView::onTileUpdate(const Position& pos)
|
||||
{
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
void MapView::lockFirstVisibleFloor(int firstVisibleFloor)
|
||||
{
|
||||
m_lockedFirstVisibleFloor = firstVisibleFloor;
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
void MapView::unlockFirstVisibleFloor()
|
||||
{
|
||||
m_lockedFirstVisibleFloor = -1;
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
void MapView::followCreature(const CreaturePtr& creature)
|
||||
{
|
||||
m_followingCreature = creature;
|
||||
m_customCameraPosition = Position();
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
void MapView::setCameraPosition(const Position& pos)
|
||||
{
|
||||
m_customCameraPosition = pos;
|
||||
m_followingCreature = nullptr;
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
void MapView::setVisibleDimension(const Size& visibleDimension)
|
||||
{
|
||||
if(visibleDimension.width() % 2 != 1 || visibleDimension.height() % 2 != 1) {
|
||||
logTraceError("visible dimension must be odd");
|
||||
return;
|
||||
}
|
||||
|
||||
if(visibleDimension.width() <= 3 || visibleDimension.height() <= 3) {
|
||||
logTraceError("cannot render less than 3x3 tiles");
|
||||
return;
|
||||
}
|
||||
|
||||
m_visibleDimension = visibleDimension;
|
||||
m_drawDimension = visibleDimension + Size(3,3);
|
||||
m_virtualCenterOffset = (m_drawDimension/2 - Size(1,1)).toPoint();
|
||||
recalculateTileSize();
|
||||
|
||||
dump << m_framebuffer->getSize();
|
||||
dump << visibleDimension * m_tileSize;
|
||||
requestVisibleTilesCacheUpdate();
|
||||
}
|
||||
|
||||
int MapView::getFirstVisibleFloor()
|
||||
{
|
||||
// return forced first visible floor
|
||||
if(m_lockedFirstVisibleFloor != -1)
|
||||
return m_lockedFirstVisibleFloor;
|
||||
|
||||
// if nothing is limiting the view, the first visible floor is 0
|
||||
int firstFloor = 0;
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
// limits to underground floors while under sea level
|
||||
if(cameraPosition.z > Otc::SEA_LEVEL)
|
||||
firstFloor = Otc::SEA_LEVEL+1;
|
||||
|
||||
// loop in 3x3 tiles around the camera
|
||||
for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) {
|
||||
for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) {
|
||||
Position pos(cameraPosition.x + ix, cameraPosition.y + iy, cameraPosition.z);
|
||||
|
||||
// process tiles that we can look through, e.g. windows, doors
|
||||
if((ix == 0 && iy == 0) || g_map.isLookPossible(pos)) {
|
||||
Position upperPos = pos;
|
||||
Position coveredPos = pos;
|
||||
|
||||
coveredPos.coveredUp();
|
||||
upperPos.up();
|
||||
|
||||
while(upperPos.z >= firstFloor) {
|
||||
// check tiles physically above
|
||||
TilePtr tile = g_map.getTile(upperPos);
|
||||
if(tile && tile->limitsFloorsView()) {
|
||||
firstFloor = upperPos.z + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// check tiles geometrically above
|
||||
tile = g_map.getTile(coveredPos);
|
||||
if(tile && tile->limitsFloorsView()) {
|
||||
firstFloor = coveredPos.z + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
coveredPos.coveredUp();
|
||||
upperPos.up();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return firstFloor;
|
||||
}
|
||||
|
||||
int MapView::getLastVisibleFloor()
|
||||
{
|
||||
Position cameraPosition = getCameraPosition();
|
||||
|
||||
// view only underground floors when below sea level
|
||||
if(cameraPosition.z > Otc::SEA_LEVEL)
|
||||
return Otc::MAX_Z;
|
||||
else
|
||||
return Otc::SEA_LEVEL;
|
||||
}
|
||||
|
||||
Position MapView::getCameraPosition()
|
||||
{
|
||||
if(m_followingCreature)
|
||||
return m_followingCreature->getPosition();
|
||||
return m_customCameraPosition;
|
||||
}
|
||||
|
||||
Point MapView::transformPositionTo2D(const Position& position)
|
||||
{
|
||||
Position cameraPosition = getCameraPosition();
|
||||
return Point((m_virtualCenterOffset.x + (position.x - cameraPosition.x) - (cameraPosition.z - position.z)) * m_tileSize,
|
||||
(m_virtualCenterOffset.y + (position.y - cameraPosition.y) - (cameraPosition.z - position.z)) * m_tileSize);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
class MapView : public LuaObject
|
||||
{
|
||||
enum {
|
||||
DEFAULT_FRAMBUFFER_SIZE = 2048
|
||||
};
|
||||
|
||||
public:
|
||||
MapView();
|
||||
|
||||
void draw(const Rect& rect);
|
||||
|
||||
private:
|
||||
void recalculateTileSize();
|
||||
bool updateVisibleTilesCache();
|
||||
void requestVisibleTilesCacheUpdate() { m_mustUpdateVisibleTilesCache = true; }
|
||||
|
||||
protected:
|
||||
void onTileUpdate(const Position& pos);
|
||||
|
||||
friend class Map;
|
||||
|
||||
public:
|
||||
void lockFirstVisibleFloor(int firstVisibleFloor);
|
||||
void unlockFirstVisibleFloor();
|
||||
void followCreature(const CreaturePtr& creature);
|
||||
|
||||
void setCameraPosition(const Position& pos);
|
||||
void setVisibleDimension(const Size& visibleDimension);
|
||||
void setAnimated(bool animated) { m_animated = animated; }
|
||||
|
||||
//void zoomIn(float factor);
|
||||
//void zoomOut(float factor);
|
||||
|
||||
bool isFollowingCreature() { return !!m_followingCreature; }
|
||||
|
||||
int getFirstVisibleFloor();
|
||||
int getLastVisibleFloor();
|
||||
Position getCameraPosition();
|
||||
Size getVisibleDimension() { return m_visibleDimension; }
|
||||
Size getVisibleSize() { return m_visibleDimension * m_tileSize; }
|
||||
CreaturePtr getFollowingCreature() { return m_followingCreature; }
|
||||
|
||||
bool isAnimated() { return m_animated; }
|
||||
|
||||
Point transformPositionTo2D(const Position& position);
|
||||
|
||||
MapViewPtr asMapView() { return std::static_pointer_cast<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;
|
||||
Boolean<true> m_mustUpdateVisibleTilesCache;
|
||||
Boolean<true> m_animated;
|
||||
std::vector<TilePtr> m_cachedVisibleTiles;
|
||||
std::vector<CreaturePtr> m_cachedFloorVisibleCreatures;
|
||||
CreaturePtr m_followingCreature;
|
||||
FrameBufferPtr m_framebuffer;
|
||||
PainterShaderProgramPtr m_shaderProgram;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -35,7 +35,7 @@ Missile::Missile() : Thing()
|
|||
void Missile::draw(const Point& p, const Rect&)
|
||||
{
|
||||
float time = (g_clock.ticks() - m_startTicks) / m_duration;
|
||||
internalDraw(p + Point(m_posDelta.x * time, m_posDelta.y * time), 0);
|
||||
//internalDraw(p + Point(m_positionDelta.x * time, m_positionDelta.y * time), 0);
|
||||
}
|
||||
|
||||
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
||||
|
@ -79,18 +79,16 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
|||
m_yPattern = 1;
|
||||
}
|
||||
|
||||
m_pos = fromPosition;
|
||||
m_posDelta = toPosition - fromPosition;
|
||||
m_position = fromPosition;
|
||||
m_positionDelta = toPosition - fromPosition;
|
||||
m_startTicks = g_clock.ticks();
|
||||
m_duration = 150 * std::sqrt(Point(m_posDelta.x, m_posDelta.y).length());
|
||||
m_posDelta.x *= Map::NUM_TILE_PIXELS;
|
||||
m_posDelta.y *= Map::NUM_TILE_PIXELS;
|
||||
m_duration = 150 * std::sqrt(Point(m_positionDelta.x, m_positionDelta.y).length());
|
||||
m_positionDelta.x *= Otc::TILE_PIXELS;
|
||||
m_positionDelta.y *= Otc::TILE_PIXELS;
|
||||
|
||||
// schedule removal
|
||||
auto self = asMissile();
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
g_map.removeThing(self);
|
||||
}, m_duration);
|
||||
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, m_duration);
|
||||
}
|
||||
|
||||
ThingType *Missile::getType()
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
|
||||
private:
|
||||
ticks_t m_startTicks;
|
||||
Position m_posDelta;
|
||||
Position m_positionDelta;
|
||||
float m_duration;
|
||||
};
|
||||
|
||||
|
|
|
@ -116,7 +116,10 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
|
|||
writePos += 4;
|
||||
}
|
||||
|
||||
return TexturePtr(new Texture(32, 32, 4, pixels));
|
||||
TexturePtr spriteTex(new Texture(32, 32, 4, pixels));
|
||||
spriteTex->setSmooth(true);
|
||||
spriteTex->generateBilinearMipmaps();
|
||||
return spriteTex;
|
||||
}
|
||||
|
||||
TexturePtr SpriteManager::getSpriteTexture(int id)
|
||||
|
|
|
@ -31,17 +31,21 @@ StaticText::StaticText()
|
|||
m_font = g_fonts.getFont("verdana-11px-rounded");
|
||||
}
|
||||
|
||||
void StaticText::draw(const Point& p, const Rect& visibleRect)
|
||||
void StaticText::draw(const Point& dest, const Rect& parentRect)
|
||||
{
|
||||
Rect rect = Rect(p - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize);
|
||||
Rect rect = Rect(dest - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize);
|
||||
Rect boundRect = rect;
|
||||
boundRect.bind(visibleRect);
|
||||
if((boundRect.center() - rect.center()).length() < visibleRect.width() / 15)
|
||||
boundRect.bind(parentRect);
|
||||
|
||||
if((boundRect.center() - rect.center()).length() < parentRect.width() / 15) {
|
||||
//TODO: cache into a framebuffer
|
||||
m_font->renderText(m_text, boundRect, Fw::AlignCenter, m_color);
|
||||
}
|
||||
}
|
||||
|
||||
bool StaticText::addMessage(const std::string& name, const std::string& type, const std::string& message)
|
||||
{
|
||||
//TODO: this could be moved to lua
|
||||
// First message
|
||||
if(m_messages.size() == 0) {
|
||||
m_name = name;
|
||||
|
@ -59,7 +63,11 @@ bool StaticText::addMessage(const std::string& name, const std::string& type, co
|
|||
auto self = asStaticText();
|
||||
g_dispatcher.scheduleEvent([self]() {
|
||||
self->removeMessage();
|
||||
}, std::max<int>(DURATION_PER_CHARACTER * message.length(), MIN_DURATION));
|
||||
}, std::max<int>(Otc::STATIC_DURATION_PER_CHARACTER * message.length(), Otc::MIN_STATIC_TEXT_DURATION));
|
||||
|
||||
|
||||
if(type == "yell" || type == "monsterYell")
|
||||
m_yell = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -72,40 +80,34 @@ void StaticText::removeMessage()
|
|||
// schedule removal
|
||||
auto self = asStaticText();
|
||||
g_dispatcher.addEvent([self]() { g_map.removeThing(self); });
|
||||
}
|
||||
else
|
||||
} else
|
||||
compose();
|
||||
}
|
||||
|
||||
void StaticText::compose()
|
||||
{
|
||||
//TODO: this could be moved to lua
|
||||
std::string text;
|
||||
text.clear();
|
||||
|
||||
if(m_messageType == "say") {
|
||||
text += m_name;
|
||||
text += " says:\n";
|
||||
m_color = Color(239, 239, 0);
|
||||
}
|
||||
else if(m_messageType == "whisper") {
|
||||
} else if(m_messageType == "whisper") {
|
||||
text += m_name;
|
||||
text += " whispers:\n";
|
||||
m_color = Color(239, 239, 0);
|
||||
}
|
||||
else if(m_messageType == "yell") {
|
||||
} else if(m_messageType == "yell") {
|
||||
text += m_name;
|
||||
text += " yells:\n";
|
||||
m_color = Color(239, 239, 0);
|
||||
}
|
||||
else if(m_messageType == "monsterSay" || m_messageType == "monsterYell") {
|
||||
} else if(m_messageType == "monsterSay" || m_messageType == "monsterYell") {
|
||||
m_color = Color(254, 101, 0);
|
||||
}
|
||||
else if(m_messageType == "npcToPlayer") {
|
||||
} else if(m_messageType == "npcToPlayer") {
|
||||
text += m_name;
|
||||
text += " says:\n";
|
||||
m_color = Color(95, 247, 247);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
logWarning("unknown speak type: ", m_messageType);
|
||||
}
|
||||
|
||||
|
@ -116,6 +118,6 @@ void StaticText::compose()
|
|||
text += "\n";
|
||||
}
|
||||
|
||||
m_text = m_font->wrapText(text, 200);
|
||||
m_text = m_font->wrapText(text, Otc::MAX_STATIC_TEXT_WIDTH);
|
||||
m_textSize = m_font->calculateTextRectSize(m_text);
|
||||
}
|
||||
|
|
|
@ -29,19 +29,16 @@
|
|||
class StaticText : public Thing
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
DURATION_PER_CHARACTER = 75,
|
||||
MIN_DURATION = 3000
|
||||
};
|
||||
|
||||
StaticText();
|
||||
|
||||
void draw(const Point& p, const Rect& visibleRect);
|
||||
void draw(const Point& dest, const Rect& parentRect);
|
||||
|
||||
std::string getName() { return m_name; }
|
||||
std::string getMessageType() { return m_messageType; }
|
||||
std::string getFirstMessage() { return m_messages[0]; }
|
||||
|
||||
bool isYell() { return m_yell; }
|
||||
|
||||
bool addMessage(const std::string& name, const std::string& type, const std::string& message);
|
||||
void removeMessage();
|
||||
|
||||
|
@ -52,6 +49,7 @@ private:
|
|||
|
||||
FontPtr m_font;
|
||||
Size m_textSize;
|
||||
Boolean<false> m_yell;
|
||||
std::vector<std::string> m_messages;
|
||||
std::string m_name, m_text;
|
||||
std::string m_messageType;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "spritemanager.h"
|
||||
#include "thingstype.h"
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include "map.h"
|
||||
|
||||
Thing::Thing()
|
||||
{
|
||||
|
@ -32,51 +33,65 @@ Thing::Thing()
|
|||
m_yPattern = 0;
|
||||
m_zPattern = 0;
|
||||
m_animation = 0;
|
||||
m_type = getType();
|
||||
}
|
||||
|
||||
void Thing::internalDraw(const Point& p, int layer)
|
||||
{
|
||||
for(int h = 0; h < m_type->dimensions[ThingType::Height]; h++) {
|
||||
for(int w = 0; w < m_type->dimensions[ThingType::Width]; w++) {
|
||||
int spriteId = m_type->getSpriteId(w, h, layer, m_xPattern, m_yPattern, m_zPattern, m_animation);
|
||||
if(!spriteId)
|
||||
continue;
|
||||
|
||||
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
|
||||
|
||||
Rect drawRect((p.x - w*32) - m_type->parameters[ThingType::DisplacementX],
|
||||
(p.y - h*32) - m_type->parameters[ThingType::DisplacementY],
|
||||
32, 32);
|
||||
g_painter.drawTexturedRect(drawRect, spriteTex);
|
||||
}
|
||||
}
|
||||
m_type = g_thingsType.getEmptyThingType();
|
||||
}
|
||||
|
||||
void Thing::setId(uint32 id)
|
||||
{
|
||||
m_id = id;
|
||||
m_type = getType();
|
||||
updateType();
|
||||
}
|
||||
|
||||
int Thing::getStackPriority()
|
||||
{
|
||||
if(m_type->properties[ThingType::IsGround])
|
||||
if(isGround())
|
||||
return 0;
|
||||
else if(m_type->properties[ThingType::IsGroundBorder])
|
||||
else if(isGroundBorder())
|
||||
return 1;
|
||||
else if(m_type->properties[ThingType::IsOnBottom])
|
||||
else if(isOnBottom())
|
||||
return 2;
|
||||
else if(m_type->properties[ThingType::IsOnTop])
|
||||
else if(isOnTop())
|
||||
return 3;
|
||||
else if(asCreature())
|
||||
return 4;
|
||||
else // common items
|
||||
return 5;
|
||||
}
|
||||
|
||||
ThingType *Thing::getType()
|
||||
const TilePtr& Thing::getCurrentTile()
|
||||
{
|
||||
return g_thingsType.getEmptyThingType();
|
||||
return g_map.getTile(m_position);
|
||||
}
|
||||
|
||||
void Thing::internalDraw(const Point& dest, float scaleFactor, int layer)
|
||||
{
|
||||
int scaledSize = Otc::TILE_PIXELS * scaleFactor;
|
||||
|
||||
for(int h = 0; h < getDimensionHeight(); h++) {
|
||||
for(int w = 0; w < getDimensionWidth(); w++) {
|
||||
int spriteId = getSpriteId(w, h, layer, m_xPattern, m_yPattern, m_zPattern, m_animation);
|
||||
if(!spriteId)
|
||||
continue;
|
||||
|
||||
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
|
||||
Rect drawRect((dest.x - w*scaledSize) - getDisplacementX()*scaleFactor,
|
||||
(dest.y - h*scaledSize) - getDisplacementY()*scaleFactor,
|
||||
scaledSize, scaledSize);
|
||||
g_painter.drawTexturedRect(drawRect, spriteTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Thing::updateType()
|
||||
{
|
||||
if(CreaturePtr creature = asCreature())
|
||||
m_type = g_thingsType.getThingType(creature->getOutfit().getId(), creature->getOutfit().getCategory());
|
||||
else if(asItem())
|
||||
m_type = g_thingsType.getThingType(m_id, ThingsType::Item);
|
||||
else if(asMissile())
|
||||
m_type = g_thingsType.getThingType(m_id, ThingsType::Missile);
|
||||
else if(asEffect())
|
||||
m_type = g_thingsType.getThingType(m_id, ThingsType::Effect);
|
||||
else
|
||||
m_type = g_thingsType.getEmptyThingType();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define THING_H
|
||||
|
||||
#include "declarations.h"
|
||||
#include "thingtype.h"
|
||||
#include "thingstype.h"
|
||||
#include <framework/luascript/luaobject.h>
|
||||
|
||||
struct Light
|
||||
|
@ -39,19 +39,16 @@ public:
|
|||
Thing();
|
||||
virtual ~Thing() { }
|
||||
|
||||
virtual void start() {}
|
||||
virtual void startAnimation() { }
|
||||
virtual void draw(const Point& dest, float scaleFactor) { }
|
||||
|
||||
virtual void draw(const Point& p, const Rect&) = 0;
|
||||
virtual void setId(uint32 id);
|
||||
virtual void setPosition(const Position& position) { m_position = position; }
|
||||
|
||||
void setId(uint32 id);
|
||||
virtual void setPos(const Position& position) { m_pos = position; }
|
||||
|
||||
uint32 getId() const { return m_id; }
|
||||
Position getPos() const { return m_pos; }
|
||||
uint32 getId() { return m_id; }
|
||||
Position getPosition() { return m_position; }
|
||||
int getStackPriority();
|
||||
virtual ThingType *getType();
|
||||
int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; }
|
||||
int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; }
|
||||
const TilePtr& getCurrentTile();
|
||||
|
||||
void setXPattern(int xPattern) { m_xPattern = xPattern; }
|
||||
void setYPattern(int yPattern) { m_yPattern = yPattern; }
|
||||
|
@ -69,29 +66,53 @@ public:
|
|||
virtual AnimatedTextPtr asAnimatedText() { return nullptr; }
|
||||
virtual StaticTextPtr asStaticText() { return nullptr; }
|
||||
|
||||
// type related
|
||||
bool isGround() { return m_type->properties[ThingType::IsGround]; }
|
||||
bool isFullGround() { return m_type->properties[ThingType::IsFullGround]; }
|
||||
bool isGroundBorder() { return m_type->properties[ThingType::IsGroundBorder]; }
|
||||
bool isOnBottom() { return m_type->properties[ThingType::IsOnBottom]; }
|
||||
bool isOnTop() { return m_type->properties[ThingType::IsOnTop]; }
|
||||
bool isDontHide() { return m_type->properties[ThingType::DontHide]; }
|
||||
bool isContainer() { return m_type->properties[ThingType::IsContainer]; }
|
||||
bool isForceUse() { return m_type->properties[ThingType::IsForceUse]; }
|
||||
bool isMultiUse() { return m_type->properties[ThingType::IsMultiUse]; }
|
||||
bool isRotateable() { return m_type->properties[ThingType::IsRotateable]; }
|
||||
bool isNotMoveable() { return m_type->properties[ThingType::IsNotMovable]; }
|
||||
bool isNotWalkable() { return m_type->properties[ThingType::NotWalkable]; }
|
||||
bool isPickupable() { return m_type->properties[ThingType::IsPickupable]; }
|
||||
bool ignoreLook() { return m_type->properties[ThingType::IgnoreLook]; }
|
||||
bool isIgnoreLook() { return m_type->properties[ThingType::IgnoreLook]; }
|
||||
bool isHangable() { return m_type->properties[ThingType::IsHangable]; }
|
||||
bool isHookSouth() { return m_type->properties[ThingType::HookSouth]; }
|
||||
bool isHookEast() { return m_type->properties[ThingType::HookEast]; }
|
||||
bool isStackable() { return m_type->properties[ThingType::IsStackable]; }
|
||||
bool blocksProjectile() { return m_type->properties[ThingType::BlockProjectile]; }
|
||||
bool isFluid() { return m_type->properties[ThingType::IsFluid]; }
|
||||
bool isFluidContainer() { return m_type->properties[ThingType::IsFluidContainer]; }
|
||||
Size getDimension() { return Size(m_type->dimensions[ThingType::Width], m_type->dimensions[ThingType::Height]); }
|
||||
int getDimensionWidth() { return m_type->dimensions[ThingType::Width]; }
|
||||
int getDimensionHeight() { return m_type->dimensions[ThingType::Height]; }
|
||||
Point getDisplacement() { return Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]); }
|
||||
int getNumPatternsX() { return m_type->dimensions[ThingType::PatternX]; }
|
||||
int getNumPatternsY() { return m_type->dimensions[ThingType::PatternY]; }
|
||||
int getNumPatternsZ() { return m_type->dimensions[ThingType::PatternZ]; }
|
||||
int getDisplacementX() { return m_type->parameters[ThingType::DisplacementX]; }
|
||||
int getDisplacementY() { return m_type->parameters[ThingType::DisplacementY]; }
|
||||
int getLayers() { return m_type->dimensions[ThingType::Layers]; }
|
||||
int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; }
|
||||
int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; }
|
||||
int getElevation() { return m_type->parameters[ThingType::Elevation]; }
|
||||
int getSpriteId(int w = 0, int h = 0, int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animation = 0) { return m_type->getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animation); }
|
||||
|
||||
protected:
|
||||
void internalDraw(const Point& p, int layer);
|
||||
void internalDraw(const Point& dest, float scaleFactor, int layer);
|
||||
void updateType();
|
||||
|
||||
uint32 m_id;
|
||||
Position m_pos;
|
||||
ThingType *m_type;
|
||||
|
||||
Position m_position;
|
||||
int m_xPattern, m_yPattern, m_zPattern, m_animation;
|
||||
|
||||
private:
|
||||
ThingType *m_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,49 +33,53 @@
|
|||
Tile::Tile(const Position& position)
|
||||
{
|
||||
m_drawElevation = 0;
|
||||
m_pos = position;
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
void Tile::draw(const Point& p, const Rect& visibleRect)
|
||||
void Tile::draw(const Point& dest, float scaleFactor)
|
||||
{
|
||||
m_drawElevation = 0;
|
||||
|
||||
// first bottom items
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
ThingType *type = thing->getType();
|
||||
if(!type->properties[ThingType::IsGround] && !type->properties[ThingType::IsGroundBorder] && !type->properties[ThingType::IsOnBottom])
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||
break;
|
||||
thing->draw(p - m_drawElevation, visibleRect);
|
||||
m_drawElevation += type->parameters[ThingType::Elevation];
|
||||
if(m_drawElevation > MAX_DRAW_ELEVATION)
|
||||
m_drawElevation = MAX_DRAW_ELEVATION;
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
}
|
||||
|
||||
// now common items
|
||||
// now common items in reverse order
|
||||
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
|
||||
const ThingPtr& thing = *it;
|
||||
ThingType *type = thing->getType();
|
||||
if(thing->asCreature() || type->properties[ThingType::IsOnTop] || type->properties[ThingType::IsOnBottom] || type->properties[ThingType::IsGroundBorder] || type->properties[ThingType::IsGround])
|
||||
if(thing->asCreature() || thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround())
|
||||
break;
|
||||
thing->draw(p - m_drawElevation, visibleRect);
|
||||
m_drawElevation += type->parameters[ThingType::Elevation];
|
||||
if(m_drawElevation > MAX_DRAW_ELEVATION)
|
||||
m_drawElevation = MAX_DRAW_ELEVATION;
|
||||
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor);
|
||||
|
||||
m_drawElevation += thing->getElevation();
|
||||
if(m_drawElevation > Otc::MAX_ELEVATION)
|
||||
m_drawElevation = Otc::MAX_ELEVATION;
|
||||
}
|
||||
|
||||
// we can render creatures in 3x3 range
|
||||
//TODO: this algorithm is slowing down render too much, but it could be cached to improve framerate
|
||||
//NOTE: looping for 9 tiles is a dirty way to render walking creatures, must change this later
|
||||
for(int xi = -1; xi <= 1; ++xi) {
|
||||
for(int yi = -1; yi <= 1; ++yi) {
|
||||
for(CreaturePtr creature : g_map.getTile(m_pos + Position(xi, yi, 0))->getCreatures()) {
|
||||
ThingType *type = creature->getType();
|
||||
Rect creatureRect(p.x + xi*32 + creature->getWalkOffset().x - type->parameters[ThingType::DisplacementX], p.y + yi*32 + creature->getWalkOffset().y - type->parameters[ThingType::DisplacementY], 32, 32);
|
||||
Rect thisTileRect(p.x, p.y, 32, 32);
|
||||
const TilePtr& tile = g_map.getTile(m_position + Position(xi, yi, 0));
|
||||
if(!tile)
|
||||
continue;
|
||||
for(const CreaturePtr& creature : tile->getCreatures()) {
|
||||
int tileSize = Otc::TILE_PIXELS * scaleFactor;
|
||||
Rect creatureRect(dest.x + xi*tileSize + (creature->getWalkOffset().x - creature->getDisplacementX())*scaleFactor,
|
||||
dest.y + yi*tileSize + (creature->getWalkOffset().y - creature->getDisplacementY())*scaleFactor,
|
||||
tileSize, tileSize);
|
||||
Rect thisTileRect(dest.x, dest.y, tileSize, tileSize);
|
||||
|
||||
// only render creatures where bottom right is inside our rect
|
||||
if(thisTileRect.contains(creatureRect.bottomRight())) {
|
||||
creature->draw(Point(p.x + xi*32 - m_drawElevation, p.y + yi*32 - m_drawElevation), visibleRect);
|
||||
creature->draw(Point(dest.x + xi*tileSize - m_drawElevation*scaleFactor,
|
||||
dest.y + yi*tileSize - m_drawElevation*scaleFactor), scaleFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,13 +87,12 @@ void Tile::draw(const Point& p, const Rect& visibleRect)
|
|||
|
||||
// effects
|
||||
for(const EffectPtr& effect : m_effects)
|
||||
effect->draw(p - m_drawElevation, visibleRect);
|
||||
effect->draw(dest, scaleFactor);
|
||||
|
||||
// top items
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
ThingType *type = thing->getType();
|
||||
if(type->properties[ThingType::IsOnTop])
|
||||
thing->draw(p, visibleRect);
|
||||
if(thing->isOnTop())
|
||||
thing->draw(dest - m_drawElevation, scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +107,8 @@ ThingPtr Tile::addThing(const ThingPtr& thing, int stackPos)
|
|||
if(!thing)
|
||||
return nullptr;
|
||||
|
||||
thing->setPosition(m_position);
|
||||
|
||||
if(EffectPtr effect = thing->asEffect()) {
|
||||
m_effects.push_back(effect);
|
||||
return nullptr;
|
||||
|
@ -124,9 +129,40 @@ ThingPtr Tile::addThing(const ThingPtr& thing, int stackPos)
|
|||
if(stackPos < (int)m_things.size())
|
||||
oldObject = m_things[stackPos];
|
||||
m_things.insert(m_things.begin() + stackPos, thing);
|
||||
|
||||
return oldObject;
|
||||
}
|
||||
|
||||
bool Tile::removeThing(const ThingPtr& thing)
|
||||
{
|
||||
if(!thing)
|
||||
return false;
|
||||
|
||||
bool removed = false;
|
||||
|
||||
if(EffectPtr effect = thing->asEffect()) {
|
||||
auto it = std::find(m_effects.begin(), m_effects.end(), effect);
|
||||
if(it != m_effects.end()) {
|
||||
m_effects.erase(it);
|
||||
removed = true;
|
||||
}
|
||||
} else {
|
||||
auto it = std::find(m_things.begin(), m_things.end(), thing);
|
||||
if(it != m_things.end()) {
|
||||
m_things.erase(it);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// reset values managed by this tile
|
||||
if(removed) {
|
||||
//thing->setDrawOffset(0);
|
||||
//thing->setStackpos(0);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
ThingPtr Tile::getThing(int stackPos)
|
||||
{
|
||||
if(stackPos >= 0 && stackPos < (int)m_things.size())
|
||||
|
@ -150,33 +186,6 @@ ThingPtr Tile::getTopThing()
|
|||
return m_things[m_things.size() - 1];
|
||||
}
|
||||
|
||||
ThingPtr Tile::removeThingByStackpos(int stackPos)
|
||||
{
|
||||
ThingPtr oldThing;
|
||||
if(stackPos >= 0 && stackPos < (int)m_things.size()) {
|
||||
oldThing = m_things[stackPos];
|
||||
m_things.erase(m_things.begin() + stackPos);
|
||||
}
|
||||
return oldThing;
|
||||
}
|
||||
|
||||
ThingPtr Tile::removeThing(const ThingPtr& thing)
|
||||
{
|
||||
if(EffectPtr effect = thing->asEffect()) {
|
||||
auto it = std::find(m_effects.begin(), m_effects.end(), effect);
|
||||
if(it != m_effects.end())
|
||||
m_effects.erase(it);
|
||||
return thing;
|
||||
}
|
||||
ThingPtr oldThing;
|
||||
auto it = std::find(m_things.begin(), m_things.end(), thing);
|
||||
if(it != m_things.end()) {
|
||||
oldThing = *it;
|
||||
m_things.erase(it);
|
||||
}
|
||||
return oldThing;
|
||||
}
|
||||
|
||||
std::vector<CreaturePtr> Tile::getCreatures()
|
||||
{
|
||||
std::vector<CreaturePtr> creatures;
|
||||
|
@ -192,8 +201,7 @@ ItemPtr Tile::getGround()
|
|||
ThingPtr firstObject = getThing(0);
|
||||
if(!firstObject)
|
||||
return nullptr;
|
||||
ThingType *type = firstObject->getType();
|
||||
if(type->properties[ThingType::IsGround])
|
||||
if(firstObject->isGround())
|
||||
return firstObject->asItem();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -213,7 +221,7 @@ ThingPtr Tile::getTopLookThing()
|
|||
|
||||
for(uint i = 0; i < m_things.size(); ++i) {
|
||||
ThingPtr thing = m_things[i];
|
||||
if(!thing->ignoreLook() && (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()))
|
||||
if(!thing->isIgnoreLook() && (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()))
|
||||
return thing;
|
||||
}
|
||||
|
||||
|
@ -239,7 +247,7 @@ CreaturePtr Tile::getTopCreature()
|
|||
CreaturePtr creature;
|
||||
for(uint i = 0; i < m_things.size(); ++i) {
|
||||
ThingPtr thing = m_things[i];
|
||||
if(thing->asLocalPlayer()) // return local player if there aint no other creature.
|
||||
if(thing->asLocalPlayer()) // return local player if there is no other creature
|
||||
creature = thing->asCreature();
|
||||
else if(thing->asCreature() && !thing->asLocalPlayer())
|
||||
return thing->asCreature();
|
||||
|
@ -288,8 +296,7 @@ bool Tile::isWalkable()
|
|||
return false;
|
||||
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
ThingType *type = thing->getType();
|
||||
if(type->properties[ThingType::NotWalkable])
|
||||
if(thing->isNotWalkable())
|
||||
return false;
|
||||
|
||||
if(CreaturePtr creature = thing->asCreature()) {
|
||||
|
@ -302,11 +309,8 @@ bool Tile::isWalkable()
|
|||
|
||||
bool Tile::isFullGround()
|
||||
{
|
||||
ThingPtr ground = getThing(0);
|
||||
if(!ground)
|
||||
return false;
|
||||
ThingType *type = ground->getType();
|
||||
if(type->properties[ThingType::IsGround] && type->properties[ThingType::IsFullGround])
|
||||
ItemPtr ground = getGround();
|
||||
if(ground && ground->isFullGround())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -314,19 +318,13 @@ bool Tile::isFullGround()
|
|||
bool Tile::isFullyOpaque()
|
||||
{
|
||||
ThingPtr firstObject = getThing(0);
|
||||
if(firstObject) {
|
||||
ThingType *type = firstObject->getType();
|
||||
if(type->properties[ThingType::IsFullGround])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return firstObject && firstObject->isFullGround();
|
||||
}
|
||||
|
||||
bool Tile::isLookPossible()
|
||||
{
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
ThingType *type = thing->getType();
|
||||
if(type->properties[ThingType::BlockProjectile])
|
||||
if(thing->blocksProjectile())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -334,14 +332,15 @@ bool Tile::isLookPossible()
|
|||
|
||||
bool Tile::isClickable()
|
||||
{
|
||||
bool hasGround = false, hasOnBottom = false, hasIgnoreLook = false;
|
||||
bool hasGround = false;
|
||||
bool hasOnBottom = false;
|
||||
bool hasIgnoreLook = false;
|
||||
for(const ThingPtr& thing : m_things) {
|
||||
ThingType *type = thing->getType();
|
||||
if(type->properties[ThingType::IsGround])
|
||||
if(thing->isGround())
|
||||
hasGround = true;
|
||||
if(type->properties[ThingType::IsOnBottom])
|
||||
if(thing->isOnBottom())
|
||||
hasOnBottom = true;
|
||||
if(type->properties[ThingType::IgnoreLook])
|
||||
if(thing->isIgnoreLook())
|
||||
hasIgnoreLook = true;
|
||||
|
||||
if((hasGround || hasOnBottom) && !hasIgnoreLook)
|
||||
|
@ -350,6 +349,11 @@ bool Tile::isClickable()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Tile::isEmpty()
|
||||
{
|
||||
return m_things.size() == 0;
|
||||
}
|
||||
|
||||
bool Tile::hasCreature()
|
||||
{
|
||||
for(const ThingPtr& thing : m_things)
|
||||
|
@ -358,7 +362,11 @@ bool Tile::hasCreature()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Tile::isEmpty()
|
||||
bool Tile::limitsFloorsView()
|
||||
{
|
||||
return m_things.size() == 0;
|
||||
// ground and walls limits the view
|
||||
ThingPtr firstThing = getThing(0);
|
||||
if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -28,21 +28,25 @@
|
|||
|
||||
class Tile : public LuaObject
|
||||
{
|
||||
enum {
|
||||
MAX_DRAW_ELEVATION = 24
|
||||
};
|
||||
public:
|
||||
Tile(const Position& position);
|
||||
|
||||
void draw(const Point& p, const Rect& visibleRect);
|
||||
void draw(const Point& dest, float scaleFactor);
|
||||
|
||||
private:
|
||||
void updateVisibleItemsCache();
|
||||
|
||||
public:
|
||||
void clean();
|
||||
|
||||
ThingPtr addThing(const ThingPtr& thing, int stackPos = -1);
|
||||
bool removeThing(const ThingPtr& thing);
|
||||
ThingPtr getThing(int stackPos);
|
||||
int getThingStackpos(const ThingPtr& thing);
|
||||
ThingPtr getTopThing();
|
||||
ThingPtr removeThingByStackpos(int stackPos);
|
||||
ThingPtr removeThing(const ThingPtr& thing);
|
||||
|
||||
void addWalkingCreature(const CreaturePtr& creature);
|
||||
void removeWalkingCreature(const CreaturePtr& creature);
|
||||
|
||||
|
||||
ThingPtr getTopLookThing();
|
||||
|
@ -51,7 +55,7 @@ public:
|
|||
ThingPtr getTopMoveThing();
|
||||
ThingPtr getTopMultiUseThing();
|
||||
|
||||
const Position& getPos() { return m_pos; }
|
||||
const Position& getPosition() { return m_position; }
|
||||
int getDrawElevation() { return m_drawElevation; }
|
||||
std::vector<CreaturePtr> getCreatures();
|
||||
ItemPtr getGround();
|
||||
|
@ -60,16 +64,19 @@ public:
|
|||
bool isFullGround();
|
||||
bool isFullyOpaque();
|
||||
bool isLookPossible();
|
||||
bool hasCreature();
|
||||
bool isEmpty();
|
||||
bool isClickable();
|
||||
bool isEmpty();
|
||||
bool hasCreature();
|
||||
bool limitsFloorsView();
|
||||
int getThingCount() { return m_things.size() + m_effects.size(); }
|
||||
|
||||
TilePtr asTile() { return std::static_pointer_cast<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;
|
||||
Position m_position;
|
||||
int m_drawElevation;
|
||||
};
|
||||
|
||||
|
|
|
@ -60,10 +60,9 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction("g_sprites", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites));
|
||||
|
||||
g_lua.registerStaticClass("g_map");
|
||||
g_lua.bindClassStaticFunction("g_map", "getFirstVisibleFloor", std::bind(&Map::getFirstVisibleFloor, &g_map));
|
||||
g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "isCovered", std::bind(&Map::isCovered, &g_map, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_map", "isCompletlyCovered", std::bind(&Map::isCompletlyCovered, &g_map, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_map", "isCompletelyCovered", std::bind(&Map::isCompletelyCovered, &g_map, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_map", "addThing", std::bind(&Map::addThing, &g_map, _1, _2, _3));
|
||||
g_lua.bindClassStaticFunction("g_map", "getThing", std::bind(&Map::getThing, &g_map, _1, _2));
|
||||
g_lua.bindClassStaticFunction("g_map", "removeThingByPos", std::bind(&Map::removeThingByPos, &g_map, _1, _2));
|
||||
|
@ -72,13 +71,8 @@ void OTClient::registerLuaFunctions()
|
|||
g_lua.bindClassStaticFunction("g_map", "getTile", std::bind(&Map::getTile, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "setCentralPosition", std::bind(&Map::setCentralPosition, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "getCentralPosition", std::bind(&Map::getCentralPosition, &g_map));
|
||||
g_lua.bindClassStaticFunction("g_map", "addCreature", std::bind(&Map::addCreature, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "getCreatureById", std::bind(&Map::getCreatureById, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "removeCreatureById", std::bind(&Map::removeCreatureById, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "setVisibleSize", std::bind(&Map::setVisibleSize, &g_map, _1));
|
||||
g_lua.bindClassStaticFunction("g_map", "getVibibleSize", std::bind(&Map::getVibibleSize, &g_map));
|
||||
g_lua.bindClassStaticFunction("g_map", "getCentralOffset", std::bind(&Map::getCentralOffset, &g_map));
|
||||
g_lua.bindClassStaticFunction("g_map", "positionTo2D", std::bind(&Map::positionTo2D, &g_map, _1));
|
||||
|
||||
g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor);
|
||||
|
||||
|
@ -91,9 +85,9 @@ void OTClient::registerLuaFunctions()
|
|||
|
||||
g_lua.registerClass<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);
|
||||
|
@ -118,7 +112,7 @@ 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.registerClass<Creature, Thing>();
|
||||
|
@ -165,14 +159,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);
|
||||
|
@ -238,6 +231,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); } );
|
||||
|
|
|
@ -407,7 +407,7 @@ void ProtocolGame::parseCreatureMove(InputMessage& msg)
|
|||
int oldStackpos = msg.getU8();
|
||||
Position newPos = parsePosition(msg);
|
||||
|
||||
ThingPtr thing = g_map.getTile(oldPos)->getThing(oldStackpos);
|
||||
ThingPtr thing = g_map.getThing(oldPos, oldStackpos);
|
||||
if(!thing) {
|
||||
logTraceError("could not get thing");
|
||||
return;
|
||||
|
@ -566,10 +566,10 @@ void ProtocolGame::parseDistanceMissile(InputMessage& msg)
|
|||
Position toPos = parsePosition(msg);
|
||||
int shotId = msg.getU8();
|
||||
|
||||
MissilePtr shot = MissilePtr(new Missile());
|
||||
shot->setId(shotId);
|
||||
shot->setPath(fromPos, toPos);
|
||||
g_map.addThing(shot, fromPos);
|
||||
MissilePtr missile = MissilePtr(new Missile());
|
||||
missile->setId(shotId);
|
||||
missile->setPath(fromPos, toPos);
|
||||
g_map.addThing(missile, fromPos);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseCreatureSquare(InputMessage& msg)
|
||||
|
@ -866,7 +866,7 @@ void ProtocolGame::parseOutfitWindow(InputMessage& msg)
|
|||
}
|
||||
|
||||
CreaturePtr creature = CreaturePtr(new Creature);
|
||||
creature->setXPattern(2);
|
||||
creature->setDirection(Otc::South);
|
||||
creature->setOutfit(outfit);
|
||||
|
||||
g_lua.callGlobalField("Game", "onOpenOutfitWindow", creature, outfitList);
|
||||
|
@ -1041,7 +1041,7 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
|||
if(knownCreature)
|
||||
creature = knownCreature;
|
||||
else
|
||||
logTraceError("server says creature is known, but its not on creatures list");
|
||||
logTraceError("server said that a creature is known, but it's not");
|
||||
} else if(thingId == 0x0061) { //creature is not known
|
||||
uint removeId = msg.getU32();
|
||||
uint id = msg.getU32();
|
||||
|
@ -1065,6 +1065,8 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
|||
|
||||
creature->setId(id);
|
||||
creature->setName(name);
|
||||
|
||||
g_map.addCreature(creature);
|
||||
}
|
||||
|
||||
uint8 healthPercent = msg.getU8();
|
||||
|
|
|
@ -30,7 +30,7 @@ void UICreature::draw()
|
|||
|
||||
if(m_creature) {
|
||||
g_painter.setColor(Fw::white);
|
||||
m_creature->draw(m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top), m_rect);
|
||||
m_creature->draw(m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top), 1);
|
||||
}
|
||||
|
||||
drawChildren();
|
||||
|
|
|
@ -38,7 +38,7 @@ void UIItem::draw()
|
|||
Point topLeft = m_rect.bottomRight() - Point(32, 32) + Point(m_padding.left, m_padding.top);
|
||||
|
||||
g_painter.setColor(Fw::white);
|
||||
m_item->draw(topLeft, m_rect);
|
||||
m_item->draw(topLeft, 1);
|
||||
|
||||
if(m_font && m_item->isStackable() && m_item->getData() > 1) {
|
||||
std::string count = Fw::tostring(m_item->getData());
|
||||
|
|
|
@ -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,56 @@
|
|||
UIMap::UIMap()
|
||||
{
|
||||
m_dragable = true;
|
||||
m_mapView = MapViewPtr(new MapView);
|
||||
g_map.addMapView(m_mapView);
|
||||
m_mapView->followCreature(g_game.getLocalPlayer());
|
||||
}
|
||||
|
||||
UIMap::~UIMap()
|
||||
{
|
||||
g_map.removeMapView(m_mapView);
|
||||
}
|
||||
|
||||
void UIMap::draw()
|
||||
{
|
||||
drawSelf();
|
||||
|
||||
// draw black brounding border
|
||||
g_painter.setColor(Fw::black);
|
||||
g_painter.drawBoundingRect(m_mapRect.expanded(1));
|
||||
g_map.draw(m_mapRect);
|
||||
|
||||
m_mapView->draw(m_mapRect);
|
||||
|
||||
drawChildren();
|
||||
}
|
||||
|
||||
void UIMap::zoomIn()
|
||||
{
|
||||
m_mapView->setVisibleDimension(m_mapView->getVisibleDimension() + Size(2,2));
|
||||
|
||||
Rect mapRect = getChildrenRect().expanded(-1);
|
||||
Size mapSize = m_mapView->getVisibleSize();
|
||||
mapSize.scale(mapRect.size(), Fw::KeepAspectRatio);
|
||||
|
||||
m_mapRect.resize(mapSize);
|
||||
m_mapRect.moveCenter(m_rect.center());
|
||||
}
|
||||
|
||||
void UIMap::zoomOut()
|
||||
{
|
||||
m_mapView->setVisibleDimension(m_mapView->getVisibleDimension() - Size(2,2));
|
||||
|
||||
Rect mapRect = getChildrenRect().expanded(-1);
|
||||
Size mapSize = m_mapView->getVisibleSize();
|
||||
mapSize.scale(mapRect.size(), Fw::KeepAspectRatio);
|
||||
|
||||
m_mapRect.resize(mapSize);
|
||||
m_mapRect.moveCenter(m_rect.center());
|
||||
}
|
||||
|
||||
TilePtr UIMap::getTile(const Point& mousePos)
|
||||
{
|
||||
/*
|
||||
if(!m_mapRect.contains(mousePos))
|
||||
return nullptr;
|
||||
|
||||
|
@ -55,12 +91,12 @@ TilePtr UIMap::getTile(const Point& mousePos)
|
|||
if(localPlayer)
|
||||
relativeStretchMousePos += localPlayer->getWalkOffset();
|
||||
|
||||
Size mapSize(g_map.getVibibleSize().width() * Map::NUM_TILE_PIXELS, g_map.getVibibleSize().height() * Map::NUM_TILE_PIXELS);
|
||||
Size mapSize(g_map.getVibibleSize().width() * Otc::TILE_PIXELS, g_map.getVibibleSize().height() * Otc::TILE_PIXELS);
|
||||
|
||||
PointF stretchFactor(m_mapRect.width() / (float)mapSize.width(), m_mapRect.height() / (float)mapSize.height());
|
||||
PointF relativeMousePos = PointF(relativeStretchMousePos.x, relativeStretchMousePos.y) / stretchFactor;
|
||||
|
||||
PointF tilePosF = relativeMousePos / Map::NUM_TILE_PIXELS;
|
||||
PointF tilePosF = relativeMousePos / Otc::TILE_PIXELS;
|
||||
Position tilePos = Position(1 + (int)tilePosF.x - g_map.getCentralOffset().x, 1 + (int)tilePosF.y - g_map.getCentralOffset().y, 0) + g_map.getCentralPosition();
|
||||
if(!tilePos.isValid())
|
||||
return nullptr;
|
||||
|
@ -70,7 +106,7 @@ TilePtr UIMap::getTile(const Point& mousePos)
|
|||
|
||||
// We must check every floor, from top to bottom to check for a clickable tile
|
||||
int firstFloor = g_map.getFirstVisibleFloor();
|
||||
tilePos.perspectiveUp(tilePos.z - firstFloor);
|
||||
tilePos.coveredUp(tilePos.z - firstFloor);
|
||||
for(int i = firstFloor; i <= Map::MAX_Z; i++) {
|
||||
tile = g_map.getTile(tilePos);
|
||||
if(tile && tile->isClickable())
|
||||
|
@ -84,12 +120,14 @@ TilePtr UIMap::getTile(const Point& mousePos)
|
|||
return nullptr;
|
||||
|
||||
return tile;
|
||||
*/
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UIMap::onGeometryChange(const Rect& oldRect, const Rect& newRect)
|
||||
{
|
||||
Rect mapRect = getChildrenRect().expanded(-1);
|
||||
Size mapSize(g_map.getVibibleSize().width() * Map::NUM_TILE_PIXELS, g_map.getVibibleSize().height() * Map::NUM_TILE_PIXELS);
|
||||
Size mapSize = m_mapView->getVisibleSize();
|
||||
mapSize.scale(mapRect.size(), Fw::KeepAspectRatio);
|
||||
|
||||
m_mapRect.resize(mapSize);
|
||||
|
|
|
@ -31,14 +31,20 @@ class UIMap : public UIWidget
|
|||
{
|
||||
public:
|
||||
UIMap();
|
||||
~UIMap();
|
||||
|
||||
void draw();
|
||||
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
|
||||
TilePtr getTile(const Point& mousePos);
|
||||
|
||||
protected:
|
||||
virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect);
|
||||
|
||||
private:
|
||||
MapViewPtr m_mapView;
|
||||
Rect m_mapRect;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
Position() : x(-1), y(-1), z(-1) { }
|
||||
Position(int x, int y, int z) : x(x), y(y), z(z) { }
|
||||
|
||||
static Position getPosFromDirection(Otc::Direction direction) {
|
||||
static Position getPositionFromDirection(Otc::Direction direction) {
|
||||
switch(direction) {
|
||||
case Otc::North:
|
||||
return Position( 0, -1, 0);
|
||||
|
@ -116,7 +116,7 @@ public:
|
|||
void up(int n = 1) { z-=n; }
|
||||
void down(int n = 1) { z+=n; }
|
||||
|
||||
void perspectiveUp(int n = 1) { x+=n; y+=n; z-=n; }
|
||||
void coveredUp(int n = 1) { x+=n; y+=n; z-=n; }
|
||||
void coveredDown(int n = 1) { x-=n; y-=n; z+=n; }
|
||||
|
||||
int x;
|
||||
|
|
Loading…
Reference in New Issue