Just rename some files

* Fix a server ping issue
This commit is contained in:
Eduardo Bart
2013-01-08 16:21:54 -02:00
parent 8d07f8eaf6
commit 122577a916
307 changed files with 383 additions and 478 deletions

100
src/client/CMakeLists.txt Normal file
View File

@@ -0,0 +1,100 @@
# CMAKE_CURRENT_LIST_DIR cmake 2.6 compatibility
if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 6)
get_filename_component(CMAKE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
endif(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 6)
# client options
add_definitions(-DOTCLIENT)
option(BOT_PROTECTION "Enable bot protection" ON)
if(BOT_PROTECTION)
add_definitions(-DBOT_PROTECTION)
message(STATUS "Bot protection: ON")
else(BOT_PROTECTION)
message(STATUS "Bot protection: OFF")
endif(BOT_PROTECTION)
set(client_SOURCES ${client_SOURCES}
# client
${CMAKE_CURRENT_LIST_DIR}/const.h
${CMAKE_CURRENT_LIST_DIR}/global.h
${CMAKE_CURRENT_LIST_DIR}/luafunctions.cpp
${CMAKE_CURRENT_LIST_DIR}/client.cpp
${CMAKE_CURRENT_LIST_DIR}/client.h
# core
${CMAKE_CURRENT_LIST_DIR}/animatedtext.cpp
${CMAKE_CURRENT_LIST_DIR}/animatedtext.h
${CMAKE_CURRENT_LIST_DIR}/container.cpp
${CMAKE_CURRENT_LIST_DIR}/container.h
${CMAKE_CURRENT_LIST_DIR}/creature.cpp
${CMAKE_CURRENT_LIST_DIR}/creature.h
${CMAKE_CURRENT_LIST_DIR}/declarations.h
${CMAKE_CURRENT_LIST_DIR}/effect.cpp
${CMAKE_CURRENT_LIST_DIR}/effect.h
${CMAKE_CURRENT_LIST_DIR}/game.cpp
${CMAKE_CURRENT_LIST_DIR}/game.h
${CMAKE_CURRENT_LIST_DIR}/shadermanager.cpp
${CMAKE_CURRENT_LIST_DIR}/shadermanager.h
${CMAKE_CURRENT_LIST_DIR}/item.cpp
${CMAKE_CURRENT_LIST_DIR}/item.h
${CMAKE_CURRENT_LIST_DIR}/localplayer.cpp
${CMAKE_CURRENT_LIST_DIR}/localplayer.h
${CMAKE_CURRENT_LIST_DIR}/map.cpp
${CMAKE_CURRENT_LIST_DIR}/map.h
${CMAKE_CURRENT_LIST_DIR}/mapio.cpp
${CMAKE_CURRENT_LIST_DIR}/mapview.cpp
${CMAKE_CURRENT_LIST_DIR}/mapview.h
${CMAKE_CURRENT_LIST_DIR}/lightview.cpp
${CMAKE_CURRENT_LIST_DIR}/lightview.h
${CMAKE_CURRENT_LIST_DIR}/missile.cpp
${CMAKE_CURRENT_LIST_DIR}/missile.h
${CMAKE_CURRENT_LIST_DIR}/outfit.cpp
${CMAKE_CURRENT_LIST_DIR}/outfit.h
${CMAKE_CURRENT_LIST_DIR}/player.cpp
${CMAKE_CURRENT_LIST_DIR}/player.h
${CMAKE_CURRENT_LIST_DIR}/spritemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/spritemanager.h
${CMAKE_CURRENT_LIST_DIR}/statictext.cpp
${CMAKE_CURRENT_LIST_DIR}/statictext.h
${CMAKE_CURRENT_LIST_DIR}/thing.cpp
${CMAKE_CURRENT_LIST_DIR}/thing.h
${CMAKE_CURRENT_LIST_DIR}/thingtypemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/thingtypemanager.h
${CMAKE_CURRENT_LIST_DIR}/thingtype.cpp
${CMAKE_CURRENT_LIST_DIR}/thingtype.h
${CMAKE_CURRENT_LIST_DIR}/itemtype.cpp
${CMAKE_CURRENT_LIST_DIR}/itemtype.h
${CMAKE_CURRENT_LIST_DIR}/tile.cpp
${CMAKE_CURRENT_LIST_DIR}/tile.h
${CMAKE_CURRENT_LIST_DIR}/houses.cpp
${CMAKE_CURRENT_LIST_DIR}/houses.h
${CMAKE_CURRENT_LIST_DIR}/towns.cpp
${CMAKE_CURRENT_LIST_DIR}/towns.h
${CMAKE_CURRENT_LIST_DIR}/creatures.cpp
${CMAKE_CURRENT_LIST_DIR}/creatures.h
# lua
${CMAKE_CURRENT_LIST_DIR}/luavaluecasts.cpp
${CMAKE_CURRENT_LIST_DIR}/luavaluecasts.h
# net
${CMAKE_CURRENT_LIST_DIR}/protocolcodes.cpp
${CMAKE_CURRENT_LIST_DIR}/protocolcodes.h
${CMAKE_CURRENT_LIST_DIR}/protocolgame.cpp
${CMAKE_CURRENT_LIST_DIR}/protocolgame.h
${CMAKE_CURRENT_LIST_DIR}/protocolgameparse.cpp
${CMAKE_CURRENT_LIST_DIR}/protocolgamesend.cpp
# ui
${CMAKE_CURRENT_LIST_DIR}/uicreature.cpp
${CMAKE_CURRENT_LIST_DIR}/uicreature.h
${CMAKE_CURRENT_LIST_DIR}/uiitem.cpp
${CMAKE_CURRENT_LIST_DIR}/uiitem.h
${CMAKE_CURRENT_LIST_DIR}/uimap.cpp
${CMAKE_CURRENT_LIST_DIR}/uimap.h
${CMAKE_CURRENT_LIST_DIR}/uiprogressrect.cpp
${CMAKE_CURRENT_LIST_DIR}/uiprogressrect.h
# util
${CMAKE_CURRENT_LIST_DIR}/position.h
)

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "animatedtext.h"
#include "map.h"
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
#include <framework/graphics/graphics.h>
AnimatedText::AnimatedText()
{
m_cachedText.setFont(g_fonts.getFont("verdana-11px-rounded"));
m_cachedText.setAlign(Fw::AlignLeft);
}
void AnimatedText::drawText(const Point& dest, const Rect& visibleRect)
{
Point p = dest;
Size textSize = m_cachedText.getTextSize();
p.x += 20 - textSize.width() / 2;
p.y += (-20 * m_animationTimer.ticksElapsed()) / Otc::ANIMATED_TEXT_DURATION;
Rect rect(p, textSize);
if(visibleRect.contains(rect)) {
//TODO: cache into a framebuffer
g_painter->setColor(m_color);
m_cachedText.draw(rect);
}
}
void AnimatedText::onAppear()
{
m_animationTimer.restart();
// schedule removal
auto self = asAnimatedText();
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, Otc::ANIMATED_TEXT_DURATION);
}
void AnimatedText::setColor(int color)
{
m_color = Color::from8bit(color);
}
void AnimatedText::setText(const std::string& text)
{
m_cachedText.setText(text);
}

54
src/client/animatedtext.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef ANIMATEDTEXT_H
#define ANIMATEDTEXT_H
#include "thing.h"
#include <framework/graphics/fontmanager.h>
#include <framework/core/timer.h>
#include <framework/graphics/cachedtext.h>
// @bindclass
class AnimatedText : public Thing
{
public:
AnimatedText();
void drawText(const Point& dest, const Rect& visibleRect);
void setColor(int color);
void setText(const std::string& text);
AnimatedTextPtr asAnimatedText() { return static_self_cast<AnimatedText>(); }
bool isAnimatedText() { return true; }
protected:
virtual void onAppear();
private:
Color m_color;
Timer m_animationTimer;
CachedText m_cachedText;
};
#endif

89
src/client/client.cpp Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "client.h"
#include <framework/core/modulemanager.h>
#include <framework/core/resourcemanager.h>
#include <framework/graphics/graphics.h>
#include "game.h"
#include "map.h"
#include "shadermanager.h"
#include "spritemanager.h"
#include <framework/core/configmanager.h>
Client g_client;
void Client::init(std::vector<std::string>& args)
{
// register needed lua functions
registerLuaFunctions();
g_game.init();
g_shaders.init();
g_things.init();
//TODO: restore options
/*
if(g_graphics.parseOption(arg))
continue;
if(arg == "-version" || arg == "--version" || arg == "-v") {
stdext::print(
m_appName, " ", m_appVersion, "\n"
"Buitt on: ", BUILD_DATE, "\n",
"Commit: ", BUILD_COMMIT, "\n",
"Compiled by: ", BUILD_COMPILER, "\n",
"Build type: ", BUILD_TYPE, "\n");
return;
} else if(arg == "-help" || arg == "--help" || arg == "-h" || arg == "-?" || arg == "/?") {
stdext::print(
"Usage: ", args[0], " [options]\n"
"Options:\n"
" -help Display this information and exit\n"
" -version Display version and exit\n"
" \n"
" -no-fbos Disable usage of opengl framebuffer objects\n"
" -no-mipmaps Disable texture mipmaping\n"
" -no-smooth Disable texture smoothing (bilinear filter)\n"
" -no-non-power-of-two-textures Use only power of two textures\n"
" -no-clamp-to-edge Don't use GL_CLAMP_TO_EDGE\n"
" -no-backbuffer-cache Don't allow backbuffer caching\n"
" -hardware-buffers Cache vertex arrays in hardware\n"
" -opengl1 Use OpenGL 1.x painter\n"
" -opengl2 Use OpenGL 2.0 painter\n");
return;
} else {
stdext::println("Unrecognized option '", arg, "', please see -help for available options list");
return;
}
*/
}
void Client::terminate()
{
g_creatures.terminate();
g_game.terminate();
g_map.terminate();
g_things.terminate();
g_sprites.terminate();
g_shaders.terminate();
}

38
src/client/client.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CLIENT_H
#define CLIENT_H
#include "global.h"
class Client
{
public:
void init(std::vector<std::string>& args);
void terminate();
void registerLuaFunctions();
};
extern Client g_client;
#endif

408
src/client/const.h Normal file
View File

@@ -0,0 +1,408 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef OTCLIENT_CONST_H
#define OTCLIENT_CONST_H
namespace Otc
{
enum {
TILE_PIXELS = 32,
MAX_ELEVATION = 24,
SEA_FLOOR = 7,
MAX_Z = 15,
UNDERGROUND_FLOOR = SEA_FLOOR+1,
VISIBLE_X_TILES = 15,
VISIBLE_Y_TILES = 11,
AWARE_UNDEGROUND_FLOOR_RANGE = 2,
AWARE_X_TILES = VISIBLE_X_TILES + 3,
AWARE_Y_TILES = VISIBLE_Y_TILES + 3,
AWARE_X_LEFT_TILES = AWARE_X_TILES/2 - 1,
AWARE_X_RIGHT_TILES = AWARE_X_TILES/2,
AWARE_Y_TOP_TILES = AWARE_Y_TILES/2 - 1,
AWARE_Y_BOTTOM_TILES = AWARE_Y_TILES/2,
INVISIBLE_TICKS_PER_FRAME = 500,
ITEM_TICKS_PER_FRAME = 500,
ANIMATED_TEXT_DURATION = 1000,
STATIC_DURATION_PER_CHARACTER = 60,
MIN_STATIC_TEXT_DURATION = 3000,
MAX_STATIC_TEXT_WIDTH = 200,
MAX_AUTOWALK_STEPS_RETRY = 10
};
enum DrawFlags {
DrawGround = 1,
DrawGroundBorders = 2,
DrawOnBottom = 4,
DrawOnTop = 8,
DrawItems = 16,
DrawCreatures = 32,
DrawEffects = 64,
DrawMissiles = 128,
DrawCreaturesInformation = 256,
DrawStaticTexts = 512,
DrawAnimatedTexts = 1024,
DrawAnimations = 2048,
DrawWalls = DrawOnBottom | DrawOnTop,
DrawEverything = DrawGround | DrawGroundBorders | DrawWalls | DrawItems |
DrawCreatures | DrawEffects | DrawMissiles | DrawCreaturesInformation |
DrawStaticTexts | DrawAnimatedTexts | DrawAnimations
};
enum DatOpts {
DatGround = 0,
DatGroundClip,
DatOnBottom,
DatOnTop,
DatContainer,
DatStackable,
DatForceUse,
DatMultiUse,
DatWritable,
DatWritableOnce,
DatFluidContainer,
DatSplash,
DatBlockWalk,
DatNotMoveable,
DatBlockProjectile,
DatBlockPathFind,
DatPickupable,
DatHangable,
DatHookSouth,
DatHookEast,
DatRotable,
DatLight,
DatDontHide,
DatTranslucent,
DatDisplacement,
DatElevation,
DatLyingCorpse,
DatAnimateAlways,
DatMinimapColor,
DatLensHelp,
DatFullGround,
DatIgnoreLook,
DatCloth,
DatAnimation, // lastest tibia
DatLastOpt = 255
};
enum InventorySlot {
InventorySlotHead = 1,
InventorySlotNecklace,
InventorySlotBackpack,
InventorySlotArmor,
InventorySlotRight,
InventorySlotLeft,
InventorySlotLegs,
InventorySlotFeet,
InventorySlotRing,
InventorySlotAmmo,
InventorySlotPurse,
InventorySlotExt1,
InventorySlotExt2,
InventorySlotExt3,
InventorySlotExt4,
LastInventorySlot
};
enum Statistic {
Health = 0,
MaxHealth,
FreeCapacity,
Experience,
Level,
LevelPercent,
Mana,
MaxMana,
MagicLevel,
MagicLevelPercent,
Soul,
Stamina,
LastStatistic
};
enum Skill {
Fist = 0,
Club,
Sword,
Axe,
Distance,
Shielding,
Fishing,
LastSkill
};
enum Direction {
North = 0,
East,
South,
West,
NorthEast,
SouthEast,
SouthWest,
NorthWest,
InvalidDirection
};
enum FluidsColor {
FluidTransparent = 0,
FluidBlue,
FluidRed,
FluidBrown,
FluidGreen,
FluidYellow,
FluidWhite,
FluidPurple
};
enum FluidsType {
FluidNone = 0,
FluidWater,
FluidMana,
FluidBeer,
FluidOil,
FluidBlood,
FluidSlime,
FluidMud,
FluidLemonade,
FluidMilk,
FluidWine,
FluidHealth,
FluidUrine,
FluidRum,
FluidFruidJuice,
FluidCoconutMilk,
FluidTea,
FluidMead
};
enum FightModes {
FightOffensive = 1,
FightBalanced = 2,
FightDefensive = 3
};
enum ChaseModes {
DontChase = 0,
ChaseOpponent = 1
};
enum PlayerSkulls {
SkullNone = 0,
SkullYellow,
SkullGreen,
SkullWhite,
SkullRed,
SkullBlack,
SkullOrange
};
enum PlayerShields {
ShieldNone = 0,
ShieldWhiteYellow, // 1 party leader
ShieldWhiteBlue, // 2 party member
ShieldBlue, // 3 party member sexp off
ShieldYellow, // 4 party leader sexp off
ShieldBlueSharedExp, // 5 party member sexp on
ShieldYellowSharedExp, // 6 // party leader sexp on
ShieldBlueNoSharedExpBlink, // 7 party member sexp inactive guilty
ShieldYellowNoSharedExpBlink, // 8 // party leader sexp inactive guilty
ShieldBlueNoSharedExp, // 9 party member sexp inactive innocent
ShieldYellowNoSharedExp // 10 party leader sexp inactive innocent
};
enum PlayerEmblems {
EmblemNone = 0,
EmblemGreen,
EmblemRed,
EmblemBlue
};
enum PlayerStates {
IconNone = 0,
IconPoison = 1,
IconBurn = 2,
IconEnergy = 4,
IconDrunk = 8,
IconManaShield = 16,
IconParalyze = 32,
IconHaste = 64,
IconSwords = 128,
IconDrowning = 256,
IconFreezing = 512,
IconDazzled = 1024,
IconCursed = 2048,
IconPartyBuff = 4096,
IconPzBlock = 8192,
IconPz = 16384,
IconBleeding = 32768,
IconHungry = 65536
};
enum MessageMode {
MessageNone = 0,
MessageSay = 1,
MessageWhisper = 2,
MessageYell = 3,
MessagePrivateFrom = 4,
MessagePrivateTo = 5,
MessageChannelManagement = 6,
MessageChannel = 7,
MessageChannelHighlight = 8,
MessageSpell = 9,
MessageNpcFrom = 10,
MessageNpcTo = 11,
MessageGamemasterBroadcast = 12,
MessageGamemasterChannel = 13,
MessageGamemasterPrivateFrom = 14,
MessageGamemasterPrivateTo = 15,
MessageLogin = 16,
MessageWarning = 17,
MessageGame = 18,
MessageFailure = 19,
MessageLook = 20,
MessageDamageDealed = 21,
MessageDamageReceived = 22,
MessageHeal = 23,
MessageExp = 24,
MessageDamageOthers = 25,
MessageHealOthers = 26,
MessageExpOthers = 27,
MessageStatus = 28,
MessageLoot = 29,
MessageTradeNpc = 30,
MessageGuild = 31,
MessagePartyManagement = 32,
MessageParty = 33,
MessageBarkLow = 34,
MessageBarkLoud = 35,
MessageReport = 36,
MessageHotkeyUse = 37,
MessageTutorialHint = 38,
MessageThankyou = 39,
MessageMarket = 40,
MessageBeyondLast = 41,
// deprecated
MessageMonsterYell = 42,
MessageMonsterSay = 43,
MessageRed = 44,
MessageBlue = 45,
MessageRVRChannel = 46,
MessageRVRAnswer = 47,
MessageRVRContinue = 48,
LastMessage = 49,
MessageInvalid = 255
};
enum GameFeature {
// 1-50 defined in c++
GameProtocolChecksum = 1,
GameAccountNames = 2,
GameChallangeOnLogin = 3,
GamePenalityOnDeath = 4,
GameNameOnNpcTrade = 5,
GameDoubleFreeCapacity = 6,
GameDoubleExperience = 7,
GameTotalCapacity = 8,
GameSkillsBase = 9,
GamePlayerRegenerationTime = 10,
GameChannelPlayerList = 11,
GamePlayerMounts = 12,
GameEnvironmentEffect = 13,
GameCreatureEmblems = 14,
GameItemAnimationPhase = 15,
GameMagicEffectU16 = 16,
GamePlayerMarket = 17,
GameSpritesU32 = 18,
GameChargeableItems = 19,
GameOfflineTrainingTime = 20,
GamePurseSlot = 21,
GameFormatCreatureName = 22,
GameSpellList = 23,
GameClientPing = 24,
GameLoginPending = 25,
GameNewSpeedLaw = 26,
// 23-50 unused yet
// 51-100 reserved to be defined in lua
LastGameFeature = 101
};
enum PathFindResult {
PathFindResultOk = 0,
PathFindResultSamePosition,
PathFindResultImpossible,
PathFindResultTooFar,
PathFindResultNoWay
};
enum PathFindFlags {
PathFindAllowNullTiles = 1,
PathFindAllowCreatures = 2,
PathFindAllowNonPathable = 4,
PathFindAllowNonWalkable = 8
};
enum AutomapFlags
{
MapMarkTick = 0,
MapMarkQuestion,
MapMarkExclamation,
MapMarkStar,
MapMarkCross,
MapMarkTemple,
MapMarkKiss,
MapMarkShovel,
MapMarkSword,
MapMarkFlag,
MapMarkLock,
MapMarkBag,
MapMarkSkull,
MapMarkDollar,
MapMarkRedNorth,
MapMarkRedSouth,
MapMarkRedEast,
MapMarkRedWest,
MapMarkGreenNorth,
MapMarkGreenSouth
};
enum VipState
{
VipStateOffline = 0,
VipStateOnline = 1,
VipStatePending = 2
};
enum SpeedFormula
{
SpeedFormulaA = 0,
SpeedFormulaB,
SpeedFormulaC,
LastSpeedFormula
};
}
#endif

102
src/client/container.cpp Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "container.h"
#include "item.h"
Container::Container(int id, int capacity, const std::string& name, const ItemPtr& containerItem, bool hasParent)
{
m_id = id;
m_capacity = capacity;
m_name = name;
m_containerItem = containerItem;
m_hasParent = hasParent;
m_closed = false;
}
ItemPtr Container::getItem(int slot)
{
if(slot < 0 || slot >= (int)m_items.size())
return nullptr;
return m_items[slot];
}
void Container::onOpen(const ContainerPtr& previousContainer)
{
callLuaField("onOpen", previousContainer);
}
void Container::onClose()
{
m_closed = true;
callLuaField("onClose");
}
void Container::onAddItem(const ItemPtr& item)
{
m_items.push_front(item);
updateItemsPositions();
callLuaField("onAddItem", 0, item);
}
void Container::onAddItems(const std::vector<ItemPtr>& items)
{
for(const ItemPtr& item : items)
m_items.push_back(item);
updateItemsPositions();
}
void Container::onUpdateItem(int slot, const ItemPtr& item)
{
if(slot < 0 || slot >= (int)m_items.size()) {
g_logger.traceError("slot not found");
return;
}
ItemPtr oldItem = m_items[slot];
m_items[slot] = item;
item->setPosition(getSlotPosition(slot));
callLuaField("onUpdateItem", slot, item, oldItem);
}
void Container::onRemoveItem(int slot)
{
if(slot < 0 || slot >= (int)m_items.size()) {
g_logger.traceError("slot not found");
return;
}
ItemPtr item = m_items[slot];
m_items.erase(m_items.begin() + slot);
updateItemsPositions();
callLuaField("onRemoveItem", slot, item);
}
void Container::updateItemsPositions()
{
for(int slot = 0; slot < (int)m_items.size(); ++slot)
m_items[slot]->setPosition(getSlotPosition(slot));
}

71
src/client/container.h Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CONTAINER_H
#define CONTAINER_H
#include "declarations.h"
#include "item.h"
#include <framework/luaengine/luaobject.h>
// @bindclass
class Container : public LuaObject
{
protected:
Container(int id, int capacity, const std::string& name, const ItemPtr& containerItem, bool hasParent);
public:
ItemPtr getItem(int slot);
std::deque<ItemPtr> getItems() { return m_items; }
int getItemsCount() { return m_items.size(); }
Position getSlotPosition(int slot) { return Position(0xffff, m_id | 0x40, slot); }
int getId() { return m_id; }
int getCapacity() { return m_capacity; }
ItemPtr getContainerItem() { return m_containerItem; }
std::string getName() { return m_name; }
bool hasParent() { return m_hasParent; }
bool isClosed() { return m_closed; }
protected:
void onOpen(const ContainerPtr& previousContainer);
void onClose();
void onAddItem(const ItemPtr& item);
void onAddItems(const std::vector<ItemPtr>& items);
void onUpdateItem(int slot, const ItemPtr& item);
void onRemoveItem(int slot);
friend class Game;
private:
void updateItemsPositions();
int m_id;
int m_capacity;
ItemPtr m_containerItem;
std::string m_name;
bool m_hasParent;
bool m_closed;
std::deque<ItemPtr> m_items;
};
#endif

776
src/client/creature.cpp Normal file
View File

@@ -0,0 +1,776 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "creature.h"
#include "thingtypemanager.h"
#include "localplayer.h"
#include "map.h"
#include "tile.h"
#include "item.h"
#include "game.h"
#include "effect.h"
#include "luavaluecasts.h"
#include "lightview.h"
#include <framework/graphics/graphics.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/clock.h>
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/painterogl2_shadersources.h>
#include <framework/graphics/texturemanager.h>
#include <framework/graphics/framebuffermanager.h>
#include "spritemanager.h"
Creature::Creature() : Thing()
{
m_id = 0;
m_healthPercent = 100;
m_speed = 200;
m_direction = Otc::South;
m_walkAnimationPhase = 0;
m_walkedPixels = 0;
m_walkTurnDirection = Otc::InvalidDirection;
m_skull = Otc::SkullNone;
m_shield = Otc::ShieldNone;
m_emblem = Otc::EmblemNone;
m_lastStepDirection = Otc::InvalidDirection;
m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
m_nameCache.setAlign(Fw::AlignTopCenter);
m_footStep = 0;
m_speedFormula.fill(-1);
}
void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
{
if(!canBeSeen())
return;
Point animationOffset = animate ? m_walkOffset : Point(0,0);
if(m_showTimedSquare && animate) {
g_painter->setColor(m_timedSquareColor);
g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max((int)(2*scaleFactor), 1));
g_painter->setColor(Color::white);
}
if(m_showStaticSquare && animate) {
g_painter->setColor(m_staticSquareColor);
g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor), std::max((int)(2*scaleFactor), 1));
g_painter->setColor(Color::white);
}
internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
m_footStepDrawn = true;
if(lightView) {
Light light = rawGetThingType()->getLight();
if(m_light.intensity != light.intensity || m_light.color != light.color)
light = m_light;
// local player always have a minimum light in complete darkness
if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
light.intensity = std::max<uint8>(light.intensity, 2);
if(light.color == 0 || light.color > 215)
light.color = 215;
}
if(light.intensity > 0)
lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
}
}
void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
{
// outfit is a real creature
if(m_outfit.getCategory() == ThingCategoryCreature) {
int animationPhase = animateWalk ? m_walkAnimationPhase : 0;
if(isAnimateAlways() && animateIdle) {
int ticksPerFrame = 1000 / getAnimationPhases();
animationPhase = (g_clock.millis() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
}
// xPattern => creature direction
int xPattern;
if(direction == Otc::NorthEast || direction == Otc::SouthEast)
xPattern = Otc::East;
else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
xPattern = Otc::West;
else
xPattern = direction;
int zPattern = 0;
if(m_outfit.getMount() != 0) {
auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
dest -= datType->getDisplacement() * scaleFactor;
datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
dest += getDisplacement() * scaleFactor;
zPattern = 1;
}
// yPattern => creature addon
for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
// continue if we dont have this addon
if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
continue;
auto datType = rawGetThingType();
datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);
if(getLayers() > 1) {
Color oldColor = g_painter->getColor();
Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
g_painter->setColor(m_outfit.getHeadColor());
datType->draw(dest, scaleFactor, SpriteMaskYellow, xPattern, yPattern, zPattern, animationPhase);
g_painter->setColor(m_outfit.getBodyColor());
datType->draw(dest, scaleFactor, SpriteMaskRed, xPattern, yPattern, zPattern, animationPhase);
g_painter->setColor(m_outfit.getLegsColor());
datType->draw(dest, scaleFactor, SpriteMaskGreen, xPattern, yPattern, zPattern, animationPhase);
g_painter->setColor(m_outfit.getFeetColor());
datType->draw(dest, scaleFactor, SpriteMaskBlue, xPattern, yPattern, zPattern, animationPhase);
g_painter->setColor(oldColor);
g_painter->setCompositionMode(oldComposition);
}
}
// outfit is a creature imitating an item or the invisible effect
} else {
ThingType *type = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory());
int animationPhase = 0;
int animationPhases = type->getAnimationPhases();
int animateTicks = Otc::ITEM_TICKS_PER_FRAME;
// when creature is an effect we cant render the first and last animation phase,
// instead we should loop in the phases between
if(m_outfit.getCategory() == ThingCategoryEffect) {
animationPhases = std::max(1, animationPhases-2);
animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
}
if(animationPhases > 1) {
if(animateIdle)
animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
else
animationPhase = animationPhases-1;
}
if(m_outfit.getCategory() == ThingCategoryEffect)
animationPhase = std::min(animationPhase+1, animationPhases);
type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
}
}
void Creature::drawOutfit(const Rect& destRect, bool resize)
{
int exactSize;
if(m_outfit.getCategory() == ThingCategoryCreature)
exactSize = getExactSize();
else
exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize();
if(g_graphics.canUseFBO()) {
const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
outfitBuffer->resize(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS));
outfitBuffer->bind();
g_painter->setAlphaWriting(true);
g_painter->clear(Color::alpha);
internalDrawOutfit(Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
outfitBuffer->release();
Rect srcRect;
if(resize)
srcRect.resize(exactSize, exactSize);
else
srcRect.resize(2*Otc::TILE_PIXELS*0.75f, 2*Otc::TILE_PIXELS*0.75f);
srcRect.moveBottomRight(Point(2*Otc::TILE_PIXELS - 1, 2*Otc::TILE_PIXELS - 1));
outfitBuffer->draw(destRect, srcRect);
} else {
float scaleFactor;
if(resize)
scaleFactor = destRect.width() / (float)exactSize;
else
scaleFactor = destRect.width() / (float)(2*Otc::TILE_PIXELS*0.75f);
Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement())*scaleFactor;
internalDrawOutfit(dest, scaleFactor, false, true, Otc::South);
}
}
void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect)
{
if(m_healthPercent < 1) // creature is dead
return;
Color fillColor = Color(96, 96, 96);
if(!useGray)
fillColor = m_informationColor;
// calculate main rects
Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4);
backgroundRect.bind(parentRect);
Size nameSize = m_nameCache.getTextSize();
Rect textRect = Rect(point.x - nameSize.width() / 2.0, point.y-12, nameSize);
textRect.bind(parentRect);
// distance them
if(textRect.top() == parentRect.top())
backgroundRect.moveTop(textRect.top() + 12);
if(backgroundRect.bottom() == parentRect.bottom())
textRect.moveTop(backgroundRect.top() - 12);
// health rect is based on background rect, so no worries
Rect healthRect = backgroundRect.expanded(-1);
healthRect.setWidth((m_healthPercent / 100.0) * 25);
// draw
g_painter->setColor(Color::black);
g_painter->drawFilledRect(backgroundRect);
g_painter->setColor(fillColor);
g_painter->drawFilledRect(healthRect);
m_nameCache.draw(textRect);
if(m_skull != Otc::SkullNone && m_skullTexture) {
g_painter->setColor(Color::white);
Rect skullRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_skullTexture->getSize());
g_painter->drawTexturedRect(skullRect, m_skullTexture);
}
if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
g_painter->setColor(Color::white);
Rect shieldRect = Rect(backgroundRect.x() + 13.5, backgroundRect.y() + 5, m_shieldTexture->getSize());
g_painter->drawTexturedRect(shieldRect, m_shieldTexture);
}
if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
g_painter->setColor(Color::white);
Rect emblemRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 16, m_emblemTexture->getSize());
g_painter->drawTexturedRect(emblemRect, m_emblemTexture);
}
}
void Creature::turn(Otc::Direction direction)
{
// if is not walking change the direction right away
if(!m_walking)
setDirection(direction);
// schedules to set the new direction when walk ends
else
m_walkTurnDirection = direction;
}
void Creature::walk(const Position& oldPos, const Position& newPos)
{
if(oldPos == newPos)
return;
// get walk direction
m_lastStepDirection = oldPos.getDirectionFromPosition(newPos);
m_lastStepFromPosition = oldPos;
m_lastStepToPosition = newPos;
// set current walking direction
setDirection(m_lastStepDirection);
// starts counting walk
m_walking = true;
m_walkTimer.restart();
m_walkedPixels = 0;
// no direction need to be changed when the walk ends
m_walkTurnDirection = Otc::InvalidDirection;
// starts updating walk
nextWalkUpdate();
}
void Creature::stopWalk()
{
if(!m_walking)
return;
// reset walk animation states
m_walkOffset = Point(0,0);
m_walkAnimationPhase = 0;
// stops the walk right away
terminateWalk();
}
void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
{
callLuaField("onPositionChange", newPos, oldPos);
}
void Creature::onAppear()
{
// cancel any disappear event
if(m_disappearEvent) {
m_disappearEvent->cancel();
m_disappearEvent = nullptr;
}
// creature appeared the first time or wasn't seen for a long time
if(m_removed) {
stopWalk();
m_removed = false;
callLuaField("onAppear");
// walk
} else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1) && m_allowAppearWalk) {
m_allowAppearWalk = false;
walk(m_oldPosition, m_position);
callLuaField("onWalk", m_oldPosition, m_position);
// teleport
} else if(m_oldPosition != m_position) {
stopWalk();
callLuaField("onDisappear");
callLuaField("onAppear");
} // else turn
}
void Creature::onDisappear()
{
if(m_disappearEvent)
m_disappearEvent->cancel();
m_oldPosition = m_position;
// a pair onDisappear and onAppear events are fired even when creatures walks or turns,
// so we must filter
auto self = static_self_cast<Creature>();
m_disappearEvent = g_dispatcher.addEvent([self] {
self->m_removed = true;
self->stopWalk();
self->callLuaField("onDisappear");
// invalidate this creature position
if(!self->isLocalPlayer())
self->setPosition(Position());
self->m_oldPosition = Position();
self->m_disappearEvent = nullptr;
});
}
void Creature::updateWalkAnimation(int totalPixelsWalked)
{
// update outfit animation
if(m_outfit.getCategory() != ThingCategoryCreature)
return;
int footAnimPhases = getAnimationPhases() - 1;
if(totalPixelsWalked == 32 || footAnimPhases == 0)
m_walkAnimationPhase = 0;
else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= getStepDuration(true) / 4 ) {
m_footStep++;
m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
m_footStepDrawn = false;
m_footTimer.restart();
}
}
void Creature::updateWalkOffset(int totalPixelsWalked)
{
m_walkOffset = Point(0,0);
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
m_walkOffset.y = 32 - totalPixelsWalked;
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
m_walkOffset.y = totalPixelsWalked - 32;
if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
m_walkOffset.x = totalPixelsWalked - 32;
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
m_walkOffset.x = 32 - totalPixelsWalked;
}
void Creature::updateWalkingTile()
{
// determine new walking tile
TilePtr newWalkingTile;
Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
Otc::TILE_PIXELS, Otc::TILE_PIXELS);
for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);
// only render creatures where bottom right is inside tile rect
if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
}
}
}
if(newWalkingTile != m_walkingTile) {
if(m_walkingTile)
m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
if(newWalkingTile) {
newWalkingTile->addWalkingCreature(static_self_cast<Creature>());
// recache visible tiles in map views
if(newWalkingTile->isEmpty())
g_map.notificateTileUpdateToMapViews(newWalkingTile->getPosition());
}
m_walkingTile = newWalkingTile;
}
}
void Creature::nextWalkUpdate()
{
// remove any previous scheduled walk updates
if(m_walkUpdateEvent)
m_walkUpdateEvent->cancel();
// do the update
updateWalk();
// schedules next update
if(m_walking) {
auto self = static_self_cast<Creature>();
m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
self->m_walkUpdateEvent = nullptr;
self->nextWalkUpdate();
}, getStepDuration() / 32);
}
}
void Creature::updateWalk()
{
float walkTicksPerPixel = getStepDuration(true) / 32;
int totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
// needed for paralyze effect
m_walkedPixels = std::max(m_walkedPixels, totalPixelsWalked);
// update walk animation and offsets
updateWalkAnimation(totalPixelsWalked);
updateWalkOffset(m_walkedPixels);
updateWalkingTile();
// terminate walk
if(m_walking && m_walkTimer.ticksElapsed() >= getStepDuration())
terminateWalk();
}
void Creature::terminateWalk()
{
// remove any scheduled walk update
if(m_walkUpdateEvent) {
m_walkUpdateEvent->cancel();
m_walkUpdateEvent = nullptr;
}
// now the walk has ended, do any scheduled turn
if(m_walkTurnDirection != Otc::InvalidDirection) {
setDirection(m_walkTurnDirection);
m_walkTurnDirection = Otc::InvalidDirection;
}
if(m_walkingTile) {
m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
m_walkingTile = nullptr;
}
m_walking = false;
m_walkedPixels = 0;
}
void Creature::setName(const std::string& name)
{
m_nameCache.setText(name);
m_name = name;
}
void Creature::setHealthPercent(uint8 healthPercent)
{
m_informationColor = Color::black;
if(healthPercent > 92) {
m_informationColor.setGreen(188);
}
else if(healthPercent > 60) {
m_informationColor.setRed(80);
m_informationColor.setGreen(161);
m_informationColor.setBlue(80);
}
else if(healthPercent > 30) {
m_informationColor.setRed(161);
m_informationColor.setGreen(161);
}
else if(healthPercent > 8) {
m_informationColor.setRed(160);
m_informationColor.setGreen(39);
m_informationColor.setBlue(39);
}
else if(healthPercent > 3) {
m_informationColor.setRed(160);
}
else {
m_informationColor.setRed(79);
}
m_healthPercent = healthPercent;
callLuaField("onHealthPercentChange", healthPercent);
}
void Creature::setDirection(Otc::Direction direction)
{
assert(direction != Otc::InvalidDirection);
m_direction = direction;
}
void Creature::setOutfit(const Outfit& outfit)
{
Outfit oldOutfit = outfit;
if(outfit.getCategory() != ThingCategoryCreature) {
if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
return;
m_outfit.setAuxId(outfit.getAuxId());
m_outfit.setCategory(outfit.getCategory());
} else {
if(outfit.getId() > 0 && !g_things.isValidDatId(outfit.getId(), ThingCategoryCreature))
return;
m_outfit = outfit;
}
m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
callLuaField("onOutfitChange", m_outfit, oldOutfit);
}
void Creature::setSpeed(uint16 speed)
{
uint16 oldSpeed = m_speed;
m_speed = speed;
// speed can change while walking (utani hur, paralyze, etc..)
if(m_walking)
nextWalkUpdate();
callLuaField("onSpeedChange", m_speed, oldSpeed);
}
void Creature::setSkull(uint8 skull)
{
m_skull = skull;
callLuaField("onSkullChange", m_skull);
}
void Creature::setShield(uint8 shield)
{
m_shield = shield;
callLuaField("onShieldChange", m_shield);
}
void Creature::setEmblem(uint8 emblem)
{
m_emblem = emblem;
callLuaField("onEmblemChange", m_emblem);
}
void Creature::setSkullTexture(const std::string& filename)
{
m_skullTexture = g_textures.getTexture(filename);
}
void Creature::setShieldTexture(const std::string& filename, bool blink)
{
m_shieldTexture = g_textures.getTexture(filename);
m_showShieldTexture = true;
if(blink && !m_shieldBlink) {
auto self = static_self_cast<Creature>();
g_dispatcher.scheduleEvent([self]() {
self->updateShield();
}, SHIELD_BLINK_TICKS);
}
m_shieldBlink = blink;
}
void Creature::setEmblemTexture(const std::string& filename)
{
m_emblemTexture = g_textures.getTexture(filename);
}
void Creature::setSpeedFormula(double speedA, double speedB, double speedC)
{
m_speedFormula[Otc::SpeedFormulaA] = speedA;
m_speedFormula[Otc::SpeedFormulaB] = speedB;
m_speedFormula[Otc::SpeedFormulaC] = speedC;
}
bool Creature::hasSpeedFormula()
{
return m_speedFormula[Otc::SpeedFormulaA] != -1 && m_speedFormula[Otc::SpeedFormulaB] != -1
&& m_speedFormula[Otc::SpeedFormulaC] != -1;
}
void Creature::addTimedSquare(uint8 color)
{
m_showTimedSquare = true;
m_timedSquareColor = Color::from8bit(color);
// schedule removal
auto self = static_self_cast<Creature>();
g_dispatcher.scheduleEvent([self]() {
self->removeTimedSquare();
}, VOLATILE_SQUARE_DURATION);
}
void Creature::updateShield()
{
m_showShieldTexture = !m_showShieldTexture;
if(m_shield != Otc::ShieldNone && m_shieldBlink) {
auto self = static_self_cast<Creature>();
g_dispatcher.scheduleEvent([self]() {
self->updateShield();
}, SHIELD_BLINK_TICKS);
}
else if(!m_shieldBlink)
m_showShieldTexture = true;
}
Point Creature::getDrawOffset()
{
Point drawOffset;
if(m_walking) {
if(m_walkingTile)
drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
drawOffset += m_walkOffset;
} else {
const TilePtr& tile = getTile();
if(tile)
drawOffset -= Point(1,1) * tile->getDrawElevation();
}
return drawOffset;
}
int Creature::getStepDuration(bool ignoreDiagonal)
{
int speed = m_speed;
if(speed < 1)
return 0;
if(g_game.getFeature(Otc::GameNewSpeedLaw))
speed *= 2;
int groundSpeed = 0;
Position tilePos = m_lastStepToPosition;
if(!tilePos.isValid())
tilePos = m_position;
const TilePtr& tile = g_map.getTile(tilePos);
if(tile) {
groundSpeed = tile->getGroundSpeed();
if(groundSpeed == 0)
groundSpeed = 150;
}
int interval = 1000;
if(groundSpeed > 0 && speed > 0)
interval = 1000 * groundSpeed;
if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
int formulatedSpeed = 1;
if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
formulatedSpeed = std::max(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
+ m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
}
interval = std::floor(interval / (double)formulatedSpeed);
}
else
interval /= speed;
if(g_game.getProtocolVersion() >= 900)
interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();
interval = std::max(interval, g_game.getServerBeat());
if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
interval *= 3;
return interval;
}
Point Creature::getDisplacement()
{
if(m_outfit.getCategory() == ThingCategoryEffect)
return Point(8, 8);
else if(m_outfit.getCategory() == ThingCategoryItem)
return Point(0, 0);
return Thing::getDisplacement();
}
int Creature::getDisplacementX()
{
if(m_outfit.getCategory() == ThingCategoryEffect)
return 8;
else if(m_outfit.getCategory() == ThingCategoryItem)
return 0;
return Thing::getDisplacementX();
}
int Creature::getDisplacementY()
{
if(m_outfit.getCategory() == ThingCategoryEffect)
return 8;
else if(m_outfit.getCategory() == ThingCategoryItem)
return 0;
return Thing::getDisplacementY();
}
int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
{
int exactSize = 0;
animationPhase = 0;
xPattern = Otc::South;
zPattern = 0;
if(m_outfit.getMount() != 0)
zPattern = 1;
for(yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
continue;
for(layer = 0; layer < getLayers(); ++layer)
exactSize = std::max(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
}
return exactSize;
}
const ThingTypePtr& Creature::getThingType()
{
return g_things.getThingType(m_outfit.getId(), ThingCategoryCreature);
}
ThingType* Creature::rawGetThingType()
{
return g_things.rawGetThingType(m_outfit.getId(), ThingCategoryCreature);
}

192
src/client/creature.h Normal file
View File

@@ -0,0 +1,192 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CREATURE_H
#define CREATURE_H
#include "thing.h"
#include "outfit.h"
#include "tile.h"
#include "mapview.h"
#include <framework/core/scheduledevent.h>
#include <framework/core/declarations.h>
#include <framework/core/timer.h>
#include <framework/graphics/fontmanager.h>
#include <framework/graphics/cachedtext.h>
// @bindclass
class Creature : public Thing
{
public:
enum {
SHIELD_BLINK_TICKS = 500,
VOLATILE_SQUARE_DURATION = 1000
};
Creature();
virtual void draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView = nullptr);
void internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView = nullptr);
void drawOutfit(const Rect& destRect, bool resize);
void drawInformation(const Point& point, bool useGray, const Rect& parentRect);
void setId(uint32 id) { m_id = id; }
void setName(const std::string& name);
void setHealthPercent(uint8 healthPercent);
void setDirection(Otc::Direction direction);
void setOutfit(const Outfit& outfit);
void setLight(const Light& light) { m_light = light; }
void setSpeed(uint16 speed);
void setSkull(uint8 skull);
void setShield(uint8 shield);
void setEmblem(uint8 emblem);
void setSkullTexture(const std::string& filename);
void setShieldTexture(const std::string& filename, bool blink);
void setEmblemTexture(const std::string& filename);
void setPassable(bool passable) { m_passable = passable; }
void setSpeedFormula(double speedA, double speedB, double speedC);
void addTimedSquare(uint8 color);
void removeTimedSquare() { m_showTimedSquare = false; }
void showStaticSquare(const Color& color) { m_showStaticSquare = true; m_staticSquareColor = color; }
void hideStaticSquare() { m_showStaticSquare = false; }
uint32 getId() { return m_id; }
std::string getName() { return m_name; }
uint8 getHealthPercent() { return m_healthPercent; }
Otc::Direction getDirection() { return m_direction; }
Outfit getOutfit() { return m_outfit; }
Light getLight() { return m_light; }
uint16 getSpeed() { return m_speed; }
uint8 getSkull() { return m_skull; }
uint8 getShield() { return m_shield; }
uint8 getEmblem() { return m_emblem; }
bool isPassable() { return m_passable; }
Point getDrawOffset();
int getStepDuration(bool ignoreDiagonal = false);
Point getWalkOffset() { return m_walkOffset; }
Position getLastStepFromPosition() { return m_lastStepFromPosition; }
Position getLastStepToPosition() { return m_lastStepToPosition; }
float getStepProgress() { return m_walkTimer.ticksElapsed() / getStepDuration(); }
float getStepTicksLeft() { return getStepDuration() - m_walkTimer.ticksElapsed(); }
ticks_t getWalkTicksElapsed() { return m_walkTimer.ticksElapsed(); }
double getSpeedFormula(Otc::SpeedFormula formula) { return m_speedFormula[formula]; }
bool hasSpeedFormula();
std::array<double, Otc::LastSpeedFormula> getSpeedFormulaArray() { return m_speedFormula; }
virtual Point getDisplacement();
virtual int getDisplacementX();
virtual int getDisplacementY();
virtual int getExactSize(int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animationPhase = 0);
void updateShield();
// walk related
void turn(Otc::Direction direction);
virtual void walk(const Position& oldPos, const Position& newPos);
virtual void stopWalk();
void allowAppearWalk() { m_allowAppearWalk = true; }
bool isWalking() { return m_walking; }
bool isRemoved() { return m_removed; }
bool isInvisible() { return m_outfit.getCategory() == ThingCategoryEffect && m_outfit.getAuxId() == 13; }
bool canBeSeen() { return !isInvisible() || isPlayer(); }
bool isCreature() { return true; }
const ThingTypePtr& getThingType();
ThingType *rawGetThingType();
virtual void onPositionChange(const Position& newPos, const Position& oldPos);
virtual void onAppear();
virtual void onDisappear();
protected:
virtual void updateWalkAnimation(int totalPixelsWalked);
virtual void updateWalkOffset(int totalPixelsWalked);
void updateWalkingTile();
virtual void nextWalkUpdate();
virtual void updateWalk();
virtual void terminateWalk();
uint32 m_id;
std::string m_name;
uint8 m_healthPercent;
Otc::Direction m_direction;
Outfit m_outfit;
Light m_light;
int m_speed;
uint8 m_skull;
uint8 m_shield;
uint8 m_emblem;
TexturePtr m_skullTexture;
TexturePtr m_shieldTexture;
TexturePtr m_emblemTexture;
stdext::boolean<true> m_showShieldTexture;
stdext::boolean<false> m_shieldBlink;
stdext::boolean<false> m_passable;
Color m_timedSquareColor;
Color m_staticSquareColor;
stdext::boolean<false> m_showTimedSquare;
stdext::boolean<false> m_showStaticSquare;
stdext::boolean<true> m_removed;
CachedText m_nameCache;
Color m_informationColor;
std::array<double, Otc::LastSpeedFormula> m_speedFormula;
// walk related
int m_walkAnimationPhase;
int m_walkedPixels;
uint m_footStep;
Timer m_walkTimer;
Timer m_footTimer;
TilePtr m_walkingTile;
stdext::boolean<false> m_walking;
stdext::boolean<false> m_allowAppearWalk;
stdext::boolean<false> m_footStepDrawn;
ScheduledEventPtr m_walkUpdateEvent;
EventPtr m_disappearEvent;
Point m_walkOffset;
Otc::Direction m_walkTurnDirection;
Otc::Direction m_lastStepDirection;
Position m_lastStepFromPosition;
Position m_lastStepToPosition;
Position m_oldPosition;
};
// @bindclass
class Npc : public Creature
{
public:
bool isNpc() { return true; }
};
// @bindclass
class Monster : public Creature
{
public:
bool isMonster() { return true; }
};
#endif

371
src/client/creatures.cpp Normal file
View File

@@ -0,0 +1,371 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "creatures.h"
#include "creature.h"
#include "map.h"
#include <framework/xml/tinyxml.h>
#include <framework/core/resourcemanager.h>
#include <boost/filesystem.hpp>
CreatureManager g_creatures;
static bool isInZone(const Position& pos/* placePos*/,
const Position& centerPos,
int radius)
{
if(radius == -1)
return true;
return ((pos.x >= centerPos.x - radius) && (pos.x <= centerPos.x + radius) &&
(pos.y >= centerPos.y - radius) && (pos.y <= centerPos.y + radius)
);
}
void CreatureManager::terminate()
{
clearSpawns();
clear();
m_nullCreature = nullptr;
}
void Spawn::load(TiXmlElement* node)
{
Position centerPos = node->readPos("center");
setCenterPos(centerPos);
setRadius(node->readType<int32>("radius"));
CreatureTypePtr cType(nullptr);
for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) {
if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc")
stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr()));
std::string cName = cNode->Attribute("name");
stdext::tolower(cName);
stdext::trim(cName);
if (!(cType = g_creatures.getCreatureByName(cName)))
continue;
cType->setSpawnTime(cNode->readType<int>("spawntime"));
Otc::Direction dir = Otc::North;
int16 dir_ = cNode->readType<int16>("direction");
if(dir_ >= Otc::East && dir_ <= Otc::West)
dir = (Otc::Direction)dir_;
cType->setDirection(dir);
centerPos.x += cNode->readType<int>("x");
centerPos.y += cNode->readType<int>("y");
centerPos.z = cNode->readType<int>("z");
addCreature(centerPos, cType);
}
}
void Spawn::save(TiXmlElement*& node)
{
node = new TiXmlElement("spawn");
const Position& c = getCenterPos();
node->SetAttribute("centerx", c.x);
node->SetAttribute("centery", c.y);
node->SetAttribute("centerz", c.z);
node->SetAttribute("radius", getRadius());
TiXmlElement* creatureNode = nullptr;
for(const auto& pair : m_creatures) {
if(!(creatureNode = new TiXmlElement("monster")))
stdext::throw_exception("oom?");
const CreatureTypePtr& creature = pair.second;
creatureNode->SetAttribute("name", creature->getName());
creatureNode->SetAttribute("spawntime", creature->getSpawnTime());
creatureNode->SetAttribute("direction", creature->getDirection());
const Position& placePos = pair.first;
assert(placePos.isValid());
creatureNode->SetAttribute("x", placePos.x);
creatureNode->SetAttribute("y", placePos.y);
creatureNode->SetAttribute("z", placePos.z);
node->LinkEndChild(creatureNode);
}
}
void Spawn::addCreature(const Position& placePos, const CreatureTypePtr& cType)
{
const Position& centerPos = getCenterPos();
int m_radius = getRadius();
if(!isInZone(placePos, centerPos, m_radius))
stdext::throw_exception(stdext::format("cannot place creature at %s %s %d (increment radius)",
stdext::to_string(placePos), stdext::to_string(centerPos),
m_radius
));
g_map.addThing(cType->cast(), placePos, 4);
m_creatures.insert(std::make_pair(placePos, cType));
}
void Spawn::removeCreature(const Position& pos)
{
auto iterator = m_creatures.find(pos);
if(iterator != m_creatures.end()) {
assert(iterator->first.isValid());
assert(g_map.removeThingByPos(iterator->first, 4));
m_creatures.erase(iterator);
}
}
CreaturePtr CreatureType::cast()
{
CreaturePtr ret(new Creature);
std::string cName = getName();
stdext::ucwords(cName);
ret->setName(cName);
ret->setDirection(getDirection());
ret->setOutfit(getOutfit());
return ret;
}
CreatureManager::CreatureManager()
{
m_nullCreature = CreatureTypePtr(new CreatureType);
}
void CreatureManager::clearSpawns()
{
for(auto pair : m_spawns)
pair.second->clear();
m_spawns.clear();
}
void CreatureManager::loadMonsters(const std::string& file)
{
TiXmlDocument doc;
doc.Parse(g_resources.loadFile(file).c_str());
if(doc.Error())
stdext::throw_exception(stdext::format("cannot open monsters file '%s': '%s'", file, doc.ErrorDesc()));
TiXmlElement* root = doc.FirstChildElement();
if(!root || root->ValueStr() != "monsters")
stdext::throw_exception("malformed monsters xml file");
for(TiXmlElement* monster = root->FirstChildElement(); monster; monster = monster->NextSiblingElement()) {
std::string fname = file.substr(0, file.find_last_of('/')) + '/' + monster->Attribute("file");
if(fname.substr(fname.length() - 4) != ".xml")
fname += ".xml";
loadSingleCreature(fname);
}
doc.Clear();
m_loaded = true;
}
void CreatureManager::loadSingleCreature(const std::string& file)
{
loadCreatureBuffer(g_resources.loadFile(file));
}
void CreatureManager::loadNpcs(const std::string& folder)
{
std::string tmp = folder;
if(!stdext::ends_with(tmp, "/"))
tmp += "/";
boost::filesystem::path npcPath(boost::filesystem::current_path().generic_string() + tmp);
if(!boost::filesystem::exists(npcPath))
stdext::throw_exception(stdext::format("NPCs folder '%s' was not found.", folder));
for(boost::filesystem::directory_iterator it(npcPath), end; it != end; ++it) {
std::string f = it->path().filename().string();
if(boost::filesystem::is_directory(it->status()))
continue;
loadCreatureBuffer(g_resources.loadFile(tmp + f));
}
}
void CreatureManager::loadSpawns(const std::string& fileName)
{
if(!isLoaded()) {
g_logger.warning("creatures aren't loaded yet to load spawns.");
return;
}
if(m_spawnLoaded) {
g_logger.warning("attempt to reload spawns.");
return;
}
TiXmlDocument doc;
doc.Parse(g_resources.loadFile(fileName).c_str());
if(doc.Error())
stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc()));
TiXmlElement* root = doc.FirstChildElement();
if(!root || root->ValueStr() != "spawns")
stdext::throw_exception("malformed spawns file");
for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) {
if(node->ValueTStr() != "spawn")
stdext::throw_exception("invalid spawn node");
SpawnPtr spawn(new Spawn);
spawn->load(node);
m_spawns.insert(std::make_pair(spawn->getCenterPos(), spawn));
}
doc.Clear();
m_spawnLoaded = true;
}
void CreatureManager::saveSpawns(const std::string& fileName)
{
TiXmlDocument doc;
doc.SetTabSize(2);
TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "");
doc.LinkEndChild(decl);
TiXmlElement* root = new TiXmlElement("spawns");
doc.LinkEndChild(root);
for(auto pair : m_spawns) {
TiXmlElement* elem;
pair.second->save(elem);
root->LinkEndChild(elem);
}
if(!doc.SaveFile(fileName))
stdext::throw_exception(stdext::format("failed to save spawns XML %s: %s", fileName, doc.ErrorDesc()));
}
void CreatureManager::loadCreatureBuffer(const std::string& buffer)
{
TiXmlDocument doc;
doc.Parse(buffer.c_str());
if(doc.Error())
stdext::throw_exception(stdext::format("cannot load creature buffer: %s", doc.ErrorDesc()));
TiXmlElement* root = doc.FirstChildElement();
if(!root || (root->ValueStr() != "monster" && root->ValueStr() != "npc"))
stdext::throw_exception("invalid root tag name");
std::string cName = root->Attribute("name");
stdext::tolower(cName);
stdext::trim(cName);
CreatureTypePtr newType(new CreatureType(cName));
for(TiXmlElement* attrib = root->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
if(attrib->ValueStr() != "look")
continue;
internalLoadCreatureBuffer(attrib, newType);
break;
}
doc.Clear();
}
void CreatureManager::internalLoadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr& m)
{
if(std::find(m_creatures.begin(), m_creatures.end(), m) != m_creatures.end())
return;
Outfit out;
int32 type = attrib->readType<int32>("type");
if(type > 0) {
out.setCategory(ThingCategoryCreature);
out.setId(type);
} else {
out.setCategory(ThingCategoryItem);
out.setAuxId(attrib->readType<int32>("typeex"));
}
{
out.setHead(attrib->readType<int>(("head")));
out.setBody(attrib->readType<int>(("body")));
out.setLegs(attrib->readType<int>(("legs")));
out.setFeet(attrib->readType<int>(("feet")));
out.setAddons(attrib->readType<int>(("addons")));
out.setMount(attrib->readType<int>(("mount")));
}
m->setOutfit(out);
m_creatures.push_back(m);
}
const CreatureTypePtr& CreatureManager::getCreatureByName(std::string name)
{
stdext::tolower(name);
stdext::trim(name);
auto it = std::find_if(m_creatures.begin(), m_creatures.end(),
[=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; });
if(it != m_creatures.end())
return *it;
g_logger.warning(stdext::format("could not find creature with name: %s", name));
return m_nullCreature;
}
const CreatureTypePtr& CreatureManager::getCreatureByLook(int look)
{
auto findFun = [=] (const CreatureTypePtr& c) -> bool
{
const Outfit& o = c->getOutfit();
return o.getId() == look || o.getAuxId() == look;
};
auto it = std::find_if(m_creatures.begin(), m_creatures.end(), findFun);
if(it != m_creatures.end())
return *it;
g_logger.warning(stdext::format("could not find creature with looktype: %d", look));
return m_nullCreature;
}
SpawnPtr CreatureManager::getSpawn(const Position& centerPos)
{
auto it = m_spawns.find(centerPos);
if(it != m_spawns.end())
return it->second;
g_logger.debug(stdext::format("failed to find spawn at center %s",stdext::to_string(centerPos)));
return nullptr;
}
SpawnPtr CreatureManager::addSpawn(const Position& centerPos, int radius)
{
auto iter = m_spawns.find(centerPos);
if(iter != m_spawns.end())
return iter->second;
SpawnPtr ret(new Spawn);
ret->setRadius(radius);
ret->setCenterPos(centerPos);
m_spawns.insert(std::make_pair(centerPos, ret));
return ret;
}

134
src/client/creatures.h Normal file
View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CREATURES_H
#define CREATURES_H
#include "declarations.h"
#include <framework/luaengine/luaobject.h>
#include "outfit.h"
enum CreatureAttr : uint8
{
CreatureAttrPosition = 0,
CreatureAttrName = 1,
CreatureAttrOutfit = 2,
CreatureAttrSpawnTime = 3,
CreatureAttrDir = 4
};
enum SpawnAttr : uint8
{
SpawnAttrRadius = 0,
SpawnAttrCenter = 1,
SpawnAttrPos = 2
};
class Spawn : public LuaObject
{
public:
Spawn() = default;
Spawn(int32 radius) { setRadius(radius); }
void setRadius(int32 r) { m_attribs.set(SpawnAttrRadius, r) ;}
int32 getRadius() { return m_attribs.get<int32>(SpawnAttrRadius); }
void setCenterPos(const Position& pos) { m_attribs.set(SpawnAttrCenter, pos); }
Position getCenterPos() { return m_attribs.get<Position>(SpawnAttrPos); }
void addCreature(const Position& placePos, const CreatureTypePtr& cType);
void removeCreature(const Position& pos);
void clear() { m_creatures.clear(); }
protected:
void load(TiXmlElement* node);
void save(TiXmlElement*& node);
private:
stdext::dynamic_storage<uint8> m_attribs;
std::unordered_map<Position, CreatureTypePtr, PositionHasher> m_creatures;
friend class CreatureManager;
};
class CreatureType : public LuaObject
{
public:
CreatureType() = default;
CreatureType(const std::string& name) { setName(name); }
void setSpawnTime(int32 spawnTime) { m_attribs.set(CreatureAttrSpawnTime, spawnTime); }
int32 getSpawnTime() { return m_attribs.get<int32>(CreatureAttrSpawnTime); }
void setName(const std::string& name) { m_attribs.set(CreatureAttrName, name); }
std::string getName() { return m_attribs.get<std::string>(CreatureAttrName); }
void setOutfit(const Outfit& o) { m_attribs.set(CreatureAttrOutfit, o); }
Outfit getOutfit() { return m_attribs.get<Outfit>(CreatureAttrOutfit); }
void setDirection(Otc::Direction dir) { m_attribs.set(CreatureAttrDir, dir); }
Otc::Direction getDirection() { return m_attribs.get<Otc::Direction>(CreatureAttrDir); }
CreaturePtr cast();
private:
stdext::dynamic_storage<uint8> m_attribs;
};
class CreatureManager
{
public:
CreatureManager();
void clear() { m_creatures.clear(); }
void clearSpawns();
void terminate();
void loadMonsters(const std::string& file);
void loadSingleCreature(const std::string& file);
void loadNpcs(const std::string& folder);
void loadCreatureBuffer(const std::string& buffer);
void loadSpawns(const std::string& fileName);
void saveSpawns(const std::string& fileName);
const CreatureTypePtr& getCreatureByName(std::string name);
const CreatureTypePtr& getCreatureByLook(int look);
SpawnPtr getSpawn(const Position& centerPos);
SpawnPtr addSpawn(const Position& centerPos, int radius);
bool isLoaded() { return m_loaded; }
bool isSpawnLoaded() { return m_spawnLoaded; }
const std::vector<CreatureTypePtr>& getCreatures() { return m_creatures; }
protected:
void internalLoadCreatureBuffer(TiXmlElement* elem, const CreatureTypePtr& m);
private:
std::vector<CreatureTypePtr> m_creatures;
std::unordered_map<Position, SpawnPtr, PositionHasher> m_spawns;
stdext::boolean<false> m_loaded, m_spawnLoaded;
CreatureTypePtr m_nullCreature;
};
extern CreatureManager g_creatures;
#endif

102
src/client/declarations.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef OTCLIENT_DECLARATIONS_H
#define OTCLIENT_DECLARATIONS_H
#include "global.h"
#include <framework/net/declarations.h>
#include <framework/ui/declarations.h>
// core
class Map;
class Game;
class MapView;
class LightView;
class Tile;
class Thing;
class Item;
class Container;
class Creature;
class Monster;
class Npc;
class Player;
class LocalPlayer;
class Effect;
class Missile;
class AnimatedText;
class StaticText;
class ThingType;
class ItemType;
class House;
class Town;
class CreatureType;
class Spawn;
typedef stdext::shared_object_ptr<MapView> MapViewPtr;
typedef stdext::shared_object_ptr<LightView> LightViewPtr;
typedef stdext::shared_object_ptr<Tile> TilePtr;
typedef stdext::shared_object_ptr<Thing> ThingPtr;
typedef stdext::shared_object_ptr<Item> ItemPtr;
typedef stdext::shared_object_ptr<Container> ContainerPtr;
typedef stdext::shared_object_ptr<Creature> CreaturePtr;
typedef stdext::shared_object_ptr<Monster> MonsterPtr;
typedef stdext::shared_object_ptr<Npc> NpcPtr;
typedef stdext::shared_object_ptr<Player> PlayerPtr;
typedef stdext::shared_object_ptr<LocalPlayer> LocalPlayerPtr;
typedef stdext::shared_object_ptr<Effect> EffectPtr;
typedef stdext::shared_object_ptr<Missile> MissilePtr;
typedef stdext::shared_object_ptr<AnimatedText> AnimatedTextPtr;
typedef stdext::shared_object_ptr<StaticText> StaticTextPtr;
typedef stdext::shared_object_ptr<ThingType> ThingTypePtr;
typedef stdext::shared_object_ptr<ItemType> ItemTypePtr;
typedef stdext::shared_object_ptr<House> HousePtr;
typedef stdext::shared_object_ptr<Town> TownPtr;
typedef stdext::shared_object_ptr<CreatureType> CreatureTypePtr;
typedef stdext::shared_object_ptr<Spawn> SpawnPtr;
typedef std::vector<ThingPtr> ThingList;
typedef std::vector<ThingTypePtr> ThingTypeList;
typedef std::vector<ItemTypePtr> ItemTypeList;
typedef std::vector<HousePtr> HouseList;
typedef std::vector<TownPtr> TownList;
typedef std::unordered_map<Position, TilePtr, PositionHasher> TileMap;
// net
class ProtocolLogin;
class ProtocolGame;
typedef stdext::shared_object_ptr<ProtocolGame> ProtocolGamePtr;
typedef stdext::shared_object_ptr<ProtocolLogin> ProtocolLoginPtr;
// ui
class UIItem;
class UICreature;
class UIMap;
class UIProgressRect;
typedef stdext::shared_object_ptr<UIItem> UIItemPtr;
typedef stdext::shared_object_ptr<UICreature> UICreaturePtr;
typedef stdext::shared_object_ptr<UIMap> UIMapPtr;
typedef stdext::shared_object_ptr<UIProgressRect> UIProgressRectPtr;
#endif

67
src/client/effect.cpp Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "effect.h"
#include "map.h"
#include <framework/core/eventdispatcher.h>
void Effect::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
{
if(m_id == 0)
return;
int animationPhase = 0;
if(animate)
animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / m_phaseDuration), getAnimationPhases() - 1);
rawGetThingType()->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
}
void Effect::onAppear()
{
m_animationTimer.restart();
m_phaseDuration = EFFECT_TICKS_PER_FRAME;
// hack to fix some animation phases duration, currently there is no better solution
if(m_id == 33)
m_phaseDuration <<= 2;
// schedule removal
auto self = asEffect();
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, m_phaseDuration * getAnimationPhases());
}
void Effect::setId(uint32 id)
{
if(!g_things.isValidDatId(id, ThingCategoryEffect))
id = 0;
m_id = id;
}
const ThingTypePtr& Effect::getThingType()
{
return g_things.getThingType(m_id, ThingCategoryEffect);
}
ThingType *Effect::rawGetThingType()
{
return g_things.rawGetThingType(m_id, ThingCategoryEffect);
}

58
src/client/effect.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef EFFECT_H
#define EFFECT_H
#include <framework/global.h>
#include <framework/core/timer.h>
#include "thing.h"
// @bindclass
class Effect : public Thing
{
enum {
EFFECT_TICKS_PER_FRAME = 75
};
public:
void draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView = nullptr);
void setId(uint32 id);
uint32 getId() { return m_id; }
EffectPtr asEffect() { return static_self_cast<Effect>(); }
bool isEffect() { return true; }
const ThingTypePtr& getThingType();
ThingType *rawGetThingType();
protected:
void onAppear();
private:
Timer m_animationTimer;
uint m_phaseDuration;
uint16 m_id;
};
#endif

1365
src/client/game.cpp Normal file

File diff suppressed because it is too large Load Diff

326
src/client/game.h Normal file
View File

@@ -0,0 +1,326 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef GAME_H
#define GAME_H
#include "declarations.h"
#include "item.h"
#include "animatedtext.h"
#include "effect.h"
#include "creature.h"
#include "container.h"
#include "protocolgame.h"
#include "localplayer.h"
#include "outfit.h"
#include <framework/core/timer.h>
#include <bitset>
typedef std::tuple<std::string, uint> Vip;
//@bindsingleton g_game
class Game
{
public:
Game();
void init();
void terminate();
private:
void resetGameStates();
protected:
void processConnectionError(const boost::system::error_code& error);
void processDisconnect();
void processPing();
void processPingBack(int elapsed);
void processLoginError(const std::string& error);
void processLoginAdvice(const std::string& message);
void processLoginWait(const std::string& message, int time);
void processPendingGame();
void processEnterGame();
void processGameStart();
void processGameEnd();
void processDeath(int penality);
void processGMActions(const std::vector<uint8>& actions);
void processInventoryChange(int slot, const ItemPtr& item);
void processAttackCancel(uint seq);
void processWalkCancel(Otc::Direction direction);
// message related
void processTextMessage(Otc::MessageMode mode, const std::string& text);
void processTalk(const std::string& name, int level, Otc::MessageMode mode, const std::string& text, int channelId, const Position& pos);
// container related
void processOpenContainer(int containerId, const ItemPtr& containerItem, const std::string& name, int capacity, bool hasParent, const std::vector<ItemPtr>& items);
void processCloseContainer(int containerId);
void processContainerAddItem(int containerId, const ItemPtr& item);
void processContainerUpdateItem(int containerId, int slot, const ItemPtr& item);
void processContainerRemoveItem(int containerId, int slot);
// channel related
void processChannelList(const std::vector<std::tuple<int, std::string> >& channelList);
void processOpenChannel(int channelId, const std::string& name);
void processOpenPrivateChannel(const std::string& name);
void processOpenOwnPrivateChannel(int channelId, const std::string& name);
void processCloseChannel(int channelId);
// rule violations
void processRuleViolationChannel(int channelId);
void processRuleViolationRemove(const std::string& name);
void processRuleViolationCancel(const std::string& name);
void processRuleViolationLock();
// vip related
void processVipAdd(uint id, const std::string& name, uint status);
void processVipStateChange(uint id, uint status);
// tutorial hint
void processTutorialHint(int id);
void processAutomapFlag(const Position& pos, int icon, const std::string& message);
// outfit
void processOpenOutfitWindow(const Outfit& currentOufit, const std::vector<std::tuple<int, std::string, int> >& outfitList,
const std::vector<std::tuple<int, std::string> >& mountList);
// npc trade
void processOpenNpcTrade(const std::vector<std::tuple<ItemPtr, std::string, int, int, int> >& items);
void processPlayerGoods(int money, const std::vector<std::tuple<ItemPtr, int> >& goods);
void processCloseNpcTrade();
// player trade
void processOwnTrade(const std::string& name, const std::vector<ItemPtr>& items);
void processCounterTrade(const std::string& name, const std::vector<ItemPtr>& items);
void processCloseTrade();
// edit text/list
void processEditText(uint id, int itemId, int maxLength, const std::string& text, const std::string& writter, const std::string& date);
void processEditList(uint id, int doorId, const std::string& text);
// questlog
void processQuestLog(const std::vector<std::tuple<int, std::string, bool> >& questList);
void processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string> >& questMissions);
// modal dialogs >= 970
void processModalDialog(uint32 id, std::string title, std::string message, int enterId, std::string enterText, int escapeId, std::string escapeText, std::vector<std::tuple<int, std::string> > choiceList);
friend class ProtocolGame;
friend class Map;
public:
// login related
void loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName);
void cancelLogin();
void forceLogout();
void safeLogout();
// walk related
bool walk(Otc::Direction direction);
void autoWalk(std::vector<Otc::Direction> dirs);
void forceWalk(Otc::Direction direction);
void turn(Otc::Direction direction);
void stop();
// item related
void look(const ThingPtr& thing);
void move(const ThingPtr &thing, const Position& toPos, int count);
void moveToParentContainer(const ThingPtr& thing, int count);
void rotate(const ThingPtr& thing);
void use(const ThingPtr& thing);
void useWith(const ItemPtr& fromThing, const ThingPtr& toThing);
void useInventoryItem(int itemId);
void useInventoryItemWith(int itemId, const ThingPtr& toThing);
// container related
void open(const ItemPtr& item, const ContainerPtr& previousContainer);
void openParent(const ContainerPtr& container);
void close(const ContainerPtr& container);
void refreshContainer(const ContainerPtr& container);
// attack/follow related
void attack(CreaturePtr creature);
void cancelAttack() { attack(nullptr); }
void follow(CreaturePtr creature);
void cancelFollow() { follow(nullptr); }
void cancelAttackAndFollow();
// talk related
void talk(const std::string& message);
void talkChannel(Otc::MessageMode mode, int channelId, const std::string& message);
void talkPrivate(Otc::MessageMode mode, const std::string& receiver, const std::string& message);
// channel related
void openPrivateChannel(const std::string& receiver);
void requestChannels();
void joinChannel(int channelId);
void leaveChannel(int channelId);
void closeNpcChannel();
void openOwnChannel();
void inviteToOwnChannel(const std::string& name);
void excludeFromOwnChannel(const std::string& name);
// party related
void partyInvite(int creatureId);
void partyJoin(int creatureId);
void partyRevokeInvitation(int creatureId);
void partyPassLeadership(int creatureId);
void partyLeave();
void partyShareExperience(bool active);
// outfit related
void requestOutfit();
void changeOutfit(const Outfit& outfit);
// vip related
void addVip(const std::string& name);
void removeVip(int playerId);
// fight modes related
void setChaseMode(Otc::ChaseModes chaseMode);
void setFightMode(Otc::FightModes fightMode);
void setSafeFight(bool on);
Otc::ChaseModes getChaseMode() { return m_chaseMode; }
Otc::FightModes getFightMode() { return m_fightMode; }
bool isSafeFight() { return m_safeFight; }
// npc trade related
void inspectNpcTrade(const ItemPtr& item);
void buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack);
void sellItem(const ItemPtr& item, int amount, bool ignoreEquipped);
void closeNpcTrade();
// player trade related
void requestTrade(const ItemPtr& item, const CreaturePtr& creature);
void inspectTrade(bool counterOffer, int index);
void acceptTrade();
void rejectTrade();
// house window and editable items related
void editText(uint id, const std::string& text);
void editList(uint id, int doorId, const std::string& text);
// reports
void reportBug(const std::string& comment);
void reportRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment);
void debugReport(const std::string& a, const std::string& b, const std::string& c, const std::string& d);
// questlog related
void requestQuestLog();
void requestQuestLine(int questId);
// 870 only
void equipItem(const ItemPtr& item);
void mount(bool mount);
// 910 only
void requestItemInfo(const ItemPtr& item, int index);
// >= 970 modal dialog
void answerModalDialog(int dialog, int button, int choice);
//void reportRuleViolation2();
void ping();
// dynamic support for game features
void enableFeature(Otc::GameFeature feature) { m_features.set(feature, true); }
void disableFeature(Otc::GameFeature feature) { m_features.set(feature, false); }
void setFeature(Otc::GameFeature feature, bool enabled) { m_features.set(feature, enabled); }
bool getFeature(Otc::GameFeature feature) { return m_features.test(feature); }
void setProtocolVersion(int version);
int getProtocolVersion() { return m_protocolVersion; }
void setClientVersion(int version);
int getClientVersion() { return m_clientVersion; }
bool canPerformGameAction();
bool checkBotProtection();
bool isOnline() { return m_online; }
bool isDead() { return m_dead; }
bool isAttacking() { return !!m_attackingCreature; }
bool isFollowing() { return !!m_followingCreature; }
int getPing() { return m_ping; }
ContainerPtr getContainer(int index) { return m_containers[index]; }
std::map<int, ContainerPtr> getContainers() { return m_containers; }
std::map<int, Vip> getVips() { return m_vips; }
CreaturePtr getAttackingCreature() { return m_attackingCreature; }
CreaturePtr getFollowingCreature() { return m_followingCreature; }
void setServerBeat(int beat) { m_serverBeat = beat; }
int getServerBeat() { return m_serverBeat; }
void setCanReportBugs(bool enable) { m_canReportBugs = enable; }
bool canReportBugs() { return m_canReportBugs; }
LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
std::string getCharacterName() { return m_characterName; }
std::string getWorldName() { return m_worldName; }
std::vector<uint8> getGMActions() { return m_gmActions; }
std::string formatCreatureName(const std::string &name);
int findEmptyContainerId();
protected:
void enableBotCall() { m_denyBotCall = false; }
void disableBotCall() { m_denyBotCall = true; }
private:
void setAttackingCreature(const CreaturePtr& creature);
void setFollowingCreature(const CreaturePtr& creature);
LocalPlayerPtr m_localPlayer;
CreaturePtr m_attackingCreature;
CreaturePtr m_followingCreature;
ProtocolGamePtr m_protocolGame;
std::map<int, ContainerPtr> m_containers;
std::map<int, Vip> m_vips;
bool m_online;
bool m_denyBotCall;
bool m_dead;
int m_serverBeat;
int m_ping;
uint m_seq;
Otc::FightModes m_fightMode;
Otc::ChaseModes m_chaseMode;
Otc::Direction m_lastWalkDir;
bool m_safeFight;
bool m_canReportBugs;
std::vector<uint8> m_gmActions;
std::string m_characterName;
std::string m_worldName;
std::bitset<Otc::LastGameFeature> m_features;
ScheduledEventPtr m_pingEvent;
ScheduledEventPtr m_walkEvent;
int m_protocolVersion;
int m_clientVersion;
};
extern Game g_game;
#endif

32
src/client/global.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef OTCLIENT_GLOBAL_H
#define OTCLIENT_GLOBAL_H
#include <framework/global.h>
// widely used headers
#include "const.h"
#include "position.h"
#endif

163
src/client/houses.cpp Normal file
View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "map.h"
#include <framework/core/resourcemanager.h>
HouseManager g_houses;
House::House()
{
m_nullTile = TilePtr(new Tile(Position()));
}
House::House(uint32 hId, const std::string &name, const Position &pos)
{
m_nullTile = TilePtr(new Tile(Position()));
setId(hId);
setName(name);
if(pos.isValid())
setEntry(pos);
}
void House::setTile(const TilePtr& tile)
{
tile->setFlags(TILESTATE_HOUSE);
m_tiles.insert(std::make_pair(tile->getPosition(), tile));
}
const TilePtr& House::getTile(const Position& position)
{
TileMap::const_iterator iter = m_tiles.find(position);
if(iter != m_tiles.end())
return iter->second;
return m_nullTile;
}
void House::load(const TiXmlElement *elem)
{
std::string name = elem->Attribute("name");
if(name.empty())
name = stdext::format("Unnamed house #%lu", getId());
setName(name);
setRent(elem->readType<uint32>("rent"));
setSize(elem->readType<uint32>("size"));
setTownId(elem->readType<uint32>("townid"));
m_isGuildHall = elem->readType<bool>("guildhall");
setEntry(elem->readPos("entry"));
}
void House::save(TiXmlElement*& elem)
{
elem = new TiXmlElement("house");
elem->SetAttribute("name", getName());
elem->SetAttribute("houseid", getId());
Position entry = getEntry();
elem->SetAttribute("entryx", entry.x);
elem->SetAttribute("entryy", entry.y);
elem->SetAttribute("entryz", entry.z);
elem->SetAttribute("rent", getRent());
elem->SetAttribute("townid", getTownId());
elem->SetAttribute("size", getSize());
elem->SetAttribute("guildhall", (int)m_isGuildHall);
}
HouseManager::HouseManager()
{
m_nullHouse = HousePtr(new House);
}
void HouseManager::addHouse(const HousePtr& house)
{
if(findHouse(house->getId()) == m_houses.end())
m_houses.push_back(house);
}
void HouseManager::removeHouse(uint32 houseId)
{
auto it = findHouse(houseId);
if(it != m_houses.end())
m_houses.erase(it);
}
const HousePtr& HouseManager::getHouse(uint32 houseId)
{
auto it = std::find_if(m_houses.begin(), m_houses.end(),
[=] (const HousePtr& house) -> bool { return house->getId() == houseId; });
return it != m_houses.end() ? *it : m_nullHouse;
}
void HouseManager::load(const std::string& fileName)
{
TiXmlDocument doc;
doc.Parse(g_resources.loadFile(fileName).c_str());
if(doc.Error())
stdext::throw_exception(stdext::format("failed to load '%s': %s (House XML)", fileName, doc.ErrorDesc()));
TiXmlElement *root = doc.FirstChildElement();
if(!root || root->ValueTStr() != "houses")
stdext::throw_exception("invalid root tag name");
for(TiXmlElement *elem = root->FirstChildElement(); elem; elem = elem->NextSiblingElement()) {
if(elem->ValueTStr() != "house")
stdext::throw_exception("invalid house tag.");
uint32 houseId = elem->readType<uint32>("houseid");
HousePtr house = getHouse(houseId);
if(!house)
house = HousePtr(new House(houseId)), addHouse(house);
house->load(elem);
}
}
void HouseManager::save(const std::string& fileName)
{
TiXmlDocument doc;
doc.SetTabSize(2);
TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "");
doc.LinkEndChild(decl);
TiXmlElement* root = new TiXmlElement("houses");
doc.LinkEndChild(root);
for(auto house : m_houses) {
TiXmlElement *elem;
house->save(elem);
root->LinkEndChild(elem);
}
if(!doc.SaveFile(fileName))
stdext::throw_exception(stdext::format("failed to save houses XML %s: %s", fileName, doc.ErrorDesc()));
}
HouseList::iterator HouseManager::findHouse(uint32 houseId)
{
return std::find_if(m_houses.begin(), m_houses.end(),
[=] (const HousePtr& house) -> bool { return house->getId() == houseId; });
}

105
src/client/houses.h Normal file
View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef HOUSES_H
#define HOUSES_H
#include "declarations.h"
#include "tile.h"
#include <framework/luaengine/luaobject.h>
enum HouseAttr : uint8
{
HouseAttrId,
HouseAttrName,
HouseAttrTown,
HouseAttrEntry,
HouseAttrSize,
HouseAttrRent
};
class House : public LuaObject
{
public:
House();
House(uint32 hId, const std::string& name = "", const Position& pos=Position());
~House() { m_tiles.clear(); m_nullTile = nullptr; }
void setTile(const TilePtr& tile);
const TilePtr& getTile(const Position& pos);
void setName(const std::string& name) { m_attribs.set(HouseAttrName, name); }
std::string getName() { return m_attribs.get<std::string>(HouseAttrName); }
void setId(uint32 hId) { m_attribs.set(HouseAttrId, hId); }
uint32 getId() { return m_attribs.get<uint32>(HouseAttrId); }
void setTownId(uint32 tid) { m_attribs.set(HouseAttrTown, tid); }
uint32 getTownId() { return m_attribs.get<uint32>(HouseAttrTown); }
void setSize(uint32 s) { m_attribs.set(HouseAttrSize, s); }
uint32 getSize() { return m_attribs.get<uint32>(HouseAttrSize); }
void setRent(uint32 r) { m_attribs.set(HouseAttrRent, r); }
uint32 getRent() { return m_attribs.get<uint32>(HouseAttrRent); }
void setEntry(const Position& p) { m_attribs.set(HouseAttrEntry, p); }
Position getEntry() { return m_attribs.get<Position>(HouseAttrEntry); }
protected:
void load(const TiXmlElement* elem);
void save(TiXmlElement*& elem);
private:
stdext::packed_storage<uint8> m_attribs;
TileMap m_tiles;
TilePtr m_nullTile;
stdext::boolean<false> m_isGuildHall;
friend class HouseManager;
};
class HouseManager {
public:
HouseManager();
void addHouse(const HousePtr& house);
void removeHouse(uint32 houseId);
HouseList getHouseList() { return m_houses; }
const HousePtr& getHouse(uint32 houseId);
void clear() { m_houses.clear(); m_nullHouse = nullptr; }
void load(const std::string& fileName);
void save(const std::string& fileName);
private:
HouseList m_houses;
HousePtr m_nullHouse;
protected:
HouseList::iterator findHouse(uint32 houseId);
};
extern HouseManager g_houses;
#endif

369
src/client/item.cpp Normal file
View File

@@ -0,0 +1,369 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "item.h"
#include "thingtypemanager.h"
#include "spritemanager.h"
#include "thing.h"
#include "tile.h"
#include "shadermanager.h"
#include "container.h"
#include "map.h"
#include "houses.h"
#include "game.h"
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
#include <framework/graphics/graphics.h>
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
Item::Item() :
m_clientId(0),
m_serverId(0),
m_countOrSubType(1)
{
}
ItemPtr Item::create(int id)
{
ItemPtr item(new Item);
item->setId(id);
return item;
}
ItemPtr Item::createFromOtb(int id)
{
ItemPtr item(new Item);
item->setOtbId(id);
return item;
}
void Item::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
{
if(m_clientId == 0)
return;
// determine animation phase
int animationPhase = calculateAnimationPhase(animate);
// determine x,y,z patterns
int xPattern = 0, yPattern = 0, zPattern = 0;
calculatePatterns(xPattern, yPattern, zPattern);
rawGetThingType()->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, lightView);
}
void Item::setId(uint32 id)
{
if(!g_things.isValidDatId(id, ThingCategoryItem))
id = 0;
m_serverId = g_things.findItemTypeByClientId(id)->getServerId();
m_clientId = id;
}
void Item::setOtbId(uint16 id)
{
if(!g_things.isValidOtbId(id))
id = 0;
auto itemType = g_things.getItemType(id);
m_serverId = id;
id = itemType->getClientId();
if(!g_things.isValidDatId(id, ThingCategoryItem))
id = 0;
m_clientId = id;
}
bool Item::isValid()
{
return g_things.isValidDatId(m_clientId, ThingCategoryItem);
}
void Item::unserializeItem(const BinaryTreePtr &in)
{
try {
while(in->canRead()) {
int attrib = in->getU8();
if(attrib == 0)
break;
switch(attrib) {
case ATTR_COUNT:
case ATTR_RUNE_CHARGES:
setCount(in->getU8());
break;
case ATTR_CHARGES:
setCount(in->getU16());
break;
case ATTR_HOUSEDOORID:
case ATTR_SCRIPTPROTECTED:
case ATTR_DUALWIELD:
case ATTR_DECAYING_STATE:
m_attribs.set(attrib, in->getU8());
break;
case ATTR_ACTION_ID:
case ATTR_UNIQUE_ID:
case ATTR_DEPOT_ID:
m_attribs.set(attrib, in->getU16());
break;
case ATTR_CONTAINER_ITEMS:
case ATTR_ATTACK:
case ATTR_EXTRAATTACK:
case ATTR_DEFENSE:
case ATTR_EXTRADEFENSE:
case ATTR_ARMOR:
case ATTR_ATTACKSPEED:
case ATTR_HITCHANCE:
case ATTR_DURATION:
case ATTR_WRITTENDATE:
case ATTR_SLEEPERGUID:
case ATTR_SLEEPSTART:
case ATTR_ATTRIBUTE_MAP:
m_attribs.set(attrib, in->getU32());
break;
case ATTR_TELE_DEST: {
Position pos;
pos.x = in->getU16();
pos.y = in->getU16();
pos.z = in->getU8();
m_attribs.set(attrib, pos);
break;
}
case ATTR_NAME:
case ATTR_TEXT:
case ATTR_DESC:
case ATTR_ARTICLE:
case ATTR_WRITTENBY:
m_attribs.set(attrib, in->getString());
break;
default:
stdext::throw_exception(stdext::format("invalid item attribute %d", attrib));
}
}
} catch(stdext::exception& e) {
g_logger.error(stdext::format("Failed to unserialize OTBM item: %s", e.what()));
}
}
void Item::serializeItem(const OutputBinaryTreePtr& out)
{
out->startNode(OTBM_ITEM);
out->addU16(getServerId());
out->addU8(ATTR_COUNT);
out->addU8(getCount());
out->addU8(ATTR_CHARGES);
out->addU16(getCountOrSubType());
Position dest = m_attribs.get<Position>(ATTR_TELE_DEST);
if(dest.isValid()) {
out->addU8(ATTR_TELE_DEST);
out->addPos(dest);
}
if(isDepot()) {
out->addU8(ATTR_DEPOT_ID);
out->addU16(getDepotId());
}
uint16 aid = m_attribs.get<uint16>(ATTR_ACTION_ID);
uint16 uid = m_attribs.get<uint16>(ATTR_UNIQUE_ID);
if(aid) {
out->addU8(ATTR_ACTION_ID);
out->addU16(aid);
}
if(uid) {
out->addU8(ATTR_UNIQUE_ID);
out->addU16(uid);
}
out->endNode();
if(!m_containerItems.empty()) {
for(auto c : m_containerItems)
c->serializeItem(out);
}
}
int Item::getSubType()
{
if(isSplash() || isFluidContainer())
return m_countOrSubType;
if(g_game.getProtocolVersion() >= 900)
return 0;
return 1;
}
int Item::getCount()
{
if(isStackable())
return m_countOrSubType;
return 1;
}
bool Item::isMoveable()
{
return !rawGetThingType()->isNotMoveable();
}
bool Item::isGround()
{
return rawGetThingType()->isGround();
}
ItemPtr Item::clone()
{
ItemPtr item = ItemPtr(new Item);
*(item.get()) = *this;
return item;
}
void Item::calculatePatterns(int& xPattern, int& yPattern, int& zPattern)
{
if(isStackable() && getNumPatternX() == 4 && getNumPatternY() == 2) {
if(m_countOrSubType <= 0) {
xPattern = 0;
yPattern = 0;
} else if(m_countOrSubType < 5) {
xPattern = m_countOrSubType-1;
yPattern = 0;
} else if(m_countOrSubType < 10) {
xPattern = 0;
yPattern = 1;
} else if(m_countOrSubType < 25) {
xPattern = 1;
yPattern = 1;
} else if(m_countOrSubType < 50) {
xPattern = 2;
yPattern = 1;
} else {
xPattern = 3;
yPattern = 1;
}
} else if(isHangable()) {
const TilePtr& tile = getTile();
if(tile) {
if(tile->mustHookSouth())
xPattern = getNumPatternX() >= 2 ? 1 : 0;
else if(tile->mustHookEast())
xPattern = getNumPatternX() >= 3 ? 2 : 0;
}
} else if(isSplash() || isFluidContainer()) {
int color = Otc::FluidTransparent;
switch(m_countOrSubType) {
case Otc::FluidNone:
color = Otc::FluidTransparent;
break;
case Otc::FluidWater:
color = Otc::FluidBlue;
break;
case Otc::FluidMana:
color = Otc::FluidPurple;
break;
case Otc::FluidBeer:
color = Otc::FluidBrown;
break;
case Otc::FluidOil:
color = Otc::FluidBrown;
break;
case Otc::FluidBlood:
color = Otc::FluidRed;
break;
case Otc::FluidSlime:
color = Otc::FluidGreen;
break;
case Otc::FluidMud:
color = Otc::FluidBrown;
break;
case Otc::FluidLemonade:
color = Otc::FluidYellow;
break;
case Otc::FluidMilk:
color = Otc::FluidWhite;
break;
case Otc::FluidWine:
color = Otc::FluidPurple;
break;
case Otc::FluidHealth:
color = Otc::FluidRed;
break;
case Otc::FluidUrine:
color = Otc::FluidYellow;
break;
case Otc::FluidRum:
color = Otc::FluidBrown;
break;
case Otc::FluidFruidJuice:
color = Otc::FluidYellow;
break;
case Otc::FluidCoconutMilk:
color = Otc::FluidWhite;
break;
case Otc::FluidTea:
color = Otc::FluidBrown;
break;
case Otc::FluidMead:
color = Otc::FluidBrown;
break;
default:
color = Otc::FluidTransparent;
break;
}
xPattern = (color % 4) % getNumPatternX();
yPattern = (color / 4) % getNumPatternY();
} else if(isGround() || isOnBottom()) {
xPattern = m_position.x % getNumPatternX();
yPattern = m_position.y % getNumPatternY();
zPattern = m_position.z % getNumPatternZ();
}
}
int Item::calculateAnimationPhase(bool animate)
{
if(getAnimationPhases() > 1) {
if(animate)
return (g_clock.millis() % (Otc::ITEM_TICKS_PER_FRAME * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
else
return getAnimationPhases()-1;
}
return 0;
}
int Item::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
{
calculatePatterns(xPattern, yPattern, zPattern);
animationPhase = calculateAnimationPhase(true);
return Thing::getExactSize(0, xPattern, yPattern, zPattern, animationPhase);
}
const ThingTypePtr& Item::getThingType()
{
return g_things.getThingType(m_clientId, ThingCategoryItem);
}
ThingType* Item::rawGetThingType()
{
return g_things.rawGetThingType(m_clientId, ThingCategoryItem);
}

144
src/client/item.h Normal file
View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef ITEM_H
#define ITEM_H
#include <framework/global.h>
#include "thing.h"
#include "effect.h"
#include "itemtype.h"
enum ItemAttr : uint8
{
ATTR_END = 0,
//ATTR_DESCRIPTION = 1,
//ATTR_EXT_FILE = 2,
ATTR_TILE_FLAGS = 3,
ATTR_ACTION_ID = 4,
ATTR_UNIQUE_ID = 5,
ATTR_TEXT = 6,
ATTR_DESC = 7,
ATTR_TELE_DEST = 8,
ATTR_ITEM = 9,
ATTR_DEPOT_ID = 10,
//ATTR_EXT_SPAWN_FILE = 11,
ATTR_RUNE_CHARGES = 12,
//ATTR_EXT_HOUSE_FILE = 13,
ATTR_HOUSEDOORID = 14,
ATTR_COUNT = 15,
ATTR_DURATION = 16,
ATTR_DECAYING_STATE = 17,
ATTR_WRITTENDATE = 18,
ATTR_WRITTENBY = 19,
ATTR_SLEEPERGUID = 20,
ATTR_SLEEPSTART = 21,
ATTR_CHARGES = 22,
ATTR_CONTAINER_ITEMS = 23,
ATTR_NAME = 30,
ATTR_PLURALNAME = 31,
ATTR_ATTACK = 33,
ATTR_EXTRAATTACK = 34,
ATTR_DEFENSE = 35,
ATTR_EXTRADEFENSE = 36,
ATTR_ARMOR = 37,
ATTR_ATTACKSPEED = 38,
ATTR_HITCHANCE = 39,
ATTR_SHOOTRANGE = 40,
ATTR_ARTICLE = 41,
ATTR_SCRIPTPROTECTED = 42,
ATTR_DUALWIELD = 43,
ATTR_ATTRIBUTE_MAP = 128
};
// @bindclass
#pragma pack(push,1) // disable memory alignment
class Item : public Thing
{
public:
Item();
virtual ~Item() { }
static ItemPtr create(int id);
static ItemPtr createFromOtb(int id);
void draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView = nullptr);
void setId(uint32 id);
void setOtbId(uint16 id);
void setCountOrSubType(int value) { m_countOrSubType = value; }
void setCount(int count) { m_countOrSubType = count; }
void setSubType(int subType) { m_countOrSubType = subType; }
int getCountOrSubType() { return m_countOrSubType; }
int getSubType();
int getCount();
uint32 getId() { return m_clientId; }
uint16 getClientId() { return m_clientId; }
uint16 getServerId() { return m_serverId; }
bool isValid();
ItemPtr clone();
void unserializeItem(const BinaryTreePtr& in);
void serializeItem(const OutputBinaryTreePtr& out);
void setDepotId(uint16 depotId) { m_attribs.set(ATTR_DEPOT_ID, depotId); }
uint16 getDepotId() { return m_attribs.get<uint16>(ATTR_DEPOT_ID); }
void setDoorId(uint8 doorId) { m_attribs.set(ATTR_HOUSEDOORID, doorId); }
uint8 getDoorId() { return m_attribs.get<uint8>(ATTR_HOUSEDOORID); }
void setActionId(uint16 actionId) { m_attribs.set(ATTR_ACTION_ID, actionId); }
void setUniqueId(uint16 uniqueId) { m_attribs.set(ATTR_UNIQUE_ID, uniqueId); }
bool isDepot() { return m_attribs.has(ATTR_DEPOT_ID); }
bool isContainer() { return m_attribs.has(ATTR_CONTAINER_ITEMS); }
bool isDoor() { return m_attribs.has(ATTR_HOUSEDOORID); }
bool isTeleport() { return m_attribs.has(ATTR_TELE_DEST); }
bool isMoveable();
bool isGround();
ItemPtr asItem() { return static_self_cast<Item>(); }
bool isItem() { return true; }
void addContainerItem(const ItemPtr& i) { m_containerItems.push_back(i); }
void clearContainerItems() { m_containerItems.clear(); }
void calculatePatterns(int& xPattern, int& yPattern, int& zPattern);
int calculateAnimationPhase(bool animate);
int getExactSize(int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animationPhase = 0);
const ThingTypePtr& getThingType();
ThingType *rawGetThingType();
private:
uint16 m_clientId;
uint16 m_serverId;
uint8 m_countOrSubType;
stdext::packed_storage<uint8> m_attribs;
std::vector<ItemPtr> m_containerItems;
};
#pragma pack(pop)
#endif

80
src/client/itemtype.cpp Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "thingtypemanager.h"
#include "thingtype.h"
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
ItemType::ItemType()
{
m_category = ItemCategoryInvalid;
}
void ItemType::unserialize(const BinaryTreePtr& node)
{
m_null = false;
m_category = (ItemCategory)node->getU8();
node->getU32(); // flags
static uint16 lastId = 99;
while(node->canRead()) {
uint8 attr = node->getU8();
if(attr == 0 || attr == 0xFF)
break;
uint16 len = node->getU16();
switch(attr) {
case ItemTypeAttrServerId: {
uint16 serverId = node->getU16();
if(serverId > 20000 && serverId < 20100) {
serverId -= 20000;
} else if(lastId > 99 && lastId != serverId - 1) {
while(lastId != serverId - 1) {
ItemTypePtr tmp(new ItemType);
tmp->setServerId(lastId++);
g_things.addItemType(tmp);
}
}
setServerId(serverId);
lastId = serverId;
break;
}
case ItemTypeAttrClientId: {
setClientId(node->getU16());
break;
}
case ItemTypeAttrName: {
setName(node->getString(len));
break;
}
default:
node->skip(len); // skip attribute
break;
}
}
}

159
src/client/itemtype.h Normal file
View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef ITEMTYPE_H
#define ITEMTYPE_H
#include <framework/core/declarations.h>
#include <framework/luaengine/luaobject.h>
#include <framework/xml/tinyxml.h>
enum ItemCategory : uint8 {
ItemCategoryInvalid = 0,
ItemCategoryGround = 1,
ItemCategoryContainer = 2,
ItemCategoryWeapon = 3,
ItemCategoryAmmunition = 4,
ItemCategoryArmor = 5,
ItemCategoryCharges = 6,
ItemCategoryTeleport = 7,
ItemCategoryMagicField = 8,
ItemCategoryWritable = 9,
ItemCategoryKey = 10,
ItemCategorySplash = 11,
ItemCategoryFluid = 12,
ItemCategoryDoor = 13,
ItemCategoryLast = 14
};
enum ItemTypeAttr : uint8 {
ItemTypeAttrServerId = 16,
ItemTypeAttrClientId = 17,
ItemTypeAttrName = 18, // deprecated
ItemTypeAttrDesc = 19, // deprecated
ItemTypeAttrSpeed = 20,
ItemTypeAttrSlot = 21, // deprecated
ItemTypeAttrMaxItems = 22, // deprecated
ItemTypeAttrWeight = 23, // deprecated
ItemTypeAttrWeapon = 24, // deprecated
ItemTypeAttrAmmunition = 25, // deprecated
ItemTypeAttrArmor = 26, // deprecated
ItemTypeAttrMagicLevel = 27, // deprecated
ItemTypeAttrMagicField = 28, // deprecated
ItemTypeAttrWritable = 29, // deprecated
ItemTypeAttrRotateTo = 30, // deprecated
ItemTypeAttrDecay = 31, // deprecated
ItemTypeAttrSpriteHash = 32,
ItemTypeAttrMinimapColor = 33,
ItemTypeAttr07 = 34,
ItemTypeAttr08 = 35,
ItemTypeAttrLight = 36,
ItemTypeAttrDecay2 = 37, // deprecated
ItemTypeAttrWeapon2 = 38, // deprecated
ItemTypeAttrAmmunition2 = 39, // deprecated
ItemTypeAttrArmor2 = 40, // deprecated
ItemTypeAttrWritable2 = 41, // deprecated
ItemTypeAttrLight2 = 42,
ItemTypeAttrTopOrder = 43,
ItemTypeAttrWrtiable3 = 44, // deprecated
ItemTypeAttrLast = 45
};
enum ClientVersion
{
ClientVersion750 = 1,
ClientVersion755 = 2,
ClientVersion760 = 3,
ClientVersion770 = 3,
ClientVersion780 = 4,
ClientVersion790 = 5,
ClientVersion792 = 6,
ClientVersion800 = 7,
ClientVersion810 = 8,
ClientVersion811 = 9,
ClientVersion820 = 10,
ClientVersion830 = 11,
ClientVersion840 = 12,
ClientVersion841 = 13,
ClientVersion842 = 14,
ClientVersion850 = 15,
ClientVersion854_OLD = 16,
ClientVersion854 = 17,
ClientVersion855 = 18,
ClientVersion860_OLD = 19,
ClientVersion860 = 20,
ClientVersion861 = 21,
ClientVersion862 = 22,
ClientVersion870 = 23,
ClientVersion871 = 24,
ClientVersion872 = 25,
ClientVersion873 = 26,
ClientVersion900 = 27,
ClientVersion910 = 28,
ClientVersion920 = 29,
ClientVersion940 = 30,
ClientVersion944_V1 = 31,
ClientVersion944_V2 = 32,
ClientVersion944_V3 = 33,
ClientVersion944_V4 = 34,
ClientVersion946 = 35,
ClientVersion950 = 36,
ClientVersion952 = 37,
ClientVersion953 = 38,
ClientVersion954 = 39,
ClientVersion960 = 40,
ClientVersion961 = 41
};
class ItemType : public LuaObject
{
public:
ItemType();
void unserialize(const BinaryTreePtr& node);
void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); }
uint16 getServerId() { return m_attribs.get<uint16>(ItemTypeAttrServerId); }
void setClientId(uint16 clientId) { m_attribs.set(ItemTypeAttrClientId, clientId); }
uint16 getClientId() { return m_attribs.get<uint16>(ItemTypeAttrClientId); }
void setCategory(ItemCategory category) { m_category = category; }
ItemCategory getCategory() { return m_category; }
void setName(const std::string& name) { m_attribs.set(ItemTypeAttrName, name); }
std::string getName() { return m_attribs.get<std::string>(ItemTypeAttrName); }
void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); }
std::string getDesc() { return m_attribs.get<std::string>(ItemTypeAttrDesc); }
bool isNull() { return m_null; }
private:
ItemCategory m_category;
stdext::boolean<true> m_null;
stdext::dynamic_storage<uint8> m_attribs;
};
#endif

136
src/client/lightview.cpp Normal file
View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "lightview.h"
#include "mapview.h"
#include <framework/graphics/framebuffer.h>
#include <framework/graphics/framebuffermanager.h>
#include <framework/graphics/painter.h>
#include <framework/graphics/image.h>
enum {
MAX_LIGHT_INTENSITY = 8,
MAX_AMBIENT_LIGHT_INTENSITY = 255
};
LightView::LightView()
{
m_lightbuffer = g_framebuffers.createFrameBuffer();
m_lightTexture = generateLightBubble(0.1f);
reset();
}
TexturePtr LightView::generateLightBubble(float centerFactor)
{
int bubbleRadius = 256;
int centerRadius = bubbleRadius * centerFactor;
int bubbleDiameter = bubbleRadius * 2;
ImagePtr lightImage = ImagePtr(new Image(Size(bubbleDiameter, bubbleDiameter)));
for(int x = 0; x < bubbleDiameter; x++) {
for(int y = 0; y < bubbleDiameter; y++) {
float radius = std::sqrt((bubbleRadius - x)*(bubbleRadius - x) + (bubbleRadius - y)*(bubbleRadius - y));
float intensity = std::max(std::min((bubbleRadius-radius)/(float)(bubbleRadius-centerRadius), 1.0f), 0.0f);
// light intensity varies inversely with the square of the distance
intensity = intensity * intensity;
uint8_t colorByte = intensity * 0xff;
uint8_t pixel[4] = {colorByte,colorByte,colorByte,0xff};
lightImage->setPixel(x, y, pixel);
}
}
TexturePtr tex = TexturePtr(new Texture(lightImage, true));
tex->setSmooth(true);
return tex;
}
void LightView::reset()
{
m_lightMap.clear();
}
void LightView::setGlobalLight(const Light& light)
{
m_globalLight = light;
}
void LightView::addLightSource(const Point& center, float scaleFactor, const Light& light)
{
int intensity = std::min<int>(light.intensity, MAX_LIGHT_INTENSITY);
int radius = intensity * Otc::TILE_PIXELS * scaleFactor;
Color color = Color::from8bit(light.color);
float brightness = 0.5f + (intensity/(float)MAX_LIGHT_INTENSITY)*0.5f;
color.setRed(color.rF() * brightness);
color.setGreen(color.gF() * brightness);
color.setBlue(color.bF() * brightness);
LightSource source;
source.center = center;
source.color = color;
source.radius = radius;
m_lightMap.push_back(source);
}
void LightView::drawGlobalLight(const Light& light)
{
Color color = Color::from8bit(light.color);
float brightness = light.intensity / (float)MAX_AMBIENT_LIGHT_INTENSITY;
color.setRed(color.rF() * brightness);
color.setGreen(color.gF() * brightness);
color.setBlue(color.bF() * brightness);
g_painter->setColor(color);
g_painter->drawFilledRect(Rect(0,0,m_lightbuffer->getSize()));
}
void LightView::drawLightSource(const Point& center, const Color& color, int radius)
{
// debug draw
//radius /= 16;
Rect dest = Rect(center - Point(radius, radius), Size(radius*2,radius*2));
g_painter->setColor(color);
g_painter->drawTexturedRect(dest, m_lightTexture);
}
void LightView::resize(const Size& size)
{
m_lightbuffer->resize(size);
}
void LightView::draw(const Rect& dest, const Rect& src)
{
g_painter->saveAndResetState();
m_lightbuffer->bind();
g_painter->setCompositionMode(Painter::CompositionMode_Replace);
drawGlobalLight(m_globalLight);
g_painter->setCompositionMode(Painter::CompositionMode_Add);
for(const LightSource& source : m_lightMap)
drawLightSource(source.center, source.color, source.radius);
m_lightbuffer->release();
g_painter->setCompositionMode(Painter::CompositionMode_Light);
m_lightbuffer->draw(dest, src);
g_painter->restoreSavedState();
}

59
src/client/lightview.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIGHTVIEW_H
#define LIGHTVIEW_H
#include "declarations.h"
#include <framework/graphics/declarations.h>
#include "thingtype.h"
struct LightSource {
Color color;
Point center;
int radius;
};
class LightView : public LuaObject
{
public:
LightView();
void reset();
void setGlobalLight(const Light& light);
void addLightSource(const Point& center, float scaleFactor, const Light& light);
void resize(const Size& size);
void draw(const Rect& dest, const Rect& src);
private:
void drawGlobalLight(const Light& light);
void drawLightSource(const Point& center, const Color& color, int radius);
TexturePtr generateLightBubble(float centerFactor);
TexturePtr m_lightTexture;
FrameBufferPtr m_lightbuffer;
MapView* m_mapView;
Light m_globalLight;
std::vector<LightSource> m_lightMap;
};
#endif

517
src/client/localplayer.cpp Normal file
View File

@@ -0,0 +1,517 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "localplayer.h"
#include "map.h"
#include "game.h"
#include "tile.h"
#include <framework/core/eventdispatcher.h>
LocalPlayer::LocalPlayer()
{
m_states = 0;
m_vocation = 0;
m_walkLockExpiration = 0;
m_lastWalkPing = -1;
m_skillsLevel.fill(-1);
m_skillsBaseLevel.fill(-1);
m_skillsLevelPercent.fill(-1);
m_health = -1;
m_maxHealth = -1;
m_freeCapacity = -1;
m_experience = -1;
m_level = -1;
m_levelPercent = -1;
m_mana = -1;
m_maxMana = -1;
m_magicLevel = -1;
m_magicLevelPercent = -1;
m_baseMagicLevel = -1;
m_soul = -1;
m_stamina = -1;
m_baseSpeed = -1;
m_regenerationTime = -1;
m_offlineTrainingTime = -1;
m_totalCapacity = -1;
}
void LocalPlayer::lockWalk(int millis)
{
m_walkLockExpiration = std::max(m_walkLockExpiration, (ticks_t) g_clock.millis() + millis);
}
bool LocalPlayer::canWalk(Otc::Direction direction)
{
// cannot walk while locked
if(m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration)
return false;
// paralyzed
if(m_speed == 0)
return false;
// last walk is not done yet
if(m_walkTimer.ticksElapsed() < getStepDuration())
return false;
// prewalk has a timeout, because for some reason that I don't know yet the server sometimes doesn't answer the prewalk
bool prewalkTimeouted = m_walking && m_preWalking && m_walkTimer.ticksElapsed() >= getStepDuration() + PREWALK_TIMEOUT;
// avoid doing more walks than wanted when receiving a lot of walks from server
if(!m_lastPrewalkDone && m_preWalking && !prewalkTimeouted)
return false;
// cannot walk while already walking
if(m_walking && !prewalkTimeouted)
return false;
return true;
}
void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
{
// a prewalk was going on
if(m_preWalking) {
if(m_waitingWalkPong) {
if(newPos == m_lastPrewalkDestionation)
m_lastWalkPing = m_walkPingTimer.ticksElapsed();
m_waitingWalkPong = false;
}
// switch to normal walking
m_preWalking = false;
m_lastPrewalkDone = true;
// if is to the last prewalk destination, updates the walk preserving the animation
if(newPos == m_lastPrewalkDestionation) {
updateWalk();
// was to another direction, replace the walk
} else
Creature::walk(oldPos, newPos);
}
// no prewalk was going on, this must be an server side automated walk
else {
m_walkPingTimer.restart();
m_autoWalking = true;
if(m_autoWalkEndEvent)
m_autoWalkEndEvent->cancel();
Creature::walk(oldPos, newPos);
}
}
void LocalPlayer::preWalk(Otc::Direction direction)
{
Position newPos = m_position.translatedToDirection(direction);
// avoid reanimating prewalks
if(m_preWalking && m_lastPrewalkDestionation == newPos)
return;
m_waitingWalkPong = false;
if(m_walkPingTimer.ticksElapsed() > getStepDuration() && m_idleTimer.ticksElapsed() > getStepDuration()*2) {
m_waitingWalkPong = true;
m_walkPingTimer.restart();
}
m_preWalking = true;
if(m_autoWalkEndEvent)
m_autoWalkEndEvent->cancel();
// start walking to direction
m_lastPrewalkDone = false;
m_lastPrewalkDestionation = newPos;
Creature::walk(m_position, newPos);
}
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
// only cancel client side walks
if(m_walking && m_preWalking)
stopWalk();
m_lastPrewalkDone = true;
m_waitingWalkPong = false;
m_walkPingTimer.restart();
m_idleTimer.restart();
// turn to the cancel direction
if(direction != Otc::InvalidDirection)
setDirection(direction);
updateAutoWalkSteps(true);
callLuaField("onCancelWalk", direction);
}
void LocalPlayer::updateAutoWalkSteps(bool walkFailed)
{
if(!m_autoWalking) {
m_autoWalkSteps.clear();
return;
}
if(!m_lastAutoWalkDestination.isValid()) {
return;
}
// for now this cannot be done from lua, due to bot protection
m_autoWalkSteps.push_back(m_lastAutoWalkDestination);
if(m_autoWalkSteps.size() >= Otc::MAX_AUTOWALK_STEPS_RETRY || walkFailed) {
autoWalk(m_lastAutoWalkDestination);
}
}
bool LocalPlayer::autoWalk(const Position& destination)
{
m_autoWalkSteps.clear();
m_lastAutoWalkDestination = destination;
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> result = g_map.findPath(m_position, destination, 127, Otc::PathFindAllowNullTiles);
std::vector<Otc::Direction> dirs = std::get<0>(result);
if(dirs.size() == 0)
return false;
g_game.autoWalk(dirs);
return true;
}
void LocalPlayer::stopAutoWalkUpdate()
{
m_lastAutoWalkDestination = Position();
m_autoWalkSteps.clear();
}
void LocalPlayer::stopWalk()
{
Creature::stopWalk(); // will call terminateWalk
m_lastPrewalkDone = true;
m_lastPrewalkDestionation = Position();
}
void LocalPlayer::updateWalkOffset(int totalPixelsWalked)
{
// pre walks offsets are calculated in the oposite direction
if(m_preWalking) {
m_walkOffset = Point(0,0);
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
m_walkOffset.y = -totalPixelsWalked;
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
m_walkOffset.y = totalPixelsWalked;
if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
m_walkOffset.x = totalPixelsWalked;
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
m_walkOffset.x = -totalPixelsWalked;
} else
Creature::updateWalkOffset(totalPixelsWalked);
}
void LocalPlayer::updateWalk()
{
int stepDuration = getStepDuration();
float walkTicksPerPixel = getStepDuration(true) / 32.0f;
int totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
// update walk animation and offsets
updateWalkAnimation(totalPixelsWalked);
updateWalkOffset(totalPixelsWalked);
updateWalkingTile();
// terminate walk only when client and server side walk are completed
if(m_walking && !m_preWalking && m_walkTimer.ticksElapsed() >= stepDuration)
terminateWalk();
}
void LocalPlayer::terminateWalk()
{
Creature::terminateWalk();
m_preWalking = false;
m_idleTimer.restart();
auto self = asLocalPlayer();
if(m_autoWalking) {
if(m_autoWalkEndEvent)
m_autoWalkEndEvent->cancel();
m_autoWalkEndEvent = g_dispatcher.scheduleEvent([self] {
self->m_autoWalking = false;
}, 100);
}
}
void LocalPlayer::onAppear()
{
Creature::onAppear();
// on teleports lock the walk
if(!m_oldPosition.isInRange(m_position,1,1))
lockWalk();
}
void LocalPlayer::onPositionChange(const Position& newPos, const Position& oldPos)
{
Creature::onPositionChange(newPos, oldPos);
updateAutoWalkSteps();
}
void LocalPlayer::setStates(int states)
{
if(m_states != states) {
int oldStates = m_states;
m_states = states;
callLuaField("onStatesChange", states, oldStates);
}
}
void LocalPlayer::setSkill(Otc::Skill skill, int level, int levelPercent)
{
if(skill >= Otc::LastSkill) {
g_logger.traceError("invalid skill");
return;
}
int oldLevel = m_skillsLevel[skill];
int oldLevelPercent = m_skillsLevelPercent[skill];
if(level != oldLevel || levelPercent != oldLevelPercent) {
m_skillsLevel[skill] = level;
m_skillsLevelPercent[skill] = levelPercent;
callLuaField("onSkillChange", skill, level, levelPercent, oldLevel, oldLevelPercent);
}
}
void LocalPlayer::setBaseSkill(Otc::Skill skill, int baseLevel)
{
if(skill >= Otc::LastSkill) {
g_logger.traceError("invalid skill");
return;
}
int oldBaseLevel = m_skillsBaseLevel[skill];
if(baseLevel != oldBaseLevel) {
m_skillsBaseLevel[skill] = baseLevel;
callLuaField("onBaseSkillChange", skill, baseLevel, oldBaseLevel);
}
}
void LocalPlayer::setHealth(double health, double maxHealth)
{
if(m_health != health || m_maxHealth != maxHealth) {
double oldHealth = m_health;
double oldMaxHealth = m_maxHealth;
m_health = health;
m_maxHealth = maxHealth;
callLuaField("onHealthChange", health, maxHealth, oldHealth, oldMaxHealth);
// cannot walk while dying
if(health == 0) {
if(isPreWalking())
stopWalk();
lockWalk();
}
}
}
void LocalPlayer::setFreeCapacity(double freeCapacity)
{
if(m_freeCapacity != freeCapacity) {
double oldFreeCapacity = m_freeCapacity;
m_freeCapacity = freeCapacity;
callLuaField("onFreeCapacityChange", freeCapacity, oldFreeCapacity);
}
}
void LocalPlayer::setTotalCapacity(double totalCapacity)
{
if(m_totalCapacity != totalCapacity) {
double oldTotalCapacity = m_totalCapacity;
m_totalCapacity = totalCapacity;
callLuaField("onTotalCapacityChange", totalCapacity, oldTotalCapacity);
}
}
void LocalPlayer::setExperience(double experience)
{
if(m_experience != experience) {
double oldExperience = m_experience;
m_experience = experience;
callLuaField("onExperienceChange", experience, oldExperience);
}
}
void LocalPlayer::setLevel(double level, double levelPercent)
{
if(m_level != level || m_levelPercent != levelPercent) {
double oldLevel = m_level;
double oldLevelPercent = m_levelPercent;
m_level = level;
m_levelPercent = levelPercent;
callLuaField("onLevelChange", level, levelPercent, oldLevel, oldLevelPercent);
}
}
void LocalPlayer::setMana(double mana, double maxMana)
{
if(m_mana != mana || m_maxMana != maxMana) {
double oldMana = m_mana;
double oldMaxMana;
m_mana = mana;
m_maxMana = maxMana;
callLuaField("onManaChange", mana, maxMana, oldMana, oldMaxMana);
}
}
void LocalPlayer::setMagicLevel(double magicLevel, double magicLevelPercent)
{
if(m_magicLevel != magicLevel || m_magicLevelPercent != magicLevelPercent) {
double oldMagicLevel = m_magicLevel;
double oldMagicLevelPercent = m_magicLevelPercent;
m_magicLevel = magicLevel;
m_magicLevelPercent = magicLevelPercent;
callLuaField("onMagicLevelChange", magicLevel, magicLevelPercent, oldMagicLevel, oldMagicLevelPercent);
}
}
void LocalPlayer::setBaseMagicLevel(double baseMagicLevel)
{
if(m_baseMagicLevel != baseMagicLevel) {
double oldBaseMagicLevel = m_baseMagicLevel;
m_baseMagicLevel = baseMagicLevel;
callLuaField("onBaseMagicLevelChange", baseMagicLevel, oldBaseMagicLevel);
}
}
void LocalPlayer::setSoul(double soul)
{
if(m_soul != soul) {
double oldSoul = m_soul;
m_soul = soul;
callLuaField("onSoulChange", soul, oldSoul);
}
}
void LocalPlayer::setStamina(double stamina)
{
if(m_stamina != stamina) {
double oldStamina = m_stamina;
m_stamina = stamina;
callLuaField("onStaminaChange", stamina, oldStamina);
}
}
void LocalPlayer::setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& item)
{
if(inventory >= Otc::LastInventorySlot) {
g_logger.traceError("invalid slot");
return;
}
if(m_inventoryItems[inventory] != item) {
ItemPtr oldItem = m_inventoryItems[inventory];
m_inventoryItems[inventory] = item;
callLuaField("onInventoryChange", inventory, item, oldItem);
}
}
void LocalPlayer::setVocation(int vocation)
{
if(m_vocation != vocation) {
int oldVocation = m_vocation;
m_vocation = vocation;
callLuaField("onVocationChange", vocation, oldVocation);
}
}
void LocalPlayer::setPremium(bool premium)
{
if(m_premium != premium) {
m_premium = premium;
callLuaField("onPremiumChange", premium);
}
}
void LocalPlayer::setBaseSpeed(double baseSpeed)
{
if(m_baseSpeed != baseSpeed) {
double oldBaseSpeed = m_baseSpeed;
m_baseSpeed = baseSpeed;
callLuaField("onBaseSpeedChange", baseSpeed, oldBaseSpeed);
}
}
void LocalPlayer::setRegenerationTime(double regenerationTime)
{
if(m_regenerationTime != regenerationTime) {
double oldRegenerationTime = m_regenerationTime;
m_regenerationTime = regenerationTime;
callLuaField("onRegenerationChange", regenerationTime, oldRegenerationTime);
}
}
void LocalPlayer::setOfflineTrainingTime(double offlineTrainingTime)
{
if(m_offlineTrainingTime != offlineTrainingTime) {
double oldOfflineTrainingTime = m_offlineTrainingTime;
m_offlineTrainingTime = offlineTrainingTime;
callLuaField("onOfflineTrainingChange", offlineTrainingTime, oldOfflineTrainingTime);
}
}
void LocalPlayer::setSpells(const std::vector<int>& spells)
{
if(m_spells != spells) {
std::vector<int> oldSpells = m_spells;
m_spells = spells;
callLuaField("onSpellsChange", spells, oldSpells);
}
}
bool LocalPlayer::hasSight(const Position& pos)
{
return m_position.isInRange(pos, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
}

169
src/client/localplayer.h Normal file
View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LOCALPLAYER_H
#define LOCALPLAYER_H
#include "player.h"
// @bindclass
class LocalPlayer : public Player
{
enum {
PREWALK_TIMEOUT = 1000
};
public:
LocalPlayer();
void unlockWalk() { m_walkLockExpiration = 0; }
void lockWalk(int millis = 250);
void stopAutoWalkUpdate();
void updateAutoWalkSteps(bool walkFailed = false);
bool autoWalk(const Position& destination);
bool canWalk(Otc::Direction direction);
void setStates(int states);
void setSkill(Otc::Skill skill, int level, int levelPercent);
void setBaseSkill(Otc::Skill skill, int baseLevel);
void setHealth(double health, double maxHealth);
void setFreeCapacity(double freeCapacity);
void setTotalCapacity(double totalCapacity);
void setExperience(double experience);
void setLevel(double level, double levelPercent);
void setMana(double mana, double maxMana);
void setMagicLevel(double magicLevel, double magicLevelPercent);
void setBaseMagicLevel(double baseMagicLevel);
void setSoul(double soul);
void setStamina(double stamina);
void setKnown(bool known) { m_known = known; }
void setPendingGame(bool pending) { m_pending = pending; }
void setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& item);
void setVocation(int vocation);
void setPremium(bool premium);
void setBaseSpeed(double baseSpeed);
void setRegenerationTime(double regenerationTime);
void setOfflineTrainingTime(double offlineTrainingTime);
void setSpells(const std::vector<int>& spells);
int getStates() { return m_states; }
int getSkillLevel(Otc::Skill skill) { return m_skillsLevel[skill]; }
int getSkillBaseLevel(Otc::Skill skill) { return m_skillsBaseLevel[skill]; }
int getSkillLevelPercent(Otc::Skill skill) { return m_skillsLevelPercent[skill]; }
int getVocation() { return m_vocation; }
int getWalkPing() { return m_lastWalkPing; }
double getHealth() { return m_health; }
double getMaxHealth() { return m_maxHealth; }
double getFreeCapacity() { return m_freeCapacity; }
double getTotalCapacity() { return m_totalCapacity; }
double getExperience() { return m_experience; }
double getLevel() { return m_level; }
double getLevelPercent() { return m_levelPercent; }
double getMana() { return m_mana; }
double getMaxMana() { return m_maxMana; }
double getMagicLevel() { return m_magicLevel; }
double getMagicLevelPercent() { return m_magicLevelPercent; }
double getBaseMagicLevel() { return m_baseMagicLevel; }
double getSoul() { return m_soul; }
double getStamina() { return m_stamina; }
double getBaseSpeed() { return m_baseSpeed; }
double getRegenerationTime() { return m_regenerationTime; }
double getOfflineTrainingTime() { return m_offlineTrainingTime; }
std::vector<int> getSpells() { return m_spells; }
ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; }
std::vector<Position> getAutoWalkSteps() { return m_autoWalkSteps; }
bool hasSight(const Position& pos);
bool isKnown() { return m_known; }
bool isPreWalking() { return m_preWalking; }
bool isAutoWalking() { return m_autoWalking; }
bool isPremium() { return m_premium; }
bool isPendingGame() { return m_pending; }
LocalPlayerPtr asLocalPlayer() { return static_self_cast<LocalPlayer>(); }
bool isLocalPlayer() { return true; }
virtual void onAppear();
virtual void onPositionChange(const Position& newPos, const Position& oldPos);
protected:
void walk(const Position& oldPos, const Position& newPos);
void preWalk(Otc::Direction direction);
void cancelWalk(Otc::Direction direction = Otc::InvalidDirection);
void stopWalk();
friend class Game;
protected:
void updateWalkOffset(int totalPixelsWalked);
void updateWalk();
void terminateWalk();
private:
// walk related
Timer m_walkPingTimer;
Position m_lastPrewalkDestionation;
Position m_lastAutoWalkDestination;
ScheduledEventPtr m_autoWalkEndEvent;
ticks_t m_walkLockExpiration;
int m_lastWalkPing;
stdext::boolean<false> m_preWalking;
stdext::boolean<true> m_lastPrewalkDone;
stdext::boolean<false> m_autoWalking;
stdext::boolean<false> m_waitingWalkPong;
stdext::boolean<false> m_premium;
stdext::boolean<false> m_known;
stdext::boolean<false> m_pending;
ItemPtr m_inventoryItems[Otc::LastInventorySlot];
Timer m_idleTimer;
std::array<int, Otc::LastSkill> m_skillsLevel;
std::array<int, Otc::LastSkill> m_skillsBaseLevel;
std::array<int, Otc::LastSkill> m_skillsLevelPercent;
std::vector<int> m_spells;
std::vector<Position> m_autoWalkSteps;
int m_states;
int m_vocation;
double m_health;
double m_maxHealth;
double m_freeCapacity;
double m_totalCapacity;
double m_experience;
double m_level;
double m_levelPercent;
double m_mana;
double m_maxMana;
double m_magicLevel;
double m_magicLevelPercent;
double m_baseMagicLevel;
double m_soul;
double m_stamina;
double m_baseSpeed;
double m_regenerationTime;
double m_offlineTrainingTime;
};
#endif

561
src/client/luafunctions.cpp Normal file
View File

@@ -0,0 +1,561 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "client.h"
#include "luavaluecasts.h"
#include "game.h"
#include "tile.h"
#include "houses.h"
#include "towns.h"
#include "container.h"
#include "item.h"
#include "effect.h"
#include "missile.h"
#include "statictext.h"
#include "animatedtext.h"
#include "creature.h"
#include "player.h"
#include "localplayer.h"
#include "map.h"
#include "thingtypemanager.h"
#include "spritemanager.h"
#include "shadermanager.h"
#include "protocolgame.h"
#include "uiitem.h"
#include "uicreature.h"
#include "uimap.h"
#include "uiprogressrect.h"
#include "outfit.h"
#include <framework/luaengine/luainterface.h>
void Client::registerLuaFunctions()
{
g_lua.registerSingletonClass("g_things");
g_lua.bindSingletonFunction("g_things", "loadDat", &ThingTypeManager::loadDat, &g_things);
g_lua.bindSingletonFunction("g_things", "loadOtb", &ThingTypeManager::loadOtb, &g_things);
g_lua.bindSingletonFunction("g_things", "loadXml", &ThingTypeManager::loadXml, &g_things);
g_lua.bindSingletonFunction("g_things", "isDatLoaded", &ThingTypeManager::isDatLoaded, &g_things);
g_lua.bindSingletonFunction("g_things", "isOtbLoaded", &ThingTypeManager::isOtbLoaded, &g_things);
g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things);
g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things);
g_lua.bindSingletonFunction("g_things", "getThingType", &ThingTypeManager::getThingType, &g_things);
g_lua.bindSingletonFunction("g_things", "getItemType", &ThingTypeManager::getItemType, &g_things);
g_lua.bindSingletonFunction("g_things", "getThingTypes", &ThingTypeManager::getThingTypes, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypeByClientId", &ThingTypeManager::findItemTypeByClientId, &g_things);
g_lua.bindSingletonFunction("g_things", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &g_things);
g_lua.registerSingletonClass("g_houses");
g_lua.bindSingletonFunction("g_houses", "clear", &HouseManager::clear, &g_houses);
g_lua.bindSingletonFunction("g_houses", "load", &HouseManager::load, &g_houses);
g_lua.bindSingletonFunction("g_houses", "save", &HouseManager::save, &g_houses);
g_lua.bindSingletonFunction("g_houses", "getHouse", &HouseManager::getHouse, &g_houses);
g_lua.bindSingletonFunction("g_houses", "addHouse", &HouseManager::addHouse, &g_houses);
g_lua.bindSingletonFunction("g_houses", "removeHouse", &HouseManager::removeHouse, &g_houses);
g_lua.bindSingletonFunction("g_houses", "getHouseList", &HouseManager::getHouseList, &g_houses);
g_lua.registerSingletonClass("g_towns");
g_lua.bindSingletonFunction("g_towns", "getTown", &TownManager::getTown, &g_towns);
g_lua.bindSingletonFunction("g_towns", "addTown", &TownManager::addTown, &g_towns);
g_lua.bindSingletonFunction("g_towns", "removeTown", &TownManager::removeTown, &g_towns);
g_lua.bindSingletonFunction("g_towns", "getTowns", &TownManager::getTowns, &g_towns);
g_lua.registerSingletonClass("g_sprites");
g_lua.bindSingletonFunction("g_sprites", "loadSpr", &SpriteManager::loadSpr, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "unload", &SpriteManager::unload, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "isLoaded", &SpriteManager::isLoaded, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "getSprSignature", &SpriteManager::getSignature, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "getSpritesCount", &SpriteManager::getSpritesCount, &g_sprites);
g_lua.registerSingletonClass("g_map");
g_lua.bindSingletonFunction("g_map", "isLookPossible", &Map::isLookPossible, &g_map);
g_lua.bindSingletonFunction("g_map", "isCovered", &Map::isCovered, &g_map);
g_lua.bindSingletonFunction("g_map", "isCompletelyCovered", &Map::isCompletelyCovered, &g_map);
g_lua.bindSingletonFunction("g_map", "addThing", &Map::addThing, &g_map);
g_lua.bindSingletonFunction("g_map", "getThing", &Map::getThing, &g_map);
g_lua.bindSingletonFunction("g_map", "removeThingByPos", &Map::removeThingByPos, &g_map);
g_lua.bindSingletonFunction("g_map", "removeThing", &Map::removeThing, &g_map);
g_lua.bindSingletonFunction("g_map", "clean", &Map::clean, &g_map);
g_lua.bindSingletonFunction("g_map", "cleanTile", &Map::cleanTile, &g_map);
g_lua.bindSingletonFunction("g_map", "cleanTexts", &Map::cleanTexts, &g_map);
g_lua.bindSingletonFunction("g_map", "getTile", &Map::getTile, &g_map);
g_lua.bindSingletonFunction("g_map", "setCentralPosition", &Map::setCentralPosition, &g_map);
g_lua.bindSingletonFunction("g_map", "getCentralPosition", &Map::getCentralPosition, &g_map);
g_lua.bindSingletonFunction("g_map", "getCreatureById", &Map::getCreatureById, &g_map);
g_lua.bindSingletonFunction("g_map", "removeCreatureById", &Map::removeCreatureById, &g_map);
g_lua.bindSingletonFunction("g_map", "getSpectators", &Map::getSpectators, &g_map);
g_lua.bindSingletonFunction("g_map", "findPath", &Map::findPath, &g_map);
g_lua.bindSingletonFunction("g_map", "loadOtbm", &Map::loadOtbm, &g_map);
g_lua.bindSingletonFunction("g_map", "saveOtbm", &Map::saveOtbm, &g_map);
g_lua.bindSingletonFunction("g_map", "loadOtcm", &Map::loadOtcm, &g_map);
g_lua.bindSingletonFunction("g_map", "saveOtcm", &Map::saveOtcm, &g_map);
g_lua.bindSingletonFunction("g_map", "getHouseFile", &Map::getHouseFile, &g_map);
g_lua.bindSingletonFunction("g_map", "setHouseFile", &Map::setHouseFile, &g_map);
g_lua.bindSingletonFunction("g_map", "getSpawnFile", &Map::getSpawnFile, &g_map);
g_lua.bindSingletonFunction("g_map", "setSpawnFile", &Map::setSpawnFile, &g_map);
g_lua.bindSingletonFunction("g_map", "createTile", &Map::createTile, &g_map);
g_lua.bindSingletonFunction("g_map", "getSize", &Map::getSize, &g_map);;
g_lua.registerSingletonClass("g_creatures");
g_lua.bindSingletonFunction("g_creatures", "getCreatures", &CreatureManager::getCreatures, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "getCreatureByName", &CreatureManager::getCreatureByName, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "getCreatureByLook", &CreatureManager::getCreatureByLook, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "getSpawn", &CreatureManager::getSpawn, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "addSpawn", &CreatureManager::addSpawn, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "loadMonsters", &CreatureManager::loadMonsters, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "loadNpcs", &CreatureManager::loadNpcs, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "loadSingleCreature", &CreatureManager::loadSingleCreature, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "loadSpawns", &CreatureManager::loadSpawns, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "saveSpawns", &CreatureManager::saveSpawns, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "isLoaded", &CreatureManager::isLoaded, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "isSpawnLoaded", &CreatureManager::isSpawnLoaded, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "clear", &CreatureManager::clear, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "clearSpawns", &CreatureManager::clearSpawns, &g_creatures);
g_lua.registerSingletonClass("g_game");
g_lua.bindSingletonFunction("g_game", "loginWorld", &Game::loginWorld, &g_game);
g_lua.bindSingletonFunction("g_game", "cancelLogin", &Game::cancelLogin, &g_game);
g_lua.bindSingletonFunction("g_game", "forceLogout", &Game::forceLogout, &g_game);
g_lua.bindSingletonFunction("g_game", "safeLogout", &Game::safeLogout, &g_game);
g_lua.bindSingletonFunction("g_game", "walk", &Game::walk, &g_game);
g_lua.bindSingletonFunction("g_game", "autoWalk", &Game::autoWalk, &g_game);
g_lua.bindSingletonFunction("g_game", "forceWalk", &Game::forceWalk, &g_game);
g_lua.bindSingletonFunction("g_game", "turn", &Game::turn, &g_game);
g_lua.bindSingletonFunction("g_game", "stop", &Game::stop, &g_game);
g_lua.bindSingletonFunction("g_game", "look", &Game::look, &g_game);
g_lua.bindSingletonFunction("g_game", "move", &Game::move, &g_game);
g_lua.bindSingletonFunction("g_game", "moveToParentContainer", &Game::moveToParentContainer, &g_game);
g_lua.bindSingletonFunction("g_game", "rotate", &Game::rotate, &g_game);
g_lua.bindSingletonFunction("g_game", "use", &Game::use, &g_game);
g_lua.bindSingletonFunction("g_game", "useWith", &Game::useWith, &g_game);
g_lua.bindSingletonFunction("g_game", "useInventoryItem", &Game::useInventoryItem, &g_game);
g_lua.bindSingletonFunction("g_game", "useInventoryItemWith", &Game::useInventoryItemWith, &g_game);
g_lua.bindSingletonFunction("g_game", "open", &Game::open, &g_game);
g_lua.bindSingletonFunction("g_game", "openParent", &Game::openParent, &g_game);
g_lua.bindSingletonFunction("g_game", "close", &Game::close, &g_game);
g_lua.bindSingletonFunction("g_game", "refreshContainer", &Game::refreshContainer, &g_game);
g_lua.bindSingletonFunction("g_game", "attack", &Game::attack, &g_game);
g_lua.bindSingletonFunction("g_game", "cancelAttack", &Game::cancelAttack, &g_game);
g_lua.bindSingletonFunction("g_game", "follow", &Game::follow, &g_game);
g_lua.bindSingletonFunction("g_game", "cancelFollow", &Game::cancelFollow, &g_game);
g_lua.bindSingletonFunction("g_game", "cancelAttackAndFollow", &Game::cancelAttackAndFollow, &g_game);
g_lua.bindSingletonFunction("g_game", "talk", &Game::talk, &g_game);
g_lua.bindSingletonFunction("g_game", "talkChannel", &Game::talkChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "talkPrivate", &Game::talkPrivate, &g_game);
g_lua.bindSingletonFunction("g_game", "openPrivateChannel", &Game::openPrivateChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "requestChannels", &Game::requestChannels, &g_game);
g_lua.bindSingletonFunction("g_game", "joinChannel", &Game::joinChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "leaveChannel", &Game::leaveChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "closeNpcChannel", &Game::closeNpcChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "openOwnChannel", &Game::openOwnChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "inviteToOwnChannel", &Game::inviteToOwnChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "excludeFromOwnChannel", &Game::excludeFromOwnChannel, &g_game);
g_lua.bindSingletonFunction("g_game", "partyInvite", &Game::partyInvite, &g_game);
g_lua.bindSingletonFunction("g_game", "partyJoin", &Game::partyJoin, &g_game);
g_lua.bindSingletonFunction("g_game", "partyRevokeInvitation", &Game::partyRevokeInvitation, &g_game);
g_lua.bindSingletonFunction("g_game", "partyPassLeadership", &Game::partyPassLeadership, &g_game);
g_lua.bindSingletonFunction("g_game", "partyLeave", &Game::partyLeave, &g_game);
g_lua.bindSingletonFunction("g_game", "partyShareExperience", &Game::partyShareExperience, &g_game);
g_lua.bindSingletonFunction("g_game", "requestOutfit", &Game::requestOutfit, &g_game);
g_lua.bindSingletonFunction("g_game", "changeOutfit", &Game::changeOutfit, &g_game);
g_lua.bindSingletonFunction("g_game", "addVip", &Game::addVip, &g_game);
g_lua.bindSingletonFunction("g_game", "removeVip", &Game::removeVip, &g_game);
g_lua.bindSingletonFunction("g_game", "setChaseMode", &Game::setChaseMode, &g_game);
g_lua.bindSingletonFunction("g_game", "setFightMode", &Game::setFightMode, &g_game);
g_lua.bindSingletonFunction("g_game", "setSafeFight", &Game::setSafeFight, &g_game);
g_lua.bindSingletonFunction("g_game", "getChaseMode", &Game::getChaseMode, &g_game);
g_lua.bindSingletonFunction("g_game", "getFightMode", &Game::getFightMode, &g_game);
g_lua.bindSingletonFunction("g_game", "isSafeFight", &Game::isSafeFight, &g_game);
g_lua.bindSingletonFunction("g_game", "inspectNpcTrade", &Game::inspectNpcTrade, &g_game);
g_lua.bindSingletonFunction("g_game", "buyItem", &Game::buyItem, &g_game);
g_lua.bindSingletonFunction("g_game", "sellItem", &Game::sellItem, &g_game);
g_lua.bindSingletonFunction("g_game", "closeNpcTrade", &Game::closeNpcTrade, &g_game);
g_lua.bindSingletonFunction("g_game", "requestTrade", &Game::requestTrade, &g_game);
g_lua.bindSingletonFunction("g_game", "inspectTrade", &Game::inspectTrade, &g_game);
g_lua.bindSingletonFunction("g_game", "acceptTrade", &Game::acceptTrade, &g_game);
g_lua.bindSingletonFunction("g_game", "rejectTrade", &Game::rejectTrade, &g_game);
g_lua.bindSingletonFunction("g_game", "reportBug", &Game::reportBug, &g_game);
g_lua.bindSingletonFunction("g_game", "reportRuleViolation", &Game::reportRuleViolation, &g_game);
g_lua.bindSingletonFunction("g_game", "debugReport", &Game::debugReport, &g_game);
g_lua.bindSingletonFunction("g_game", "editText", &Game::editText, &g_game);
g_lua.bindSingletonFunction("g_game", "editList", &Game::editList, &g_game);
g_lua.bindSingletonFunction("g_game", "requestQuestLog", &Game::requestQuestLog, &g_game);
g_lua.bindSingletonFunction("g_game", "requestQuestLine", &Game::requestQuestLine, &g_game);
g_lua.bindSingletonFunction("g_game", "equipItem", &Game::equipItem, &g_game);
g_lua.bindSingletonFunction("g_game", "mount", &Game::mount, &g_game);
g_lua.bindSingletonFunction("g_game", "requestItemInfo", &Game::requestItemInfo, &g_game);
g_lua.bindSingletonFunction("g_game", "ping", &Game::ping, &g_game);
g_lua.bindSingletonFunction("g_game", "canPerformGameAction", &Game::canPerformGameAction, &g_game);
g_lua.bindSingletonFunction("g_game", "canReportBugs", &Game::canReportBugs, &g_game);
g_lua.bindSingletonFunction("g_game", "checkBotProtection", &Game::checkBotProtection, &g_game);
g_lua.bindSingletonFunction("g_game", "isOnline", &Game::isOnline, &g_game);
g_lua.bindSingletonFunction("g_game", "isDead", &Game::isDead, &g_game);
g_lua.bindSingletonFunction("g_game", "isAttacking", &Game::isAttacking, &g_game);
g_lua.bindSingletonFunction("g_game", "isFollowing", &Game::isFollowing, &g_game);
g_lua.bindSingletonFunction("g_game", "getPing", &Game::getPing, &g_game);
g_lua.bindSingletonFunction("g_game", "getContainer", &Game::getContainer, &g_game);
g_lua.bindSingletonFunction("g_game", "getContainers", &Game::getContainers, &g_game);
g_lua.bindSingletonFunction("g_game", "getVips", &Game::getVips, &g_game);
g_lua.bindSingletonFunction("g_game", "getAttackingCreature", &Game::getAttackingCreature, &g_game);
g_lua.bindSingletonFunction("g_game", "getFollowingCreature", &Game::getFollowingCreature, &g_game);
g_lua.bindSingletonFunction("g_game", "getServerBeat", &Game::getServerBeat, &g_game);
g_lua.bindSingletonFunction("g_game", "getLocalPlayer", &Game::getLocalPlayer, &g_game);
g_lua.bindSingletonFunction("g_game", "getProtocolGame", &Game::getProtocolGame, &g_game);
g_lua.bindSingletonFunction("g_game", "getProtocolVersion", &Game::getProtocolVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "setProtocolVersion", &Game::setProtocolVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "getClientVersion", &Game::getClientVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "setClientVersion", &Game::setClientVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "getCharacterName", &Game::getCharacterName, &g_game);
g_lua.bindSingletonFunction("g_game", "getWorldName", &Game::getWorldName, &g_game);
g_lua.bindSingletonFunction("g_game", "getGMActions", &Game::getGMActions, &g_game);
g_lua.bindSingletonFunction("g_game", "getFeature", &Game::getFeature, &g_game);
g_lua.bindSingletonFunction("g_game", "setFeature", &Game::setFeature, &g_game);
g_lua.bindSingletonFunction("g_game", "enableFeature", &Game::enableFeature, &g_game);
g_lua.bindSingletonFunction("g_game", "answerModalDialog", &Game::answerModalDialog, &g_game);
g_lua.registerSingletonClass("g_shaders");
g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "createFragmentShader", &ShaderManager::createFragmentShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "createFragmentShaderFromCode", &ShaderManager::createFragmentShaderFromCode, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "createItemShader", &ShaderManager::createItemShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "createMapShader", &ShaderManager::createMapShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "getDefaultItemShader", &ShaderManager::getDefaultItemShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "getDefaultMapShader", &ShaderManager::getDefaultMapShader, &g_shaders);
g_lua.bindSingletonFunction("g_shaders", "getShader", &ShaderManager::getShader, &g_shaders);
g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor);
g_lua.registerClass<ProtocolGame, Protocol>();
g_lua.bindClassStaticFunction<ProtocolGame>("create", []{ return ProtocolGamePtr(new ProtocolGame); });
g_lua.bindClassMemberFunction<ProtocolGame>("login", &ProtocolGame::login);
g_lua.bindClassMemberFunction<ProtocolGame>("sendExtendedOpcode", &ProtocolGame::sendExtendedOpcode);
g_lua.bindClassMemberFunction<ProtocolGame>("addPosition", &ProtocolGame::addPosition);
g_lua.bindClassMemberFunction<ProtocolGame>("setMapDescription", &ProtocolGame::setMapDescription);
g_lua.bindClassMemberFunction<ProtocolGame>("setFloorDescription", &ProtocolGame::setFloorDescription);
g_lua.bindClassMemberFunction<ProtocolGame>("setTileDescription", &ProtocolGame::setTileDescription);
g_lua.bindClassMemberFunction<ProtocolGame>("getOutfit", &ProtocolGame::getOutfit);
g_lua.bindClassMemberFunction<ProtocolGame>("getThing", &ProtocolGame::getThing);
g_lua.bindClassMemberFunction<ProtocolGame>("getCreature", &ProtocolGame::getCreature);
g_lua.bindClassMemberFunction<ProtocolGame>("getItem", &ProtocolGame::getItem);
g_lua.bindClassMemberFunction<ProtocolGame>("getPosition", &ProtocolGame::getPosition);
g_lua.registerClass<Container>();
g_lua.bindClassMemberFunction<Container>("getItem", &Container::getItem);
g_lua.bindClassMemberFunction<Container>("getItems", &Container::getItems);
g_lua.bindClassMemberFunction<Container>("getItemsCount", &Container::getItemsCount);
g_lua.bindClassMemberFunction<Container>("getSlotPosition", &Container::getSlotPosition);
g_lua.bindClassMemberFunction<Container>("getName", &Container::getName);
g_lua.bindClassMemberFunction<Container>("getId", &Container::getId);
g_lua.bindClassMemberFunction<Container>("getCapacity", &Container::getCapacity);
g_lua.bindClassMemberFunction<Container>("getContainerItem", &Container::getContainerItem);
g_lua.bindClassMemberFunction<Container>("hasParent", &Container::hasParent);
g_lua.bindClassMemberFunction<Container>("isClosed", &Container::isClosed);
g_lua.registerClass<Thing>();
g_lua.bindClassMemberFunction<Thing>("setId", &Thing::setId);
g_lua.bindClassMemberFunction<Thing>("setPosition", &Thing::setPosition);
g_lua.bindClassMemberFunction<Thing>("getId", &Thing::getId);
g_lua.bindClassMemberFunction<Thing>("getPosition", &Thing::getPosition);
g_lua.bindClassMemberFunction<Thing>("getStackPriority", &Thing::getStackPriority);
g_lua.bindClassMemberFunction<Thing>("getAnimationPhases", &Thing::getAnimationPhases);
g_lua.bindClassMemberFunction<Thing>("isItem", &Thing::isItem);
g_lua.bindClassMemberFunction<Thing>("isMonster", &Thing::isMonster);
g_lua.bindClassMemberFunction<Thing>("isNpc", &Thing::isNpc);
g_lua.bindClassMemberFunction<Thing>("isCreature", &Thing::isCreature);
g_lua.bindClassMemberFunction<Thing>("isEffect", &Thing::isEffect);
g_lua.bindClassMemberFunction<Thing>("isMissile", &Thing::isMissile);
g_lua.bindClassMemberFunction<Thing>("isPlayer", &Thing::isPlayer);
g_lua.bindClassMemberFunction<Thing>("isLocalPlayer", &Thing::isLocalPlayer);
g_lua.bindClassMemberFunction<Thing>("isAnimatedText", &Thing::isAnimatedText);
g_lua.bindClassMemberFunction<Thing>("isStaticText", &Thing::isStaticText);
g_lua.bindClassMemberFunction<Thing>("isGround", &Thing::isGround);
g_lua.bindClassMemberFunction<Thing>("isGroundBorder", &Thing::isGroundBorder);
g_lua.bindClassMemberFunction<Thing>("isOnBottom", &Thing::isOnBottom);
g_lua.bindClassMemberFunction<Thing>("isOnTop", &Thing::isOnTop);
g_lua.bindClassMemberFunction<Thing>("isContainer", &Thing::isContainer);
g_lua.bindClassMemberFunction<Thing>("isForceUse", &Thing::isForceUse);
g_lua.bindClassMemberFunction<Thing>("isMultiUse", &Thing::isMultiUse);
g_lua.bindClassMemberFunction<Thing>("isRotateable", &Thing::isRotateable);
g_lua.bindClassMemberFunction<Thing>("isNotMoveable", &Thing::isNotMoveable);
g_lua.bindClassMemberFunction<Thing>("isPickupable", &Thing::isPickupable);
g_lua.bindClassMemberFunction<Thing>("isIgnoreLook", &Thing::isIgnoreLook);
g_lua.bindClassMemberFunction<Thing>("isStackable", &Thing::isStackable);
g_lua.bindClassMemberFunction<Thing>("isHookSouth", &Thing::isHookSouth);
g_lua.bindClassMemberFunction<Thing>("isTranslucent", &Thing::isTranslucent);
g_lua.bindClassMemberFunction<Thing>("isFullGround", &Thing::isFullGround);
g_lua.bindClassMemberFunction<Thing>("isMarketable", &Thing::isMarketable);
g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer);
g_lua.bindClassMemberFunction<Thing>("getMarketData", &Thing::getMarketData);
g_lua.registerClass<House>();
g_lua.bindClassStaticFunction<House>("create", []{ return HousePtr(new House); });
g_lua.bindClassMemberFunction<House>("setId", &House::setId);
g_lua.bindClassMemberFunction<House>("setName", &House::setName);
g_lua.bindClassMemberFunction<House>("getName", &House::getName);
g_lua.bindClassMemberFunction<House>("setTownId", &House::setTownId);
g_lua.bindClassMemberFunction<House>("getTownId", &House::getTownId);
g_lua.bindClassMemberFunction<House>("setTile", &House::setTile);
g_lua.bindClassMemberFunction<House>("getTile", &House::getTile);
g_lua.bindClassMemberFunction<House>("setEntry", &House::setEntry);
g_lua.bindClassMemberFunction<House>("getEntry", &House::getEntry);
g_lua.bindClassMemberFunction<House>("setSize", &House::setSize);
g_lua.bindClassMemberFunction<House>("getSize", &House::getSize);
g_lua.bindClassMemberFunction<House>("setRent", &House::setRent);
g_lua.bindClassMemberFunction<House>("getRent", &House::getRent);
g_lua.registerClass<Spawn>();
g_lua.bindClassStaticFunction<Spawn>("create", []{ return SpawnPtr(new Spawn); });
g_lua.bindClassMemberFunction<Spawn>("setRadius", &Spawn::setRadius);
g_lua.bindClassMemberFunction<Spawn>("getRadius", &Spawn::getRadius);
g_lua.bindClassMemberFunction<Spawn>("setCenterPos", &Spawn::setCenterPos);
g_lua.bindClassMemberFunction<Spawn>("getCenterPos", &Spawn::getCenterPos);
g_lua.bindClassMemberFunction<Spawn>("addCreature", &Spawn::addCreature);
g_lua.bindClassMemberFunction<Spawn>("removeCreature", &Spawn::removeCreature);
g_lua.registerClass<Town>();
g_lua.bindClassStaticFunction<Town>("create", []{ return TownPtr(new Town); });
g_lua.bindClassMemberFunction<Town>("setId", &Town::setId);
g_lua.bindClassMemberFunction<Town>("setName", &Town::setName);
g_lua.bindClassMemberFunction<Town>("setPos", &Town::setPos);
g_lua.bindClassMemberFunction<Town>("setTemplePos", &Town::setPos); // alternative method
g_lua.bindClassMemberFunction<Town>("getId", &Town::getId);
g_lua.bindClassMemberFunction<Town>("getName", &Town::getName);
g_lua.bindClassMemberFunction<Town>("getPos", &Town::getPos);
g_lua.bindClassMemberFunction<Town>("getTemplePos", &Town::getPos); // alternative method
g_lua.registerClass<CreatureType>();
g_lua.bindClassStaticFunction<CreatureType>("create", []{ return CreatureTypePtr(new CreatureType); });
g_lua.bindClassMemberFunction<CreatureType>("setName", &CreatureType::setName);
g_lua.bindClassMemberFunction<CreatureType>("setOutfit", &CreatureType::setOutfit);
g_lua.bindClassMemberFunction<CreatureType>("setSpawnTime", &CreatureType::setSpawnTime);
g_lua.bindClassMemberFunction<CreatureType>("getName", &CreatureType::getName);
g_lua.bindClassMemberFunction<CreatureType>("getOutfit", &CreatureType::getOutfit);
g_lua.bindClassMemberFunction<CreatureType>("getSpawnTime", &CreatureType::getSpawnTime);
g_lua.bindClassMemberFunction<CreatureType>("cast", &CreatureType::cast);
g_lua.registerClass<Creature, Thing>();
g_lua.bindClassStaticFunction<Creature>("create", []{ return CreaturePtr(new Creature); });
g_lua.bindClassMemberFunction<Creature>("getId", &Creature::getId);
g_lua.bindClassMemberFunction<Creature>("getName", &Creature::getName);
g_lua.bindClassMemberFunction<Creature>("getHealthPercent", &Creature::getHealthPercent);
g_lua.bindClassMemberFunction<Creature>("getSpeed", &Creature::getSpeed);
g_lua.bindClassMemberFunction<Creature>("getSkull", &Creature::getSkull);
g_lua.bindClassMemberFunction<Creature>("getShield", &Creature::getShield);
g_lua.bindClassMemberFunction<Creature>("getEmblem", &Creature::getEmblem);
g_lua.bindClassMemberFunction<Creature>("setOutfit", &Creature::setOutfit);
g_lua.bindClassMemberFunction<Creature>("getOutfit", &Creature::getOutfit);
g_lua.bindClassMemberFunction<Creature>("getDirection", &Creature::getDirection);
g_lua.bindClassMemberFunction<Creature>("getStepDuration", &Creature::getStepDuration);
g_lua.bindClassMemberFunction<Creature>("getStepProgress", &Creature::getStepProgress);
g_lua.bindClassMemberFunction<Creature>("getWalkTicksElapsed", &Creature::getWalkTicksElapsed);
g_lua.bindClassMemberFunction<Creature>("getStepTicksLeft", &Creature::getStepTicksLeft);
g_lua.bindClassMemberFunction<Creature>("setDirection", &Creature::setDirection);
g_lua.bindClassMemberFunction<Creature>("setSkullTexture", &Creature::setSkullTexture);
g_lua.bindClassMemberFunction<Creature>("setShieldTexture", &Creature::setShieldTexture);
g_lua.bindClassMemberFunction<Creature>("setEmblemTexture", &Creature::setEmblemTexture);
g_lua.bindClassMemberFunction<Creature>("showStaticSquare", &Creature::showStaticSquare);
g_lua.bindClassMemberFunction<Creature>("hideStaticSquare", &Creature::hideStaticSquare);
g_lua.bindClassMemberFunction<Creature>("isWalking", &Creature::isWalking);
g_lua.bindClassMemberFunction<Creature>("isInvisible", &Creature::isInvisible);
g_lua.bindClassMemberFunction<Creature>("canBeSeen", &Creature::canBeSeen);
g_lua.registerClass<ItemType>();
g_lua.bindClassMemberFunction<ItemType>("getServerId", &ItemType::getServerId);
g_lua.bindClassMemberFunction<ItemType>("getClientId", &ItemType::getClientId);
g_lua.registerClass<ThingType>();
g_lua.bindClassMemberFunction<ThingType>("getId", &ThingType::getId);
g_lua.bindClassMemberFunction<ThingType>("getMarketData", &ThingType::getMarketData);
g_lua.bindClassMemberFunction<ThingType>("getClothSlot", &ThingType::getClothSlot);
g_lua.bindClassMemberFunction<ThingType>("getCategory", &ThingType::getCategory);
g_lua.registerClass<Item, Thing>();
g_lua.bindClassStaticFunction<Item>("create", &Item::create);
g_lua.bindClassStaticFunction<Item>("createOtb", &Item::createFromOtb);
g_lua.bindClassMemberFunction<Item>("clone", &Item::clone);
g_lua.bindClassMemberFunction<Item>("setCount", &Item::setCount);
g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount);
g_lua.bindClassMemberFunction<Item>("getId", &Item::getId);
g_lua.bindClassMemberFunction<Item>("isStackable", &Item::isStackable);
g_lua.bindClassMemberFunction<Item>("isMarketable", &Item::isMarketable);
g_lua.bindClassMemberFunction<Item>("getMarketData", &Item::getMarketData);
g_lua.bindClassMemberFunction<Item>("getClothSlot", &Item::getClothSlot);
g_lua.registerClass<Effect, Thing>();
g_lua.registerClass<Missile, Thing>();
g_lua.registerClass<StaticText, Thing>();
g_lua.bindClassStaticFunction<StaticText>("create", []{ return StaticTextPtr(new StaticText); });
g_lua.bindClassMemberFunction<StaticText>("addMessage", &StaticText::addMessage);
g_lua.registerClass<AnimatedText, Thing>();
g_lua.registerClass<Player, Creature>();
g_lua.registerClass<Npc, Creature>();
g_lua.registerClass<Monster, Creature>();
g_lua.registerClass<LocalPlayer, Player>();
g_lua.bindClassMemberFunction<LocalPlayer>("unlockWalk", &LocalPlayer::unlockWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("lockWalk", &LocalPlayer::lockWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("canWalk", &LocalPlayer::canWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("setStates", &LocalPlayer::setStates);
g_lua.bindClassMemberFunction<LocalPlayer>("setSkill", &LocalPlayer::setSkill);
g_lua.bindClassMemberFunction<LocalPlayer>("setHealth", &LocalPlayer::setHealth);
g_lua.bindClassMemberFunction<LocalPlayer>("setTotalCapacity", &LocalPlayer::setTotalCapacity);
g_lua.bindClassMemberFunction<LocalPlayer>("setFreeCapacity", &LocalPlayer::setFreeCapacity);
g_lua.bindClassMemberFunction<LocalPlayer>("setExperience", &LocalPlayer::setExperience);
g_lua.bindClassMemberFunction<LocalPlayer>("setLevel", &LocalPlayer::setLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("setMana", &LocalPlayer::setMana);
g_lua.bindClassMemberFunction<LocalPlayer>("setMagicLevel", &LocalPlayer::setMagicLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("setSoul", &LocalPlayer::setSoul);
g_lua.bindClassMemberFunction<LocalPlayer>("setStamina", &LocalPlayer::setStamina);
g_lua.bindClassMemberFunction<LocalPlayer>("setKnown", &LocalPlayer::setKnown);
g_lua.bindClassMemberFunction<LocalPlayer>("setInventoryItem", &LocalPlayer::setInventoryItem);
g_lua.bindClassMemberFunction<LocalPlayer>("getStates", &LocalPlayer::getStates);
g_lua.bindClassMemberFunction<LocalPlayer>("getSkillLevel", &LocalPlayer::getSkillLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("getSkillBaseLevel", &LocalPlayer::getSkillBaseLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("getSkillLevelPercent", &LocalPlayer::getSkillLevelPercent);
g_lua.bindClassMemberFunction<LocalPlayer>("getHealth", &LocalPlayer::getHealth);
g_lua.bindClassMemberFunction<LocalPlayer>("getMaxHealth", &LocalPlayer::getMaxHealth);
g_lua.bindClassMemberFunction<LocalPlayer>("getFreeCapacity", &LocalPlayer::getFreeCapacity);
g_lua.bindClassMemberFunction<LocalPlayer>("getExperience", &LocalPlayer::getExperience);
g_lua.bindClassMemberFunction<LocalPlayer>("getLevel", &LocalPlayer::getLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("getLevelPercent", &LocalPlayer::getLevelPercent);
g_lua.bindClassMemberFunction<LocalPlayer>("getMana", &LocalPlayer::getMana);
g_lua.bindClassMemberFunction<LocalPlayer>("getMaxMana", &LocalPlayer::getMaxMana);
g_lua.bindClassMemberFunction<LocalPlayer>("getMagicLevel", &LocalPlayer::getMagicLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("getMagicLevelPercent", &LocalPlayer::getMagicLevelPercent);
g_lua.bindClassMemberFunction<LocalPlayer>("getSoul", &LocalPlayer::getSoul);
g_lua.bindClassMemberFunction<LocalPlayer>("getStamina", &LocalPlayer::getStamina);
g_lua.bindClassMemberFunction<LocalPlayer>("getOfflineTrainingTime", &LocalPlayer::getOfflineTrainingTime);
g_lua.bindClassMemberFunction<LocalPlayer>("getRegenerationTime", &LocalPlayer::getRegenerationTime);
g_lua.bindClassMemberFunction<LocalPlayer>("getBaseSpeed", &LocalPlayer::getBaseSpeed);
g_lua.bindClassMemberFunction<LocalPlayer>("getBaseMagicLevel", &LocalPlayer::getBaseMagicLevel);
g_lua.bindClassMemberFunction<LocalPlayer>("getTotalCapacity", &LocalPlayer::getTotalCapacity);
g_lua.bindClassMemberFunction<LocalPlayer>("getInventoryItem", &LocalPlayer::getInventoryItem);
g_lua.bindClassMemberFunction<LocalPlayer>("getVocation", &LocalPlayer::getVocation);
g_lua.bindClassMemberFunction<LocalPlayer>("getWalkPing", &LocalPlayer::getWalkPing);
g_lua.bindClassMemberFunction<LocalPlayer>("isPremium", &LocalPlayer::isPremium);
g_lua.bindClassMemberFunction<LocalPlayer>("isKnown", &LocalPlayer::isKnown);
g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("hasSight", &LocalPlayer::hasSight);
g_lua.bindClassMemberFunction<LocalPlayer>("isAutoWalking", &LocalPlayer::isAutoWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("stopAutoWalkUpdate", &LocalPlayer::stopAutoWalkUpdate);
g_lua.bindClassMemberFunction<LocalPlayer>("updateAutoWalkSteps", &LocalPlayer::updateAutoWalkSteps);
g_lua.bindClassMemberFunction<LocalPlayer>("autoWalk", &LocalPlayer::autoWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("getAutoWalkSteps", &LocalPlayer::getAutoWalkSteps);
g_lua.registerClass<Tile>();
g_lua.bindClassMemberFunction<Tile>("clean", &Tile::clean);
g_lua.bindClassMemberFunction<Tile>("addThing", &Tile::addThing);
g_lua.bindClassMemberFunction<Tile>("getThing", &Tile::getThing);
g_lua.bindClassMemberFunction<Tile>("getThingStackpos", &Tile::getThingStackpos);
g_lua.bindClassMemberFunction<Tile>("getThingCount", &Tile::getThingCount);
g_lua.bindClassMemberFunction<Tile>("getTopThing", &Tile::getTopThing);
g_lua.bindClassMemberFunction<Tile>("removeThing", &Tile::removeThing);
g_lua.bindClassMemberFunction<Tile>("getTopLookThing", &Tile::getTopLookThing);
g_lua.bindClassMemberFunction<Tile>("getTopUseThing", &Tile::getTopUseThing);
g_lua.bindClassMemberFunction<Tile>("getTopCreature", &Tile::getTopCreature);
g_lua.bindClassMemberFunction<Tile>("getTopMoveThing", &Tile::getTopMoveThing);
g_lua.bindClassMemberFunction<Tile>("getTopMultiUseThing", &Tile::getTopMultiUseThing);
g_lua.bindClassMemberFunction<Tile>("getPosition", &Tile::getPosition);
g_lua.bindClassMemberFunction<Tile>("getDrawElevation", &Tile::getDrawElevation);
g_lua.bindClassMemberFunction<Tile>("getCreatures", &Tile::getCreatures);
g_lua.bindClassMemberFunction<Tile>("getGround", &Tile::getGround);
g_lua.bindClassMemberFunction<Tile>("isWalkable", &Tile::isWalkable);
g_lua.bindClassMemberFunction<Tile>("isFullGround", &Tile::isFullGround);
g_lua.bindClassMemberFunction<Tile>("isFullyOpaque", &Tile::isFullyOpaque);
g_lua.bindClassMemberFunction<Tile>("isLookPossible", &Tile::isLookPossible);
g_lua.bindClassMemberFunction<Tile>("hasCreature", &Tile::hasCreature);
g_lua.bindClassMemberFunction<Tile>("isEmpty", &Tile::isEmpty);
g_lua.bindClassMemberFunction<Tile>("isClickable", &Tile::isClickable);
g_lua.registerClass<UIItem, UIWidget>();
g_lua.bindClassStaticFunction<UIItem>("create", []{ return UIItemPtr(new UIItem); });
g_lua.bindClassMemberFunction<UIItem>("setItemId", &UIItem::setItemId);
g_lua.bindClassMemberFunction<UIItem>("setItemCount", &UIItem::setItemCount);
g_lua.bindClassMemberFunction<UIItem>("setItemSubType", &UIItem::setItemSubType);
g_lua.bindClassMemberFunction<UIItem>("setItem", &UIItem::setItem);
g_lua.bindClassMemberFunction<UIItem>("setVirtual", &UIItem::setVirtual);
g_lua.bindClassMemberFunction<UIItem>("clearItem", &UIItem::clearItem);
g_lua.bindClassMemberFunction<UIItem>("getItemId", &UIItem::getItemId);
g_lua.bindClassMemberFunction<UIItem>("getItemCount", &UIItem::getItemCount);
g_lua.bindClassMemberFunction<UIItem>("getItemSubType", &UIItem::getItemSubType);
g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem);
g_lua.bindClassMemberFunction<UIItem>("isVirtual", &UIItem::isVirtual);
g_lua.registerClass<UICreature, UIWidget>();
g_lua.bindClassStaticFunction<UICreature>("create", []{ return UICreaturePtr(new UICreature); } );
g_lua.bindClassMemberFunction<UICreature>("setCreature", &UICreature::setCreature);
g_lua.bindClassMemberFunction<UICreature>("setOutfit", &UICreature::setOutfit);
g_lua.bindClassMemberFunction<UICreature>("setFixedCreatureSize", &UICreature::setFixedCreatureSize);
g_lua.bindClassMemberFunction<UICreature>("getCreature", &UICreature::getCreature);
g_lua.bindClassMemberFunction<UICreature>("isFixedCreatureSize", &UICreature::isFixedCreatureSize);
g_lua.registerClass<UIMap, UIWidget>();
g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); });
g_lua.bindClassMemberFunction<UIMap>("drawSelf", &UIMap::drawSelf);
g_lua.bindClassMemberFunction<UIMap>("setZoom", &UIMap::setZoom);
g_lua.bindClassMemberFunction<UIMap>("zoomIn", &UIMap::zoomIn);
g_lua.bindClassMemberFunction<UIMap>("zoomOut", &UIMap::zoomOut);
g_lua.bindClassMemberFunction<UIMap>("followCreature", &UIMap::followCreature);
g_lua.bindClassMemberFunction<UIMap>("setCameraPosition", &UIMap::setCameraPosition);
g_lua.bindClassMemberFunction<UIMap>("setMaxZoomIn", &UIMap::setMaxZoomIn);
g_lua.bindClassMemberFunction<UIMap>("setMaxZoomOut", &UIMap::setMaxZoomOut);
g_lua.bindClassMemberFunction<UIMap>("setMultifloor", &UIMap::setMultifloor);
g_lua.bindClassMemberFunction<UIMap>("setVisibleDimension", &UIMap::setVisibleDimension);
g_lua.bindClassMemberFunction<UIMap>("setViewMode", &UIMap::setViewMode);
g_lua.bindClassMemberFunction<UIMap>("setAutoViewMode", &UIMap::setAutoViewMode);
g_lua.bindClassMemberFunction<UIMap>("setDrawFlags", &UIMap::setDrawFlags);
g_lua.bindClassMemberFunction<UIMap>("setDrawTexts", &UIMap::setDrawTexts);
g_lua.bindClassMemberFunction<UIMap>("setDrawMinimapColors", &UIMap::setDrawMinimapColors);
g_lua.bindClassMemberFunction<UIMap>("setDrawLights", &UIMap::setDrawLights);
g_lua.bindClassMemberFunction<UIMap>("setAnimated", &UIMap::setAnimated);
g_lua.bindClassMemberFunction<UIMap>("setKeepAspectRatio", &UIMap::setKeepAspectRatio);
g_lua.bindClassMemberFunction<UIMap>("setMapShader", &UIMap::setMapShader);
g_lua.bindClassMemberFunction<UIMap>("setMinimumAmbientLight", &UIMap::setMinimumAmbientLight);
g_lua.bindClassMemberFunction<UIMap>("isMultifloor", &UIMap::isMultifloor);
g_lua.bindClassMemberFunction<UIMap>("isAutoViewModeEnabled", &UIMap::isAutoViewModeEnabled);
g_lua.bindClassMemberFunction<UIMap>("isDrawingTexts", &UIMap::isDrawingTexts);
g_lua.bindClassMemberFunction<UIMap>("isDrawingMinimapColors", &UIMap::isDrawingMinimapColors);
g_lua.bindClassMemberFunction<UIMap>("isDrawingLights", &UIMap::isDrawingLights);
g_lua.bindClassMemberFunction<UIMap>("isAnimating", &UIMap::isAnimating);
g_lua.bindClassMemberFunction<UIMap>("isKeepAspectRatioEnabled", &UIMap::isKeepAspectRatioEnabled);
g_lua.bindClassMemberFunction<UIMap>("getVisibleDimension", &UIMap::getVisibleDimension);
g_lua.bindClassMemberFunction<UIMap>("getViewMode", &UIMap::getViewMode);
g_lua.bindClassMemberFunction<UIMap>("getFollowingCreature", &UIMap::getFollowingCreature);
g_lua.bindClassMemberFunction<UIMap>("getDrawFlags", &UIMap::getDrawFlags);
g_lua.bindClassMemberFunction<UIMap>("getCameraPosition", &UIMap::getCameraPosition);
g_lua.bindClassMemberFunction<UIMap>("getPosition", &UIMap::getPosition);
g_lua.bindClassMemberFunction<UIMap>("getTile", &UIMap::getTile);
g_lua.bindClassMemberFunction<UIMap>("getMaxZoomIn", &UIMap::getMaxZoomIn);
g_lua.bindClassMemberFunction<UIMap>("getMaxZoomOut", &UIMap::getMaxZoomOut);
g_lua.bindClassMemberFunction<UIMap>("getZoom", &UIMap::getZoom);
g_lua.bindClassMemberFunction<UIMap>("getMapShader", &UIMap::getMapShader);
g_lua.bindClassMemberFunction<UIMap>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight);
g_lua.registerClass<UIProgressRect, UIWidget>();
g_lua.bindClassStaticFunction<UIProgressRect>("create", []{ return UIProgressRectPtr(new UIProgressRect); } );
g_lua.bindClassMemberFunction<UIProgressRect>("setPercent", &UIProgressRect::setPercent);
g_lua.bindClassMemberFunction<UIProgressRect>("getPercent", &UIProgressRect::getPercent);
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "luavaluecasts.h"
#include <framework/luaengine/luainterface.h>
int push_luavalue(const Outfit& outfit)
{
g_lua.newTable();
g_lua.pushInteger(outfit.getId());
g_lua.setField("type");
g_lua.pushInteger(outfit.getAuxId());
g_lua.setField("auxType");
g_lua.pushInteger(outfit.getAddons());
g_lua.setField("addons");
g_lua.pushInteger(outfit.getHead());
g_lua.setField("head");
g_lua.pushInteger(outfit.getBody());
g_lua.setField("body");
g_lua.pushInteger(outfit.getLegs());
g_lua.setField("legs");
g_lua.pushInteger(outfit.getFeet());
g_lua.setField("feet");
if(g_game.getFeature(Otc::GamePlayerMounts)) {
g_lua.pushInteger(outfit.getMount());
g_lua.setField("mount");
}
return 1;
}
bool luavalue_cast(int index, Outfit& outfit)
{
if(g_lua.isTable(index)) {
g_lua.getField("type", index);
outfit.setId(g_lua.popInteger());
g_lua.getField("auxType", index);
outfit.setAuxId(g_lua.popInteger());
g_lua.getField("addons", index);
outfit.setAddons(g_lua.popInteger());
g_lua.getField("head", index);
outfit.setHead(g_lua.popInteger());
g_lua.getField("body", index);
outfit.setBody(g_lua.popInteger());
g_lua.getField("legs", index);
outfit.setLegs(g_lua.popInteger());
g_lua.getField("feet", index);
outfit.setFeet(g_lua.popInteger());
if(g_game.getFeature(Otc::GamePlayerMounts)) {
g_lua.getField("mount", index);
outfit.setMount(g_lua.popInteger());
}
return true;
}
return false;
}
int push_luavalue(const Position& pos)
{
if(pos.isValid()) {
g_lua.newTable();
g_lua.pushInteger(pos.x);
g_lua.setField("x");
g_lua.pushInteger(pos.y);
g_lua.setField("y");
g_lua.pushInteger(pos.z);
g_lua.setField("z");
} else
g_lua.pushNil();
return 1;
}
bool luavalue_cast(int index, Position& pos)
{
if(g_lua.isTable(index)) {
g_lua.getField("x", index);
pos.x = g_lua.popInteger();
g_lua.getField("y", index);
pos.y = g_lua.popInteger();
g_lua.getField("z", index);
pos.z = g_lua.popInteger();
return true;
}
return false;
}
int push_luavalue(const MarketData& data)
{
g_lua.newTable();
g_lua.pushInteger(data.category);
g_lua.setField("category");
g_lua.pushString(data.name);
g_lua.setField("name");
g_lua.pushInteger(data.requiredLevel);
g_lua.setField("requiredLevel");
g_lua.pushInteger(data.restrictVocation);
g_lua.setField("restrictVocation");
g_lua.pushInteger(data.showAs);
g_lua.setField("showAs");
g_lua.pushInteger(data.tradeAs);
g_lua.setField("tradeAs");
return 1;
}
bool luavalue_cast(int index, MarketData& data)
{
if(g_lua.isTable(index)) {
g_lua.getField("category", index);
data.category = g_lua.popInteger();
g_lua.getField("name", index);
data.name = g_lua.popString();
g_lua.getField("requiredLevel", index);
data.requiredLevel = g_lua.popInteger();
g_lua.getField("restrictVocation", index);
data.restrictVocation = g_lua.popInteger();
g_lua.getField("showAs", index);
data.showAs = g_lua.popInteger();
g_lua.getField("tradeAs", index);
data.tradeAs = g_lua.popInteger();
return true;
}
return false;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef OTCLIENT_LUAVALUECASTS_H
#define OTCLIENT_LUAVALUECASTS_H
#include "global.h"
#include <framework/luaengine/declarations.h>
#include "game.h"
#include "outfit.h"
// outfit
int push_luavalue(const Outfit& outfit);
bool luavalue_cast(int index, Outfit& outfit);
// position
int push_luavalue(const Position& pos);
bool luavalue_cast(int index, Position& pos);
// market
int push_luavalue(const MarketData& data);
bool luavalue_cast(int index, MarketData& data);
#endif

584
src/client/map.cpp Normal file
View File

@@ -0,0 +1,584 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "map.h"
#include "game.h"
#include "localplayer.h"
#include "tile.h"
#include "item.h"
#include "missile.h"
#include "statictext.h"
#include "mapview.h"
#include <framework/core/eventdispatcher.h>
#include <framework/core/application.h>
Map g_map;
TilePtr Map::m_nulltile;
void Map::terminate()
{
clean();
}
void Map::addMapView(const MapViewPtr& mapView)
{
m_mapViews.push_back(mapView);
}
void Map::removeMapView(const MapViewPtr& mapView)
{
auto it = std::find(m_mapViews.begin(), m_mapViews.end(), mapView);
if(it != m_mapViews.end())
m_mapViews.erase(it);
}
void Map::notificateTileUpdateToMapViews(const Position& pos)
{
for(const MapViewPtr& mapView : m_mapViews)
mapView->onTileUpdate(pos);
}
void Map::clean()
{
cleanDynamicThings();
for(int i=0;i<=Otc::MAX_Z;++i)
m_tileBlocks[i].clear();
m_waypoints.clear();
g_towns.clear();
g_houses.clear();
g_creatures.clearSpawns();
m_tilesRect = Rect(65534, 65534, 0, 0);
}
void Map::cleanDynamicThings()
{
for(const auto& pair : m_knownCreatures) {
const CreaturePtr& creature = pair.second;
removeThing(creature);
}
m_knownCreatures.clear();
for(int i=0;i<=Otc::MAX_Z;++i)
m_floorMissiles[i].clear();
cleanTexts();
}
void Map::cleanTexts()
{
m_animatedTexts.clear();
m_staticTexts.clear();
}
void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
{
if(!thing)
return;
if(thing->isItem() || thing->isCreature() || thing->isEffect()) {
const TilePtr& tile = getOrCreateTile(pos);
tile->addThing(thing, stackPos);
} else {
if(thing->isMissile()) {
m_floorMissiles[pos.z].push_back(thing->static_self_cast<Missile>());
thing->onAppear();
} else if(thing->isAnimatedText()) {
AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
m_animatedTexts.push_back(animatedText);
} else if(thing->isStaticText()) {
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
bool mustAdd = true;
for(auto other : m_staticTexts) {
// try to combine messages
if(other->getPosition() == pos && other->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) {
mustAdd = false;
break;
}
}
if(mustAdd) {
m_staticTexts.push_back(staticText);
staticText->onAppear();
}
}
thing->setPosition(pos);
thing->onAppear();
}
notificateTileUpdateToMapViews(pos);
}
ThingPtr Map::getThing(const Position& pos, int stackPos)
{
if(TilePtr tile = getTile(pos))
return tile->getThing(stackPos);
return nullptr;
}
bool Map::removeThing(const ThingPtr& thing)
{
if(!thing)
return false;
notificateTileUpdateToMapViews(thing->getPosition());
if(thing->isMissile()) {
MissilePtr missile = thing->static_self_cast<Missile>();
int z = missile->getPosition().z;
auto it = std::find(m_floorMissiles[z].begin(), m_floorMissiles[z].end(), missile);
if(it != m_floorMissiles[z].end()) {
m_floorMissiles[z].erase(it);
return true;
}
} else if(thing->isAnimatedText()) {
AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
auto it = std::find(m_animatedTexts.begin(), m_animatedTexts.end(), animatedText);
if(it != m_animatedTexts.end()) {
m_animatedTexts.erase(it);
return true;
}
} else if(thing->isStaticText()) {
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
auto it = std::find(m_staticTexts.begin(), m_staticTexts.end(), staticText);
if(it != m_staticTexts.end()) {
m_staticTexts.erase(it);
return true;
}
} else if(const TilePtr& tile = thing->getTile())
return tile->removeThing(thing);
return false;
}
bool Map::removeThingByPos(const Position& pos, int stackPos)
{
if(TilePtr tile = getTile(pos))
return removeThing(tile->getThing(stackPos));
return false;
}
const TilePtr& Map::createTile(const Position& pos)
{
if(!pos.isMapPosition())
return m_nulltile;
if(pos.x < m_tilesRect.left())
m_tilesRect.setLeft(pos.x);
if(pos.y < m_tilesRect.top())
m_tilesRect.setTop(pos.y);
if(pos.x > m_tilesRect.right())
m_tilesRect.setRight(pos.x);
if(pos.y > m_tilesRect.bottom())
m_tilesRect.setBottom(pos.y);
TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)];
return block.create(pos);
}
template <typename... Items>
const TilePtr& Map::createTileEx(const Position& pos, const Items&... items)
{
if(!pos.isValid())
return m_nulltile;
const TilePtr& tile = getOrCreateTile(pos);
auto vec = {items...};
for(auto it : vec)
addThing(it, pos);
return tile;
}
const TilePtr& Map::getOrCreateTile(const Position& pos)
{
if(!pos.isMapPosition())
return m_nulltile;
if(pos.x < m_tilesRect.left())
m_tilesRect.setLeft(pos.x);
if(pos.y < m_tilesRect.top())
m_tilesRect.setTop(pos.y);
if(pos.x > m_tilesRect.right())
m_tilesRect.setRight(pos.x);
if(pos.y > m_tilesRect.bottom())
m_tilesRect.setBottom(pos.y);
TileBlock& block = m_tileBlocks[pos.z][getBlockIndex(pos)];
return block.getOrCreate(pos);
}
const TilePtr& Map::getTile(const Position& pos)
{
if(!pos.isMapPosition())
return m_nulltile;
auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos));
if(it != m_tileBlocks[pos.z].end())
return it->second.get(pos);
return m_nulltile;
}
void Map::cleanTile(const Position& pos)
{
if(!pos.isMapPosition())
return;
auto it = m_tileBlocks[pos.z].find(getBlockIndex(pos));
if(it != m_tileBlocks[pos.z].end()) {
TileBlock& block = it->second;
if(const TilePtr& tile = block.get(pos)) {
tile->clean();
if(tile->canErase())
block.remove(pos);
notificateTileUpdateToMapViews(pos);
}
}
}
void Map::addCreature(const CreaturePtr& creature)
{
m_knownCreatures[creature->getId()] = creature;
}
CreaturePtr Map::getCreatureById(uint32 id)
{
auto it = m_knownCreatures.find(id);
if(it == m_knownCreatures.end())
return nullptr;
return it->second;
}
void Map::removeCreatureById(uint32 id)
{
if(id == 0)
return;
auto it = m_knownCreatures.find(id);
if(it != m_knownCreatures.end())
m_knownCreatures.erase(it);
}
void Map::setCentralPosition(const Position& centralPosition)
{
m_centralPosition = centralPosition;
// remove creatures from tiles that we are not aware anymore
for(const auto& pair : m_knownCreatures) {
const CreaturePtr& creature = pair.second;
if(!isAwareOfPosition(creature->getPosition()))
removeThing(creature);
}
// this fixes local player position when the local player is removed from the map,
// the local player is removed from the map when there are too many creatures on his tile,
// so there is no enough stackpos to the server send him
g_dispatcher.addEvent([this] {
LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
if(!localPlayer || localPlayer->getPosition() == m_centralPosition)
return;
TilePtr tile = localPlayer->getTile();
if(tile && tile->hasThing(localPlayer))
return;
Position oldPos = localPlayer->getPosition();
Position pos = m_centralPosition;
if(oldPos != pos) {
if(!localPlayer->isRemoved())
localPlayer->onDisappear();
localPlayer->setPosition(pos);
localPlayer->onAppear();
g_logger.debug("forced player position update");
}
});
for(const MapViewPtr& mapView : m_mapViews)
mapView->onMapCenterChange(centralPosition);
}
std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
{
return getSpectatorsInRange(centerPos, multiFloor, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
}
std::vector<CreaturePtr> Map::getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange)
{
return getSpectatorsInRangeEx(centerPos, multiFloor, xRange, xRange, yRange, yRange);
}
std::vector<CreaturePtr> Map::getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange)
{
int minZRange = 0;
int maxZRange = 0;
std::vector<CreaturePtr> creatures;
if(multiFloor) {
minZRange = 0;
maxZRange = Otc::MAX_Z;
}
//TODO: optimize
//TODO: get creatures from other floors corretly
//TODO: delivery creatures in distance order
for(int iz=-minZRange; iz<=maxZRange; ++iz) {
for(int iy=-minYRange; iy<=maxYRange; ++iy) {
for(int ix=-minXRange; ix<=maxXRange; ++ix) {
TilePtr tile = getTile(centerPos.translated(ix,iy,iz));
if(!tile)
continue;
auto tileCreatures = tile->getCreatures();
creatures.insert(creatures.end(), tileCreatures.rbegin(), tileCreatures.rend());
}
}
}
return creatures;
}
bool Map::isLookPossible(const Position& pos)
{
TilePtr tile = getTile(pos);
return tile && tile->isLookPossible();
}
bool Map::isCovered(const Position& pos, int firstFloor)
{
// check for tiles on top of the postion
Position tilePos = pos;
while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
TilePtr tile = getTile(tilePos);
// the below tile is covered when the above tile has a full ground
if(tile && tile->isFullGround())
return true;
}
return false;
}
bool Map::isCompletelyCovered(const Position& pos, int firstFloor)
{
const TilePtr& checkTile = getTile(pos);
Position tilePos = pos;
while(tilePos.coveredUp() && tilePos.z >= firstFloor) {
bool covered = true;
bool done = false;
// check in 2x2 range tiles that has no transparent pixels
for(int x=0;x<2 && !done;++x) {
for(int y=0;y<2 && !done;++y) {
const TilePtr& tile = getTile(tilePos.translated(-x, -y));
if(!tile || !tile->isFullyOpaque()) {
covered = false;
done = true;
} else if(x==0 && y==0 && (!checkTile || checkTile->isSingleDimension())) {
done = true;
}
}
}
if(covered)
return true;
}
return false;
}
bool Map::isAwareOfPosition(const Position& pos)
{
if(pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor())
return false;
Position groundedPos = pos;
while(groundedPos.z != m_centralPosition.z) {
if(groundedPos.z > m_centralPosition.z)
groundedPos.coveredUp();
else
groundedPos.coveredDown();
}
return m_centralPosition.isInRange(groundedPos, Otc::AWARE_X_LEFT_TILES,
Otc::AWARE_X_RIGHT_TILES,
Otc::AWARE_Y_TOP_TILES,
Otc::AWARE_Y_BOTTOM_TILES);
}
int Map::getFirstAwareFloor()
{
if(m_centralPosition.z > Otc::SEA_FLOOR)
return m_centralPosition.z-Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
else
return 0;
}
int Map::getLastAwareFloor()
{
if(m_centralPosition.z > Otc::SEA_FLOOR)
return std::min(m_centralPosition.z+Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
else
return Otc::SEA_FLOOR;
}
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxSteps, int flags)
{
// pathfinding using A* search algorithm
// as described in http://en.wikipedia.org/wiki/A*_search_algorithm
struct Node {
Node(const Position& pos) : cost(0), totalCost(0), steps(0), pos(pos), prev(nullptr), dir(Otc::InvalidDirection), evaluated(false) { }
bool operator<(const Node& other) const { return totalCost < other.totalCost; }
float cost;
float totalCost;
int steps;
Position pos;
Node *prev;
Otc::Direction dir;
bool evaluated;
};
struct LessNode : std::binary_function<Node*, Node*, bool> {
bool operator()(Node* a, Node* b) const {
return b->totalCost < a->totalCost;
}
};
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> ret;
std::vector<Otc::Direction>& dirs = std::get<0>(ret);
Otc::PathFindResult& result = std::get<1>(ret);
result = Otc::PathFindResultNoWay;
if(startPos == goalPos) {
result = Otc::PathFindResultSamePosition;
return ret;
}
if(startPos.z != goalPos.z) {
result = Otc::PathFindResultImpossible;
return ret;
}
if(startPos.distance(goalPos) > maxSteps) {
result = Otc::PathFindResultTooFar;
return ret;
}
std::unordered_map<Position, Node*, PositionHasher> nodes;
std::priority_queue<Node*, std::vector<Node*>, LessNode> searchList;
Node *currentNode = new Node(startPos);
currentNode->pos = startPos;
nodes[startPos] = currentNode;
Node *foundNode = nullptr;
while(currentNode) {
// too far
if(currentNode->steps >= maxSteps) {
result = Otc::PathFindResultTooFar;
break;
}
// path found
if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost))
foundNode = currentNode;
// cost too high
if(foundNode && currentNode->totalCost >= foundNode->cost)
break;
for(int i=-1;i<=1;++i) {
for(int j=-1;j<=1;++j) {
if(i == 0 && j == 0)
continue;
Position neighborPos = currentNode->pos.translated(i, j);
const TilePtr& tile = getTile(neighborPos);
float walkFactor = 0;
if(neighborPos != goalPos) {
/*
Known Issue with Otc::PathFindAllowNullTiles flag:
If you are above ground floor this will attempt to path over null
tiles, need to rework this for "fly servers" and blank map click,
but it is breaking normal path finding.
*/
if(!(flags & Otc::PathFindAllowNullTiles) && !tile)
walkFactor = 1.0f;
if(tile) {
if(!(flags & Otc::PathFindAllowCreatures) && tile->hasCreature())
continue;
if(!(flags & Otc::PathFindAllowNonPathable) && !tile->isPathable())
continue;
if(!(flags & Otc::PathFindAllowNonWalkable) && !tile->isWalkable())
continue;
}
}
Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos);
if(walkDir >= Otc::NorthEast)
walkFactor += 3.0f;
else
walkFactor += 1.0f;
int groundSpeed = tile ? tile->getGroundSpeed() : 100;
float cost = currentNode->cost + (groundSpeed * walkFactor) / 100.0f;
Node *neighborNode;
if(nodes.find(neighborPos) == nodes.end()) {
neighborNode = new Node(neighborPos);
nodes[neighborPos] = neighborNode;
} else {
neighborNode = nodes[neighborPos];
if(neighborNode->cost < cost)
continue;
}
neighborNode->prev = currentNode;
neighborNode->cost = cost;
neighborNode->steps = currentNode->steps + 1;
neighborNode->totalCost = neighborNode->cost + neighborPos.distance(goalPos);
neighborNode->dir = walkDir;
neighborNode->evaluated = false;
searchList.push(neighborNode);
}
}
currentNode->evaluated = true;
currentNode = nullptr;
while(searchList.size() > 0 && !currentNode) {
Node *node = searchList.top();
searchList.pop();
if(!node->evaluated)
currentNode = node;
}
}
if(foundNode) {
currentNode = foundNode;
while(currentNode) {
dirs.push_back(currentNode->dir);
currentNode = currentNode->prev;
}
dirs.pop_back();
std::reverse(dirs.begin(), dirs.end());
result = Otc::PathFindResultOk;
}
for(auto it : nodes)
delete it.second;
return ret;
}

216
src/client/map.h Normal file
View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MAP_H
#define MAP_H
#include "creature.h"
#include "houses.h"
#include "towns.h"
#include "creatures.h"
#include "animatedtext.h"
#include "statictext.h"
#include "tile.h"
#include <framework/core/clock.h>
enum OTBM_ItemAttr
{
OTBM_ATTR_DESCRIPTION = 1,
OTBM_ATTR_EXT_FILE = 2,
OTBM_ATTR_TILE_FLAGS = 3,
OTBM_ATTR_ACTION_ID = 4,
OTBM_ATTR_UNIQUE_ID = 5,
OTBM_ATTR_TEXT = 6,
OTBM_ATTR_DESC = 7,
OTBM_ATTR_TELE_DEST = 8,
OTBM_ATTR_ITEM = 9,
OTBM_ATTR_DEPOT_ID = 10,
OTBM_ATTR_SPAWN_FILE = 11,
OTBM_ATTR_RUNE_CHARGES = 12,
OTBM_ATTR_HOUSE_FILE = 13,
OTBM_ATTR_HOUSEDOORID = 14,
OTBM_ATTR_COUNT = 15,
OTBM_ATTR_DURATION = 16,
OTBM_ATTR_DECAYING_STATE = 17,
OTBM_ATTR_WRITTENDATE = 18,
OTBM_ATTR_WRITTENBY = 19,
OTBM_ATTR_SLEEPERGUID = 20,
OTBM_ATTR_SLEEPSTART = 21,
OTBM_ATTR_CHARGES = 22,
OTBM_ATTR_CONTAINER_ITEMS = 23,
OTBM_ATTR_ATTRIBUTE_MAP = 128,
/// just random numbers, they're not actually used by the binary reader...
OTBM_ATTR_WIDTH = 129,
OTBM_ATTR_HEIGHT = 130
};
enum OTBM_NodeTypes_t
{
OTBM_ROOTV2 = 1,
OTBM_MAP_DATA = 2,
OTBM_ITEM_DEF = 3,
OTBM_TILE_AREA = 4,
OTBM_TILE = 5,
OTBM_ITEM = 6,
OTBM_TILE_SQUARE = 7,
OTBM_TILE_REF = 8,
OTBM_SPAWNS = 9,
OTBM_SPAWN_AREA = 10,
OTBM_MONSTER = 11,
OTBM_TOWNS = 12,
OTBM_TOWN = 13,
OTBM_HOUSETILE = 14,
OTBM_WAYPOINTS = 15,
OTBM_WAYPOINT = 16
};
enum {
OTCM_SIGNATURE = 0x4D43544F,
OTCM_VERSION = 1
};
enum {
BLOCK_SIZE = 32
};
class TileBlock {
public:
TileBlock() { m_tiles.fill(nullptr); }
const TilePtr& create(const Position& pos) {
TilePtr& tile = m_tiles[getTileIndex(pos)];
tile = TilePtr(new Tile(pos));
return tile;
}
const TilePtr& getOrCreate(const Position& pos) {
TilePtr& tile = m_tiles[getTileIndex(pos)];
if(!tile)
tile = TilePtr(new Tile(pos));
return tile;
}
const TilePtr& get(const Position& pos) { return m_tiles[getTileIndex(pos)]; }
void remove(const Position& pos) { m_tiles[getTileIndex(pos)] = nullptr; }
uint getTileIndex(const Position& pos) { return ((pos.y % BLOCK_SIZE) * BLOCK_SIZE) + (pos.x % BLOCK_SIZE); }
const std::array<TilePtr, BLOCK_SIZE*BLOCK_SIZE>& getTiles() const { return m_tiles; }
private:
std::array<TilePtr, BLOCK_SIZE*BLOCK_SIZE> m_tiles;
};
//@bindsingleton g_map
class Map
{
public:
void terminate();
void addMapView(const MapViewPtr& mapView);
void removeMapView(const MapViewPtr& mapView);
void notificateTileUpdateToMapViews(const Position& pos);
bool loadOtcm(const std::string& fileName);
void saveOtcm(const std::string& fileName);
void loadOtbm(const std::string& fileName, const UIWidgetPtr& pbar = 0);
void saveOtbm(const std::string& fileName, const UIWidgetPtr& pbar = 0);
// otbm attributes (description, size, etc.)
void setHouseFile(const std::string& file) { m_attribs.set(OTBM_ATTR_HOUSE_FILE, file); }
void setSpawnFile(const std::string& file) { m_attribs.set(OTBM_ATTR_SPAWN_FILE, file); }
void setDescription(const std::string& desc) { m_attribs.set(OTBM_ATTR_DESCRIPTION, desc); }
void setWidth(uint16 w) { m_attribs.set(OTBM_ATTR_WIDTH, w); }
void setHeight(uint16 h) { m_attribs.set(OTBM_ATTR_HEIGHT, h); }
std::string getHouseFile() { return m_attribs.get<std::string>(OTBM_ATTR_HOUSE_FILE); }
std::string getSpawnFile() { return m_attribs.get<std::string>(OTBM_ATTR_SPAWN_FILE); }
Size getSize() { return Size(m_attribs.get<uint16>(OTBM_ATTR_WIDTH), m_attribs.get<uint16>(OTBM_ATTR_HEIGHT)); }
std::vector<std::string> getDescriptions() { return stdext::split(m_attribs.get<std::string>(OTBM_ATTR_DESCRIPTION), "\n"); }
void clean();
void cleanDynamicThings();
void cleanTexts();
// thing related
void addThing(const ThingPtr& thing, const Position& pos, int stackPos = -1);
ThingPtr getThing(const Position& pos, int stackPos);
bool removeThing(const ThingPtr& thing);
bool removeThingByPos(const Position& pos, int stackPos);
// tile related
const TilePtr& createTile(const Position& pos);
template <typename... Items>
const TilePtr& createTileEx(const Position& pos, const Items&... items);
const TilePtr& getOrCreateTile(const Position& pos);
const TilePtr& getTile(const Position& pos);
void cleanTile(const Position& pos);
// known creature related
void addCreature(const CreaturePtr& creature);
CreaturePtr getCreatureById(uint32 id);
void removeCreatureById(uint32 id);
std::vector<CreaturePtr> getSpectators(const Position& centerPos, bool multiFloor);
std::vector<CreaturePtr> getSpectatorsInRange(const Position& centerPos, bool multiFloor, int xRange, int yRange);
std::vector<CreaturePtr> getSpectatorsInRangeEx(const Position& centerPos, bool multiFloor, int minXRange, int maxXRange, int minYRange, int maxYRange);
void setLight(const Light& light) { m_light = light; }
void setCentralPosition(const Position& centralPosition);
bool isLookPossible(const Position& pos);
bool isCovered(const Position& pos, int firstFloor = 0);
bool isCompletelyCovered(const Position& pos, int firstFloor = 0);
bool isAwareOfPosition(const Position& pos);
Light getLight() { return m_light; }
Position getCentralPosition() { return m_centralPosition; }
int getFirstAwareFloor();
int getLastAwareFloor();
const std::vector<MissilePtr>& getFloorMissiles(int z) { return m_floorMissiles[z]; }
std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; }
std::vector<StaticTextPtr> getStaticTexts() { return m_staticTexts; }
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps, int flags = 0);
private:
uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); }
std::unordered_map<uint, TileBlock> m_tileBlocks[Otc::MAX_Z+1];
std::unordered_map<uint32, CreaturePtr> m_knownCreatures;
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
std::vector<AnimatedTextPtr> m_animatedTexts;
std::vector<StaticTextPtr> m_staticTexts;
std::vector<MapViewPtr> m_mapViews;
std::unordered_map<Position, std::string, PositionHasher> m_waypoints;
Light m_light;
Position m_centralPosition;
Rect m_tilesRect;
stdext::packed_storage<uint8> m_attribs;
static TilePtr m_nulltile;
};
extern Map g_map;
#endif

524
src/client/mapio.cpp Normal file
View File

@@ -0,0 +1,524 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "map.h"
#include "tile.h"
#include "game.h"
#include <framework/core/application.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
#include <framework/xml/tinyxml.h>
#include <framework/ui/uiwidget.h>
void Map::loadOtbm(const std::string& fileName, const UIWidgetPtr& pbar)
{
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName));
fin->cache();
if(!g_things.isOtbLoaded())
stdext::throw_exception("OTB isn't loaded yet to load a map.");
if(fin->getU32())
stdext::throw_exception("Unknown file version detected");
BinaryTreePtr root = fin->getBinaryTree();
if(root->getU8())
stdext::throw_exception("could not read root property!");
uint32 headerVersion = root->getU32();
if(headerVersion > 3)
stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion));
setWidth(root->getU16());
setHeight(root->getU16());
uint32 headerMajorItems = root->getU8();
if(headerMajorItems > g_things.getOtbMajorVersion()) {
stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d",
headerMajorItems, g_things.getOtbMajorVersion()));
}
root->skip(3);
uint32 headerMinorItems = root->getU32();
if(headerMinorItems > g_things.getOtbMinorVersion()) {
g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d or less",
headerMinorItems, g_things.getOtbMinorVersion()));
}
BinaryTreePtr node = root->getChildren()[0];
if(node->getU8() != OTBM_MAP_DATA)
stdext::throw_exception("Could not read root data node");
while (node->canRead()) {
uint8 attribute = node->getU8();
std::string tmp = node->getString();
switch (attribute) {
case OTBM_ATTR_DESCRIPTION:
setDescription(tmp);
break;
case OTBM_ATTR_SPAWN_FILE:
setSpawnFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp);
break;
case OTBM_ATTR_HOUSE_FILE:
setHouseFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp);
break;
default:
stdext::throw_exception(stdext::format("Invalid attribute '%d'", (int)attribute));
}
}
for(const BinaryTreePtr& nodeMapData : node->getChildren()) {
uint8 mapDataType = nodeMapData->getU8();
if(mapDataType == OTBM_TILE_AREA) {
Position basePos = nodeMapData->getPosition();
unsigned int pbarvalue=0;
for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) {
uint8 type = nodeTile->getU8();
if(type != OTBM_TILE && type != OTBM_HOUSETILE)
stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type));
HousePtr house = nullptr;
uint32 flags = TILESTATE_NONE;
Position pos = basePos + nodeTile->getPoint();
if(type == OTBM_HOUSETILE) {
uint32 hId = nodeTile->getU32();
TilePtr tile = getOrCreateTile(pos);
if(!(house = g_houses.getHouse(hId))) {
house = HousePtr(new House(hId));
g_houses.addHouse(house);
}
house->setTile(tile);
}
while(nodeTile->canRead()) {
uint8 tileAttr = nodeTile->getU8();
switch (tileAttr) {
case OTBM_ATTR_TILE_FLAGS: {
uint32 _flags = nodeTile->getU32();
if((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE)
flags |= TILESTATE_PROTECTIONZONE;
else if((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE)
flags |= TILESTATE_OPTIONALZONE;
else if((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE)
flags |= TILESTATE_HARDCOREZONE;
if((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT)
flags |= TILESTATE_NOLOGOUT;
if((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH)
flags |= TILESTATE_REFRESH;
break;
}
case OTBM_ATTR_ITEM: {
addThing(Item::createFromOtb(nodeTile->getU16()), pos);
break;
}
default: {
stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %s",
(int)tileAttr, stdext::to_string(pos)));
}
}
}
for(const BinaryTreePtr& nodeItem : nodeTile->getChildren()) {
if(nodeItem->getU8() != OTBM_ITEM)
stdext::throw_exception("invalid item node");
ItemPtr item = Item::createFromOtb(nodeItem->getU16());
item->unserializeItem(nodeItem);
if(item->isContainer()) {
for(const BinaryTreePtr& containerItem : nodeItem->getChildren()) {
if(containerItem->getU8() != OTBM_ITEM)
stdext::throw_exception("invalid container item node");
ItemPtr cItem = Item::createFromOtb(containerItem->getU16());
cItem->unserializeItem(containerItem);
item->addContainerItem(cItem);
}
}
if(house && item->isMoveable()) {
g_logger.warning(stdext::format("Movable item found in house: %d at pos %s - escaping...", item->getId(), stdext::to_string(pos)));
item.reset();
}
addThing(item, pos);
}
if(const TilePtr& tile = getTile(pos)) {
if(house)
tile->setHouseId(house->getId());
tile->setFlags((tileflags_t)flags);
//if(!(++pbarvalue % 8192) && pbar);
}
}
} else if(mapDataType == OTBM_TOWNS) {
TownPtr town = nullptr;
for(const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) {
if(nodeTown->getU8() != OTBM_TOWN)
stdext::throw_exception("invalid town node.");
uint32 townId = nodeTown->getU32();
std::string townName = nodeTown->getString();
Position townCoords = nodeTown->getPosition();
if(!(town = g_towns.getTown(townId))) {
town = TownPtr(new Town(townId, townName, townCoords));
g_towns.addTown(town);
}
}
} else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) {
for(const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) {
if(nodeWaypoint->getU8() != OTBM_WAYPOINT)
stdext::throw_exception("invalid waypoint node.");
std::string name = nodeWaypoint->getString();
Position waypointPos = nodeWaypoint->getPosition();
if(waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end())
m_waypoints.insert(std::make_pair(waypointPos, name));
}
} else
stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType));
}
fin->close();
}
void Map::saveOtbm(const std::string& fileName, const UIWidgetPtr&/* pbar*/)
{
FileStreamPtr fin = g_resources.createFile(fileName);
if(!fin)
stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
fin->cache();
std::string dir;
if(fileName.find_last_of('/') == std::string::npos)
dir = g_resources.getWorkDir();
else
dir = fileName.substr(0, fileName.find_last_of('/'));
uint32 version = 0;
if(g_things.getOtbMajorVersion() < ClientVersion820)
version = 1;
else
version = 2;
/// Usually when a map has empty house/spawn file it means the map is new.
/// TODO: Ask the user for a map name instead of those ugly uses of substr
std::string::size_type sep_pos;
std::string houseFile = getHouseFile();
std::string spawnFile = getSpawnFile();
std::string cpyf;
if((sep_pos = fileName.rfind('.')) != std::string::npos && stdext::ends_with(fileName, ".otbm"))
cpyf = fileName.substr(0, sep_pos);
if(houseFile.empty())
houseFile = cpyf + "-houses.xml";
if(spawnFile.empty())
spawnFile = cpyf + "-spawns.xml";
/// we only need the filename to save to, the directory should be resolved by the OTBM loader not here
if((sep_pos = spawnFile.rfind('/')) != std::string::npos)
spawnFile = spawnFile.substr(sep_pos + 1);
if((sep_pos = houseFile.rfind('/')) != std::string::npos)
houseFile = houseFile.substr(sep_pos + 1);
fin->addU32(0); // file version
OutputBinaryTreePtr root(new OutputBinaryTree(fin));
{
root->addU32(version);
Size mapSize = getSize();
root->addU16(mapSize.width());
root->addU16(mapSize.height());
root->addU32(g_things.getOtbMajorVersion());
root->addU32(g_things.getOtbMinorVersion());
root->startNode(OTBM_MAP_DATA);
{
// own description.
for(const auto& desc : getDescriptions()) {
root->addU8(OTBM_ATTR_DESCRIPTION);
root->addString(desc);
}
// special one
root->addU8(OTBM_ATTR_DESCRIPTION);
root->addString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion()));
// spawn file.
root->addU8(OTBM_ATTR_SPAWN_FILE);
root->addString(spawnFile);
// house file.
if(version > 1) {
root->addU8(OTBM_ATTR_HOUSE_FILE);
root->addString(houseFile);
}
int px = -1, py = -1, pz =-1;
bool firstNode = true;
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
for(const auto& it : m_tileBlocks[z]) {
const TileBlock& block = it.second;
for(const TilePtr& tile : block.getTiles()) {
if(!tile || tile->isEmpty())
continue;
const Position& pos = tile->getPosition();
if(!pos.isValid())
continue;
if(pos.x < px || pos.x >= px + 256
|| pos.y < py || pos.y >= py + 256
|| pos.z != pz) {
if(!firstNode)
root->endNode(); /// OTBM_TILE_AREA
firstNode = false;
root->startNode(OTBM_TILE_AREA);
px = pos.x & 0xFF00;
py = pos.y & 0xFF00;
pz = pos.z;
root->addPos(Position(px, py, pz));
}
root->startNode(tile->isHouseTile() ? OTBM_HOUSETILE : OTBM_TILE);
root->addPoint(Point(pos.x, pos.y) & 0xFF);
if(tile->isHouseTile())
root->addU32(tile->getHouseId());
if(tile->getFlags()) {
root->addU8(OTBM_ATTR_TILE_FLAGS);
root->addU32(tile->getFlags());
}
const auto& itemList = tile->getItems();
const ItemPtr& ground = tile->getGround();
if(ground) {
// Those types are called "complex" needs other stuff to be written.
// For containers, there is container items, for depot, depot it and so on.
if(!ground->isContainer() && !ground->isDepot()
&& !ground->isDoor() && !ground->isTeleport()) {
root->addU8(OTBM_ATTR_ITEM);
root->addU16(ground->getServerId());
} else
ground->serializeItem(root);
}
for(const ItemPtr& item : itemList)
if(!item->isGround())
item->serializeItem(root);
root->endNode(); // OTBM_TILE
}
}
}
if(!firstNode)
root->endNode(); // OTBM_TILE_AREA
root->startNode(OTBM_TOWNS);
for(const TownPtr& town : g_towns.getTowns()) {
root->addU32(town->getId());
root->addString(town->getName());
root->addPos(town->getPos());
}
root->endNode();
if(version > 1) {
root->startNode(OTBM_WAYPOINTS);
for(const auto& it : m_waypoints) {
root->addString(it.second);
root->addPos(it.first);
}
root->endNode();
}
}
root->endNode(); // OTBM_MAP_DATA
}
root->endNode();
fin->flush();
fin->close();
}
bool Map::loadOtcm(const std::string& fileName)
{
try {
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception("unable to open file");
stdext::timer loadTimer;
fin->cache();
uint32 signature = fin->getU32();
if(signature != OTCM_SIGNATURE)
stdext::throw_exception("invalid otcm file");
uint16 start = fin->getU16();
uint16 version = fin->getU16();
fin->getU32(); // flags
switch(version) {
case 1: {
fin->getString(); // description
uint32 datSignature = fin->getU32();
fin->getU16(); // protocol version
fin->getString(); // world name
if(datSignature != g_things.getDatSignature())
g_logger.warning("otcm map loaded was created with a different dat signature");
break;
}
default:
stdext::throw_exception("otcm version not supported");
}
fin->seek(start);
while(true) {
Position pos;
pos.x = fin->getU16();
pos.y = fin->getU16();
pos.z = fin->getU8();
// end of file
if(!pos.isValid())
break;
const TilePtr& tile = g_map.createTile(pos);
int stackPos = 0;
while(true) {
int id = fin->getU16();
// end of tile
if(id == 0xFFFF)
break;
int countOrSubType = fin->getU8();
ItemPtr item = Item::create(id);
item->setCountOrSubType(countOrSubType);
if(item->isValid())
tile->addThing(item, stackPos++);
}
}
fin->close();
// well, this is really slow
g_logger.debug(stdext::format("Otcm load time: %.2f seconds", loadTimer.elapsed_seconds()));
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load OTCM map: %s", e.what()));
return false;
}
}
void Map::saveOtcm(const std::string& fileName)
{
try {
stdext::timer saveTimer;
FileStreamPtr fin = g_resources.createFile(fileName);
fin->cache();
//TODO: compression flag with zlib
uint32 flags = 0;
// header
fin->addU32(OTCM_SIGNATURE);
fin->addU16(0); // data start, will be overwritten later
fin->addU16(OTCM_VERSION);
fin->addU32(flags);
// version 1 header
fin->addString("OTCM 1.0"); // map description
fin->addU32(g_things.getDatSignature());
fin->addU16(g_game.getProtocolVersion());
fin->addString(g_game.getWorldName());
// go back and rewrite where the map data starts
uint32 start = fin->tell();
fin->seek(4);
fin->addU16(start);
fin->seek(start);
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
for(const auto& it : m_tileBlocks[z]) {
const TileBlock& block = it.second;
for(const TilePtr& tile : block.getTiles()) {
if(!tile || tile->isEmpty())
continue;
Position pos = tile->getPosition();
fin->addU16(pos.x);
fin->addU16(pos.y);
fin->addU8(pos.z);
for(const ThingPtr& thing : tile->getThings()) {
if(thing->isItem()) {
ItemPtr item = thing->static_self_cast<Item>();
fin->addU16(item->getId());
fin->addU8(item->getCountOrSubType());
}
}
// end of tile
fin->addU16(0xFFFF);
}
}
}
// end of file
Position invalidPos;
fin->addU16(invalidPos.x);
fin->addU16(invalidPos.y);
fin->addU8(invalidPos.z);
fin->flush();
fin->close();
//g_logger.debug(stdext::format("Otcm save time: %.2f seconds", saveTimer.elapsed_seconds()));
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to save OTCM map: %s", e.what()));
}
}

668
src/client/mapview.cpp Normal file
View File

@@ -0,0 +1,668 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "mapview.h"
#include "creature.h"
#include "map.h"
#include "tile.h"
#include "statictext.h"
#include "animatedtext.h"
#include "missile.h"
#include "shadermanager.h"
#include "lightview.h"
#include <framework/graphics/graphics.h>
#include <framework/graphics/image.h>
#include <framework/graphics/framebuffermanager.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/application.h>
#include <framework/core/resourcemanager.h>
enum {
// 3840x2160 => 1080p optimized
// 2560x1440 => 720p optimized
// 1728x972 => 480p optimized
NEAR_VIEW_AREA = 32*32,
MID_VIEW_AREA = 64*64,
FAR_VIEW_AREA = 128*128,
MAX_TILE_DRAWS = NEAR_VIEW_AREA*7
};
MapView::MapView()
{
m_viewMode = NEAR_VIEW;
m_lockedFirstVisibleFloor = -1;
m_cachedFirstVisibleFloor = 7;
m_cachedLastVisibleFloor = 7;
m_updateTilesPos = 0;
m_minimumAmbientLight = 0;
m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS;
m_framebuffer = g_framebuffers.createFrameBuffer();
setVisibleDimension(Size(15, 11));
m_shader = g_shaders.getDefaultMapShader();
}
MapView::~MapView()
{
#ifndef NDEBUG
assert(!g_app.isTerminated());
#endif
}
void MapView::draw(const Rect& rect)
{
// update visible tiles cache when needed
if(m_mustUpdateVisibleTilesCache || m_updateTilesPos > 0)
updateVisibleTilesCache(m_mustUpdateVisibleTilesCache ? 0 : m_updateTilesPos);
float scaleFactor = m_tileSize/(float)Otc::TILE_PIXELS;
Position cameraPosition = getCameraPosition();
int drawFlags = 0;
if(m_viewMode == NEAR_VIEW)
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls |
Otc::DrawItems | Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawMissiles | Otc::DrawAnimations;
else
drawFlags = Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawWalls | Otc::DrawItems;
Size tileSize = Size(1,1) * m_tileSize;
if(m_mustDrawVisibleTilesCache || (drawFlags & Otc::DrawAnimations)) {
m_framebuffer->bind();
if(m_mustCleanFramebuffer) {
Rect clearRect = Rect(0, 0, m_drawDimension * m_tileSize);
g_painter->setColor(Color::black);
g_painter->drawFilledRect(clearRect);
if(m_drawLights) {
m_lightView->reset();
m_lightView->resize(m_framebuffer->getSize());
Light ambientLight;
if(cameraPosition.z <= Otc::SEA_FLOOR) {
ambientLight = g_map.getLight();
} else {
ambientLight.color = 215;
ambientLight.intensity = 0;
}
ambientLight.intensity = std::max<int>(m_minimumAmbientLight*255, ambientLight.intensity);
m_lightView->setGlobalLight(ambientLight);
}
}
g_painter->setColor(Color::white);
auto it = m_cachedVisibleTiles.begin();
auto end = m_cachedVisibleTiles.end();
for(int z=m_cachedLastVisibleFloor;z>=m_cachedFirstVisibleFloor;--z) {
while(it != end) {
const TilePtr& tile = *it;
Position tilePos = tile->getPosition();
if(tilePos.z != z)
break;
else
++it;
if(!m_drawMinimapColors)
tile->draw(transformPositionTo2D(tilePos, cameraPosition), scaleFactor, drawFlags, m_lightView.get());
else {
uint8 c = tile->getMinimapColorByte();
if(c == 0)
continue;
g_painter->setColor(Color::from8bit(c));
g_painter->drawFilledRect(Rect(transformPositionTo2D(tilePos, cameraPosition), tileSize));
}
}
if(drawFlags & Otc::DrawMissiles && !m_drawMinimapColors) {
for(const MissilePtr& missile : g_map.getFloorMissiles(z)) {
missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), scaleFactor, drawFlags & Otc::DrawAnimations, m_lightView.get());
}
}
}
m_framebuffer->release();
// generating mipmaps each frame can be slow in older cards
//m_framebuffer->getTexture()->buildHardwareMipmaps();
m_mustDrawVisibleTilesCache = false;
}
Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * m_tileSize;
if(isFollowingCreature())
drawOffset += m_followingCreature->getWalkOffset() * scaleFactor;
Size srcSize = rect.size();
Size srcVisible = m_visibleDimension * m_tileSize;
srcSize.scale(srcVisible, Fw::KeepAspectRatio);
drawOffset.x += (srcVisible.width() - srcSize.width()) / 2;
drawOffset.y += (srcVisible.height() - srcSize.height()) / 2;
Rect srcRect = Rect(drawOffset, srcSize);
g_painter->setColor(Color::white);
glDisable(GL_BLEND);
g_painter->setShaderProgram(m_shader);
#if 0
// debug source area
g_painter->saveAndResetState();
m_framebuffer->bind();
g_painter->setColor(Color::green);
g_painter->drawBoundingRect(srcRect, 2);
m_framebuffer->release();
g_painter->restoreSavedState();
m_framebuffer->draw(rect);
#else
m_framebuffer->draw(rect, srcRect);
#endif
g_painter->resetShaderProgram();
glEnable(GL_BLEND);
// this could happen if the player position is not known yet
if(!cameraPosition.isValid())
return;
float horizontalStretchFactor = rect.width() / (float)srcRect.width();
float verticalStretchFactor = rect.height() / (float)srcRect.height();
// avoid drawing texts on map in far zoom outs
if(m_viewMode == NEAR_VIEW && m_drawTexts) {
for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
if(!creature->canBeSeen())
continue;
Point creatureOffset = Point(16 - creature->getDisplacementX(), -3 - creature->getDisplacementY());
Position pos = creature->getPosition();
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
p += (creature->getDrawOffset() + creatureOffset) * scaleFactor;
p.x = p.x * horizontalStretchFactor;
p.y = p.y * verticalStretchFactor;
p += rect.topLeft();
creature->drawInformation(p, g_map.isCovered(pos, m_cachedFirstVisibleFloor), rect);
}
}
// lights are drawn after names and before texts
if(m_drawLights)
m_lightView->draw(rect, srcRect);
if(m_viewMode == NEAR_VIEW && m_drawTexts) {
for(const StaticTextPtr& staticText : g_map.getStaticTexts()) {
Position pos = staticText->getPosition();
// ony draw static texts from current camera floor, unless yells
//if(pos.z != cameraPosition.z && !staticText->isYell())
// continue;
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
p.x = p.x * horizontalStretchFactor;
p.y = p.y * verticalStretchFactor;
p += rect.topLeft();
staticText->drawText(p, rect);
}
for(const AnimatedTextPtr& animatedText : g_map.getAnimatedTexts()) {
Position pos = animatedText->getPosition();
// only draw animated texts from visible floors
if(pos.z < m_cachedFirstVisibleFloor || pos.z > m_cachedLastVisibleFloor)
continue;
// dont draw animated texts from covered tiles
if(pos.z != cameraPosition.z && g_map.isCovered(pos, m_cachedFirstVisibleFloor))
continue;
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
p.x = p.x * horizontalStretchFactor;
p.y = p.y * verticalStretchFactor;
p += rect.topLeft();
animatedText->drawText(p, rect);
}
} else if(m_viewMode > NEAR_VIEW) {
// draw a cross in the center instead of our creature
/*
Known Issue: Changing Z axis causes the cross to go off a little bit.
*/
Rect vRect(0, 0, 2, 10);
Rect hRect(0, 0, 10, 2);
g_painter->setColor(Color::white);
if(!m_follow && m_followingCreature)
{
Position pos = m_followingCreature->getPosition();
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
p.x = p.x * horizontalStretchFactor;
p.y = p.y * verticalStretchFactor;
p += rect.topLeft();
vRect.setX(p.x); vRect.setY(p.y - 4);
hRect.setX(p.x - 4); hRect.setY(p.y);
hRect.setWidth(10); hRect.setHeight(2);
vRect.setWidth(2); vRect.setHeight(10);
}
else {
vRect.moveCenter(rect.center());
hRect.moveCenter(rect.center());
}
g_painter->drawFilledRect(vRect);
g_painter->drawFilledRect(hRect);
}
}
void MapView::updateVisibleTilesCache(int start)
{
if(start == 0) {
m_cachedFirstVisibleFloor = calcFirstVisibleFloor();
m_cachedLastVisibleFloor = calcLastVisibleFloor();
assert(m_cachedFirstVisibleFloor >= 0 && m_cachedLastVisibleFloor >= 0 &&
m_cachedFirstVisibleFloor <= Otc::MAX_Z && m_cachedLastVisibleFloor <= Otc::MAX_Z);
if(m_cachedLastVisibleFloor < m_cachedFirstVisibleFloor)
m_cachedLastVisibleFloor = m_cachedFirstVisibleFloor;
m_cachedFloorVisibleCreatures.clear();
m_cachedVisibleTiles.clear();
m_mustCleanFramebuffer = true;
m_mustDrawVisibleTilesCache = true;
m_mustUpdateVisibleTilesCache = false;
m_updateTilesPos = 0;
} else
m_mustCleanFramebuffer = false;
// there is no tile to render on invalid positions
Position cameraPosition = getCameraPosition();
if(!cameraPosition.isValid())
return;
bool stop = false;
// clear current visible tiles cache
m_cachedVisibleTiles.clear();
m_mustDrawVisibleTilesCache = true;
m_updateTilesPos = 0;
// cache visible tiles in draw order
// draw from last floor (the lower) to first floor (the higher)
for(int iz = m_cachedLastVisibleFloor; iz >= m_cachedFirstVisibleFloor && !stop; --iz) {
if(m_viewMode <= FAR_VIEW) {
const int numDiagonals = m_drawDimension.width() + m_drawDimension.height() - 1;
// loop through / diagonals beginning at top left and going to top right
for(int diagonal = 0; diagonal < numDiagonals && !stop; ++diagonal) {
// loop current diagonal tiles
int advance = std::max(diagonal - m_drawDimension.height(), 0);
for(int iy = diagonal - advance, ix = advance; iy >= 0 && ix < m_drawDimension.width() && !stop; --iy, ++ix) {
// only start really looking tiles in the desired start
if(m_updateTilesPos < start) {
m_updateTilesPos++;
continue;
}
// avoid rendering too much tiles at once
if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS && m_viewMode >= HUGE_VIEW) {
stop = true;
break;
}
// position on current floor
//TODO: check position limits
Position tilePos = cameraPosition.translated(ix - m_virtualCenterOffset.x, iy - m_virtualCenterOffset.y);
// adjust tilePos to the wanted floor
tilePos.coveredUp(cameraPosition.z - iz);
if(const TilePtr& tile = g_map.getTile(tilePos)) {
// skip tiles that have nothing
if(!tile->isDrawable())
continue;
// skip tiles that are completely behind another tile
if(g_map.isCompletelyCovered(tilePos, m_cachedFirstVisibleFloor))
continue;
m_cachedVisibleTiles.push_back(tile);
}
m_updateTilesPos++;
}
}
} else {
// cache tiles in spiral mode
static std::vector<Point> m_spiral;
if(start == 0) {
m_spiral.resize(m_drawDimension.area());
int width = m_drawDimension.width();
int height = m_drawDimension.height();
int tpx = width/2 - 2;
int tpy = height/2 - 2;
int count = 0;
Rect area(0, 0, m_drawDimension);
m_spiral[count++] = Point(tpx+1,tpy+1);
for(int step = 1; tpx >= 0 || tpy >= 0; ++step, --tpx, --tpy) {
int qs = 2*step;
Rect lines[4] = {
Rect(tpx, tpy, qs, 1),
Rect(tpx + qs, tpy, 1, qs),
Rect(tpx + 1, tpy + qs, qs, 1),
Rect(tpx, tpy + 1, 1, qs),
};
for(int i=0;i<4;++i) {
int sx = std::max(lines[i].left(), area.left());
int ex = std::min(lines[i].right(), area.right());
int sy = std::max(lines[i].top(), area.top());
int ey = std::min(lines[i].bottom(), area.bottom());
for(int qx=sx;qx<=ex;++qx)
for(int qy=sy;qy<=ey;++qy)
m_spiral[count++] = Point(qx, qy);
}
}
}
for(m_updateTilesPos = start; m_updateTilesPos < (int)m_spiral.size(); ++m_updateTilesPos) {
// avoid rendering too much tiles at once
if((int)m_cachedVisibleTiles.size() > MAX_TILE_DRAWS) {
stop = true;
break;
}
const Point& p = m_spiral[m_updateTilesPos];
Position tilePos = cameraPosition.translated(p.x - m_virtualCenterOffset.x, p.y - m_virtualCenterOffset.y);
tilePos.coveredUp(cameraPosition.z - iz);
if(const TilePtr& tile = g_map.getTile(tilePos)) {
if(tile->isDrawable())
m_cachedVisibleTiles.push_back(tile);
}
}
}
}
if(!stop) {
m_updateTilesPos = 0;
m_spiral.clear();
}
if(start == 0 && m_viewMode <= NEAR_VIEW)
m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false);
}
void MapView::updateGeometry(const Size& visibleDimension, const Size& optimizedSize)
{
int tileSize = 0;
Size bufferSize;
if(!m_drawMinimapColors) {
int possiblesTileSizes[] = {1,2,4,8,16,32};
for(int candidateTileSize : possiblesTileSizes) {
bufferSize = (visibleDimension + Size(3,3)) * candidateTileSize;
if(bufferSize.width() > g_graphics.getMaxTextureSize() || bufferSize.height() > g_graphics.getMaxTextureSize())
break;
tileSize = candidateTileSize;
if(optimizedSize.width() < bufferSize.width() - 3*candidateTileSize && optimizedSize.height() < bufferSize.height() - 3*candidateTileSize)
break;
}
if(tileSize == 0) {
g_logger.traceError("reached max zoom out");
return;
}
} else {
tileSize = 1;
bufferSize = visibleDimension + Size(3,3);
}
Size drawDimension = visibleDimension + Size(3,3);
Point virtualCenterOffset = (drawDimension/2 - Size(1,1)).toPoint();
Point visibleCenterOffset = virtualCenterOffset;
ViewMode viewMode = m_viewMode;
if(m_autoViewMode) {
if(tileSize >= 32 && visibleDimension.area() <= NEAR_VIEW_AREA)
viewMode = NEAR_VIEW;
else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA)
viewMode = MID_VIEW;
else if(tileSize >= 8 && visibleDimension.area() <= FAR_VIEW_AREA)
viewMode = FAR_VIEW;
else
viewMode = HUGE_VIEW;
if(viewMode >= FAR_VIEW)
m_multifloor = false;
else
m_multifloor = true;
}
// draw actually more than what is needed to avoid massive recalculations on huge views
/*
if(viewMode >= HUGE_VIEW) {
Size oldDimension = drawDimension;
drawDimension = (m_framebuffer->getSize() / tileSize);
virtualCenterOffset += (drawDimension - oldDimension).toPoint() / 2;
}
*/
m_viewMode = viewMode;
m_visibleDimension = visibleDimension;
m_drawDimension = drawDimension;
m_tileSize = tileSize;
m_virtualCenterOffset = virtualCenterOffset;
m_visibleCenterOffset = visibleCenterOffset;
m_optimizedSize = optimizedSize;
m_framebuffer->resize(bufferSize);
requestVisibleTilesCacheUpdate();
}
void MapView::onTileUpdate(const Position& pos)
{
if(!m_drawMinimapColors)
requestVisibleTilesCacheUpdate();
}
void MapView::onMapCenterChange(const Position& pos)
{
requestVisibleTilesCacheUpdate();
}
void MapView::lockFirstVisibleFloor(int firstVisibleFloor)
{
m_lockedFirstVisibleFloor = firstVisibleFloor;
requestVisibleTilesCacheUpdate();
}
void MapView::unlockFirstVisibleFloor()
{
m_lockedFirstVisibleFloor = -1;
requestVisibleTilesCacheUpdate();
}
void MapView::setVisibleDimension(const Size& visibleDimension)
{
if(visibleDimension == m_visibleDimension)
return;
if(visibleDimension.width() % 2 != 1 || visibleDimension.height() % 2 != 1) {
g_logger.traceError("visible dimension must be odd");
return;
}
if(visibleDimension < Size(3,3)) {
g_logger.traceError("reach max zoom in");
return;
}
updateGeometry(visibleDimension, m_optimizedSize);
}
void MapView::setViewMode(MapView::ViewMode viewMode)
{
m_viewMode = viewMode;
requestVisibleTilesCacheUpdate();
}
void MapView::setAutoViewMode(bool enable)
{
m_autoViewMode = enable;
if(enable)
updateGeometry(m_visibleDimension, m_optimizedSize);
}
void MapView::optimizeForSize(const Size& visibleSize)
{
updateGeometry(m_visibleDimension, visibleSize);
}
void MapView::followCreature(const CreaturePtr& creature)
{
m_follow = true;
m_followingCreature = creature;
requestVisibleTilesCacheUpdate();
}
void MapView::setCameraPosition(const Position& pos)
{
m_follow = false;
m_customCameraPosition = pos;
requestVisibleTilesCacheUpdate();
}
int MapView::calcFirstVisibleFloor()
{
int z = 7;
// return forced first visible floor
if(m_lockedFirstVisibleFloor != -1) {
z = m_lockedFirstVisibleFloor;
} else {
Position cameraPosition = getCameraPosition();
// this could happens if the player is not known yet
if(cameraPosition.isValid()) {
// avoid rendering multifloors in far views
if(!m_multifloor) {
z = cameraPosition.z;
} else {
// if nothing is limiting the view, the first visible floor is 0
int firstFloor = 0;
// limits to underground floors while under sea level
if(cameraPosition.z > Otc::SEA_FLOOR)
firstFloor = std::max(cameraPosition.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::UNDERGROUND_FLOOR);
// loop in 3x3 tiles around the camera
for(int ix = -1; ix <= 1 && firstFloor < cameraPosition.z; ++ix) {
for(int iy = -1; iy <= 1 && firstFloor < cameraPosition.z; ++iy) {
Position pos = cameraPosition.translated(ix, iy);
// process tiles that we can look through, e.g. windows, doors
if((ix == 0 && iy == 0) || (/*(std::abs(ix) != std::abs(iy)) && */g_map.isLookPossible(pos))) {
Position upperPos = pos;
Position coveredPos = pos;
while(coveredPos.coveredUp() && upperPos.up() && upperPos.z >= firstFloor) {
// check tiles physically above
TilePtr tile = g_map.getTile(upperPos);
if(tile && tile->limitsFloorsView()) {
firstFloor = upperPos.z + 1;
break;
}
// check tiles geometrically above
tile = g_map.getTile(coveredPos);
if(tile && tile->limitsFloorsView()) {
firstFloor = coveredPos.z + 1;
break;
}
}
}
}
}
z = firstFloor;
}
}
}
// just ensure the that the floor is in the valid range
z = std::min(std::max(z, 0), (int)Otc::MAX_Z);
return z;
}
int MapView::calcLastVisibleFloor()
{
if(!m_multifloor)
return calcFirstVisibleFloor();
int z = 7;
Position cameraPosition = getCameraPosition();
// this could happens if the player is not known yet
if(cameraPosition.isValid()) {
// view only underground floors when below sea level
if(cameraPosition.z > Otc::SEA_FLOOR)
z = cameraPosition.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
else
z = Otc::SEA_FLOOR;
}
if(m_lockedFirstVisibleFloor != -1)
z = std::max(m_lockedFirstVisibleFloor, z);
// just ensure the that the floor is in the valid range
z = std::min(std::max(z, 0), (int)Otc::MAX_Z);
return z;
}
Position MapView::getCameraPosition()
{
if(isFollowingCreature())
return m_followingCreature->getPosition();
return m_customCameraPosition;
}
void MapView::setDrawMinimapColors(bool enable)
{
if(m_drawMinimapColors == enable)
return;
m_drawMinimapColors = enable;
updateGeometry(m_visibleDimension, m_optimizedSize);
requestVisibleTilesCacheUpdate();
m_smooth = !enable;
m_framebuffer->setSmooth(m_smooth);
}
void MapView::setDrawLights(bool enable)
{
if(enable == m_drawLights)
return;
if(enable)
m_lightView = LightViewPtr(new LightView);
else
m_lightView = nullptr;
m_drawLights = enable;
}

158
src/client/mapview.h Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MAPVIEW_H
#define MAPVIEW_H
#include "declarations.h"
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/declarations.h>
#include <framework/luaengine/luaobject.h>
#include <framework/core/declarations.h>
// @bindclass
class MapView : public LuaObject
{
public:
enum ViewMode {
NEAR_VIEW,
MID_VIEW,
FAR_VIEW,
HUGE_VIEW
};
MapView();
~MapView();
void draw(const Rect& rect);
private:
void updateGeometry(const Size& visibleDimension, const Size& optimizedSize);
void updateVisibleTilesCache(int start = 0);
void requestVisibleTilesCacheUpdate() { m_mustUpdateVisibleTilesCache = true; }
protected:
void onTileUpdate(const Position& pos);
void onMapCenterChange(const Position& pos);
friend class Map;
public:
// floor visibility related
void lockFirstVisibleFloor(int firstVisibleFloor);
void unlockFirstVisibleFloor();
int getLockedFirstVisibleFloor() { return m_lockedFirstVisibleFloor; }
void setMultifloor(bool enable) { m_multifloor = enable; requestVisibleTilesCacheUpdate(); }
bool isMultifloor() { return m_multifloor; }
// map dimension related
void setVisibleDimension(const Size& visibleDimension);
Size getVisibleDimension() { return m_visibleDimension; }
int getTileSize() { return m_tileSize; }
Point getVisibleCenterOffset() { return m_visibleCenterOffset; }
int getCachedFirstVisibleFloor() { return m_cachedFirstVisibleFloor; }
int getCachedLastVisibleFloor() { return m_cachedLastVisibleFloor; }
// view mode related
void setViewMode(ViewMode viewMode);
ViewMode getViewMode() { return m_viewMode; }
void optimizeForSize(const Size& visibleSize);
void setAutoViewMode(bool enable);
bool isAutoViewModeEnabled() { return m_autoViewMode; }
// camera related
void followCreature(const CreaturePtr& creature);
CreaturePtr getFollowingCreature() { return m_followingCreature; }
bool isFollowingCreature() { return m_followingCreature && m_follow; }
void setCameraPosition(const Position& pos);
Position getCameraPosition();
void setMinimumAmbientLight(float intensity) { m_minimumAmbientLight = intensity; }
float getMinimumAmbientLight() { return m_minimumAmbientLight; }
// drawing related
void setDrawFlags(Otc::DrawFlags drawFlags) { m_drawFlags = drawFlags; requestVisibleTilesCacheUpdate(); }
Otc::DrawFlags getDrawFlags() { return m_drawFlags; }
void setDrawTexts(bool enable) { m_drawTexts = enable; }
bool isDrawingTexts() { return m_drawTexts; }
void setDrawMinimapColors(bool enable);
bool isDrawingMinimapColors() { return m_drawMinimapColors; }
void setAnimated(bool animated) { m_animated = animated; requestVisibleTilesCacheUpdate(); }
bool isAnimating() { return m_animated; }
void setDrawLights(bool enable);
bool isDrawingLights() { return m_drawLights; }
void setShader(const PainterShaderProgramPtr& shader) { m_shader = shader; }
PainterShaderProgramPtr getShader() { return m_shader; }
MapViewPtr asMapView() { return static_self_cast<MapView>(); }
private:
int calcFirstVisibleFloor();
int calcLastVisibleFloor();
Point transformPositionTo2D(const Position& position, const Position& relativePosition) {
return Point((m_virtualCenterOffset.x + (position.x - relativePosition.x) - (relativePosition.z - position.z)) * m_tileSize,
(m_virtualCenterOffset.y + (position.y - relativePosition.y) - (relativePosition.z - position.z)) * m_tileSize);
}
int m_lockedFirstVisibleFloor;
int m_cachedFirstVisibleFloor;
int m_cachedLastVisibleFloor;
int m_tileSize;
int m_updateTilesPos;
Size m_drawDimension;
Size m_visibleDimension;
Size m_optimizedSize;
Point m_virtualCenterOffset;
Point m_visibleCenterOffset;
Position m_customCameraPosition;
stdext::boolean<true> m_mustUpdateVisibleTilesCache;
stdext::boolean<true> m_mustDrawVisibleTilesCache;
stdext::boolean<true> m_mustCleanFramebuffer;
stdext::boolean<true> m_multifloor;
stdext::boolean<true> m_animated;
stdext::boolean<true> m_autoViewMode;
stdext::boolean<true> m_drawTexts;
stdext::boolean<true> m_smooth;
stdext::boolean<false> m_drawMinimapColors;
stdext::boolean<false> m_drawLights;
stdext::boolean<true> m_follow;
std::vector<TilePtr> m_cachedVisibleTiles;
std::vector<CreaturePtr> m_cachedFloorVisibleCreatures;
CreaturePtr m_followingCreature;
FrameBufferPtr m_framebuffer;
PainterShaderProgramPtr m_shader;
ViewMode m_viewMode;
Otc::DrawFlags m_drawFlags;
std::vector<Point> m_spiral;
LightViewPtr m_lightView;
float m_minimumAmbientLight;
};
#endif

25
src/client/minimap.cpp Normal file
View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "minimap.h"

66
src/client/minimap.h Normal file
View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MINIMAP_H
#define MINIMAP_H
#include "global.h"
#include <framework/graphics/image.h>
/*
enum {
MINIMAP_AREA_SIZE = 32
};
struct MinimapArea
{
ImagePtr img;
TexturePtr tex;
uint8 colors[MINIMAP_AREA_SIZE][MINIMAP_AREA_SIZE];
stdext::boolean<true> mustUpdate;
};
class Minimap
{
public:
void init();
void terminate();
void loadOtmm();
void saveOtmm();
void updateTile(const Position& pos, uint8 color);
private:
struct MinimaAreaHasher : std::unary_function<Position, std::size_t> {
std::size_t operator()(const Position& pos) const {
return ((pos.x/MINIMAP_AREA_SIZE) * 0x8000 + (pos.y/MINIMAP_AREA_SIZE)) * 16 + pos.z;
}
};
std::unordered_map<Position, ImagePtr, MinimaAreaHasher> m_areas;
};
extern Minimap g_minimap;
*/
#endif

99
src/client/missile.cpp Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "missile.h"
#include "thingtypemanager.h"
#include "map.h"
#include "tile.h"
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
void Missile::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
{
if(m_id == 0 || !animate)
return;
int xPattern = 0, yPattern = 0;
if(m_direction == Otc::NorthWest) {
xPattern = 0;
yPattern = 0;
} else if(m_direction == Otc::North) {
xPattern = 1;
yPattern = 0;
} else if(m_direction == Otc::NorthEast) {
xPattern = 2;
yPattern = 0;
} else if(m_direction == Otc::East) {
xPattern = 2;
yPattern = 1;
} else if(m_direction == Otc::SouthEast) {
xPattern = 2;
yPattern = 2;
} else if(m_direction == Otc::South) {
xPattern = 1;
yPattern = 2;
} else if(m_direction == Otc::SouthWest) {
xPattern = 0;
yPattern = 2;
} else if(m_direction == Otc::West) {
xPattern = 0;
yPattern = 1;
} else {
xPattern = 1;
yPattern = 1;
}
float fraction = m_animationTimer.ticksElapsed() / m_duration;
rawGetThingType()->draw(dest + m_delta * fraction * scaleFactor, scaleFactor, 0, xPattern, yPattern, 0, 0, lightView);
}
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
{
m_direction = fromPosition.getDirectionFromPosition(toPosition);
m_position = fromPosition;
m_delta = Point(toPosition.x - fromPosition.x, toPosition.y - fromPosition.y);
m_duration = 150 * std::sqrt(m_delta.length());
m_delta *= Otc::TILE_PIXELS;
m_animationTimer.restart();
// schedule removal
auto self = asMissile();
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, m_duration);
}
void Missile::setId(uint32 id)
{
if(!g_things.isValidDatId(id, ThingCategoryMissile))
id = 0;
m_id = id;
}
const ThingTypePtr& Missile::getThingType()
{
return g_things.getThingType(m_id, ThingCategoryMissile);
}
ThingType* Missile::rawGetThingType()
{
return g_things.rawGetThingType(m_id, ThingCategoryMissile);
}

59
src/client/missile.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHOT_H
#define SHOT_H
#include <framework/global.h>
#include <framework/core/timer.h>
#include "thing.h"
// @bindclass
class Missile : public Thing
{
enum {
TICKS_PER_FRAME = 75
};
public:
void draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView = nullptr);
void setId(uint32 id);
void setPath(const Position& fromPosition, const Position& toPosition);
uint32 getId() { return m_id; }
MissilePtr asMissile() { return static_self_cast<Missile>(); }
bool isMissile() { return true; }
const ThingTypePtr& getThingType();
ThingType *rawGetThingType();
private:
Timer m_animationTimer;
Point m_delta;
float m_duration;
uint16 m_id;
Otc::Direction m_direction;
};
#endif

131
src/client/outfit.cpp Normal file
View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "outfit.h"
Outfit::Outfit()
{
m_category = ThingCategoryCreature;
m_id = 128;
m_auxId = 0;
resetClothes();
}
Color Outfit::getColor(int color)
{
if(color >= HSI_H_STEPS * HSI_SI_VALUES)
color = 0;
float loc1 = 0, loc2 = 0, loc3 = 0;
if(color % HSI_H_STEPS != 0) {
loc1 = color % HSI_H_STEPS * 1.0/18.0;
loc2 = 1;
loc3 = 1;
switch(int(color / HSI_H_STEPS)) {
case 0:
loc2 = 0.25;
loc3 = 1.00;
break;
case 1:
loc2 = 0.25;
loc3 = 0.75;
break;
case 2:
loc2 = 0.50;
loc3 = 0.75;
break;
case 3:
loc2 = 0.667;
loc3 = 0.75;
break;
case 4:
loc2 = 1.00;
loc3 = 1.00;
break;
case 5:
loc2 = 1.00;
loc3 = 0.75;
break;
case 6:
loc2 = 1.00;
loc3 = 0.50;
break;
}
}
else {
loc1 = 0;
loc2 = 0;
loc3 = 1 - (float)color / HSI_H_STEPS / (float)HSI_SI_VALUES;
}
if(loc3 == 0)
return Color(0, 0, 0);
if(loc2 == 0) {
int loc7 = int(loc3 * 255);
return Color(loc7, loc7, loc7);
}
float red = 0, green = 0, blue = 0;
if(loc1 < 1.0/6.0) {
red = loc3;
blue = loc3 * (1 - loc2);
green = blue + (loc3 - blue) * 6 * loc1;
}
else if(loc1 < 2.0/6.0) {
green = loc3;
blue = loc3 * (1 - loc2);
red = green - (loc3 - blue) * (6 * loc1 - 1);
}
else if(loc1 < 3.0/6.0) {
green = loc3;
red = loc3 * (1 - loc2);
blue = red + (loc3 - red) * (6 * loc1 - 2);
}
else if(loc1 < 4.0/6.0) {
blue = loc3;
red = loc3 * (1 - loc2);
green = blue - (loc3 - red) * (6 * loc1 - 3);
}
else if(loc1 < 5.0/6.0) {
blue = loc3;
green = loc3 * (1 - loc2);
red = green + (loc3 - green) * (6 * loc1 - 4);
}
else {
red = loc3;
green = loc3 * (1 - loc2);
blue = red - (loc3 - green) * (6 * loc1 - 5);
}
return Color(int(red * 255), int(green * 255), int(blue * 255));
}
void Outfit::resetClothes()
{
setHead(0);
setBody(0);
setLegs(0);
setFeet(0);
setMount(0);
}

74
src/client/outfit.h Normal file
View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef OUTFIT_H
#define OUTFIT_H
#include <framework/util/color.h>
#include "thingtypemanager.h"
class Outfit
{
enum {
HSI_SI_VALUES = 7,
HSI_H_STEPS = 19
};
public:
Outfit();
static Color getColor(int color);
void setId(int id) { m_id = id; }
void setAuxId(int id) { m_auxId = id; }
void setHead(int head) { m_head = head; m_headColor = getColor(head); }
void setBody(int body) { m_body = body; m_bodyColor = getColor(body); }
void setLegs(int legs) { m_legs = legs; m_legsColor = getColor(legs); }
void setFeet(int feet) { m_feet = feet; m_feetColor = getColor(feet); }
void setAddons(int addons) { m_addons = addons; }
void setMount(int mount) { m_mount = mount; }
void setCategory(ThingCategory category) { m_category = category; }
void resetClothes();
int getId() const { return m_id; }
int getAuxId() const { return m_auxId; }
int getHead() const { return m_head; }
int getBody() const { return m_body; }
int getLegs() const { return m_legs; }
int getFeet() const { return m_feet; }
int getAddons() const { return m_addons; }
int getMount() const { return m_mount; }
ThingCategory getCategory() const { return m_category; }
Color getHeadColor() const { return m_headColor; }
Color getBodyColor() const { return m_bodyColor; }
Color getLegsColor() const { return m_legsColor; }
Color getFeetColor() const { return m_feetColor; }
private:
ThingCategory m_category;
int m_id, m_auxId, m_head, m_body, m_legs, m_feet, m_addons, m_mount;
Color m_headColor, m_bodyColor, m_legsColor, m_feetColor;
};
#endif

23
src/client/player.cpp Normal file
View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "player.h"

39
src/client/player.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PLAYER_H
#define PLAYER_H
#include "creature.h"
// @bindclass
class Player : public Creature
{
public:
Player() { }
virtual ~Player() { }
PlayerPtr asPlayer() { return static_self_cast<Player>(); }
bool isPlayer() { return true; }
};
#endif

241
src/client/position.h Normal file
View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef POSITION_H
#define POSITION_H
#include "const.h"
#include <framework/stdext/types.h>
#include <framework/const.h>
#include <framework/util/point.h>
class Position
{
public:
Position() : x(65535), y(65535), z(255) { }
Position(uint16 x, uint16 y, uint8 z) : x(x), y(y), z(z) { }
Position translatedToDirection(Otc::Direction direction) {
Position pos = *this;
switch(direction) {
case Otc::North:
pos.y--;
break;
case Otc::East:
pos.x++;
break;
case Otc::South:
pos.y++;
break;
case Otc::West:
pos.x--;
break;
case Otc::NorthEast:
pos.x++;
pos.y--;
break;
case Otc::SouthEast:
pos.x++;
pos.y++;
break;
case Otc::SouthWest:
pos.x--;
pos.y++;
break;
case Otc::NorthWest:
pos.x--;
pos.y--;
break;
default:
break;
}
return pos;
}
Position translatedToReverseDirection(Otc::Direction direction) {
Position pos = *this;
switch(direction) {
case Otc::North:
pos.y++;
break;
case Otc::East:
pos.x--;
break;
case Otc::South:
pos.y--;
break;
case Otc::West:
pos.x++;
break;
case Otc::NorthEast:
pos.x--;
pos.y++;
break;
case Otc::SouthEast:
pos.x--;
pos.y--;
break;
case Otc::SouthWest:
pos.x++;
pos.y--;
break;
case Otc::NorthWest:
pos.x++;
pos.y++;
break;
default:
break;
}
return pos;
}
Otc::Direction getDirectionFromPosition(const Position& position) const {
int dx = position.x - x;
int dy = position.y - y;
if(dx == 0 && dy == 0)
return Otc::InvalidDirection;
else if(dx == 0) {
if(dy < 0)
return Otc::North;
else if(dy > 0)
return Otc::South;
}
else if(dy == 0) {
if(dx < 0)
return Otc::West;
else if(dx > 0)
return Otc::East;
}
else {
float angle = std::atan2(dy * -1, dx) * RAD_TO_DEC;
if(angle < 0)
angle += 360;
if(angle >= 360 - 22.5 || angle < 0 + 22.5)
return Otc::East;
else if(angle >= 45 - 22.5 && angle < 45 + 22.5)
return Otc::NorthEast;
else if(angle >= 90 - 22.5 && angle < 90 + 22.5)
return Otc::North;
else if(angle >= 135 - 22.5 && angle < 135 + 22.5)
return Otc::NorthWest;
else if(angle >= 180 - 22.5 && angle < 180 + 22.5)
return Otc::West;
else if(angle >= 225 - 22.5 && angle < 225 + 22.5)
return Otc::SouthWest;
else if(angle >= 270 - 22.5 && angle < 270 + 22.5)
return Otc::South;
else if(angle >= 315 - 22.5 && angle < 315 + 22.5)
return Otc::SouthEast;
}
return Otc::InvalidDirection;
}
bool isMapPosition() const { return (x < 65535 && y < 65535 && z <= Otc::MAX_Z); }
bool isValid() const { return !(x == 65535 && y == 65535 && z == 255); }
float distance(const Position& pos) const { return sqrt(pow((pos.x - x), 2) + pow((pos.y - y), 2)); }
int manhattanDistance(const Position& pos) const { return std::abs(pos.x - x) + std::abs(pos.y - y); }
void translate(int dx, int dy, short dz = 0) { x += dx; y += dy; z += dz; }
Position translated(int dx, int dy, short dz = 0) const { Position pos = *this; pos.x += dx; pos.y += dy; pos.z += dz; return pos; }
Position operator+(const Position& other) const { return Position(x + other.x, y + other.y, z + other.z); }
Position& operator+=(const Position& other) { x+=other.x; y+=other.y; z +=other.z; return *this; }
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; }
// Point conversion(s)
Position operator+(const Point& other) const { return Position(x + other.x, y + other.y, z); }
Position& operator+=(const Point& other) { x += other.x; y += other.y; 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; }
bool isInRange(const Position& pos, int xRange, int yRange) const { return std::abs(x-pos.x) <= xRange && std::abs(y-pos.y) <= yRange && z == pos.z; }
bool isInRange(const Position& pos, int minXRange, int maxXRange, int minYRange, int maxYRange) const {
return (pos.x >= x-minXRange && pos.x <= x+maxXRange && pos.y >= y-minYRange && pos.y <= y+maxYRange && pos.z == z);
}
bool up(int n = 1) {
int nz = z-n;
if(nz >= 0 && nz <= Otc::MAX_Z) {
z = nz;
return true;
}
return false;
}
bool down(int n = 1) {
int nz = z+n;
if(nz >= 0 && nz <= Otc::MAX_Z) {
z = nz;
return true;
}
return false;
}
bool coveredUp(int n = 1) {
int nx = x+n, ny = y+n, nz = z-n;
if(nx >= 0 && nx <= 65535 && ny >= 0 && ny <= 65535 && nz >= 0 && nz <= Otc::MAX_Z) {
x = nx; y = ny; z = nz;
return true;
}
return false;
}
bool coveredDown(int n = 1) {
int nx = x-n, ny = y-n, nz = z+n;
if(nx >= 0 && nx <= 65535 && ny >= 0 && ny <= 65535 && nz >= 0 && nz <= Otc::MAX_Z) {
x = nx; y = ny; z = nz;
return true;
}
return false;
}
uint16 x;
uint16 y;
uint8 z;
};
struct PositionHasher : std::unary_function<Position, std::size_t> {
std::size_t operator()(const Position& pos) const {
return (((pos.x * 8192) + pos.y) * 16) + pos.z;
}
};
inline std::ostream& operator<<(std::ostream& out, const Position& pos)
{
out << (int)pos.x << " " << (int)pos.y << " " << (int)pos.z;
return out;
}
inline std::istream& operator>>(std::istream& in, Position& pos)
{
int x, y, z;
in >> x >> y >> z;
pos.x = x;
pos.y = y;
pos.z = z;
return in;
}
#endif

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "protocolcodes.h"
namespace Proto {
std::map<uint8, uint8> messageModesMap;
void buildMessageModesMap(int version) {
messageModesMap.clear();
if(version >= 900) {
for(int i=Otc::MessageNone;i<=Otc::MessageBeyondLast;++i)
messageModesMap[i] = i;
} else if(version >= 861) {
messageModesMap[Otc::MessageNone] = 0;
messageModesMap[Otc::MessageSay] = 1;
messageModesMap[Otc::MessageWhisper] = 2;
messageModesMap[Otc::MessageYell] = 3;
messageModesMap[Otc::MessageNpcTo] = 4;
messageModesMap[Otc::MessageNpcFrom] = 5;
messageModesMap[Otc::MessagePrivateFrom] = 6;
messageModesMap[Otc::MessagePrivateTo] = 6;
messageModesMap[Otc::MessageChannel] = 7;
messageModesMap[Otc::MessageChannelManagement] = 8;
messageModesMap[Otc::MessageGamemasterBroadcast] = 9;
messageModesMap[Otc::MessageGamemasterChannel] = 10;
messageModesMap[Otc::MessageGamemasterPrivateFrom] = 11;
messageModesMap[Otc::MessageGamemasterPrivateTo] = 11;
messageModesMap[Otc::MessageChannelHighlight] = 12;
messageModesMap[Otc::MessageMonsterSay] = 13;
messageModesMap[Otc::MessageMonsterYell] = 14;
messageModesMap[Otc::MessageWarning] = 15;
messageModesMap[Otc::MessageGame] = 16;
messageModesMap[Otc::MessageLogin] = 17;
messageModesMap[Otc::MessageStatus] = 18;
messageModesMap[Otc::MessageLook] = 19;
messageModesMap[Otc::MessageFailure] = 20;
messageModesMap[Otc::MessageBlue] = 21;
messageModesMap[Otc::MessageRed] = 22;
} else if(version >= 854) {
messageModesMap[Otc::MessageNone] = 0;
messageModesMap[Otc::MessageSay] = 1;
messageModesMap[Otc::MessageWhisper] = 2;
messageModesMap[Otc::MessageYell] = 3;
messageModesMap[Otc::MessageNpcTo] = 4;
messageModesMap[Otc::MessageNpcFrom] = 5;
messageModesMap[Otc::MessagePrivateFrom] = 6;
messageModesMap[Otc::MessagePrivateTo] = 6;
messageModesMap[Otc::MessageChannel] = 7;
messageModesMap[Otc::MessageChannelManagement] = 8;
messageModesMap[Otc::MessageRVRChannel] = 9;
messageModesMap[Otc::MessageRVRAnswer] = 10;
messageModesMap[Otc::MessageRVRContinue] = 11;
messageModesMap[Otc::MessageGamemasterBroadcast] = 12;
messageModesMap[Otc::MessageGamemasterChannel] = 13;
messageModesMap[Otc::MessageGamemasterPrivateFrom] = 14;
messageModesMap[Otc::MessageGamemasterPrivateTo] = 14;
messageModesMap[Otc::MessageChannelHighlight] = 15;
// 16, 17, 18 ??
messageModesMap[Otc::MessageRed] = 18;
messageModesMap[Otc::MessageMonsterSay] = 19;
messageModesMap[Otc::MessageMonsterYell] = 20;
messageModesMap[Otc::MessageWarning] = 21;
messageModesMap[Otc::MessageGame] = 22;
messageModesMap[Otc::MessageLogin] = 23;
messageModesMap[Otc::MessageStatus] = 24;
messageModesMap[Otc::MessageLook] = 25;
messageModesMap[Otc::MessageFailure] = 26;
messageModesMap[Otc::MessageBlue] = 27;
} else if(version >= 810) {
messageModesMap[Otc::MessageNone] = 0;
messageModesMap[Otc::MessageSay] = 1;
messageModesMap[Otc::MessageWhisper] = 2;
messageModesMap[Otc::MessageYell] = 3;
messageModesMap[Otc::MessagePrivateFrom] = 4;
messageModesMap[Otc::MessagePrivateTo] = 4;
messageModesMap[Otc::MessageChannel] = 5;
messageModesMap[Otc::MessageRVRChannel] = 6;
messageModesMap[Otc::MessageRVRAnswer] = 7;
messageModesMap[Otc::MessageRVRContinue] = 8;
messageModesMap[Otc::MessageGamemasterBroadcast] = 9;
messageModesMap[Otc::MessageGamemasterChannel] = 10;
messageModesMap[Otc::MessageGamemasterPrivateFrom] = 11;
messageModesMap[Otc::MessageGamemasterPrivateTo] = 11;
messageModesMap[Otc::MessageChannelHighlight] = 12;
// 13, 14, 15 ??
messageModesMap[Otc::MessageMonsterSay] = 16;
messageModesMap[Otc::MessageMonsterYell] = 17;
messageModesMap[Otc::MessageWarning] = 18;
messageModesMap[Otc::MessageGame] = 19;
messageModesMap[Otc::MessageLogin] = 20;
messageModesMap[Otc::MessageStatus] = 21;
messageModesMap[Otc::MessageLook] = 22;
messageModesMap[Otc::MessageFailure] = 23;
messageModesMap[Otc::MessageBlue] = 24;
messageModesMap[Otc::MessageRed] = 25;
}
}
Otc::MessageMode translateMessageModeFromServer(uint8 mode)
{
auto it = std::find_if(messageModesMap.begin(), messageModesMap.end(), [=] (const std::pair<uint8, uint8>& p) { return p.second == mode; });
if(it != messageModesMap.end())
return (Otc::MessageMode)it->first;
return Otc::MessageInvalid;
}
uint8 translateMessageModeToServer(Otc::MessageMode mode)
{
if(mode < 0 || mode >= Otc::LastMessage)
return Otc::MessageInvalid;
auto it = messageModesMap.find(mode);
if(it != messageModesMap.end())
return it->second;
return Otc::MessageInvalid;
}
}

260
src/client/protocolcodes.h Normal file
View File

@@ -0,0 +1,260 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PROTOCOLCODES_H
#define PROTOCOLCODES_H
#include "global.h"
namespace Proto {
enum LoginServerOpts {
LoginServerError = 10,
LoginServerMotd = 20,
LoginServerUpdateNeeded = 30,
LoginServerCharacterList = 100
};
enum CreatureOpcode {
UnknownCreature = 97,
OutdatedCreature = 98,
Creature = 99
};
enum GameServerOpcodes : uint8
{
GameServerInitGame = 10,
GameServerGMActions = 11,
GameServerEnterGame = 15,
GameServerLoginError = 20,
GameServerLoginAdvice = 21,
GameServerLoginWait = 22,
GameServerAddCreature = 23,
GameServerPingBack = 29,
GameServerPing = 30,
GameServerChallange = 31,
GameServerDeath = 40,
// all in game opcodes must be greater than 50
GameServerFirstGameOpcode = 50,
// otclient ONLY
GameServerExtendedOpcode = 50,
// NOTE: add any custom opcodes in this range
// 51 - 99
// original tibia ONLY
GameServerFullMap = 100,
GameServerMapTopRow = 101,
GameServerMapRightRow = 102,
GameServerMapBottomRow = 103,
GameServerMapLeftRow = 104,
GameServerUpdateTile = 105,
GameServerCreateOnMap = 106,
GameServerChangeOnMap = 107,
GameServerDeleteOnMap = 108,
GameServerMoveCreature = 109,
GameServerOpenContainer = 110,
GameServerCloseContainer = 111,
GameServerCreateContainer = 112,
GameServerChangeInContainer = 113,
GameServerDeleteInContainer = 114,
GameServerSetInventory = 120,
GameServerDeleteInventory = 121,
GameServerOpenNpcTrade = 122,
GameServerPlayerGoods = 123,
GameServerCloseNpcTrade = 124,
GameServerOwnTrade = 125,
GameServerCounterTrade = 126,
GameServerCloseTrade = 127,
GameServerAmbient = 130,
GameServerGraphicalEffect = 131,
GameServerTextEffect = 132,
GameServerMissleEffect = 133,
GameServerMarkCreature = 134,
GameServerTrappers = 135,
GameServerCreatureHealth = 140,
GameServerCreatureLight = 141,
GameServerCreatureOutfit = 142,
GameServerCreatureSpeed = 143,
GameServerCreatureSkull = 144,
GameServerCreatureParty = 145,
GameServerCreatureUnpass = 146,
GameServerEditText = 150,
GameServerEditList = 151,
GameServerPlayerDataBasic = 159, // 950
GameServerPlayerData = 160,
GameServerPlayerSkills = 161,
GameServerPlayerState = 162,
GameServerClearTarget = 163,
GameServerSpellDelay = 164, // 870
GameServerSpellGroupDelay = 165, // 870
GameServerMultiUseDelay = 166, // 870
GameServerTalk = 170,
GameServerChannels = 171,
GameServerOpenChannel = 172,
GameServerOpenPrivateChannel = 173,
GameServerRuleViolationChannel = 174,
GameServerRuleViolationRemove = 175,
GameServerRuleViolationCancel = 176,
GameServerRuleViolationLock = 177,
GameServerOpenOwnChannel = 178,
GameServerCloseChannel = 179,
GameServerTextMessage = 180,
GameServerCancelWalk = 181,
GameServerWalkWait = 182,
GameServerFloorChangeUp = 190,
GameServerFloorChangeDown = 191,
GameServerChooseOutfit = 200,
GameServerVipAdd = 210,
GameServerVipState = 211,
GameServerVipLogout = 212,
GameServerTutorialHint = 220,
GameServerAutomapFlag = 221,
GameServerQuestLog = 240,
GameServerQuestLine = 241,
GameServerChannelEvent = 243, // 910
GameServerItemInfo = 244, // 910
GameServerPlayerInventory = 245, // 910
GameServerMarketEnter = 246, // 944
GameServerMarketLeave = 247, // 944
GameServerMarketDetail = 248, // 944
GameServerMarketBrowse = 249, // 944
GameServerShowModalDialog = 250 // 960
};
enum ClientOpcodes : uint8
{
ClientEnterAccount = 1,
ClientPendingGame = 10,
ClientEnterGame = 15,
ClientLeaveGame = 20,
ClientPing = 29,
ClientPingBack = 30,
// all in game opcodes must be equal or greater than 50
ClientFirstGameOpcode = 50,
// otclient ONLY
ClientExtendedOpcode = 50,
// NOTE: add any custom opcodes in this range
// 51 - 99
// original tibia ONLY
ClientAutoWalk = 100,
ClientWalkNorth = 101,
ClientWalkEast = 102,
ClientWalkSouth = 103,
ClientWalkWest = 104,
ClientStop = 105,
ClientWalkNorthEast = 106,
ClientWalkSouthEast = 107,
ClientWalkSouthWest = 108,
ClientWalkNorthWest = 109,
ClientTurnNorth = 111,
ClientTurnEast = 112,
ClientTurnSouth = 113,
ClientTurnWest = 114,
ClientEquipItem = 119, // 910
ClientMove = 120,
ClientInspectNpcTrade = 121,
ClientBuyItem = 122,
ClientSellItem = 123,
ClientCloseNpcTrade = 124,
ClientRequestTrade = 125,
ClientInspectTrade = 126,
ClientAcceptTrade = 127,
ClientRejectTrade = 128,
ClientUseItem = 130,
ClientUseItemWith = 131,
ClientUseOnCreature = 132,
ClientRotateItem = 133,
ClientCloseContainer = 135,
ClientUpContainer = 136,
ClientEditText = 137,
ClientEditList = 138,
ClientLook = 140,
ClientLookCreature = 141,
ClientTalk = 150,
ClientRequestChannels = 151,
ClientJoinChannel = 152,
ClientLeaveChannel = 153,
ClientOpenPrivateChannel = 154,
ClientCloseNpcChannel = 158,
ClientChangeFightModes = 160,
ClientAttack = 161,
ClientFollow = 162,
ClientInviteToParty = 163,
ClientJoinParty = 164,
ClientRevokeInvitation = 165,
ClientPassLeadership = 166,
ClientLeaveParty = 167,
ClientShareExperience = 168,
ClientDisbandParty = 169,
ClientOpenOwnChannel = 170,
ClientInviteToOwnChannel = 171,
ClientExcludeFromOwnChannel = 172,
ClientCancelAttackAndFollow = 190,
ClientUpdateTile = 201,
ClientRefreshContainer = 202,
ClientRequestOutfit = 210,
ClientChangeOutfit = 211,
ClientMount = 212, // 870
ClientAddVip = 220,
ClientRemoveVip = 221,
ClientBugReport = 230,
ClientRuleViolation = 231,
ClientDebugReport = 232,
ClientRequestQuestLog = 240,
ClientRequestQuestLine = 241,
ClientNewRuleViolation = 242, // 910
ClientRequestItemInfo = 243, // 910
ClientMarketLeave = 244, // 944
ClientMarketBrowse = 245, // 944
ClientMarketCreate = 246, // 944
ClientMarketCancel = 247, // 944
ClientMarketAccept = 248, // 944
ClientAnswerModalDialog = 249 // 960
};
enum CreatureType {
CreatureTypePlayer = 0,
CreatureTypeMonster,
CreatureTypeNpc
};
enum CreaturesIdRange {
PlayerStartId = 0x10000000,
PlayerEndId = 0x40000000,
MonsterStartId = 0x40000000,
MonsterEndId = 0x80000000,
NpcStartId = 0x80000000,
NpcEndId = 0xffffffff
};
void buildMessageModesMap(int version);
Otc::MessageMode translateMessageModeFromServer(uint8 mode);
uint8 translateMessageModeToServer(Otc::MessageMode mode);
}
#endif

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "protocolgame.h"
#include "game.h"
#include "player.h"
#include "item.h"
#include "localplayer.h"
void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName)
{
m_accountName = accountName;
m_accountPassword = accountPassword;
m_characterName = characterName;
connect(host, port);
}
void ProtocolGame::onConnect()
{
m_firstRecv = true;
Protocol::onConnect();
m_localPlayer = g_game.getLocalPlayer();
if(g_game.getFeature(Otc::GameProtocolChecksum))
enableChecksum();
if(!g_game.getFeature(Otc::GameChallangeOnLogin))
sendLoginPacket(0, 0);
recv();
}
void ProtocolGame::onRecv(const InputMessagePtr& inputMessage)
{
if(m_firstRecv) {
m_firstRecv = false;
if(g_game.getProtocolVersion() > 810) {
int size = inputMessage->getU16();
if(size != inputMessage->getUnreadSize()) {
g_logger.traceError("invalid message size");
return;
}
}
}
parseMessage(inputMessage);
recv();
}
void ProtocolGame::onError(const boost::system::error_code& error)
{
Protocol::onError(error);
g_game.processConnectionError(error);
}

233
src/client/protocolgame.h Normal file
View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PROTOCOLGAME_H
#define PROTOCOLGAME_H
#include "declarations.h"
#include "protocolcodes.h"
#include <framework/net/protocol.h>
#include "creature.h"
class ProtocolGame : public Protocol
{
public:
void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName);
void send(const OutputMessagePtr& outputMessage);
void sendExtendedOpcode(uint8 opcode, const std::string& buffer);
void sendLoginPacket(uint challangeTimestamp, uint8 challangeRandom);
void sendEnterGame();
void sendLogout();
void sendPing();
void sendPingBack();
void sendAutoWalk(const std::vector<Otc::Direction>& path);
void sendWalkNorth();
void sendWalkEast();
void sendWalkSouth();
void sendWalkWest();
void sendStop();
void sendWalkNorthEast();
void sendWalkSouthEast();
void sendWalkSouthWest();
void sendWalkNorthWest();
void sendTurnNorth();
void sendTurnEast();
void sendTurnSouth();
void sendTurnWest();
void sendEquipItem(int itemId, int countOrSubType);
void sendMove(const Position& fromPos, int itemId, int stackpos, const Position& toPos, int count);
void sendInspectNpcTrade(int itemId, int count);
void sendBuyItem(int itemId, int subType, int amount, bool ignoreCapacity, bool buyWithBackpack);
void sendSellItem(int itemId, int subType, int amount, bool ignoreEquipped);
void sendCloseNpcTrade();
void sendRequestTrade(const Position& pos, int thingId, int stackpos, uint playerId);
void sendInspectTrade(bool counterOffer, int index);
void sendAcceptTrade();
void sendRejectTrade();
void sendUseItem(const Position& position, int itemId, int stackpos, int index);
void sendUseItemWith(const Position& fromPos, int itemId, int fromStackpos, const Position& toPos, int toThingId, int toStackpos);
void sendUseOnCreature(const Position& pos, int thingId, int stackpos, uint creatureId);
void sendRotateItem(const Position& pos, int thingId, int stackpos);
void sendCloseContainer(int containerId);
void sendUpContainer(int containerId);
void sendEditText(uint id, const std::string& text);
void sendEditList(uint id, int doorId, const std::string& text);
void sendLook(const Position& position, int thingId, int stackpos);
void sendLookCreature(uint creatureId);
void sendTalk(Otc::MessageMode mode, int channelId, const std::string& receiver, const std::string& message);
void sendRequestChannels();
void sendJoinChannel(int channelId);
void sendLeaveChannel(int channelId);
void sendOpenPrivateChannel(const std::string& receiver);
void sendCloseNpcChannel();
void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight);
void sendAttack(uint creatureId, uint seq);
void sendFollow(uint creatureId, uint seq);
void sendInviteToParty(uint creatureId);
void sendJoinParty(uint creatureId);
void sendRevokeInvitation(uint creatureId);
void sendPassLeadership(uint creatureId);
void sendLeaveParty();
void sendShareExperience(bool active);
void sendOpenOwnChannel();
void sendInviteToOwnChannel(const std::string& name);
void sendExcludeFromOwnChannel(const std::string& name);
void sendCancelAttackAndFollow();
void sendRefreshContainer(int containerId);
void sendRequestOutfit();
void sendChangeOutfit(const Outfit& outfit);
void sendMountStatus(bool mount);
void sendAddVip(const std::string& name);
void sendRemoveVip(uint playerId);
void sendBugReport(const std::string& comment);
void sendRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment);
void sendDebugReport(const std::string& a, const std::string& b, const std::string& c, const std::string& d);
void sendRequestQuestLog();
void sendRequestQuestLine(int questId);
void sendNewNewRuleViolation(int reason, int action, const std::string& characterName, const std::string& comment, const std::string& translation);
void sendRequestItemInfo(int itemId, int subType, int index);
void sendAnswerModalDialog(int dialog, int button, int choice);
protected:
void onConnect();
void onRecv(const InputMessagePtr& inputMessage);
void onError(const boost::system::error_code& error);
friend class Game;
public:
void addPosition(const OutputMessagePtr& msg, const Position& position);
private:
void parseMessage(const InputMessagePtr& msg);
void parsePendingGame(const InputMessagePtr& msg);
void parseEnterGame(const InputMessagePtr& msg);
void parseInitGame(const InputMessagePtr& msg);
void parseGMActions(const InputMessagePtr& msg);
void parseLoginError(const InputMessagePtr& msg);
void parseLoginAdvice(const InputMessagePtr& msg);
void parseLoginWait(const InputMessagePtr& msg);
void parsePing(const InputMessagePtr& msg);
void parsePingBack(const InputMessagePtr& msg);
void parseChallange(const InputMessagePtr& msg);
void parseDeath(const InputMessagePtr& msg);
void parseMapDescription(const InputMessagePtr& msg);
void parseMapMoveNorth(const InputMessagePtr& msg);
void parseMapMoveEast(const InputMessagePtr& msg);
void parseMapMoveSouth(const InputMessagePtr& msg);
void parseMapMoveWest(const InputMessagePtr& msg);
void parseUpdateTile(const InputMessagePtr& msg);
void parseTileAddThing(const InputMessagePtr& msg);
void parseTileTransformThing(const InputMessagePtr& msg);
void parseTileRemoveThing(const InputMessagePtr& msg);
void parseCreatureMove(const InputMessagePtr& msg);
void parseOpenContainer(const InputMessagePtr& msg);
void parseCloseContainer(const InputMessagePtr& msg);
void parseContainerAddItem(const InputMessagePtr& msg);
void parseContainerUpdateItem(const InputMessagePtr& msg);
void parseContainerRemoveItem(const InputMessagePtr& msg);
void parseAddInventoryItem(const InputMessagePtr& msg);
void parseRemoveInventoryItem(const InputMessagePtr& msg);
void parseOpenNpcTrade(const InputMessagePtr& msg);
void parsePlayerGoods(const InputMessagePtr& msg);
void parseCloseNpcTrade(const InputMessagePtr&);
void parseWorldLight(const InputMessagePtr& msg);
void parseMagicEffect(const InputMessagePtr& msg);
void parseAnimatedText(const InputMessagePtr& msg);
void parseDistanceMissile(const InputMessagePtr& msg);
void parseCreatureMark(const InputMessagePtr& msg);
void parseTrappers(const InputMessagePtr& msg);
void parseCreatureHealth(const InputMessagePtr& msg);
void parseCreatureLight(const InputMessagePtr& msg);
void parseCreatureOutfit(const InputMessagePtr& msg);
void parseCreatureSpeed(const InputMessagePtr& msg);
void parseCreatureSkulls(const InputMessagePtr& msg);
void parseCreatureShields(const InputMessagePtr& msg);
void parseCreatureUnpass(const InputMessagePtr& msg);
void parseEditText(const InputMessagePtr& msg);
void parseEditList(const InputMessagePtr& msg);
void parsePlayerInfo(const InputMessagePtr& msg);
void parsePlayerStats(const InputMessagePtr& msg);
void parsePlayerSkills(const InputMessagePtr& msg);
void parsePlayerState(const InputMessagePtr& msg);
void parsePlayerCancelAttack(const InputMessagePtr& msg);
void parseSpellCooldown(const InputMessagePtr& msg);
void parseSpellGroupCooldown(const InputMessagePtr& msg);
void parseMultiUseCooldown(const InputMessagePtr& msg);
void parseTalk(const InputMessagePtr& msg);
void parseChannelList(const InputMessagePtr& msg);
void parseOpenChannel(const InputMessagePtr& msg);
void parseOpenPrivateChannel(const InputMessagePtr& msg);
void parseOpenOwnPrivateChannel(const InputMessagePtr& msg);
void parseCloseChannel(const InputMessagePtr& msg);
void parseRuleViolationChannel(const InputMessagePtr& msg);
void parseRuleViolationRemove(const InputMessagePtr& msg);
void parseRuleViolationCancel(const InputMessagePtr& msg);
void parseRuleViolationLock(const InputMessagePtr& msg);
void parseOwnTrade(const InputMessagePtr& msg);
void parseCounterTrade(const InputMessagePtr& msg);
void parseCloseTrade(const InputMessagePtr&);
void parseTextMessage(const InputMessagePtr& msg);
void parseCancelWalk(const InputMessagePtr& msg);
void parseWalkWait(const InputMessagePtr& msg);
void parseFloorChangeUp(const InputMessagePtr& msg);
void parseFloorChangeDown(const InputMessagePtr& msg);
void parseOpenOutfitWindow(const InputMessagePtr& msg);
void parseVipAdd(const InputMessagePtr& msg);
void parseVipState(const InputMessagePtr& msg);
void parseVipLogout(const InputMessagePtr& msg);
void parseTutorialHint(const InputMessagePtr& msg);
void parseAutomapFlag(const InputMessagePtr& msg);
void parseQuestLog(const InputMessagePtr& msg);
void parseQuestLine(const InputMessagePtr& msg);
void parseChannelEvent(const InputMessagePtr& msg);
void parseItemInfo(const InputMessagePtr& msg);
void parsePlayerInventory(const InputMessagePtr& msg);
void parseShowModalDialog(const InputMessagePtr& msg);
void parseExtendedOpcode(const InputMessagePtr& msg);
public:
void setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height);
int setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip);
int setTileDescription(const InputMessagePtr& msg, Position position);
Outfit getOutfit(const InputMessagePtr& msg);
ThingPtr getThing(const InputMessagePtr& msg);
ThingPtr getMappedThing(const InputMessagePtr& msg);
CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0);
ItemPtr getItem(const InputMessagePtr& msg, int id = 0);
Position getPosition(const InputMessagePtr& msg);
private:
stdext::boolean<false> m_enableSendExtendedOpcode;
stdext::boolean<false> m_gameInitialized;
stdext::boolean<false> m_mapKnown;
stdext::boolean<true> m_firstRecv;
std::string m_accountName;
std::string m_accountPassword;
std::string m_characterName;
stdext::timer m_pingTimer;
LocalPlayerPtr m_localPlayer;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,782 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "protocolgame.h"
#include "game.h"
void ProtocolGame::send(const OutputMessagePtr& outputMessage)
{
// avoid usage of automated sends (bot modules)
if(!g_game.checkBotProtection())
return;
Protocol::send(outputMessage);
}
void ProtocolGame::sendExtendedOpcode(uint8 opcode, const std::string& buffer)
{
if(m_enableSendExtendedOpcode) {
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientExtendedOpcode);
msg->addU8(opcode);
msg->addString(buffer);
send(msg);
} else {
g_logger.error(stdext::format("Unable to send extended opcode %d, extended opcodes are not enabled", opcode));
}
}
void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRandom)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientPendingGame);
msg->addU16(g_lua.callGlobalField<int>("g_game", "getOsType"));
msg->addU16(g_game.getProtocolVersion());
if(g_game.getProtocolVersion() >= 971) {
msg->addU32(g_game.getClientVersion());
msg->addU8(0); // clientType
}
int paddingBytes = 128;
msg->addU8(0); // first RSA byte must be 0
paddingBytes -= 1;
// xtea key
generateXteaKey();
msg->addU32(m_xteaKey[0]);
msg->addU32(m_xteaKey[1]);
msg->addU32(m_xteaKey[2]);
msg->addU32(m_xteaKey[3]);
msg->addU8(0); // is gm set?
paddingBytes -= 17;
if(g_game.getFeature(Otc::GameProtocolChecksum))
enableChecksum();
if(g_game.getFeature(Otc::GameAccountNames)) {
msg->addString(m_accountName);
msg->addString(m_characterName);
msg->addString(m_accountPassword);
paddingBytes -= 6 + m_accountName.length() + m_characterName.length() + m_accountPassword.length();
} else {
msg->addU32(stdext::from_string<uint32>(m_accountName));
msg->addString(m_characterName);
msg->addString(m_accountPassword);
paddingBytes -= 8 + m_characterName.length() + m_accountPassword.length();
}
if(g_game.getFeature(Otc::GameChallangeOnLogin)) {
msg->addU32(challangeTimestamp);
msg->addU8(challangeRandom);
paddingBytes -= 5;
}
// complete the 128 bytes for rsa encryption with zeros
msg->addPaddingBytes(paddingBytes);
// encrypt with RSA
msg->encryptRsa(128);
send(msg);
enableXteaEncryption();
}
void ProtocolGame::sendEnterGame()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientEnterGame);
send(msg);
}
void ProtocolGame::sendLogout()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientLeaveGame);
send(msg);
}
void ProtocolGame::sendPing()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientPing);
m_pingTimer.restart();
Protocol::send(msg);
}
void ProtocolGame::sendPingBack()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientPingBack);
send(msg);
}
void ProtocolGame::sendAutoWalk(const std::vector<Otc::Direction>& path)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientAutoWalk);
msg->addU8(path.size());
for(Otc::Direction dir : path) {
uint8 byte;
switch(dir) {
case Otc::East:
byte = 1;
break;
case Otc::NorthEast:
byte = 2;
break;
case Otc::North:
byte = 3;
break;
case Otc::NorthWest:
byte = 4;
break;
case Otc::West:
byte = 5;
break;
case Otc::SouthWest:
byte = 6;
break;
case Otc::South:
byte = 7;
break;
case Otc::SouthEast:
byte = 8;
break;
default:
byte = 0;
break;
}
msg->addU8(byte);
}
send(msg);
}
void ProtocolGame::sendWalkNorth()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkNorth);
send(msg);
}
void ProtocolGame::sendWalkEast()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkEast);
send(msg);
}
void ProtocolGame::sendWalkSouth()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkSouth);
send(msg);
}
void ProtocolGame::sendWalkWest()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkWest);
send(msg);
}
void ProtocolGame::sendStop()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientStop);
send(msg);
}
void ProtocolGame::sendWalkNorthEast()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkNorthEast);
send(msg);
}
void ProtocolGame::sendWalkSouthEast()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkSouthEast);
send(msg);
}
void ProtocolGame::sendWalkSouthWest()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkSouthWest);
send(msg);
}
void ProtocolGame::sendWalkNorthWest()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientWalkNorthWest);
send(msg);
}
void ProtocolGame::sendTurnNorth()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientTurnNorth);
send(msg);
}
void ProtocolGame::sendTurnEast()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientTurnEast);
send(msg);
}
void ProtocolGame::sendTurnSouth()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientTurnSouth);
send(msg);
}
void ProtocolGame::sendTurnWest()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientTurnWest);
send(msg);
}
void ProtocolGame::sendEquipItem(int itemId, int countOrSubType)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientEquipItem);
msg->addU16(itemId);
msg->addU8(countOrSubType);
send(msg);
}
void ProtocolGame::sendMove(const Position& fromPos, int thingId, int stackpos, const Position& toPos, int count)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientMove);
addPosition(msg, fromPos);
msg->addU16(thingId);
msg->addU8(stackpos);
addPosition(msg, toPos);
msg->addU8(count);
send(msg);
}
void ProtocolGame::sendInspectNpcTrade(int itemId, int count)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientInspectNpcTrade);
msg->addU16(itemId);
msg->addU8(count);
send(msg);
}
void ProtocolGame::sendBuyItem(int itemId, int subType, int amount, bool ignoreCapacity, bool buyWithBackpack)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientBuyItem);
msg->addU16(itemId);
msg->addU8(subType);
msg->addU8(amount);
msg->addU8(ignoreCapacity ? 0x01 : 0x00);
msg->addU8(buyWithBackpack ? 0x01 : 0x00);
send(msg);
}
void ProtocolGame::sendSellItem(int itemId, int subType, int amount, bool ignoreEquipped)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientSellItem);
msg->addU16(itemId);
msg->addU8(subType);
msg->addU8(amount);
msg->addU8(ignoreEquipped ? 0x01 : 0x00);
send(msg);
}
void ProtocolGame::sendCloseNpcTrade()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientCloseNpcTrade);
send(msg);
}
void ProtocolGame::sendRequestTrade(const Position& pos, int thingId, int stackpos, uint creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRequestTrade);
addPosition(msg, pos);
msg->addU16(thingId);
msg->addU8(stackpos);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendInspectTrade(bool counterOffer, int index)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientInspectTrade);
msg->addU8(counterOffer ? 0x01 : 0x00);
msg->addU8(index);
send(msg);
}
void ProtocolGame::sendAcceptTrade()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientAcceptTrade);
send(msg);
}
void ProtocolGame::sendRejectTrade()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRejectTrade);
send(msg);
}
void ProtocolGame::sendUseItem(const Position& position, int itemId, int stackpos, int index)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientUseItem);
addPosition(msg, position);
msg->addU16(itemId);
msg->addU8(stackpos);
msg->addU8(index);
send(msg);
}
void ProtocolGame::sendUseItemWith(const Position& fromPos, int itemId, int fromStackpos, const Position& toPos, int toThingId, int toStackpos)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientUseItemWith);
addPosition(msg, fromPos);
msg->addU16(itemId);
msg->addU8(fromStackpos);
addPosition(msg, toPos);
msg->addU16(toThingId);
msg->addU8(toStackpos);
send(msg);
}
void ProtocolGame::sendUseOnCreature(const Position& pos, int thingId, int stackpos, uint creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientUseOnCreature);
addPosition(msg, pos);
msg->addU16(thingId);
msg->addU8(stackpos);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendRotateItem(const Position& pos, int thingId, int stackpos)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRotateItem);
addPosition(msg, pos);
msg->addU16(thingId);
msg->addU8(stackpos);
send(msg);
}
void ProtocolGame::sendCloseContainer(int containerId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientCloseContainer);
msg->addU8(containerId);
send(msg);
}
void ProtocolGame::sendUpContainer(int containerId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientUpContainer);
msg->addU8(containerId);
send(msg);
}
void ProtocolGame::sendEditText(uint id, const std::string& text)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientEditText);
msg->addU32(id);
msg->addString(text);
send(msg);
}
void ProtocolGame::sendEditList(uint id, int doorId, const std::string& text)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientEditList);
msg->addU8(doorId);
msg->addU32(id);
msg->addString(text);
send(msg);
}
void ProtocolGame::sendLook(const Position& position, int thingId, int stackpos)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientLook);
addPosition(msg, position);
msg->addU16(thingId);
msg->addU8(stackpos);
send(msg);
}
void ProtocolGame::sendLookCreature(uint32 creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientLookCreature);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendTalk(Otc::MessageMode mode, int channelId, const std::string& receiver, const std::string& message)
{
if(message.empty())
return;
if(message.length() > 255) {
g_logger.traceError("message too large");
return;
}
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientTalk);
msg->addU8(Proto::translateMessageModeToServer(mode));
switch(mode) {
case Otc::MessagePrivateTo:
case Otc::MessageGamemasterPrivateTo:
msg->addString(receiver);
break;
case Otc::MessageChannel:
case Otc::MessageChannelHighlight:
case Otc::MessageChannelManagement:
case Otc::MessageGamemasterChannel:
msg->addU16(channelId);
break;
default:
break;
}
msg->addString(message);
send(msg);
}
void ProtocolGame::sendRequestChannels()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRequestChannels);
send(msg);
}
void ProtocolGame::sendJoinChannel(int channelId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientJoinChannel);
msg->addU16(channelId);
send(msg);
}
void ProtocolGame::sendLeaveChannel(int channelId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientLeaveChannel);
msg->addU16(channelId);
send(msg);
}
void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientOpenPrivateChannel);
msg->addString(receiver);
send(msg);
}
void ProtocolGame::sendCloseNpcChannel()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientCloseNpcChannel);
send(msg);
}
void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientChangeFightModes);
msg->addU8(fightMode);
msg->addU8(chaseMode);
msg->addU8(safeFight ? 0x01: 0x00);
send(msg);
}
void ProtocolGame::sendAttack(uint creatureId, uint seq)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientAttack);
msg->addU32(creatureId);
msg->addU32(seq);
send(msg);
}
void ProtocolGame::sendFollow(uint creatureId, uint seq)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientFollow);
msg->addU32(creatureId);
msg->addU32(seq);
send(msg);
}
void ProtocolGame::sendInviteToParty(uint creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientInviteToParty);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendJoinParty(uint creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientJoinParty);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendRevokeInvitation(uint creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRevokeInvitation);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendPassLeadership(uint creatureId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientPassLeadership);
msg->addU32(creatureId);
send(msg);
}
void ProtocolGame::sendLeaveParty()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientLeaveParty);
send(msg);
}
void ProtocolGame::sendShareExperience(bool active)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientShareExperience);
msg->addU8(active ? 0x01 : 0x00);
if(g_game.getProtocolVersion() < 910)
msg->addU8(0);
send(msg);
}
void ProtocolGame::sendOpenOwnChannel()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientOpenOwnChannel);
send(msg);
}
void ProtocolGame::sendInviteToOwnChannel(const std::string& name)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientInviteToOwnChannel);
msg->addString(name);
send(msg);
}
void ProtocolGame::sendExcludeFromOwnChannel(const std::string& name)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientExcludeFromOwnChannel);
msg->addString(name);
send(msg);
}
void ProtocolGame::sendCancelAttackAndFollow()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientCancelAttackAndFollow);
send(msg);
}
void ProtocolGame::sendRefreshContainer(int containerId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRefreshContainer);
msg->addU8(containerId);
send(msg);
}
void ProtocolGame::sendRequestOutfit()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRequestOutfit);
send(msg);
}
void ProtocolGame::sendChangeOutfit(const Outfit& outfit)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientChangeOutfit);
msg->addU16(outfit.getId());
msg->addU8(outfit.getHead());
msg->addU8(outfit.getBody());
msg->addU8(outfit.getLegs());
msg->addU8(outfit.getFeet());
msg->addU8(outfit.getAddons());
if(g_game.getFeature(Otc::GamePlayerMounts))
msg->addU16(outfit.getMount());
send(msg);
}
void ProtocolGame::sendMountStatus(bool mount)
{
if(g_game.getFeature(Otc::GamePlayerMounts)) {
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientMount);
msg->addU8(mount);
send(msg);
} else {
g_logger.error("ProtocolGame::sendMountStatus does not support the current protocol.");
}
}
void ProtocolGame::sendAddVip(const std::string& name)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientAddVip);
msg->addString(name);
send(msg);
}
void ProtocolGame::sendRemoveVip(uint playerId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRemoveVip);
msg->addU32(playerId);
send(msg);
}
void ProtocolGame::sendBugReport(const std::string& comment)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientBugReport);
msg->addString(comment);
send(msg);
}
void ProtocolGame::sendRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRuleViolation);
msg->addString(target);
msg->addU8(reason);
msg->addU8(action);
msg->addString(comment);
msg->addString(statement);
msg->addU16(statementId);
msg->addU8(ipBanishment);
send(msg);
}
void ProtocolGame::sendDebugReport(const std::string& a, const std::string& b, const std::string& c, const std::string& d)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientDebugReport);
msg->addString(a);
msg->addString(b);
msg->addString(c);
msg->addString(d);
send(msg);
}
void ProtocolGame::sendRequestQuestLog()
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRequestQuestLog);
send(msg);
}
void ProtocolGame::sendRequestQuestLine(int questId)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRequestQuestLine);
msg->addU16(questId);
send(msg);
}
void ProtocolGame::sendNewNewRuleViolation(int reason, int action, const std::string& characterName, const std::string& comment, const std::string& translation)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientNewRuleViolation);
msg->addU8(reason);
msg->addU8(action);
msg->addString(characterName);
msg->addString(comment);
msg->addString(translation);
send(msg);
}
void ProtocolGame::sendRequestItemInfo(int itemId, int subType, int index)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientRequestItemInfo);
msg->addU8(subType);
msg->addU16(itemId);
msg->addU8(index);
send(msg);
}
void ProtocolGame::sendAnswerModalDialog(int dialog, int button, int choice)
{
OutputMessagePtr msg(new OutputMessage);
msg->addU8(Proto::ClientAnswerModalDialog);
msg->addU32(dialog);
msg->addU8(button);
msg->addU8(choice);
send(msg);
}
void ProtocolGame::addPosition(const OutputMessagePtr& msg, const Position& position)
{
msg->addU16(position.x);
msg->addU16(position.y);
msg->addU8(position.z);
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shadermanager.h"
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/painterogl2_shadersources.h>
ShaderManager g_shaders;
void ShaderManager::init()
{
if(!g_graphics.canUseShaders())
return;
m_defaultItemShader = createFragmentShaderFromCode("Item", glslMainFragmentShader + glslTextureSrcFragmentShader);
setupItemShader(m_defaultItemShader);
m_defaultMapShader = createFragmentShaderFromCode("Map", glslMainFragmentShader + glslTextureSrcFragmentShader);
PainterShaderProgram::release();
}
void ShaderManager::terminate()
{
m_defaultItemShader = nullptr;
m_defaultMapShader = nullptr;
m_shaders.clear();
}
PainterShaderProgramPtr ShaderManager::createShader(const std::string& name)
{
if(!g_graphics.canUseShaders()) {
g_logger.error(stdext::format("unable to create shader '%s', shaders are not supported", name));
return nullptr;
}
PainterShaderProgramPtr shader(new PainterShaderProgram);
m_shaders[name] = shader;
return shader;
}
PainterShaderProgramPtr ShaderManager::createFragmentShader(const std::string& name, const std::string& file)
{
PainterShaderProgramPtr shader = createShader(name);
if(!shader)
return nullptr;
shader->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
if(!shader->addShaderFromSourceFile(Shader::Fragment, file)) {
g_logger.error(stdext::format("unable to load fragment shader '%s' from source file '%s'", name, file));
return nullptr;
}
if(!shader->link()) {
g_logger.error(stdext::format("unable to link shader '%s' from file '%s'", name, file));
return nullptr;
}
m_shaders[name] = shader;
return shader;
}
PainterShaderProgramPtr ShaderManager::createFragmentShaderFromCode(const std::string& name, const std::string& code)
{
PainterShaderProgramPtr shader = createShader(name);
if(!shader)
return nullptr;
shader->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
if(!shader->addShaderFromSourceCode(Shader::Fragment, code)) {
g_logger.error(stdext::format("unable to load fragment shader '%s'", name));
return nullptr;
}
if(!shader->link()) {
g_logger.error(stdext::format("unable to link shader '%s'", name));
return nullptr;
}
m_shaders[name] = shader;
return shader;
}
PainterShaderProgramPtr ShaderManager::createItemShader(const std::string& name, const std::string& file)
{
PainterShaderProgramPtr shader = createFragmentShader(name, file);
if(shader)
setupItemShader(shader);
return shader;
}
void ShaderManager::setupItemShader(const PainterShaderProgramPtr& shader)
{
if(!shader)
return;
shader->bindUniformLocation(ITEM_ID_UNIFORM, "u_ItemId");
}
PainterShaderProgramPtr ShaderManager::getShader(const std::string& name)
{
auto it = m_shaders.find(name);
if(it != m_shaders.end())
return it->second;
return nullptr;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SHADERMANAGER_H
#define SHADERMANAGER_H
#include "declarations.h"
#include <framework/graphics/paintershaderprogram.h>
//@bindsingleton g_shaders
class ShaderManager
{
public:
enum {
ITEM_ID_UNIFORM = 10
};
void init();
void terminate();
PainterShaderProgramPtr createShader(const std::string& name);
PainterShaderProgramPtr createFragmentShader(const std::string& name, const std::string& file);
PainterShaderProgramPtr createFragmentShaderFromCode(const std::string& name, const std::string& code);
PainterShaderProgramPtr createItemShader(const std::string& name, const std::string& file);
PainterShaderProgramPtr createMapShader(const std::string& name, const std::string& file) { return createFragmentShader(name, file); }
const PainterShaderProgramPtr& getDefaultItemShader() { return m_defaultItemShader; }
const PainterShaderProgramPtr& getDefaultMapShader() { return m_defaultMapShader; }
PainterShaderProgramPtr getShader(const std::string& name);
private:
void setupItemShader(const PainterShaderProgramPtr& shader);
PainterShaderProgramPtr m_defaultItemShader;
PainterShaderProgramPtr m_defaultMapShader;
std::unordered_map<std::string, PainterShaderProgramPtr> m_shaders;
};
extern ShaderManager g_shaders;
#endif

View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "spritemanager.h"
#include "game.h"
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <framework/graphics/image.h>
SpriteManager g_sprites;
SpriteManager::SpriteManager()
{
m_spritesCount = 0;
m_signature = 0;
}
void SpriteManager::terminate()
{
unload();
}
bool SpriteManager::loadSpr(const std::string& file)
{
m_spritesCount = 0;
m_signature = 0;
m_loaded = false;
try {
m_spritesFile = g_resources.openFile(file);
// cache file buffer to avoid lags from hard drive
m_spritesFile->cache();
m_signature = m_spritesFile->getU32();
m_spritesCount = g_game.getFeature(Otc::GameSpritesU32) ? m_spritesFile->getU32() : m_spritesFile->getU16();
m_spritesOffset = m_spritesFile->tell();
m_loaded = true;
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("Failed to load sprites from '%s': %s", file, e.what()));
return false;
}
}
void SpriteManager::unload()
{
m_spritesCount = 0;
m_signature = 0;
m_spritesFile = nullptr;
}
ImagePtr SpriteManager::getSpriteImage(int id)
{
try {
enum {
SPRITE_SIZE = 32,
SPRITE_DATA_SIZE = SPRITE_SIZE*SPRITE_SIZE*4
};
if(id == 0 || !m_spritesFile)
return nullptr;
m_spritesFile->seek(((id-1) * 4) + m_spritesOffset);
uint32 spriteAddress = m_spritesFile->getU32();
// no sprite? return an empty texture
if(spriteAddress == 0)
return nullptr;
m_spritesFile->seek(spriteAddress);
// skip color key
m_spritesFile->getU8();
m_spritesFile->getU8();
m_spritesFile->getU8();
uint16 pixelDataSize = m_spritesFile->getU16();
ImagePtr image(new Image(Size(SPRITE_SIZE, SPRITE_SIZE)));
uint8 *pixels = image->getPixelData();
int writePos = 0;
int read = 0;
// decompress pixels
while(read < pixelDataSize && writePos < SPRITE_DATA_SIZE) {
uint16 transparentPixels = m_spritesFile->getU16();
uint16 coloredPixels = m_spritesFile->getU16();
for(int i = 0; i < transparentPixels && writePos < SPRITE_DATA_SIZE; i++) {
pixels[writePos + 0] = 0x00;
pixels[writePos + 1] = 0x00;
pixels[writePos + 2] = 0x00;
pixels[writePos + 3] = 0x00;
writePos += 4;
}
for(int i = 0; i < coloredPixels && writePos < SPRITE_DATA_SIZE; i++) {
pixels[writePos + 0] = m_spritesFile->getU8();
pixels[writePos + 1] = m_spritesFile->getU8();
pixels[writePos + 2] = m_spritesFile->getU8();
pixels[writePos + 3] = 0xFF;
writePos += 4;
}
read += 4 + (3 * coloredPixels);
}
// fill remaining pixels with alpha
while(writePos < SPRITE_DATA_SIZE) {
pixels[writePos + 0] = 0x00;
pixels[writePos + 1] = 0x00;
pixels[writePos + 2] = 0x00;
pixels[writePos + 3] = 0x00;
writePos += 4;
}
return image;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("Failed to get sprite id %d: %s", id, e.what()));
return nullptr;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SPRITEMANAGER_H
#define SPRITEMANAGER_H
#include <framework/core/declarations.h>
#include <framework/graphics/declarations.h>
//@bindsingleton g_sprites
class SpriteManager
{
public:
SpriteManager();
void terminate();
bool loadSpr(const std::string& file);
void unload();
uint32 getSignature() { return m_signature; }
int getSpritesCount() { return m_spritesCount; }
ImagePtr getSpriteImage(int id);
bool isLoaded() { return m_loaded; }
private:
stdext::boolean<false> m_loaded;
uint32 m_signature;
int m_spritesCount;
int m_spritesOffset;
FileStreamPtr m_spritesFile;
};
extern SpriteManager g_sprites;
#endif

142
src/client/statictext.cpp Normal file
View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "statictext.h"
#include "map.h"
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/fontmanager.h>
StaticText::StaticText()
{
m_cachedText.setFont(g_fonts.getFont("verdana-11px-rounded"));
m_cachedText.setAlign(Fw::AlignCenter);
}
void StaticText::drawText(const Point& dest, const Rect& parentRect)
{
Size textSize = m_cachedText.getTextSize();
Rect rect = Rect(dest - Point(textSize.width() / 2, textSize.height()) + Point(20, 5), textSize);
Rect boundRect = rect;
boundRect.bind(parentRect);
// draw only if the real center is not too far from the parent center, or its a yell
//if(g_map.isAwareOfPosition(m_position) || isYell()) {
g_painter->setColor(m_color);
m_cachedText.draw(boundRect);
//}
}
bool StaticText::addMessage(const std::string& name, Otc::MessageMode mode, const std::string& text)
{
//TODO: this could be moved to lua
// first message
if(m_messages.size() == 0) {
m_name = name;
m_mode = mode;
}
// check if we can really own the message
else if(m_name != name || m_mode != mode) {
return false;
}
// too many messages
else if(m_messages.size() > 10) {
m_messages.pop_front();
m_updateEvent->cancel();
m_updateEvent = nullptr;
}
int delay = std::max<int>(Otc::STATIC_DURATION_PER_CHARACTER * text.length(), Otc::MIN_STATIC_TEXT_DURATION);
if(isYell())
delay *= 2;
m_messages.push_back(std::make_pair(text, g_clock.millis() + delay));
compose();
if(!m_updateEvent)
scheduleUpdate();
return true;
}
void StaticText::update()
{
m_messages.pop_front();
if(m_messages.empty()) {
// schedule removal
auto self = asStaticText();
g_dispatcher.addEvent([self]() { g_map.removeThing(self); });
} else {
compose();
scheduleUpdate();
}
}
void StaticText::scheduleUpdate()
{
int delay = std::max<int>(m_messages.front().second - g_clock.millis(), 0);
auto self = asStaticText();
m_updateEvent = g_dispatcher.scheduleEvent([self]() {
self->m_updateEvent = nullptr;
self->update();
}, delay);
}
void StaticText::compose()
{
//TODO: this could be moved to lua
std::string text;
if(m_mode == Otc::MessageSay) {
text += m_name;
text += " says:\n";
m_color = Color(239, 239, 0);
} else if(m_mode == Otc::MessageWhisper) {
text += m_name;
text += " whispers:\n";
m_color = Color(239, 239, 0);
} else if(m_mode == Otc::MessageYell) {
text += m_name;
text += " yells:\n";
m_color = Color(239, 239, 0);
} else if(m_mode == Otc::MessageMonsterSay || m_mode == Otc::MessageMonsterYell || m_mode == Otc::MessageSpell || m_mode == Otc::MessageBarkLow || m_mode == Otc::MessageBarkLoud) {
m_color = Color(254, 101, 0);
} else if(m_mode == Otc::MessageNpcFrom) {
text += m_name;
text += " says:\n";
m_color = Color(95, 247, 247);
} else {
g_logger.warning(stdext::format("Unknown speak type: %d", m_mode));
}
for(uint i = 0; i < m_messages.size(); ++i) {
text += m_messages[i].first;
if(i < m_messages.size() - 1)
text += "\n";
}
m_cachedText.setText(text);
m_cachedText.wrapText(275);
}

63
src/client/statictext.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef STATICTEXT_H
#define STATICTEXT_H
#include "thing.h"
#include <framework/graphics/cachedtext.h>
#include <framework/core/timer.h>
// @bindclass
class StaticText : public Thing
{
public:
StaticText();
void drawText(const Point& dest, const Rect& parentRect);
std::string getName() { return m_name; }
Otc::MessageMode getMessageMode() { return m_mode; }
std::string getFirstMessage() { return m_messages[0].first; }
bool isYell() { return m_mode == Otc::MessageYell || m_mode == Otc::MessageMonsterYell || m_mode == Otc::MessageBarkLoud; }
bool addMessage(const std::string& name, Otc::MessageMode mode, const std::string& text);
StaticTextPtr asStaticText() { return static_self_cast<StaticText>(); }
bool isStaticText() { return true; }
private:
void update();
void scheduleUpdate();
void compose();
stdext::boolean<false> m_yell;
std::deque<std::pair<std::string, ticks_t>> m_messages;
std::string m_name;
Otc::MessageMode m_mode;
Color m_color;
CachedText m_cachedText;
ScheduledEventPtr m_updateEvent;
};
#endif

96
src/client/thing.cpp Normal file
View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "thing.h"
#include "spritemanager.h"
#include "thingtypemanager.h"
#include <framework/graphics/graphics.h>
#include "map.h"
#include "tile.h"
#include "game.h"
Thing::Thing() :
m_datId(0)
{
}
void Thing::setPosition(const Position& position)
{
if(m_position == position)
return;
Position oldPos = m_position;
m_position = position;
onPositionChange(position, oldPos);
}
int Thing::getStackPriority()
{
if(isGround())
return 0;
else if(isGroundBorder())
return 1;
else if(isOnBottom())
return 2;
else if(isOnTop())
return 3;
else if(isCreature())
return 4;
else // common items
return 5;
}
const TilePtr& Thing::getTile()
{
return g_map.getTile(m_position);
}
ContainerPtr Thing::getParentContainer()
{
if(m_position.x == 0xffff && m_position.y & 0x40) {
int containerId = m_position.y ^ 0x40;
return g_game.getContainer(containerId);
}
return nullptr;
}
int Thing::getStackpos()
{
if(m_position.x == 65535 && isItem()) // is inside a container
return m_position.z;
else if(const TilePtr& tile = getTile())
return tile->getThingStackpos(static_self_cast<Thing>());
else {
g_logger.traceError("got a thing with invalid stackpos");
return -1;
}
}
const ThingTypePtr& Thing::getThingType()
{
return g_things.getNullThingType();
}
ThingType* Thing::rawGetThingType()
{
return g_things.getNullThingType().get();
}

132
src/client/thing.h Normal file
View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef THING_H
#define THING_H
#include "declarations.h"
#include "thingtype.h"
#include "thingtypemanager.h"
#include <framework/luaengine/luaobject.h>
// @bindclass
#pragma pack(push,1) // disable memory alignment
class Thing : public LuaObject
{
public:
Thing();
virtual ~Thing() { }
virtual void draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView = nullptr) { }
virtual void setId(uint32 id) { }
void setPosition(const Position& position);
virtual uint32 getId() { return 0; }
Position getPosition() { return m_position; }
int getStackPriority();
const TilePtr& getTile();
ContainerPtr getParentContainer();
int getStackpos();
virtual bool isItem() { return false; }
virtual bool isEffect() { return false; }
virtual bool isMissile() { return false; }
virtual bool isCreature() { return false; }
virtual bool isNpc() { return false; }
virtual bool isMonster() { return false; }
virtual bool isPlayer() { return false; }
virtual bool isLocalPlayer() { return false; }
virtual bool isAnimatedText() { return false; }
virtual bool isStaticText() { return false; }
// type shortcuts
virtual const ThingTypePtr& getThingType();
virtual ThingType *rawGetThingType();
Size getSize() { return rawGetThingType()->getSize(); }
int getWidth() { return rawGetThingType()->getWidth(); }
int getHeight() { return rawGetThingType()->getHeight(); }
virtual Point getDisplacement() { return rawGetThingType()->getDisplacement(); }
virtual int getDisplacementX() { return rawGetThingType()->getDisplacementX(); }
virtual int getDisplacementY() { return rawGetThingType()->getDisplacementY(); }
virtual int getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase) { return rawGetThingType()->getExactSize(layer, xPattern, yPattern, zPattern, animationPhase); }
int getLayers() { return rawGetThingType()->getLayers(); }
int getNumPatternX() { return rawGetThingType()->getNumPatternX(); }
int getNumPatternY() { return rawGetThingType()->getNumPatternY(); }
int getNumPatternZ() { return rawGetThingType()->getNumPatternZ(); }
int getAnimationPhases() { return rawGetThingType()->getAnimationPhases(); }
int getGroundSpeed() { return rawGetThingType()->getGroundSpeed(); }
int getMaxTextLength() { return rawGetThingType()->getMaxTextLength(); }
Light getLight() { return rawGetThingType()->getLight(); }
int getMinimapColor() { return rawGetThingType()->getMinimapColor(); }
int getLensHelp() { return rawGetThingType()->getLensHelp(); }
int getClothSlot() { return rawGetThingType()->getClothSlot(); }
int getElevation() { return rawGetThingType()->getElevation(); }
bool isGround() { return rawGetThingType()->isGround(); }
bool isGroundBorder() { return rawGetThingType()->isGroundBorder(); }
bool isOnBottom() { return rawGetThingType()->isOnBottom(); }
bool isOnTop() { return rawGetThingType()->isOnTop(); }
bool isContainer() { return rawGetThingType()->isContainer(); }
bool isStackable() { return rawGetThingType()->isStackable(); }
bool isForceUse() { return rawGetThingType()->isForceUse(); }
bool isMultiUse() { return rawGetThingType()->isMultiUse(); }
bool isWritable() { return rawGetThingType()->isWritable(); }
bool isChargeable() { return rawGetThingType()->isChargeable(); }
bool isWritableOnce() { return rawGetThingType()->isWritableOnce(); }
bool isFluidContainer() { return rawGetThingType()->isFluidContainer(); }
bool isSplash() { return rawGetThingType()->isSplash(); }
bool isNotWalkable() { return rawGetThingType()->isNotWalkable(); }
bool isNotMoveable() { return rawGetThingType()->isNotMoveable(); }
bool blockProjectile() { return rawGetThingType()->blockProjectile(); }
bool isNotPathable() { return rawGetThingType()->isNotPathable(); }
bool isPickupable() { return rawGetThingType()->isPickupable(); }
bool isHangable() { return rawGetThingType()->isHangable(); }
bool isHookSouth() { return rawGetThingType()->isHookSouth(); }
bool isHookEast() { return rawGetThingType()->isHookEast(); }
bool isRotateable() { return rawGetThingType()->isRotateable(); }
bool hasLight() { return rawGetThingType()->hasLight(); }
bool isDontHide() { return rawGetThingType()->isDontHide(); }
bool isTranslucent() { return rawGetThingType()->isTranslucent(); }
bool hasDisplacement() { return rawGetThingType()->hasDisplacement(); }
bool hasElevation() { return rawGetThingType()->hasElevation(); }
bool isLyingCorpse() { return rawGetThingType()->isLyingCorpse(); }
bool isAnimateAlways() { return rawGetThingType()->isAnimateAlways(); }
bool hasMiniMapColor() { return rawGetThingType()->hasMiniMapColor(); }
bool hasLensHelp() { return rawGetThingType()->hasLensHelp(); }
bool isFullGround() { return rawGetThingType()->isFullGround(); }
bool isIgnoreLook() { return rawGetThingType()->isIgnoreLook(); }
bool isCloth() { return rawGetThingType()->isCloth(); }
bool isMarketable() { return rawGetThingType()->isMarketable(); }
MarketData getMarketData() { return rawGetThingType()->getMarketData(); }
virtual void onPositionChange(const Position& newPos, const Position& oldPos) { }
virtual void onAppear() { }
virtual void onDisappear() { }
protected:
Position m_position;
uint16 m_datId;
};
#pragma pack(pop)
#endif

67
src/client/thingstype.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef DATMANAGER_H
#define DATMANAGER_H
#include <framework/global.h>
#include <framework/core/declarations.h>
#include "thingtype.h"
//@bindsingleton g_thingsType
class ThingsType
{
public:
enum Categories {
Item = 0,
Creature,
Effect,
Missile,
LastCategory
};
bool load(const std::string& file);
void unload();
bool parseThingType(const FileStreamPtr& fin, ThingType& thingType);
ThingType *getEmptyThingType() { return &m_emptyThingType; }
ThingType *getThingType(uint16 id, Categories category);
uint32 getSignature() { return m_signature; }
bool isLoaded() { return m_loaded; }
uint16 getFirstItemId() { return 100; }
uint16 getMaxItemid() { return m_things[Item].size() + 99; }
bool isValidItemId(int id) { return id >= getFirstItemId() && id <= getMaxItemid(); }
private:
uint32 m_signature;
stdext::boolean<false> m_loaded;
ThingTypeList m_things[LastCategory];
static ThingType m_emptyThingType;
};
extern ThingsType g_thingsType;
#endif

304
src/client/thingtype.cpp Normal file
View File

@@ -0,0 +1,304 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "thingtype.h"
#include "spritemanager.h"
#include "game.h"
#include "lightview.h"
#include <framework/graphics/graphics.h>
#include <framework/graphics/texture.h>
#include <framework/graphics/image.h>
#include <framework/graphics/texturemanager.h>
#include <framework/core/filestream.h>
ThingType::ThingType()
{
m_category = ThingInvalidCategory;
m_id = 0;
m_null = true;
m_exactSize = 0;
m_numPatternX = m_numPatternY = m_numPatternZ = 0;
m_animationPhases = 0;
m_layers = 0;
m_elevation = 0;
}
void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin)
{
m_null = false;
m_id = clientId;
m_category = category;
bool done = false;
for(int i = 0 ; i < ThingLastAttr;++i) {
int attr = fin->getU8();
if(attr == ThingLastAttr) {
done = true;
break;
}
if(g_game.getFeature(Otc::GameChargeableItems)) {
if(attr == ThingAttrWritable) {
m_attribs.set(ThingAttrChargeable, true);
continue;
} else if(attr > ThingAttrWritable)
attr -= 1;
}
switch(attr) {
case ThingAttrDisplacement: {
m_displacement.x = fin->getU16();
m_displacement.y = fin->getU16();
m_attribs.set(attr, true);
break;
}
case ThingAttrLight: {
Light light;
light.intensity = fin->getU16();
light.color = fin->getU16();
m_attribs.set(attr, light);
break;
}
case ThingAttrMarket: {
MarketData market;
market.category = fin->getU16();
market.tradeAs = fin->getU16();
market.showAs = fin->getU16();
market.name = fin->getString();
market.restrictVocation = fin->getU16();
market.requiredLevel = fin->getU16();
m_attribs.set(attr, market);
break;
}
case ThingAttrElevation: {
m_elevation = fin->getU16();
m_attribs.set(attr, m_elevation);
break;
}
case ThingAttrGround:
case ThingAttrWritable:
case ThingAttrWritableOnce:
case ThingAttrMinimapColor:
case ThingAttrCloth:
case ThingAttrLensHelp:
m_attribs.set(attr, fin->getU16());
break;
default:
m_attribs.set(attr, true);
break;
};
}
if(!done)
stdext::throw_exception("corrupt data");
uint8 width = fin->getU8();
uint8 height = fin->getU8();
m_size = Size(width, height);
m_exactSize = (width > 1 || height > 1) ? std::min((int)fin->getU8(), std::max(width * 32, height * 32)) : 32;
m_layers = fin->getU8();
m_numPatternX = fin->getU8();
m_numPatternY = fin->getU8();
m_numPatternZ = fin->getU8();
m_animationPhases = fin->getU8();
int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
if(totalSprites == 0)
stdext::throw_exception("a thing type has no sprites");
if(totalSprites > 4096)
stdext::throw_exception("a thing type has more than 4096 sprites");
m_spritesIndex.resize(totalSprites);
for(int i = 0; i < totalSprites; i++)
m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();
m_textures.resize(m_animationPhases);
m_texturesFramesRects.resize(m_animationPhases);
m_texturesFramesOriginRects.resize(m_animationPhases);
m_texturesFramesOffsets.resize(m_animationPhases);
}
void ThingType::draw(const Point& dest, float scaleFactor, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, LightView *lightView)
{
if(m_null)
return;
const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects.
int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
Point textureOffset;
Rect textureRect;
if(scaleFactor != 1.0f) {
textureRect = m_texturesFramesOriginRects[animationPhase][frameIndex];
} else {
textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
textureRect = m_texturesFramesRects[animationPhase][frameIndex];
}
Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * 32) * scaleFactor,
textureRect.size() * scaleFactor);
g_painter->drawTexturedRect(screenRect, texture, textureRect);
if(lightView && hasLight()) {
Light light = getLight();
if(light.intensity > 0)
lightView->addLightSource(screenRect.center(), scaleFactor, light);
}
}
const TexturePtr& ThingType::getTexture(int animationPhase)
{
TexturePtr& animationPhaseTexture = m_textures[animationPhase];
if(!animationPhaseTexture) {
// we don't need layers in common items, they will be pre-drawn
int textureLayers = 1;
int numLayers = m_layers;
if(m_category == ThingCategoryCreature && numLayers >= 2) {
// 5 layers: outfit base, red mask, green mask, blue mask, yellow mask
textureLayers = 5;
numLayers = 5;
}
int indexSize = textureLayers * m_numPatternX * m_numPatternY * m_numPatternZ;
Size textureSize = getBestTextureDimension(m_size.width(), m_size.height(), indexSize);
ImagePtr fullImage = ImagePtr(new Image(textureSize * Otc::TILE_PIXELS));
m_texturesFramesRects[animationPhase].resize(indexSize);
m_texturesFramesOriginRects[animationPhase].resize(indexSize);
m_texturesFramesOffsets[animationPhase].resize(indexSize);
for(int z = 0; z < m_numPatternZ; ++z) {
for(int y = 0; y < m_numPatternY; ++y) {
for(int x = 0; x < m_numPatternX; ++x) {
for(int l = 0; l < numLayers; ++l) {
bool spriteMask = (m_category == ThingCategoryCreature && l > 0);
int frameIndex = getTextureIndex(l % textureLayers, x, y, z);
Point framePos = Point(frameIndex % (textureSize.width() / m_size.width()) * m_size.width(),
frameIndex / (textureSize.width() / m_size.width()) * m_size.height()) * Otc::TILE_PIXELS;
for(int h = 0; h < m_size.height(); ++h) {
for(int w = 0; w < m_size.width(); ++w) {
uint spriteIndex = getSpriteIndex(w, h, spriteMask ? 1 : l, x, y, z, animationPhase);
ImagePtr spriteImage = g_sprites.getSpriteImage(m_spritesIndex[spriteIndex]);
if(spriteImage) {
if(spriteMask) {
static Color maskColors[] = { Color::red, Color::green, Color::blue, Color::yellow };
spriteImage->overwriteMask(maskColors[l - 1]);
}
Point spritePos = Point(m_size.width() - w - 1,
m_size.height() - h - 1) * Otc::TILE_PIXELS;
fullImage->blit(framePos + spritePos, spriteImage);
}
}
}
Rect drawRect(framePos + Point(m_size.width(), m_size.height()) * Otc::TILE_PIXELS - Point(1,1), framePos);
for(int x = framePos.x; x < framePos.x + m_size.width() * Otc::TILE_PIXELS; ++x) {
for(int y = framePos.y; y < framePos.y + m_size.height() * Otc::TILE_PIXELS; ++y) {
uint8 *p = fullImage->getPixel(x,y);
if(p[3] != 0x00) {
drawRect.setTop (std::min(y, (int)drawRect.top()));
drawRect.setLeft (std::min(x, (int)drawRect.left()));
drawRect.setBottom(std::max(y, (int)drawRect.bottom()));
drawRect.setRight (std::max(x, (int)drawRect.right()));
}
}
}
m_texturesFramesRects[animationPhase][frameIndex] = drawRect;
m_texturesFramesOriginRects[animationPhase][frameIndex] = Rect(framePos, Size(m_size.width(), m_size.height()) * Otc::TILE_PIXELS);
m_texturesFramesOffsets[animationPhase][frameIndex] = drawRect.topLeft() - framePos;
}
}
}
}
animationPhaseTexture = TexturePtr(new Texture(fullImage, true));
animationPhaseTexture->setSmooth(true);
}
return animationPhaseTexture;
}
Size ThingType::getBestTextureDimension(int w, int h, int count)
{
const int MAX = 32;
int k = 1;
while(k < w)
k<<=1;
w = k;
k = 1;
while(k < h)
k<<=1;
h = k;
int numSprites = w*h*count;
assert(numSprites <= MAX*MAX);
assert(w <= MAX);
assert(h <= MAX);
Size bestDimension = Size(MAX, MAX);
for(int i=w;i<=MAX;i<<=1) {
for(int j=h;j<=MAX;j<<=1) {
Size candidateDimension = Size(i, j);
if(candidateDimension.area() < numSprites)
continue;
if((candidateDimension.area() < bestDimension.area()) ||
(candidateDimension.area() == bestDimension.area() && candidateDimension.width() + candidateDimension.height() < bestDimension.width() + bestDimension.height()))
bestDimension = candidateDimension;
}
}
return bestDimension;
}
uint ThingType::getSpriteIndex(int w, int h, int l, int x, int y, int z, int a) {
uint index =
((((((a % m_animationPhases)
* m_numPatternZ + z)
* m_numPatternY + y)
* m_numPatternX + x)
* m_layers + l)
* m_size.height() + h)
* m_size.width() + w;
assert(index < m_spritesIndex.size());
return index;
}
uint ThingType::getTextureIndex(int l, int x, int y, int z) {
return ((l * m_numPatternZ + z)
* m_numPatternY + y)
* m_numPatternX + x;
}
int ThingType::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
{
getTexture(animationPhase); // we must calculate it anyway.
int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
Size size = m_texturesFramesOriginRects[animationPhase][frameIndex].size() - m_texturesFramesOffsets[animationPhase][frameIndex].toSize();
return std::max(size.width(), size.height());
}

201
src/client/thingtype.h Normal file
View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef THINGTYPE_H
#define THINGTYPE_H
#include "declarations.h"
#include <framework/core/declarations.h>
#include <framework/graphics/texture.h>
#include <framework/graphics/coordsbuffer.h>
#include <framework/luaengine/luaobject.h>
#include <framework/net/server.h>
enum ThingCategory : uint8 {
ThingCategoryItem = 0,
ThingCategoryCreature,
ThingCategoryEffect,
ThingCategoryMissile,
ThingInvalidCategory,
ThingLastCategory = ThingInvalidCategory
};
enum ThingAttr : uint8 {
ThingAttrGround = 0,
ThingAttrGroundBorder = 1,
ThingAttrOnBottom = 2,
ThingAttrOnTop = 3,
ThingAttrContainer = 4,
ThingAttrStackable = 5,
ThingAttrForceUse = 6,
ThingAttrMultiUse = 7,
ThingAttrWritable = 8,
ThingAttrWritableOnce = 9,
ThingAttrFluidContainer = 10,
ThingAttrSplash = 11,
ThingAttrNotWalkable = 12,
ThingAttrNotMoveable = 13,
ThingAttrBlockProjectile = 14,
ThingAttrNotPathable = 15,
ThingAttrPickupable = 16,
ThingAttrHangable = 17,
ThingAttrHookSouth = 18,
ThingAttrHookEast = 19,
ThingAttrRotateable = 20,
ThingAttrLight = 21,
ThingAttrDontHide = 22,
ThingAttrTranslucent = 23,
ThingAttrDisplacement = 24,
ThingAttrElevation = 25,
ThingAttrLyingCorpse = 26,
ThingAttrAnimateAlways = 27,
ThingAttrMinimapColor = 28,
ThingAttrLensHelp = 29,
ThingAttrFullGround = 30,
ThingAttrLook = 31,
ThingAttrCloth = 32,
ThingAttrMarket = 33,
ThingAttrChargeable = 254, // deprecated
ThingLastAttr = 255
};
enum SpriteMask {
SpriteMaskRed = 1,
SpriteMaskGreen,
SpriteMaskBlue,
SpriteMaskYellow
};
struct MarketData {
std::string name;
int category;
uint16 requiredLevel;
uint16 restrictVocation;
uint16 showAs;
uint16 tradeAs;
};
struct Light {
Light() { intensity = 0; color = 215; }
uint8 intensity;
uint8 color;
};
class ThingType : public LuaObject
{
public:
ThingType();
void unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin);
void draw(const Point& dest, float scaleFactor, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, LightView *lightView = nullptr);
uint16 getId() { return m_id; }
ThingCategory getCategory() { return m_category; }
bool isNull() { return m_null; }
bool hasAttr(ThingAttr attr) { return m_attribs.has(attr); }
Size getSize() { return m_size; }
int getWidth() { return m_size.width(); }
int getHeight() { return m_size.height(); }
int getExactSize(int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animationPhase = 0);
int getLayers() { return m_layers; }
int getNumPatternX() { return m_numPatternX; }
int getNumPatternY() { return m_numPatternY; }
int getNumPatternZ() { return m_numPatternZ; }
int getAnimationPhases() { return m_animationPhases; }
Point getDisplacement() { return m_displacement; }
int getDisplacementX() { return getDisplacement().x; }
int getDisplacementY() { return getDisplacement().y; }
int getElevation() { return m_elevation; }
int getGroundSpeed() { return m_attribs.get<uint16>(ThingAttrGround); }
int getMaxTextLength() { return m_attribs.has(ThingAttrWritableOnce) ? m_attribs.get<uint16>(ThingAttrWritableOnce) : m_attribs.get<uint16>(ThingAttrWritable); }
Light getLight() { return m_attribs.get<Light>(ThingAttrLight); }
int getMinimapColor() { return m_attribs.get<uint16>(ThingAttrMinimapColor); }
int getLensHelp() { return m_attribs.get<uint16>(ThingAttrLensHelp); }
int getClothSlot() { return m_attribs.get<uint16>(ThingAttrCloth); }
MarketData getMarketData() { return m_attribs.get<MarketData>(ThingAttrMarket); }
bool isGround() { return m_attribs.has(ThingAttrGround); }
bool isGroundBorder() { return m_attribs.has(ThingAttrGroundBorder); }
bool isOnBottom() { return m_attribs.has(ThingAttrOnBottom); }
bool isOnTop() { return m_attribs.has(ThingAttrOnTop); }
bool isContainer() { return m_attribs.has(ThingAttrContainer); }
bool isStackable() { return m_attribs.has(ThingAttrStackable); }
bool isForceUse() { return m_attribs.has(ThingAttrForceUse); }
bool isMultiUse() { return m_attribs.has(ThingAttrMultiUse); }
bool isWritable() { return m_attribs.has(ThingAttrWritable); }
bool isChargeable() { return m_attribs.has(ThingAttrChargeable); }
bool isWritableOnce() { return m_attribs.has(ThingAttrWritableOnce); }
bool isFluidContainer() { return m_attribs.has(ThingAttrFluidContainer); }
bool isSplash() { return m_attribs.has(ThingAttrSplash); }
bool isNotWalkable() { return m_attribs.has(ThingAttrNotWalkable); }
bool isNotMoveable() { return m_attribs.has(ThingAttrNotMoveable); }
bool blockProjectile() { return m_attribs.has(ThingAttrBlockProjectile); }
bool isNotPathable() { return m_attribs.has(ThingAttrNotPathable); }
bool isPickupable() { return m_attribs.has(ThingAttrPickupable); }
bool isHangable() { return m_attribs.has(ThingAttrHangable); }
bool isHookSouth() { return m_attribs.has(ThingAttrHookSouth); }
bool isHookEast() { return m_attribs.has(ThingAttrHookEast); }
bool isRotateable() { return m_attribs.has(ThingAttrRotateable); }
bool hasLight() { return m_attribs.has(ThingAttrLight); }
bool isDontHide() { return m_attribs.has(ThingAttrDontHide); }
bool isTranslucent() { return m_attribs.has(ThingAttrTranslucent); }
bool hasDisplacement() { return m_attribs.has(ThingAttrDisplacement); }
bool hasElevation() { return m_attribs.has(ThingAttrElevation); }
bool isLyingCorpse() { return m_attribs.has(ThingAttrLyingCorpse); }
bool isAnimateAlways() { return m_attribs.has(ThingAttrAnimateAlways); }
bool hasMiniMapColor() { return m_attribs.has(ThingAttrMinimapColor); }
bool hasLensHelp() { return m_attribs.has(ThingAttrLensHelp); }
bool isFullGround() { return m_attribs.has(ThingAttrFullGround); }
bool isIgnoreLook() { return m_attribs.has(ThingAttrLook); }
bool isCloth() { return m_attribs.has(ThingAttrCloth); }
bool isMarketable() { return m_attribs.has(ThingAttrMarket); }
private:
const TexturePtr& getTexture(int animationPhase);
Size getBestTextureDimension(int w, int h, int count);
uint getSpriteIndex(int w, int h, int l, int x, int y, int z, int a);
uint getTextureIndex(int l, int x, int y, int z);
ThingCategory m_category;
uint16 m_id;
bool m_null;
stdext::dynamic_storage<uint8> m_attribs;
Size m_size;
Point m_displacement;
int m_exactSize;
int m_numPatternX, m_numPatternY, m_numPatternZ;
int m_animationPhases;
int m_layers;
int m_elevation;
std::vector<int> m_spritesIndex;
std::vector<TexturePtr> m_textures;
std::vector<std::vector<Rect>> m_texturesFramesRects;
std::vector<std::vector<Rect>> m_texturesFramesOriginRects;
std::vector<std::vector<Point>> m_texturesFramesOffsets;
};
#endif

View File

@@ -0,0 +1,291 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "thingtypemanager.h"
#include "spritemanager.h"
#include "thing.h"
#include "thingtype.h"
#include "itemtype.h"
#include "creature.h"
#include "creatures.h"
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
#include <framework/xml/tinyxml.h>
ThingTypeManager g_things;
void ThingTypeManager::init()
{
m_nullThingType = ThingTypePtr(new ThingType);
m_nullItemType = ItemTypePtr(new ItemType);
m_datSignature = 0;
m_otbMinorVersion = 0;
m_otbMajorVersion = 0;
m_datLoaded = false;
m_xmlLoaded = false;
m_otbLoaded = false;
for(int i = 0; i < ThingLastCategory; ++i)
m_thingTypes[i].resize(1, m_nullThingType);
m_itemTypes.resize(1, m_nullItemType);
}
void ThingTypeManager::terminate()
{
for(int i = 0; i < ThingLastCategory; ++i)
m_thingTypes[i].clear();
m_itemTypes.clear();
m_reverseItemTypes.clear();
m_nullThingType = nullptr;
m_nullItemType = nullptr;
}
bool ThingTypeManager::loadDat(const std::string& file)
{
m_datLoaded = false;
m_datSignature = 0;
try {
FileStreamPtr fin = g_resources.openFile(file);
m_datSignature = fin->getU32();
int numThings[ThingLastCategory];
for(int category = 0; category < ThingLastCategory; ++category) {
int count = fin->getU16() + 1;
m_thingTypes[category].clear();
m_thingTypes[category].resize(count, m_nullThingType);
}
for(int category = 0; category < ThingLastCategory; ++category) {
uint16 firstId = 1;
if(category == ThingCategoryItem)
firstId = 100;
for(uint16 id = firstId; id < m_thingTypes[category].size(); ++id) {
ThingTypePtr type(new ThingType);
type->unserialize(id, (ThingCategory)category, fin);
m_thingTypes[category][id] = type;
}
}
m_datLoaded = true;
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what()));
return false;
}
}
void ThingTypeManager::loadOtb(const std::string& file)
{
FileStreamPtr fin = g_resources.openFile(file);
uint signature = fin->getU32();
if(signature != 0)
stdext::throw_exception("invalid otb file");
BinaryTreePtr root = fin->getBinaryTree();
signature = root->getU32();
if(signature != 0)
stdext::throw_exception("invalid otb file");
root->skip(4);
m_otbMajorVersion = root->getU32();
m_otbMinorVersion = root->getU32();
root->skip(4);
root->skip(128); // description
m_reverseItemTypes.clear();
m_itemTypes.resize(root->getChildren().size() + 1, m_nullItemType);
for(const BinaryTreePtr& node : root->getChildren()) {
ItemTypePtr itemType(new ItemType);
itemType->unserialize(node);
addItemType(itemType);
uint16 clientId = itemType->getClientId();
if(clientId >= m_reverseItemTypes.size())
m_reverseItemTypes.resize(clientId+1);
m_reverseItemTypes[clientId] = itemType;
}
m_otbLoaded = true;
}
void ThingTypeManager::loadXml(const std::string& file)
{
if(!isOtbLoaded())
stdext::throw_exception("OTB must be loaded before XML");
TiXmlDocument doc;
doc.Parse(g_resources.loadFile(file).c_str());
if(doc.Error())
stdext::throw_exception(stdext::format("failed to parse '%s': '%s'", file, doc.ErrorDesc()));
TiXmlElement* root = doc.FirstChildElement();
if(!root || root->ValueTStr() != "items")
stdext::throw_exception("invalid root tag name");
for (TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) {
if(element->ValueTStr() != "item")
continue;
uint16 id = element->readType<uint16>("id");
if(id != 0) {
std::vector<std::string> s_ids = stdext::split(element->Attribute("id"), ";");
for(const std::string& s : s_ids) {
std::vector<int32> ids = stdext::split<int32>(s, "-");
if(ids.size() > 1) {
int32 i = ids[0];
while(i <= ids[1])
parseItemType(i++, element);
} else
parseItemType(atoi(s.c_str()), element);
}
} else {
std::vector<int32> begin = stdext::split<int32>(element->Attribute("fromid"), ";");
std::vector<int32> end = stdext::split<int32>(element->Attribute("toid"), ";");
if(begin[0] && begin.size() == end.size()) {
size_t size = begin.size();
for(size_t i = 0; i < size; ++i) {
while(begin[i] <= end[i])
parseItemType(begin[i]++, element);
}
}
}
}
doc.Clear();
m_xmlLoaded = true;
g_logger.debug("items.xml read successfully.");
}
void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
{
uint16 serverId = id;
ItemTypePtr itemType = nullptr;
if(serverId > 20000 && serverId < 20100) {
serverId -= 20000;
itemType = ItemTypePtr(new ItemType);
itemType->setServerId(serverId);
addItemType(itemType);
} else
itemType = getItemType(serverId);
itemType->setName(elem->Attribute("name"));
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
std::string key = attrib->Attribute("key");
if(key.empty())
continue;
stdext::tolower(key);
if(key == "description")
itemType->setDesc(attrib->Attribute("value"));
else if(key == "weapontype")
itemType->setCategory(ItemCategoryWeapon);
else if(key == "ammotype")
itemType->setCategory(ItemCategoryAmmunition);
else if(key == "armor")
itemType->setCategory(ItemCategoryArmor);
else if(key == "charges")
itemType->setCategory(ItemCategoryCharges);
else if(key == "type") {
std::string value = attrib->Attribute("value");
stdext::tolower(value);
if(value == "key")
itemType->setCategory(ItemCategoryKey);
else if(value == "magicfield")
itemType->setCategory(ItemCategoryMagicField);
else if(value == "teleport")
itemType->setCategory(ItemCategoryTeleport);
else if(value == "door")
itemType->setCategory(ItemCategoryDoor);
}
}
}
void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
{
uint16 id = itemType->getServerId();
if(id > m_itemTypes.size())
m_itemTypes.resize(id + 1, m_nullItemType);
m_itemTypes[id] = itemType;
}
const ItemTypePtr& ThingTypeManager::findItemTypeByClientId(uint16 id)
{
if(id == 0 || id >= m_reverseItemTypes.size())
return m_nullItemType;
if(m_reverseItemTypes[id])
return m_reverseItemTypes[id];
else
return m_nullItemType;
}
const ThingTypePtr& ThingTypeManager::getThingType(uint16 id, ThingCategory category)
{
if(category >= ThingLastCategory || id >= m_thingTypes[category].size()) {
g_logger.error(stdext::format("invalid thing type client id %d in category %d", id, category));
return m_nullThingType;
}
return m_thingTypes[category][id];
}
const ItemTypePtr& ThingTypeManager::getItemType(uint16 id)
{
if(id >= m_itemTypes.size() || m_itemTypes[id] == m_nullItemType) {
g_logger.error(stdext::format("invalid thing type server id %d", id));
return m_nullItemType;
}
return m_itemTypes[id];
}
ThingTypeList ThingTypeManager::findThingTypeByAttr(ThingAttr attr, ThingCategory category)
{
ThingTypeList ret;
for(const ThingTypePtr& type : m_thingTypes[category])
if(type->hasAttr(attr))
ret.push_back(type);
return ret;
}
ItemTypeList ThingTypeManager::findItemTypeByCategory(ItemCategory category)
{
ItemTypeList ret;
for(const ItemTypePtr& type : m_itemTypes)
if(type->getCategory() == category)
ret.push_back(type);
return ret;
}
const ThingTypeList& ThingTypeManager::getThingTypes(ThingCategory category)
{
ThingTypeList ret;
if(category >= ThingLastCategory)
stdext::throw_exception(stdext::format("invalid thing type category %d", category));
return m_thingTypes[category];
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef THINGTYPEMANAGER_H
#define THINGTYPEMANAGER_H
#include <framework/global.h>
#include <framework/core/declarations.h>
#include "thingtype.h"
#include "itemtype.h"
class ThingTypeManager
{
public:
void init();
void terminate();
bool loadDat(const std::string& file);
void loadOtb(const std::string& file);
void loadXml(const std::string& file);
void parseItemType(uint16 id, TiXmlElement *elem);
void addItemType(const ItemTypePtr& itemType);
const ItemTypePtr& findItemTypeByClientId(uint16 id);
const ThingTypePtr& getNullThingType() { return m_nullThingType; }
const ItemTypePtr& getNullItemType() { return m_nullItemType; }
const ThingTypePtr& getThingType(uint16 id, ThingCategory category);
const ItemTypePtr& getItemType(uint16 id);
ThingType* rawGetThingType(uint16 id, ThingCategory category) { return m_thingTypes[category][id].get(); }
ItemType* rawGetItemType(uint16 id) { return m_itemTypes[id].get(); }
ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category);
ItemTypeList findItemTypeByCategory(ItemCategory category);
const ThingTypeList& getThingTypes(ThingCategory category);
const ItemTypeList& getItemTypes() { return m_itemTypes; }
uint32 getDatSignature() { return m_datSignature; }
uint32 getOtbMajorVersion() { return m_otbMajorVersion; }
uint32 getOtbMinorVersion() { return m_otbMinorVersion; }
bool isDatLoaded() { return m_datLoaded; }
bool isXmlLoaded() { return m_xmlLoaded; }
bool isOtbLoaded() { return m_otbLoaded; }
bool isValidDatId(uint16 id, ThingCategory category) { return id >= 1 && id < m_thingTypes[category].size(); }
bool isValidOtbId(uint16 id) { return id >= 1 && id < m_itemTypes.size(); }
private:
ThingTypeList m_thingTypes[ThingLastCategory];
ItemTypeList m_reverseItemTypes;
ItemTypeList m_itemTypes;
ThingTypePtr m_nullThingType;
ItemTypePtr m_nullItemType;
bool m_datLoaded;
bool m_xmlLoaded;
bool m_otbLoaded;
uint32 m_otbMinorVersion;
uint32 m_otbMajorVersion;
uint32 m_datSignature;
};
extern ThingTypeManager g_things;
#endif

638
src/client/tile.cpp Normal file
View File

@@ -0,0 +1,638 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "tile.h"
#include "item.h"
#include "thingtypemanager.h"
#include "map.h"
#include "game.h"
#include "localplayer.h"
#include "effect.h"
#include "protocolgame.h"
#include "lightview.h"
#include <framework/graphics/fontmanager.h>
Tile::Tile(const Position& position) :
m_position(position),
m_drawElevation(0),
m_flags(0)
{
}
void Tile::draw(const Point& dest, float scaleFactor, int drawFlags, LightView *lightView)
{
bool animate = drawFlags & Otc::DrawAnimations;
// first bottom items
if(drawFlags & (Otc::DrawGround | Otc::DrawGroundBorders | Otc::DrawOnBottom)) {
m_drawElevation = 0;
for(const ThingPtr& thing : m_things) {
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
break;
if((thing->isGround() && drawFlags & Otc::DrawGround) ||
(thing->isGroundBorder() && drawFlags & Otc::DrawGroundBorders) ||
(thing->isOnBottom() && drawFlags & Otc::DrawOnBottom)) {
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate, lightView);
}
m_drawElevation += thing->getElevation();
if(m_drawElevation > Otc::MAX_ELEVATION)
m_drawElevation = Otc::MAX_ELEVATION;
}
}
int redrawPreviousTopW = 0;
int redrawPreviousTopH = 0;
if(drawFlags & Otc::DrawItems) {
// now common items in reverse order
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
const ThingPtr& thing = *it;
if(thing->isOnTop() || thing->isOnBottom() || thing->isGroundBorder() || thing->isGround() || thing->isCreature())
break;
thing->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate, lightView);
if(thing->isLyingCorpse()) {
redrawPreviousTopW = std::max(thing->getWidth(), redrawPreviousTopW);
redrawPreviousTopH = std::max(thing->getHeight(), redrawPreviousTopH);
}
m_drawElevation += thing->getElevation();
if(m_drawElevation > Otc::MAX_ELEVATION)
m_drawElevation = Otc::MAX_ELEVATION;
}
}
// after we render 2x2 lying corpses, we must redraw previous creatures/ontop above them
if(redrawPreviousTopH > 0 || redrawPreviousTopW > 0) {
int topRedrawFlags = drawFlags & (Otc::DrawCreatures | Otc::DrawEffects | Otc::DrawOnTop | Otc::DrawAnimations);
if(topRedrawFlags) {
for(int x=-redrawPreviousTopW;x<=0;++x) {
for(int y=-redrawPreviousTopH;y<=0;++y) {
if(x == 0 && y == 0)
continue;
const TilePtr& tile = g_map.getTile(m_position.translated(x,y));
if(tile)
tile->draw(dest + Point(x*Otc::TILE_PIXELS, y*Otc::TILE_PIXELS)*scaleFactor, scaleFactor, topRedrawFlags);
}
}
}
}
// creatures
if(drawFlags & Otc::DrawCreatures) {
if(animate) {
for(const CreaturePtr& creature : m_walkingCreatures) {
creature->draw(Point(dest.x + ((creature->getPosition().x - m_position.x)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor,
dest.y + ((creature->getPosition().y - m_position.y)*Otc::TILE_PIXELS - m_drawElevation)*scaleFactor), scaleFactor, animate, lightView);
}
}
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
const ThingPtr& thing = *it;
if(!thing->isCreature())
continue;
CreaturePtr creature = thing->static_self_cast<Creature>();
if(creature && (!creature->isWalking() || !animate))
creature->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate, lightView);
}
}
// effects
if(drawFlags & Otc::DrawEffects) {
for(const EffectPtr& effect : m_effects){
effect->draw(dest - m_drawElevation*scaleFactor, scaleFactor, animate, lightView);
}
}
// top items
if(drawFlags & Otc::DrawOnTop) {
for(const ThingPtr& thing : m_things) {
if(thing->isOnTop()){
thing->draw(dest, scaleFactor, animate, lightView);
}
}
}
// draw translucent light (for tiles beneath holes)
if(hasTranslucentLight() && lightView) {
Light light;
light.intensity = 1;
lightView->addLightSource(dest + Point(16,16) * scaleFactor, scaleFactor, light);
}
}
void Tile::clean()
{
while(!m_things.empty())
removeThing(m_things.front());
}
void Tile::addWalkingCreature(const CreaturePtr& creature)
{
m_walkingCreatures.push_back(creature);
}
void Tile::removeWalkingCreature(const CreaturePtr& creature)
{
auto it = std::find(m_walkingCreatures.begin(), m_walkingCreatures.end(), creature);
if(it != m_walkingCreatures.end())
m_walkingCreatures.erase(it);
}
void Tile::addThing(const ThingPtr& thing, int stackPos)
{
if(!thing)
return;
if(thing->isEffect()) {
m_effects.push_back(thing->static_self_cast<Effect>());
} else {
// priority 854
// 0 - ground, --> -->
// 1 - ground borders --> -->
// 2 - bottom (walls), --> -->
// 3 - on top (doors) --> -->
// 4 - creatures, from top to bottom <-- -->
// 5 - items, from top to bottom <-- <--
if(stackPos < 0 || stackPos == 255) {
int priority = thing->getStackPriority();
// -1 or 255 => auto detect position
// -2 => append
bool append;
if(stackPos == -2)
append = true;
else {
append = (priority <= 3);
// newer protocols does not store creatures in reverse order
if(g_game.getProtocolVersion() >= 854 && priority == 4)
append = !append;
}
for(stackPos = 0; stackPos < (int)m_things.size(); ++stackPos) {
int otherPriority = m_things[stackPos]->getStackPriority();
if((append && otherPriority > priority) || (!append && otherPriority >= priority))
break;
}
} else if(stackPos > (int)m_things.size())
stackPos = m_things.size();
m_things.insert(m_things.begin() + stackPos, thing);
if(m_things.size() > MAX_THINGS)
removeThing(m_things[MAX_THINGS]);
/*
// check stack priorities
// this code exists to find stackpos bugs faster
int lastPriority = 0;
for(const ThingPtr& thing : m_things) {
int priority = thing->getStackPriority();
assert(lastPriority <= priority);
lastPriority = priority;
}
*/
}
thing->setPosition(m_position);
thing->onAppear();
if(thing->isTranslucent())
checkTranslucentLight();
}
bool Tile::removeThing(ThingPtr thing)
{
if(!thing)
return false;
bool removed = false;
if(thing->isEffect()) {
EffectPtr effect = thing->static_self_cast<Effect>();
auto it = std::find(m_effects.begin(), m_effects.end(), effect);
if(it != m_effects.end()) {
m_effects.erase(it);
removed = true;
}
} else {
auto it = std::find(m_things.begin(), m_things.end(), thing);
if(it != m_things.end()) {
m_things.erase(it);
removed = true;
}
}
thing->onDisappear();
if(thing->isTranslucent())
checkTranslucentLight();
return removed;
}
ThingPtr Tile::getThing(int stackPos)
{
if(stackPos >= 0 && stackPos < (int)m_things.size())
return m_things[stackPos];
return nullptr;
}
EffectPtr Tile::getEffect(uint16 id)
{
for(const EffectPtr& effect : m_effects)
if(effect->getId() == id)
return effect;
return nullptr;
}
bool Tile::hasThing(const ThingPtr& thing)
{
return std::find(m_things.begin(), m_things.end(), thing) != m_things.end();
}
int Tile::getThingStackpos(const ThingPtr& thing)
{
for(uint stackpos = 0; stackpos < m_things.size(); ++stackpos) {
if(thing == m_things[stackpos])
return stackpos;
}
return -1;
}
ThingPtr Tile:: getTopThing()
{
if(isEmpty())
return nullptr;
for(const ThingPtr& thing : m_things) {
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop() && !thing->isCreature())
return thing;
}
return m_things[m_things.size() - 1];
}
std::vector<ItemPtr> Tile::getItems()
{
std::vector<ItemPtr> items;
for(const ThingPtr& thing : m_things) {
if(!thing->isItem())
continue;
ItemPtr item = thing->static_self_cast<Item>();
items.push_back(item);
}
return items;
}
std::vector<CreaturePtr> Tile::getCreatures()
{
std::vector<CreaturePtr> creatures;
for(const ThingPtr& thing : m_things) {
if(thing->isCreature())
creatures.push_back(thing->static_self_cast<Creature>());
}
return creatures;
}
ItemPtr Tile::getGround()
{
ThingPtr firstObject = getThing(0);
if(!firstObject)
return nullptr;
if(firstObject->isGround() && firstObject->isItem())
return firstObject->static_self_cast<Item>();
return nullptr;
}
int Tile::getGroundSpeed()
{
int groundSpeed = 100;
if(ItemPtr ground = getGround())
groundSpeed = ground->getGroundSpeed();
return groundSpeed;
}
uint8 Tile::getMinimapColorByte()
{
uint8 color = 0;
for(const ThingPtr& thing : m_things) {
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())
break;
uint8 c = thing->getMinimapColor();
if(c != 0)
color = c;
}
return color;
}
ThingPtr Tile::getTopLookThing()
{
if(isEmpty())
return nullptr;
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(!thing->isIgnoreLook() && (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()))
return thing;
}
return m_things[0];
}
ThingPtr Tile::getTopUseThing()
{
if(isEmpty())
return nullptr;
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop() && !thing->isCreature()))
return thing;
}
return m_things[0];
}
CreaturePtr Tile::getTopCreature()
{
CreaturePtr creature;
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(thing->isLocalPlayer()) // return local player if there is no other creature
creature = thing->static_self_cast<Creature>();
else if(thing->isCreature() && !thing->isLocalPlayer())
return thing->static_self_cast<Creature>();
}
if(!creature && !m_walkingCreatures.empty())
creature = m_walkingCreatures.back();
// check for walking creatures in tiles around
if(!creature) {
for(int xi=-1;xi<=1;++xi) {
for(int yi=-1;yi<=1;++yi) {
Position pos = m_position.translated(xi, yi);
if(pos == m_position)
continue;
const TilePtr& tile = g_map.getTile(pos);
if(tile) {
for(const CreaturePtr& c : tile->getCreatures()) {
if(c->isWalking() && c->getLastStepFromPosition() == m_position && c->getStepProgress() < 0.75f) {
creature = c;
}
}
}
}
}
}
return creature;
}
ThingPtr Tile::getTopMoveThing()
{
if(isEmpty())
return nullptr;
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop() && !thing->isCreature()) {
if(i > 0 && thing->isNotMoveable())
return m_things[i-1];
return thing;
}
}
for(const ThingPtr& thing : m_things) {
if(thing->isCreature())
return thing;
}
return m_things[0];
}
ThingPtr Tile::getTopMultiUseThing(bool ignoreCreature)
{
// this is related to classic controls, getting top item, forceuse for creature
if(isEmpty())
return nullptr;
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) {
if(thing->isCreature() && ignoreCreature)
continue;
if(i > 0 && thing->isSplash())
return m_things[i-1];
return thing;
}
}
for(uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnTop()) {
if(thing->isCreature() && ignoreCreature)
continue;
return thing;
}
}
return m_things[0];
}
bool Tile::isWalkable()
{
if(!getGround())
return false;
for(const ThingPtr& thing : m_things) {
if(thing->isNotWalkable())
return false;
if(thing->isCreature()) {
CreaturePtr creature = thing->static_self_cast<Creature>();
if(!creature->isPassable() && creature->canBeSeen())
return false;
}
}
return true;
}
bool Tile::changesFloor()
{
for(const ThingPtr& thing : m_things) {
if(thing->isTranslucent() || (thing->isOnBottom() && thing->hasElevation()))
return true;
}
return false;
}
bool Tile::isPathable()
{
for(const ThingPtr& thing : m_things) {
if(thing->isNotPathable())
return false;
}
return true;
}
bool Tile::isFullGround()
{
ItemPtr ground = getGround();
if(ground && ground->isFullGround())
return true;
return false;
}
bool Tile::isFullyOpaque()
{
ThingPtr firstObject = getThing(0);
return firstObject && firstObject->isFullGround();
}
bool Tile::isSingleDimension()
{
if(!m_walkingCreatures.empty())
return false;
for(const ThingPtr& thing : m_things) {
if(thing->getHeight() != 1 || thing->getWidth() != 1)
return false;
}
return true;
}
bool Tile::isLookPossible()
{
for(const ThingPtr& thing : m_things) {
if(thing->blockProjectile())
return false;
}
return true;
}
bool Tile::isClickable()
{
bool hasGround = false;
bool hasOnBottom = false;
bool hasIgnoreLook = false;
for(const ThingPtr& thing : m_things) {
if(thing->isGround())
hasGround = true;
if(thing->isOnBottom())
hasOnBottom = true;
if(thing->isIgnoreLook())
hasIgnoreLook = true;
if((hasGround || hasOnBottom) && !hasIgnoreLook)
return true;
}
return false;
}
bool Tile::isEmpty()
{
return m_things.size() == 0;
}
bool Tile::isDrawable()
{
return !m_things.empty() || !m_walkingCreatures.empty() || !m_effects.empty();
}
bool Tile::mustHookEast()
{
for(const ThingPtr& thing : m_things)
if(thing->isHookEast())
return true;
return false;
}
bool Tile::mustHookSouth()
{
for(const ThingPtr& thing : m_things)
if(thing->isHookSouth())
return true;
return false;
}
bool Tile::hasCreature()
{
for(const ThingPtr& thing : m_things)
if(thing->isCreature())
return true;
return false;
}
bool Tile::limitsFloorsView()
{
// ground and walls limits the view
ThingPtr firstThing = getThing(0);
if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom()))
return true;
return false;
}
bool Tile::canErase()
{
return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty() && m_flags == 0;
}
bool Tile::hasElevation(int elevation)
{
int count = 0;
for(const ThingPtr& thing : m_things)
if(thing->getElevation() > 0)
count++;
return count >= elevation;
}
void Tile::checkTranslucentLight()
{
if(m_position.z != Otc::SEA_FLOOR)
return;
Position downPos = m_position;
if(!downPos.down())
return;
TilePtr tile = g_map.getOrCreateTile(downPos);
if(!tile)
return;
bool translucent = false;
for(const ThingPtr& thing : m_things) {
if(thing->isTranslucent() || thing->hasLensHelp()) {
translucent = true;
break;
}
}
if(translucent)
tile->m_flags = tile->m_flags | TILESTATE_TRANSLUECENT_LIGHT;
else
tile->m_flags = tile->m_flags & ~TILESTATE_TRANSLUECENT_LIGHT;
}

135
src/client/tile.h Normal file
View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TILE_H
#define TILE_H
#include "declarations.h"
#include "mapview.h"
#include "effect.h"
#include "creature.h"
#include "item.h"
#include <framework/luaengine/luaobject.h>
enum tileflags_t
{
TILESTATE_NONE = 0,
TILESTATE_PROTECTIONZONE = 1 << 0,
TILESTATE_TRASHED = 1 << 1,
TILESTATE_OPTIONALZONE = 1 << 2,
TILESTATE_NOLOGOUT = 1 << 3,
TILESTATE_HARDCOREZONE = 1 << 4,
TILESTATE_REFRESH = 1 << 5,
// internal usage
TILESTATE_HOUSE = 1 << 6,
TILESTATE_TELEPORT = 1 << 17,
TILESTATE_MAGICFIELD = 1 << 18,
TILESTATE_MAILBOX = 1 << 19,
TILESTATE_TRASHHOLDER = 1 << 20,
TILESTATE_BED = 1 << 21,
TILESTATE_DEPOT = 1 << 22,
TILESTATE_TRANSLUECENT_LIGHT = 1 << 23
};
#pragma pack(push,1) // disable memory alignment
class Tile : public LuaObject
{
public:
enum {
MAX_THINGS = 10
};
Tile(const Position& position);
void draw(const Point& dest, float scaleFactor, int drawFlags, LightView *lightView = nullptr);
public:
void clean();
void addWalkingCreature(const CreaturePtr& creature);
void removeWalkingCreature(const CreaturePtr& creature);
void addThing(const ThingPtr& thing, int stackPos);
bool removeThing(ThingPtr thing);
ThingPtr getThing(int stackPos);
EffectPtr getEffect(uint16 id);
bool hasThing(const ThingPtr& thing);
int getThingStackpos(const ThingPtr& thing);
ThingPtr getTopThing();
ThingPtr getTopLookThing();
ThingPtr getTopUseThing();
CreaturePtr getTopCreature();
ThingPtr getTopMoveThing();
ThingPtr getTopMultiUseThing(bool ignoreCreature = true);
const Position& getPosition() { return m_position; }
int getDrawElevation() { return m_drawElevation; }
std::vector<ItemPtr> getItems();
std::vector<CreaturePtr> getCreatures();
std::vector<CreaturePtr> getWalkingCreatures() { return m_walkingCreatures; }
std::vector<ThingPtr> getThings() { return m_things; }
ItemPtr getGround();
int getGroundSpeed();
uint8 getMinimapColorByte();
int getThingCount() { return m_things.size() + m_effects.size(); }
bool isPathable();
bool isWalkable();
bool changesFloor();
bool isFullGround();
bool isFullyOpaque();
bool isSingleDimension();
bool isLookPossible();
bool isClickable();
bool isEmpty();
bool isDrawable();
bool hasTranslucentLight() { return m_flags & TILESTATE_TRANSLUECENT_LIGHT; }
bool mustHookSouth();
bool mustHookEast();
bool hasCreature();
bool limitsFloorsView();
bool canErase();
bool hasElevation(int elevation = 1);
void setFlags(tileflags_t flags) { m_flags |= (uint32)flags; }
uint32 getFlags() { return m_flags; }
void setHouseId(uint32 hid) { m_houseId = hid; }
uint32 getHouseId() { return m_houseId; }
bool isHouseTile() const { return (m_flags & TILESTATE_HOUSE) == TILESTATE_HOUSE; }
TilePtr asTile() { return static_self_cast<Tile>(); }
private:
void checkTranslucentLight();
stdext::packed_vector<CreaturePtr> m_walkingCreatures;
stdext::packed_vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
stdext::packed_vector<ThingPtr> m_things;
Position m_position;
uint8 m_drawElevation;
uint32 m_flags, m_houseId;
};
#pragma pack(pop)
#endif

65
src/client/towns.cpp Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "towns.h"
TownManager g_towns;
Town::Town(uint32 tid, const std::string& name, const Position& pos)
: m_id(tid), m_name(name)
{
if(pos.isValid())
m_pos = pos;
}
TownManager::TownManager()
{
m_nullTown = TownPtr(new Town);
}
void TownManager::addTown(const TownPtr &town)
{
if(findTown(town->getId()) == m_towns.end())
m_towns.push_back(town);
}
void TownManager::removeTown(uint32 townId)
{
auto it = findTown(townId);
if(it != m_towns.end())
m_towns.erase(it);
}
const TownPtr& TownManager::getTown(uint32 townId)
{
auto it = std::find_if(m_towns.begin(), m_towns.end(),
[=] (const TownPtr& town) -> bool { return town->getId() == townId; });
if(it != m_towns.end())
return *it;
return m_nullTown;
}
TownList::iterator TownManager::findTown(uint32 townId)
{
return std::find_if(m_towns.begin(), m_towns.end(),
[=] (const TownPtr& town) -> bool { return town->getId() == townId; });
}

71
src/client/towns.h Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TOWNS_H
#define TOWNS_H
#include "declarations.h"
#include <framework/luaengine/luaobject.h>
class Town : public LuaObject
{
public:
Town() { }
Town(uint32 tid, const std::string& name, const Position& pos=Position());
void setId(uint32 tid) { m_id = tid; }
void setName(const std::string& name) { m_name = name; }
void setPos(const Position& pos) { m_pos = pos; }
uint32 getId() { return m_id; }
std::string getName() { return m_name; }
Position getPos() { return m_pos; }
private:
uint32 m_id;
std::string m_name;
Position m_pos; // temple pos
};
class TownManager
{
public:
TownManager();
void addTown(const TownPtr& town);
void removeTown(uint32 townId);
const TownPtr& getTown(uint32 townId);
TownList getTowns() { return m_towns; }
void clear() { m_towns.clear(); m_nullTown = nullptr; }
private:
TownList m_towns;
TownPtr m_nullTown;
protected:
TownList::iterator findTown(uint32 townId);
};
extern TownManager g_towns;
#endif

57
src/client/uicreature.cpp Normal file
View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "uicreature.h"
#include <framework/otml/otml.h>
#include <framework/graphics/graphics.h>
void UICreature::drawSelf(Fw::DrawPane drawPane)
{
if((drawPane & Fw::ForegroundPane) == 0)
return;
UIWidget::drawSelf(drawPane);
if(m_creature) {
Rect drawRect = getPaddingRect();
g_painter->setColor(Color::white);
m_creature->drawOutfit(drawRect, !m_fixedCreatureSize);
}
}
void UICreature::setOutfit(const Outfit& outfit)
{
if(!m_creature)
m_creature = CreaturePtr(new Creature);
m_creature->setDirection(Otc::South);
m_creature->setOutfit(outfit);
}
void UICreature::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "fixed-creature-size")
setFixedCreatureSize(node->value<bool>());
}
}

49
src/client/uicreature.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UICREATURE_H
#define UICREATURE_H
#include "declarations.h"
#include <framework/ui/uiwidget.h>
#include "creature.h"
class UICreature : public UIWidget
{
public:
void drawSelf(Fw::DrawPane drawPane);
void setCreature(const CreaturePtr& creature) { m_creature = creature; }
void setFixedCreatureSize(bool fixed) { m_fixedCreatureSize = fixed; }
void setOutfit(const Outfit& outfit);
CreaturePtr getCreature() { return m_creature; }
bool isFixedCreatureSize() { return m_fixedCreatureSize; }
protected:
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
CreaturePtr m_creature;
stdext::boolean<false> m_fixedCreatureSize;
};
#endif

103
src/client/uiitem.cpp Normal file
View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "uiitem.h"
#include <framework/otml/otml.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/fontmanager.h>
UIItem::UIItem()
{
m_draggable = true;
}
void UIItem::drawSelf(Fw::DrawPane drawPane)
{
if((drawPane & Fw::ForegroundPane) == 0)
return;
// draw style components in order
if(m_backgroundColor.aF() > Fw::MIN_ALPHA) {
Rect backgroundDestRect = m_rect;
backgroundDestRect.expand(-m_borderWidth.top, -m_borderWidth.right, -m_borderWidth.bottom, -m_borderWidth.left);
drawBackground(m_rect);
}
drawImage(m_rect);
if(m_item) {
Rect drawRect = getPaddingRect();
Point dest = drawRect.bottomRight() + Point(1,1);
int exactSize = std::max(32, m_item->getExactSize());
if(exactSize == 0)
return;
float scaleFactor = std::min(drawRect.width() / (float)exactSize, drawRect.height() / (float)exactSize);
dest += (m_item->getDisplacement() - Point(32,32)) * scaleFactor;
if(isEnabled())
g_painter->setColor(Color::white);
else
g_painter->setColor(Color(100, 100, 100));
m_item->draw(dest, scaleFactor, true);
if(m_font && (m_item->isStackable() || m_item->isChargeable()) && m_item->getCountOrSubType() > 1) {
std::string count = stdext::to_string(m_item->getCount());
g_painter->setColor(Color(231, 231, 231));
m_font->drawText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight);
}
// debug, show item id
//m_font->drawText(stdext::to_string(m_item->getId()), m_rect, Fw::AlignBottomRight);
}
drawBorder(m_rect);
drawIcon(m_rect);
drawText(m_rect);
}
void UIItem::setItemId(int id)
{
if(!m_item && id != 0)
m_item = Item::create(id);
else {
// remove item
if(id == 0)
m_item = nullptr;
else
m_item->setId(id);
}
}
void UIItem::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "item-id")
setItemId(node->value<int>());
else if(node->tag() == "item-count")
setItemCount(node->value<int>());
else if(node->tag() == "virtual")
setVirtual(node->value<bool>());
}
}

56
src/client/uiitem.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UIITEM_H
#define UIITEM_H
#include "declarations.h"
#include <framework/ui/uiwidget.h>
#include "item.h"
class UIItem : public UIWidget
{
public:
UIItem();
void drawSelf(Fw::DrawPane drawPane);
void setItemId(int id);
void setItemCount(int count) { if(m_item) m_item->setCount(count); }
void setItemSubType(int subType) { if(m_item) m_item->setSubType(subType); }
void setItem(const ItemPtr& item) { m_item = item; }
void setVirtual(bool virt) { m_virtual = virt; }
void clearItem() { setItemId(0); }
int getItemId() { return m_item ? m_item->getId() : 0; }
int getItemCount() { return m_item ? m_item->getCount() : 0; }
int getItemSubType() { return m_item ? m_item->getSubType() : 0; }
ItemPtr getItem() { return m_item; }
bool isVirtual() { return m_virtual; }
protected:
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
ItemPtr m_item;
stdext::boolean<false> m_virtual;
};
#endif

235
src/client/uimap.cpp Normal file
View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "uimap.h"
#include "game.h"
#include "map.h"
#include "mapview.h"
#include <framework/otml/otml.h>
#include <framework/graphics/graphics.h>
#include "localplayer.h"
UIMap::UIMap()
{
m_draggable = true;
m_mapView = MapViewPtr(new MapView);
m_zoom = m_mapView->getVisibleDimension().height();
m_aspectRatio = 0.0f;
m_maxZoomIn = 3;
m_maxZoomOut = 512;
m_mapRect.resize(1,1);
g_map.addMapView(m_mapView);
}
UIMap::~UIMap()
{
g_map.removeMapView(m_mapView);
}
void UIMap::drawSelf(Fw::DrawPane drawPane)
{
UIWidget::drawSelf(drawPane);
if(drawPane & Fw::ForegroundPane) {
// draw map border
g_painter->setColor(Color::black);
g_painter->drawBoundingRect(m_mapRect.expanded(1));
if(drawPane != Fw::BothPanes) {
glDisable(GL_BLEND);
g_painter->setColor(Color::alpha);
g_painter->drawFilledRect(m_mapRect);
glEnable(GL_BLEND);
}
}
if(drawPane & Fw::BackgroundPane) {
g_painter->setColor(Color::white);
m_mapView->draw(m_mapRect);
}
}
bool UIMap::setZoom(int zoom)
{
m_zoom = std::min(std::max(zoom, m_maxZoomIn), m_maxZoomOut);
updateVisibleDimension();
return false;
}
bool UIMap::zoomIn()
{
int delta = 2;
if(m_zoom - delta <= m_maxZoomIn)
return false;
m_zoom -= delta;
updateVisibleDimension();
return true;
}
bool UIMap::zoomOut()
{
int delta = 2;
if(m_zoom + delta >= m_maxZoomOut)
return false;
m_zoom += 2;
updateVisibleDimension();
return true;
}
void UIMap::setVisibleDimension(const Size& visibleDimension)
{
m_mapView->setVisibleDimension(visibleDimension);
if(m_aspectRatio != 0.0f) {
m_aspectRatio = visibleDimension.ratio();
updateMapSize();
}
}
void UIMap::setKeepAspectRatio(bool enable)
{
if(enable)
m_aspectRatio = getVisibleDimension().ratio();
else
m_aspectRatio = 0.0f;
updateMapSize();
}
Position UIMap::getPosition(const Point& mousePos)
{
if(!m_mapRect.contains(mousePos))
return Position();
Point relativeMousePos = mousePos - m_mapRect.topLeft();
Size visibleSize = getVisibleDimension() * m_mapView->getTileSize();
Position cameraPosition = getCameraPosition();
// if we have no camera, its impossible to get the tile
if(!cameraPosition.isValid())
return Position();
float scaleFactor = m_mapView->getTileSize() / (float)Otc::TILE_PIXELS;
float horizontalStretchFactor = visibleSize.width() / (float)m_mapRect.width();
float verticalStretchFactor = visibleSize.height() / (float)m_mapRect.height();
Point tilePos2D = Point(relativeMousePos.x * horizontalStretchFactor, relativeMousePos.y * verticalStretchFactor);
if(m_mapView->isFollowingCreature())
tilePos2D += getFollowingCreature()->getWalkOffset() * scaleFactor;
tilePos2D /= m_mapView->getTileSize();
Point visibleCenterOffset = m_mapView->getVisibleCenterOffset();
Position position = Position(1 + (int)tilePos2D.x - visibleCenterOffset.x, 1 + (int)tilePos2D.y - visibleCenterOffset.y, 0) + cameraPosition;
if(!position.isValid())
return Position();
return position;
}
TilePtr UIMap::getTile(const Point& mousePos)
{
Position tilePos = getPosition(mousePos);
if(!tilePos.isValid())
return nullptr;
// we must check every floor, from top to bottom to check for a clickable tile
TilePtr tile;
tilePos.coveredUp(tilePos.z - m_mapView->getCachedFirstVisibleFloor());
for(int i = m_mapView->getCachedFirstVisibleFloor(); i <= m_mapView->getCachedLastVisibleFloor(); i++) {
tile = g_map.getTile(tilePos);
if(tile && tile->isClickable())
break;
tilePos.coveredDown();
}
if(!tile || !tile->isClickable())
return nullptr;
return tile;
}
void UIMap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "multifloor")
setMultifloor(node->value<bool>());
else if(node->tag() == "auto-view-mode")
setAutoViewMode(node->value<bool>());
else if(node->tag() == "draw-texts")
setDrawTexts(node->value<bool>());
else if(node->tag() == "draw-minimap-colors")
setDrawMinimapColors(node->value<bool>());
else if(node->tag() == "draw-lights")
setDrawLights(node->value<bool>());
else if(node->tag() == "animated")
setAnimated(node->value<bool>());
}
}
void UIMap::onGeometryChange(const Rect& oldRect, const Rect& newRect)
{
UIWidget::onGeometryChange(oldRect, newRect);
updateMapSize();
}
void UIMap::updateVisibleDimension()
{
int dimensionHeight = m_zoom;
float ratio = 1;
if(!m_mapRect.isEmpty())
ratio = m_mapRect.size().ratio();
if(dimensionHeight % 2 == 0)
dimensionHeight += 1;
int dimensionWidth = m_zoom * ratio;
if(dimensionWidth % 2 == 0)
dimensionWidth += 1;
m_mapView->setVisibleDimension(Size(dimensionWidth, dimensionHeight));
if(m_aspectRatio != 0.0f)
updateMapSize();
}
void UIMap::updateMapSize()
{
Rect clippingRect = getPaddingRect();
Size mapSize;
if(m_aspectRatio != 0.0f) {
Rect mapRect = clippingRect.expanded(-1);
mapSize = Size(m_aspectRatio*m_zoom, m_zoom);
mapSize.scale(mapRect.size(), Fw::KeepAspectRatio);
} else {
mapSize = clippingRect.expanded(-1).size();
}
m_mapRect.resize(mapSize);
m_mapRect.moveCenter(clippingRect.center());
m_mapView->optimizeForSize(mapSize);
if(m_aspectRatio == 0.0f)
updateVisibleDimension();
}

98
src/client/uimap.h Normal file
View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UIMAP_H
#define UIMAP_H
#include "declarations.h"
#include <framework/ui/uiwidget.h>
#include "tile.h"
#include "mapview.h"
class UIMap : public UIWidget
{
public:
UIMap();
~UIMap();
void drawSelf(Fw::DrawPane drawPane);
bool setZoom(int zoom);
bool zoomIn();
bool zoomOut();
void followCreature(const CreaturePtr& creature) { m_mapView->followCreature(creature); }
void setCameraPosition(const Position& pos) { m_mapView->setCameraPosition(pos); }
void setMaxZoomIn(int maxZoomIn) { m_maxZoomIn = maxZoomIn; }
void setMaxZoomOut(int maxZoomOut) { m_maxZoomOut = maxZoomOut; }
void setMultifloor(bool enable) { m_mapView->setMultifloor(enable); }
void setVisibleDimension(const Size& visibleDimension);
void setViewMode(MapView::ViewMode viewMode) { m_mapView->setViewMode(viewMode); }
void setAutoViewMode(bool enable) { m_mapView->setAutoViewMode(enable); }
void setDrawFlags(Otc::DrawFlags drawFlags) { m_mapView->setDrawFlags(drawFlags); }
void setDrawTexts(bool enable) { m_mapView->setDrawTexts(enable); }
void setDrawMinimapColors(bool enable) { m_mapView->setDrawMinimapColors(enable); }
void setDrawLights(bool enable) { m_mapView->setDrawLights(enable); }
void setAnimated(bool enable) { m_mapView->setAnimated(enable); }
void setKeepAspectRatio(bool enable);
void setMapShader(const PainterShaderProgramPtr& shader) { m_mapView->setShader(shader); }
void setMinimumAmbientLight(float intensity) { m_mapView->setMinimumAmbientLight(intensity); }
bool isMultifloor() { return m_mapView->isMultifloor(); }
bool isAutoViewModeEnabled() { return m_mapView->isAutoViewModeEnabled(); }
bool isDrawingTexts() { return m_mapView->isDrawingTexts(); }
bool isDrawingMinimapColors() { return m_mapView->isDrawingMinimapColors(); }
bool isDrawingLights() { return m_mapView->isDrawingLights(); }
bool isAnimating() { return m_mapView->isAnimating(); }
bool isKeepAspectRatioEnabled() { return m_aspectRatio != 0.0f; }
Size getVisibleDimension() { return m_mapView->getVisibleDimension(); }
MapView::ViewMode getViewMode() { return m_mapView->getViewMode(); }
CreaturePtr getFollowingCreature() { return m_mapView->getFollowingCreature(); }
Otc::DrawFlags getDrawFlags() { return m_mapView->getDrawFlags(); }
Position getCameraPosition() { return m_mapView->getCameraPosition(); }
Position getPosition(const Point& mousePos);
TilePtr getTile(const Point& mousePos);
int getMaxZoomIn() { return m_maxZoomIn; }
int getMaxZoomOut() { return m_maxZoomOut; }
int getZoom() { return m_zoom; }
PainterShaderProgramPtr getMapShader() { return m_mapView->getShader(); }
float getMinimumAmbientLight() { return m_mapView->getMinimumAmbientLight(); }
protected:
virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect);
private:
void updateVisibleDimension();
void updateMapSize();
int m_zoom;
MapViewPtr m_mapView;
Rect m_mapRect;
float m_aspectRatio;
int m_maxZoomIn;
int m_maxZoomOut;
};
#endif

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "uiprogressrect.h"
#include <framework/otml/otml.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/fontmanager.h>
UIProgressRect::UIProgressRect()
{
m_percent = 0;
}
void UIProgressRect::drawSelf(Fw::DrawPane drawPane)
{
if((drawPane & Fw::ForegroundPane) == 0)
return;
g_painter->setColor(m_backgroundColor);
// todo: check +1 to right/bottom
// todo: add smooth
Rect drawRect = getPaddingRect();
// 0% - 12.5% (12.5)
// triangle from top center, to top right (var x)
if(m_percent < 12.5) {
Point var = Point(std::max(m_percent - 0.0, 0.0) * (drawRect.right() - drawRect.horizontalCenter()) / 12.5, 0);
g_painter->drawFilledTriangle(drawRect.center(), drawRect.topRight() + Point(1,0), drawRect.topCenter() + var);
}
// 12.5% - 37.5% (25)
// triangle from top right to bottom right (var y)
if(m_percent < 37.5) {
Point var = Point(0, std::max(m_percent - 12.5, 0.0) * (drawRect.bottom() - drawRect.top()) / 25.0);
g_painter->drawFilledTriangle(drawRect.center(), drawRect.bottomRight() + Point(1,1), drawRect.topRight() + var + Point(1,0));
}
// 37.5% - 62.5% (25)
// triangle from bottom right to bottom left (var x)
if(m_percent < 62.5) {
Point var = Point(std::max(m_percent - 37.5, 0.0) * (drawRect.right() - drawRect.left()) / 25.0, 0);
g_painter->drawFilledTriangle(drawRect.center(), drawRect.bottomLeft() + Point(0,1), drawRect.bottomRight() - var + Point(1,1));
}
// 62.5% - 87.5% (25)
// triangle from bottom left to top left
if(m_percent < 87.5) {
Point var = Point(0, std::max(m_percent - 62.5, 0.0) * (drawRect.bottom() - drawRect.top()) / 25.0);
g_painter->drawFilledTriangle(drawRect.center(), drawRect.topLeft(), drawRect.bottomLeft() - var + Point(0,1));
}
// 87.5% - 100% (12.5)
// triangle from top left to top center
if(m_percent < 100) {
Point var = Point(std::max(m_percent - 87.5, 0.0) * (drawRect.horizontalCenter() - drawRect.left()) / 12.5, 0);
g_painter->drawFilledTriangle(drawRect.center(), drawRect.topCenter(), drawRect.topLeft() + var);
}
drawImage(m_rect);
drawBorder(m_rect);
drawIcon(m_rect);
drawText(m_rect);
}
void UIProgressRect::setPercent(float percent)
{
m_percent = std::max(std::min((double)percent, 100.0), 0.0);
}
void UIProgressRect::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "percent")
setPercent(node->value<float>());
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UIPROGRESSRECT_H
#define UIPROGRESSRECT_H
#include "declarations.h"
#include <framework/ui/uiwidget.h>
#include "item.h"
class UIProgressRect : public UIWidget
{
public:
UIProgressRect();
void drawSelf(Fw::DrawPane drawPane);
void setPercent(float percent);
float getPercent() { return m_percent; }
protected:
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
float m_percent;
};
#endif