fix gitignore and add missing sources

This commit is contained in:
Eduardo Bart 2011-08-15 11:11:24 -03:00
parent d8cc37afdb
commit b21ccd16f9
34 changed files with 2906 additions and 1 deletions

2
.gitignore vendored
View File

@ -4,7 +4,7 @@ CMakeFiles
CMakeCache.txt CMakeCache.txt
cmake_install.cmake cmake_install.cmake
Makefile Makefile
otclient ./otclient
otclient.exe otclient.exe
*.dll *.dll
.kdev* .kdev*

22
src/otclient/core/const.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef OTCLIENT_CORE_CONST_H
#define OTCLIENT_CORE_CONST_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
};
#endif

View File

@ -0,0 +1,64 @@
#include "creature.h"
#include "tibiadat.h"
#include <framework/graphics/graphics.h>
#include <framework/graphics/framebuffer.h>
#include "game.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
// 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();
}

View File

@ -0,0 +1,47 @@
#ifndef CREATURE_H
#define CREATURE_H
#include "thing.h"
struct Outfit
{
uint16 type;
uint8 head;
uint8 body;
uint8 legs;
uint8 feet;
uint8 addons;
};
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

View File

@ -0,0 +1,21 @@
#ifndef OTCLIENT_CORE_DECLARATIONS_H
#define OTCLIENT_CORE_DECLARATIONS_H
#include <otclient/global.h>
#include "const.h"
class Thing;
class Item;
class Tile;
class Creature;
class Player;
class Effect;
typedef std::shared_ptr<Thing> ThingPtr;
typedef std::shared_ptr<Item> ItemPtr;
typedef std::shared_ptr<Tile> TilePtr;
typedef std::shared_ptr<Creature> CreaturePtr;
typedef std::shared_ptr<Player> PlayerPtr;
typedef std::shared_ptr<Effect> EffectPtr;
#endif

View File

@ -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);
}

View File

@ -0,0 +1,19 @@
#ifndef EFFECT_H
#define EFFECT_H
#include <framework/global.h>
#include "thing.h"
class Effect : public Thing
{
public:
Effect();
virtual ThingAttributes *getAttributes();
void draw(int x, int y);
private:
};
#endif // EFFECT_H

View File

@ -0,0 +1,8 @@
#include "game.h"
Game g_game;
Game::Game()
{
m_online = false;
}

33
src/otclient/core/game.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef GAME_H
#define GAME_H
#include <framework/global.h>
#include "map.h"
#include "player.h"
#include <otclient/net/protocolgame.h>
class Game
{
public:
Game();
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;
ProtocolGamePtr m_protocolGame;
bool m_online;
};
extern Game g_game;
#endif // GAME_H

View File

@ -0,0 +1,35 @@
#include "item.h"
#include "tibiadat.h"
#include "tibiaspr.h"
#include <framework/graphics/graphics.h>
#include "thing.h"
Item::Item()
{
m_type = Thing::TYPE_ITEM;
}
ThingAttributes *Item::getAttributes()
{
return g_tibiaDat.getItemAttributes(m_id);
}
void Item::draw(int x, int y)
{
ThingAttributes *itemAttributes = getAttributes();
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) {
xdiv = m_position.x % itemAttributes->xdiv;
ydiv = m_position.y % itemAttributes->ydiv;
zdiv = m_position.z % itemAttributes->zdiv;
}
for(int b = 0; b < itemAttributes->blendframes; b++)
internalDraw(x, y, b, xdiv, ydiv, zdiv, anim);
}

24
src/otclient/core/item.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef ITEM_H
#define ITEM_H
#include <framework/global.h>
#include "thing.h"
class Item : public Thing
{
public:
Item();
virtual ThingAttributes *getAttributes();
void draw(int x, int y);
void setCount(uint8 count) { m_count = count; }
virtual Item* getItem() { return this; }
virtual const Item* getItem() const { return this; }
private:
uint8 m_count;
};
#endif // ITEM_H

74
src/otclient/core/map.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "map.h"
#include "game.h"
#include <framework/graphics/graphics.h>
#include <framework/graphics/framebuffer.h>
void Map::draw(int x, int y)
{
if(!m_framebuffer)
m_framebuffer = FrameBufferPtr(new FrameBuffer(15*32, 11*32));
g_graphics.bindColor(Color::white);
m_framebuffer->bind();
Position *playerPos = g_game.getPlayer()->getPosition();
// player is above 7
if(playerPos->z <= 7) {
// player pos it 8-6. check if we can draw upper floors.
bool draw = true;
for(int jz = 6; jz >= 0; --jz) {
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 = -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[itemPos])
m_tiles[itemPos]->draw((ix + 7 - (7-iz))*32, (iy + 5 - (7-iz))*32);
}
}
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(Rect(x, y, g_graphics.getScreenSize()));
}
void Map::addThing(ThingPtr thing, uint8 stackpos)
{
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);
}
}

29
src/otclient/core/map.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef MAP_H
#define MAP_H
#include "tile.h"
#include "effect.h"
#include <framework/graphics/declarations.h>
#include <unordered_map>
struct MapPositionHasher : std::unary_function<Position, std::size_t> {
std::size_t operator()(const Position& pos) const {
return ((((pos.x * 65536) + pos.y) * 15) + pos.z) % 1000000;
}
};
class Map
{
public:
void addThing(ThingPtr thing, uint8 stackpos = 0);
void draw(int x, int y);
private:
std::unordered_map<Position, TilePtr, MapPositionHasher> m_tiles;
std::list<ThingPtr> m_effects;
FrameBufferPtr m_framebuffer;
};
#endif

View File

@ -0,0 +1,22 @@
#ifndef PLAYER_H
#define PLAYER_H
#include "creature.h"
class Player : public Creature
{
public:
void setDrawSpeed(uint16 drawSpeed) { m_drawSpeed = drawSpeed; }
uint16 getDrawSpeed() { return m_drawSpeed; }
void setCanReportBugs(uint8 canReportBugs) { m_canReportBugs = (canReportBugs != 0); }
bool getCanReportBugs() { return m_canReportBugs; }
private:
uint16 m_drawSpeed;
bool m_canReportBugs;
};
#endif

View File

@ -0,0 +1,83 @@
#include "thing.h"
#include "tibiaspr.h"
#include <framework/graphics/graphics.h>
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));
}
}
}

65
src/otclient/core/thing.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef THING_H
#define THING_H
#include <otclient/global.h>
#include "declarations.h"
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<Thing> ThingPtr;
class Thing
{
public:
Thing();
enum Type {
TYPE_NONE,
TYPE_ITEM,
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; }
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

View File

@ -0,0 +1,205 @@
#include "tibiadat.h"
#include "tibiaspr.h"
#include <framework/core/resourcemanager.h>
TibiaDat g_tibiaDat;
bool TibiaDat::load(const std::string& filename)
{
std::stringstream fin;
g_resources.loadFile(filename, fin);
fin.read((char*)&m_signature, 4);
fin.read((char*)&m_groupCount[0], 2);
fin.read((char*)&m_groupCount[1], 2);
fin.read((char*)&m_groupCount[2], 2);
fin.read((char*)&m_groupCount[3], 2);
m_groupCount[0] -= 99;
m_totalCount = m_groupCount[0] + m_groupCount[1] + m_groupCount[2] + m_groupCount[3];
m_thingsAttributes = new ThingAttributes*[m_totalCount+1];
for(uint16 i = 0; i <= m_totalCount; i++)
m_thingsAttributes[i] = NULL;
uint8 read_byte;
uint16 read_short;
//uint32 read_long;
for(uint16 id = 0; (id <= m_totalCount) && !fin.eof(); id++) {
m_thingsAttributes[id] = new ThingAttributes();
m_thingsAttributes[id]->id = id;
uint8 opt;
bool done = false;
while(!done) {
fin.read((char*)&opt, 1);
if(opt == 0x00) { // Ground tile
fin.read((char*)&m_thingsAttributes[id]->speed, 2);
m_thingsAttributes[id]->group = THING_GROUP_GROUND;
}
else if(opt == 0x01) { // All OnTop
m_thingsAttributes[id]->alwaysOnTop = true;
m_thingsAttributes[id]->alwaysOnTopOrder = 1;
}
else if(opt == 0x02) { // Can walk trough (open doors, arces, bug pen fence)
m_thingsAttributes[id]->alwaysOnTop = true;
m_thingsAttributes[id]->alwaysOnTopOrder = 2;
}
else if(opt == 0x03) { // Can walk trough (arces)
m_thingsAttributes[id]->alwaysOnTop = true;
m_thingsAttributes[id]->alwaysOnTopOrder = 3;
}
else if(opt == 0x04) { // Container
m_thingsAttributes[id]->group = THING_GROUP_CONTAINER;
}
else if(opt == 0x05) { // Stackable
m_thingsAttributes[id]->stackable = true;
}
else if(opt == 0x06) { // Unknown
}
else if(opt == 0x07) { // Useable
m_thingsAttributes[id]->useable = true;
}
else if(opt == 0x08) { // Writtable
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_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_thingsAttributes[id]->group = THING_GROUP_FLUID;
}
else if(opt == 0x0B) { // Splashes
m_thingsAttributes[id]->group = THING_GROUP_SPLASH;
}
else if(opt == 0x0C) { // Blocks solid objects (creatures, walls etc)
m_thingsAttributes[id]->blockSolid = true;
}
else if(opt == 0x0D) { // Not moveable
m_thingsAttributes[id]->moveable = false;
}
else if(opt == 0x0E) { // Blocks missiles (walls, magic wall etc)
m_thingsAttributes[id]->blockProjectile = true;
}
else if(opt == 0x0F) { // Blocks pathfind algorithms (monsters)
m_thingsAttributes[id]->blockPathFind = true;
}
else if(opt == 0x10) { // Blocks monster movement (flowers, parcels etc)
m_thingsAttributes[id]->pickupable = true;
}
else if(opt == 0x11) { // Hangable objects (wallpaper etc)
m_thingsAttributes[id]->isHangable = true;
}
else if(opt == 0x12) { // Horizontal wall
m_thingsAttributes[id]->isHorizontal = true;
}
else if(opt == 0x13) { // Vertical wall
m_thingsAttributes[id]->isVertical = true;
}
else if(opt == 0x14) { // Rotable
m_thingsAttributes[id]->rotable = true;
}
else if(opt == 0x15) { // Light info
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) { // 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) { // 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_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_thingsAttributes[id]->readable = true;
}
else if(opt == 0x1E) {
}
else if(opt == 0x1F) {
m_thingsAttributes[id]->lookThrough = true;
}
else if(opt == 0x20) {
}
else if(opt == 0xFF) {
done = true;
}
else {
logDebug("Unknown byte code: ", opt);
return false;
}
}
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_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_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_thingsAttributes[id]->sprites = new uint16[totalSprites];
for(uint16 i = 0; i < totalSprites; i++) {
fin.read((char*)&read_short, 2);
m_thingsAttributes[id]->sprites[i] = read_short-1;
}
}
return true;
}
ThingAttributes *TibiaDat::getItemAttributes(uint16 id)
{
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]];
}

View File

@ -0,0 +1,31 @@
#ifndef TIBIADAT_H
#define TIBIADAT_H
#include <framework/global.h>
#include "thing.h"
class TibiaDat
{
public:
bool load(const std::string& filename);
ThingAttributes *getItemAttributes(uint16 id);
ThingAttributes *getCreatureAttributes(uint16 id);
ThingAttributes *getEffectAttributes(uint16 id);
ThingAttributes *getShotAttributes(uint16 id);
uint16 getGroupCount(int i) { return m_groupCount[i]; }
uint32 getSignature() { return m_signature; }
uint16 getTotalCount() { return m_totalCount; }
private:
uint32 m_signature, m_totalCount;
uint16 m_groupCount[4];
ThingAttributes **m_thingsAttributes;
};
extern TibiaDat g_tibiaDat;
#endif // TIBIADAT_H

View File

@ -0,0 +1,120 @@
#include "tibiaspr.h"
#include <framework/core/resourcemanager.h>
TibiaSpr g_tibiaSpr;
TibiaSpr::TibiaSpr()
{
m_sprites = NULL;
m_spritesCount = 0;
}
TibiaSpr::~TibiaSpr()
{
//for(uint16 i = 0; i < m_spritesCount; i++)
//if(m_sprites[i])
//delete m_sprites[i];
if(m_sprites)
delete []m_sprites;
//delete m_transparentSprite;
}
bool TibiaSpr::load(const std::string &filename)
{
g_resources.loadFile(filename, m_fin);
m_fin.read((char*)&m_signature, 4);
m_fin.read((char*)&m_spritesCount, 2);
m_sprites = new TexturePtr[m_spritesCount];
//for(uint16 i = 0; i < m_spritesCount; i++)
//m_sprites[i] = NULL;
uchar pixels[4096];
for(int i = 0; i < 32*32*4; i += 4) {
pixels[i + 0] = 0xFF;
pixels[i + 1] = 0x00;
pixels[i + 2] = 0xFF;
pixels[i + 3] = 0xFF;
}
m_transparentSprite = TexturePtr(new Texture(32, 32, 4, pixels));
return true;
}
TexturePtr TibiaSpr::loadSprite(uint32 id)
{
if(m_fin.eof())
return TexturePtr();
m_fin.seekg((id * 4) + 6, std::ios_base::beg);
uint32 spriteAddress;
m_fin.read((char*)&spriteAddress, 4);
if(spriteAddress == 0) // Some error on tibia.spr, save a blank image.
return TexturePtr();
m_fin.seekg(spriteAddress, std::ios_base::beg);
uint32 colorKey = 0;
m_fin.read((char*)&colorKey, 3);
uint16 spriteSize;
m_fin.read((char*)&spriteSize, 2);
uchar image[4096];
uint16 imgPos = 0, read = 0, transparentPixels, coloredPixels, x;
while(read < spriteSize) {
m_fin.read((char*)&transparentPixels, 2);
m_fin.read((char*)&coloredPixels, 2);
for(x = 0; x < transparentPixels; x++) {
image[imgPos + 0] = 0x00;
image[imgPos + 1] = 0x00;
image[imgPos + 2] = 0x00;
image[imgPos + 3] = 0x00;
imgPos += 4;
}
for(x = 0; x < coloredPixels; x++) {
m_fin.read((char*)&image[imgPos + 0], 1);
m_fin.read((char*)&image[imgPos + 1], 1);
m_fin.read((char*)&image[imgPos + 2], 1);
image[imgPos + 3] = 0xFF;
imgPos += 4;
}
read += 4 + (3 * coloredPixels);
}
// Fill remaining bytes with pink.
if(imgPos < 32 * 32 * 4) {
for(x = imgPos; x < 32 * 32 * 4; x += 4) {
image[x + 0] = 0xFF;
image[x + 1] = 0x00;
image[x + 2] = 0xFF;
image[x + 3] = 0x00;
}
}
return TexturePtr(new Texture(32, 32, 4, image));
}
TexturePtr TibiaSpr::getSprite(uint32 id)
{
if(!m_sprites)
return m_transparentSprite;
if(!m_sprites[id]) {
m_sprites[id] = loadSprite(id);
if(!m_sprites[id])
return m_transparentSprite;
}
return m_sprites[id];
}

View File

@ -0,0 +1,31 @@
#ifndef TIBIASPR_H
#define TIBIASPR_H
#include <framework/global.h>
#include <framework/graphics/texture.h>
class TibiaSpr
{
public:
TibiaSpr();
~TibiaSpr();
bool load(const std::string& filename);
uint32 getSignature() { return m_signature; }
uint16 getSpritesCount() { return m_spritesCount; }
TexturePtr getSprite(uint32 id);
private:
TexturePtr loadSprite(uint32 id);
std::stringstream m_fin;
uint32 m_signature;
uint16 m_spritesCount;
TexturePtr *m_sprites;
TexturePtr m_transparentSprite;
};
extern TibiaSpr g_tibiaSpr;
#endif // TIBIASPR_H

View File

@ -0,0 +1,66 @@
#include "tile.h"
#include "item.h"
#include "tibiadat.h"
Tile::Tile()
{
m_ground = NULL;
}
void Tile::addThing(ThingPtr thing, uint8 stackpos)
{
if(!thing)
return;
ThingAttributes *thingAttributes = thing->getAttributes();
if(thingAttributes) {
if(thing->getType() == Thing::TYPE_ITEM) {
if(thingAttributes->group == THING_GROUP_GROUND)
m_ground = thing;
else {
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);
}
}
}
void Tile::draw(int x, int y)
{
if(m_ground)
m_ground->draw(x, y);
for(auto it = m_itemsTop.begin(), end = m_itemsTop.end(); it != end; ++it)
(*it)->draw(x, y);
for(auto it = m_creatures.begin(), end = m_creatures.end(); it != end; ++it)
(*it)->draw(x, y);
for(auto it = m_itemsBot.begin(), end = m_itemsBot.end(); it != end; ++it)
(*it)->draw(x, y);
}
bool Tile::hasGround()
{
return m_ground != 0;
}
int Tile::getStackSize()
{
int ret = 0;
if(m_ground)
ret++;
ret += m_itemsBot.size();
ret += m_creatures.size();
ret += m_itemsTop.size();
return ret;
}

24
src/otclient/core/tile.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef TILE_H
#define TILE_H
#include "thing.h"
class Tile
{
public:
Tile();
void addThing(ThingPtr thing, uint8 stackpos);
void draw(int x, int y);
bool hasGround();
int getStackSize();
private:
ThingPtr m_ground;
std::list<ThingPtr> m_itemsBot;
std::list<ThingPtr> m_creatures;
std::list<ThingPtr> m_itemsTop;
};
#endif

9
src/otclient/global.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef OTCLIENT_GLOBAL_H
#define OTCLIENT_GLOBAL_H
#include <framework/global.h>
// widely used headers
#include <otclient/util/position.h>
#endif

View File

@ -0,0 +1,52 @@
#ifndef OTCLIENT_NET_DECLARATIONS_H
#define OTCLIENT_NET_DECLARATIONS_H
#include <otclient/global.h>
#include <framework/net/declarations.h>
class ProtocolLogin;
class ProtocolGame;
typedef std::shared_ptr<ProtocolGame> ProtocolGamePtr;
typedef std::shared_ptr<ProtocolLogin> ProtocolLoginPtr;
#define CIPSOFT_PUBLIC_RSA "1321277432058722840622950990822933849527763264961655079678763618" \
"4334395343554449668205332383339435179772895415509701210392836078" \
"6959821132214473291575712138800495033169914814069637740318278150" \
"2907336840325241747827401343576296990629870233111328210165697754" \
"88792221429527047321331896351555606801473202394175817"
#define OTSERV_PUBLIC_RSA "1091201329673994292788609605089955415282375029027981291234687579" \
"3726629149257644633073969600111060390723088861007265581882535850" \
"3429057592827629436413108566029093628212635953836686562675849720" \
"6207862794310902180176810615217550567108238764764442605581471797" \
"07119674283982419152118103759076030616683978566631413"
// TODO: place it somewhere else
enum SpeakClasses {
SPEAK_SAY = 0x01, //normal talk
SPEAK_WHISPER = 0x02, //whispering - #w text
SPEAK_YELL = 0x03, //yelling - #y text
SPEAK_PRIVATE_PN = 0x04, //Player-to-NPC speaking(NPCs channel)
SPEAK_PRIVATE_NP = 0x05, //NPC-to-Player speaking
SPEAK_PRIVATE = 0x06, //Players speaking privately to players
SPEAK_CHANNEL_Y = 0x07, //Yellow message in chat
SPEAK_CHANNEL_W = 0x08, //White message in chat
SPEAK_RVR_CHANNEL = 0x09, //Reporting rule violation - Ctrl+R
SPEAK_RVR_ANSWER = 0x0A, //Answering report
SPEAK_RVR_CONTINUE = 0x0B, //Answering the answer of the report
SPEAK_BROADCAST = 0x0C, //Broadcast a message - #b
SPEAK_CHANNEL_R1 = 0x0D, //Talk red on chat - #c
SPEAK_PRIVATE_RED = 0x0E, //Red private - @name@ text
SPEAK_CHANNEL_O = 0x0F, //Talk orange on text
//SPEAK_ = 0x10, //?
SPEAK_CHANNEL_R2 = 0x11, //Talk red anonymously on chat - #d
//SPEAK_ = 0x12, //?
SPEAK_MONSTER_SAY = 0x13, //Talk orange
SPEAK_MONSTER_YELL = 0x14 //Yell orange
};
#endif

View File

@ -0,0 +1,99 @@
#include <otclient/net/protocolgame.h>
#include <otclient/core/game.h>
#include <framework/net/rsa.h>
ProtocolGame::ProtocolGame()
{
m_checksumEnabled = false;
g_game.setProtocol(ProtocolGamePtr(this));
}
ProtocolGame::~ProtocolGame()
{
sendLogout();
g_game.setProtocol(NULL);
}
void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, uint32 ip, uint16 port, const std::string& characterName)
{
if(accountName.empty() || accountPassword.empty()) {
callLuaField("onError", "You must enter an account name and password.");
return;
}
m_accountName = accountName;
m_accountPassword = accountPassword;
m_characterName = characterName;
char host[16];
sprintf(host, "%d.%d.%d.%d", (uint8)ip, (uint8)(ip >> 8), (uint8)(ip >> 16), (uint8)(ip >> 24));
connect(host, port);
}
void ProtocolGame::onConnect()
{
recv();
}
void ProtocolGame::sendLoginPacket(uint32 timestamp, uint8 unknown)
{
OutputMessage oMsg;
oMsg.addU8(0x0A); // Protocol id
oMsg.addU16(0x02); // OS
oMsg.addU16(862); // Client version
oMsg.addU8(0); // First RSA byte must be 0x00 // 1
// Generete xtea key.
m_xteaKey[0] = 432324;
m_xteaKey[1] = 24324;
m_xteaKey[2] = 423432;
m_xteaKey[3] = 234324;
// Add xtea key
oMsg.addU32(m_xteaKey[0]); // 5
oMsg.addU32(m_xteaKey[1]); // 9
oMsg.addU32(m_xteaKey[2]); // 13
oMsg.addU32(m_xteaKey[3]); // 17
oMsg.addU8(0); // is gm set?
oMsg.addString(m_accountName); // Account Name // 20
oMsg.addString(m_characterName); // Character Name // 22
oMsg.addString(m_accountPassword); // Password // 24
oMsg.addU32(timestamp); // 28
oMsg.addU8(unknown); // 29
// Packet data must have since byte 0, start, 128 bytes
oMsg.addPaddingBytes(128 - (29 + m_accountName.length() + m_characterName.length() + m_accountPassword.length()));
// Encrypt msg with RSA
if(!Rsa::encrypt((char*)oMsg.getBuffer() + 6 + oMsg.getMessageSize() - 128, 128, OTSERV_PUBLIC_RSA))
return;
send(oMsg);
m_xteaEncryptionEnabled = true;
recv();
}
void ProtocolGame::onRecv(InputMessage& inputMessage)
{
static bool firstRecv = true;
if(firstRecv) {
inputMessage.skipBytes(3);
uint32 timestamp = inputMessage.getU32();
uint8 unknown = inputMessage.getU8();
m_checksumEnabled = true;
sendLoginPacket(timestamp, unknown);
firstRecv = false;
}
else {
parseMessage(inputMessage);
}
}

View File

@ -0,0 +1,120 @@
#ifndef PROTOCOLGAME_H
#define PROTOCOLGAME_H
#include "declarations.h"
#include <framework/net/protocol.h>
#include <otclient/core/player.h>
#include <otclient/core/item.h>
class ProtocolGame : public Protocol
{
public:
ProtocolGame();
~ProtocolGame();
public:
void login(const std::string& accountName, const std::string& accountPassword, uint32 ip, uint16 port, const std::string& characterName);
void onConnect();
void onRecv(InputMessage& inputMessage);
// Send Messages
void sendLogout();
void sendPing();
void sendWalkNorth();
void sendWalkEast();
void sendWalkSouth();
void sendWalkWest();
private:
void sendLoginPacket(uint32 timestamp, uint8 unknown);
// Parse Messages
void parseMessage(InputMessage& msg);
void parsePlayerLogin(InputMessage& msg);
void parseGMActions(InputMessage& msg);
void parseErrorMessage(InputMessage& msg);
void parseFYIMessage(InputMessage& msg);
void parseWaitList(InputMessage& msg);
void parsePing(InputMessage&);
void parseDeath(InputMessage&);
void parseCanReportBugs(InputMessage& msg);
void parseMapDescription(InputMessage& msg);
void parseMoveNorth(InputMessage& msg);
void parseMoveEast(InputMessage& msg);
void parseMoveSouth(InputMessage& msg);
void parseMoveWest(InputMessage& msg);
void parseUpdateTile(InputMessage& msg);
void parseTileAddThing(InputMessage& msg);
void parseTileTransformThing(InputMessage& msg);
void parseTileRemoveThing(InputMessage& msg);
void parseCreatureMove(InputMessage& msg);
void parseOpenContainer(InputMessage& msg);
void parseCloseContainer(InputMessage& msg);
void parseContainerAddItem(InputMessage& msg);
void parseContainerUpdateItem(InputMessage& msg);
void parseContainerRemoveItem(InputMessage& msg);
void parseAddInventoryItem(InputMessage& msg);
void parseRemoveInventoryItem(InputMessage& msg);
void parseOpenShopWindow(InputMessage& msg);
void parsePlayerCash(InputMessage& msg);
void parseCloseShopWindow(InputMessage&);
void parseWorldLight(InputMessage& msg);
void parseMagicEffect(InputMessage& msg);
void parseAnimatedText(InputMessage& msg);
void parseDistanceShot(InputMessage& msg);
void parseCreatureSquare(InputMessage& msg);
void parseCreatureHealth(InputMessage& msg);
void parseCreatureLight(InputMessage& msg);
void parseCreatureOutfit(InputMessage& msg);
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);
void parsePlayerSkills(InputMessage& msg);
void parsePlayerIcons(InputMessage& msg);
void parsePlayerCancelAttack(InputMessage& msg);
void parseCreatureSpeak(InputMessage& msg);
void parseChannelList(InputMessage& msg);
void parseOpenChannel(InputMessage& msg);
void parseOpenPrivatePlayerChat(InputMessage& msg);
void parseOpenRuleViolation(InputMessage& msg);
void parseRuleViolationAF(InputMessage& msg);
void parseRuleViolationB0(InputMessage& msg);
void parseRuleViolationB1(InputMessage& msg);
void parseCreatePrivateChannel(InputMessage& msg);
void parseClosePrivateChannel(InputMessage& msg);
void parseSafeTradeRequest(InputMessage& msg);
void parseSafeTradeClose(InputMessage&);
void parseTextMessage(InputMessage& msg);
void parseCancelWalk(InputMessage& msg);
void parseFloorChangeUp(InputMessage& msg);
void parseFloorChangeDown(InputMessage& msg);
void parseOutfitWindow(InputMessage& msg);
void parseVipState(InputMessage& msg);
void parseVipLogin(InputMessage& msg);
void parseVipLogout(InputMessage& msg);
void parseShowTutorial(InputMessage& msg);
void parseAddMarker(InputMessage& msg);
void parseQuestList(InputMessage& msg);
void parseQuestPartList(InputMessage& msg);
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);
ThingPtr internalGetThing(InputMessage& msg);
Outfit internalCreatureOutfit(InputMessage& msg);
ItemPtr internalGetItem(InputMessage& msg, uint16 id);
Position parsePosition(InputMessage& msg);
std::string m_accountName, m_accountPassword, m_characterName;
};
#endif // PROTOCOLGAME_H

View File

@ -0,0 +1,943 @@
#include "protocolgame.h"
#include <otclient/core/player.h>
#include <otclient/core/tibiadat.h>
#include <otclient/core/game.h>
#include <otclient/core/map.h>
#include <otclient/core/effect.h>
void ProtocolGame::parseMessage(InputMessage& msg)
{
while(!msg.end()) {
uint8 opt = msg.getU8();
dump << "Protocol opt: " << std::hex << (int)opt << std::dec;
switch(opt) {
case 0x0A:
parsePlayerLogin(msg);
break;
case 0x0B:
parseGMActions(msg);
break;
case 0x14:
parseErrorMessage(msg);
break;
case 0x15:
parseFYIMessage(msg);
break;
case 0x16:
parseWaitList(msg);
break;
case 0x1E:
parsePing(msg);
break;
case 0x28:
parseDeath(msg);
break;
case 0x32:
parseCanReportBugs(msg);
break;
case 0x64:
parseMapDescription(msg);
break;
case 0x65:
parseMoveNorth(msg);
break;
case 0x66:
parseMoveEast(msg);
break;
case 0x67:
parseMoveSouth(msg);
break;
case 0x68:
parseMoveWest(msg);
break;
case 0x69:
parseUpdateTile(msg);
break;
case 0x6A:
parseTileAddThing(msg);
break;
case 0x6B:
parseTileTransformThing(msg);
break;
case 0x6C:
parseTileRemoveThing(msg);
break;
case 0x6D:
parseCreatureMove(msg);
break;
case 0x6E:
parseOpenContainer(msg);
break;
case 0x6F:
parseCloseContainer(msg);
break;
case 0x70:
parseContainerAddItem(msg);
break;
case 0x71:
parseContainerUpdateItem(msg);
break;
case 0x72:
parseContainerRemoveItem(msg);
break;
case 0x78:
parseAddInventoryItem(msg);
break;
case 0x79:
parseRemoveInventoryItem(msg);
break;
case 0x7A:
parseOpenShopWindow(msg);
break;
case 0x7B:
parsePlayerCash(msg);
break;
case 0x7C:
parseCloseShopWindow(msg);
break;
case 0x7D:
parseSafeTradeRequest(msg);
break;
case 0x7E:
parseSafeTradeRequest(msg);
break;
case 0x7F:
parseSafeTradeClose(msg);
break;
case 0x82:
parseWorldLight(msg);
break;
case 0x83:
parseMagicEffect(msg);
break;
case 0x84:
parseAnimatedText(msg);
break;
case 0x85:
parseDistanceShot(msg);
break;
case 0x86:
parseCreatureSquare(msg);
break;
case 0x8C:
parseCreatureHealth(msg);
break;
case 0x8D:
parseCreatureLight(msg);
break;
case 0x8E:
parseCreatureOutfit(msg);
break;
case 0x8F:
parseCreatureSpeed(msg);
break;
case 0x90:
parseCreatureSkulls(msg);
break;
case 0x91:
parseCreatureShields(msg);
break;
case 0x96:
parseItemTextWindow(msg);
break;
case 0x97:
parseHouseTextWindow(msg);
break;
case 0xA0:
parsePlayerStats(msg);
break;
case 0xA1:
parsePlayerSkills(msg);
break;
case 0xA2:
parsePlayerIcons(msg);
break;
case 0xA3:
parsePlayerCancelAttack(msg);
break;
case 0xAA:
parseCreatureSpeak(msg);
break;
case 0xAB:
parseChannelList(msg);
break;
case 0xAC:
parseOpenChannel(msg);
break;
case 0xAD:
parseOpenPrivatePlayerChat(msg);
break;
case 0xAE:
parseOpenRuleViolation(msg);
break;
case 0xAF:
parseRuleViolationAF(msg);
break;
case 0xB0:
parseRuleViolationB0(msg);
break;
case 0xB1:
parseRuleViolationB1(msg);
break;
case 0xB2:
parseCreatePrivateChannel(msg);
break;
case 0xB3:
parseClosePrivateChannel(msg);
break;
case 0xB4:
parseTextMessage(msg);
break;
case 0xB5:
parseCancelWalk(msg);
break;
case 0xBE:
parseFloorChangeUp(msg);
break;
case 0xBF:
parseFloorChangeDown(msg);
break;
case 0xC8:
parseOutfitWindow(msg);
break;
case 0xD2:
parseVipState(msg);
break;
case 0xD3:
parseVipLogin(msg);
break;
case 0xD4:
parseVipLogout(msg);
break;
case 0xDC:
parseShowTutorial(msg);
break;
case 0xDD:
parseAddMarker(msg);
break;
case 0xF0:
parseQuestList(msg);
break;
case 0xF1:
parseQuestPartList(msg);
break;
default:
logDebug("UNKNOWN PACKET BYTE.", opt);
//skipPacket = true;
break;
}
}
recv();
}
void ProtocolGame::parsePlayerLogin(InputMessage& msg)
{
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)
{
for(uint8 i = 0; i < 28; ++i)
msg.getU8();
}
void ProtocolGame::parseErrorMessage(InputMessage& msg)
{
std::string error = msg.getString();
callLuaField("onError", error);
}
void ProtocolGame::parseFYIMessage(InputMessage& msg)
{
msg.getString(); // message
}
void ProtocolGame::parseWaitList(InputMessage& msg)
{
msg.getString(); // message
msg.getU8();// + 1 // time
}
void ProtocolGame::parsePing(InputMessage&)
{
sendPing();
}
void ProtocolGame::parseDeath(InputMessage&)
{
}
void ProtocolGame::parseCanReportBugs(InputMessage& msg)
{
msg.getU8(); // report bugs
}
void ProtocolGame::parseMapDescription(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->setPosition(parsePosition(msg));
setMapDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, player->getPosition()->z, 18, 14);
}
void ProtocolGame::parseMoveNorth(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->getPosition()->y--;
setMapDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, player->getPosition()->z, 18, 1);
}
void ProtocolGame::parseMoveEast(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->getPosition()->x++;
setMapDescription(msg, player->getPosition()->x + 9, player->getPosition()->y - 6, player->getPosition()->z, 1, 14);
}
void ProtocolGame::parseMoveSouth(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->getPosition()->y++;
setMapDescription(msg, player->getPosition()->x - 8, player->getPosition()->y + 7, player->getPosition()->z, 18, 1);
}
void ProtocolGame::parseMoveWest(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->getPosition()->x--;
setMapDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, player->getPosition()->z, 1, 14);
}
void ProtocolGame::parseUpdateTile(InputMessage& msg)
{
Position tilePos = parsePosition(msg);
uint16 thingId = msg.getU16(true);
if(thingId == 0xFF01) {
msg.getU16();
}
else {
setTileDescription(msg, tilePos);
msg.getU16();
}
}
void ProtocolGame::parseTileAddThing(InputMessage& msg)
{
parsePosition(msg); // tilePos
msg.getU8(); // stackPos
internalGetThing(msg);
}
void ProtocolGame::parseTileTransformThing(InputMessage& msg)
{
parsePosition(msg); // tilePos
msg.getU8(); // stackPos
uint16 thingId = msg.getU16();
if(thingId == 0x0061 || thingId == 0x0062 || thingId == 0x0063) {
msg.getU32(); // creatureId
msg.getU8(); // direction
}
else {
internalGetItem(msg, thingId);
}
}
void ProtocolGame::parseTileRemoveThing(InputMessage& msg)
{
parsePosition(msg); // tilePos
msg.getU8(); // stackPos
}
void ProtocolGame::parseCreatureMove(InputMessage& msg)
{
parsePosition(msg); // oldPos
msg.getU8(); // oldStackPos
parsePosition(msg); // newPos
}
void ProtocolGame::parseOpenContainer(InputMessage& msg)
{
msg.getU8(); // cid
msg.getU16(); // itemid
msg.getString(); // name
msg.getU8(); // capacity
msg.getU8(); // hasParent
uint8 size = msg.getU8(); // size
for(uint32 i = 0; i < size; i++)
internalGetItem(msg, 0xFFFF);
}
void ProtocolGame::parseCloseContainer(InputMessage& msg)
{
msg.getU8(); // cid
}
void ProtocolGame::parseContainerAddItem(InputMessage& msg)
{
msg.getU8(); // cid
internalGetItem(msg, 0xFFFF);
}
void ProtocolGame::parseContainerUpdateItem(InputMessage& msg)
{
msg.getU8(); // cid
msg.getU8(); // slot
internalGetItem(msg, 0xFFFF);
}
void ProtocolGame::parseContainerRemoveItem(InputMessage& msg)
{
msg.getU8(); // cid
msg.getU8(); // slot
}
void ProtocolGame::parseAddInventoryItem(InputMessage& msg)
{
msg.getU8(); // slot
internalGetItem(msg, 0xFFFF);
}
void ProtocolGame::parseRemoveInventoryItem(InputMessage& msg)
{
msg.getU8(); // slot
}
void ProtocolGame::parseOpenShopWindow(InputMessage& msg)
{
uint8 listCount = msg.getU8();
for(uint8 i = 0; i < listCount; ++i) {
msg.getU16(); // item id
msg.getU8(); // runecharges
msg.getString(); // item name
msg.getU32(); // weight
msg.getU32(); // buy price
msg.getU32(); // sell price
}
}
void ProtocolGame::parsePlayerCash(InputMessage& msg)
{
msg.getU32();
uint8 size = msg.getU8();
for(int i = 0; i < size; i++) {
msg.getU16(); // itemid
msg.getU8(); // runecharges
}
}
void ProtocolGame::parseCloseShopWindow(InputMessage&)
{
}
void ProtocolGame::parseSafeTradeRequest(InputMessage& msg)
{
msg.getString(); // name
uint8 count = msg.getU8();
for(uint8 i = 0; i < count; i++)
internalGetItem(msg, 0xFFFF);
}
void ProtocolGame::parseSafeTradeClose(InputMessage&)
{
}
void ProtocolGame::parseWorldLight(InputMessage& msg)
{
msg.getU8(); // level
msg.getU8(); // color
}
void ProtocolGame::parseMagicEffect(InputMessage& msg)
{
EffectPtr effect = EffectPtr(new Effect());
effect->setPosition(parsePosition(msg));
effect->setId(msg.getU8());
g_game.getMap()->addThing(effect);
}
void ProtocolGame::parseAnimatedText(InputMessage& msg)
{
parsePosition(msg); // textPos
msg.getU8(); // color
msg.getString(); // text
}
void ProtocolGame::parseDistanceShot(InputMessage& msg)
{
parsePosition(msg); // fromPos
parsePosition(msg); // toPos
msg.getU8(); // effect
}
void ProtocolGame::parseCreatureSquare(InputMessage& msg)
{
msg.getU32(); // creatureId
msg.getU8(); // color
}
void ProtocolGame::parseCreatureHealth(InputMessage& msg)
{
msg.getU32(); // creatureId
msg.getU8(); // percent
}
void ProtocolGame::parseCreatureLight(InputMessage& msg)
{
msg.getU32(); // creature id
msg.getU8(); // level
msg.getU8(); // color
}
void ProtocolGame::parseCreatureOutfit(InputMessage& msg)
{
msg.getU32(); // creature id
internalCreatureOutfit(msg);
}
void ProtocolGame::parseCreatureSpeed(InputMessage& msg)
{
msg.getU32(); // creature id
msg.getU16(); // speed
}
void ProtocolGame::parseCreatureSkulls(InputMessage& msg)
{
msg.getU32(); // creature id
msg.getU8(); // skull
}
void ProtocolGame::parseCreatureShields(InputMessage& msg)
{
msg.getU32(); // creature id
msg.getU8(); // shield
}
void ProtocolGame::parseCreatureTurn(InputMessage& msg)
{
msg.getU32(); // creature id
msg.getU8(); // direction
}
void ProtocolGame::parseItemTextWindow(InputMessage& msg)
{
msg.getU32(); // windowId
msg.getU16(); // itemid
msg.getU16(); // max length
msg.getString(); // text
msg.getString(); // writter
msg.getString(); // date
}
void ProtocolGame::parseHouseTextWindow(InputMessage& msg)
{
msg.getU8(); // unknown
msg.getU32(); // windowId
msg.getString(); // text
}
void ProtocolGame::parsePlayerStats(InputMessage& msg)
{
msg.getU16(); // health
msg.getU16(); // max health
msg.getU32(); // free capacity
msg.getU32(); // experience
msg.getU16(); // level
msg.getU8(); // level percent
msg.getU16(); // mana
msg.getU16(); // max mana
msg.getU8(); // magic level
msg.getU8(); // magic level percent
msg.getU8(); // soul
msg.getU16(); // stamina
}
void ProtocolGame::parsePlayerSkills(InputMessage& msg)
{
msg.getU8(); // fist skill
msg.getU8(); // fist percent
msg.getU8(); // club skill
msg.getU8(); // club percent
msg.getU8(); // sword skill
msg.getU8(); // sword percent
msg.getU8(); // axe skill
msg.getU8(); // axe percent
msg.getU8(); // distance skill
msg.getU8(); // distance percent
msg.getU8(); // shielding skill
msg.getU8(); // shielding percent
msg.getU8(); // fishing skill
msg.getU8(); // fishing percent
}
void ProtocolGame::parsePlayerIcons(InputMessage& msg)
{
msg.getU16(); // icons
}
void ProtocolGame::parsePlayerCancelAttack(InputMessage& msg)
{
msg.getU32();
}
void ProtocolGame::parseCreatureSpeak(InputMessage& msg)
{
msg.getU32(); // unkSpeak
msg.getString(); // name
msg.getU16(); // level
uint8 type = msg.getU8();
switch(type) {
case SPEAK_SAY:
case SPEAK_WHISPER:
case SPEAK_YELL:
case SPEAK_MONSTER_SAY:
case SPEAK_MONSTER_YELL:
case SPEAK_PRIVATE_NP:
parsePosition(msg); // creaturePos
break;
case SPEAK_CHANNEL_R1:
case SPEAK_CHANNEL_R2:
case SPEAK_CHANNEL_O:
case SPEAK_CHANNEL_Y:
case SPEAK_CHANNEL_W:
msg.getU16(); // channelId
break;
case SPEAK_RVR_CHANNEL:
msg.getU32(); // time
break;
default:
//qDebug() << "Unknown speak type. opt: 0xAA, type: " << type;
break;
}
msg.getString(); // message
}
void ProtocolGame::parseChannelList(InputMessage& msg)
{
uint8 count = msg.getU8();
for(uint8 i = 0; i < count; i++) {
msg.getU16();
msg.getString();
}
}
void ProtocolGame::parseOpenChannel(InputMessage& msg)
{
msg.getU16(); // channelId
msg.getString(); // name
}
void ProtocolGame::parseOpenPrivatePlayerChat(InputMessage& msg)
{
msg.getString(); // name
}
void ProtocolGame::parseOpenRuleViolation(InputMessage& msg)
{
msg.getU16(); // a
}
void ProtocolGame::parseRuleViolationAF(InputMessage& msg)
{
msg.getU16(); // a
}
void ProtocolGame::parseRuleViolationB0(InputMessage& msg)
{
msg.getU16(); // a
}
void ProtocolGame::parseRuleViolationB1(InputMessage& msg)
{
msg.getU16(); // a
}
void ProtocolGame::parseCreatePrivateChannel(InputMessage& msg)
{
msg.getU16(); // channel id
msg.getString(); // channel name
}
void ProtocolGame::parseClosePrivateChannel(InputMessage& msg)
{
msg.getU16(); // channel id
}
void ProtocolGame::parseTextMessage(InputMessage& msg)
{
msg.getU8(); // messageType
std::string message = msg.getString();
logDebug(message);
}
void ProtocolGame::parseCancelWalk(InputMessage& msg)
{
msg.getU8(); // direction
}
void ProtocolGame::parseFloorChangeUp(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->getPosition()->z--;
int32 skip = 0;
if(player->getPosition()->z == 7)
for(int32 i = 5; i >= 0; i--)
setFloorDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, i, 18, 14, 8 - i, &skip);
else if(player->getPosition()->z > 7)
setFloorDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, player->getPosition()->z - 2, 18, 14, 3, &skip);
player->getPosition()->x++;
player->getPosition()->y++;
}
void ProtocolGame::parseFloorChangeDown(InputMessage& msg)
{
Player *player = g_game.getPlayer();
player->getPosition()->z++;
int32 skip = 0;
if(player->getPosition()->z == 8) {
int32 j, i;
for(i = player->getPosition()->z, j = -1; i < (int32)player->getPosition()->z + 3; ++i, --j)
setFloorDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, i, 18, 14, j, &skip);
}
else if(player->getPosition()->z > 8 && player->getPosition()->z < 14)
setFloorDescription(msg, player->getPosition()->x - 8, player->getPosition()->y - 6, player->getPosition()->z + 2, 18, 14, -3, &skip);
player->getPosition()->x--;
player->getPosition()->y--;
}
void ProtocolGame::parseOutfitWindow(InputMessage& msg)
{
internalCreatureOutfit(msg);
uint8 outfitCount = msg.getU8();
for(int i = 0; i < outfitCount; i++) {
msg.getU16(); // outfit id
msg.getString(); // outfit name
msg.getU8(); // addons
}
}
void ProtocolGame::parseVipState(InputMessage& msg)
{
msg.getU32(); // player id
msg.getString(); // player name
msg.getU8(); // online
}
void ProtocolGame::parseVipLogin(InputMessage& msg)
{
msg.getU32(); // player id
}
void ProtocolGame::parseVipLogout(InputMessage& msg)
{
msg.getU32(); // player id
}
void ProtocolGame::parseShowTutorial(InputMessage& msg)
{
msg.getU8(); // tutorial id
}
void ProtocolGame::parseAddMarker(InputMessage& msg)
{
parsePosition(msg); // position
msg.getU8(); // icon
msg.getString(); // message
}
void ProtocolGame::parseQuestList(InputMessage& msg)
{
uint16 questsCount = msg.getU16();
for(uint16 i = 0; i < questsCount; i++) {
msg.getU16(); // quest id
msg.getString(); // quest name
msg.getU8(); // quest state
}
}
void ProtocolGame::parseQuestPartList(InputMessage& msg)
{
msg.getU16(); // quest id
uint8 missionCount = msg.getU8();
for(uint8 i = 0; i < missionCount; i++) {
msg.getString(); // quest name
msg.getString(); // quest description
}
}
void ProtocolGame::setMapDescription(InputMessage& msg, int32 x, int32 y, int32 z, int32 width, int32 height)
{
int startz, endz, zstep, skip = 0;
if(z > 7) {
startz = z - 2;
endz = (15 < z+2) ? 15 : z+2;
zstep = 1;
}
else {
startz = 7;
endz = 0;
zstep = -1;
}
logDebug((int)startz);
for(int nz = startz; nz != endz + zstep; nz += zstep)
setFloorDescription(msg, x, y, nz, width, height, z - nz, &skip);
}
void ProtocolGame::setFloorDescription(InputMessage& msg, int32 x, int32 y, int32 z, int32 width, int32 height, int32 offset, int32* skipTiles)
{
int32 skip = *skipTiles;
for(int32 nx = 0; nx < width; nx++) {
for(int32 ny = 0; ny < height; ny++) {
if(skip == 0) {
uint16 tileOpt = msg.getU16(true);
if(tileOpt >= 0xFF00)
skip = (msg.getU16() & 0xFF);
else {
Position pos(x + nx + offset, y + ny + offset, z);
setTileDescription(msg, pos);
skip = (msg.getU16() & 0xFF);
}
}
else
skip--;
}
}
*skipTiles = skip;
}
void ProtocolGame::setTileDescription(InputMessage& msg, Position position)
{
int stackpos = 0;
while(1){
stackpos++;
uint16 inspectTileId = msg.getU16(true);
if(inspectTileId >= 0xFF00)
return;
else {
if(stackpos > 10) {
logDebug("[ProtocolGame::setTileDescription] Too many things!.");
return;
}
ThingPtr thing = internalGetThing(msg);
if(thing)
thing->setPosition(position);
g_game.getMap()->addThing(thing, stackpos);
}
}
}
ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
{
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
creature->setId(msg.getU32());
}
else if(thingId == 0x0061) { //creature is not known
msg.getU32(); // remove id
creature->setId(msg.getU32());
creature->setName(msg.getString());
}
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
if(thingId == 0x0061) // emblem is sent only in packet type 0x61
msg.getU8();
msg.getU8(); // impassable
thing = creature;
}
else if(thingId == 0x0063) { // creature turn
parseCreatureTurn(msg);
}
else // item
thing = internalGetItem(msg, thingId);
return thing;
}
Outfit ProtocolGame::internalCreatureOutfit(InputMessage& msg)
{
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 {
outfit.type = msg.getU16();
}
return outfit;
}
ItemPtr ProtocolGame::internalGetItem(InputMessage& msg, uint16 id)
{
ItemPtr item = ItemPtr(new Item());
if(id == 0xFFFF)
id = msg.getU16();
item->setId(id);
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;
}
Position ProtocolGame::parsePosition(InputMessage& msg)
{
uint16 x = msg.getU16();
uint16 y = msg.getU16();
uint8 z = msg.getU8();
return Position(x, y, z);
}

View File

@ -0,0 +1,44 @@
#include "protocolgame.h"
void ProtocolGame::sendLogout()
{
OutputMessage oMsg;
oMsg.addU8(0x14);
send(oMsg);
}
void ProtocolGame::sendPing()
{
OutputMessage oMsg;
oMsg.addU8(0x1E);
send(oMsg);
}
void ProtocolGame::sendWalkNorth()
{
OutputMessage oMsg;
oMsg.addU8(0x65);
send(oMsg);
}
void ProtocolGame::sendWalkEast()
{
OutputMessage oMsg;
oMsg.addU8(0x66);
send(oMsg);
}
void ProtocolGame::sendWalkSouth()
{
OutputMessage oMsg;
oMsg.addU8(0x67);
send(oMsg);
}
void ProtocolGame::sendWalkWest()
{
OutputMessage oMsg;
oMsg.addU8(0x68);
send(oMsg);
}

View File

@ -0,0 +1,153 @@
#include "protocollogin.h"
#include <framework/net/outputmessage.h>
#include <framework/net/rsa.h>
#include <framework/luascript/luainterface.h>
#include <boost/bind.hpp>
// TODO just testing
#include "protocolgame.h"
ProtocolLogin::ProtocolLogin()
{
}
ProtocolLogin::~ProtocolLogin()
{
}
void ProtocolLogin::login(const std::string& accountName, const std::string& accountPassword)
{
if(accountName.empty() || accountPassword.empty()) {
callLuaField("onError", "You must enter an account name and password.");
return;
}
m_accountName = accountName;
m_accountPassword = accountPassword;
/*static const char hosts[][32] = {
"login01.tibia.com",
"login02.tibia.com",
"login03.tibia.com",
"login04.tibia.com",
"login05.tibia.com",
"tibia01.cipsoft.com",
"tibia02.cipsoft.com",
"tibia03.cipsoft.com",
"tibia04.cipsoft.com",
"tibia05.cipsoft.com"
};
std::string host = hosts[rand() % 10];*/
std::string host = "sv3.radbr.com";
uint16 port = 7171;
connect(host, port);
}
void ProtocolLogin::onConnect()
{
sendLoginPacket();
}
void ProtocolLogin::sendLoginPacket()
{
OutputMessage oMsg;
oMsg.addU8(0x01); // Protocol id
oMsg.addU16(0x02); // OS
oMsg.addU16(862); // Client version
oMsg.addU32(0x4E12DAFF); // Data Signature
oMsg.addU32(0x4E12DB27); // Sprite Signature
oMsg.addU32(0x4E119CBF); // Picture Signature
oMsg.addU8(0); // First RSA byte must be 0x00 // 1
// Generete xtea key.
m_xteaKey[0] = 432324;
m_xteaKey[1] = 24324;
m_xteaKey[2] = 423432;
m_xteaKey[3] = 234324;
// Add xtea key
oMsg.addU32(m_xteaKey[0]); // 5
oMsg.addU32(m_xteaKey[1]); // 9
oMsg.addU32(m_xteaKey[2]); // 13
oMsg.addU32(m_xteaKey[3]); // 17
oMsg.addString(m_accountName); // Account Name // 19
oMsg.addString(m_accountPassword); // Password // 21
// Packet data must have since byte 0, start, 128 bytes
oMsg.addPaddingBytes(128 - (21 + m_accountName.length() + m_accountPassword.length()));
// Encrypt msg with RSA
if(!Rsa::encrypt((char*)oMsg.getBuffer() + 6 + oMsg.getMessageSize() - 128, 128, OTSERV_PUBLIC_RSA))
return;
send(oMsg);
m_xteaEncryptionEnabled = true;
recv();
}
void ProtocolLogin::onRecv(InputMessage& inputMessage)
{
while(!inputMessage.end()) {
uint8 opt = inputMessage.getU8();
logDebug("opt:",(uint)opt);
switch(opt) {
case 0x0A:
parseError(inputMessage);
break;
case 0x14:
parseMOTD(inputMessage);
break;
case 0x1e:
callLuaField("onError", "Client needs update.");
break;
case 0x64:
parseCharacterList(inputMessage);
break;
}
}
}
void ProtocolLogin::parseError(InputMessage& inputMessage)
{
std::string error = inputMessage.getString();
logDebug(error);
callLuaField("onError", error);
}
void ProtocolLogin::parseMOTD(InputMessage& inputMessage)
{
std::string motd = inputMessage.getString();
logDebug(motd);
callLuaField("onMotd", motd);
}
void ProtocolLogin::parseCharacterList(InputMessage& inputMessage)
{
uint8 characters = inputMessage.getU8();
for(int i = 0; i < characters; ++i) {
std::string name = inputMessage.getString();
std::string world = inputMessage.getString();
uint32 ip = inputMessage.getU32();
uint16 port = inputMessage.getU16();
logDebug("character: ", name.c_str(), world.c_str(), ip, " ", port);
// TODO just test
if(i == 0) {
ProtocolGamePtr protocolGame = ProtocolGamePtr(new ProtocolGame);
protocolGame->login(m_accountName, m_accountPassword, ip, port, name);
}
}
uint16 premiumDays = inputMessage.getU16();
logDebug("prem days: ", premiumDays);
}

View File

@ -0,0 +1,39 @@
#ifndef PROTOCOLLOGIN_H
#define PROTOCOLLOGIN_H
#include "declarations.h"
#include <framework/net/protocol.h>
class ProtocolLogin;
typedef std::shared_ptr<ProtocolLogin> ProtocolLoginPtr;
class ProtocolLogin : public Protocol
{
public:
ProtocolLogin();
~ProtocolLogin();
static ProtocolLoginPtr create() { return ProtocolLoginPtr(new ProtocolLogin); }
void login(const std::string& accountName, const std::string& accountPassword);
void onConnect();
void onRecv(InputMessage& inputMessage);
void cancel() { /* TODO: this func */ }
ProtocolLoginPtr asProtocolLogin() { return std::static_pointer_cast<ProtocolLogin>(shared_from_this()); }
virtual const char* getLuaTypeName() const { return "ProtocolLogin"; }
private:
void sendLoginPacket();
void parseError(InputMessage& inputMessage);
void parseMOTD(InputMessage& inputMessage);
void parseCharacterList(InputMessage& inputMessage);
std::string m_accountName, m_accountPassword;
};
#endif

278
src/otclient/otclient.cpp Normal file
View File

@ -0,0 +1,278 @@
#include "otclient.h"
#include <framework/core/modulemanager.h>
#include <framework/core/configmanager.h>
#include <framework/core/resourcemanager.h>
#include <framework/core/eventdispatcher.h>
#include <framework/luascript/luainterface.h>
#include <framework/platform/platform.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/fontmanager.h>
#include <framework/ui/uimanager.h>
#include <framework/ui/uiwidget.h>
#include <framework/net/connection.h>
#include <otclient/net/protocolgame.h>
#include <otclient/core/game.h>
#include <otclient/core/map.h>
#define POLL_CYCLE_DELAY 10
OTClient g_client;
void OTClient::init(std::vector<std::string> args)
{
m_running = false;
m_stopping = false;
// print client information
logInfo("OTClient 0.2.0");
// initialize platform related stuff
g_platform.init(this, "OTClient");
// initialize script environment
g_lua.init();
// register otclient lua functions
registerLuaFunctions();
// initialize resources
g_resources.init(args[0].c_str());
// load configurations
loadConfigurations();
// create the client window
g_platform.createWindow(g_configs.get("window x"), g_configs.get("window y"),
g_configs.get("window width"), g_configs.get("window height"),
550, 450,
g_configs.get("window maximized"));
g_platform.setWindowTitle("OTClient");
// initialize graphics
g_graphics.init();
// initialize event dispatcher
g_dispatcher.init();
// initialize network
//g_network.init();
// initialize the ui
g_ui.init();
// discover and load modules
g_modules.discoverAndLoadModules();
// now that everything is initialized, setup configurations
setupConfigurations();
// now that everything is loaded, show the window
g_platform.showWindow();
}
void OTClient::run()
{
std::string fpsText;
Size fpsTextSize;
FontPtr defaultFont = g_fonts.getDefaultFont();
int frameTicks = g_platform.getTicks();
int lastFpsTicks = frameTicks;
int lastPollTicks = frameTicks;
int frameCount = 0;
m_stopping = false;
m_running = true;
if(g_ui.getRootWidget()->getChildCount() == 0) {
logError("ERROR: there is no root widgets to display, the app will close");
m_stopping = true;
}
// run the first poll
poll();
while(!m_stopping) {
frameTicks = g_platform.getTicks();
// calculate fps
frameCount++;
if(frameTicks - lastFpsTicks >= 1000) {
fpsText = fw::mkstr("FPS: ", frameCount);
fpsTextSize = defaultFont->calculateTextRectSize(fpsText);
frameCount = 0;
lastFpsTicks = frameTicks;
}
// poll events every POLL_CYCLE_DELAY
// this delay exists to avoid massive polling thus increasing framerate
if(frameTicks - lastPollTicks >= POLL_CYCLE_DELAY) {
poll();
lastPollTicks = frameTicks;
}
// only render when the windows is visible
if(g_platform.isWindowVisible()) {
// render begin
g_graphics.beginRender();
// render everything
render();
// render fps
defaultFont->renderText(fpsText, Point(g_graphics.getScreenSize().width() - fpsTextSize.width() - 10, 10));
// render end
g_graphics.endRender();
// swap the old buffer with the new rendered
g_platform.swapBuffers();
} else {
// sleeps until next poll to avoid massive cpu usage
g_platform.sleep(POLL_CYCLE_DELAY+1);
}
}
m_stopping = false;
m_running = false;
}
void OTClient::terminate()
{
// hide the window because there is no render anymore
g_platform.hideWindow();
// run modules unload event
g_modules.unloadModules();
// terminate ui
g_ui.terminate();
// release remaining lua object references
g_lua.collectGarbage();
// poll remaining events
poll();
// terminate network
//g_network.terminate();
// terminate dispatcher
g_dispatcher.terminate();
// terminate graphics
g_graphics.terminate();
// save configurations
saveConfigurations();
// release resources
g_resources.terminate();
// terminate script environment
g_lua.terminate();
// end platform related stuff
g_platform.terminate();
}
void OTClient::exit()
{
// stops the main loop
m_stopping = true;
}
void OTClient::poll()
{
// poll platform events
g_platform.poll();
// poll network events
//g_network.poll();
Connection::poll();
// poll dispatcher events
g_dispatcher.poll();
}
void OTClient::render()
{
if(g_game.getOnline())
g_game.getMap()->draw(0, 0);
// everything is rendered by UI components
g_ui.render();
}
void OTClient::loadConfigurations()
{
// default window size
int defWidth = 550;
int defHeight = 450;
// sets default window configuration
g_configs.set("window x", (g_platform.getDisplayWidth() - defWidth)/2);
g_configs.set("window y", (g_platform.getDisplayHeight() - defHeight)/2);
g_configs.set("window width", defWidth);
g_configs.set("window height", defHeight);
g_configs.set("window maximized", false);
g_configs.set("vsync", true);
// loads user configuration
if(!g_configs.load("config.otml"))
logInfo("Using default configurations.");
}
void OTClient::setupConfigurations()
{
// activate vertical synchronization?
g_platform.setVerticalSync(g_configs.get("vsync"));
}
void OTClient::saveConfigurations()
{
g_configs.set("window x", g_platform.getWindowX());
g_configs.set("window y", g_platform.getWindowY());
g_configs.set("window width", g_platform.getWindowWidth());
g_configs.set("window height", g_platform.getWindowHeight());
g_configs.set("window maximized", g_platform.isWindowMaximized());
// saves user configuration
if(!g_configs.save())
logError("ERROR: configurations are lost because it couldn't be saved");
}
void OTClient::onClose()
{
if(m_onCloseCallback)
m_onCloseCallback();
else
exit();
}
void OTClient::onResize(const Size& size)
{
g_graphics.resize(size);
g_ui.resize(size);
}
void OTClient::onInputEvent(const InputEvent& event)
{
g_ui.inputEvent(event);
ProtocolGamePtr protocol = g_game.getProtocol();
if(protocol) {
if(event.type == EventKeyDown) {
if(event.keycode == KC_UP)
protocol->sendWalkNorth();
if(event.keycode == KC_RIGHT)
protocol->sendWalkEast();
if(event.keycode == KC_DOWN)
protocol->sendWalkSouth();
if(event.keycode == KC_LEFT)
protocol->sendWalkWest();
}
}
}

52
src/otclient/otclient.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef OTCLIENT_H
#define OTCLIENT_H
#include <framework/platform/platformlistener.h>
class OTClient : public PlatformListener
{
public:
/// Where everything begins...
void init(std::vector<std::string> args);
/// Main loop
void run();
/// Called when the client is terminating
void terminate();
/// Stop running
void exit();
/// Poll platform, dispatcher and network events
void poll();
/// Render each frame
void render();
/// Fired when user tryes to close the window
void onClose();
/// Fired when user resize the window
void onResize(const Size& size);
/// Fired on an user input event
void onInputEvent(const InputEvent& event);
bool isRunning() const { return m_running; }
void setOnClose(const SimpleCallback& onCloseCallback) { m_onCloseCallback = onCloseCallback; }
SimpleCallback getOnClose() const { return m_onCloseCallback; }
private:
/// Set default configurations and load the user configurations
void loadConfigurations();
/// Use the loaded configurations to setup other classes
void setupConfigurations();
void saveConfigurations();
void registerLuaFunctions();
bool m_running;
bool m_stopping;
SimpleCallback m_onCloseCallback;
};
extern OTClient g_client;
#endif

View File

@ -0,0 +1,25 @@
#include "otclient.h"
#include <framework/luascript/luainterface.h>
#include <otclient/core/tibiadat.h>
#include <otclient/core/tibiaspr.h>
#include <otclient/net/protocollogin.h>
#include <otclient/net/protocolgame.h>
void OTClient::registerLuaFunctions()
{
// easy typing _1, _2, ...
using namespace std::placeholders;
g_lua.bindGlobalFunction("exit", std::bind(&OTClient::exit, &g_client));
g_lua.bindGlobalFunction("setOnClose", std::bind(&OTClient::setOnClose, &g_client, _1));
g_lua.bindGlobalFunction("importDat", std::bind(&TibiaDat::load, &g_tibiaDat, _1));
g_lua.bindGlobalFunction("importSpr", std::bind(&TibiaSpr::load, &g_tibiaSpr, _1));
g_lua.registerClass<ProtocolLogin, Protocol>();
g_lua.bindClassStaticFunction<ProtocolLogin>("create", &ProtocolLogin::create);
g_lua.bindClassMemberFunction("login", &ProtocolLogin::login);
g_lua.bindClassMemberFunction("cancel", &ProtocolLogin::cancel);
g_lua.registerClass<ProtocolGame, Protocol>();
}

View File

@ -0,0 +1,50 @@
#ifndef POSITION_H
#define POSITION_H
#include <framework/util/types.h>
enum Direction
{
DIRECTION_NORTH,
DIRECTION_EAST,
DIRECTION_SOUTH,
DIRECTION_WEST
};
class Position
{
public:
Position() : x(-1), y(-1), z(-1) { }
Position(int x, int y, int z) : x(x), y(y), z(z) { }
bool isValid() const { return x >= 0 && y >= 0 && z >= 0 && x < 65536 && y < 65536 && z < 15; }
Position operator+(const Position& other) const { return Position(x + other.x, y + other.y, z + other.z); }
Position& operator+=(const Position& other) { x+=other.x; y+=other.y; z +=other.z; return *this; }
Position operator-(const Position& other) const { return Position(x - other.x, y - other.y, z + other.z); }
Position& operator-=(const Position& other) { x-=other.x; y-=other.y; z-=other.z; return *this; }
Position& operator=(const Position& other) { x = other.x; y = other.y; z = other.z; return *this; }
bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }
bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; }
int x;
int y;
int z;
};
template<class T>
std::ostream& operator<<(std::ostream& out, const Position& pos)
{
out << pos.x << " " << pos.y << " " << pos.z;
return out;
}
template<class T>
std::istream& operator>>(std::istream& in, Position& pos)
{
in >> pos.x >> pos.y >> pos.z;
return in;
}
#endif