diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d67f33c..0f2bce00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,8 @@ SET(SOURCES src/item.cpp src/tile.cpp src/thing.cpp + src/creature.cpp + src/effect.cpp # framework third party src/framework/thirdparty/apngloader.cpp diff --git a/src/creature.cpp b/src/creature.cpp new file mode 100644 index 00000000..431474c9 --- /dev/null +++ b/src/creature.cpp @@ -0,0 +1,64 @@ +#include "creature.h" +#include "tibiadat.h" +#include "graphics/graphics.h" +#include +#include "game.h" + +#include +#include +#include + + + + + + +// OW BART TEM COMO USAR 2 FRAMEBUFFER? +// SERIA O IDEAL PARA DESENHAR A COR DOS BONEQUIN. + + + + + + +Creature::Creature() +{ + m_type = Thing::TYPE_CREATURE; +} + +ThingAttributes *Creature::getAttributes() +{ + return g_tibiaDat.getCreatureAttributes(m_outfit.type); +} + +void Creature::draw(int x, int y) +{ + //ThingAttributes *creatureAttributes = getAttributes(); + int anim = 0; + + // draw outfit + internalDraw(x, y, 0, m_direction, 0, 0, anim); + + // draw addons + //for(int a = 0; a < m_outfit.addons; ++a) { + //internalDraw(x, y, 0, m_direction, m_outfit.addons & (1 << a), 0, anim); + //} + //glPushAttrib(GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT); + + //glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + + //Color colors[4] = {Color::yellow, Color::red, Color::green, Color::blue}; + + //for(int i = 0; i < 4; ++i) { + + + /*g_graphics.bindColor(colors[i]); + internalDraw(creatureAttributes->width*32 - 32, creatureAttributes->height*32 - 32, 1, m_direction, 0, 0, 0); + framebuffer.unbind(); + + + g_graphics.bindColor(Color::green);*/ + //framebuffer.draw(x, y, creatureAttributes->width*32, creatureAttributes->height*32); + //} + //glPopAttrib(); +} diff --git a/src/creature.h b/src/creature.h new file mode 100644 index 00000000..3eb0aee3 --- /dev/null +++ b/src/creature.h @@ -0,0 +1,51 @@ +#ifndef CREATURE_H +#define CREATURE_H + +#include +#include "thing.h" + +struct Outfit +{ + uint16 type; + uint8 head; + uint8 body; + uint8 legs; + uint8 feet; + uint8 addons; +}; + +class Creature; +typedef std::shared_ptr CreaturePtr; + +class Creature : public Thing +{ +public: + Creature(); + + virtual ThingAttributes *getAttributes(); + void draw(int x, int y); + + void setName(const std::string& name) { m_name = name; } + std::string getName() { return m_name; } + + void setHealthPercent(uint8 healthPercent) { m_healthPercent = healthPercent; } + uint8 getHealthPercent() { return m_healthPercent; } + + void setDirection(Direction direction) { m_direction = direction; } + Direction getDirection() { return m_direction; } + + void setOutfit(const Outfit& outfit) { m_outfit = outfit; } + Outfit getOutfit() { return m_outfit; } + + virtual Creature *getCreature() { return this; } + virtual const Creature *getCreature() const { return this; } + +private: + std::string m_name; + uint8 m_healthPercent; + Direction m_direction; + Outfit m_outfit; + +}; + +#endif // CREATURE_H diff --git a/src/effect.cpp b/src/effect.cpp new file mode 100644 index 00000000..fcdec57f --- /dev/null +++ b/src/effect.cpp @@ -0,0 +1,18 @@ +#include "effect.h" +#include "tibiadat.h" + +Effect::Effect() +{ + m_type = Thing::TYPE_EFFECT; +} + +ThingAttributes *Effect::getAttributes() +{ + return g_tibiaDat.getEffectAttributes(m_id); +} + +void Effect::draw(int x, int y) +{ + int anim = 0; + internalDraw(x, y, 0, 0, 0, 0, anim); +} diff --git a/src/effect.h b/src/effect.h new file mode 100644 index 00000000..1a1cc73c --- /dev/null +++ b/src/effect.h @@ -0,0 +1,21 @@ +#ifndef EFFECT_H +#define EFFECT_H + +#include +#include "thing.h" + +class Effect; +typedef std::shared_ptr EffectPtr; + +class Effect : public Thing +{ +public: + Effect(); + + virtual ThingAttributes *getAttributes(); + void draw(int x, int y); + +private: +}; + +#endif // EFFECT_H diff --git a/src/framework/net/connection.cpp b/src/framework/net/connection.cpp index 9055fc5f..1633502f 100644 --- a/src/framework/net/connection.cpp +++ b/src/framework/net/connection.cpp @@ -11,6 +11,11 @@ Connection::Connection() : { } +Connection::~Connection() +{ + disconnect(); +} + void Connection::poll() { ioService.poll(); @@ -28,6 +33,11 @@ void Connection::connect(const std::string& host, uint16 port, const ConnectCall m_timer.async_wait(std::bind(&Connection::onTimeout, shared_from_this(), std::placeholders::_1)); } +void Connection::disconnect() +{ + m_socket.close(); +} + void Connection::send(uint8* buffer, uint16 size) { asio::async_write(m_socket, diff --git a/src/framework/net/connection.h b/src/framework/net/connection.h index bd36819b..2091aef4 100644 --- a/src/framework/net/connection.h +++ b/src/framework/net/connection.h @@ -11,10 +11,12 @@ class Connection : public std::enable_shared_from_this, boost::nonco public: Connection(); + ~Connection(); static void poll(); void connect(const std::string& host, uint16 port, const ConnectCallback& connectCallback); + void disconnect(); void send(uint8* buffer, uint16 size); void recv(uint16 bytes, uint32 timeout, const RecvCallback& callback); diff --git a/src/framework/util/color.cpp b/src/framework/util/color.cpp index b80289d5..5c1bcb76 100644 --- a/src/framework/util/color.cpp +++ b/src/framework/util/color.cpp @@ -1,9 +1,10 @@ #include "color.h" -Color Color::white(0xFF, 0xFF, 0xFF, 0xFF); -Color Color::black(0x00, 0x00, 0x00, 0xFF); -Color Color::alpha(0x00, 0x00, 0x00, 0x00); -Color Color::red (0xFF, 0x00, 0x00, 0xFF); -Color Color::green(0x00, 0xFF, 0x00, 0xFF); -Color Color::blue (0x00, 0x00, 0xFF, 0xFF); -Color Color::pink (0xFF, 0x00, 0xFF, 0xFF); +Color Color::white (0xFF, 0xFF, 0xFF, 0xFF); +Color Color::black (0x00, 0x00, 0x00, 0xFF); +Color Color::alpha (0x00, 0x00, 0x00, 0x00); +Color Color::red (0xFF, 0x00, 0x00, 0xFF); +Color Color::green (0x00, 0xFF, 0x00, 0xFF); +Color Color::blue (0x00, 0x00, 0xFF, 0xFF); +Color Color::pink (0xFF, 0x00, 0xFF, 0xFF); +Color Color::yellow(0x00, 0xFF, 0xFF, 0xFF); diff --git a/src/framework/util/color.h b/src/framework/util/color.h index adacb81e..415b1a26 100644 --- a/src/framework/util/color.h +++ b/src/framework/util/color.h @@ -39,6 +39,7 @@ public: static Color green; static Color blue; static Color pink; + static Color yellow; private: RGBA color; diff --git a/src/game.cpp b/src/game.cpp index f9e55c6b..d3968153 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,3 +1,8 @@ #include "game.h" Game g_game; + +Game::Game() +{ + m_online = false; +} diff --git a/src/game.h b/src/game.h index 7d6bf8c7..f1eb21a4 100644 --- a/src/game.h +++ b/src/game.h @@ -9,17 +9,22 @@ class Game { public: + Game(); - void setProtocol(ProtocolGame *protocolGame) { m_protocolGame = protocolGame; } - ProtocolGame *getProtocol() { return m_protocolGame; } + void setProtocol(ProtocolGamePtr protocolGame) { m_protocolGame = protocolGame; } + ProtocolGamePtr getProtocol() { return m_protocolGame; } Map *getMap() { return &m_map; } Player *getPlayer() { return &m_player; } + void setOnline(bool online) { m_online = online; } + bool getOnline() { return m_online; } + private: Map m_map; Player m_player; - ProtocolGame *m_protocolGame; + ProtocolGamePtr m_protocolGame; + bool m_online; }; diff --git a/src/item.cpp b/src/item.cpp index 1533c045..3c7a866d 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2,96 +2,34 @@ #include "tibiadat.h" #include "tibiaspr.h" #include - -ItemAttributes::ItemAttributes() -{ - group = ITEM_GROUP_NONE; - blockSolid = false; - hasHeight = false; - blockPathFind = false; - blockProjectile = false; - alwaysOnTop = false; - alwaysOnTopOrder = 0; - stackable = false; - useable = false; - moveable = true; - pickupable = false; - rotable = false; - readable = false; - lookThrough = false; - speed = 0; - lightLevel = 0; - lightColor = 0; - isVertical = false; - isHorizontal = false; - isHangable = false; - miniMapColor = 0; - hasMiniMapColor = false; - subParam07 = 0; - subParam08 = 0; - sprites = NULL; - width = 0; - height = 0; - blendframes = 0; - xdiv = 0; - ydiv = 0; - zdiv = 0; - animcount = 0; -} - -ItemAttributes::~ItemAttributes() -{ - if(sprites) - delete []sprites; -} +#include "thing.h" Item::Item() { m_type = Thing::TYPE_ITEM; } -void Item::draw(int x, int y, int z) +ThingAttributes *Item::getAttributes() { - ItemAttributes *itemAttributes = g_tibiaDat.getItemAttributes(m_id); + return g_tibiaDat.getItemAttributes(m_id); +} - int cDivX = 0, cDivY = 0, cDivZ = 0, cAnim = 0; +void Item::draw(int x, int y) +{ + ThingAttributes *itemAttributes = getAttributes(); - if(itemAttributes->group == ITEM_GROUP_SPLASH || itemAttributes->group == ITEM_GROUP_FLUID || itemAttributes->stackable) { + int xdiv = 0, ydiv = 0, zdiv = 0, anim = 0; + + if(itemAttributes->group == THING_GROUP_SPLASH || itemAttributes->group == THING_GROUP_FLUID || itemAttributes->stackable) { //cDivX = subType % itemAttributes->xdiv; //cDivY = subType / itemAttributes->xdiv; } else if(!itemAttributes->moveable) { - cDivX = x % itemAttributes->xdiv; - cDivY = y % itemAttributes->ydiv; - cDivZ = z % itemAttributes->zdiv; + xdiv = m_position.x % itemAttributes->xdiv; + ydiv = m_position.y % itemAttributes->ydiv; + zdiv = m_position.z % itemAttributes->zdiv; } - x *= 32; - y *= 32; - z = (7-z)*32; - - for(int b = 0; b < itemAttributes->blendframes; b++) { - for(int yi = 0; yi < itemAttributes->height; yi++) { - for(int xi = 0; xi < itemAttributes->width; xi++) { - uint16 sprIndex = xi + - yi * itemAttributes->width + - b * itemAttributes->width * itemAttributes->height + - cDivX * itemAttributes->width * itemAttributes->height * itemAttributes->blendframes + - cDivY * itemAttributes->width * itemAttributes->height * itemAttributes->blendframes * itemAttributes->xdiv + - cDivZ * itemAttributes->width * itemAttributes->height * itemAttributes->blendframes * itemAttributes->xdiv * itemAttributes->ydiv + - cAnim * itemAttributes->width * itemAttributes->height * itemAttributes->blendframes * itemAttributes->xdiv * itemAttributes->ydiv * itemAttributes->zdiv; - uint16 itemId = itemAttributes->sprites[sprIndex]; - if(itemId == 0xFFFF) - continue; - TexturePtr data = g_tibiaSpr.getSprite(itemId); - - // todo verify this to draw in correct pos (screenX, screenY) - g_graphics.drawTexturedRect(Rect(x - xi*32 - z, y - yi*32 - z, 32, 32), data, Rect(0, 0, 32, 32)); - - //g_graphics.drawBoundingRect(Rect(x - xi*32 - z, y - yi*32 - z, 32, 32), Color::green); - if(x/32 == 7 && y/32 == 5 && z/32+7 == 7) - g_graphics.drawBoundingRect(Rect(x - xi*32 - z, y - yi*32 - z, 32, 32), Color::red); - } - } - } + for(int b = 0; b < itemAttributes->blendframes; b++) + internalDraw(x, y, b, xdiv, ydiv, zdiv, anim); } diff --git a/src/item.h b/src/item.h index 26bd87bd..b0a9fb18 100644 --- a/src/item.h +++ b/src/item.h @@ -4,47 +4,16 @@ #include #include "thing.h" -enum ItemGroup { - ITEM_GROUP_NONE = 0, - ITEM_GROUP_GROUND, - ITEM_GROUP_CONTAINER, - ITEM_GROUP_WEAPON, - ITEM_GROUP_AMMUNITION, - ITEM_GROUP_ARMOR, - ITEM_GROUP_RUNE, - ITEM_GROUP_TELEPORT, - ITEM_GROUP_MAGICFIELD, - ITEM_GROUP_WRITEABLE, - ITEM_GROUP_KEY, - ITEM_GROUP_SPLASH, - ITEM_GROUP_FLUID, - ITEM_GROUP_DOOR, - ITEM_GROUP_LAST -}; +class Item; +typedef std::shared_ptr ItemPtr; -class ItemAttributes -{ -public: - ItemAttributes(); - ~ItemAttributes(); - - bool stackable, alwaysOnTop, useable, readable, moveable, blockSolid, blockProjectile, blockPathFind, pickupable, - isHangable, isHorizontal, isVertical, rotable, hasHeight, lookThrough, hasMiniMapColor; - uint8 alwaysOnTopOrder, width, height, blendframes, xdiv, ydiv, zdiv, animcount; - uint16 id, speed, subParam07, subParam08, lightLevel, lightColor, uheight, miniMapColor; - uint16 *sprites; - ItemGroup group; -}; - -class Item : virtual public Thing +class Item : public Thing { public: Item(); - void draw(int x, int y, int z); - - void setId(uint16 id) { m_id = id; } - uint16 getId() const { return m_id; } + virtual ThingAttributes *getAttributes(); + void draw(int x, int y); void setCount(uint8 count) { m_count = count; } @@ -52,8 +21,7 @@ public: virtual const Item* getItem() const { return this; } private: - uint16 m_id; uint8 m_count; }; -#endif +#endif // ITEM_H diff --git a/src/map.cpp b/src/map.cpp index 7917d6a0..f09a8ae2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -17,41 +17,59 @@ void Map::draw(int x, int y) if(playerPos->z <= 7) { // player pos it 8-6. check if we can draw upper floors. - /*bool draw = true; + bool draw = true; for(int jz = 6; jz >= 0; --jz) { - if(m_tiles[Position(8+(6-jz), 6+(6-jz), jz)]->getStackSize() > 0) { - draw = false; + Position coverPos = Position(playerPos->x-(6-jz), playerPos->y-(6-jz), jz); + if(m_tiles[coverPos]) { + if(m_tiles[coverPos]->getStackSize() > 0 && jz < playerPos->z) { + draw = false; + } } - }*/ + } for(int iz = 7; iz > 0; --iz) { // +1 in draws cause 64x64 items may affect view. - for(int ix = - 8; ix < + 8; ++ix) { - for(int iy = - 6; iy < + 6; ++iy) { - Position relativePos = Position(playerPos->x + ix, playerPos->y + iy, iz); + for(int ix = -7; ix < + 8+7; ++ix) { + for(int iy = -5; iy < + 6+7; ++iy) { + Position itemPos = Position(playerPos->x + ix, playerPos->y + iy, iz); //Position drawPos = Position(ix + 8, iy - playerPos->y + 6, iz); //logDebug("x: ", relativePos.x, " y: ", relativePos.y, " z: ", (int)relativePos.z); - if(m_tiles.find(relativePos) != m_tiles.end()) - m_tiles[relativePos]->draw(ix + 8, iy + 6, iz); + if(m_tiles[itemPos]) + m_tiles[itemPos]->draw((ix + 7 - (7-iz))*32, (iy + 5 - (7-iz))*32); } } - //if(!draw) - //break; + if(!draw) + break; } } + // draw effects + for(auto it = m_effects.begin(), end = m_effects.end(); it != end; ++it) { + Position *effectPos = (*it)->getPosition(); + (*it)->draw((effectPos->x - playerPos->x + 7) * 32, (effectPos->y - playerPos->y + 5) * 32); + } + + // debug draws + g_graphics.drawBoundingRect(Rect(7*32, 5*32, 32, 32), Color::red); + m_framebuffer->unbind(); m_framebuffer->draw(x, y, g_graphics.getScreenSize().width(), g_graphics.getScreenSize().height()); } -void Map::addThing(Thing *thing, const Position& pos) +void Map::addThing(ThingPtr thing, uint8 stackpos) { - if(m_tiles.find(pos) == m_tiles.end()) { - m_tiles[pos] = TilePtr(new Tile()); + if(thing->getType() == Thing::TYPE_ITEM || thing->getType() == Thing::TYPE_CREATURE) { + if(!m_tiles[*thing->getPosition()]) { + m_tiles[*thing->getPosition()] = TilePtr(new Tile()); + } + + m_tiles[*thing->getPosition()]->addThing(thing, stackpos); + } + else if(thing->getType() == Thing::TYPE_EFFECT) { + m_effects.push_back(thing); } - m_tiles[pos]->addThing(thing); } diff --git a/src/map.h b/src/map.h index 4a0afbba..e8dce278 100644 --- a/src/map.h +++ b/src/map.h @@ -3,18 +3,22 @@ #include "position.h" #include "tile.h" +#include "effect.h" #include #include class Map { public: - void addThing(Thing *thing, const Position& pos); + void addThing(ThingPtr thing, uint8 stackpos = 0); void draw(int x, int y); + FrameBufferPtr getFramebuffer() { return m_framebuffer; } + private: std::unordered_map m_tiles; + std::list m_effects; FrameBufferPtr m_framebuffer; }; diff --git a/src/otclient.cpp b/src/otclient.cpp index 85fe0065..d0da0227 100644 --- a/src/otclient.cpp +++ b/src/otclient.cpp @@ -199,7 +199,8 @@ void OTClient::poll() void OTClient::render() { - g_game.getMap()->draw(0, 0); + if(g_game.getOnline()) + g_game.getMap()->draw(0, 0); // everything is rendered by UI components g_ui.render(); @@ -261,7 +262,7 @@ void OTClient::onInputEvent(const InputEvent& event) { g_ui.inputEvent(event); - ProtocolGame *protocol = g_game.getProtocol(); + ProtocolGamePtr protocol = g_game.getProtocol(); if(protocol) { if(event.type == EventKeyDown) { if(event.keycode == KC_UP) diff --git a/src/player.h b/src/player.h index 8e6e4b79..b2aff45e 100644 --- a/src/player.h +++ b/src/player.h @@ -1,17 +1,22 @@ #ifndef PLAYER_H #define PLAYER_H -#include "position.h" +#include "creature.h" -class Player +class Player : public Creature { public: + void setDrawSpeed(uint16 drawSpeed) { m_drawSpeed = drawSpeed; } + uint16 getDrawSpeed() { return m_drawSpeed; } - void setPosition(const Position& position) { m_position = position; } - Position *getPosition() { return &m_position; } + void setCanReportBugs(uint8 canReportBugs) { m_canReportBugs = (canReportBugs != 0); } + bool getCanReportBugs() { return m_canReportBugs; } private: - Position m_position; + + uint16 m_drawSpeed; + bool m_canReportBugs; + }; #endif diff --git a/src/position.h b/src/position.h index 72797e25..91c106c9 100644 --- a/src/position.h +++ b/src/position.h @@ -3,6 +3,14 @@ #include +enum Direction +{ + DIRECTION_NORTH, + DIRECTION_EAST, + DIRECTION_SOUTH, + DIRECTION_WEST +}; + class Position { public: diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index e77f4a73..f172a2ad 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -5,11 +5,12 @@ ProtocolGame::ProtocolGame() { m_checksumEnabled = false; - g_game.setProtocol(this); + g_game.setProtocol(ProtocolGamePtr(this)); } ProtocolGame::~ProtocolGame() { + sendLogout(); g_game.setProtocol(NULL); } diff --git a/src/protocolgame.h b/src/protocolgame.h index 6cca9336..c99b5ed4 100644 --- a/src/protocolgame.h +++ b/src/protocolgame.h @@ -3,7 +3,7 @@ #include #include "player.h" -#include "thing.h" +#include "item.h" class ProtocolGame; typedef std::shared_ptr ProtocolGamePtr; @@ -22,6 +22,7 @@ public: void onRecv(InputMessage& inputMessage); // Send Messages + void sendLogout(); void sendPing(); void sendWalkNorth(); void sendWalkEast(); @@ -73,6 +74,7 @@ private: void parseCreatureSpeed(InputMessage& msg); void parseCreatureSkulls(InputMessage& msg); void parseCreatureShields(InputMessage& msg); + void parseCreatureTurn(InputMessage& msg); void parseItemTextWindow(InputMessage& msg); void parseHouseTextWindow(InputMessage& msg); void parsePlayerStats(InputMessage& msg); @@ -107,9 +109,9 @@ private: void setMapDescription(InputMessage& msg, int32 x, int32 y, int32 z, int32 width, int32 height); void setFloorDescription(InputMessage& msg, int32 x, int32 y, int32 z, int32 width, int32 height, int32 offset, int32* skipTiles); void setTileDescription(InputMessage& msg, Position position); - Thing *internalGetThing(InputMessage& msg); - void internalCreatureOutfit(InputMessage& msg); - Item *internalGetItem(InputMessage& msg, uint16 id); + ThingPtr internalGetThing(InputMessage& msg); + Outfit internalCreatureOutfit(InputMessage& msg); + ItemPtr internalGetItem(InputMessage& msg, uint16 id); Position parsePosition(InputMessage& msg); diff --git a/src/protocolgameparse.cpp b/src/protocolgameparse.cpp index 043406e6..77077d48 100644 --- a/src/protocolgameparse.cpp +++ b/src/protocolgameparse.cpp @@ -3,6 +3,7 @@ #include "tibiadat.h" #include "game.h" #include "map.h" +#include "effect.h" #include void ProtocolGame::parseMessage(InputMessage& msg) @@ -235,9 +236,12 @@ void ProtocolGame::parseMessage(InputMessage& msg) void ProtocolGame::parsePlayerLogin(InputMessage& msg) { - msg.getU32(); // player id - msg.getU16(); // drawing speed. - msg.getU8(); // can report bugs + Player *player = g_game.getPlayer(); + player->setId(msg.getU32()); + player->setDrawSpeed(msg.getU16()); + player->setCanReportBugs(msg.getU8()); + + g_game.setOnline(true); } void ProtocolGame::parseGMActions(InputMessage& msg) @@ -248,7 +252,8 @@ void ProtocolGame::parseGMActions(InputMessage& msg) void ProtocolGame::parseErrorMessage(InputMessage& msg) { - msg.getString(); // message + std::string error = msg.getString(); + callLuaField("onError", error); } void ProtocolGame::parseFYIMessage(InputMessage& msg) @@ -280,12 +285,7 @@ void ProtocolGame::parseCanReportBugs(InputMessage& msg) void ProtocolGame::parseMapDescription(InputMessage& msg) { Player *player = g_game.getPlayer(); - - Position playerPos = parsePosition(msg); - - logDebug("x: ", playerPos.x, " y: ", playerPos.y, " z: ", (int)playerPos.z); - player->setPosition(playerPos); - logDebug("x: ", player->getPosition()->x, " y: ", player->getPosition()->y, " z: ", (int)player->getPosition()->z); + player->setPosition(parsePosition(msg)); setMapDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, player->getPosition()->z, 18, 14); } @@ -462,8 +462,11 @@ void ProtocolGame::parseWorldLight(InputMessage& msg) void ProtocolGame::parseMagicEffect(InputMessage& msg) { - parsePosition(msg); // effect pos - msg.getU8(); // effect + EffectPtr effect = EffectPtr(new Effect()); + effect->setPosition(parsePosition(msg)); + effect->setId(msg.getU8()); + + g_game.getMap()->addThing(effect); } void ProtocolGame::parseAnimatedText(InputMessage& msg) @@ -523,6 +526,12 @@ void ProtocolGame::parseCreatureShields(InputMessage& msg) msg.getU8(); // shield } +void ProtocolGame::parseCreatureTurn(InputMessage& msg) +{ + msg.getU32(); // creature id + msg.getU8(); // direction +} + void ProtocolGame::parseItemTextWindow(InputMessage& msg) { msg.getU32(); // windowId @@ -828,43 +837,48 @@ void ProtocolGame::setFloorDescription(InputMessage& msg, int32 x, int32 y, int3 void ProtocolGame::setTileDescription(InputMessage& msg, Position position) { - int n = 0; + int stackpos = 0; while(1){ - n++; + stackpos++; uint16 inspectTileId = msg.getU16(true); if(inspectTileId >= 0xFF00) return; else { - if(n > 10) { + if(stackpos > 10) { logDebug("[ProtocolGame::setTileDescription] Too many things!."); return; } - g_game.getMap()->addThing(internalGetThing(msg), position); + ThingPtr thing = internalGetThing(msg); + if(thing) + thing->setPosition(position); + g_game.getMap()->addThing(thing, stackpos); } } } -Thing *ProtocolGame::internalGetThing(InputMessage& msg) +ThingPtr ProtocolGame::internalGetThing(InputMessage& msg) { - Thing *thing = NULL; + ThingPtr thing; uint16 thingId = msg.getU16(); if(thingId == 0x0061 || thingId == 0x0062) { // add new creature + CreaturePtr creature = CreaturePtr(new Creature); + if(thingId == 0x0062) { //creature is known - msg.getU32(); // creature id + creature->setId(msg.getU32()); } else if(thingId == 0x0061) { //creature is not known msg.getU32(); // remove id - msg.getU32(); // creature id - msg.getString(); // creature name + creature->setId(msg.getU32()); + creature->setName(msg.getString()); } - msg.getU8(); // hp - msg.getU8(); // direction - internalCreatureOutfit(msg); - msg.getU8(); // level - msg.getU8(); // color + creature->setHealthPercent(msg.getU8()); + creature->setDirection((Direction)msg.getU8()); + creature->setOutfit(internalCreatureOutfit(msg)); + msg.getU8(); // light level + msg.getU8(); // light color msg.getU16(); // speed msg.getU8(); // skull msg.getU8(); // shield @@ -873,10 +887,11 @@ Thing *ProtocolGame::internalGetThing(InputMessage& msg) msg.getU8(); msg.getU8(); // impassable + thing = creature; + } else if(thingId == 0x0063) { // creature turn - msg.getU32(); // creature id - msg.getU8(); // direction + parseCreatureTurn(msg); } else // item thing = internalGetItem(msg, thingId); @@ -884,31 +899,35 @@ Thing *ProtocolGame::internalGetThing(InputMessage& msg) return thing; } -void ProtocolGame::internalCreatureOutfit(InputMessage& msg) +Outfit ProtocolGame::internalCreatureOutfit(InputMessage& msg) { - uint16 lookType = msg.getU16(); // looktype - if(lookType != 0) { - msg.getU8(); // lookhead - msg.getU8(); // lookbody - msg.getU8(); // looklegs - msg.getU8(); // lookfeet - msg.getU8(); // lookaddons + Outfit outfit; + + outfit.type = msg.getU16(); // looktype + if(outfit.type != 0) { + outfit.head = msg.getU8(); + outfit.body = msg.getU8(); + outfit.legs = msg.getU8(); + outfit.feet = msg.getU8(); + outfit.addons = msg.getU8(); } else { - msg.getU16(); // looktype + outfit.type = msg.getU16(); } + + return outfit; } -Item *ProtocolGame::internalGetItem(InputMessage& msg, uint16 id) +ItemPtr ProtocolGame::internalGetItem(InputMessage& msg, uint16 id) { - Item *item = new Item(); + ItemPtr item = ItemPtr(new Item()); if(id == 0xFFFF) id = msg.getU16(); item->setId(id); - ItemAttributes *itemAttributes = g_tibiaDat.getItemAttributes(id); - if(itemAttributes->stackable || itemAttributes->group == ITEM_GROUP_FLUID || itemAttributes->group == ITEM_GROUP_SPLASH) + ThingAttributes *itemAttributes = g_tibiaDat.getItemAttributes(id); + if(itemAttributes->stackable || itemAttributes->group == THING_GROUP_FLUID || itemAttributes->group == THING_GROUP_SPLASH) item->setCount(msg.getU8()); return item; diff --git a/src/protocolgamesend.cpp b/src/protocolgamesend.cpp index bbede8b6..696f794c 100644 --- a/src/protocolgamesend.cpp +++ b/src/protocolgamesend.cpp @@ -1,5 +1,12 @@ #include "protocolgame.h" +void ProtocolGame::sendLogout() +{ + OutputMessage oMsg; + oMsg.addU8(0x14); + send(oMsg); +} + void ProtocolGame::sendPing() { OutputMessage oMsg; diff --git a/src/thing.cpp b/src/thing.cpp index 7e719914..fe8f042d 100644 --- a/src/thing.cpp +++ b/src/thing.cpp @@ -1,6 +1,83 @@ #include "thing.h" +#include "tibiaspr.h" +#include + +ThingAttributes::ThingAttributes() +{ + group = THING_GROUP_NONE; + blockSolid = false; + hasHeight = false; + blockPathFind = false; + blockProjectile = false; + alwaysOnTop = false; + alwaysOnTopOrder = 0; + stackable = false; + useable = false; + moveable = true; + pickupable = false; + rotable = false; + readable = false; + lookThrough = false; + speed = 0; + lightLevel = 0; + lightColor = 0; + isVertical = false; + isHorizontal = false; + isHangable = false; + miniMapColor = 0; + hasMiniMapColor = false; + subParam07 = 0; + subParam08 = 0; + sprites = NULL; + width = 0; + height = 0; + blendframes = 0; + xdiv = 0; + ydiv = 0; + zdiv = 0; + animcount = 0; + xOffset = 0; + yOffset = 0; +} + +ThingAttributes::~ThingAttributes() +{ + if(sprites) + delete []sprites; +} Thing::Thing() { m_type = TYPE_NONE; } + +void Thing::internalDraw(int x, int y, int blendframes, int xdiv, int ydiv, int zdiv, int anim) +{ + ThingAttributes *thingAttributes = getAttributes(); + if(!thingAttributes) + return; + + for(int yi = 0; yi < thingAttributes->height; yi++) { + for(int xi = 0; xi < thingAttributes->width; xi++) { + uint16 sprIndex = xi + + yi * thingAttributes->width + + blendframes * thingAttributes->width * thingAttributes->height + + xdiv * thingAttributes->width * thingAttributes->height * thingAttributes->blendframes + + ydiv * thingAttributes->width * thingAttributes->height * thingAttributes->blendframes * thingAttributes->xdiv + + zdiv * thingAttributes->width * thingAttributes->height * thingAttributes->blendframes * thingAttributes->xdiv * thingAttributes->ydiv + + anim * thingAttributes->width * thingAttributes->height * thingAttributes->blendframes * thingAttributes->xdiv * thingAttributes->ydiv * thingAttributes->zdiv; + uint16 itemId = thingAttributes->sprites[sprIndex]; + if(itemId == 0xFFFF) + continue; + TexturePtr data = g_tibiaSpr.getSprite(itemId); + + int offsetX = 0, offsetY = 0; + if(thingAttributes->hasHeight) { + offsetX = thingAttributes->xOffset; + offsetY = thingAttributes->xOffset; // << look to xoffset + } + + g_graphics.drawTexturedRect(Rect((x - xi*32) - offsetX, (y - yi*32) - offsetY, 32, 32), data, Rect(0, 0, 32, 32)); + } + } +} diff --git a/src/thing.h b/src/thing.h index 3e48c42f..80145bc3 100644 --- a/src/thing.h +++ b/src/thing.h @@ -2,9 +2,45 @@ #define THING_H #include +#include "position.h" +enum ThingAttributesGroup { + THING_GROUP_NONE = 0, + THING_GROUP_GROUND, + THING_GROUP_CONTAINER, + THING_GROUP_WEAPON, + THING_GROUP_AMMUNITION, + THING_GROUP_ARMOR, + THING_GROUP_RUNE, + THING_GROUP_TELEPORT, + THING_GROUP_MAGICFIELD, + THING_GROUP_WRITEABLE, + THING_GROUP_KEY, + THING_GROUP_SPLASH, + THING_GROUP_FLUID, + THING_GROUP_DOOR, + THING_GROUP_LAST +}; + +struct ThingAttributes +{ + ThingAttributes(); + ~ThingAttributes(); + + bool stackable, alwaysOnTop, useable, readable, moveable, blockSolid, blockProjectile, blockPathFind, pickupable, + isHangable, isHorizontal, isVertical, rotable, hasHeight, lookThrough, hasMiniMapColor; + uint8 alwaysOnTopOrder, width, height, blendframes, xdiv, ydiv, zdiv, animcount, xOffset, yOffset; + uint16 id, speed, subParam07, subParam08, lightLevel, lightColor, miniMapColor; + uint16 *sprites; + ThingAttributesGroup group; +}; + +class Creature; class Item; +class Thing; +typedef std::shared_ptr ThingPtr; + class Thing { public: @@ -13,19 +49,35 @@ public: enum Type { TYPE_NONE, TYPE_ITEM, - TYPE_CREATURE + TYPE_CREATURE, + TYPE_EFFECT, + TYPE_SHOT }; + void setId(uint32 id) { m_id = id; } + uint32 getId() { return m_id; } + void setType(Type type) { m_type = type; } Type getType() const { return m_type; } - virtual void draw(int, int, int) {} + void setPosition(const Position& position) { m_position = position; } + Position *getPosition() { return &m_position; } + + virtual void draw(int, int) {} + virtual ThingAttributes *getAttributes() { return NULL; } virtual Item* getItem() { return NULL; } virtual const Item *getItem() const { return NULL; } + virtual Creature *getCreature() { return NULL; } + virtual const Creature *getCreature() const { return NULL; } protected: + void internalDraw(int x, int y, int blendframes, int xdiv, int ydiv, int zdiv, int anim); + + uint32 m_id; Type m_type; + Position m_position; + }; #endif // THING_H diff --git a/src/tibiadat.cpp b/src/tibiadat.cpp index 6285a26f..d437c864 100644 --- a/src/tibiadat.cpp +++ b/src/tibiadat.cpp @@ -20,17 +20,17 @@ bool TibiaDat::load(const std::string& filename) m_totalCount = m_groupCount[0] + m_groupCount[1] + m_groupCount[2] + m_groupCount[3]; - m_itemsAttributes = new ItemAttributes*[m_totalCount+1]; + m_thingsAttributes = new ThingAttributes*[m_totalCount+1]; for(uint16 i = 0; i <= m_totalCount; i++) - m_itemsAttributes[i] = NULL; + m_thingsAttributes[i] = NULL; uint8 read_byte; uint16 read_short; - uint32 read_long; + //uint32 read_long; for(uint16 id = 0; (id <= m_totalCount) && !fin.eof(); id++) { - m_itemsAttributes[id] = new ItemAttributes(); - m_itemsAttributes[id]->id = id; + m_thingsAttributes[id] = new ThingAttributes(); + m_thingsAttributes[id]->id = id; uint8 opt; bool done = false; @@ -38,109 +38,116 @@ bool TibiaDat::load(const std::string& filename) fin.read((char*)&opt, 1); if(opt == 0x00) { // Ground tile - fin.read((char*)&m_itemsAttributes[id]->speed, 2); - m_itemsAttributes[id]->group = ITEM_GROUP_GROUND; + fin.read((char*)&m_thingsAttributes[id]->speed, 2); + m_thingsAttributes[id]->group = THING_GROUP_GROUND; } else if(opt == 0x01) { // All OnTop - m_itemsAttributes[id]->alwaysOnTop = true; - m_itemsAttributes[id]->alwaysOnTopOrder = 1; + m_thingsAttributes[id]->alwaysOnTop = true; + m_thingsAttributes[id]->alwaysOnTopOrder = 1; } else if(opt == 0x02) { // Can walk trough (open doors, arces, bug pen fence) - m_itemsAttributes[id]->alwaysOnTop = true; - m_itemsAttributes[id]->alwaysOnTopOrder = 2; + m_thingsAttributes[id]->alwaysOnTop = true; + m_thingsAttributes[id]->alwaysOnTopOrder = 2; } else if(opt == 0x03) { // Can walk trough (arces) - m_itemsAttributes[id]->alwaysOnTop = true; - m_itemsAttributes[id]->alwaysOnTopOrder = 3; + m_thingsAttributes[id]->alwaysOnTop = true; + m_thingsAttributes[id]->alwaysOnTopOrder = 3; } else if(opt == 0x04) { // Container - m_itemsAttributes[id]->group = ITEM_GROUP_CONTAINER; + m_thingsAttributes[id]->group = THING_GROUP_CONTAINER; } else if(opt == 0x05) { // Stackable - m_itemsAttributes[id]->stackable = true; + m_thingsAttributes[id]->stackable = true; } else if(opt == 0x06) { // Unknown } else if(opt == 0x07) { // Useable - m_itemsAttributes[id]->useable = true; + m_thingsAttributes[id]->useable = true; } else if(opt == 0x08) { // Writtable - m_itemsAttributes[id]->group = ITEM_GROUP_WRITEABLE; - m_itemsAttributes[id]->readable = true; - fin.read((char*)&m_itemsAttributes[id]->subParam07, 2); + m_thingsAttributes[id]->group = THING_GROUP_WRITEABLE; + m_thingsAttributes[id]->readable = true; + fin.read((char*)&m_thingsAttributes[id]->subParam07, 2); } else if(opt == 0x09) { // Writtable once // Writtable objects that can't be edited by players - m_itemsAttributes[id]->readable = true; - fin.read((char*)&m_itemsAttributes[id]->subParam08, 2); + m_thingsAttributes[id]->readable = true; + fin.read((char*)&m_thingsAttributes[id]->subParam08, 2); } else if(opt == 0x0A) { // Fluid containers fin.read((char*)&read_byte, 1); - m_itemsAttributes[id]->group = ITEM_GROUP_FLUID; + m_thingsAttributes[id]->group = THING_GROUP_FLUID; } else if(opt == 0x0B) { // Splashes - m_itemsAttributes[id]->group = ITEM_GROUP_SPLASH; + m_thingsAttributes[id]->group = THING_GROUP_SPLASH; } else if(opt == 0x0C) { // Blocks solid objects (creatures, walls etc) - m_itemsAttributes[id]->blockSolid = true; + m_thingsAttributes[id]->blockSolid = true; } else if(opt == 0x0D) { // Not moveable - m_itemsAttributes[id]->moveable = false; + m_thingsAttributes[id]->moveable = false; } else if(opt == 0x0E) { // Blocks missiles (walls, magic wall etc) - m_itemsAttributes[id]->blockProjectile = true; + m_thingsAttributes[id]->blockProjectile = true; } else if(opt == 0x0F) { // Blocks pathfind algorithms (monsters) - m_itemsAttributes[id]->blockPathFind = true; + m_thingsAttributes[id]->blockPathFind = true; } else if(opt == 0x10) { // Blocks monster movement (flowers, parcels etc) - m_itemsAttributes[id]->pickupable = true; + m_thingsAttributes[id]->pickupable = true; } else if(opt == 0x11) { // Hangable objects (wallpaper etc) - m_itemsAttributes[id]->isHangable = true; + m_thingsAttributes[id]->isHangable = true; } else if(opt == 0x12) { // Horizontal wall - m_itemsAttributes[id]->isHorizontal = true; + m_thingsAttributes[id]->isHorizontal = true; } else if(opt == 0x13) { // Vertical wall - m_itemsAttributes[id]->isVertical = true; + m_thingsAttributes[id]->isVertical = true; } else if(opt == 0x14) { // Rotable - m_itemsAttributes[id]->rotable = true; + m_thingsAttributes[id]->rotable = true; } else if(opt == 0x15) { // Light info - fin.read((char*)&m_itemsAttributes[id]->lightLevel, 2); - fin.read((char*)&m_itemsAttributes[id]->lightColor, 2); + fin.read((char*)&m_thingsAttributes[id]->lightLevel, 2); + fin.read((char*)&m_thingsAttributes[id]->lightColor, 2); } else if(opt == 0x16) { } else if(opt == 0x17) { // Changes floor } - else if(opt == 0x18) { // Unknown - fin.read((char*)&read_long, 4); + else if(opt == 0x18) { // Thing must be drawed with offset + m_thingsAttributes[id]->hasHeight = true; + fin.read((char*)&m_thingsAttributes[id]->xOffset, 1); + fin.read((char*)&m_thingsAttributes[id]->yOffset, 1); + + fin.read((char*)&read_short, 2); } - else if(opt == 0x19) { // Has height - m_itemsAttributes[id]->hasHeight = true; - fin.read((char*)&m_itemsAttributes[id]->uheight, 2); + else if(opt == 0x19) { // pixels characters height + + fin.read((char*)&m_thingsAttributes[id]->xOffset, 1); + fin.read((char*)&m_thingsAttributes[id]->yOffset, 1); + //logDebug((int)m_thingsAttributes[id]->xOffset, " ", (int)m_thingsAttributes[id]->yOffset); } else if(opt == 0x1A) { + //m_thingsAttributes[id]->hasHeight = true; } else if(opt == 0x1B) { } else if(opt == 0x1C) { // Minimap color - fin.read((char*)&m_itemsAttributes[id]->miniMapColor, 2); - m_itemsAttributes[id]->hasMiniMapColor = true; + fin.read((char*)&m_thingsAttributes[id]->miniMapColor, 2); + m_thingsAttributes[id]->hasMiniMapColor = true; } else if(opt == 0x1D) { // Unknown fin.read((char*)&read_short, 2); if(read_short == 1112) - m_itemsAttributes[id]->readable = true; + m_thingsAttributes[id]->readable = true; } else if(opt == 0x1E) { } else if(opt == 0x1F) { - m_itemsAttributes[id]->lookThrough = true; + m_thingsAttributes[id]->lookThrough = true; } else if(opt == 0x20) { } @@ -153,32 +160,46 @@ bool TibiaDat::load(const std::string& filename) } } - fin.read((char*)&m_itemsAttributes[id]->width, 1); - fin.read((char*)&m_itemsAttributes[id]->height, 1); - if((m_itemsAttributes[id]->width > 1) || (m_itemsAttributes[id]->height > 1)) + fin.read((char*)&m_thingsAttributes[id]->width, 1); + fin.read((char*)&m_thingsAttributes[id]->height, 1); + if((m_thingsAttributes[id]->width > 1) || (m_thingsAttributes[id]->height > 1)) fin.read((char*)&read_byte, 1); - fin.read((char*)&m_itemsAttributes[id]->blendframes, 1); - fin.read((char*)&m_itemsAttributes[id]->xdiv, 1); - fin.read((char*)&m_itemsAttributes[id]->ydiv, 1); - fin.read((char*)&m_itemsAttributes[id]->zdiv, 1); - fin.read((char*)&m_itemsAttributes[id]->animcount, 1); + fin.read((char*)&m_thingsAttributes[id]->blendframes, 1); + fin.read((char*)&m_thingsAttributes[id]->xdiv, 1); + fin.read((char*)&m_thingsAttributes[id]->ydiv, 1); + fin.read((char*)&m_thingsAttributes[id]->zdiv, 1); + fin.read((char*)&m_thingsAttributes[id]->animcount, 1); // Read sprites id. - uint16 totalSprites = m_itemsAttributes[id]->width * m_itemsAttributes[id]->height * m_itemsAttributes[id]->blendframes * m_itemsAttributes[id]->xdiv * m_itemsAttributes[id]->ydiv * m_itemsAttributes[id]->zdiv * m_itemsAttributes[id]->animcount; + uint16 totalSprites = m_thingsAttributes[id]->width * m_thingsAttributes[id]->height * m_thingsAttributes[id]->blendframes * m_thingsAttributes[id]->xdiv * m_thingsAttributes[id]->ydiv * m_thingsAttributes[id]->zdiv * m_thingsAttributes[id]->animcount; - m_itemsAttributes[id]->sprites = new uint16[totalSprites]; + m_thingsAttributes[id]->sprites = new uint16[totalSprites]; for(uint16 i = 0; i < totalSprites; i++) { fin.read((char*)&read_short, 2); - m_itemsAttributes[id]->sprites[i] = read_short-1; + m_thingsAttributes[id]->sprites[i] = read_short-1; } } return true; } -ItemAttributes *TibiaDat::getItemAttributes(uint16 id) +ThingAttributes *TibiaDat::getItemAttributes(uint16 id) { - // items id start at 100. - return m_itemsAttributes[id - 100]; + return m_thingsAttributes[id - 100]; +} + +ThingAttributes *TibiaDat::getCreatureAttributes(uint16 id) +{ + return m_thingsAttributes[id - 1 + m_groupCount[0]]; +} + +ThingAttributes *TibiaDat::getEffectAttributes(uint16 id) +{ + return m_thingsAttributes[id - 1 + m_groupCount[0] + m_groupCount[1]]; +} + +ThingAttributes *TibiaDat::getShotAttributes(uint16 id) +{ + return m_thingsAttributes[id - 100 + m_groupCount[0] + m_groupCount[1] + m_groupCount[2]]; } diff --git a/src/tibiadat.h b/src/tibiadat.h index 61803308..362a3a8f 100644 --- a/src/tibiadat.h +++ b/src/tibiadat.h @@ -2,14 +2,17 @@ #define TIBIADAT_H #include -#include "item.h" +#include "thing.h" class TibiaDat { public: bool load(const std::string& filename); - ItemAttributes *getItemAttributes(uint16 id); + ThingAttributes *getItemAttributes(uint16 id); + ThingAttributes *getCreatureAttributes(uint16 id); + ThingAttributes *getEffectAttributes(uint16 id); + ThingAttributes *getShotAttributes(uint16 id); uint16 getGroupCount(int i) { return m_groupCount[i]; } @@ -20,7 +23,7 @@ private: uint32 m_signature, m_totalCount; uint16 m_groupCount[4]; - ItemAttributes **m_itemsAttributes; + ThingAttributes **m_thingsAttributes; }; extern TibiaDat g_tibiaDat; diff --git a/src/tile.cpp b/src/tile.cpp index 6f4c7ecf..f39620fb 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -7,44 +7,43 @@ Tile::Tile() m_ground = NULL; } -void Tile::addThing(Thing *thing) +void Tile::addThing(ThingPtr thing, uint8 stackpos) { if(!thing) return; - if(thing->getType() == Thing::TYPE_ITEM) { - Item *item = thing->getItem(); - if(item) { - ItemAttributes *itemAttributes = g_tibiaDat.getItemAttributes(item->getId()); - - if(itemAttributes->group == ITEM_GROUP_GROUND) - m_ground = item; + ThingAttributes *thingAttributes = thing->getAttributes(); + if(thingAttributes) { + if(thing->getType() == Thing::TYPE_ITEM) { + if(thingAttributes->group == THING_GROUP_GROUND) + m_ground = thing; else { - if(itemAttributes->alwaysOnTop) + if(thingAttributes->alwaysOnTop) m_itemsTop.push_back(thing); else m_itemsBot.push_back(thing); } } + else if(thing->getType() == Thing::TYPE_CREATURE) { + m_creatures.push_back(thing); + } } - else if(thing->getType() == Thing::TYPE_CREATURE) { - } } -void Tile::draw(int x, int y, int z) +void Tile::draw(int x, int y) { if(m_ground) - m_ground->draw(x, y, z); + m_ground->draw(x, y); for(auto it = m_itemsTop.begin(), end = m_itemsTop.end(); it != end; ++it) - (*it)->draw(x, y, z); + (*it)->draw(x, y); for(auto it = m_creatures.begin(), end = m_creatures.end(); it != end; ++it) - (*it)->draw(x, y, z); + (*it)->draw(x, y); for(auto it = m_itemsBot.begin(), end = m_itemsBot.end(); it != end; ++it) - (*it)->draw(x, y, z); + (*it)->draw(x, y); } diff --git a/src/tile.h b/src/tile.h index 8754ceee..852e0b7b 100644 --- a/src/tile.h +++ b/src/tile.h @@ -3,6 +3,7 @@ #include #include "thing.h" +#include "position.h" class Tile; typedef std::shared_ptr TilePtr; @@ -12,17 +13,17 @@ class Tile public: Tile(); - void addThing(Thing *thing); + void addThing(ThingPtr thing, uint8 stackpos); - void draw(int x, int y, int z); + void draw(int x, int y); bool hasGround(); int getStackSize(); private: - Item *m_ground; - std::list m_itemsBot; - std::list m_creatures; - std::list m_itemsTop; + ThingPtr m_ground; + std::list m_itemsBot; + std::list m_creatures; + std::list m_itemsTop; }; #endif // TILE_H