Open sourced 90% of files

This commit is contained in:
OTCv8
2020-06-10 17:42:52 +02:00
parent 541e189d3f
commit 04b9c2590c
285 changed files with 58231 additions and 0 deletions

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

@@ -0,0 +1,113 @@
# 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(-DCLIENT)
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_client.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}/animator.h
${CMAKE_CURRENT_LIST_DIR}/animator.cpp
${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}/minimap.cpp
${CMAKE_CURRENT_LIST_DIR}/minimap.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_client.cpp
${CMAKE_CURRENT_LIST_DIR}/luavaluecasts_client.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}/uiminimap.cpp
${CMAKE_CURRENT_LIST_DIR}/uiminimap.h
${CMAKE_CURRENT_LIST_DIR}/uiprogressrect.cpp
${CMAKE_CURRENT_LIST_DIR}/uiprogressrect.h
${CMAKE_CURRENT_LIST_DIR}/uimapanchorlayout.cpp
${CMAKE_CURRENT_LIST_DIR}/uimapanchorlayout.h
${CMAKE_CURRENT_LIST_DIR}/uisprite.cpp
${CMAKE_CURRENT_LIST_DIR}/uisprite.h
# util
${CMAKE_CURRENT_LIST_DIR}/position.h
)
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/luafunctions.cpp
PROPERTIES LANGUAGE CXX COMPILE_FLAGS "-g0 -Os")

101
src/client/animatedtext.cpp Normal file
View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2010-2017 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 "game.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)
{
static float tf = Otc::ANIMATED_TEXT_DURATION;
static float tftf = Otc::ANIMATED_TEXT_DURATION * Otc::ANIMATED_TEXT_DURATION;
Point p = dest;
Size textSize = m_cachedText.getTextSize();
float t = m_animationTimer.ticksElapsed();
p.x -= textSize.width() / 2;
if(g_game.getFeature(Otc::GameDiagonalAnimatedText)) {
p.x -= (4 * t / tf) + (8 * t * t / tftf);
}
p.y += (-48 * t) / tf;
p += m_offset;
Rect rect(p, textSize);
if(visibleRect.contains(rect)) {
float t0 = tf / 1.2;
Color color = m_color;
if(t > t0) {
color.setAlpha((float)(1 - (t - t0) / (tf - t0)));
}
m_cachedText.draw(rect, color);
}
}
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);
}
bool AnimatedText::merge(const AnimatedTextPtr& other)
{
if(other->getColor() != m_color)
return false;
if(other->getCachedText().getFont() != m_cachedText.getFont())
return false;
if(m_animationTimer.ticksElapsed() > Otc::ANIMATED_TEXT_DURATION / 2.5)
return false;
try {
int number = stdext::safe_cast<int>(m_cachedText.getText());
int otherNumber = stdext::safe_cast<int>(other->getCachedText().getText());
m_cachedText.setText(std::to_string(number + otherNumber));
return true;
} catch(...) {}
return false;
}

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

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2010-2017 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);
void setOffset(const Point& offset) { m_offset = offset; }
Color getColor() { return m_color; }
const CachedText& getCachedText() const { return m_cachedText; }
Point getOffset() { return m_offset; }
Timer getTimer() { return m_animationTimer; }
bool merge(const AnimatedTextPtr& other);
AnimatedTextPtr asAnimatedText() { return static_self_cast<AnimatedText>(); }
bool isAnimatedText() { return true; }
std::string getText() { return m_cachedText.getText(); }
protected:
virtual void onAppear();
private:
Color m_color;
Timer m_animationTimer;
CachedText m_cachedText;
Point m_offset;
};
#endif

244
src/client/animator.cpp Normal file
View File

@@ -0,0 +1,244 @@
/*
* Copyright (c) 2010-2017 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 "declarations.h"
#include "animator.h"
#include <framework/core/clock.h>
#include <framework/core/filestream.h>
#include <framework/util/extras.h>
#include <framework/stdext/fastrand.h>
Animator::Animator()
{
m_animationPhases = 0;
m_startPhase = 0;
m_loopCount = 0;
m_async = false;
m_currentDuration = 0;
m_currentDirection = AnimDirForward;
m_currentLoop = 0;
m_lastPhaseTicks = 0;
m_isComplete = false;
m_phase = 0;
}
void Animator::unserialize(int animationPhases, const FileStreamPtr& fin)
{
m_animationPhases = animationPhases;
m_async = fin->getU8() == 0;
m_loopCount = fin->get32();
m_startPhase = fin->get8();
for(int i = 0; i < m_animationPhases; ++i) {
int minimum = fin->getU32();
int maximum = fin->getU32();
m_phaseDurations.push_back(std::make_pair(minimum, std::max(0, maximum - minimum)));
}
m_phase = getStartPhase();
VALIDATE(m_animationPhases == (int)m_phaseDurations.size());
VALIDATE(m_startPhase >= -1 && m_startPhase < m_animationPhases);
}
void Animator::serialize(const FileStreamPtr& fin)
{
fin->addU8(m_async ? 0 : 1);
fin->add32(m_loopCount);
fin->add8(m_startPhase);
for(auto& phase : m_phaseDurations) {
fin->addU32(phase.first);
fin->addU32(phase.first + phase.second);
}
}
void Animator::setPhase(int phase)
{
if(m_phase == phase) return;
if(m_async) {
if(phase == AnimPhaseAsync)
m_phase = 0;
else if(phase == AnimPhaseRandom)
m_phase = (int)stdext::random_range(0, (long)m_animationPhases);
else if(phase >= 0 && phase < m_animationPhases)
m_phase = phase;
else
m_phase = getStartPhase();
m_isComplete = false;
m_lastPhaseTicks = g_clock.millis();
m_currentDuration = getPhaseDuration(phase);
m_currentLoop = 0;
} else
calculateSynchronous();
}
int Animator::getPhase()
{
ticks_t ticks = g_clock.millis();
if(ticks != m_lastPhaseTicks && !m_isComplete) {
int elapsedTicks = (int)(ticks - m_lastPhaseTicks);
if(elapsedTicks >= m_currentDuration) {
int phase = 0;
if(m_loopCount < 0)
phase = getPingPongPhase();
else
phase = getLoopPhase();
if(m_phase != phase) {
int duration = getPhaseDuration(phase) - (elapsedTicks - m_currentDuration);
if(duration < 0 && !m_async) {
calculateSynchronous();
} else {
m_phase = phase;
m_currentDuration = std::max<int>(0, duration);
}
} else
m_isComplete = true;
} else
m_currentDuration -= elapsedTicks;
m_lastPhaseTicks = ticks;
}
return m_phase;
}
int Animator::getPhaseAt(Timer& timer, int lastPhase)
{
static int rand_val = 6;
ticks_t time = timer.ticksElapsed();
for (int i = lastPhase; i < m_animationPhases; ++i) {
int phaseDuration = m_phaseDurations[i].second == 0 ?
m_phaseDurations[i].first : m_phaseDurations[i].first + rand_val % (m_phaseDurations[i].second);
rand_val = rand_val * 7 + 11;
if (time < phaseDuration) {
timer.restart();
timer.adjust(-time);
return i;
}
time -= phaseDuration;
}
return -1;
/*
ticks_t total = 0;
for (const auto &pair : m_phaseDurations) {
total += std::get<1>(pair);
if (time < total) {
return index;
}
++index;
}
return std::min<int>(index, m_animationPhases - 1);
*/
}
int Animator::getStartPhase()
{
if(m_startPhase > -1)
return m_startPhase;
return (int)stdext::random_range(0, (long)m_animationPhases);
}
void Animator::resetAnimation()
{
m_isComplete = false;
m_currentDirection = AnimDirForward;
m_currentLoop = 0;
setPhase(AnimPhaseAutomatic);
}
int Animator::getPingPongPhase()
{
int count = m_currentDirection == AnimDirForward ? 1 : -1;
int nextPhase = m_phase + count;
if(nextPhase < 0 || nextPhase >= m_animationPhases) {
m_currentDirection = m_currentDirection == AnimDirForward ? AnimDirBackward : AnimDirForward;
count *= -1;
}
return m_phase + count;
}
int Animator::getLoopPhase()
{
int nextPhase = m_phase + 1;
if(nextPhase < m_animationPhases)
return nextPhase;
if(m_loopCount == 0)
return 0;
if(m_currentLoop < (m_loopCount - 1)) {
m_currentLoop++;
return 0;
}
return m_phase;
}
int Animator::getPhaseDuration(int phase)
{
VALIDATE(phase < (int)m_phaseDurations.size());
auto& data = m_phaseDurations.at(phase);
if (data.second == 0) return data.first;
int min = data.first;
int max = min + data.second;
return (int)stdext::random_range((long)min, (long)max);
}
void Animator::calculateSynchronous()
{
int totalDuration = 0;
for(int i = 0; i < m_animationPhases; i++)
totalDuration += getPhaseDuration(i);
ticks_t ticks = g_clock.millis();
int elapsedTicks = (int)(ticks % totalDuration);
int totalTime = 0;
for(int i = 0; i < m_animationPhases; i++) {
int duration = getPhaseDuration(i);
if(elapsedTicks >= totalTime && elapsedTicks < totalTime + duration) {
m_phase = i;
m_currentDuration = duration - (elapsedTicks - totalTime);
break;
}
totalTime += duration;
}
m_lastPhaseTicks = ticks;
}
ticks_t Animator::getTotalDuration()
{
ticks_t time = 0;
for (const auto &pair: m_phaseDurations) {
time += pair.first + pair.second;
}
return time;
}

87
src/client/animator.h Normal file
View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2010-2017 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 ANIMATOR_H
#define ANIMATOR_H
#include "declarations.h"
#include <framework/core/declarations.h>
#include <framework/core/timer.h>
enum AnimationPhase : int16
{
AnimPhaseAutomatic = -1,
AnimPhaseRandom = 254,
AnimPhaseAsync = 255,
};
enum AnimationDirection : uint8
{
AnimDirForward = 0,
AnimDirBackward = 1
};
class Animator : public stdext::shared_object
{
public:
Animator();
void unserialize(int animationPhases, const FileStreamPtr& fin);
void serialize(const FileStreamPtr& fin);
void setPhase(int phase);
int getPhase();
int getPhaseAt(Timer& timer, int lastPhase = 0);
int getStartPhase();
int getAnimationPhases() { return m_animationPhases; }
bool isAsync() { return m_async; }
bool isComplete() { return m_isComplete; }
ticks_t getTotalDuration();
void resetAnimation();
private:
int getPingPongPhase();
int getLoopPhase();
int getPhaseDuration(int phase);
void calculateSynchronous();
int m_animationPhases;
int m_startPhase;
int m_loopCount;
bool m_async;
std::vector< std::pair<int, int> > m_phaseDurations;
int m_currentDuration;
AnimationDirection m_currentDirection;
int m_currentLoop;
ticks_t m_lastPhaseTicks;
bool m_isComplete;
int m_phase;
};
#endif

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

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2010-2017 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 "minimap.h"
#include <framework/core/configmanager.h>
Client g_client;
void Client::init(std::vector<std::string>& args)
{
// register needed lua functions
registerLuaFunctions();
g_map.init();
g_minimap.init();
g_game.init();
g_shaders.init();
g_things.init();
}
void Client::terminate()
{
g_creatures.terminate();
g_game.terminate();
g_map.terminate();
g_minimap.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-2017 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

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

@@ -0,0 +1,614 @@
/*
* Copyright (c) 2010-2017 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_CONST_H
#define CLIENT_CONST_H
namespace Otc
{
enum : int {
TILE_PIXELS = 32,
MAX_ELEVATION = 24,
SEA_FLOOR = 7,
MAX_Z = 15,
UNDERGROUND_FLOOR = SEA_FLOOR+1,
AWARE_UNDEGROUND_FLOOR_RANGE = 2,
INVISIBLE_TICKS_PER_FRAME = 500,
INVISIBLE_TICKS_PER_FRAME_FAST = 100,
ITEM_TICKS_PER_FRAME = 500,
ITEM_TICKS_PER_FRAME_FAST = 100,
ANIMATED_TEXT_DURATION = 1000,
STATIC_DURATION_PER_CHARACTER = 60,
MIN_STATIC_TEXT_DURATION = 3000,
MAX_STATIC_TEXT_WIDTH = 200,
MAX_AUTOWALK_STEPS_RETRY = 10,
MAX_AUTOWALK_DIST = 127
};
enum DepthConst {
MAX_DEPTH = 16384 - 2048
};
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,
DrawBars = 4096,
DrawNames = 8192,
DrawLights = 16384,
DrawManaBar = 32768,
DontDrawLocalPlayer = 65536,
DrawIcons = 131072,
DrawWalls = DrawOnBottom | DrawOnTop,
DrawEverything = DrawGround | DrawGroundBorders | DrawWalls | DrawItems |
DrawCreatures | DrawEffects | DrawMissiles | DrawCreaturesInformation |
DrawStaticTexts | DrawAnimatedTexts | DrawAnimations | DrawBars | DrawNames |
DrawLights | DrawManaBar | DrawIcons
};
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,
CriticalChance,
CriticalDamage,
LifeLeechChance,
LifeLeechAmount,
ManaLeechChance,
ManaLeechAmount,
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 PVPModes {
WhiteDove = 0,
WhiteHand = 1,
YellowHand = 2,
RedFist = 3
};
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
ShieldGray // 11 member of another party
};
enum PlayerEmblems {
EmblemNone = 0,
EmblemGreen,
EmblemRed,
EmblemBlue,
EmblemMember,
EmblemOther
};
enum CreatureIcons {
NpcIconNone = 0,
NpcIconChat,
NpcIconTrade,
NpcIconQuest,
NpcIconTradeQuest
};
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,
MessageMana = 41,
MessageBeyondLast = 42,
// deprecated
MessageMonsterYell = 43,
MessageMonsterSay = 44,
MessageRed = 45,
MessageBlue = 46,
MessageRVRChannel = 47,
MessageRVRAnswer = 48,
MessageRVRContinue = 49,
MessageGameHighlight = 50,
MessageNpcFromStartBlock = 51,
LastMessage = 52,
MessageInvalid = 255
};
enum GameFeature {
GameProtocolChecksum = 1,
GameAccountNames = 2,
GameChallengeOnLogin = 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,
GameTileAddThingWithStackpos = 19,
GameOfflineTrainingTime = 20,
GamePurseSlot = 21,
GameFormatCreatureName = 22,
GameSpellList = 23,
GameClientPing = 24,
GameExtendedClientPing = 25,
GameDoubleHealth = 28,
GameDoubleSkills = 29,
GameChangeMapAwareRange = 30,
GameMapMovePosition = 31,
GameAttackSeq = 32,
GameBlueNpcNameColor = 33,
GameDiagonalAnimatedText = 34,
GameLoginPending = 35,
GameNewSpeedLaw = 36,
GameForceFirstAutoWalkStep = 37,
GameMinimapRemove = 38,
GameDoubleShopSellAmount = 39,
GameContainerPagination = 40,
GameThingMarks = 41,
GameLooktypeU16 = 42,
GamePlayerStamina = 43,
GamePlayerAddons = 44,
GameMessageStatements = 45,
GameMessageLevel = 46,
GameNewFluids = 47,
GamePlayerStateU16 = 48,
GameNewOutfitProtocol = 49,
GamePVPMode = 50,
GameWritableDate = 51,
GameAdditionalVipInfo = 52,
GameBaseSkillU16 = 53,
GameCreatureIcons = 54,
GameHideNpcNames = 55,
GameSpritesAlphaChannel = 56,
GamePremiumExpiration = 57,
GameBrowseField = 58,
GameEnhancedAnimations = 59,
GameOGLInformation = 60,
GameMessageSizeCheck = 61,
GamePreviewState = 62,
GameLoginPacketEncryption = 63,
GameClientVersion = 64,
GameContentRevision = 65,
GameExperienceBonus = 66,
GameAuthenticator = 67,
GameUnjustifiedPoints = 68,
GameSessionKey = 69,
GameDeathType = 70,
GameIdleAnimations = 71,
GameKeepUnawareTiles = 72,
GameIngameStore = 73,
GameIngameStoreHighlights = 74,
GameIngameStoreServiceType = 75,
GameAdditionalSkills = 76,
GameDistanceEffectU16 = 77,
GamePrey = 78,
GameDoubleMagicLevel = 79,
GameExtendedOpcode = 80,
GameMinimapLimitedToSingleFloor = 81,
GameDoubleLevel = 83,
GameDoubleSoul = 84,
GameDoublePlayerGoodsMoney = 85,
GameCreatureWalkthrough = 86,
GameDoubleTradeMoney = 87,
// 90-99 otclientv8 features
GameNewWalking = 90,
GameSlowerManualWalking = 91,
GameItemTooltip = 93,
GameBot = 95,
GameBiggerMapCache = 96,
GameForceLight = 97,
GameNoDebug = 98,
GameBotProtection = 99,
// Custom features for customer
GameFasterAnimations = 101,
GameCenteredOutfits = 102,
GameSendIdentifiers = 103,
GameWingsAndAura = 104,
// advanced features
GamePacketSizeU32 = 110,
GamePacketCompression = 111,
LastGameFeature = 120
};
enum PathFindResult {
PathFindResultOk = 0,
PathFindResultSamePosition,
PathFindResultImpossible,
PathFindResultTooFar,
PathFindResultNoWay
};
enum PathFindFlags {
PathFindAllowNotSeenTiles = 1,
PathFindAllowCreatures = 2,
PathFindAllowNonPathable = 4,
PathFindAllowNonWalkable = 8,
PathFindIgnoreCreatures = 16
};
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
};
enum Blessings {
BlessingNone = 0,
BlessingAdventurer = 1,
BlessingSpiritualShielding = 1 << 1,
BlessingEmbraceOfTibia = 1 << 2,
BlessingFireOfSuns = 1 << 3,
BlessingWisdomOfSolitude = 1 << 4,
BlessingSparkOfPhoenix = 1 << 5
};
enum DeathType {
DeathRegular = 0,
DeathBlessed = 1
};
enum StoreProductTypes {
ProductTypeOther = 0,
ProductTypeNameChange = 1
};
enum StoreErrorTypes {
StoreNoError = -1,
StorePurchaseError = 0,
StoreNetworkError = 1,
StoreHistoryError = 2,
StoreTransferError = 3,
StoreInformation = 4
};
enum StoreStates {
StateNone = 0,
StateNew = 1,
StateSale = 2,
StateTimed = 3
};
enum PreySlotNum_t : uint8_t {
PREY_SLOTNUM_FIRST,
PREY_SLOTNUM_SECOND,
PREY_SLOTNUM_THIRD,
PREY_SLOTNUM_LAST = PREY_SLOTNUM_THIRD
};
enum PreyState_t : uint8_t {
PREY_STATE_LOCKED = 0,
PREY_STATE_INACTIVE = 1,
PREY_STATE_ACTIVE = 2,
PREY_STATE_SELECTION = 3,
PREY_STATE_SELECTION_CHANGE_MONSTER = 4, // unused; hmm
PREY_STATE_SELECTION_FROMALL = 5,
PREY_STATE_CHANGE_FROMALL = 6, // unused :(
};
enum PreyMessageDialog_t : uint8_t {
//PREY_MESSAGEDIALOG_IMBUEMENT_SUCCESS = 0,
//PREY_MESSAGEDIALOG_IMBUEMENT_ERROR = 1,
//PREY_MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED = 2,
//PREY_MESSAGEDIALOG_IMBUEMENT_STATION_NOT_FOUND = 3,
//PREY_MESSAGEDIALOG_IMBUEMENT_CHARM_SUCCESS = 10,
//PREY_MESSAGEDIALOG_IMBUEMENT_CHARM_ERROR = 11,
PREY_MESSAGEDIALOG_PREY_MESSAGE = 20,
PREY_MESSAGEDIALOG_PREY_ERROR = 21,
};
enum PreyResourceType_t : uint8_t {
PREY_RESOURCETYPE_BANK_GOLD = 0,
PREY_RESOURCETYPE_INVENTORY_GOLD = 1,
PREY_RESOURCETYPE_PREY_BONUS_REROLLS = 10
};
enum PreyBonusType_t : uint8_t {
PREY_BONUS_DAMAGE_BOOST = 0,
PREY_BONUS_DAMAGE_REDUCTION = 1,
PREY_BONUS_XP_BONUS = 2,
PREY_BONUS_IMPROVED_LOOT = 3,
PREY_BONUS_NONE = 4, // internal usage but still added to client;
PREY_BONUS_FIRST = PREY_BONUS_DAMAGE_BOOST,
PREY_BONUS_LAST = PREY_BONUS_IMPROVED_LOOT,
};
enum PreyAction_t : uint8_t {
PREY_ACTION_LISTREROLL = 0,
PREY_ACTION_BONUSREROLL = 1,
PREY_ACTION_MONSTERSELECTION = 2,
PREY_ACTION_REQUEST_ALL_MONSTERS = 3,
PREY_ACTION_CHANGE_FROM_ALL = 4,
PREY_ACTION_LOCK_PREY = 5,
};
enum PreyConfigState {
PREY_CONFIG_STATE_FREE,
PREY_CONFIG_STATE_PREMIUM,
PREY_CONFIG_STATE_TIBIACOINS
};
enum PreyUnlockState_t : uint8_t {
PREY_UNLOCK_STORE_AND_PREMIUM = 0,
PREY_UNLOCK_STORE = 1,
PREY_UNLOCK_NONE = 2,
};
}
#endif

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

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2010-2017 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, bool isUnlocked, bool hasPages, int containerSize, int firstIndex)
{
m_id = id;
m_capacity = capacity;
m_name = name;
m_containerItem = containerItem;
m_hasParent = hasParent;
m_closed = false;
m_unlocked = isUnlocked;
m_hasPages = hasPages;
m_size = containerSize;
m_firstIndex = firstIndex;
}
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, int slot)
{
slot -= m_firstIndex;
m_size++;
// indicates that there is a new item on next page
if(m_hasPages && slot > m_capacity) {
callLuaField("onSizeChange", m_size);
return;
}
if(slot == 0)
m_items.push_front(item);
else
m_items.push_back(item);
updateItemsPositions();
callLuaField("onSizeChange", m_size);
callLuaField("onAddItem", slot, item);
}
ItemPtr Container::findItemById(uint itemId, int subType)
{
for(const ItemPtr item : m_items)
if(item->getId() == itemId && (subType == -1 || item->getSubType() == subType))
return item;
return nullptr;
}
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)
{
slot -= m_firstIndex;
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, const ItemPtr& lastItem)
{
slot -= m_firstIndex;
if(m_hasPages && slot >= (int)m_items.size()) {
m_size--;
callLuaField("onSizeChange", m_size);
return;
}
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);
if(lastItem) {
onAddItem(lastItem, m_firstIndex + m_capacity - 1);
m_size--;
}
m_size--;
updateItemsPositions();
callLuaField("onSizeChange", m_size);
callLuaField("onRemoveItem", slot, item);
}
void Container::updateItemsPositions()
{
for(int slot = 0; slot < (int)m_items.size(); ++slot)
m_items[slot]->setPosition(getSlotPosition(slot));
}

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

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2010-2017 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, bool isUnlocked, bool hasPages, int containerSize, int firstIndex);
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; }
bool isUnlocked() { return m_unlocked; }
bool hasPages() { return m_hasPages; }
int getSize() { return m_size; }
int getFirstIndex() { return m_firstIndex; }
ItemPtr findItemById(uint itemId, int subType);
protected:
void onOpen(const ContainerPtr& previousContainer);
void onClose();
void onAddItem(const ItemPtr& item, int slot);
void onAddItems(const std::vector<ItemPtr>& items);
void onUpdateItem(int slot, const ItemPtr& item);
void onRemoveItem(int slot, const ItemPtr& lastItem);
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;
bool m_unlocked;
bool m_hasPages;
int m_size;
int m_firstIndex;
std::deque<ItemPtr> m_items;
};
#endif

1101
src/client/creature.cpp Normal file

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/ui/uiwidget.h>
// @bindclass
class Creature : public Thing
{
public:
enum {
SHIELD_BLINK_TICKS = 500,
VOLATILE_SQUARE_DURATION = 1000
};
Creature();
virtual ~Creature();
virtual void draw(const Point& dest, bool animate = true, LightView* lightView = nullptr);
virtual void drawOutfit(const Rect& destRect, Otc::Direction direction = Otc::InvalidDirection, const Color& color = Color::white);
void drawInformation(const Point& point, bool useGray, const Rect& parentRect, int drawFlags);
bool isInsideOffset(Point offset);
void setId(uint32 id) { m_id = id; }
void setName(const std::string& name);
void setManaPercent(int8 value) { m_manaPercent = value; }
void setHealthPercent(uint8 healthPercent);
void setDirection(Otc::Direction direction);
void setOutfit(const Outfit& outfit);
void setOutfitColor(const Color& color, int duration);
void setLight(const Light& light) { m_light = light; }
void setSpeed(uint16 speed);
void setBaseSpeed(double baseSpeed);
void setSkull(uint8 skull);
void setShield(uint8 shield);
void setEmblem(uint8 emblem);
void setType(uint8 type);
void setIcon(uint8 icon);
void setSkullTexture(const std::string& filename);
void setShieldTexture(const std::string& filename, bool blink);
void setEmblemTexture(const std::string& filename);
void setTypeTexture(const std::string& filename);
void setIconTexture(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; }
void setInformationColor(const Color& color) { m_useCustomInformationColor = true; m_informationColor = color; }
void resetInformationColor() { m_useCustomInformationColor = false; }
Point getInformationOffset() { return m_informationOffset; }
void setInformationOffset(int x, int y) { m_informationOffset = Point(x, y); }
void setText(const std::string& text, const Color& color);
std::string getText();
void clearText() { setText("", Color::white); }
uint32 getId() { return m_id; }
std::string getName() { return m_name; }
uint8 getHealthPercent() { return m_healthPercent; }
int8 getManaPercent() { return m_manaPercent; }
Otc::Direction getDirection() { return m_direction; }
Otc::Direction getWalkDirection() { return m_walkDirection; }
Outfit getOutfit() { return m_outfit; }
int getOutfitNumber() { return m_outfitNumber; }
Light getLight() { return m_light; }
uint16 getSpeed() { return m_speed; }
double getBaseSpeed() { return m_baseSpeed; }
uint8 getSkull() { return m_skull; }
uint8 getShield() { return m_shield; }
uint8 getEmblem() { return m_emblem; }
uint8 getType() { return m_type; }
uint8 getIcon() { return m_icon; }
bool isPassable() { return m_passable; }
Point getDrawOffset();
int getStepDuration(bool ignoreDiagonal = false, Otc::Direction dir = Otc::InvalidDirection);
Point getWalkOffset(bool inNextFrame = false) { return inNextFrame ? m_walkOffsetInNextFrame : m_walkOffset; }
Position getLastStepFromPosition() { return m_lastStepFromPosition; }
Position getLastStepToPosition() { return m_lastStepToPosition; }
float getStepProgress() { return m_walkTimer.ticksElapsed() / getStepDuration(); }
int 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);
PointF getJumpOffset() { return m_jumpOffset; }
void updateShield();
// walk related
int getWalkAnimationPhases();
virtual void turn(Otc::Direction direction);
void jump(int height, int duration);
virtual void walk(const Position& oldPos, const Position& newPos);
virtual void stopWalk();
void allowAppearWalk(uint16_t stepSpeed) { m_allowAppearWalk = true; m_stepDuration = stepSpeed; }
bool isWalking() { return m_walking; }
bool isRemoved() { return m_removed; }
bool isInvisible() { return m_outfit.getCategory() == ThingCategoryEffect && m_outfit.getAuxId() == 13; }
bool isDead() { return m_healthPercent <= 0; }
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();
virtual void onDeath();
virtual bool isPreWalking() { return false; }
virtual Position getPrewalkingPosition(bool beforePrewalk = false) { return m_position; }
TilePtr getWalkingTileOrTile() {
return m_walkingTile ? m_walkingTile : getTile();
}
virtual bool isServerWalking() { return true; }
void setElevation(uint8 elevation) {
m_elevation = elevation;
}
uint8 getElevation() {
return m_elevation;
}
// widgets
void addTopWidget(const UIWidgetPtr& widget);
void addBottomWidget(const UIWidgetPtr& widget);
void addDirectionalWidget(const UIWidgetPtr& widget);
void removeTopWidget(const UIWidgetPtr& widget);
void removeBottomWidget(const UIWidgetPtr& widget);
void removeDirectionalWidget(const UIWidgetPtr& widget);
std::list<UIWidgetPtr> getTopWidgets();
std::list<UIWidgetPtr> getBottomWidgets();
std::list<UIWidgetPtr> getDirectionalWdigets();
void clearWidgets();
void clearTopWidgets();
void clearBottomWidgets();
void clearDirectionalWidgets();
void drawTopWidgets(const Point& rect, const Otc::Direction direction);
void drawBottomWidgets(const Point& rect, const Otc::Direction direction);
protected:
virtual void updateWalkAnimation(int totalPixelsWalked);
virtual void updateWalkOffset(int totalPixelsWalked, bool inNextFrame = false);
void updateWalkingTile();
virtual void nextWalkUpdate();
virtual void updateWalk();
virtual void terminateWalk();
void updateOutfitColor(Color color, Color finalColor, Color delta, int duration);
void updateJump();
uint32 m_id;
std::string m_name;
uint8 m_healthPercent;
int8 m_manaPercent;
Otc::Direction m_direction;
Otc::Direction m_walkDirection;
Outfit m_outfit;
int m_outfitNumber = 0;
Light m_light;
int m_speed;
double m_baseSpeed;
uint8 m_skull;
uint8 m_shield;
uint8 m_emblem;
uint8 m_type;
uint8 m_icon;
TexturePtr m_skullTexture;
TexturePtr m_shieldTexture;
TexturePtr m_emblemTexture;
TexturePtr m_typeTexture;
TexturePtr m_iconTexture;
stdext::boolean<true> m_showShieldTexture;
stdext::boolean<false> m_shieldBlink;
stdext::boolean<false> m_passable;
Color m_timedSquareColor;
Color m_staticSquareColor;
Color m_nameColor;
stdext::boolean<false> m_showTimedSquare;
stdext::boolean<false> m_showStaticSquare;
stdext::boolean<true> m_removed;
CachedText m_nameCache;
Color m_informationColor;
bool m_useCustomInformationColor = false;
Point m_informationOffset;
Color m_outfitColor;
ScheduledEventPtr m_outfitColorUpdateEvent;
Timer m_outfitColorTimer;
static std::array<double, Otc::LastSpeedFormula> m_speedFormula;
// walk related
int m_walkAnimationPhase;
int m_walkedPixels;
uint m_footStep;
Timer m_walkTimer;
ticks_t m_footLastStep;
TilePtr m_walkingTile;
stdext::boolean<false> m_walking;
stdext::boolean<false> m_allowAppearWalk;
ScheduledEventPtr m_walkUpdateEvent;
ScheduledEventPtr m_walkFinishAnimEvent;
EventPtr m_disappearEvent;
Point m_walkOffset;
Point m_walkOffsetInNextFrame;
Otc::Direction m_lastStepDirection;
Position m_lastStepFromPosition;
Position m_lastStepToPosition;
Position m_oldPosition;
uint8 m_elevation = 0;
uint16 m_stepDuration = 0;
// jump related
float m_jumpHeight = 0;
float m_jumpDuration = 0;
PointF m_jumpOffset;
Timer m_jumpTimer;
// for bot
StaticTextPtr m_text;
// widgets
std::list<UIWidgetPtr> m_bottomWidgets;
std::list<UIWidgetPtr> m_directionalWidgets;
std::list<UIWidgetPtr> m_topWidgets;
};
// @bindclass
class Npc : public Creature
{
public:
bool isNpc() { return true; }
};
// @bindclass
class Monster : public Creature
{
public:
bool isMonster() { return true; }
};
#endif

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

@@ -0,0 +1,426 @@
/*
* Copyright (c) 2010-2017 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>
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;
centerPos.x = node->readType<int>("centerx");
centerPos.y = node->readType<int>("centery");
centerPos.z = node->readType<int>("centerz");
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);
stdext::ucwords(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);
Position placePos;
placePos.x = centerPos.x + cNode->readType<int>("x");
placePos.y = centerPos.y + cNode->readType<int>("y");
placePos.z = cNode->readType<int>("z");
cType->setRace(cNode->ValueStr() == "npc" ? CreatureRaceNpc : CreatureRaceMonster);
addCreature(placePos, cType);
}
}
void Spawn::save(TiXmlElement* node)
{
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) {
const CreatureTypePtr& creature = pair.second;
if(!(creatureNode = new TiXmlElement(creature->getRace() == CreatureRaceNpc ? "npc" : "monster")))
stdext::throw_exception("Spawn::save: Ran out of memory while allocating XML element! Terminating now.");
creatureNode->SetAttribute("name", creature->getName());
creatureNode->SetAttribute("spawntime", creature->getSpawnTime());
creatureNode->SetAttribute("direction", creature->getDirection());
const Position& placePos = pair.first;
VALIDATE(placePos.isValid());
creatureNode->SetAttribute("x", placePos.x - c.x);
creatureNode->SetAttribute("y", placePos.y - c.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)) {
g_logger.warning(stdext::format("cannot place creature at %s (spawn's center position: %s, spawn radius: %d) (increment radius)",
stdext::to_string(placePos), stdext::to_string(centerPos),
m_radius
));
return;
}
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()) {
VALIDATE(iterator->first.isValid());
VALIDATE(g_map.removeThingByPos(iterator->first, 4));
m_creatures.erase(iterator);
}
}
std::vector<CreatureTypePtr> Spawn::getCreatures()
{
std::vector<CreatureTypePtr> creatures;
for (auto p : m_creatures)
creatures.push_back(p.second);
return creatures;
}
CreaturePtr CreatureType::cast()
{
CreaturePtr ret(new Creature);
std::string cName = getName();
stdext::tolower(cName);
stdext::trim(cName);
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.readFileContents(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.readFileContents(file));
}
void CreatureManager::loadNpcs(const std::string& folder)
{
std::string tmp = folder;
if(!stdext::ends_with(tmp, "/"))
tmp += "/";
if(!g_resources.directoryExists(tmp))
stdext::throw_exception(stdext::format("NPCs folder '%s' was not found.", folder));
const auto& fileList = g_resources.listDirectoryFiles(tmp);
for(const std::string& file : fileList)
loadCreatureBuffer(g_resources.readFileContents(tmp + file));
}
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;
}
try {
TiXmlDocument doc;
doc.Parse(g_resources.readFileContents(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;
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to load '%s': %s", fileName, e.what()));
}
}
void CreatureManager::saveSpawns(const std::string& fileName)
{
try {
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 = new TiXmlElement("spawn");
pair.second->save(elem);
root->LinkEndChild(elem);
}
if(!doc.SaveFile("data"+fileName))
stdext::throw_exception(stdext::format("failed to save spawns XML %s: %s", fileName, doc.ErrorDesc()));
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
}
}
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);
stdext::ucwords(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);
stdext::ucwords(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::getSpawnForPlacePos(const Position& pos)
{
for (const auto& pair : m_spawns) {
const Position& centerPos = pair.first;
const SpawnPtr& spawn = pair.second;
if (isInZone(pos, centerPos, spawn->getRadius()))
return spawn;
}
return nullptr;
}
SpawnPtr CreatureManager::addSpawn(const Position& centerPos, int radius)
{
auto iter = m_spawns.find(centerPos);
if(iter != m_spawns.end()) {
if(iter->second->getRadius() != radius)
iter->second->setRadius(radius);
return iter->second;
}
SpawnPtr ret(new Spawn);
ret->setRadius(radius);
ret->setCenterPos(centerPos);
m_spawns.insert(std::make_pair(centerPos, ret));
return ret;
}
void CreatureManager::deleteSpawn(const SpawnPtr& spawn)
{
const Position& centerPos = spawn->getCenterPos();
auto it = m_spawns.find(centerPos);
if(it != m_spawns.end())
m_spawns.erase(it);
}
std::vector<SpawnPtr> CreatureManager::getSpawns()
{
std::vector<SpawnPtr> spawns;
for (auto p : m_spawns)
spawns.push_back(p.second);
return spawns;
}
/* vim: set ts=4 sw=4 et: */

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

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2010-2017 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,
CreatureAttrRace = 5
};
enum CreatureRace : uint8
{
CreatureRaceNpc = 0,
CreatureRaceMonster = 1
};
enum SpawnAttr : uint8
{
SpawnAttrRadius = 0,
SpawnAttrCenter = 1,
};
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>(SpawnAttrCenter); }
std::vector<CreatureTypePtr> getCreatures();
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); }
void setRace(CreatureRace race) { m_attribs.set(CreatureAttrRace, race); }
CreatureRace getRace() { return m_attribs.get<CreatureRace>(CreatureAttrRace); }
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);
std::vector<SpawnPtr> getSpawns();
SpawnPtr getSpawn(const Position& centerPos);
SpawnPtr getSpawnForPlacePos(const Position& pos);
SpawnPtr addSpawn(const Position& centerPos, int radius);
void deleteSpawn(const SpawnPtr& spawn);
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

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

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2010-2017 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_DECLARATIONS_H
#define CLIENT_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 Animator;
class ThingType;
class ItemType;
class House;
class Town;
class CreatureType;
class Spawn;
class TileBlock;
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<Animator> AnimatorPtr;
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::list<HousePtr> HouseList;
typedef std::list<TownPtr> TownList;
typedef std::list<ItemPtr> ItemList;
typedef std::list<TilePtr> TileList;
typedef std::vector<ItemPtr> ItemVector;
typedef std::unordered_map<Position, TilePtr, PositionHasher> TileMap;
typedef std::unordered_map<Position, CreatureTypePtr, PositionHasher> CreatureMap;
typedef std::unordered_map<Position, SpawnPtr, PositionHasher> SpawnMap;
// 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 UIMinimap;
class UIProgressRect;
class UIMapAnchorLayout;
class UIPositionAnchor;
class UISprite;
typedef stdext::shared_object_ptr<UIItem> UIItemPtr;
typedef stdext::shared_object_ptr<UICreature> UICreaturePtr;
typedef stdext::shared_object_ptr<UISprite> UISpritePtr;
typedef stdext::shared_object_ptr<UIMap> UIMapPtr;
typedef stdext::shared_object_ptr<UIMinimap> UIMinimapPtr;
typedef stdext::shared_object_ptr<UIProgressRect> UIProgressRectPtr;
typedef stdext::shared_object_ptr<UIMapAnchorLayout> UIMapAnchorLayoutPtr;
typedef stdext::shared_object_ptr<UIPositionAnchor> UIPositionAnchorPtr;
#endif

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

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2010-2017 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 "game.h"
#include <framework/core/eventdispatcher.h>
#include <framework/util/extras.h>
void Effect::draw(const Point& dest, int offsetX, int offsetY, bool animate, LightView* lightView)
{
if(m_id == 0)
return;
if(animate) {
if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
// This requires a separate getPhaseAt method as using getPhase would make all magic effects use the same phase regardless of their appearance time
m_animationPhase = rawGetThingType()->getAnimator()->getPhaseAt(m_animationTimer, m_animationPhase);
} else {
// hack to fix some animation phases duration, currently there is no better solution
int ticks = EFFECT_TICKS_PER_FRAME;
if (m_id == 33) {
ticks <<= 2;
}
m_animationPhase = std::min<int>((int)(m_animationTimer.ticksElapsed() / ticks), getAnimationPhases() - 1);
}
}
int xPattern = offsetX % getNumPatternX();
if(xPattern < 0)
xPattern += getNumPatternX();
int yPattern = offsetY % getNumPatternY();
if(yPattern < 0)
yPattern += getNumPatternY();
rawGetThingType()->draw(dest, 0, xPattern, yPattern, 0, m_animationPhase, Color::white, lightView);
}
void Effect::onAppear()
{
m_animationTimer.restart();
int duration = 0;
if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
duration = getThingType()->getAnimator() ? getThingType()->getAnimator()->getTotalDuration() : 1000;
} else {
duration = EFFECT_TICKS_PER_FRAME;
// hack to fix some animation phases duration, currently there is no better solution
if(m_id == 33) {
duration <<= 2;
}
duration *= getAnimationPhases();
}
// schedule removal
auto self = asEffect();
g_dispatcher.scheduleEvent([self]() { g_map.removeThing(self); }, duration);
}
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);
}

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

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2010-2017 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, bool animate = true, LightView* lightView = nullptr) override {}
void draw(const Point& dest, int offsetX = 0, int offsetY = 0, bool animate = true, LightView* lightView = nullptr);
void setId(uint32 id) override;
uint32 getId() { return m_id; }
EffectPtr asEffect() { return static_self_cast<Effect>(); }
bool isEffect() { return true; }
const ThingTypePtr& getThingType() override;
ThingType *rawGetThingType() override;
protected:
void onAppear();
private:
uint16 m_id;
Timer m_animationTimer;
int m_animationPhase = 0;
};
#endif

1641
src/client/game.cpp Normal file

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,476 @@
/*
* Copyright (c) 2010-2017 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>
struct UnjustifiedPoints {
bool operator==(const UnjustifiedPoints& other) {
return killsDay == other.killsDay &&
killsDayRemaining == other.killsDayRemaining &&
killsWeek == other.killsWeek &&
killsWeekRemaining == other.killsWeekRemaining &&
killsMonth == other.killsMonth &&
killsMonthRemaining == other.killsMonthRemaining &&
skullTime == other.skullTime;
}
uint8 killsDay;
uint8 killsDayRemaining;
uint8 killsWeek;
uint8 killsWeekRemaining;
uint8 killsMonth;
uint8 killsMonthRemaining;
uint8 skullTime;
};
typedef std::tuple<std::string, uint, std::string, int, bool> 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();
void processNewPing(uint32_t pingId);
void processUpdateNeeded(const std::string& signature);
void processLoginError(const std::string& error);
void processLoginAdvice(const std::string& message);
void processLoginWait(const std::string& message, int time);
void processLoginToken(bool unknown);
void processLogin();
void processPendingGame();
void processEnterGame();
void processGameStart();
void processGameEnd();
void processDeath(int deathType, 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);
void processNewWalkCancel(Otc::Direction dir);
void processPredictiveWalkCancel(const Position& pos, Otc::Direction dir);
void processWalkId(uint32_t walkId);
void processPlayerHelpers(int helpers);
void processPlayerModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeMode, Otc::PVPModes pvpMode);
// 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, bool isUnlocked, bool hasPages, int containerSize, int firstIndex);
void processCloseContainer(int containerId);
void processContainerAddItem(int containerId, const ItemPtr& item, int slot);
void processContainerUpdateItem(int containerId, int slot, const ItemPtr& item);
void processContainerRemoveItem(int containerId, int slot, const ItemPtr& lastItem);
// 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, const std::string& description, int iconId, bool notifyLogin);
void processVipStateChange(uint id, uint status);
// tutorial hint
void processTutorialHint(int id);
void processAddAutomapFlag(const Position& pos, int icon, const std::string& message);
void processRemoveAutomapFlag(const Position& pos, int icon, const std::string& message);
// outfit
void processOpenOutfitWindow(const Outfit& currentOutfit, 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, int64_t, int64_t> >& items);
void processPlayerGoods(uint64_t 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& writer, 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, std::vector<std::tuple<int, std::string> > buttonList, int enterButton, int escapeButton, std::vector<std::tuple<int, std::string> > choiceList, bool priority);
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, const std::string& authenticatorToken, const std::string& sessionKey);
void cancelLogin();
void forceLogout();
void safeLogout();
// walk related
void walk(Otc::Direction direction, bool withPreWalk);
void autoWalk(const std::vector<Otc::Direction>& dirs, Position startPos);
void turn(Otc::Direction direction);
void stop();
// item related
void look(const ThingPtr& thing, bool isBattleList = false);
void move(const ThingPtr& thing, const Position& toPos, int count);
void moveRaw(const Position& pos, int id, int stackpos, const Position& toPos, int count);
void moveToParentContainer(const ThingPtr& thing, int count);
void rotate(const ThingPtr& thing);
void wrap(const ThingPtr& thing);
void use(const ThingPtr& thing);
void useWith(const ItemPtr& fromThing, const ThingPtr& toThing, int subType = 0);
void useInventoryItem(int itemId, int subType = 0);
void useInventoryItemWith(int itemId, const ThingPtr& toThing, int subType = 0);
ItemPtr findItemInContainers(uint itemId, int subType);
// container related
int 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, bool cancel = false);
void cancelAttack() { attack(nullptr, true); }
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);
void editVip(int playerId, const std::string& description, int iconId, bool notifyLogin);
// fight modes related
void setChaseMode(Otc::ChaseModes chaseMode);
void setFightMode(Otc::FightModes fightMode);
void setSafeFight(bool on);
void setPVPMode(Otc::PVPModes pvpMode);
Otc::ChaseModes getChaseMode() { return m_chaseMode; }
Otc::FightModes getFightMode() { return m_fightMode; }
bool isSafeFight() { return m_safeFight; }
Otc::PVPModes getPVPMode() { return m_pvpMode; }
// pvp related
void setUnjustifiedPoints(UnjustifiedPoints unjustifiedPoints);
UnjustifiedPoints getUnjustifiedPoints() { return m_unjustifiedPoints; };
void setOpenPvpSituations(int openPvpSitations);
int getOpenPvpSituations() { return m_openPvpSituations; }
// 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);
// rule violations (only gms)
void openRuleViolation(const std::string& reporter);
void closeRuleViolation(const std::string& reporter);
void cancelRuleViolation();
// 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(uint32 dialog, int button, int choice);
// >= 984 browse field
void browseField(const Position& position);
void seekInContainer(int cid, int index);
// >= 1080 ingame store
void buyStoreOffer(int offerId, int productType, const std::string& name = "");
void requestTransactionHistory(int page, int entriesPerPage);
void requestStoreOffers(const std::string& categoryName, int serviceType = 0);
void openStore(int serviceType = 0);
void transferCoins(const std::string& recipient, int amount);
void openTransactionHistory(int entriesPerPage);
// >= 1100
void preyAction(int slot, int actionType, int index);
void preyRequest();
void applyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm);
void clearImbuement(uint8_t slot);
void closeImbuingWindow();
//void reportRuleViolation2();
void ping();
void newPing();
void setPingDelay(int delay) { m_pingDelay = delay; }
// otclient only
void changeMapAwareRange(int xrange, int yrange);
// dynamic support for game features
void resetFeatures() { m_features.reset(); }
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 setCustomProtocolVersion(int version) { m_customProtocolVersion = version; }
int getCustomProtocolVersion() { return m_customProtocolVersion != 0 ? m_customProtocolVersion : m_protocolVersion; }
void setClientVersion(int version);
int getClientVersion() { return m_clientVersion; }
void setCustomOs(int os) { m_clientCustomOs = os; }
int getOs();
bool canPerformGameAction();
bool checkBotProtection();
bool isOnline() { return m_online; }
bool isLogging() { return !m_online && m_protocolGame; }
bool isDead() { return m_dead; }
bool isAttacking() { return !!m_attackingCreature && !m_attackingCreature->isRemoved(); }
bool isFollowing() { return !!m_followingCreature && !m_followingCreature->isRemoved(); }
bool isConnectionOk() { return m_protocolGame && m_protocolGame->getElapsedTicksSinceLastRead() < 5000; }
int getPing() { return m_ping; }
ContainerPtr getContainer(int index) { if (m_containers.find(index) == m_containers.end()) { return nullptr; } 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; }
void setExpertPvpMode(bool enable) { m_expertPvpMode = enable; }
bool getExpertPvpMode() { return m_expertPvpMode; }
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; }
bool isGM() { return m_gmActions.size() > 0; }
Otc::Direction getLastWalkDir() { return m_lastWalkDir; }
std::string formatCreatureName(const std::string &name);
int findEmptyContainerId();
void setTibiaCoins(int coins, int transferableCoins)
{
m_coins = coins;
m_transferableCoins = transferableCoins;
}
int getTibiaCoins()
{
return m_coins;
}
int getTransferableTibiaCoins()
{
return m_transferableCoins;
}
void setMaxPreWalkingSteps(uint value) { m_maxPreWalkingSteps = value; }
uint getMaxPreWalkingSteps() { return m_maxPreWalkingSteps; }
void showRealDirection(bool value) { m_showRealDirection = value; }
bool shouldShowingRealDirection() { return m_showRealDirection; }
uint getWalkId() { return m_walkId; }
uint getWalkPreditionId() { return m_walkPrediction; }
void ignoreServerDirection(bool value) { m_ignoreServerDirection = value; }
bool isIgnoringServerDirection()
{
return m_ignoreServerDirection;
}
void enableTileThingLuaCallback(bool value) { m_tileThingsLuaCallback = value; }
bool isTileThingLuaCallbackEnabled() { return m_tileThingsLuaCallback; }
int getRecivedPacketsCount()
{
return m_protocolGame ? m_protocolGame->getRecivedPacketsCount() : 0;
}
int getRecivedPacketsSize()
{
return m_protocolGame ? m_protocolGame->getRecivedPacketsSize() : 0;
}
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;
bool m_expertPvpMode;
int m_serverBeat;
ticks_t m_ping;
uint m_pingSent;
uint m_pingReceived;
uint m_walkId = 0;
uint m_walkPrediction = 0;
uint m_maxPreWalkingSteps = 2;
stdext::timer m_pingTimer;
std::map<uint32_t, stdext::timer> m_newPingIds;
uint m_seq;
int m_pingDelay;
int m_newPingDelay;
Otc::FightModes m_fightMode;
Otc::ChaseModes m_chaseMode;
Otc::PVPModes m_pvpMode;
Otc::Direction m_lastWalkDir;
bool m_waitingForAnotherDir = false;
UnjustifiedPoints m_unjustifiedPoints;
int m_openPvpSituations;
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_newPingEvent;
ScheduledEventPtr m_checkConnectionEvent;
bool m_connectionFailWarned;
int m_protocolVersion;
int m_customProtocolVersion = 0;
int m_clientVersion;
std::string m_clientSignature;
int m_clientCustomOs;
int m_coins;
int m_transferableCoins;
bool m_showRealDirection = false;
bool m_ignoreServerDirection = true;
bool m_tileThingsLuaCallback = false;
};
extern Game g_game;
#endif

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

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2010-2017 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_GLOBAL_H
#define CLIENT_GLOBAL_H
#include <framework/global.h>
// widely used headers
#include "const.h"
#include "position.h"
#endif

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

@@ -0,0 +1,210 @@
/*
* Copyright (c) 2010-2017 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()
{
}
House::House(uint32 hId, const std::string &name, const Position &pos)
{
setId(hId);
setName(name);
if(pos.isValid())
setEntry(pos);
}
void House::setTile(const TilePtr& tile)
{
tile->setFlag(TILESTATE_HOUSE);
tile->setHouseId(getId());
m_tiles.insert(std::make_pair(tile->getPosition(), tile));
}
TilePtr House::getTile(const Position& position)
{
TileMap::const_iterator iter = m_tiles.find(position);
if(iter != m_tiles.end())
return iter->second;
return nullptr;
}
void House::addDoor(const ItemPtr& door)
{
if (!door) return;
door->setDoorId(m_lastDoorId);
m_doors[m_lastDoorId++] = door;
}
void House::removeDoorById(uint32 doorId)
{
if(doorId >= m_lastDoorId)
stdext::throw_exception(stdext::format("Failed to remove door of id %d (would overflow), max id: %d",
doorId, m_lastDoorId));
m_doors[doorId] = nullptr;
}
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");
Position entryPos;
entryPos.x = elem->readType<int>("entryx");
entryPos.y = elem->readType<int>("entryy");
entryPos.z = elem->readType<int>("entryz");
setEntry(entryPos);
}
void House::save(TiXmlElement* elem)
{
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()
{
}
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);
}
HousePtr HouseManager::getHouse(uint32 houseId)
{
auto it = findHouse(houseId);
return it != m_houses.end() ? *it : nullptr;
}
HousePtr HouseManager::getHouseByName(std::string name)
{
auto it = std::find_if(m_houses.begin(), m_houses.end(),
[=] (const HousePtr& house) -> bool { return house->getName() == name; });
return it != m_houses.end() ? *it : nullptr;
}
void HouseManager::load(const std::string& fileName)
{
try {
TiXmlDocument doc;
doc.Parse(g_resources.readFileContents(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);
}
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to load '%s': %s", fileName, e.what()));
}
sort();
}
void HouseManager::save(const std::string& fileName)
{
try {
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 = new TiXmlElement("house");
house->save(elem);
root->LinkEndChild(elem);
}
if(!doc.SaveFile("data"+fileName))
stdext::throw_exception(stdext::format("failed to save houses XML %s: %s", fileName, doc.ErrorDesc()));
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
}
}
HouseList HouseManager::filterHouses(uint32 townId)
{
HouseList ret;
for(const HousePtr& house : m_houses)
if(house->getTownId() == townId)
ret.push_back(house);
return ret;
}
HouseList::iterator HouseManager::findHouse(uint32 houseId)
{
return std::find_if(m_houses.begin(), m_houses.end(),
[=] (const HousePtr& house) -> bool { return house->getId() == houseId; });
}
void HouseManager::sort()
{
m_houses.sort([] (const HousePtr& lhs, const HousePtr& rhs) { return lhs->getName() < rhs->getName(); });
}
/* vim: set ts=4 sw=4 et: */

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

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2010-2017 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(); }
void setTile(const TilePtr& tile);
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); }
void addDoor(const ItemPtr& door);
void removeDoor(const ItemPtr& door) { removeDoorById(door->getDoorId()); }
void removeDoorById(uint32 doorId);
protected:
void load(const TiXmlElement* elem);
void save(TiXmlElement* elem);
private:
stdext::packed_storage<uint8> m_attribs;
TileMap m_tiles;
ItemVector m_doors;
uint32 m_lastDoorId;
stdext::boolean<false> m_isGuildHall;
friend class HouseManager;
};
class HouseManager {
public:
HouseManager();
void addHouse(const HousePtr& house);
void removeHouse(uint32 houseId);
HousePtr getHouse(uint32 houseId);
HousePtr getHouseByName(std::string name);
void load(const std::string& fileName);
void save(const std::string& fileName);
void sort();
void clear() { m_houses.clear(); }
HouseList getHouseList() { return m_houses; }
HouseList filterHouses(uint32 townId);
private:
HouseList m_houses;
protected:
HouseList::iterator findHouse(uint32 houseId);
};
extern HouseManager g_houses;
#endif

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

@@ -0,0 +1,440 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/util/stats.h>
Item::Item() :
m_clientId(0),
m_serverId(0),
m_countOrSubType(1),
m_color(Color::alpha),
m_async(true),
m_phase(0),
m_lastPhase(0)
{
}
ItemPtr Item::create(int id, int countOrSubtype)
{
ItemPtr item(new Item);
item->setId(id);
item->setCountOrSubType(countOrSubtype);
return item;
}
ItemPtr Item::createFromOtb(int id)
{
ItemPtr item(new Item);
item->setOtbId(id);
return item;
}
std::string Item::getName()
{
return g_things.findItemTypeByClientId(m_clientId)->getName();
}
void Item::draw(const Point& dest, 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);
Color color(Color::white);
if (m_color != Color::alpha)
color = m_color;
size_t drawQueueSize = g_drawQueue->size();
rawGetThingType()->draw(dest, 0, xPattern, yPattern, zPattern, animationPhase, color, lightView);
if (m_marked) {
g_drawQueue->setMark(drawQueueSize, updatedMarkedColor());
}
}
void Item::draw(const Rect& dest, bool animate)
{
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);
Color color(Color::white);
if (m_color != Color::alpha)
color = m_color;
rawGetThingType()->draw(dest, 0, xPattern, yPattern, zPattern, animationPhase, color);
}
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.x, dest.y, dest.z);
}
if(isDepot()) {
out->addU8(ATTR_DEPOT_ID);
out->addU16(getDepotId());
}
if(isHouseDoor()) {
out->addU8(ATTR_HOUSEDOORID);
out->addU8(getDoorId());
}
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);
}
std::string text = getText();
if(g_things.getItemType(m_serverId)->isWritable() && !text.empty()) {
out->addU8(ATTR_TEXT);
out->addString(text);
}
std::string desc = getDescription();
if(!desc.empty()) {
out->addU8(ATTR_DESC);
out->addString(desc);
}
out->endNode();
for(auto i : m_containerItems)
i->serializeItem(out);
}
int Item::getSubType()
{
if(isSplash() || isFluidContainer())
return m_countOrSubType;
if(g_game.getClientVersion() >= 860)
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)
{
// Avoid crashes with invalid items
if(!isValid())
return;
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;
if(g_game.getFeature(Otc::GameNewFluids)) {
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;
}
} else
color = m_countOrSubType;
xPattern = (color % 4) % getNumPatternX();
yPattern = (color / 4) % getNumPatternY();
} else {
xPattern = m_position.x % std::max<int>(1, getNumPatternX());
yPattern = m_position.y % std::max<int>(1, getNumPatternY());
zPattern = m_position.z % std::max<int>(1, getNumPatternZ());
}
}
int Item::calculateAnimationPhase(bool animate)
{
if(getAnimationPhases() > 1) {
if(animate) {
if(getAnimator() != nullptr)
return getAnimator()->getPhase();
if(m_async)
return (g_clock.millis() % ((g_game.getFeature(Otc::GameEnhancedAnimations) ? Otc::ITEM_TICKS_PER_FRAME_FAST : Otc::ITEM_TICKS_PER_FRAME) * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
else {
if(g_clock.millis() - m_lastPhase >= (g_game.getFeature(Otc::GameEnhancedAnimations) ? Otc::ITEM_TICKS_PER_FRAME_FAST : Otc::ITEM_TICKS_PER_FRAME)) {
m_phase = (m_phase + 1) % getAnimationPhases();
m_lastPhase = g_clock.millis();
}
return m_phase;
}
} 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(layer, 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);
}
/* vim: set ts=4 sw=4 et :*/

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

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2010-2017 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, int countOrSubtype = 1);
static ItemPtr createFromOtb(int id);
void draw(const Point& dest, bool animate = true, LightView* lightView = nullptr);
void draw(const Rect& dest, bool animate = true);
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; }
void setColor(const Color& c) { m_color = c; }
void setTooltip(const std::string& str) { m_tooltip = str; }
int getCountOrSubType() { return m_countOrSubType; }
int getSubType();
int getCount();
uint32 getId() { return m_clientId; }
uint16 getClientId() { return m_clientId; }
uint16 getServerId() { return m_serverId; }
std::string getName();
bool isValid();
std::string getTooltip() { return m_tooltip; }
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); }
uint16 getUniqueId() { return m_attribs.get<uint16>(ATTR_ACTION_ID); }
uint16 getActionId() { return m_attribs.get<uint16>(ATTR_UNIQUE_ID); }
void setActionId(uint16 actionId) { m_attribs.set(ATTR_ACTION_ID, actionId); }
void setUniqueId(uint16 uniqueId) { m_attribs.set(ATTR_UNIQUE_ID, uniqueId); }
std::string getText() { return m_attribs.get<std::string>(ATTR_TEXT); }
std::string getDescription() { return m_attribs.get<std::string>(ATTR_DESC); }
void setDescription(std::string desc) { m_attribs.set(ATTR_DESC, desc); }
void setText(std::string txt) { m_attribs.set(ATTR_TEXT, txt); }
Position getTeleportDestination() { return m_attribs.get<Position>(ATTR_TELE_DEST); }
void setTeleportDestination(const Position& pos) { m_attribs.set(ATTR_TELE_DEST, pos); }
void setAsync(bool enable) { m_async = enable; }
bool isHouseDoor() { return m_attribs.has(ATTR_HOUSEDOORID); }
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 clone();
ItemPtr asItem() { return static_self_cast<Item>(); }
bool isItem() { return true; }
ItemVector getContainerItems() { return m_containerItems; }
ItemPtr getContainerItem(int slot) { return m_containerItems[slot]; }
void addContainerItemIndexed(const ItemPtr& i, int slot) { m_containerItems[slot] = i; }
void addContainerItem(const ItemPtr& i) { m_containerItems.push_back(i); }
void removeContainerItem(int slot) { m_containerItems[slot] = nullptr; }
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;
uint16 m_countOrSubType;
stdext::packed_storage<uint8> m_attribs;
ItemVector m_containerItems;
Color m_color;
bool m_async;
std::string m_tooltip;
uint8 m_phase;
ticks_t m_lastPhase;
};
#pragma pack(pop)
#endif

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

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2010-2017 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 "game.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(g_game.getClientVersion() < 960) {
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);
}
}
} else {
if(serverId > 30000 && serverId < 30100) {
serverId -= 30000;
} 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;
case ItemTypeAttrWritable:
m_attribs.set(ItemTypeAttrWritable, true);
break;
default:
node->skip(len); // skip attribute
break;
}
}
}

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

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2010-2017 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,
ItemCategoryDeprecated = 14,
ItemCategoryLast = 15
};
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
ItemTypeAttrWareId = 45,
ItemTypeAttrLast = 46
};
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; }
bool isWritable() { return m_attribs.get<bool>(ItemTypeAttrWritable); }
private:
ItemCategory m_category;
stdext::boolean<true> m_null;
stdext::dynamic_storage<uint8> m_attribs;
};
#endif

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

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2010-2017 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 <framework/graphics/painter.h>
void LightView::addLight(const Point& pos, uint8_t color, uint8_t intensity)
{
if (!m_lights.empty()) {
Light& prevLight = m_lights.back();
if (prevLight.pos == pos && prevLight.color == color) {
prevLight.intensity = std::max(prevLight.intensity, intensity);
return;
}
}
m_lights.push_back(Light{ pos, color, intensity });
}
void LightView::setFieldBrightness(const Point& pos, size_t start, uint8_t color)
{
size_t index = (pos.y / Otc::TILE_PIXELS) * m_mapSize.width() + (pos.x / Otc::TILE_PIXELS);
if (index >= m_tiles.size()) return;
m_tiles[index].start = start;
m_tiles[index].color = color;
}
void LightView::draw() // render thread
{
static std::vector<uint8_t> buffer;
if(buffer.size() < 4u * m_mapSize.area())
buffer.resize(m_mapSize.area() * 4);
// hidden code
m_lightTexture->update();
glBindTexture(GL_TEXTURE_2D, m_lightTexture->getId());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_mapSize.width(), m_mapSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
Point offset = m_src.topLeft();
Size size = m_src.size();
CoordsBuffer coords;
coords.addRect(RectF(m_dest.left(), m_dest.top(), m_dest.width(), m_dest.height()),
RectF((float)offset.x / Otc::TILE_PIXELS, (float)offset.y / Otc::TILE_PIXELS,
(float)size.width() / Otc::TILE_PIXELS, (float)size.height() / Otc::TILE_PIXELS));
g_painterNew->resetColor();
g_painterNew->setCompositionMode(Painter::CompositionMode_Multiply);
g_painterNew->drawTextureCoords(coords, m_lightTexture);
g_painterNew->resetCompositionMode();
}

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

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2017 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 "thingtype.h"
#include <framework/graphics/declarations.h>
#include <framework/graphics/drawqueue.h>
#include <set>
struct TileLight {
size_t start;
uint8_t color;
};
class LightView : public DrawQueueItem
{
public:
LightView(TexturePtr& lightTexture, const Size& mapSize, const Rect& dest, const Rect& src, uint8_t color, uint8_t intensity) :
DrawQueueItem(nullptr), m_lightTexture(lightTexture), m_mapSize(mapSize), m_dest(dest), m_src(src) {
m_globalLight = Color::from8bit(color) * ((float)intensity / 255.f);
m_tiles.resize(m_mapSize.area(), TileLight{ 0, 0 });
}
inline void addLight(const Point& pos, const Light& light)
{
return addLight(pos, light.color, light.intensity);
}
void addLight(const Point& pos, uint8_t color, uint8_t intensity);
void setFieldBrightness(const Point& pos, size_t start, uint8_t color);
size_t size() { return m_lights.size(); }
void draw() override;
private:
TexturePtr m_lightTexture;
Size m_mapSize;
Rect m_dest, m_src;
Color m_globalLight;
std::vector<Light> m_lights;
std::vector<TileLight> m_tiles;
};
#endif

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

@@ -0,0 +1,623 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/graphics/graphics.h>
#include <framework/util/extras.h>
LocalPlayer::LocalPlayer()
{
m_states = 0;
m_vocation = 0;
m_blessings = Otc::BlessingNone;
m_walkLockExpiration = 0;
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::draw(const Point& dest, bool animate, LightView* lightView)
{
Creature::draw(dest, animate, lightView);
}
void LocalPlayer::lockWalk(int millis)
{
m_walkLockExpiration = std::max<int>(m_walkLockExpiration, (ticks_t) g_clock.millis() + millis);
}
bool LocalPlayer::canWalk(Otc::Direction direction, bool ignoreLock) {
// cannot walk while locked
if ((m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration) && !ignoreLock)
return false;
// paralyzed
if (m_speed == 0)
return false;
// last walk is not done yet
if (m_walking && (m_walkTimer.ticksElapsed() < getStepDuration()) && !isAutoWalking() && !isServerWalking())
return false;
auto tile = g_map.getTile(getPrewalkingPosition(true));
if (isPreWalking() && (!m_lastPrewalkDone || (tile && tile->isBlocking())))
return false;
// cannot walk while already walking
if ((m_walking && !isAutoWalking() && !isServerWalking()) && (!isPreWalking() || !m_lastPrewalkDone))
return false;
// Without new walking limit only to 1 prewalk
if (!m_preWalking.empty() && !g_game.getFeature(Otc::GameNewWalking))
return false;
// Limit pre walking steps
if (m_preWalking.size() >= g_game.getMaxPreWalkingSteps()) // max 3 extra steps
return false;
if (!m_preWalking.empty()) { // disallow diagonal extented prewalking walking
auto dir = m_position.getDirectionFromPosition(m_preWalking.back());
if ((dir == Otc::NorthWest || dir == Otc::NorthEast || dir == Otc::SouthWest || dir == Otc::SouthEast)) {
return false;
}
if (!g_map.getTile(getPrewalkingPosition())->isWalkable())
return false;
}
return true;
}
void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
{
if (g_extras.debugWalking) {
g_logger.info(stdext::format("[%i] LocalPlayer::walk", (int)g_clock.millis()));
}
m_lastAutoWalkRetries = 0;
// a prewalk was going on
if (isPreWalking()) {
for (auto it = m_preWalking.begin(); it != m_preWalking.end(); ++it) {
if (*it == newPos) {
m_preWalking.erase(m_preWalking.begin(), ++it);
if(!isPreWalking()) // reset pre walking
updateWalk();
return;
}
}
if (g_extras.debugWalking) {
g_logger.info(stdext::format("[%i] LocalPlayer::walk invalid prewalk", (int)g_clock.millis()));
}
// invalid pre walk
m_preWalking.clear();
m_serverWalking = true;
if(m_serverWalkEndEvent)
m_serverWalkEndEvent->cancel();
Creature::walk(oldPos, newPos);
} else { // no prewalk was going on, this must be an server side automated walk
if (g_extras.debugWalking) {
g_logger.info(stdext::format("[%i] LocalPlayer::walk server walk", (int)g_clock.millis()));
}
m_serverWalking = true;
if(m_serverWalkEndEvent)
m_serverWalkEndEvent->cancel();
m_lastAutoWalkRetries = 0;
Creature::walk(oldPos, newPos);
}
}
void LocalPlayer::preWalk(Otc::Direction direction)
{
}
void LocalPlayer::cancelWalk(Otc::Direction direction)
{
if (g_game.getFeature(Otc::GameNewWalking)) {
return;
}
return cancelNewWalk(direction);
}
void LocalPlayer::cancelNewWalk(Otc::Direction dir)
{
if (g_extras.debugWalking) {
g_logger.info(stdext::format("[%i] cancelWalk", (int)g_clock.millis()));
}
bool clearedPrewalk = !m_preWalking.empty();
m_preWalking.clear();
g_map.requestVisibleTilesCacheUpdate();
if (clearedPrewalk) {
stopWalk();
}
m_idleTimer.restart();
if (retryAutoWalk()) return;
if (!g_game.isIgnoringServerDirection() || !g_game.getFeature(Otc::GameNewWalking)) {
setDirection(dir);
}
callLuaField("onCancelWalk", dir);
}
bool LocalPlayer::predictiveCancelWalk(const Position& pos, uint32_t predictionId, Otc::Direction dir)
{
if (g_extras.debugPredictiveWalking) {
g_logger.info(stdext::format("[%i] predictiveCancelWalk: %i - %i", (int)g_clock.millis(), predictionId, (int)m_preWalking.size()));
}
return false;
}
bool LocalPlayer::retryAutoWalk()
{
return false;
}
bool LocalPlayer::autoWalk(Position destination, bool retry)
{
// reset state
m_autoWalkDestination = Position();
m_lastAutoWalkPosition = Position();
if(m_autoWalkContinueEvent)
m_autoWalkContinueEvent->cancel();
m_autoWalkContinueEvent = nullptr;
if (!retry)
m_lastAutoWalkRetries = 0;
if(destination == getPrewalkingPosition())
return true;
m_autoWalkDestination = destination;
auto self(asLocalPlayer());
g_map.findPathAsync(getPrewalkingPosition(), destination, [self](PathFindResult_ptr result) {
if (self->m_autoWalkDestination != result->destination)
return;
if (g_extras.debugWalking) {
g_logger.info(stdext::format("Async path search finished with complexity %i/50000", result->complexity));
}
if (result->status != Otc::PathFindResultOk) {
if (self->m_lastAutoWalkRetries > 0 && self->m_lastAutoWalkRetries <= 3) { // try again in 300, 700, 1200 ms if canceled by server
self->m_autoWalkContinueEvent = g_dispatcher.scheduleEvent(std::bind(&LocalPlayer::autoWalk, self, result->destination, true), 200 + self->m_lastAutoWalkRetries * 100);
return;
}
self->m_autoWalkDestination = Position();
self->callLuaField("onAutoWalkFail", result->status);
return;
}
if(!g_game.getFeature(Otc::GameNewWalking) && result->path.size() > 127)
result->path.resize(127);
else if(result->path.size() > 4095)
result->path.resize(4095);
if (result->path.empty()) {
self->m_autoWalkDestination = Position();
self->callLuaField("onAutoWalkFail", result->status);
return;
}
auto finalAutowalkPos = self->getPrewalkingPosition().translatedToDirections(result->path).back();
if (self->m_autoWalkDestination != finalAutowalkPos) {
self->m_lastAutoWalkPosition = finalAutowalkPos;
}
g_game.autoWalk(result->path, result->start);
});
if(!retry)
lockWalk();
return true;
}
void LocalPlayer::stopAutoWalk()
{
m_autoWalkDestination = Position();
m_lastAutoWalkPosition = Position();
if (m_autoWalkContinueEvent) {
m_autoWalkContinueEvent->cancel();
m_autoWalkContinueEvent = nullptr;
}
}
void LocalPlayer::stopWalk() {
if (g_extras.debugWalking) {
g_logger.info(stdext::format("[%i] stopWalk", (int)g_clock.millis()));
}
Creature::stopWalk(); // will call terminateWalk
m_preWalking.clear();
}
void LocalPlayer::updateWalkOffset(int totalPixelsWalked, bool inNextFrame)
{
// pre walks offsets are calculated in the oposite direction
if(isPreWalking()) {
Point& walkOffset = inNextFrame ? m_walkOffsetInNextFrame : m_walkOffset;
walkOffset = Point(0,0);
if(m_walkDirection == Otc::North || m_walkDirection == Otc::NorthEast || m_walkDirection == Otc::NorthWest)
walkOffset.y = -totalPixelsWalked;
else if(m_walkDirection == Otc::South || m_walkDirection == Otc::SouthEast || m_walkDirection == Otc::SouthWest)
walkOffset.y = totalPixelsWalked;
if(m_walkDirection == Otc::East || m_walkDirection == Otc::NorthEast || m_walkDirection == Otc::SouthEast)
walkOffset.x = totalPixelsWalked;
else if(m_walkDirection == Otc::West || m_walkDirection == Otc::NorthWest || m_walkDirection == Otc::SouthWest)
walkOffset.x = -totalPixelsWalked;
} else
Creature::updateWalkOffset(totalPixelsWalked, inNextFrame);
}
void LocalPlayer::updateWalk()
{
if (!m_walking)
return;
float walkTicksPerPixel = ((float)(getStepDuration(true) + 10)) / 32.0f;
int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
int totalPixelsWalkedInNextFrame = std::min<int>((m_walkTimer.ticksElapsed() + 15) / walkTicksPerPixel, 32.0f);
// needed for paralyze effect
m_walkedPixels = std::max<int>(m_walkedPixels, totalPixelsWalked);
int walkedPixelsInNextFrame = std::max<int>(m_walkedPixels, totalPixelsWalkedInNextFrame);
// update walk animation and offsets
updateWalkAnimation(totalPixelsWalked);
updateWalkOffset(m_walkedPixels);
updateWalkOffset(walkedPixelsInNextFrame, true);
updateWalkingTile();
int stepDuration = getStepDuration();
// terminate walk only when client and server side walk are completed
if (m_walking && m_walkTimer.ticksElapsed() >= stepDuration)
m_lastPrewalkDone = true;
if(m_walking && m_walkTimer.ticksElapsed() >= stepDuration && !isPreWalking())
terminateWalk();
}
void LocalPlayer::terminateWalk()
{
if (g_extras.debugWalking) {
g_logger.info(stdext::format("[%i] terminateWalk", (int)g_clock.millis()));
}
Creature::terminateWalk();
m_idleTimer.restart();
m_preWalking.clear();
m_walking = false;
auto self = asLocalPlayer();
if(m_serverWalking) {
if(m_serverWalkEndEvent)
m_serverWalkEndEvent->cancel();
m_serverWalkEndEvent = g_dispatcher.scheduleEvent([self] {
self->m_serverWalking = false;
}, 100);
}
callLuaField("onWalkFinish");
}
void LocalPlayer::onAppear()
{
Creature::onAppear();
/* Does not seem to be needed anymore
// 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);
if(newPos == m_autoWalkDestination)
stopAutoWalk();
else if(m_autoWalkDestination.isValid() && newPos == m_lastAutoWalkPosition)
autoWalk(m_autoWalkDestination);
m_walkMatrix.updatePosition(newPos);
}
void LocalPlayer::turn(Otc::Direction direction)
{
Creature::setDirection(direction);
callLuaField("onTurn", direction);
}
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::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);
}
}
void LocalPlayer::setBlessings(int blessings)
{
if(blessings != m_blessings) {
int oldBlessings = m_blessings;
m_blessings = blessings;
callLuaField("onBlessingsChange", blessings, oldBlessings);
}
}
bool LocalPlayer::hasSight(const Position& pos)
{
return m_position.isInRange(pos, g_map.getAwareRange().left - 1, g_map.getAwareRange().top - 1);
}

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

@@ -0,0 +1,205 @@
/*
* Copyright (c) 2010-2017 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"
#include "walkmatrix.h"
// @bindclass
class LocalPlayer : public Player
{
enum {
PREWALK_TIMEOUT = 1000
};
public:
LocalPlayer();
void draw(const Point& dest, bool animate = true, LightView* lightView = nullptr) override;
void unlockWalk() { m_walkLockExpiration = 0; }
void lockWalk(int millis = 200);
void stopAutoWalk();
bool autoWalk(Position destination, bool retry = false);
bool canWalk(Otc::Direction direction, bool ignoreLock = false);
bool isWalkLocked() {
return (m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration);
}
void turn(Otc::Direction) override;
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 setRegenerationTime(double regenerationTime);
void setOfflineTrainingTime(double offlineTrainingTime);
void setSpells(const std::vector<int>& spells);
void setBlessings(int blessings);
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; }
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 std::max<double>(m_mana, 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 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]; }
int getBlessings() { return m_blessings; }
bool hasSight(const Position& pos);
bool isKnown() { return m_known; }
bool isAutoWalking() { return m_autoWalkDestination.isValid(); }
bool isServerWalking() override { return m_serverWalking; }
bool isPremium() { return m_premium; }
bool isPendingGame() { return m_pending; }
LocalPlayerPtr asLocalPlayer() { return static_self_cast<LocalPlayer>(); }
bool isLocalPlayer() override { return true; }
void onAppear() override;
void onPositionChange(const Position& newPos, const Position& oldPos) override;
// pre walking
void preWalk(Otc::Direction direction);
bool isPreWalking() override { return !m_preWalking.empty(); }
Position getPrewalkingPosition(bool beforePrewalk = false) override {
if(m_preWalking.empty())
return m_position;
else if (!beforePrewalk && m_preWalking.size() == 1)
return m_position;
auto ret = m_preWalking.rbegin();
if(!beforePrewalk)
ret++;
return *ret;
}
uint32_t getWalkPrediction(const Position& pos)
{
return m_walkMatrix.get(pos);
};
std::string dumpWalkMatrix()
{
return m_walkMatrix.dump();
}
void startServerWalking() { m_serverWalking = true; }
void finishServerWalking() { m_serverWalking = false; }
protected:
void walk(const Position& oldPos, const Position& newPos);
void cancelWalk(Otc::Direction direction = Otc::InvalidDirection);
void cancelNewWalk(Otc::Direction dir);
bool predictiveCancelWalk(const Position& pos, uint32_t predictionId, Otc::Direction dir);
bool retryAutoWalk();
void stopWalk();
friend class Game;
protected:
void updateWalkOffset(int totalPixelsWalked, bool inNextFrame = false) override;
void updateWalk() override;
void terminateWalk() override;
private:
// walk related
Position m_autoWalkDestination;
Position m_lastAutoWalkPosition;
int m_lastAutoWalkRetries = 0;
ScheduledEventPtr m_serverWalkEndEvent;
ScheduledEventPtr m_autoWalkContinueEvent;
ticks_t m_walkLockExpiration;
// walking and pre walking
std::list<Position> m_preWalking;
bool m_serverWalking = false;
bool m_lastPrewalkDone = false;
WalkMatrix m_walkMatrix;
bool m_premium = false;
bool m_known = false;
bool m_pending = false;
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;
int m_states;
int m_vocation;
int m_blessings;
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_regenerationTime;
double m_offlineTrainingTime;
};
#endif

View File

@@ -0,0 +1,921 @@
/*
* Copyright (c) 2010-2017 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_client.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 "minimap.h"
#include "thingtypemanager.h"
#include "spritemanager.h"
#include "shadermanager.h"
#include "protocolgame.h"
#include "uiitem.h"
#include "uicreature.h"
#include "uimap.h"
#include "uiminimap.h"
#include "uimapanchorlayout.h"
#include "uiprogressrect.h"
#include "uisprite.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);
#ifdef WITH_ENCRYPTION
g_lua.bindSingletonFunction("g_things", "saveDat", &ThingTypeManager::saveDat, &g_things);
g_lua.bindSingletonFunction("g_things", "dumpTextures", &ThingTypeManager::dumpTextures, &g_things);
g_lua.bindSingletonFunction("g_things", "replaceTextures", &ThingTypeManager::replaceTextures, &g_things);
#endif
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", "loadOtml", &ThingTypeManager::loadOtml, &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", "getContentRevision", &ThingTypeManager::getContentRevision, &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", "findItemTypeByName", &ThingTypeManager::findItemTypeByName, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypesByName", &ThingTypeManager::findItemTypesByName, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypesByString", &ThingTypeManager::findItemTypesByString, &g_things);
g_lua.bindSingletonFunction("g_things", "findItemTypeByCategory", &ThingTypeManager::findItemTypeByCategory, &g_things);
g_lua.bindSingletonFunction("g_things", "findThingTypeByAttr", &ThingTypeManager::findThingTypeByAttr, &g_things);
g_lua.bindSingletonFunction("g_things", "getMarketCategories", &ThingTypeManager::getMarketCategories, &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", "getHouseByName", &HouseManager::getHouseByName, &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.bindSingletonFunction("g_houses", "filterHouses", &HouseManager::filterHouses, &g_houses);
g_lua.bindSingletonFunction("g_houses", "sort", &HouseManager::sort, &g_houses);
g_lua.registerSingletonClass("g_towns");
g_lua.bindSingletonFunction("g_towns", "getTown", &TownManager::getTown, &g_towns);
g_lua.bindSingletonFunction("g_towns", "getTownByName",&TownManager::getTownByName,&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.bindSingletonFunction("g_towns", "sort", &TownManager::sort, &g_towns);
g_lua.registerSingletonClass("g_sprites");
g_lua.bindSingletonFunction("g_sprites", "loadSpr", &SpriteManager::loadSpr, &g_sprites);
#ifdef WITH_ENCRYPTION
g_lua.bindSingletonFunction("g_sprites", "saveSpr", &SpriteManager::saveSpr, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "dumpSprites", &SpriteManager::dumpSprites, &g_sprites);
g_lua.bindSingletonFunction("g_sprites", "encryptSprites", &SpriteManager::encryptSprites, &g_sprites);
#endif
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", "colorizeThing", &Map::colorizeThing, &g_map);
g_lua.bindSingletonFunction("g_map", "removeThingColor", &Map::removeThingColor, &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", "getOrCreateTile", &Map::getOrCreateTile, &g_map);
g_lua.bindSingletonFunction("g_map", "getTiles", &Map::getTiles, &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", "getSpectatorsInRange", &Map::getSpectatorsInRange, &g_map);
g_lua.bindSingletonFunction("g_map", "getSpectatorsInRangeEx", &Map::getSpectatorsInRangeEx, &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", "setWidth", &Map::setWidth, &g_map);
g_lua.bindSingletonFunction("g_map", "setHeight", &Map::setHeight, &g_map);
g_lua.bindSingletonFunction("g_map", "getSize", &Map::getSize, &g_map);
g_lua.bindSingletonFunction("g_map", "setDescription", &Map::setDescription, &g_map);
g_lua.bindSingletonFunction("g_map", "getDescriptions", &Map::getDescriptions, &g_map);
g_lua.bindSingletonFunction("g_map", "clearDescriptions", &Map::clearDescriptions, &g_map);
g_lua.bindSingletonFunction("g_map", "setShowZone", &Map::setShowZone, &g_map);
g_lua.bindSingletonFunction("g_map", "setShowZones", &Map::setShowZones, &g_map);
g_lua.bindSingletonFunction("g_map", "setZoneColor", &Map::setZoneColor, &g_map);
g_lua.bindSingletonFunction("g_map", "setZoneOpacity", &Map::setZoneOpacity, &g_map);
g_lua.bindSingletonFunction("g_map", "getZoneOpacity", &Map::getZoneOpacity, &g_map);
g_lua.bindSingletonFunction("g_map", "getZoneColor", &Map::getZoneColor, &g_map);
g_lua.bindSingletonFunction("g_map", "showZones", &Map::showZones, &g_map);
g_lua.bindSingletonFunction("g_map", "showZone", &Map::showZone, &g_map);
g_lua.bindSingletonFunction("g_map", "setForceShowAnimations", &Map::setForceShowAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "isForcingAnimations", &Map::isForcingAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "isShowingAnimations", &Map::isShowingAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "setShowAnimations", &Map::setShowAnimations, &g_map);
g_lua.bindSingletonFunction("g_map", "findItemsById", &Map::findItemsById, &g_map);
g_lua.bindSingletonFunction("g_map", "getAwareRange", &Map::getAwareRangeAsSize, &g_map);
g_lua.bindSingletonFunction("g_map", "findEveryPath", &Map::findEveryPath, &g_map);
g_lua.bindSingletonFunction("g_map", "getMinimapColor", &Map::getMinimapColor, &g_map);
g_lua.bindSingletonFunction("g_map", "isPatchable", &Map::isPatchable, &g_map);
g_lua.bindSingletonFunction("g_map", "isWalkable", &Map::isWalkable, &g_map);
g_lua.registerSingletonClass("g_minimap");
g_lua.bindSingletonFunction("g_minimap", "clean", &Minimap::clean, &g_minimap);
g_lua.bindSingletonFunction("g_minimap", "loadImage", &Minimap::loadImage, &g_minimap);
g_lua.bindSingletonFunction("g_minimap", "saveImage", &Minimap::saveImage, &g_minimap);
g_lua.bindSingletonFunction("g_minimap", "loadOtmm", &Minimap::loadOtmm, &g_minimap);
g_lua.bindSingletonFunction("g_minimap", "saveOtmm", &Minimap::saveOtmm, &g_minimap);
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", "getSpawnForPlacePos", &CreatureManager::getSpawnForPlacePos, &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.bindSingletonFunction("g_creatures", "getSpawns", &CreatureManager::getSpawns, &g_creatures);
g_lua.bindSingletonFunction("g_creatures", "deleteSpawn", &CreatureManager::deleteSpawn, &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", "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", "moveRaw", &Game::moveRaw, &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", "wrap", &Game::wrap, &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", "findItemInContainers", &Game::findItemInContainers, &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", "editVip", &Game::editVip, &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", "setPVPMode", &Game::setPVPMode, &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", "getPVPMode", &Game::getPVPMode, &g_game);
g_lua.bindSingletonFunction("g_game", "getUnjustifiedPoints", &Game::getUnjustifiedPoints, &g_game);
g_lua.bindSingletonFunction("g_game", "getOpenPvpSituations", &Game::getOpenPvpSituations, &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", "openRuleViolation", &Game::openRuleViolation, &g_game);
g_lua.bindSingletonFunction("g_game", "closeRuleViolation", &Game::closeRuleViolation, &g_game);
g_lua.bindSingletonFunction("g_game", "cancelRuleViolation", &Game::cancelRuleViolation, &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", "setPingDelay", &Game::setPingDelay, &g_game);
g_lua.bindSingletonFunction("g_game", "changeMapAwareRange", &Game::changeMapAwareRange, &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", "isLogging", &Game::isLogging, &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", "isConnectionOk", &Game::isConnectionOk, &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", "getCustomProtocolVersion", &Game::getCustomProtocolVersion, &g_game);
g_lua.bindSingletonFunction("g_game", "setCustomProtocolVersion", &Game::setCustomProtocolVersion, &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", "setCustomOs", &Game::setCustomOs, &g_game);
g_lua.bindSingletonFunction("g_game", "getOs", &Game::getOs, &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", "disableFeature", &Game::disableFeature, &g_game);
g_lua.bindSingletonFunction("g_game", "resetFeatures", &Game::resetFeatures, &g_game);
g_lua.bindSingletonFunction("g_game", "isGM", &Game::isGM, &g_game);
g_lua.bindSingletonFunction("g_game", "answerModalDialog", &Game::answerModalDialog, &g_game);
g_lua.bindSingletonFunction("g_game", "browseField", &Game::browseField, &g_game);
g_lua.bindSingletonFunction("g_game", "seekInContainer", &Game::seekInContainer, &g_game);
g_lua.bindSingletonFunction("g_game", "getLastWalkDir", &Game::getLastWalkDir, &g_game);
g_lua.bindSingletonFunction("g_game", "buyStoreOffer", &Game::buyStoreOffer, &g_game);
g_lua.bindSingletonFunction("g_game", "requestTransactionHistory", &Game::requestTransactionHistory, &g_game);
g_lua.bindSingletonFunction("g_game", "requestStoreOffers", &Game::requestStoreOffers, &g_game);
g_lua.bindSingletonFunction("g_game", "openStore", &Game::openStore, &g_game);
g_lua.bindSingletonFunction("g_game", "transferCoins", &Game::transferCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "openTransactionHistory", &Game::openTransactionHistory, &g_game);
g_lua.bindSingletonFunction("g_game", "preyAction", &Game::preyAction, &g_game);
g_lua.bindSingletonFunction("g_game", "preyRequest", &Game::preyRequest, &g_game);
g_lua.bindSingletonFunction("g_game", "applyImbuement", &Game::applyImbuement, &g_game);
g_lua.bindSingletonFunction("g_game", "clearImbuement", &Game::clearImbuement, &g_game);
g_lua.bindSingletonFunction("g_game", "closeImbuingWindow", &Game::closeImbuingWindow, &g_game);
g_lua.bindSingletonFunction("g_game", "setTibiaCoins", &Game::setTibiaCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "getTibiaCoins", &Game::getTibiaCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "getTransferableTibiaCoins", &Game::getTransferableTibiaCoins, &g_game);
g_lua.bindSingletonFunction("g_game", "getMaxPreWalkingSteps", &Game::getMaxPreWalkingSteps, &g_game);
g_lua.bindSingletonFunction("g_game", "setMaxPreWalkingSteps", &Game::setMaxPreWalkingSteps, &g_game);
g_lua.bindSingletonFunction("g_game", "ignoreServerDirection", &Game::ignoreServerDirection, &g_game);
g_lua.bindSingletonFunction("g_game", "showRealDirection", &Game::showRealDirection, &g_game);
g_lua.bindSingletonFunction("g_game", "enableTileThingLuaCallback", &Game::enableTileThingLuaCallback, &g_game);
g_lua.bindSingletonFunction("g_game", "isTileThingLuaCallbackEnabled", &Game::isTileThingLuaCallbackEnabled, &g_game);
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsCount", &Game::getRecivedPacketsCount, &g_game);
g_lua.bindSingletonFunction("g_game", "getRecivedPacketsSize", &Game::getRecivedPacketsSize, &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("getOutfitColor", Outfit::getColor);
g_lua.bindGlobalFunction("getAngleFromPos", Position::getAngleFromPositions);
g_lua.bindGlobalFunction("getDirectionFromPos", Position::getDirectionFromPositions);
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.bindClassMemberFunction<Container>("isUnlocked", &Container::isUnlocked);
g_lua.bindClassMemberFunction<Container>("hasPages", &Container::hasPages);
g_lua.bindClassMemberFunction<Container>("getSize", &Container::getSize);
g_lua.bindClassMemberFunction<Container>("getFirstIndex", &Container::getFirstIndex);
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>("getStackPos", &Thing::getStackPos);
g_lua.bindClassMemberFunction<Thing>("getAnimationPhases", &Thing::getAnimationPhases);
g_lua.bindClassMemberFunction<Thing>("getTile", &Thing::getTile);
g_lua.bindClassMemberFunction<Thing>("setMarked", &Thing::setMarked);
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>("getMarketData", &Thing::getMarketData);
g_lua.bindClassMemberFunction<Thing>("isUsable", &Thing::isUsable);
g_lua.bindClassMemberFunction<Thing>("isWrapable", &Thing::isWrapable);
g_lua.bindClassMemberFunction<Thing>("isUnwrapable", &Thing::isUnwrapable);
g_lua.bindClassMemberFunction<Thing>("isTopEffect", &Thing::isTopEffect);
g_lua.bindClassMemberFunction<Thing>("isLyingCorpse", &Thing::isLyingCorpse);
g_lua.bindClassMemberFunction<Thing>("getParentContainer", &Thing::getParentContainer);
g_lua.bindClassMemberFunction<Thing>("hide", &Thing::hide);
g_lua.bindClassMemberFunction<Thing>("show", &Thing::show);
g_lua.bindClassMemberFunction<Thing>("setHidden", &Thing::setHidden);
g_lua.bindClassMemberFunction<Thing>("isHidden", &Thing::isHidden);
g_lua.registerClass<House>();
g_lua.bindClassStaticFunction<House>("create", []{ return HousePtr(new House); });
g_lua.bindClassMemberFunction<House>("setId", &House::setId);
g_lua.bindClassMemberFunction<House>("getId", &House::getId);
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>("addDoor", &House::addDoor);
g_lua.bindClassMemberFunction<House>("removeDoor", &House::removeDoor);
g_lua.bindClassMemberFunction<House>("removeDoorById", &House::removeDoorById);
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.bindClassMemberFunction<Spawn>("getCreatures", &Spawn::getCreatures);
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>("setManaPercent", &LocalPlayer::setManaPercent);
g_lua.bindClassMemberFunction<Creature>("getManaPercent", &LocalPlayer::getManaPercent);
g_lua.bindClassMemberFunction<Creature>("getHealthPercent", &Creature::getHealthPercent);
g_lua.bindClassMemberFunction<Creature>("getSpeed", &Creature::getSpeed);
g_lua.bindClassMemberFunction<Creature>("setSpeed", &Creature::setSpeed);
g_lua.bindClassMemberFunction<Creature>("getBaseSpeed", &Creature::getBaseSpeed);
g_lua.bindClassMemberFunction<Creature>("setBaseSpeed", &Creature::setBaseSpeed);
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>("setSkull", &Creature::setSkull);
g_lua.bindClassMemberFunction<Creature>("setShield", &Creature::setShield);
g_lua.bindClassMemberFunction<Creature>("setEmblem", &Creature::setEmblem);
g_lua.bindClassMemberFunction<Creature>("getType", &Creature::getType);
g_lua.bindClassMemberFunction<Creature>("getIcon", &Creature::getIcon);
g_lua.bindClassMemberFunction<Creature>("setOutfit", &Creature::setOutfit);
g_lua.bindClassMemberFunction<Creature>("getOutfit", &Creature::getOutfit);
g_lua.bindClassMemberFunction<Creature>("setOutfitColor", &Creature::setOutfitColor);
g_lua.bindClassMemberFunction<Creature>("getDirection", &Creature::getDirection);
g_lua.bindClassMemberFunction<Creature>("getWalkDirection", &Creature::getWalkDirection);
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>("setTypeTexture", &Creature::setTypeTexture);
g_lua.bindClassMemberFunction<Creature>("setIconTexture", &Creature::setIconTexture);
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>("isDead", &Creature::isDead);
g_lua.bindClassMemberFunction<Creature>("isRemoved", &Creature::isRemoved);
g_lua.bindClassMemberFunction<Creature>("canBeSeen", &Creature::canBeSeen);
g_lua.bindClassMemberFunction<Creature>("jump", &Creature::jump);
g_lua.bindClassMemberFunction<Creature>("getPrewalkingPosition", &Creature::getPrewalkingPosition);
g_lua.bindClassMemberFunction<Creature>("setInformationColor", &Creature::setInformationColor);
g_lua.bindClassMemberFunction<Creature>("resetInformationColor", &Creature::resetInformationColor);
g_lua.bindClassMemberFunction<Creature>("setInformationOffset", &Creature::setInformationOffset);
g_lua.bindClassMemberFunction<Creature>("getInformationOffset", &Creature::getInformationOffset);
g_lua.bindClassMemberFunction<Creature>("setText", &Creature::setText);
g_lua.bindClassMemberFunction<Creature>("getText", &Creature::getText);
g_lua.bindClassMemberFunction<Creature>("clearText", &Creature::clearText);
// widgets
g_lua.bindClassMemberFunction<Creature>("addTopWidget", &Creature::addTopWidget);
g_lua.bindClassMemberFunction<Creature>("addBottomWidget", &Creature::addBottomWidget);
g_lua.bindClassMemberFunction<Creature>("addDirectionalWidget", &Creature::addDirectionalWidget);
g_lua.bindClassMemberFunction<Creature>("removeTopWidget", &Creature::removeTopWidget);
g_lua.bindClassMemberFunction<Creature>("removeBottomWidget", &Creature::removeBottomWidget);
g_lua.bindClassMemberFunction<Creature>("removeDirectionalWidget", &Creature::removeDirectionalWidget);
g_lua.bindClassMemberFunction<Creature>("getTopWidgets", &Creature::getTopWidgets);
g_lua.bindClassMemberFunction<Creature>("getBottomWidgets", &Creature::getBottomWidgets);
g_lua.bindClassMemberFunction<Creature>("getDirectionalWdigets", &Creature::getDirectionalWdigets);
g_lua.bindClassMemberFunction<Creature>("clearWidgets", &Creature::clearWidgets);
g_lua.bindClassMemberFunction<Creature>("clearTopWidgets", &Creature::clearTopWidgets);
g_lua.bindClassMemberFunction<Creature>("clearBottomWidgets", &Creature::clearBottomWidgets);
g_lua.bindClassMemberFunction<Creature>("clearDirectionalWidgets", &Creature::clearDirectionalWidgets);
g_lua.registerClass<ItemType>();
g_lua.bindClassMemberFunction<ItemType>("getServerId", &ItemType::getServerId);
g_lua.bindClassMemberFunction<ItemType>("getClientId", &ItemType::getClientId);
g_lua.bindClassMemberFunction<ItemType>("isWritable", &ItemType::isWritable);
g_lua.registerClass<ThingType>();
g_lua.bindClassStaticFunction<ThingType>("create", []{ return ThingTypePtr(new ThingType); });
g_lua.bindClassMemberFunction<ThingType>("getId", &ThingType::getId);
g_lua.bindClassMemberFunction<ThingType>("getClothSlot", &ThingType::getClothSlot);
g_lua.bindClassMemberFunction<ThingType>("getCategory", &ThingType::getCategory);
g_lua.bindClassMemberFunction<ThingType>("getSize", &ThingType::getSize);
g_lua.bindClassMemberFunction<ThingType>("getWidth", &ThingType::getWidth);
g_lua.bindClassMemberFunction<ThingType>("getHeight", &ThingType::getHeight);
g_lua.bindClassMemberFunction<ThingType>("getDisplacement", &ThingType::getDisplacement);
g_lua.bindClassMemberFunction<ThingType>("getDisplacementX", &ThingType::getDisplacementX);
g_lua.bindClassMemberFunction<ThingType>("getDisplacementY", &ThingType::getDisplacementY);
g_lua.bindClassMemberFunction<ThingType>("getExactSize", &ThingType::getExactSize);
g_lua.bindClassMemberFunction<ThingType>("getRealSize", &ThingType::getRealSize);
g_lua.bindClassMemberFunction<ThingType>("getLayers", &ThingType::getLayers);
g_lua.bindClassMemberFunction<ThingType>("getNumPatternX", &ThingType::getNumPatternX);
g_lua.bindClassMemberFunction<ThingType>("getNumPatternY", &ThingType::getNumPatternY);
g_lua.bindClassMemberFunction<ThingType>("getNumPatternZ", &ThingType::getNumPatternZ);
g_lua.bindClassMemberFunction<ThingType>("getAnimationPhases", &ThingType::getAnimationPhases);
g_lua.bindClassMemberFunction<ThingType>("getGroundSpeed", &ThingType::getGroundSpeed);
g_lua.bindClassMemberFunction<ThingType>("getMaxTextLength", &ThingType::getMaxTextLength);
g_lua.bindClassMemberFunction<ThingType>("getLight", &ThingType::getLight);
g_lua.bindClassMemberFunction<ThingType>("getMinimapColor", &ThingType::getMinimapColor);
g_lua.bindClassMemberFunction<ThingType>("getLensHelp", &ThingType::getLensHelp);
g_lua.bindClassMemberFunction<ThingType>("getClothSlot", &ThingType::getClothSlot);
g_lua.bindClassMemberFunction<ThingType>("getElevation", &ThingType::getElevation);
g_lua.bindClassMemberFunction<ThingType>("isGround", &ThingType::isGround);
g_lua.bindClassMemberFunction<ThingType>("isGroundBorder", &ThingType::isGroundBorder);
g_lua.bindClassMemberFunction<ThingType>("isOnBottom", &ThingType::isOnBottom);
g_lua.bindClassMemberFunction<ThingType>("isOnTop", &ThingType::isOnTop);
g_lua.bindClassMemberFunction<ThingType>("isContainer", &ThingType::isContainer);
g_lua.bindClassMemberFunction<ThingType>("isStackable", &ThingType::isStackable);
g_lua.bindClassMemberFunction<ThingType>("isForceUse", &ThingType::isForceUse);
g_lua.bindClassMemberFunction<ThingType>("isMultiUse", &ThingType::isMultiUse);
g_lua.bindClassMemberFunction<ThingType>("isWritable", &ThingType::isWritable);
g_lua.bindClassMemberFunction<ThingType>("isChargeable", &ThingType::isChargeable);
g_lua.bindClassMemberFunction<ThingType>("isWritableOnce", &ThingType::isWritableOnce);
g_lua.bindClassMemberFunction<ThingType>("isFluidContainer", &ThingType::isFluidContainer);
g_lua.bindClassMemberFunction<ThingType>("isSplash", &ThingType::isSplash);
g_lua.bindClassMemberFunction<ThingType>("isNotWalkable", &ThingType::isNotWalkable);
g_lua.bindClassMemberFunction<ThingType>("isNotMoveable", &ThingType::isNotMoveable);
g_lua.bindClassMemberFunction<ThingType>("blockProjectile", &ThingType::blockProjectile);
g_lua.bindClassMemberFunction<ThingType>("isNotPathable", &ThingType::isNotPathable);
g_lua.bindClassMemberFunction<ThingType>("setPathable", &ThingType::setPathable);
g_lua.bindClassMemberFunction<ThingType>("isPickupable", &ThingType::isPickupable);
g_lua.bindClassMemberFunction<ThingType>("isHangable", &ThingType::isHangable);
g_lua.bindClassMemberFunction<ThingType>("isHookSouth", &ThingType::isHookSouth);
g_lua.bindClassMemberFunction<ThingType>("isHookEast", &ThingType::isHookEast);
g_lua.bindClassMemberFunction<ThingType>("isRotateable", &ThingType::isRotateable);
g_lua.bindClassMemberFunction<ThingType>("hasLight", &ThingType::hasLight);
g_lua.bindClassMemberFunction<ThingType>("isDontHide", &ThingType::isDontHide);
g_lua.bindClassMemberFunction<ThingType>("isTranslucent", &ThingType::isTranslucent);
g_lua.bindClassMemberFunction<ThingType>("hasDisplacement", &ThingType::hasDisplacement);
g_lua.bindClassMemberFunction<ThingType>("hasElevation", &ThingType::hasElevation);
g_lua.bindClassMemberFunction<ThingType>("isLyingCorpse", &ThingType::isLyingCorpse);
g_lua.bindClassMemberFunction<ThingType>("isAnimateAlways", &ThingType::isAnimateAlways);
g_lua.bindClassMemberFunction<ThingType>("hasMiniMapColor", &ThingType::hasMiniMapColor);
g_lua.bindClassMemberFunction<ThingType>("hasLensHelp", &ThingType::hasLensHelp);
g_lua.bindClassMemberFunction<ThingType>("isFullGround", &ThingType::isFullGround);
g_lua.bindClassMemberFunction<ThingType>("isIgnoreLook", &ThingType::isIgnoreLook);
g_lua.bindClassMemberFunction<ThingType>("isCloth", &ThingType::isCloth);
g_lua.bindClassMemberFunction<ThingType>("isMarketable", &ThingType::isMarketable);
g_lua.bindClassMemberFunction<ThingType>("getMarketData", &ThingType::getMarketData);
g_lua.bindClassMemberFunction<ThingType>("isUsable", &ThingType::isUsable);
g_lua.bindClassMemberFunction<ThingType>("isWrapable", &ThingType::isWrapable);
g_lua.bindClassMemberFunction<ThingType>("isUnwrapable", &ThingType::isUnwrapable);
g_lua.bindClassMemberFunction<ThingType>("isTopEffect", &ThingType::isTopEffect);
g_lua.bindClassMemberFunction<ThingType>("getSprites", &ThingType::getSprites);
g_lua.bindClassMemberFunction<ThingType>("hasAttribute", &ThingType::hasAttr);
g_lua.bindClassMemberFunction<ThingType>("exportImage", &ThingType::exportImage);
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>("getContainerItems", &Item::getContainerItems);
g_lua.bindClassMemberFunction<Item>("getContainerItem", &Item::getContainerItem);
g_lua.bindClassMemberFunction<Item>("addContainerItem", &Item::addContainerItem);
g_lua.bindClassMemberFunction<Item>("addContainerItemIndexed", &Item::addContainerItemIndexed);
g_lua.bindClassMemberFunction<Item>("removeContainerItem", &Item::removeContainerItem);
g_lua.bindClassMemberFunction<Item>("clearContainerItems", &Item::clearContainerItems);
g_lua.bindClassMemberFunction<Item>("getContainerItem", &Item::getContainerItem);
g_lua.bindClassMemberFunction<Item>("setCount", &Item::setCount);
g_lua.bindClassMemberFunction<Item>("getCount", &Item::getCount);
g_lua.bindClassMemberFunction<Item>("getSubType", &Item::getSubType);
g_lua.bindClassMemberFunction<Item>("getCountOrSubType", &Item::getCountOrSubType);
g_lua.bindClassMemberFunction<Item>("getId", &Item::getId);
g_lua.bindClassMemberFunction<Item>("getServerId", &Item::getServerId);
g_lua.bindClassMemberFunction<Item>("getName", &Item::getName);
g_lua.bindClassMemberFunction<Item>("getDescription", &Item::getDescription);
g_lua.bindClassMemberFunction<Item>("getText", &Item::getText);
g_lua.bindClassMemberFunction<Item>("setDescription", &Item::setDescription);
g_lua.bindClassMemberFunction<Item>("setText", &Item::setText);
g_lua.bindClassMemberFunction<Item>("getUniqueId", &Item::getUniqueId);
g_lua.bindClassMemberFunction<Item>("getActionId", &Item::getActionId);
g_lua.bindClassMemberFunction<Item>("setUniqueId", &Item::setUniqueId);
g_lua.bindClassMemberFunction<Item>("setActionId", &Item::setActionId);
g_lua.bindClassMemberFunction<Item>("getTeleportDestination", &Item::getTeleportDestination);
g_lua.bindClassMemberFunction<Item>("setTeleportDestination", &Item::setTeleportDestination);
g_lua.bindClassMemberFunction<Item>("isStackable", &Item::isStackable);
g_lua.bindClassMemberFunction<Item>("isMarketable", &Item::isMarketable);
g_lua.bindClassMemberFunction<Item>("isFluidContainer", &Item::isFluidContainer);
g_lua.bindClassMemberFunction<Item>("getMarketData", &Item::getMarketData);
g_lua.bindClassMemberFunction<Item>("getClothSlot", &Item::getClothSlot);
g_lua.bindClassMemberFunction<Item>("getTooltip", &Item::getTooltip);
g_lua.bindClassMemberFunction<Item>("setTooltip", &Item::setTooltip);
g_lua.registerClass<Effect, Thing>();
g_lua.bindClassStaticFunction<Effect>("create", []{ return EffectPtr(new Effect); });
g_lua.bindClassMemberFunction<Effect>("setId", &Effect::setId);
g_lua.registerClass<Missile, Thing>();
g_lua.bindClassStaticFunction<Missile>("create", []{ return MissilePtr(new Missile); });
g_lua.bindClassMemberFunction<Missile>("setId", &Missile::setId);
g_lua.bindClassMemberFunction<Missile>("getId", &Missile::getId);
g_lua.bindClassMemberFunction<Missile>("getSource", &Missile::getSource);
g_lua.bindClassMemberFunction<Missile>("getDestination", &Missile::getDestination);
g_lua.registerClass<StaticText, Thing>();
g_lua.bindClassStaticFunction<StaticText>("create", []{ return StaticTextPtr(new StaticText); });
g_lua.bindClassMemberFunction<StaticText>("addMessage", &StaticText::addMessage);
g_lua.bindClassMemberFunction<StaticText>("addColoredMessage", &StaticText::addColoredMessage);
g_lua.bindClassMemberFunction<StaticText>("setText", &StaticText::setText);
g_lua.bindClassMemberFunction<StaticText>("setFont", &StaticText::setFont);
g_lua.bindClassMemberFunction<StaticText>("setColor", &StaticText::setColor);
g_lua.bindClassMemberFunction<StaticText>("getColor", &StaticText::getColor);
g_lua.bindClassMemberFunction<StaticText>("getText", &StaticText::getText);
g_lua.registerClass<AnimatedText, Thing>();
g_lua.bindClassMemberFunction<AnimatedText>("getText", &AnimatedText::getText);
g_lua.bindClassMemberFunction<AnimatedText>("getOffset", &AnimatedText::getOffset);
g_lua.bindClassMemberFunction<AnimatedText>("getColor", &AnimatedText::getColor);
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>("isWalkLocked", &LocalPlayer::isWalkLocked);
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>("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>("getBlessings", &LocalPlayer::getBlessings);
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>("isServerWalking", &LocalPlayer::isServerWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("stopAutoWalk", &LocalPlayer::stopAutoWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("autoWalk", &LocalPlayer::autoWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("preWalk", &LocalPlayer::preWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("dumpWalkMatrix", &LocalPlayer::dumpWalkMatrix);
g_lua.bindClassMemberFunction<LocalPlayer>("startServerWalking", &LocalPlayer::startServerWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("finishServerWalking", &LocalPlayer::finishServerWalking);
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>("getThings", &Tile::getThings);
g_lua.bindClassMemberFunction<Tile>("getEffect", &Tile::getEffect);
g_lua.bindClassMemberFunction<Tile>("getEffects", &Tile::getEffects);
g_lua.bindClassMemberFunction<Tile>("getItems", &Tile::getItems);
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>("getTopLookThingEx", &Tile::getTopLookThingEx);
g_lua.bindClassMemberFunction<Tile>("getTopUseThing", &Tile::getTopUseThing);
g_lua.bindClassMemberFunction<Tile>("getTopCreature", &Tile::getTopCreature);
g_lua.bindClassMemberFunction<Tile>("getTopCreatureEx", &Tile::getTopCreatureEx);
g_lua.bindClassMemberFunction<Tile>("getTopMoveThing", &Tile::getTopMoveThing);
g_lua.bindClassMemberFunction<Tile>("getTopMultiUseThing", &Tile::getTopMultiUseThing);
g_lua.bindClassMemberFunction<Tile>("getTopMultiUseThingEx", &Tile::getTopMultiUseThingEx);
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>("isHouseTile", &Tile::isHouseTile);
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>("hasBlockingCreature", &Tile::hasBlockingCreature);
g_lua.bindClassMemberFunction<Tile>("isEmpty", &Tile::isEmpty);
g_lua.bindClassMemberFunction<Tile>("isClickable", &Tile::isClickable);
g_lua.bindClassMemberFunction<Tile>("isPathable", &Tile::isPathable);
g_lua.bindClassMemberFunction<Tile>("overwriteMinimapColor", &Tile::overwriteMinimapColor);
g_lua.bindClassMemberFunction<Tile>("select", &Tile::select);
g_lua.bindClassMemberFunction<Tile>("unselect", &Tile::unselect);
g_lua.bindClassMemberFunction<Tile>("isSelected", &Tile::isSelected);
g_lua.bindClassMemberFunction<Tile>("remFlag", &Tile::remFlag);
g_lua.bindClassMemberFunction<Tile>("setFlag", &Tile::setFlag);
g_lua.bindClassMemberFunction<Tile>("setFlags", &Tile::setFlags);
g_lua.bindClassMemberFunction<Tile>("getFlags", &Tile::getFlags);
g_lua.bindClassMemberFunction<Tile>("hasFlag", &Tile::hasFlag);
g_lua.bindClassMemberFunction<Tile>("getElevation", &Tile::getElevation);
g_lua.bindClassMemberFunction<Tile>("hasElevation", &Tile::hasElevation);
g_lua.bindClassMemberFunction<Tile>("isBlocking", &Tile::isBlocking);
// for bot
g_lua.bindClassMemberFunction<Tile>("setText", &Tile::setText);
g_lua.bindClassMemberFunction<Tile>("getText", &Tile::getText);
g_lua.bindClassMemberFunction<Tile>("setTimer", &Tile::setTimer);
g_lua.bindClassMemberFunction<Tile>("getTimer", &Tile::getTimer);
g_lua.bindClassMemberFunction<Tile>("setFill", &Tile::setFill);
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>("setItemVisible", &UIItem::setItemVisible);
g_lua.bindClassMemberFunction<UIItem>("setItem", &UIItem::setItem);
g_lua.bindClassMemberFunction<UIItem>("setVirtual", &UIItem::setVirtual);
g_lua.bindClassMemberFunction<UIItem>("setShowCount", &UIItem::setShowCount);
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>("getItemCountOrSubType", &UIItem::getItemCountOrSubType);
g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem);
g_lua.bindClassMemberFunction<UIItem>("isVirtual", &UIItem::isVirtual);
g_lua.bindClassMemberFunction<UIItem>("isItemVisible", &UIItem::isItemVisible);
g_lua.registerClass<UISprite, UIWidget>();
g_lua.bindClassStaticFunction<UISprite>("create", []{ return UISpritePtr(new UISprite); });
g_lua.bindClassMemberFunction<UISprite>("setSpriteId", &UISprite::setSpriteId);
g_lua.bindClassMemberFunction<UISprite>("clearSprite", &UISprite::clearSprite);
g_lua.bindClassMemberFunction<UISprite>("getSpriteId", &UISprite::getSpriteId);
g_lua.bindClassMemberFunction<UISprite>("setSpriteColor", &UISprite::setSpriteColor);
g_lua.bindClassMemberFunction<UISprite>("hasSprite", &UISprite::hasSprite);
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.bindClassMemberFunction<UICreature>("setAutoRotating", &UICreature::setAutoRotating);
g_lua.bindClassMemberFunction<UICreature>("setDirection", &UICreature::setDirection);
g_lua.bindClassMemberFunction<UICreature>("setScale", &UICreature::setScale);
g_lua.bindClassMemberFunction<UICreature>("getScale", &UICreature::getScale);
g_lua.bindClassMemberFunction<UICreature>("setOptimized", &UICreature::setOptimized);
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>("movePixels", &UIMap::movePixels);
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>("lockVisibleFloor", &UIMap::lockVisibleFloor);
g_lua.bindClassMemberFunction<UIMap>("unlockVisibleFloor", &UIMap::unlockVisibleFloor);
g_lua.bindClassMemberFunction<UIMap>("setVisibleDimension", &UIMap::setVisibleDimension);
g_lua.bindClassMemberFunction<UIMap>("setDrawFlags", &UIMap::setDrawFlags);
g_lua.bindClassMemberFunction<UIMap>("setDrawTexts", &UIMap::setDrawTexts);
g_lua.bindClassMemberFunction<UIMap>("setDrawNames", &UIMap::setDrawNames);
g_lua.bindClassMemberFunction<UIMap>("setDrawHealthBars", &UIMap::setDrawHealthBars);
g_lua.bindClassMemberFunction<UIMap>("setDrawHealthBarsOnTop", &UIMap::setDrawHealthBarsOnTop);
g_lua.bindClassMemberFunction<UIMap>("setDrawLights", &UIMap::setDrawLights);
g_lua.bindClassMemberFunction<UIMap>("setDrawManaBar", &UIMap::setDrawManaBar);
g_lua.bindClassMemberFunction<UIMap>("setDrawPlayerBars", &UIMap::setDrawPlayerBars);
g_lua.bindClassMemberFunction<UIMap>("setAnimated", &UIMap::setAnimated);
g_lua.bindClassMemberFunction<UIMap>("setKeepAspectRatio", &UIMap::setKeepAspectRatio);
g_lua.bindClassMemberFunction<UIMap>("setMinimumAmbientLight", &UIMap::setMinimumAmbientLight);
g_lua.bindClassMemberFunction<UIMap>("setLimitVisibleRange", &UIMap::setLimitVisibleRange);
g_lua.bindClassMemberFunction<UIMap>("setFloorFading", &UIMap::setFloorFading);
g_lua.bindClassMemberFunction<UIMap>("setCrosshair", &UIMap::setCrosshair);
g_lua.bindClassMemberFunction<UIMap>("isMultifloor", &UIMap::isMultifloor);
g_lua.bindClassMemberFunction<UIMap>("isDrawingTexts", &UIMap::isDrawingTexts);
g_lua.bindClassMemberFunction<UIMap>("isDrawingNames", &UIMap::isDrawingNames);
g_lua.bindClassMemberFunction<UIMap>("isDrawingHealthBars", &UIMap::isDrawingHealthBars);
g_lua.bindClassMemberFunction<UIMap>("isDrawingHealthBarsOnTop", &UIMap::isDrawingHealthBarsOnTop);
g_lua.bindClassMemberFunction<UIMap>("isDrawingLights", &UIMap::isDrawingLights);
g_lua.bindClassMemberFunction<UIMap>("isDrawingManaBar", &UIMap::isDrawingManaBar);
g_lua.bindClassMemberFunction<UIMap>("isLimitVisibleRangeEnabled", &UIMap::isLimitVisibleRangeEnabled);
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>("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>("getPositionOffset", &UIMap::getPositionOffset);
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>("getMinimumAmbientLight", &UIMap::getMinimumAmbientLight);
g_lua.registerClass<UIMinimap, UIWidget>();
g_lua.bindClassStaticFunction<UIMinimap>("create", []{ return UIMinimapPtr(new UIMinimap); });
g_lua.bindClassMemberFunction<UIMinimap>("zoomIn", &UIMinimap::zoomIn);
g_lua.bindClassMemberFunction<UIMinimap>("zoomOut", &UIMinimap::zoomOut);
g_lua.bindClassMemberFunction<UIMinimap>("setZoom", &UIMinimap::setZoom);
g_lua.bindClassMemberFunction<UIMinimap>("setMixZoom", &UIMinimap::setMinZoom);
g_lua.bindClassMemberFunction<UIMinimap>("setMaxZoom", &UIMinimap::setMaxZoom);
g_lua.bindClassMemberFunction<UIMinimap>("setCameraPosition", &UIMinimap::setCameraPosition);
g_lua.bindClassMemberFunction<UIMinimap>("floorUp", &UIMinimap::floorUp);
g_lua.bindClassMemberFunction<UIMinimap>("floorDown", &UIMinimap::floorDown);
g_lua.bindClassMemberFunction<UIMinimap>("getTilePoint", &UIMinimap::getTilePoint);
g_lua.bindClassMemberFunction<UIMinimap>("getTilePosition", &UIMinimap::getTilePosition);
g_lua.bindClassMemberFunction<UIMinimap>("getTileRect", &UIMinimap::getTileRect);
g_lua.bindClassMemberFunction<UIMinimap>("getCameraPosition", &UIMinimap::getCameraPosition);
g_lua.bindClassMemberFunction<UIMinimap>("getMinZoom", &UIMinimap::getMinZoom);
g_lua.bindClassMemberFunction<UIMinimap>("getMaxZoom", &UIMinimap::getMaxZoom);
g_lua.bindClassMemberFunction<UIMinimap>("getZoom", &UIMinimap::getZoom);
g_lua.bindClassMemberFunction<UIMinimap>("getScale", &UIMinimap::getScale);
g_lua.bindClassMemberFunction<UIMinimap>("anchorPosition", &UIMinimap::anchorPosition);
g_lua.bindClassMemberFunction<UIMinimap>("fillPosition", &UIMinimap::fillPosition);
g_lua.bindClassMemberFunction<UIMinimap>("centerInPosition", &UIMinimap::centerInPosition);
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);
g_lua.registerClass<UIMapAnchorLayout, UIAnchorLayout>();
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 2010-2017 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_client.h"
#include <framework/luaengine/luainterface.h>
int push_luavalue(const Outfit& outfit)
{
g_lua.createTable(0, 8);
g_lua.pushInteger(outfit.getId());
g_lua.setField("type");
g_lua.pushInteger(outfit.getAuxId());
g_lua.setField("auxType");
if(g_game.getFeature(Otc::GamePlayerAddons)) {
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");
}
if (g_game.getFeature(Otc::GameWingsAndAura)) {
g_lua.pushInteger(outfit.getWings());
g_lua.setField("wings");
g_lua.pushInteger(outfit.getAura());
g_lua.setField("aura");
}
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());
if(g_game.getFeature(Otc::GamePlayerAddons)) {
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());
}
if (g_game.getFeature(Otc::GameWingsAndAura)) {
g_lua.getField("wings", index);
outfit.setMount(g_lua.popInteger());
g_lua.getField("aura", index);
outfit.setMount(g_lua.popInteger());
}
return true;
}
return false;
}
int push_luavalue(const Position& pos)
{
if(pos.isValid()) {
g_lua.createTable(0, 3);
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.createTable(0, 6);
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;
}
int push_luavalue(const StoreCategory& category)
{
g_lua.createTable(0, 5);
g_lua.pushString(category.name);
g_lua.setField("name");
g_lua.pushString(category.description);
g_lua.setField("description");
g_lua.pushInteger(category.state);
g_lua.setField("state");
g_lua.pushString(category.icon);
g_lua.setField("icon");
g_lua.pushString(category.parent);
g_lua.setField("parent");
return 1;
}
bool luavalue_cast(int index, StoreCategory& data)
{
if (g_lua.isTable(index)) {
g_lua.getField("name", index);
data.name = g_lua.popString();
g_lua.getField("description", index);
data.description = g_lua.popString();
g_lua.getField("state", index);
data.state = g_lua.popInteger();
g_lua.getField("icon", index);
data.icon = g_lua.popString();
g_lua.getField("parent", index);
data.parent = g_lua.popString();
return true;
}
return false;
}
int push_luavalue(const StoreOffer& offer)
{
g_lua.createTable(0, 6);
g_lua.pushInteger(offer.id);
g_lua.setField("id");
g_lua.pushString(offer.name);
g_lua.setField("name");
g_lua.pushString(offer.description);
g_lua.setField("description");
g_lua.pushInteger(offer.price);
g_lua.setField("price");
g_lua.pushInteger(offer.state);
g_lua.setField("state");
g_lua.pushString(offer.icon);
g_lua.setField("icon");
return 1;
}
bool luavalue_cast(int index, StoreOffer& data)
{
if (g_lua.isTable(index)) {
g_lua.getField("id", index);
data.id = g_lua.popInteger();
g_lua.getField("name", index);
data.name = g_lua.popString();
g_lua.getField("description", index);
data.description = g_lua.popString();
g_lua.getField("state", index);
data.state = g_lua.popInteger();
g_lua.getField("price", index);
data.price = g_lua.popInteger();
g_lua.getField("icon", index);
data.icon = g_lua.popString();
return true;
}
return false;
}
int push_luavalue(const Imbuement& i)
{
g_lua.createTable(0, 11);
g_lua.pushInteger(i.id);
g_lua.setField("id");
g_lua.pushString(i.name);
g_lua.setField("name");
g_lua.pushString(i.description);
g_lua.setField("description");
g_lua.pushString(i.group);
g_lua.setField("group");
g_lua.pushInteger(i.imageId);
g_lua.setField("imageId");
g_lua.pushInteger(i.duration);
g_lua.setField("duration");
g_lua.pushBoolean(i.premiumOnly);
g_lua.setField("premiumOnly");
g_lua.createTable(i.sources.size(), 0);
for (size_t j = 0; j < i.sources.size(); ++j) {
g_lua.createTable(0, 2);
g_lua.pushObject(i.sources[j].first);
g_lua.setField("item");
g_lua.pushString(i.sources[j].second);
g_lua.setField("description");
g_lua.rawSeti(j + 1);
}
g_lua.setField("sources");
g_lua.pushInteger(i.cost);
g_lua.setField("cost");
g_lua.pushInteger(i.successRate);
g_lua.setField("successRate");
g_lua.pushInteger(i.protectionCost);
g_lua.setField("protectionCost");
return 1;
}
int push_luavalue(const Light& light)
{
g_lua.createTable(0, 2);
g_lua.pushInteger(light.color);
g_lua.setField("color");
g_lua.pushInteger(light.intensity);
g_lua.setField("intensity");
return 1;
}
bool luavalue_cast(int index, Light& light)
{
if(g_lua.isTable(index)) {
g_lua.getField("color", index);
light.color = g_lua.popInteger();
g_lua.getField("intensity", index);
light.intensity = g_lua.popInteger();
return true;
}
return false;
}
int push_luavalue(const UnjustifiedPoints& unjustifiedPoints)
{
g_lua.createTable(0, 7);
g_lua.pushInteger(unjustifiedPoints.killsDay);
g_lua.setField("killsDay");
g_lua.pushInteger(unjustifiedPoints.killsDayRemaining);
g_lua.setField("killsDayRemaining");
g_lua.pushInteger(unjustifiedPoints.killsWeek);
g_lua.setField("killsWeek");
g_lua.pushInteger(unjustifiedPoints.killsWeekRemaining);
g_lua.setField("killsWeekRemaining");
g_lua.pushInteger(unjustifiedPoints.killsMonth);
g_lua.setField("killsMonth");
g_lua.pushInteger(unjustifiedPoints.killsMonthRemaining);
g_lua.setField("killsMonthRemaining");
g_lua.pushInteger(unjustifiedPoints.skullTime);
g_lua.setField("skullTime");
return 1;
}
bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints)
{
if(g_lua.isTable(index)) {
g_lua.getField("killsDay", index);
unjustifiedPoints.killsDay = g_lua.popInteger();
g_lua.getField("killsDayRemaining", index);
unjustifiedPoints.killsDayRemaining = g_lua.popInteger();
g_lua.getField("killsWeek", index);
unjustifiedPoints.killsWeek = g_lua.popInteger();
g_lua.getField("killsWeekRemaining", index);
unjustifiedPoints.killsWeekRemaining = g_lua.popInteger();
g_lua.getField("killsMonth", index);
unjustifiedPoints.killsMonth = g_lua.popInteger();
g_lua.getField("killsMonthRemaining", index);
unjustifiedPoints.killsMonthRemaining = g_lua.popInteger();
g_lua.getField("skullTime", index);
unjustifiedPoints.skullTime = g_lua.popInteger();
return true;
}
return false;
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2010-2017 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_LUAVALUECASTS_H
#define CLIENT_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);
// store category
int push_luavalue(const StoreCategory& category);
bool luavalue_cast(int index, StoreCategory& data);
// store offer
int push_luavalue(const StoreOffer& offer);
bool luavalue_cast(int index, StoreOffer& offer);
// imbuement
int push_luavalue(const Imbuement& offer);
// light
int push_luavalue(const Light& light);
bool luavalue_cast(int index, Light& light);
// unjustified points
int push_luavalue(const UnjustifiedPoints& unjustifiedPoints);
bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints);
#endif

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

@@ -0,0 +1,969 @@
/*
* Copyright (c) 2010-2017 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 "minimap.h"
#include <framework/core/asyncdispatcher.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/application.h>
#include <framework/util/extras.h>
#include <set>
Map g_map;
TilePtr Map::m_nulltile = nullptr;
void Map::init()
{
resetAwareRange();
m_animationFlags |= Animation_Show;
}
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::notificateTileUpdate(const Position& pos, bool updateMinimap)
{
if(!pos.isMapPosition())
return;
for(const MapViewPtr& mapView : m_mapViews)
mapView->onTileUpdate(pos);
if (!updateMinimap)
return;
if (!g_game.getFeature(Otc::GameMinimapLimitedToSingleFloor) || (m_centralPosition.z == pos.z)) {
g_minimap.updateTile(pos, getTile(pos));
}
}
void Map::requestVisibleTilesCacheUpdate() {
for (const MapViewPtr& mapView : m_mapViews)
mapView->requestVisibleTilesCacheUpdate();
}
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);
if(tile)
tile->addThing(thing, stackPos);
} else {
if(thing->isMissile()) {
m_floorMissiles[pos.z].push_back(thing->static_self_cast<Missile>());
} else if(thing->isAnimatedText()) {
// this code will stack animated texts of the same color
AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
AnimatedTextPtr prevAnimatedText;
bool merged = false;
for(auto other : m_animatedTexts) {
if(other->getPosition() == pos) {
prevAnimatedText = other;
if(other->merge(animatedText)) {
merged = true;
break;
}
}
}
if(!merged) {
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->addColoredMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) {
mustAdd = false;
break;
}
}
if(mustAdd)
m_staticTexts.push_back(staticText);
else
return;
}
thing->setPosition(pos);
thing->onAppear();
if (thing->isMissile()) {
g_lua.callGlobalField("g_map", "onMissle", thing);
} else if (thing->isAnimatedText()) {
AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>();
g_lua.callGlobalField("g_map", "onAnimatedText", thing, animatedText->getText());
} else if (thing->isStaticText()) {
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
g_lua.callGlobalField("g_map", "onStaticText", thing, staticText->getText());
}
}
notificateTileUpdate(pos, thing->isItem());
}
void Map::setTileSpeed(const Position& pos, uint16_t speed, uint8_t blocking) {
const TilePtr& tile = getOrCreateTile(pos);
if (tile)
tile->setSpeed(speed, blocking);
}
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;
bool ret = false;
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);
ret = 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);
ret = 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);
ret = true;
}
} else if(const TilePtr& tile = thing->getTile())
ret = tile->removeThing(thing);
notificateTileUpdate(thing->getPosition(), thing->isItem());
return ret;
}
bool Map::removeThingByPos(const Position& pos, int stackPos)
{
if(TilePtr tile = getTile(pos))
return removeThing(tile->getThing(stackPos));
return false;
}
void Map::colorizeThing(const ThingPtr& thing, const Color& color)
{
if(!thing)
return;
if(thing->isItem())
thing->static_self_cast<Item>()->setColor(color);
else if(thing->isCreature()) {
const TilePtr& tile = thing->getTile();
VALIDATE(tile);
const ThingPtr& topThing = tile->getTopThing();
VALIDATE(topThing);
topThing->static_self_cast<Item>()->setColor(color);
}
}
void Map::removeThingColor(const ThingPtr& thing)
{
if(!thing)
return;
if(thing->isItem())
thing->static_self_cast<Item>()->setColor(Color::alpha);
else if(thing->isCreature()) {
const TilePtr& tile = thing->getTile();
VALIDATE(tile);
const ThingPtr& topThing = tile->getTopThing();
VALIDATE(topThing);
topThing->static_self_cast<Item>()->setColor(Color::alpha);
}
}
StaticTextPtr Map::getStaticText(const Position& pos)
{
for(auto staticText : m_staticTexts) {
// try to combine messages
if(staticText->getPosition() == pos)
return staticText;
}
return nullptr;
}
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;
}
const TileList Map::getTiles(int floor/* = -1*/)
{
TileList tiles;
if(floor > Otc::MAX_Z) {
return tiles;
}
else if(floor < 0) {
// Search all floors
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
for(const auto& pair : m_tileBlocks[z]) {
const TileBlock& block = pair.second;
for(const TilePtr& tile : block.getTiles()) {
if(tile != nullptr)
tiles.push_back(tile);
}
}
}
}
else {
for(const auto& pair : m_tileBlocks[floor]) {
const TileBlock& block = pair.second;
for(const TilePtr& tile : block.getTiles()) {
if(tile != nullptr)
tiles.push_back(tile);
}
}
}
return tiles;
}
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);
notificateTileUpdate(pos, false);
}
}
for(auto it = m_staticTexts.begin();it != m_staticTexts.end();) {
const StaticTextPtr& staticText = *it;
if(staticText->getPosition() == pos && staticText->getMessageMode() == Otc::MessageNone)
it = m_staticTexts.erase(it);
else
++it;
}
if (!g_game.getFeature(Otc::GameMinimapLimitedToSingleFloor) || (m_centralPosition.z == pos.z)) {
g_minimap.updateTile(pos, getTile(pos));
}
}
void Map::setShowZone(tileflags_t zone, bool show)
{
if(show)
m_zoneFlags |= (uint32)zone;
else
m_zoneFlags &= ~(uint32)zone;
}
void Map::setShowZones(bool show)
{
if(!show)
m_zoneFlags = 0;
else if(m_zoneFlags == 0)
m_zoneFlags = TILESTATE_HOUSE | TILESTATE_PROTECTIONZONE;
}
void Map::setZoneColor(tileflags_t zone, const Color& color)
{
if((m_zoneFlags & zone) == zone)
m_zoneColors[zone] = color;
}
Color Map::getZoneColor(tileflags_t flag)
{
auto it = m_zoneColors.find(flag);
if(it == m_zoneColors.end())
return Color::alpha;
return it->second;
}
void Map::setForceShowAnimations(bool force)
{
if(force) {
if(!(m_animationFlags & Animation_Force))
m_animationFlags |= Animation_Force;
} else
m_animationFlags &= ~Animation_Force;
}
bool Map::isForcingAnimations()
{
return (m_animationFlags & Animation_Force) == Animation_Force;
}
bool Map::isShowingAnimations()
{
return (m_animationFlags & Animation_Show) == Animation_Show;
}
void Map::setShowAnimations(bool show)
{
if(show) {
if(!(m_animationFlags & Animation_Show))
m_animationFlags |= Animation_Show;
} else
m_animationFlags &= ~Animation_Show;
}
std::map<Position, ItemPtr> Map::findItemsById(uint16 clientId, uint32 max)
{
std::map<Position, ItemPtr> ret;
uint32 count = 0;
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
for(const auto& pair : m_tileBlocks[z]) {
const TileBlock& block = pair.second;
for(const TilePtr& tile : block.getTiles()) {
if(unlikely(!tile || tile->isEmpty()))
continue;
for(const ItemPtr& item : tile->getItems()) {
if(item->getId() == clientId) {
ret.insert(std::make_pair(tile->getPosition(), item));
if(++count >= max)
break;
}
}
}
}
}
return ret;
}
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::removeUnawareThings()
{
// remove creatures from tiles that we are not aware of anymore
for(const auto& pair : m_knownCreatures) {
const CreaturePtr& creature = pair.second;
if(!isAwareOfPosition(creature->getPosition()))
removeThing(creature);
}
// remove static texts from tiles that we are not aware anymore
for(auto it = m_staticTexts.begin(); it != m_staticTexts.end();) {
const StaticTextPtr& staticText = *it;
if(staticText->getMessageMode() == Otc::MessageNone && !isAwareOfPosition(staticText->getPosition()))
it = m_staticTexts.erase(it);
else
++it;
}
bool extended = g_game.getFeature(Otc::GameBiggerMapCache);
if(!g_game.getFeature(Otc::GameKeepUnawareTiles)) {
// remove tiles that we are not aware anymore
for(int z = 0; z <= Otc::MAX_Z; ++z) {
auto& tileBlocks = m_tileBlocks[z];
for(auto it = tileBlocks.begin(); it != tileBlocks.end();) {
TileBlock& block = (*it).second;
bool blockEmpty = true;
for(const TilePtr& tile : block.getTiles()) {
if(!tile)
continue;
const Position& pos = tile->getPosition();
if(!isAwareOfPositionForClean(pos, extended))
block.remove(pos);
else
blockEmpty = false;
}
if(blockEmpty)
it = tileBlocks.erase(it);
else
++it;
}
}
}
}
void Map::setCentralPosition(const Position& centralPosition)
{
if(m_centralPosition == centralPosition)
return;
m_centralPosition = centralPosition;
removeUnawareThings();
// 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::getSightSpectators(const Position& centerPos, bool multiFloor)
{
return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left - 1, m_awareRange.right - 2, m_awareRange.top - 1, m_awareRange.bottom - 2);
}
std::vector<CreaturePtr> Map::getSpectators(const Position& centerPos, bool multiFloor)
{
return getSpectatorsInRangeEx(centerPos, multiFloor, m_awareRange.left, m_awareRange.right, m_awareRange.top, m_awareRange.bottom);
}
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, bool extended)
{
if ((pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor()) && !extended)
return false;
Position groundedPos = pos;
while (groundedPos.z != m_centralPosition.z) {
if (groundedPos.z > m_centralPosition.z) {
if (groundedPos.x == 65535 || groundedPos.y == 65535) // When pos == 65535,65535,15 we cant go up to 65536,65536,14
break;
groundedPos.coveredUp();
} else {
if (groundedPos.x == 0 || groundedPos.y == 0) // When pos == 0,0,0 we cant go down to -1,-1,1
break;
groundedPos.coveredDown();
}
}
if (extended) {
return m_centralPosition.isInRange(groundedPos, m_awareRange.left * 2,
m_awareRange.right * 2,
m_awareRange.top * 2,
m_awareRange.bottom * 2);
}
return m_centralPosition.isInRange(groundedPos, m_awareRange.left,
m_awareRange.right,
m_awareRange.top,
m_awareRange.bottom);
}
bool Map::isAwareOfPositionForClean(const Position& pos, bool extended)
{
if ((pos.z < getFirstAwareFloor() || pos.z > getLastAwareFloor()) && !extended)
return false;
Position groundedPos = pos;
while (groundedPos.z != m_centralPosition.z) {
if (groundedPos.z > m_centralPosition.z) {
if (groundedPos.x == 65535 || groundedPos.y == 65535) // When pos == 65535,65535,15 we cant go up to 65536,65536,14
break;
groundedPos.coveredUp();
} else {
if (groundedPos.x == 0 || groundedPos.y == 0) // When pos == 0,0,0 we cant go down to -1,-1,1
break;
groundedPos.coveredDown();
}
}
if (extended) {
return m_centralPosition.isInRange(groundedPos, m_awareRange.left * 4,
m_awareRange.right * 4,
m_awareRange.top * 4,
m_awareRange.bottom * 4);
}
return m_centralPosition.isInRange(groundedPos, m_awareRange.left + 1,
m_awareRange.right + 1,
m_awareRange.top + 1,
m_awareRange.bottom + 1);
}
void Map::setAwareRange(const AwareRange& range)
{
m_awareRange = range;
removeUnawareThings();
}
void Map::resetAwareRange()
{
AwareRange range;
range.left = 8;
range.top = 6;
range.bottom = 7;
range.right = 9;
setAwareRange(range);
}
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<int>(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 maxComplexity, int flags)
{
// pathfinding using A* search algorithm (otclientv8 note: it's dijkstra algorithm)
// as described in http://en.wikipedia.org/wiki/A*_search_algorithm
struct SNode {
SNode(const Position& pos) : cost(0), totalCost(0), pos(pos), prev(nullptr), dir(Otc::InvalidDirection) { }
float cost;
float totalCost;
Position pos;
SNode *prev;
Otc::Direction dir;
};
struct LessNode {
bool operator()(std::pair<SNode*, float> a, std::pair<SNode*, float> b) const {
return b.second < a.second;
}
};
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;
}
// check the goal pos is walkable
if(g_map.isAwareOfPosition(goalPos)) {
const TilePtr goalTile = getTile(goalPos);
if(!goalTile || (!goalTile->isWalkable(flags & Otc::PathFindIgnoreCreatures))) {
return ret;
}
}
else {
const MinimapTile& goalTile = g_minimap.getTile(goalPos);
if(goalTile.hasFlag(MinimapTileNotWalkable)) {
return ret;
}
}
std::unordered_map<Position, SNode*, PositionHasher> nodes;
std::priority_queue<std::pair<SNode*, float>, std::vector<std::pair<SNode*, float>>, LessNode> searchList;
// hidden code
for(auto it : nodes)
delete it.second;
return ret;
}
PathFindResult_ptr Map::newFindPath(const Position& start, const Position& goal, std::shared_ptr<std::list<Node*>> visibleNodes) {
auto ret = std::make_shared<PathFindResult>();
ret->start = start;
ret->destination = goal;
if (start == goal) {
ret->status = Otc::PathFindResultSamePosition;
return ret;
}
if (goal.z != start.z) {
return ret;
}
struct LessNode {
bool operator()(Node* a, Node* b) const {
return b->totalCost < a->totalCost;
}
};
std::unordered_map<Position, Node*, PositionHasher> nodes;
std::priority_queue<Node*, std::vector<Node*>, LessNode> searchList;
if (visibleNodes) {
for (auto& node : *visibleNodes)
nodes.emplace(node->pos, node);
}
Node* initNode = new Node{ 1, 0, start, nullptr, 0, 0 };
nodes[start] = initNode;
searchList.push(initNode);
int limit = 50000;
float distance = start.distance(goal);
// hidden code
return ret;
}
void Map::findPathAsync(const Position& start, const Position& goal, std::function<void(PathFindResult_ptr)> callback) {
}
std::map<std::string, std::tuple<int, int, int, std::string>> Map::findEveryPath(const Position& start, int maxDistance, const std::map<std::string, std::string>& params)
{
// using Dijkstra's algorithm
struct LessNode {
bool operator()(Node* a, Node* b) const
{
return b->totalCost < a->totalCost;
}
};
if (g_extras.debugPathfinding) {
g_logger.info(stdext::format("findEveryPath: %i %i %i - %i", start.x, start.y, start.z, maxDistance));
for (auto& param : params) {
g_logger.info(stdext::format("%s - %s", param.first, param.second));
}
}
std::map<std::string, std::string>::const_iterator it;
it = params.find("ignoreLastCreature");
bool ignoreLastCreature = it != params.end() && it->second != "0" && it->second != "";
it = params.find("ignoreCreatures");
bool ignoreCreatures = it != params.end() && it->second != "0" && it->second != "";
it = params.find("ignoreNonPathable");
bool ignoreNonPathable = it != params.end() && it->second != "0" && it->second != "";
it = params.find("ignoreNonWalkable");
bool ignoreNonWalkable = it != params.end() && it->second != "0" && it->second != "";
it = params.find("ignoreStairs");
bool ignoreStairs = it != params.end() && it->second != "0" && it->second != "";
it = params.find("ignoreCost");
bool ignoreCost = it != params.end() && it->second != "0" && it->second != "";
it = params.find("allowUnseen");
bool allowUnseen = it != params.end() && it->second != "0" && it->second != "";
it = params.find("allowOnlyVisibleTiles");
bool allowOnlyVisibleTiles = it != params.end() && it->second != "0" && it->second != "";
it = params.find("marginMin");
bool hasMargin = it != params.end();
it = params.find("marginMax");
hasMargin = hasMargin || (it != params.end());
Position destPos;
it = params.find("destination");
if (it != params.end()) {
std::vector<int32> pos = stdext::split<int32>(it->second, ",");
if (pos.size() == 3) {
destPos = Position(pos[0], pos[1], pos[2]);
}
}
std::map<std::string, std::tuple<int, int, int, std::string>> ret;
std::unordered_map<Position, Node*, PositionHasher> nodes;
std::priority_queue<Node*, std::vector<Node*>, LessNode> searchList;
Node* initNode = new Node{ 1, 0, start, nullptr, 0, 0 };
nodes[start] = initNode;
searchList.push(initNode);
// hidden code
for (auto& node : nodes) {
if (node.second)
delete node.second;
}
return ret;
}
int Map::getMinimapColor(const Position& pos)
{
int color = 0;
if (const TilePtr& tile = getTile(pos)) {
color = tile->getMinimapColorByte();
}
if (color == 0) {
const MinimapTile& mtile = g_minimap.getTile(pos);
color = mtile.color;
}
return color;
}
bool Map::isPatchable(const Position& pos)
{
if (const TilePtr& tile = getTile(pos)) {
return tile->isPathable();
}
const MinimapTile& mtile = g_minimap.getTile(pos);
return !mtile.hasFlag(MinimapTileNotPathable);
}
bool Map::isWalkable(const Position& pos, bool ignoreCreatures)
{
if (const TilePtr& tile = getTile(pos)) {
return tile->isWalkable(ignoreCreatures);
}
const MinimapTile& mtile = g_minimap.getTile(pos);
return !mtile.hasFlag(MinimapTileNotPathable);
}

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

@@ -0,0 +1,304 @@
/*
* Copyright (c) 2010-2017 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
};
enum : uint8 {
Animation_Force,
Animation_Show
};
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;
};
struct AwareRange
{
int top;
int right;
int bottom;
int left;
int horizontal() { return left + right + 1; }
int vertical() { return top + bottom + 1; }
};
struct PathFindResult
{
Otc::PathFindResult status = Otc::PathFindResultNoWay;
std::vector<Otc::Direction> path;
int complexity = 0;
Position start;
Position destination;
};
using PathFindResult_ptr = std::shared_ptr<PathFindResult>;
struct Node {
float cost;
float totalCost;
Position pos;
Node *prev;
int distance;
int unseen;
};
//@bindsingleton g_map
class Map
{
public:
void init();
void terminate();
void addMapView(const MapViewPtr& mapView);
void removeMapView(const MapViewPtr& mapView);
void notificateTileUpdate(const Position& pos, bool updateMinimap = false);
void requestVisibleTilesCacheUpdate();
bool loadOtcm(const std::string& fileName);
void saveOtcm(const std::string& fileName);
void loadOtbm(const std::string& fileName);
void saveOtbm(const std::string& fileName);
// 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 clearDescriptions() { m_attribs.remove(OTBM_ATTR_DESCRIPTION); }
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);
void setTileSpeed(const Position & pos, uint16_t speed, uint8_t blocking);
ThingPtr getThing(const Position& pos, int stackPos);
bool removeThing(const ThingPtr& thing);
bool removeThingByPos(const Position& pos, int stackPos);
void colorizeThing(const ThingPtr& thing, const Color& color);
void removeThingColor(const ThingPtr& thing);
StaticTextPtr getStaticText(const Position& pos);
// 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);
const TileList getTiles(int floor = -1);
void cleanTile(const Position& pos);
// tile zone related
void setShowZone(tileflags_t zone, bool show);
void setShowZones(bool show);
void setZoneColor(tileflags_t flag, const Color& color);
void setZoneOpacity(float opacity) { m_zoneOpacity = opacity; }
float getZoneOpacity() { return m_zoneOpacity; }
Color getZoneColor(tileflags_t flag);
tileflags_t getZoneFlags() { return (tileflags_t)m_zoneFlags; }
bool showZones() { return m_zoneFlags != 0; }
bool showZone(tileflags_t zone) { return (m_zoneFlags & zone) == zone; }
void setForceShowAnimations(bool force);
bool isForcingAnimations();
bool isShowingAnimations();
void setShowAnimations(bool show);
std::map<Position, ItemPtr> findItemsById(uint16 clientId, uint32 max);
// known creature related
void addCreature(const CreaturePtr& creature);
CreaturePtr getCreatureById(uint32 id);
void removeCreatureById(uint32 id);
std::vector<CreaturePtr> getSightSpectators(const Position& centerPos, bool multiFloor);
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, bool extended = false);
bool isAwareOfPositionForClean(const Position& pos, bool extended = false);
void setAwareRange(const AwareRange& range);
void resetAwareRange();
AwareRange getAwareRange() { return m_awareRange; }
Size getAwareRangeAsSize() { return Size(m_awareRange.horizontal(), m_awareRange.vertical()); }
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 maxComplexity, int flags = 0);
PathFindResult_ptr newFindPath(const Position& start, const Position& goal, std::shared_ptr<std::list<Node*>> visibleNodes);
void findPathAsync(const Position & start, const Position & goal, std::function<void(PathFindResult_ptr)> callback);
// tuple = <cost, distance, prevPos>
std::map<std::string, std::tuple<int, int, int, std::string>> findEveryPath(const Position& start, int maxDistance, const std::map<std::string, std::string>& params);
int getMinimapColor(const Position& pos);
bool isPatchable(const Position& pos);
bool isWalkable(const Position& pos, bool ignoreCreatures);
private:
void removeUnawareThings();
uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); }
std::map<uint, TileBlock> m_tileBlocks[Otc::MAX_Z+1];
std::map<uint32, CreaturePtr> m_knownCreatures;
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
std::vector<AnimatedTextPtr> m_animatedTexts;
std::vector<StaticTextPtr> m_staticTexts;
std::vector<MapViewPtr> m_mapViews;
std::unordered_map<Position, std::string, PositionHasher> m_waypoints;
uint8 m_animationFlags;
uint32 m_zoneFlags;
std::map<uint32, Color> m_zoneColors;
float m_zoneOpacity;
Light m_light;
Position m_centralPosition;
Rect m_tilesRect;
stdext::packed_storage<uint8> m_attribs;
AwareRange m_awareRange;
static TilePtr m_nulltile;
};
extern Map g_map;
#endif

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

@@ -0,0 +1,538 @@
/*
* Copyright (c) 2010-2017 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)
{
try {
if(!g_things.isOtbLoaded())
stdext::throw_exception("OTB isn't loaded yet to load a map.");
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName));
char identifier[4];
if(fin->read(identifier, 1, 4) < 4)
stdext::throw_exception("Could not read file identifier");
if(memcmp(identifier, "OTBM", 4) != 0 && memcmp(identifier, "\0\0\0\0", 4) != 0)
stdext::throw_exception(stdext::format("Invalid file identifier detected: %s", identifier));
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;
basePos.x = nodeMapData->getU16();
basePos.y = nodeMapData->getU16();
basePos.z = nodeMapData->getU8();
for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) {
uint8 type = nodeTile->getU8();
if(unlikely(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(unlikely(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("Moveable 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->setFlag(TILESTATE_HOUSE);
tile->setFlag(flags);
}
}
} 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;
townCoords.x = nodeTown->getU16();
townCoords.y = nodeTown->getU16();
townCoords.z = nodeTown->getU8();
if(!(town = g_towns.getTown(townId)))
g_towns.addTown(TownPtr(new Town(townId, townName, townCoords)));
}
g_towns.sort();
} 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;
waypointPos.x = nodeWaypoint->getU16();
waypointPos.y = nodeWaypoint->getU16();
waypointPos.z = nodeWaypoint->getU8();
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();
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to load '%s': %s", fileName, e.what()));
}
}
void Map::saveOtbm(const std::string& fileName)
{
try {
FileStreamPtr fin = g_resources.createFile(fileName);
if(!fin)
stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
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);
{
root->addU8(OTBM_ATTR_DESCRIPTION);
root->addString(m_attribs.get<std::string>(OTBM_ATTR_DESCRIPTION));
root->addU8(OTBM_ATTR_SPAWN_FILE);
root->addString(spawnFile);
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(unlikely(!tile || tile->isEmpty()))
continue;
const Position& pos = tile->getPosition();
if(unlikely(!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(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->startNode(OTBM_TOWN);
root->addU32(town->getId());
root->addString(town->getName());
Position townPos = town->getPos();
root->addPos(townPos.x, townPos.y, townPos.z);
root->endNode();
}
root->endNode();
if(version > 1) {
root->startNode(OTBM_WAYPOINTS);
for(const auto& it : m_waypoints) {
root->startNode(OTBM_WAYPOINT);
root->addString(it.second);
Position pos = it.first;
root->addPos(pos.x, pos.y, pos.z);
root->endNode();
}
root->endNode();
}
}
root->endNode(); // OTBM_MAP_DATA
}
root->endNode();
fin->flush();
fin->close();
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
}
}
bool Map::loadOtcm(const std::string& fileName)
{
try {
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception("unable to open file");
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++);
}
g_map.notificateTileUpdate(pos);
}
fin->close();
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);
//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.getClientVersion());
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();
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to save OTCM map: %s", e.what()));
}
}
/* vim: set ts=4 sw=4 et: */

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

@@ -0,0 +1,537 @@
/*
* Copyright (c) 2010-2017 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 "localplayer.h"
#include "game.h"
#include "spritemanager.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>
#include <framework/graphics/texturemanager.h>
#include <framework/graphics/atlas.h>
#include <framework/util/extras.h>
#include <framework/core/adaptiverenderer.h>
MapView::MapView()
{
m_lockedFirstVisibleFloor = -1;
m_cachedFirstVisibleFloor = 7;
m_cachedLastVisibleFloor = 7;
m_fadeOutTime = 0;
m_fadeInTime = 0;
m_minimumAmbientLight = 0;
m_optimizedSize = Size(g_map.getAwareRange().horizontal(), g_map.getAwareRange().vertical()) * g_sprites.spriteSize();
setVisibleDimension(Size(15, 11));
}
MapView::~MapView()
{
#ifndef NDEBUG
VALIDATE(!g_app.isTerminated());
#endif
}
void MapView::drawTileTexts(const Rect& rect, const Rect& srcRect)
{
Position cameraPosition = getCameraPosition();
Point drawOffset = srcRect.topLeft();
float horizontalStretchFactor = rect.width() / (float)srcRect.width();
float verticalStretchFactor = rect.height() / (float)srcRect.height();
auto player = g_game.getLocalPlayer();
for (auto& tile : m_cachedVisibleTiles) {
Position tilePos = tile.first->getPosition();
if (tilePos.z != player->getPosition().z) continue;
Point p = transformPositionTo2D(tilePos, cameraPosition) - drawOffset;
p.x *= horizontalStretchFactor;
p.y *= verticalStretchFactor;
p += rect.topLeft();
p.y += 5;
tile.first->drawTexts(p);
}
}
void MapView::drawBackground(const Rect& rect, const TilePtr& crosshairTile) {
Position cameraPosition = getCameraPosition();
if (m_mustUpdateVisibleTilesCache) {
updateVisibleTilesCache();
}
if (g_game.getFeature(Otc::GameForceLight)) {
m_drawLight = true;
m_minimumAmbientLight = 0.05f;
}
Rect srcRect = calcFramebufferSource(rect.size());
g_drawQueue->setFrameBuffer(rect, m_optimizedSize, srcRect);
if (m_drawLight) {
Light ambientLight;
if (cameraPosition.z <= Otc::SEA_FLOOR)
ambientLight = g_map.getLight();
if (!m_lightTexture || m_lightTexture->getSize() != m_drawDimension)
m_lightTexture = TexturePtr(new Texture(m_drawDimension, false, true));
m_lightView = std::make_unique<LightView>(m_lightTexture, m_drawDimension, rect, srcRect, ambientLight.color,
std::max<int>(m_minimumAmbientLight * 255, ambientLight.intensity));
}
auto itm = m_cachedVisibleTiles.begin();
auto end = m_cachedVisibleTiles.end();
for (int z = m_cachedLastVisibleFloor; z >= m_cachedFirstFadingFloor; --z) {
float fading = 1.0;
if (m_floorFading > 0) {
fading = 0.;
if (m_floorFading > 0) {
fading = stdext::clamp<float>((float)m_fadingFloorTimers[z].elapsed_millis() / (float)m_floorFading, 0.f, 1.f);
if (z < m_cachedFirstVisibleFloor)
fading = 1.0 - fading;
}
if (fading == 0) break;
}
size_t floorStart = g_drawQueue->size();
size_t lightFloorStart = m_lightView ? m_lightView->size() : 0;
for (; itm != end; ++itm) {
Position tilePos = itm->first->getPosition();
if (tilePos.z != z)
break;
Point tileDrawPos = transformPositionTo2D(tilePos, cameraPosition);
if (m_lightView) {
ItemPtr ground = itm->first->getGround();
if (ground && ground->isGround() && !ground->isTranslucent()) {
m_lightView->setFieldBrightness(tileDrawPos, lightFloorStart, 0);
}
}
itm->first->drawBottom(tileDrawPos, m_lightView.get());
if (m_crosshair && itm->first == crosshairTile)
{
g_drawQueue->addTexturedRect(Rect(tileDrawPos, tileDrawPos + Otc::TILE_PIXELS - 1),
m_crosshair, Rect(0, 0, m_crosshair->getSize()));
}
itm->first->drawTop(tileDrawPos, m_lightView.get());
}
for (const MissilePtr& missile : g_map.getFloorMissiles(z)) {
missile->draw(transformPositionTo2D(missile->getPosition(), cameraPosition), true, m_lightView.get());
}
if (fading < 0.99)
g_drawQueue->setOpacity(floorStart, fading);
}
}
void MapView::drawForeground(const Rect& rect)
{
// this could happen if the player position is not known yet
Position cameraPosition = getCameraPosition();
if (!cameraPosition.isValid())
return;
Rect srcRect = calcFramebufferSource(rect.size());
Point drawOffset = srcRect.topLeft();
float horizontalStretchFactor = rect.width() / (float)srcRect.width();
float verticalStretchFactor = rect.height() / (float)srcRect.height();
// creatures
std::vector<std::pair<CreaturePtr, Point>> creatures;
for (const CreaturePtr& creature : g_map.getSpectatorsInRangeEx(cameraPosition, false, m_visibleDimension.width() / 2, m_visibleDimension.width() / 2 + 1, m_visibleDimension.height() / 2, m_visibleDimension.height() / 2 + 1)) {
if (!creature->canBeSeen())
continue;
PointF jumpOffset = creature->getJumpOffset();
Point creatureOffset = Point(16 - creature->getDisplacementX(), -creature->getDisplacementY() - 2);
Position pos = creature->getPrewalkingPosition();
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
p += (creature->getDrawOffset() + creatureOffset) - Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));
p.x = p.x * horizontalStretchFactor;
p.y = p.y * verticalStretchFactor;
p += rect.topLeft();
creatures.push_back(std::make_pair(creature, p));
}
for (auto& c : creatures) {
int flags = Otc::DrawIcons;
if (m_drawNames) { flags |= Otc::DrawNames; }
if ((!c.first->isLocalPlayer() || m_drawPlayerBars) && !m_drawHealthBarsOnTop) {
if (m_drawHealthBars) { flags |= Otc::DrawBars; }
if (m_drawManaBar) { flags |= Otc::DrawManaBar; }
}
c.first->drawInformation(c.second, g_map.isCovered(c.first->getPrewalkingPosition(), m_cachedFirstVisibleFloor), rect, flags);
}
if (m_lightView) {
g_drawQueue->add(m_lightView.release());
}
// texts
int limit = g_adaptiveRenderer.textsLimit();
for (int i = 0; i < 2; ++i) {
for (const StaticTextPtr& staticText : g_map.getStaticTexts()) {
Position pos = staticText->getPosition();
if (pos.z != cameraPosition.z && staticText->getMessageMode() == Otc::MessageNone)
continue;
if ((staticText->getMessageMode() != Otc::MessageSay && staticText->getMessageMode() != Otc::MessageYell)) {
if (i == 0)
continue;
} else if (i == 1)
continue;
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset + Point(8, 0);
p.x *= horizontalStretchFactor;
p.y *= verticalStretchFactor;
p += rect.topLeft();
staticText->drawText(p, rect);
if (--limit == 0)
break;
}
}
limit = g_adaptiveRenderer.textsLimit();
for (const AnimatedTextPtr& animatedText : g_map.getAnimatedTexts()) {
Position pos = animatedText->getPosition();
if (pos.z != cameraPosition.z)
continue;
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset + Point(16, 8);
p.x *= horizontalStretchFactor;
p.y *= verticalStretchFactor;
p += rect.topLeft();
animatedText->drawText(p, rect);
if (--limit == 0)
break;
}
// tile texts
drawTileTexts(rect, srcRect);
// bars on top
if (m_drawHealthBarsOnTop) {
for (auto& c : creatures) {
int flags = 0;
if ((!c.first->isLocalPlayer() || m_drawPlayerBars)) {
if (m_drawHealthBars) { flags |= Otc::DrawBars; }
if (m_drawManaBar) { flags |= Otc::DrawManaBar; }
}
c.first->drawInformation(c.second, g_map.isCovered(c.first->getPrewalkingPosition(), m_cachedFirstVisibleFloor), rect, flags);
}
}
}
void MapView::updateVisibleTilesCache()
{
// hidden
}
void MapView::updateGeometry(const Size& visibleDimension, const Size& optimizedSize)
{
m_multifloor = true;
m_visibleDimension = visibleDimension;
m_drawDimension = visibleDimension + Size(3, 3);
m_virtualCenterOffset = (m_drawDimension / 2 - Size(1, 1)).toPoint();
m_visibleCenterOffset = m_virtualCenterOffset;
m_optimizedSize = m_drawDimension * g_sprites.spriteSize();
requestVisibleTilesCacheUpdate();
}
void MapView::onTileUpdate(const Position& pos)
{
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::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();
}
Position MapView::getPosition(const Point& point, const Size& mapSize)
{
Position cameraPosition = getCameraPosition();
// if we have no camera, its impossible to get the tile
if(!cameraPosition.isValid())
return Position();
Rect srcRect = calcFramebufferSource(mapSize);
float sh = srcRect.width() / (float)mapSize.width();
float sv = srcRect.height() / (float)mapSize.height();
Point framebufferPos = Point(point.x * sh, point.y * sv);
Point realPos = (framebufferPos + srcRect.topLeft());
Point centerOffset = realPos / Otc::TILE_PIXELS;
Point tilePos2D = getVisibleCenterOffset() - m_drawDimension.toPoint() + centerOffset + Point(2,2);
if(tilePos2D.x + cameraPosition.x < 0 && tilePos2D.y + cameraPosition.y < 0)
return Position();
Position position = Position(tilePos2D.x, tilePos2D.y, 0) + cameraPosition;
if(!position.isValid())
return Position();
return position;
}
Point MapView::getPositionOffset(const Point& point, const Size& mapSize)
{
Position cameraPosition = getCameraPosition();
// if we have no camera, its impossible to get the tile
if (!cameraPosition.isValid())
return Point(0, 0);
Rect srcRect = calcFramebufferSource(mapSize);
float sh = srcRect.width() / (float)mapSize.width();
float sv = srcRect.height() / (float)mapSize.height();
Point framebufferPos = Point(point.x * sh, point.y * sv);
Point realPos = (framebufferPos + srcRect.topLeft());
return Point(realPos.x % Otc::TILE_PIXELS, realPos.y % Otc::TILE_PIXELS);
}
void MapView::move(int x, int y)
{
m_moveOffset.x += x;
m_moveOffset.y += y;
int32_t tmp = m_moveOffset.x / g_sprites.spriteSize();
bool requestTilesUpdate = false;
if(tmp != 0) {
m_customCameraPosition.x += tmp;
m_moveOffset.x %= g_sprites.spriteSize();
requestTilesUpdate = true;
}
tmp = m_moveOffset.y / g_sprites.spriteSize();
if(tmp != 0) {
m_customCameraPosition.y += tmp;
m_moveOffset.y %= g_sprites.spriteSize();
requestTilesUpdate = true;
}
if(requestTilesUpdate)
requestVisibleTilesCacheUpdate();
}
Rect MapView::calcFramebufferSource(const Size& destSize, bool inNextFrame)
{
float scaleFactor = g_sprites.spriteSize()/(float)Otc::TILE_PIXELS;
Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * g_sprites.spriteSize();
if(isFollowingCreature())
drawOffset += m_followingCreature->getWalkOffset(inNextFrame) * scaleFactor;
Size srcSize = destSize;
Size srcVisible = m_visibleDimension * g_sprites.spriteSize();
srcSize.scale(srcVisible, Fw::KeepAspectRatio);
drawOffset.x += (srcVisible.width() - srcSize.width()) / 2;
drawOffset.y += (srcVisible.height() - srcSize.height()) / 2;
return Rect(drawOffset, srcSize);
}
int MapView::calcFirstVisibleFloor(bool forFading)
{
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<int>(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 && !forFading; ++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(!g_map.isLookPossible(pos))) {
firstFloor = upperPos.z + 1;
break;
}
// check tiles geometrically above
tile = g_map.getTile(coveredPos);
if(tile && tile->limitsFloorsView(g_map.isLookPossible(pos))) {
firstFloor = coveredPos.z + 1;
break;
}
}
}
}
}
z = firstFloor;
}
}
}
// just ensure the that the floor is in the valid range
z = stdext::clamp<int>(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<int>(m_lockedFirstVisibleFloor, z);
// just ensure the that the floor is in the valid range
z = stdext::clamp<int>(z, 0, (int)Otc::MAX_Z);
return z;
}
Point MapView::transformPositionTo2D(const Position& position, const Position& relativePosition) {
return Point((m_virtualCenterOffset.x + (position.x - relativePosition.x) - (relativePosition.z - position.z)) * g_sprites.spriteSize(),
(m_virtualCenterOffset.y + (position.y - relativePosition.y) - (relativePosition.z - position.z)) * g_sprites.spriteSize());
}
Position MapView::getCameraPosition()
{
if (isFollowingCreature()) {
return m_followingCreature->getPrewalkingPosition();
}
return m_customCameraPosition;
}
void MapView::setDrawLights(bool enable)
{
m_drawLight = enable;
}
void MapView::setCrosshair(const std::string& file)
{
if (file == "")
m_crosshair = nullptr;
else
m_crosshair = g_textures.getTexture(file);
}
/* vim: set ts=4 sw=4 et: */

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

@@ -0,0 +1,177 @@
/*
* Copyright (c) 2010-2017 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>
#include "lightview.h"
// @bindclass
class MapView : public LuaObject
{
public:
MapView();
~MapView();
void drawBackground(const Rect& rect, const TilePtr& crosshairTile = nullptr);
void drawForeground(const Rect& rect);
void drawTexts(const Rect& rect, const Rect& srcRect);
private:
void drawTileTexts(const Rect& rect, const Rect& srcRect);
void updateGeometry(const Size& visibleDimension, const Size& optimizedSize);
void updateVisibleTilesCache();
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);
void optimizeForSize(const Size & visibleSize);
Size getVisibleDimension() { return m_visibleDimension; }
Point getVisibleCenterOffset() { return m_visibleCenterOffset; }
int getCachedFirstVisibleFloor() { return m_cachedFirstVisibleFloor; }
int getCachedLastVisibleFloor() { return m_cachedLastVisibleFloor; }
// 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 setDrawNames(bool enable) { m_drawNames = enable; }
bool isDrawingNames() { return m_drawNames; }
void setDrawHealthBars(bool enable) { m_drawHealthBars = enable; }
bool isDrawingHealthBars() { return m_drawHealthBars; }
void setDrawHealthBarsOnTop(bool enable) { m_drawHealthBarsOnTop = enable; }
bool isDrawingHealthBarsOnTop() { return m_drawHealthBarsOnTop; }
void setDrawLights(bool enable);
bool isDrawingLights() { return m_drawLight; }
void setDrawManaBar(bool enable) { m_drawManaBar = enable; }
bool isDrawingManaBar() { return m_drawManaBar; }
void setDrawPlayerBars(bool enable) { m_drawPlayerBars = enable; }
void move(int x, int y);
void setAnimated(bool animated) { m_animated = animated; requestVisibleTilesCacheUpdate(); }
bool isAnimating() { return m_animated; }
void setFloorFading(int value) { m_floorFading = value; }
void setCrosshair(const std::string& file);
//void setShader(const PainterShaderProgramPtr& shader, float fadein, float fadeout);
//PainterShaderProgramPtr getShader() { return m_shader; }
Position getPosition(const Point& point, const Size& mapSize);
Point getPositionOffset(const Point& point, const Size& mapSize);
MapViewPtr asMapView() { return static_self_cast<MapView>(); }
private:
Rect calcFramebufferSource(const Size& destSize, bool inNextFrame = false);
int calcFirstVisibleFloor(bool forFading = false);
int calcLastVisibleFloor();
Point transformPositionTo2D(const Position& position, const Position& relativePosition);
stdext::timer m_mapRenderTimer;
int m_lockedFirstVisibleFloor;
int m_cachedFirstVisibleFloor;
int m_cachedFirstFadingFloor;
int m_cachedLastVisibleFloor;
int m_updateTilesPos;
int m_floorFading = 500;
TexturePtr m_crosshair = nullptr;
Size m_drawDimension;
Size m_visibleDimension;
Size m_optimizedSize;
Point m_virtualCenterOffset;
Point m_visibleCenterOffset;
Point m_moveOffset;
Position m_customCameraPosition;
Position m_lastCameraPosition;
stdext::boolean<true> m_mustUpdateVisibleTilesCache;
stdext::boolean<true> m_mustDrawVisibleTilesCache;
stdext::boolean<true> m_multifloor;
stdext::boolean<true> m_animated;
stdext::boolean<true> m_drawTexts;
stdext::boolean<true> m_drawNames;
stdext::boolean<true> m_drawHealthBars;
stdext::boolean<false> m_drawHealthBarsOnTop;
stdext::boolean<true> m_drawManaBar;
bool m_drawPlayerBars = true;
stdext::boolean<true> m_smooth;
stdext::timer m_fadingFloorTimers[Otc::MAX_Z + 1];
stdext::boolean<true> m_follow;
std::vector<std::pair<TilePtr, bool>> m_cachedVisibleTiles;
CreaturePtr m_followingCreature;
//PainterShaderProgramPtr m_shader;
Otc::DrawFlags m_drawFlags;
bool m_drawLight = false;
float m_minimumAmbientLight;
std::unique_ptr<LightView> m_lightView;
TexturePtr m_lightTexture;
Timer m_fadeTimer;
//PainterShaderProgramPtr m_nextShader;
float m_fadeInTime;
float m_fadeOutTime;
//stdext::boolean<true> m_shaderSwitchDone;
};
#endif

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

@@ -0,0 +1,438 @@
/*
* Copyright (c) 2010-2017 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"
#include "tile.h"
#include <framework/graphics/image.h>
#include <framework/graphics/texture.h>
#include <framework/graphics/painter.h>
#include <framework/graphics/image.h>
#include <framework/graphics/framebuffermanager.h>
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <zlib.h>
#include <framework/util/stats.h>
Minimap g_minimap;
void MinimapBlock::clean()
{
m_tiles.fill(MinimapTile());
m_texture.reset();
m_mustUpdate = false;
}
void MinimapBlock::update()
{
if(!m_mustUpdate)
return;
ImagePtr image(new Image(Size(MMBLOCK_SIZE, MMBLOCK_SIZE)));
bool shouldDraw = false;
for(int x=0;x<MMBLOCK_SIZE;++x) {
for(int y=0;y<MMBLOCK_SIZE;++y) {
uint8 c = getTile(x, y).color;
Color col = Color::alpha;
if(c != 255) {
col = Color::from8bit(c);
shouldDraw = true;
}
image->setPixel(x, y, col);
}
}
if(shouldDraw) {
m_texture = TexturePtr(new Texture(image));
} else
m_texture.reset();
m_mustUpdate = false;
}
void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile)
{
if(m_tiles[getTileIndex(x,y)].color != tile.color)
m_mustUpdate = true;
m_tiles[getTileIndex(x,y)] = tile;
}
void Minimap::init()
{
}
void Minimap::terminate()
{
clean();
}
void Minimap::clean()
{
std::lock_guard<std::mutex> lock(m_lock);
for(int i=0;i<=Otc::MAX_Z;++i)
m_tileBlocks[i].clear();
}
void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scale, const Color& color)
{
if(screenRect.isEmpty())
return;
Rect mapRect = calcMapRect(screenRect, mapCenter, scale);
g_drawQueue->addFilledRect(screenRect, color);
if(MMBLOCK_SIZE*scale <= 1 || !mapCenter.isMapPosition()) {
return;
}
size_t drawQueueStart = g_drawQueue->size();
Point blockOff = getBlockOffset(mapRect.topLeft());
Point off = Point((mapRect.size() * scale).toPoint() - screenRect.size().toPoint())/2;
Point start = screenRect.topLeft() -(mapRect.topLeft() - blockOff)*scale - off;
for(int y = blockOff.y, ys = start.y;ys<screenRect.bottom();y += MMBLOCK_SIZE, ys += MMBLOCK_SIZE*scale) {
if(y < 0 || y >= 65536)
continue;
for(int x = blockOff.x, xs = start.x;xs<screenRect.right();x += MMBLOCK_SIZE, xs += MMBLOCK_SIZE*scale) {
if(x < 0 || x >= 65536)
continue;
Position blockPos(x, y, mapCenter.z);
if(!hasBlock(blockPos))
continue;
MinimapBlock& block = getBlock(Position(x, y, mapCenter.z));
block.update();
const TexturePtr& tex = block.getTexture();
if(tex) {
Rect src(0, 0, MMBLOCK_SIZE, MMBLOCK_SIZE);
Rect dest(xs, ys, MMBLOCK_SIZE * scale, MMBLOCK_SIZE * scale);
g_drawQueue->addTexturedRect(dest, tex, src);
}
}
}
g_drawQueue->setClip(drawQueueStart, screenRect);
}
Point Minimap::getTilePoint(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale)
{
if(screenRect.isEmpty() || pos.z != mapCenter.z)
return Point(-1,-1);
Rect mapRect = calcMapRect(screenRect, mapCenter, scale);
Point off = Point((mapRect.size() * scale).toPoint() - screenRect.size().toPoint())/2;
Point posoff = (Point(pos.x,pos.y) - mapRect.topLeft())*scale;
return posoff + screenRect.topLeft() - off + (Point(1,1)*scale)/2;
}
Position Minimap::getTilePosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale)
{
if(screenRect.isEmpty())
return Position();
Rect mapRect = calcMapRect(screenRect, mapCenter, scale);
Point off = Point((mapRect.size() * scale).toPoint() - screenRect.size().toPoint())/2;
Point pos2d = (point - screenRect.topLeft() + off)/scale + mapRect.topLeft();
return Position(pos2d.x, pos2d.y, mapCenter.z);
}
Rect Minimap::getTileRect(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale)
{
if(screenRect.isEmpty() || pos.z != mapCenter.z)
return Rect();
int tileSize = 32 * scale;
Rect tileRect(0,0,tileSize, tileSize);
tileRect.moveCenter(getTilePoint(pos, screenRect, mapCenter, scale));
return tileRect;
}
Rect Minimap::calcMapRect(const Rect& screenRect, const Position& mapCenter, float scale)
{
int w = screenRect.width() / scale, h = std::ceil(screenRect.height() / scale);
Rect mapRect(0,0,w,h);
mapRect.moveCenter(Point(mapCenter.x, mapCenter.y));
return mapRect;
}
void Minimap::updateTile(const Position& pos, const TilePtr& tile)
{
MinimapTile minimapTile;
if(tile) {
minimapTile.color = tile->getMinimapColorByte();
minimapTile.flags |= MinimapTileWasSeen;
if(!tile->isWalkable(true))
minimapTile.flags |= MinimapTileNotWalkable;
if(!tile->isPathable())
minimapTile.flags |= MinimapTileNotPathable;
minimapTile.speed = std::min<int>((int)std::ceil(tile->getGroundSpeed() / 10.0f), 255);
} else {
minimapTile.color = 255;
minimapTile.flags |= MinimapTileEmpty;
minimapTile.speed = 1;
}
if(minimapTile != MinimapTile()) {
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile);
block.justSaw();
}
}
const MinimapTile& Minimap::getTile(const Position& pos)
{
static MinimapTile nulltile;
if(pos.z <= Otc::MAX_Z && hasBlock(pos)) {
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y);
}
return nulltile;
}
std::pair<MinimapBlock_ptr, MinimapTile> Minimap::threadGetTile(const Position& pos) {
std::lock_guard<std::mutex> lock(m_lock);
static MinimapTile nulltile;
if (pos.z <= Otc::MAX_Z && hasBlock(pos)) {
MinimapBlock_ptr block = m_tileBlocks[pos.z][getBlockIndex(pos)];
if (block) {
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
return std::make_pair(block, block->getTile(pos.x - offsetPos.x, pos.y - offsetPos.y));
}
}
return std::make_pair(nullptr, nulltile);
}
bool Minimap::loadImage(const std::string& fileName, const Position& topLeft, float colorFactor)
{
if(colorFactor <= 0.01f)
colorFactor = 1.0f;
try {
ImagePtr image = Image::load(fileName);
uint8 waterc = Color::to8bit(std::string("#3300cc"));
// non pathable colors
Color nonPathableColors[] = {
std::string("#ffff00"), // yellow
};
// non walkable colors
Color nonWalkableColors[] = {
std::string("#000000"), // oil, black
std::string("#006600"), // trees, dark green
std::string("#ff3300"), // walls, red
std::string("#666666"), // mountain, grey
std::string("#ff6600"), // lava, orange
std::string("#00ff00"), // positon
std::string("#ccffff"), // ice, very light blue
};
for(int y=0;y<image->getHeight();++y) {
for(int x=0;x<image->getWidth();++x) {
Color color = *(uint32*)image->getPixel(x,y);
uint8 c = Color::to8bit(color * colorFactor);
int flags = 0;
if(c == waterc || color.a() == 0) {
flags |= MinimapTileNotWalkable;
c = 255; // alpha
}
if(flags != 0) {
for(Color &col : nonWalkableColors) {
if(col == color) {
flags |= MinimapTileNotWalkable;
break;
}
}
}
if(flags != 0) {
for(Color &col : nonPathableColors) {
if(col == color) {
flags |= MinimapTileNotPathable;
break;
}
}
}
if(c == 255)
continue;
Position pos(topLeft.x + x, topLeft.y + y, topLeft.z);
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
MinimapTile& tile = block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y);
if(!(tile.flags & MinimapTileWasSeen)) {
tile.color = c;
tile.flags = flags;
block.mustUpdate();
}
}
}
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load OTMM minimap: %s", e.what()));
return false;
}
}
void Minimap::saveImage(const std::string& fileName, const Rect& mapRect)
{
//TODO
}
bool Minimap::loadOtmm(const std::string& fileName)
{
try {
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception("unable to open file");
uint32 signature = fin->getU32();
if(signature != OTMM_SIGNATURE)
stdext::throw_exception("invalid OTMM file");
uint16 start = fin->getU16();
uint16 version = fin->getU16();
fin->getU32(); // flags
switch(version) {
case 1: {
fin->getString(); // description
break;
}
default:
stdext::throw_exception("OTMM version not supported");
}
fin->seek(start);
uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
std::vector<uchar> compressBuffer(compressBound(blockSize));
std::vector<uchar> decompressBuffer(blockSize);
while(true) {
Position pos;
pos.x = fin->getU16();
pos.y = fin->getU16();
pos.z = fin->getU8();
// end of file or file is corrupted
if(!pos.isValid() || pos.z >= Otc::MAX_Z+1)
break;
MinimapBlock& block = getBlock(pos);
ulong len = fin->getU16();
ulong destLen = blockSize;
fin->read(compressBuffer.data(), len);
int ret = uncompress(decompressBuffer.data(), &destLen, compressBuffer.data(), len);
if(ret != Z_OK || destLen != blockSize)
break;
memcpy((uchar*)&block.getTiles(), decompressBuffer.data(), blockSize);
block.mustUpdate();
block.justSaw();
}
fin->close();
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load OTMM minimap: %s", e.what()));
return false;
}
}
void Minimap::saveOtmm(const std::string& fileName)
{
try {
stdext::timer saveTimer;
FileStreamPtr fin = g_resources.createFile(fileName);
//TODO: compression flag with zlib
uint32 flags = 0;
// header
fin->addU32(OTMM_SIGNATURE);
fin->addU16(0); // data start, will be overwritten later
fin->addU16(OTMM_VERSION);
fin->addU32(flags);
// version 1 header
fin->addString("OTMM 1.0"); // description
// go back and rewrite where the map data starts
uint32 start = fin->tell();
fin->seek(4);
fin->addU16(start);
fin->seek(start);
uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
std::vector<uchar> compressBuffer(compressBound(blockSize));
const int COMPRESS_LEVEL = 3;
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
for(auto& it : m_tileBlocks[z]) {
int index = it.first;
MinimapBlock& block = *it.second;
if(!block.wasSeen())
continue;
Position pos = getIndexPosition(index, z);
fin->addU16(pos.x);
fin->addU16(pos.y);
fin->addU8(pos.z);
ulong len = blockSize;
int ret = compress2(compressBuffer.data(), &len, (uchar*)&block.getTiles(), blockSize, COMPRESS_LEVEL);
VALIDATE(ret == Z_OK);
fin->addU16(len);
fin->write(compressBuffer.data(), len);
}
}
// end of file
Position invalidPos;
fin->addU16(invalidPos.x);
fin->addU16(invalidPos.y);
fin->addU8(invalidPos.z);
fin->flush();
fin->close();
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to save OTMM minimap: %s", e.what()));
}
}

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

@@ -0,0 +1,125 @@
/*
* Copyright (c) 2010-2017 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 "declarations.h"
#include <framework/graphics/declarations.h>
enum {
MMBLOCK_SIZE = 64,
OTMM_SIGNATURE = 0x4D4d544F,
OTMM_VERSION = 1
};
enum MinimapTileFlags {
MinimapTileWasSeen = 1,
MinimapTileNotPathable = 2,
MinimapTileNotWalkable = 4,
MinimapTileEmpty = 8
};
#pragma pack(push,1) // disable memory alignment
struct MinimapTile
{
MinimapTile() : flags(0), color(255), speed(10) { }
uint8 flags;
uint8 color;
uint8 speed;
bool hasFlag(MinimapTileFlags flag) const { return flags & flag; }
int getSpeed() const { return speed * 10; }
bool operator==(const MinimapTile& other) const { return color == other.color && flags == other.flags && speed == other.speed; }
bool operator!=(const MinimapTile& other) const { return !(*this == other); }
};
class MinimapBlock
{
public:
void clean();
void update();
void updateTile(int x, int y, const MinimapTile& tile);
MinimapTile& getTile(int x, int y) { return m_tiles[getTileIndex(x,y)]; }
void resetTile(int x, int y) { m_tiles[getTileIndex(x,y)] = MinimapTile(); }
uint getTileIndex(int x, int y) { return ((y % MMBLOCK_SIZE) * MMBLOCK_SIZE) + (x % MMBLOCK_SIZE); }
const TexturePtr& getTexture() { return m_texture; }
std::array<MinimapTile, MMBLOCK_SIZE * MMBLOCK_SIZE>& getTiles() { return m_tiles; }
void mustUpdate() { m_mustUpdate = true; }
void justSaw() { m_wasSeen = true; }
bool wasSeen() { return m_wasSeen; }
private:
TexturePtr m_texture;
std::array<MinimapTile, MMBLOCK_SIZE * MMBLOCK_SIZE> m_tiles;
stdext::boolean<true> m_mustUpdate;
stdext::boolean<false> m_wasSeen;
};
#pragma pack(pop)
using MinimapBlock_ptr = std::shared_ptr<MinimapBlock>;
class Minimap
{
public:
void init();
void terminate();
void clean();
void draw(const Rect& screenRect, const Position& mapCenter, float scale, const Color& color);
Point getTilePoint(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale);
Position getTilePosition(const Point& point, const Rect& screenRect, const Position& mapCenter, float scale);
Rect getTileRect(const Position& pos, const Rect& screenRect, const Position& mapCenter, float scale);
void updateTile(const Position& pos, const TilePtr& tile);
const MinimapTile& getTile(const Position& pos);
std::pair<MinimapBlock_ptr, MinimapTile> threadGetTile(const Position& pos);
bool loadImage(const std::string& fileName, const Position& topLeft, float colorFactor);
void saveImage(const std::string& fileName, const Rect& mapRect);
bool loadOtmm(const std::string& fileName);
void saveOtmm(const std::string& fileName);
private:
Rect calcMapRect(const Rect& screenRect, const Position& mapCenter, float scale);
bool hasBlock(const Position& pos) { return m_tileBlocks[pos.z].find(getBlockIndex(pos)) != m_tileBlocks[pos.z].end(); }
MinimapBlock& getBlock(const Position& pos) {
std::lock_guard<std::mutex> lock(m_lock);
auto& ptr = m_tileBlocks[pos.z][getBlockIndex(pos)];
if (!ptr)
ptr = std::make_shared<MinimapBlock>();
return *ptr;
}
Point getBlockOffset(const Point& pos) { return Point(pos.x - pos.x % MMBLOCK_SIZE,
pos.y - pos.y % MMBLOCK_SIZE); }
Position getIndexPosition(int index, int z) { return Position((index % (65536 / MMBLOCK_SIZE))*MMBLOCK_SIZE,
(index / (65536 / MMBLOCK_SIZE))*MMBLOCK_SIZE, z); }
uint getBlockIndex(const Position& pos) { return ((pos.y / MMBLOCK_SIZE) * (65536 / MMBLOCK_SIZE)) + (pos.x / MMBLOCK_SIZE); }
std::unordered_map<uint, MinimapBlock_ptr> m_tileBlocks[Otc::MAX_Z+1];
std::mutex m_lock;
};
extern Minimap g_minimap;
#endif

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

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2010-2017 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, 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, 0, xPattern, yPattern, 0, 0, Color::white, lightView);
}
void Missile::setPath(const Position& fromPosition, const Position& toPosition)
{
m_source = fromPosition;
m_destination = 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);
}

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

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-2017 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, bool animate = true, 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();
Position getSource() { return m_source; }
Position getDestination() { return m_destination; }
private:
Timer m_animationTimer;
Point m_delta;
float m_duration;
uint16 m_id;
Otc::Direction m_direction;
Position m_source, m_destination;
};
#endif

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

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2010-2017 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"
#include "game.h"
#include "spritemanager.h"
#include <framework/graphics/painter.h>
#include <framework/graphics/drawqueue.h>
Outfit::Outfit()
{
m_category = ThingCategoryCreature;
m_id = 128;
m_auxId = 0;
resetClothes();
}
void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, bool animate, LightView* lightView)
{
// direction correction
if (m_category != ThingCategoryCreature)
direction = Otc::North;
else if (direction == Otc::NorthEast || direction == Otc::SouthEast)
direction = Otc::East;
else if (direction == Otc::NorthWest || direction == Otc::SouthWest)
direction = Otc::West;
auto type = g_things.rawGetThingType(m_category == ThingCategoryCreature ? m_id : m_auxId, m_category);
int animationPhase = walkAnimationPhase;
if (animate && m_category == ThingCategoryCreature) {
auto idleAnimator = type->getIdleAnimator();
if (idleAnimator) {
if (walkAnimationPhase > 0) {
animationPhase += idleAnimator->getAnimationPhases() - 1;;
} else {
animationPhase = idleAnimator->getPhase();
}
} else if (type->isAnimateAlways()) {
int phases = type->getAnimator() ? type->getAnimator()->getAnimationPhases() : type->getAnimationPhases();
int ticksPerFrame = 1000 / phases;
animationPhase = (g_clock.millis() % (ticksPerFrame * phases)) / ticksPerFrame;
}
} else if(animate) {
int animationPhases = type->getAnimationPhases();
int animateTicks = g_game.getFeature(Otc::GameEnhancedAnimations) ? Otc::ITEM_TICKS_PER_FRAME_FAST : Otc::ITEM_TICKS_PER_FRAME;
if (m_category == ThingCategoryEffect) {
animationPhases = std::max<int>(1, animationPhases - 2);
animateTicks = g_game.getFeature(Otc::GameEnhancedAnimations) ? Otc::INVISIBLE_TICKS_PER_FRAME_FAST : Otc::INVISIBLE_TICKS_PER_FRAME;
}
if (animationPhases > 1)
animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
if (m_category == ThingCategoryEffect)
animationPhase = std::min<int>(animationPhase + 1, animationPhases);
}
int zPattern = m_mount > 0 ? std::min<int>(1, type->getNumPatternZ() - 1) : 0;
if (zPattern > 0) {
int mountAnimationPhase = walkAnimationPhase;
auto mountType = g_things.rawGetThingType(m_mount, ThingCategoryCreature);
auto idleAnimator = mountType->getIdleAnimator();
if (idleAnimator && animate) {
if (walkAnimationPhase > 0) {
mountAnimationPhase += idleAnimator->getAnimationPhases() - 1;
} else {
mountAnimationPhase = idleAnimator->getPhase();
}
}
dest -= mountType->getDisplacement();
mountType->draw(dest, 0, direction, 0, 0, mountAnimationPhase, Color::white, lightView);
dest += type->getDisplacement();
}
if (m_aura) {
auto auraType = g_things.rawGetThingType(m_aura, ThingCategoryCreature);
auraType->draw(dest, 0, direction, 0, 0, 0, Color::white, lightView);
}
if (m_wings && (direction == Otc::South || direction == Otc::West)) {
auto wingsType = g_things.rawGetThingType(m_wings, ThingCategoryCreature);
wingsType->draw(dest, 0, direction, 0, 0, animationPhase, Color::white, lightView);
}
for (int yPattern = 0; yPattern < type->getNumPatternY(); yPattern++) {
if (yPattern > 0 && !(getAddons() & (1 << (yPattern - 1)))) {
continue;
}
if (type->getLayers() <= 1) {
type->draw(dest, 0, direction, yPattern, zPattern, animationPhase, Color::white, lightView);
continue;
}
uint32_t colors = m_head + (m_body << 8) + (m_legs << 16) + (m_feet << 24);
type->drawOutfit(dest, direction, yPattern, zPattern, animationPhase, colors, Color::white, lightView);
}
if (m_wings && (direction == Otc::North || direction == Otc::East)) {
auto wingsType = g_things.rawGetThingType(m_wings, ThingCategoryCreature);
wingsType->draw(dest, 0, direction, 0, 0, animationPhase, Color::white, lightView);
}
}
void Outfit::draw(const Rect& dest, Otc::Direction direction, uint animationPhase, bool animate)
{
int size = g_drawQueue->size();
draw(Point(0, 0), direction, animationPhase, animate);
g_drawQueue->correctOutfit(dest, size);
}
void Outfit::resetClothes()
{
setHead(0);
setBody(0);
setLegs(0);
setFeet(0);
setMount(0);
}

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

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2010-2017 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
{
public:
Outfit();
static Color getColor(int color)
{
return Color::getOutfitColor(color);
}
void draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, bool animate = true, LightView* lightView = nullptr);
void draw(const Rect& dest, Otc::Direction direction, uint animationPhase, bool animate = true);
void setId(int id) { m_id = id; }
void setAuxId(int id) { m_auxId = id; }
void setHead(int head) { m_head = head; }
void setBody(int body) { m_body = body; }
void setLegs(int legs) { m_legs = legs; }
void setFeet(int feet) { m_feet = feet; }
void setAddons(int addons) { m_addons = addons; }
void setMount(int mount) { m_mount = mount; }
void setWings(int wings) { m_wings = wings; }
void setAura(int aura) { m_aura = aura; }
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; }
int getWings() const { return m_wings; }
int getAura() const { return m_aura; }
ThingCategory getCategory() const { return m_category; }
private:
ThingCategory m_category;
int m_id, m_auxId, m_head, m_body, m_legs, m_feet, m_addons, m_mount = 0, m_wings = 0, m_aura = 0;
};
#endif

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

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2010-2017 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-2017 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

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

@@ -0,0 +1,273 @@
/*
* Copyright (c) 2010-2017 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>
#include <vector>
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;
}
std::vector<Position> translatedToDirections(const std::vector<Otc::Direction>& dirs) const {
Position lastPos = *this;
std::vector<Position> positions;
if(!lastPos.isValid())
return positions;
positions.push_back(lastPos);
for(auto dir : dirs) {
lastPos = lastPos.translatedToDirection(dir);
if(!lastPos.isValid())
break;
positions.push_back(lastPos);
}
return positions;
}
static double getAngleFromPositions(const Position& fromPos, const Position& toPos) {
// Returns angle in radians from 0 to 2Pi. -1 means positions are equal.
int dx = toPos.x - fromPos.x;
int dy = toPos.y - fromPos.y;
if(dx == 0 && dy == 0)
return -1;
float angle = std::atan2(dy * -1, dx);
if(angle < 0)
angle += 2 * Fw::pi;
return angle;
}
double getAngleFromPosition(const Position& position) const {
return getAngleFromPositions(*this, position);
}
static Otc::Direction getDirectionFromPositions(const Position& fromPos,
const Position& toPos)
{
float angle = getAngleFromPositions(fromPos, toPos) * RAD_TO_DEC;
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;
else
return Otc::InvalidDirection;
}
Otc::Direction getDirectionFromPosition(const Position& position) const {
return getDirectionFromPositions(*this, position);
}
bool isMapPosition() const { return (x >=0 && y >= 0 && z >= 0 && 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, int zRange = 0) const { return std::abs(x-pos.x) <= xRange && std::abs(y-pos.y) <= yRange && std::abs(z - pos.z) <= zRange; }
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);
}
// operator less than for std::map
bool operator<(const Position& other) const { return x < other.x || y < other.y || z < other.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;
}
std::string toString()
{
return std::to_string(x) + "," + std::to_string(y) + "," + std::to_string(z);
}
int x;
int y;
short z;
};
struct PositionHasher {
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,196 @@
/*
* Copyright (c) 2010-2017 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 >= 1094) {
messageModesMap[Otc::MessageMana] = 43;
}
if(version >= 1055) { // might be 1054
messageModesMap[Otc::MessageNone] = 0;
messageModesMap[Otc::MessageSay] = 1;
messageModesMap[Otc::MessageWhisper] = 2;
messageModesMap[Otc::MessageYell] = 3;
messageModesMap[Otc::MessagePrivateFrom] = 4;
messageModesMap[Otc::MessagePrivateTo] = 5;
messageModesMap[Otc::MessageChannelManagement] = 6;
messageModesMap[Otc::MessageChannel] = 7;
messageModesMap[Otc::MessageChannelHighlight] = 8;
messageModesMap[Otc::MessageSpell] = 9;
messageModesMap[Otc::MessageNpcFromStartBlock] = 10;
messageModesMap[Otc::MessageNpcFrom] = 11;
messageModesMap[Otc::MessageNpcTo] = 12;
messageModesMap[Otc::MessageGamemasterBroadcast] = 13;
messageModesMap[Otc::MessageGamemasterChannel] = 14;
messageModesMap[Otc::MessageGamemasterPrivateFrom] = 15;
messageModesMap[Otc::MessageGamemasterPrivateTo] = 16;
messageModesMap[Otc::MessageLogin] = 17;
messageModesMap[Otc::MessageWarning] = 18; // Admin
messageModesMap[Otc::MessageGame] = 19;
messageModesMap[Otc::MessageGameHighlight] = 20;
messageModesMap[Otc::MessageFailure] = 21;
messageModesMap[Otc::MessageLook] = 22;
messageModesMap[Otc::MessageDamageDealed] = 23;
messageModesMap[Otc::MessageDamageReceived] = 24;
messageModesMap[Otc::MessageHeal] = 25;
messageModesMap[Otc::MessageExp] = 26;
messageModesMap[Otc::MessageDamageOthers] = 27;
messageModesMap[Otc::MessageHealOthers] = 28;
messageModesMap[Otc::MessageExpOthers] = 29;
messageModesMap[Otc::MessageStatus] = 30;
messageModesMap[Otc::MessageLoot] = 31;
messageModesMap[Otc::MessageTradeNpc] = 32;
messageModesMap[Otc::MessageGuild] = 33;
messageModesMap[Otc::MessagePartyManagement] = 34;
messageModesMap[Otc::MessageParty] = 35;
messageModesMap[Otc::MessageBarkLow] = 36;
messageModesMap[Otc::MessageBarkLoud] = 37;
messageModesMap[Otc::MessageReport] = 38;
messageModesMap[Otc::MessageHotkeyUse] = 39;
messageModesMap[Otc::MessageTutorialHint] = 40;
messageModesMap[Otc::MessageThankyou] = 41;
messageModesMap[Otc::MessageMarket] = 42;
} else if(version >= 1036) {
for(int i = Otc::MessageNone; i <= Otc::MessageBeyondLast; ++i) {
if(i >= Otc::MessageNpcTo)
messageModesMap[i] = i + 1;
else
messageModesMap[i] = i;
}
} else if(version >= 900) {
for(int i = Otc::MessageNone; i <= Otc::MessageBeyondLast; ++i)
messageModesMap[i] = i;
messageModesMap[Otc::MessageNpcFromStartBlock] = 10;
messageModesMap[Otc::MessageNpcFrom] = 11;
} 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::MessageNpcFromStartBlock] = 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 >= 840) {
messageModesMap[Otc::MessageNone] = 0;
messageModesMap[Otc::MessageSay] = 1;
messageModesMap[Otc::MessageWhisper] = 2;
messageModesMap[Otc::MessageYell] = 3;
messageModesMap[Otc::MessageNpcTo] = 4;
messageModesMap[Otc::MessageNpcFromStartBlock] = 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 ??
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 >= 760) {
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;
}
}

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

@@ -0,0 +1,342 @@
/*
* Copyright (c) 2010-2017 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 ItemOpcode {
StaticText = 96,
UnknownCreature = 97,
OutdatedCreature = 98,
Creature = 99
};
enum GameServerOpcodes : uint8
{
GameServerLoginOrPendingState = 10,
GameServerGMActions = 11,
GameServerEnterGame = 15,
GameServerUpdateNeeded = 17,
GameServerLoginError = 20,
GameServerLoginAdvice = 21,
GameServerLoginWait = 22,
GameServerLoginSuccess = 23,
GameServerLoginToken = 24,
GameServerStoreButtonIndicators = 25, // 1097
GameServerPingBack = 29,
GameServerPing = 30,
GameServerChallenge = 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
// OTClientV8 64-79
GameServerNewPing = 64,
GameServerChangeMapAwareRange = 66,
GameServerFeatures = 67,
GameServerNewCancelWalk = 69,
GameServerPredictiveCancelWalk = 70,
GameServerWalkId = 71,
GameServerFloorDescription = 75,
GameServerProcessesRequest = 80,
GameServerDllsRequest = 81,
GameServerWindowsRequests = 82,
GameServerClientCheck = 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,
GameServerCreatureMarks = 147,
GameServerPlayerHelpers = 148,
GameServerCreatureType = 149,
GameServerEditText = 150,
GameServerEditList = 151,
GameServerNews = 152,
GameServerBlessings = 156,
GameServerPreset = 157,
GameServerPremiumTrigger = 158, // 1038
GameServerPlayerDataBasic = 159, // 950
GameServerPlayerData = 160,
GameServerPlayerSkills = 161,
GameServerPlayerState = 162,
GameServerClearTarget = 163,
GameServerPlayerModes = 167,
GameServerSpellDelay = 164, // 870
GameServerSpellGroupDelay = 165, // 870
GameServerMultiUseDelay = 166, // 870
GameServerSetStoreDeepLink = 168, // 1097
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,
GameServerUnjustifiedStats = 183,
GameServerPvpSituations = 184,
GameServerFloorChangeUp = 190,
GameServerFloorChangeDown = 191,
GameServerChooseOutfit = 200,
GameServerImpactTracker = 204,
GameServerSupplyTracker = 206,
GameServerLootTracker = 207,
GameServerQuestTracker = 208,
GameServerKillTracker = 209,
GameServerVipAdd = 210,
GameServerVipState = 211,
GameServerVipLogout = 212,
GameServerTutorialHint = 220,
GameServerAutomapFlag = 221,
GameServerCoinBalance = 223,
GameServerStoreError = 224, // 1080
GameServerRequestPurchaseData = 225, // 1080
GameServerPreyFreeRolls = 230,
GameServerPreyTimeLeft = 231,
GameServerPreyData = 232,
GameServerPreyPrices = 233,
GameServerImbuementWindow = 235,
GaneServerCloseImbuementWindow = 236,
GameServerMessageDialog = 237,
GameServerResourceBalance = 238,
GameServerQuestLog = 240,
GameServerQuestLine = 241,
GameServerCoinBalanceUpdate = 242,
GameServerChannelEvent = 243, // 910
GameServerItemInfo = 244, // 910
GameServerPlayerInventory = 245, // 910
GameServerMarketEnter = 246, // 944
GameServerMarketLeave = 247, // 944
GameServerMarketDetail = 248, // 944
GameServerMarketBrowse = 249, // 944
GameServerModalDialog = 250, // 960
GameServerStore = 251, // 1080
GameServerStoreOffers = 252, // 1080
GameServerStoreTransactionHistory = 253, // 1080
GameServerStoreCompletePurchase = 254 // 1080
};
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
// OTClientV8 64-79
ClientNewPing = 64,
ClientChangeMapAwareRange = 66,
ClientNewWalk = 69,
ClientProcessesResponse = 80,
ClientDllsResponse = 81,
ClientWindowsResponse = 82,
// 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,
ClientWrapableItem = 139,
ClientLook = 140,
ClientLookCreature = 141,
ClientTalk = 150,
ClientRequestChannels = 151,
ClientJoinChannel = 152,
ClientLeaveChannel = 153,
ClientOpenPrivateChannel = 154,
ClientOpenRuleViolation = 155,
ClientCloseRuleViolation = 156,
ClientCancelRuleViolation = 157,
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,
ClientBrowseField = 203,
ClientSeekInContainer = 204,
ClientRequestOutfit = 210,
ClientChangeOutfit = 211,
ClientMount = 212, // 870
ApplyImbuemente = 213,
ClearingImbuement = 214,
CloseImbuingWindow = 215,
ClientAddVip = 220,
ClientRemoveVip = 221,
ClientEditVip = 222,
ClientBugReport = 230,
ClientRuleViolation = 231,
ClientDebugReport = 232,
ClientPreyAction = 235,
ClientPreyRequest = 237,
ClientTransferCoins = 239, // 1080
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
ClientOpenStore = 250, // 1080
ClientRequestStoreOffers = 251, // 1080
ClientBuyStoreOffer = 252, // 1080
ClientOpenTransactionHistory = 253, // 1080
ClientRequestTransactionHistory = 254 // 1080
};
enum CreatureType {
CreatureTypePlayer = 0,
CreatureTypeMonster,
CreatureTypeNpc,
CreatureTypeSummonOwn,
CreatureTypeSummonOther,
CreatureTypeUnknown = 0xFF
};
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,82 @@
/*
* Copyright (c) 2010-2017 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
*
* 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, const std::string& authenticatorToken, const std::string& sessionKey)
{
m_accountName = accountName;
m_accountPassword = accountPassword;
m_authenticatorToken = authenticatorToken;
m_sessionKey = sessionKey;
m_characterName = characterName;
connect(host, port);
}
void ProtocolGame::onConnect()
{
m_firstRecv = true;
Protocol::onConnect();
m_localPlayer = g_game.getLocalPlayer();
if (g_game.getFeature(Otc::GamePacketSizeU32))
enableBigPackets();
if(g_game.getFeature(Otc::GameProtocolChecksum))
enableChecksum();
if(!g_game.getFeature(Otc::GameChallengeOnLogin))
sendLoginPacket(0, 0);
recv();
}
void ProtocolGame::onRecv(const InputMessagePtr& inputMessage)
{
m_recivedPackeds += 1;
m_recivedPackedsSize += inputMessage->getMessageSize();
if(m_firstRecv) {
m_firstRecv = false;
if(g_game.getFeature(Otc::GameMessageSizeCheck)) {
int size = g_game.getFeature(Otc::GamePacketSizeU32) ? inputMessage->getU32() : 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)
{
g_game.processConnectionError(error);
disconnect();
}

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

@@ -0,0 +1,313 @@
/*
* Copyright (c) 2010-2017 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, const std::string& authenticatorToken, const std::string& sessionKey);
void send(const OutputMessagePtr& outputMessage);
void sendExtendedOpcode(uint8 opcode, const std::string& buffer);
void sendLoginPacket(uint challengeTimestamp, uint8 challengeRandom);
void sendEnterGame();
void sendLogout();
void sendPing();
void sendPingBack();
void sendNewPing(uint32_t pingId, uint16_t localPing, uint16_t fps);
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 sendWrapableItem(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, const Position& pos, Otc::Direction dir);
void sendRequestChannels();
void sendJoinChannel(int channelId);
void sendLeaveChannel(int channelId);
void sendOpenPrivateChannel(const std::string& receiver);
void sendOpenRuleViolation(const std::string& reporter);
void sendCloseRuleViolation(const std::string& reporter);
void sendCancelRuleViolation();
void sendCloseNpcChannel();
void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight, Otc::PVPModes pvpMode);
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 sendApplyImbuement(uint8_t slot, uint32_t imbuementId, bool protectionCharm);
void sendClearImbuement(uint8_t slot);
void sendCloseImbuingWindow();
void sendAddVip(const std::string& name);
void sendRemoveVip(uint playerId);
void sendEditVip(uint playerId, const std::string& description, int iconId, bool notifyLogin);
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(uint32 dialog, int button, int choice);
void sendBrowseField(const Position& position);
void sendSeekInContainer(int cid, int index);
void sendBuyStoreOffer(int offerId, int productType, const std::string& name);
void sendRequestTransactionHistory(int page, int entriesPerPage);
void sendRequestStoreOffers(const std::string& categoryName, int serviceType);
void sendOpenStore(int serviceType);
void sendTransferCoins(const std::string& recipient, int amount);
void sendOpenTransactionHistory(int entiresPerPage);
void sendPreyAction(int slot, int actionType, int index);
void sendPreyRequest();
void sendProcesses();
void sendDlls();
void sendWindows();
// otclient only
void sendChangeMapAwareRange(int xrange, int yrange);
void sendNewWalk(int walkId, int predictionId, const Position& pos, uint8_t flags, const std::vector<Otc::Direction>& path);
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 parseStoreButtonIndicators(const InputMessagePtr& msg);
void parseSetStoreDeepLink(const InputMessagePtr& msg);
void parseStore(const InputMessagePtr& msg);
void parseStoreError(const InputMessagePtr& msg);
void parseStoreTransactionHistory(const InputMessagePtr& msg);
void parseStoreOffers(const InputMessagePtr& msg);
void parseCompleteStorePurchase(const InputMessagePtr& msg);
void parseRequestPurchaseData(const InputMessagePtr& msg);
void parseCoinBalance(const InputMessagePtr& msg);
void parseCoinBalanceUpdate(const InputMessagePtr& msg);
void parseBlessings(const InputMessagePtr& msg);
void parseUnjustifiedStats(const InputMessagePtr& msg);
void parsePvpSituations(const InputMessagePtr& msg);
void parsePreset(const InputMessagePtr& msg);
void parseCreatureType(const InputMessagePtr& msg);
void parsePlayerHelpers(const InputMessagePtr& msg);
void parseMessage(const InputMessagePtr& msg);
void parsePendingGame(const InputMessagePtr& msg);
void parseEnterGame(const InputMessagePtr& msg);
void parseLogin(const InputMessagePtr& msg);
void parseGMActions(const InputMessagePtr& msg);
void parseUpdateNeeded(const InputMessagePtr& msg);
void parseLoginError(const InputMessagePtr& msg);
void parseLoginAdvice(const InputMessagePtr& msg);
void parseLoginWait(const InputMessagePtr& msg);
void parseLoginToken(const InputMessagePtr& msg);
void parsePing(const InputMessagePtr& msg);
void parsePingBack(const InputMessagePtr& msg);
void parseNewPing(const InputMessagePtr& msg);
void parseChallenge(const InputMessagePtr& msg);
void parseDeath(const InputMessagePtr& msg);
void parseMapDescription(const InputMessagePtr& msg);
void parseFloorDescription(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 parsePremiumTrigger(const InputMessagePtr& msg);
void parsePreyFreeRolls(const InputMessagePtr& msg);
void parsePreyTimeLeft(const InputMessagePtr& msg);
void parsePreyData(const InputMessagePtr& msg);
void parsePreyPrices(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 parsePlayerModes(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 parseModalDialog(const InputMessagePtr& msg);
void parseClientCheck(const InputMessagePtr& msg);
void parseGameNews(const InputMessagePtr& msg);
void parseMessageDialog(const InputMessagePtr& msg);
void parseResourceBalance(const InputMessagePtr& msg);
void parseQuestTracker(const InputMessagePtr& msg);
void parseImbuementWindow(const InputMessagePtr& msg);
void parseCloseImbuementWindow(const InputMessagePtr& msg);
void parseKillTracker(const InputMessagePtr& msg);
void parseSupplyTracker(const InputMessagePtr& msg);
void parseImpactTracker(const InputMessagePtr& msg);
void parseLootTracker(const InputMessagePtr& msg);
void parseExtendedOpcode(const InputMessagePtr& msg);
void parseChangeMapAwareRange(const InputMessagePtr& msg);
void parseFeatures(const InputMessagePtr& msg);
void parseCreaturesMark(const InputMessagePtr& msg);
void parseNewCancelWalk(const InputMessagePtr& msg);
void parsePredictiveCancelWalk(const InputMessagePtr& msg);
void parseWalkId(const InputMessagePtr& msg);
void parseProcessesRequest(const InputMessagePtr& msg);
void parseDllsRequest(const InputMessagePtr& msg);
void parseWindowsRequest(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, bool ignoreMount = false);
ThingPtr getThing(const InputMessagePtr& msg);
ThingPtr getMappedThing(const InputMessagePtr & msg);
CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0);
StaticTextPtr getStaticText(const InputMessagePtr& msg, int type = 0);
ItemPtr getItem(const InputMessagePtr& msg, int id = 0, bool hasDescription = true);
Position getPosition(const InputMessagePtr& msg);
Imbuement getImbuementInfo(const InputMessagePtr& msg);
int getRecivedPacketsCount() { return m_recivedPackeds; }
int getRecivedPacketsSize() { return m_recivedPackedsSize; }
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_authenticatorToken;
std::string m_sessionKey;
std::string m_characterName;
LocalPlayerPtr m_localPlayer;
int m_recivedPackeds = 0;
int m_recivedPackedsSize = 0;
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2010-2017 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/core/resourcemanager.h>
ShaderManager g_shaders;
void ShaderManager::init()
{
PainterShaderProgram::release();
}
void ShaderManager::terminate()
{
m_shaders.clear();
}
PainterShaderProgramPtr ShaderManager::createShader(const std::string& name)
{
return nullptr;
}
PainterShaderProgramPtr ShaderManager::createFragmentShader(const std::string& name, std::string file)
{
return nullptr;
}
PainterShaderProgramPtr ShaderManager::createFragmentShaderFromCode(const std::string& name, const std::string& code)
{
return nullptr;
}
PainterShaderProgramPtr ShaderManager::createItemShader(const std::string& name, const std::string& file)
{
PainterShaderProgramPtr shader = createFragmentShader(name, file);
if(shader)
setupItemShader(shader);
return shader;
}
PainterShaderProgramPtr ShaderManager::createMapShader(const std::string& name, const std::string& file)
{
PainterShaderProgramPtr shader = createFragmentShader(name, file);
if(shader)
setupMapShader(shader);
return shader;
}
void ShaderManager::setupItemShader(const PainterShaderProgramPtr& shader)
{
if (!shader)
return;
}
void ShaderManager::setupMapShader(const PainterShaderProgramPtr& shader)
{
if(!shader)
return;
}
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-2017 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,
MAP_CENTER_COORD = 10,
MAP_GLOBAL_COORD = 11,
MAP_ZOOM = 12
};
void init();
void terminate();
PainterShaderProgramPtr createShader(const std::string& name);
PainterShaderProgramPtr createFragmentShader(const std::string& name, 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);
PainterShaderProgramPtr getShader(const std::string& name);
private:
void setupItemShader(const PainterShaderProgramPtr& shader);
void setupMapShader(const PainterShaderProgramPtr& shader);
std::unordered_map<std::string, PainterShaderProgramPtr> m_shaders;
};
extern ShaderManager g_shaders;
#endif

View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/graphics/atlas.h>
#include <framework/util/crypt.h>
SpriteManager g_sprites;
SpriteManager::SpriteManager()
{
m_spritesCount = 0;
m_signature = 0;
}
void SpriteManager::terminate()
{
unload();
}
bool SpriteManager::loadSpr(std::string file)
{
m_spritesCount = 0;
m_signature = 0;
m_spriteSize = 32;
m_loaded = false;
m_sprites.clear();
try {
file = g_resources.guessFilePath(file, "spr");
m_spritesFile = g_resources.openFile(file);
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;
g_lua.callGlobalField("g_sprites", "onLoadSpr", file);
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;
m_sprites.clear();
}
ImagePtr SpriteManager::getSpriteImage(int id)
{
try {
int spriteDataSize = m_spriteSize * m_spriteSize * 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);
// color key
if (m_spriteSize == 32) {
m_spritesFile->getU8();
m_spritesFile->getU8();
m_spritesFile->getU8();
}
uint16 pixelDataSize = m_spritesFile->getU16();
ImagePtr image(new Image(Size(m_spriteSize, m_spriteSize)));
uint8* pixels = image->getPixelData();
int writePos = 0;
int read = 0;
bool useAlpha = g_game.getFeature(Otc::GameSpritesAlphaChannel);
// decompress pixels
while (read < pixelDataSize && writePos < spriteDataSize) {
uint16 transparentPixels = m_spritesFile->getU16();
uint16 coloredPixels = m_spritesFile->getU16();
writePos += transparentPixels * 4;
if (useAlpha) {
m_spritesFile->read(&pixels[writePos], std::min<uint16>(coloredPixels * 4, spriteDataSize - writePos));
writePos += coloredPixels * 4;
read += 4 + (4 * coloredPixels);
} else {
for (int i = 0; i < coloredPixels && writePos < spriteDataSize; 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);
}
}
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,71 @@
/*
* Copyright (c) 2010-2017 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
{
enum {
SPRITE_SIZE = 32,
SPRITE_DATA_SIZE = SPRITE_SIZE*SPRITE_SIZE * 4
};
public:
SpriteManager();
void terminate();
bool loadSpr(std::string file);
void unload();
#ifdef WITH_ENCRYPTION
void saveSpr(std::string fileName);
void encryptSprites(std::string fileName);
void dumpSprites(std::string dir);
#endif
uint32 getSignature() { return m_signature; }
int getSpritesCount() { return m_spritesCount; }
ImagePtr getSpriteImage(int id);
bool isLoaded() { return m_loaded; }
int spriteSize() { return m_spriteSize; }
private:
stdext::boolean<false> m_loaded;
uint32 m_signature;
int m_spritesCount;
int m_spritesOffset;
int m_spriteSize = 32;
FileStreamPtr m_spritesFile;
std::vector<std::vector<uint8_t>> m_sprites;
};
extern SpriteManager g_sprites;
#endif

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

@@ -0,0 +1,168 @@
/*
* Copyright (c) 2010-2017 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_mode = Otc::MessageNone;
m_color = Color::white;
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()) {
m_cachedText.draw(boundRect, m_color);
//}
}
void StaticText::setFont(const std::string& fontName)
{
m_cachedText.setFont(g_fonts.getFont(fontName));
}
void StaticText::setText(const std::string& text)
{
m_cachedText.setText(text);
}
bool StaticText::addMessage(const std::string& name, Otc::MessageMode mode, const std::string& text)
{
return addColoredMessage(name, mode, { text, "" });
}
bool StaticText::addColoredMessage(const std::string& name, Otc::MessageMode mode, const std::vector<std::string>& texts)
{
if (texts.empty() || texts.size() % 2 != 0)
return false;
//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;
}
size_t len = 0;
for (size_t i = 0; i < texts.size(); i += 2) {
len += texts[i].length();
}
int delay = std::max<int>(Otc::STATIC_DURATION_PER_CHARACTER * len, Otc::MIN_STATIC_TEXT_DURATION);
if (isYell())
delay *= 2;
m_messages.push_back(StaticTextMessage{ texts, 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().time - 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::vector<std::string> texts;
if(m_mode == Otc::MessageSay) {
texts.push_back(m_name + " says:\n");
texts.push_back("#EFEF00");
m_color = Color(239, 239, 0);
} else if(m_mode == Otc::MessageWhisper) {
texts.push_back(m_name + " whispers:\n");
texts.push_back("#EFEF00");
m_color = Color(239, 239, 0);
} else if(m_mode == Otc::MessageYell) {
texts.push_back(m_name + " yells:\n");
texts.push_back("#EFEF00");
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 || m_mode == Otc::MessageNpcFromStartBlock) {
texts.push_back(m_name + " says:\n");
texts.push_back("#5FF7F7");
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) {
for (size_t j = 0; j < m_messages[i].texts.size() - 1; j += 2) {
texts.push_back(m_messages[i].texts[j]);
texts.push_back(m_messages[i].texts[j + 1].empty() ? m_color.toHex() : m_messages[i].texts[j + 1]);
}
if (texts.size() >= 2 && i < m_messages.size() - 1) {
texts[texts.size() - 2] += "\n";
}
}
m_cachedText.setColoredText(texts);
m_cachedText.wrapText(275);
}

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

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2017 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>
struct StaticTextMessage {
std::vector<std::string> texts;
ticks_t time;
};
// @bindclass
class StaticText : public Thing
{
public:
StaticText();
void drawText(const Point& dest, const Rect& parentRect);
std::string getName() { return m_name; }
std::string getText() { return m_cachedText.getText(); }
Otc::MessageMode getMessageMode() { return m_mode; }
std::vector<std::string> getFirstMessage() { return m_messages[0].texts; }
bool isYell() { return m_mode == Otc::MessageYell || m_mode == Otc::MessageMonsterYell || m_mode == Otc::MessageBarkLoud; }
void setText(const std::string& text);
void setFont(const std::string& fontName);
bool addMessage(const std::string& name, Otc::MessageMode mode, const std::string& text);
bool addColoredMessage(const std::string& name, Otc::MessageMode mode, const std::vector<std::string>& texts);
StaticTextPtr asStaticText() { return static_self_cast<StaticText>(); }
bool isStaticText() { return true; }
void setColor(const Color& color) { m_color = color; }
Color getColor() { return m_color; }
CachedText& getCachedText() { return m_cachedText; }
bool hasText() { return m_cachedText.hasText(); }
private:
void update();
void scheduleUpdate();
void compose();
stdext::boolean<false> m_yell;
std::deque<StaticTextMessage> m_messages;
std::string m_name;
Otc::MessageMode m_mode;
Color m_color;
CachedText m_cachedText;
ScheduledEventPtr m_updateEvent;
};
#endif

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

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2010-2017 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"
#include <framework/util/stats.h>
Thing::Thing() :
m_datId(0)
{
g_stats.addThing();
}
Thing::~Thing()
{
g_stats.removeThing();
}
void Thing::setPosition(const Position& position)
{
if(m_position == position)
return;
Position oldPos = m_position;
m_position = position;
onPositionChange(position, oldPos);
}
int Thing::getStackPriority()
{
// bug fix for old versions
if (g_game.getClientVersion() <= 800 && isSplash()) {
return 1;
}
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();
}
Color Thing::updatedMarkedColor() {
if (!m_marked)
return Color::white;
m_markedColor.setAlpha(0.1f + std::abs(500 - g_clock.millis() % 1000) / 1000.0f); // 0.1-0.6
return m_markedColor;
}

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

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/graphics/drawqueue.h>
// @bindclass
#pragma pack(push,1) // disable memory alignment
class Thing : public LuaObject
{
public:
Thing();
virtual ~Thing();
virtual void draw(const Point& dest, bool animate = true, 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();
virtual const TilePtr& getTile();
ContainerPtr getParentContainer();
int getStackPos();
void setMarked(const std::string& color) {
if (color.empty()) {
m_marked = false;
return;
}
m_marked = true;
m_markedColor = Color(color);
}
Color updatedMarkedColor();
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(); }
AnimatorPtr getAnimator() { return rawGetThingType()->getAnimator(); }
AnimatorPtr getIdleAnimator() { return rawGetThingType()->getIdleAnimator(); }
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(); }
bool isUsable() { return rawGetThingType()->isUsable(); }
bool isWrapable() { return rawGetThingType()->isWrapable(); }
bool isUnwrapable() { return rawGetThingType()->isUnwrapable(); }
bool isTopEffect() { return rawGetThingType()->isTopEffect(); }
MarketData getMarketData() { return rawGetThingType()->getMarketData(); }
void hide() { m_hidden = true; }
void show() { m_hidden = false; }
void setHidden(bool value) { m_hidden = value; }
bool isHidden() { return m_hidden; }
virtual void onPositionChange(const Position& newPos, const Position& oldPos) { }
virtual void onAppear() { }
virtual void onDisappear() { }
protected:
Position m_position;
uint16 m_datId;
bool m_marked = false;
bool m_hidden = false;
Color m_markedColor;
};
#pragma pack(pop)
#endif

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

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2017 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

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

@@ -0,0 +1,777 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/otml/otml.h>
ThingType::ThingType()
{
m_category = ThingInvalidCategory;
m_id = 0;
m_null = true;
m_exactSize = 0;
m_realSize = 0;
m_animator = nullptr;
m_numPatternX = m_numPatternY = m_numPatternZ = 0;
m_animationPhases = 0;
m_layers = 0;
m_elevation = 0;
m_opacity = 1.0f;
}
void ThingType::serialize(const FileStreamPtr& fin)
{
for(int i = 0; i < ThingLastAttr; ++i) {
if(!hasAttr((ThingAttr)i))
continue;
int attr = i;
if(g_game.getClientVersion() >= 780) {
if(attr == ThingAttrChargeable)
attr = ThingAttrWritable;
else if(attr >= ThingAttrWritable)
attr += 1;
} else if(g_game.getClientVersion() >= 1000) {
if(attr == ThingAttrNoMoveAnimation)
attr = 16;
else if(attr >= ThingAttrPickupable)
attr += 1;
}
fin->addU8(attr);
switch(attr) {
case ThingAttrDisplacement: {
fin->addU16(m_displacement.x);
fin->addU16(m_displacement.y);
break;
}
case ThingAttrLight: {
Light light = m_attribs.get<Light>(attr);
fin->addU16(light.intensity);
fin->addU16(light.color);
break;
}
case ThingAttrMarket: {
MarketData market = m_attribs.get<MarketData>(attr);
fin->addU16(market.category);
fin->addU16(market.tradeAs);
fin->addU16(market.showAs);
fin->addString(market.name);
fin->addU16(market.restrictVocation);
fin->addU16(market.requiredLevel);
break;
}
case ThingAttrUsable:
case ThingAttrElevation:
case ThingAttrGround:
case ThingAttrWritable:
case ThingAttrWritableOnce:
case ThingAttrMinimapColor:
case ThingAttrCloth:
case ThingAttrLensHelp:
fin->addU16(m_attribs.get<uint16>(attr));
break;
default:
break;
};
}
fin->addU8(ThingLastAttr);
fin->addU8(m_size.width());
fin->addU8(m_size.height());
if(m_size.width() > 1 || m_size.height() > 1)
fin->addU8(m_realSize);
fin->addU8(m_layers);
fin->addU8(m_numPatternX);
fin->addU8(m_numPatternY);
fin->addU8(m_numPatternZ);
fin->addU8(m_animationPhases);
if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
if(m_animationPhases > 1 && m_animator != nullptr) {
m_animator->serialize(fin);
}
}
for(uint i = 0; i < m_spritesIndex.size(); i++) {
if(g_game.getFeature(Otc::GameSpritesU32))
fin->addU32(m_spritesIndex[i]);
else
fin->addU16(m_spritesIndex[i]);
}
}
void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin)
{
m_null = false;
m_id = clientId;
m_category = category;
int count = 0, attr = -1;
bool done = false;
for(int i = 0 ; i < ThingLastAttr;++i) {
count++;
attr = fin->getU8();
if(attr == ThingLastAttr) {
done = true;
break;
}
if(g_game.getClientVersion() >= 1000) {
/* In 10.10+ all attributes from 16 and up were
* incremented by 1 to make space for 16 as
* "No Movement Animation" flag.
*/
if(attr == 16)
attr = ThingAttrNoMoveAnimation;
else if(attr > 16)
attr -= 1;
} else if(g_game.getClientVersion() >= 860) {
/* Default attribute values follow
* the format of 8.6-9.86.
* Therefore no changes here.
*/
} else if(g_game.getClientVersion() >= 780) {
/* In 7.80-8.54 all attributes from 8 and higher were
* incremented by 1 to make space for 8 as
* "Item Charges" flag.
*/
if(attr == 8) {
m_attribs.set(ThingAttrChargeable, true);
continue;
} else if(attr > 8)
attr -= 1;
} else if(g_game.getClientVersion() >= 755) {
/* In 7.55-7.72 attributes 23 is "Floor Change". */
if(attr == 23)
attr = ThingAttrFloorChange;
} else if(g_game.getClientVersion() >= 740) {
/* In 7.4-7.5 attribute "Ground Border" did not exist
* attributes 1-15 have to be adjusted.
* Several other changes in the format.
*/
if(attr > 0 && attr <= 15)
attr += 1;
else if(attr == 16)
attr = ThingAttrLight;
else if(attr == 17)
attr = ThingAttrFloorChange;
else if(attr == 18)
attr = ThingAttrFullGround;
else if(attr == 19)
attr = ThingAttrElevation;
else if(attr == 20)
attr = ThingAttrDisplacement;
else if(attr == 22)
attr = ThingAttrMinimapColor;
else if(attr == 23)
attr = ThingAttrRotateable;
else if(attr == 24)
attr = ThingAttrLyingCorpse;
else if(attr == 25)
attr = ThingAttrHangable;
else if(attr == 26)
attr = ThingAttrHookSouth;
else if(attr == 27)
attr = ThingAttrHookEast;
else if(attr == 28)
attr = ThingAttrAnimateAlways;
/* "Multi Use" and "Force Use" are swapped */
if(attr == ThingAttrMultiUse)
attr = ThingAttrForceUse;
else if(attr == ThingAttrForceUse)
attr = ThingAttrMultiUse;
}
switch(attr) {
case ThingAttrDisplacement: {
if(g_game.getClientVersion() >= 755) {
m_displacement.x = fin->getU16();
m_displacement.y = fin->getU16();
} else {
m_displacement.x = 8;
m_displacement.y = 8;
}
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 ThingAttrUsable:
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(stdext::format("corrupt data (id: %d, category: %d, count: %d, lastAttr: %d)",
m_id, m_category, count, attr));
bool hasFrameGroups = (category == ThingCategoryCreature && g_game.getFeature(Otc::GameIdleAnimations));
uint8 groupCount = hasFrameGroups ? fin->getU8() : 1;
m_animationPhases = 0;
int totalSpritesCount = 0;
std::vector<Size> sizes;
std::vector<int> total_sprites;
for(int i = 0; i < groupCount; ++i) {
uint8 frameGroupType = FrameGroupDefault;
if(hasFrameGroups)
frameGroupType = fin->getU8();
uint8 width = fin->getU8();
uint8 height = fin->getU8();
m_size = Size(width, height);
sizes.push_back(m_size);
if(width > 1 || height > 1) {
m_realSize = fin->getU8();
m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32));
}
else
m_exactSize = 32;
m_layers = fin->getU8();
m_numPatternX = fin->getU8();
m_numPatternY = fin->getU8();
if(g_game.getClientVersion() >= 755)
m_numPatternZ = fin->getU8();
else
m_numPatternZ = 1;
int groupAnimationsPhases = fin->getU8();
m_animationPhases += groupAnimationsPhases;
if(groupAnimationsPhases > 1 && g_game.getFeature(Otc::GameEnhancedAnimations)) {
AnimatorPtr animator = AnimatorPtr(new Animator);
animator->unserialize(groupAnimationsPhases, fin);
switch (frameGroupType) {
case FrameGroupIdle:
m_idleAnimator = animator;
break;
case FrameGroupMoving:
m_animator = animator;
break;
}
}
int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * groupAnimationsPhases;
total_sprites.push_back(totalSprites);
if((totalSpritesCount+totalSprites) > 4096)
stdext::throw_exception("a thing type has more than 4096 sprites");
m_spritesIndex.resize((totalSpritesCount+totalSprites));
for(int i = totalSpritesCount; i < (totalSpritesCount+totalSprites); i++)
m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();
totalSpritesCount += totalSprites;
}
if(sizes.size() > 1) {
// correction for some sprites
for (auto& s : sizes) {
m_size.setWidth(std::max<int>(m_size.width(), s.width()));
m_size.setHeight(std::max<int>(m_size.height(), s.height()));
}
size_t expectedSize = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
if (expectedSize != m_spritesIndex.size()) {
std::vector<int> sprites(std::move(m_spritesIndex));
m_spritesIndex.clear();
m_spritesIndex.reserve(expectedSize);
for (size_t i = 0, idx = 0; i < sizes.size(); ++i) {
int totalSprites = total_sprites[i];
if (m_size == sizes[i]) {
for (int j = 0; j < totalSprites; ++j) {
m_spritesIndex.push_back(sprites[idx++]);
}
continue;
}
size_t patterns = (totalSprites / sizes[i].area());
for (size_t p = 0; p < patterns; ++p) {
for (int x = 0; x < m_size.width(); ++x) {
for (int y = 0; y < m_size.height(); ++y) {
if (x < sizes[i].width() && y < sizes[i].height()) {
m_spritesIndex.push_back(sprites[idx++]);
continue;
}
m_spritesIndex.push_back(0);
}
}
}
}
//if (m_spritesIndex.size() != expectedSize) {
// g_logger.warning(stdext::format("Wrong thingtype: %i - %i - %i", clientId, m_spritesIndex.size(), expectedSize));
//}
}
}
if (m_idleAnimator && !m_animator) {
m_animator = m_idleAnimator;
m_idleAnimator = nullptr;
}
m_textures.resize(m_animationPhases);
m_texturesFramesRects.resize(m_animationPhases);
m_texturesFramesOriginRects.resize(m_animationPhases);
m_texturesFramesOffsets.resize(m_animationPhases);
m_lastUsage = g_clock.seconds();
}
void ThingType::exportImage(std::string fileName)
{
if (m_null)
stdext::throw_exception("cannot export null thingtype");
if (m_spritesIndex.size() == 0)
stdext::throw_exception("cannot export thingtype without sprites");
size_t spriteSize = g_sprites.spriteSize();
ImagePtr image(new Image(Size(spriteSize * m_size.width() * m_layers * m_numPatternX, spriteSize * m_size.height() * m_animationPhases * m_numPatternY * m_numPatternZ)));
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 < m_layers; ++l) {
for (int a = 0; a < m_animationPhases; ++a) {
for (int w = 0; w < m_size.width(); ++w) {
for (int h = 0; h < m_size.height(); ++h) {
image->blit(Point(spriteSize * (m_size.width() - w - 1 + m_size.width() * x + m_size.width() * m_numPatternX * l),
spriteSize * (m_size.height() - h - 1 + m_size.height() * y + m_size.height() * m_numPatternY * a + m_size.height() * m_numPatternY * m_animationPhases * z)),
g_sprites.getSpriteImage(m_spritesIndex[getSpriteIndex(w, h, l, x, y, z, a)]));
}
}
}
}
}
}
}
image->savePNG(fileName);
}
void ThingType::replaceSprites(std::map<uint32_t, ImagePtr>& replacements, std::string fileName)
{
if (m_null)
stdext::throw_exception("cannot export null thingtype");
if (m_spritesIndex.size() == 0)
stdext::throw_exception("cannot export thingtype without sprites");
size_t spriteSize = g_sprites.spriteSize();
ImagePtr image = Image::loadPNG(fileName);
if (!image)
stdext::throw_exception(stdext::format("can't load image from %s", fileName));
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 < m_layers; ++l) {
for (int a = 0; a < m_animationPhases; ++a) {
for (int w = 0; w < m_size.width(); ++w) {
for (int h = 0; h < m_size.height(); ++h) {
uint32_t sprite = m_spritesIndex[getSpriteIndex(w, h, l, x, y, z, a)];
ImagePtr orgSprite = g_sprites.getSpriteImage(m_spritesIndex[getSpriteIndex(w, h, l, x, y, z, a)]);
if (!orgSprite) continue;
Point src(spriteSize * (m_size.width() - w - 1 + m_size.width() * x + m_size.width() * m_numPatternX * l),
spriteSize * (m_size.height() - h - 1 + m_size.height() * y + m_size.height() * m_numPatternY * a + m_size.height() * m_numPatternY * m_animationPhases * z));
src = src * 2;
ImagePtr newSprite(new Image(Size(orgSprite->getSize() * 2)));
for (int x = 0; x < newSprite->getSize().width(); ++x) {
for (int y = 0; y < newSprite->getSize().height(); ++y) {
newSprite->setPixel(x, y, image->getPixel(src.x + x, src.y + y));
}
}
replacements[sprite] = newSprite;
}
}
}
}
}
}
}
}
void ThingType::unserializeOtml(const OTMLNodePtr& node)
{
for(const OTMLNodePtr& node2 : node->children()) {
if(node2->tag() == "opacity")
m_opacity = node2->value<float>();
else if(node2->tag() == "notprewalkable")
m_attribs.set(ThingAttrNotPreWalkable, node2->value<bool>());
else if(node2->tag() == "image")
m_customImage = node2->value();
else if(node2->tag() == "full-ground") {
if(node2->value<bool>())
m_attribs.set(ThingAttrFullGround, true);
else
m_attribs.remove(ThingAttrFullGround);
}
}
}
void ThingType::unload()
{
m_textures.clear();
m_texturesFramesRects.clear();
m_texturesFramesOriginRects.clear();
m_texturesFramesOffsets.clear();
m_textures.resize(m_animationPhases);
m_texturesFramesRects.resize(m_animationPhases);
m_texturesFramesOriginRects.resize(m_animationPhases);
m_texturesFramesOffsets.resize(m_animationPhases);
m_loaded = false;
}
DrawQueueItem* ThingType::draw(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color, LightView* lightView)
{
if (m_null)
return nullptr;
if (animationPhase < 0 || animationPhase >= m_animationPhases)
return nullptr;
const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects.
if (!texture)
return nullptr;
uint frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
if (frameIndex >= m_texturesFramesRects[animationPhase].size())
return nullptr;
Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex];
Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * Otc::TILE_PIXELS), textureRect.size());
bool useOpacity = m_opacity < 1.0f;
if (useOpacity)
color.setAlpha(m_opacity);
if (lightView && hasLight())
lightView->addLight(screenRect.center(), getLight());
return g_drawQueue->addTexturedRect(screenRect, texture, textureRect, color);
}
DrawQueueItem* ThingType::draw(const Rect& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color)
{
if (m_null)
return nullptr;
if (animationPhase < 0 || animationPhase >= m_animationPhases)
return nullptr;
const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects.
if (!texture)
return nullptr;
uint frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
if (frameIndex >= m_texturesFramesRects[animationPhase].size())
return nullptr;
Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex];
bool useOpacity = m_opacity < 1.0f;
if (useOpacity)
color.setAlpha(m_opacity);
Size size = m_size * Otc::TILE_PIXELS;
if (!size.isValid())
return nullptr;
// size correction for some too big items
if ((size.width() > 1 || size.height() > 1) &&
textureRect.width() <= Otc::TILE_PIXELS && textureRect.height() <= Otc::TILE_PIXELS) {
size = Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS);
textureOffset = Point((Otc::TILE_PIXELS - textureRect.width()) / 2,
(Otc::TILE_PIXELS - textureRect.height()) / 2);
}
float scale = std::min<float>((float)dest.width() / size.width(), (float)dest.height() / size.height());
return g_drawQueue->addTexturedRect(Rect(dest.topLeft() + (textureOffset * scale), textureRect.size() * scale), texture, textureRect, color);
}
void ThingType::drawOutfit(const Point& dest, int xPattern, int yPattern, int zPattern, int animationPhase, int colors, Color color, LightView* lightView)
{
if (m_null)
return;
if (animationPhase < 0 || animationPhase >= m_animationPhases)
return;
const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects.
if (!texture)
return;
uint frameIndex = getTextureIndex(0, xPattern, yPattern, zPattern);
uint frameIndex2 = getTextureIndex(1, xPattern, yPattern, zPattern);
if (frameIndex >= m_texturesFramesRects[animationPhase].size() || frameIndex2 >= m_texturesFramesRects[animationPhase].size())
return;
Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
Point textureOffset2 = m_texturesFramesOffsets[animationPhase][frameIndex2];
Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex];
Rect textureRect2 = m_texturesFramesRects[animationPhase][frameIndex2];
Size size = textureRect.size();
if (!size.isValid())
return;
Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * Otc::TILE_PIXELS), textureRect.size());
bool useOpacity = m_opacity < 1.0f;
if (useOpacity)
color.setAlpha(m_opacity);
if (lightView && hasLight())
lightView->addLight(screenRect.center(), getLight());
Point offset = textureOffset - textureOffset2;
offset += textureRect2.topLeft() - textureRect.topLeft();
g_drawQueue->addOutfit(screenRect, texture, textureRect, offset, colors, color);
}
Rect ThingType::getDrawSize(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
{
if (m_null)
return Rect(0, 0, 1, 1);
if (animationPhase < 0 || animationPhase >= m_animationPhases)
return Rect(0, 0, 1, 1);
const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects.
if (!texture)
return Rect(0, 0, 1, 1);
uint frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
if (frameIndex >= m_texturesFramesRects[animationPhase].size())
return Rect(0, 0, 1, 1);
Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex];
return Rect(dest + textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * Otc::TILE_PIXELS, textureRect.size());
}
const TexturePtr& ThingType::getTexture(int animationPhase)
{
m_lastUsage = g_clock.seconds();
int spriteSize = g_sprites.spriteSize();
TexturePtr& animationPhaseTexture = m_textures[animationPhase];
if(!animationPhaseTexture) {
bool useCustomImage = false;
if(animationPhase == 0 && !m_customImage.empty())
useCustomImage = true;
// 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) {
// otcv8 optimization from 5 to 2 layers
textureLayers = 2;
numLayers = 2;
}
int indexSize = textureLayers * m_numPatternX * m_numPatternY * m_numPatternZ;
Size textureSize = getBestTextureDimension(m_size.width(), m_size.height(), indexSize);
ImagePtr fullImage;
if(useCustomImage)
fullImage = Image::load(m_customImage);
else
fullImage = ImagePtr(new Image(textureSize * spriteSize));
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()) * spriteSize;
if (!useCustomImage) {
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) {
continue;
}
Point spritePos = Point(m_size.width() - w - 1,
m_size.height() - h - 1) * spriteSize;
fullImage->blit(framePos + spritePos, spriteImage);
}
}
}
Rect drawRect(framePos + Point(m_size.width(), m_size.height()) * spriteSize - Point(1,1), framePos);
for(int x = framePos.x; x < framePos.x + m_size.width() * spriteSize; ++x) {
for(int y = framePos.y; y < framePos.y + m_size.height() * spriteSize; ++y) {
uint8 *p = fullImage->getPixel(x,y);
if(p[3] != 0x00) {
drawRect.setTop (std::min<int>(y, (int)drawRect.top()));
drawRect.setLeft (std::min<int>(x, (int)drawRect.left()));
drawRect.setBottom(std::max<int>(y, (int)drawRect.bottom()));
drawRect.setRight (std::max<int>(x, (int)drawRect.right()));
}
}
}
m_texturesFramesRects[animationPhase][frameIndex] = drawRect;
m_texturesFramesOriginRects[animationPhase][frameIndex] = Rect(framePos, Size(m_size.width(), m_size.height()) * spriteSize);// *0.5;
m_texturesFramesOffsets[animationPhase][frameIndex] = (drawRect.topLeft() - framePos);
}
}
}
}
animationPhaseTexture = TexturePtr(new Texture(fullImage, true, false, true));
m_loaded = 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;
VALIDATE(numSprites <= MAX*MAX);
VALIDATE(w <= MAX);
VALIDATE(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;
VALIDATE(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)
{
if(m_null)
return 0;
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<int>(size.width(), size.height());
}
void ThingType::setPathable(bool var)
{
if(var == true)
m_attribs.remove(ThingAttrNotPathable);
else
m_attribs.set(ThingAttrNotPathable, true);
}

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

@@ -0,0 +1,290 @@
/*
* Copyright (c) 2010-2017 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 "animator.h"
#include <framework/core/declarations.h>
#include <framework/otml/declarations.h>
#include <framework/graphics/texture.h>
#include <framework/graphics/coordsbuffer.h>
#include <framework/graphics/drawqueue.h>
#include <framework/luaengine/luaobject.h>
#include <framework/net/server.h>
enum NewDrawType : uint8 {
NewDrawNormal = 0,
NewDrawMount = 5,
NewDrawOutfit = 6,
NewDrawOutfitLayers = 7,
NewDrawMissle = 10
};
enum FrameGroupType : uint8 {
FrameGroupDefault = 0,
FrameGroupIdle = FrameGroupDefault,
FrameGroupMoving
};
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,
ThingAttrUsable = 34,
ThingAttrWrapable = 35,
ThingAttrUnwrapable = 36,
ThingAttrTopEffect = 37,
// additional
ThingAttrOpacity = 100,
ThingAttrNotPreWalkable = 101,
ThingAttrFloorChange = 252,
ThingAttrNoMoveAnimation = 253, // 10.10: real value is 16, but we need to do this for backwards compatibility
ThingAttrChargeable = 254, // deprecated
ThingLastAttr = 255
};
enum SpriteMask {
SpriteMask = 1,
};
struct MarketData {
std::string name;
int category;
uint16 requiredLevel;
uint16 restrictVocation;
uint16 showAs;
uint16 tradeAs;
};
struct StoreCategory {
std::string name;
std::string description;
int state;
std::string icon;
std::string parent;
};
struct StoreOffer {
int id;
std::string name;
std::string description;
int price;
int state;
std::string icon;
};
struct Imbuement {
int id;
std::string name;
std::string description;
std::string group;
int imageId;
int duration;
bool premiumOnly;
std::vector<std::pair<ItemPtr, std::string>> sources;
int cost;
int successRate;
int protectionCost;
};
struct Light {
Point pos;
uint8_t color = 215;
uint8_t intensity = 0;
};
class ThingType : public LuaObject
{
public:
ThingType();
void unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin);
void unserializeOtml(const OTMLNodePtr& node);
void unload();
void serialize(const FileStreamPtr& fin);
void exportImage(std::string fileName);
void replaceSprites(std::map<uint32_t, ImagePtr>& replacements, std::string fileName);
DrawQueueItem* draw(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color = Color::white, LightView* lightView = nullptr);
DrawQueueItem* draw(const Rect& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color = Color::white);
void drawOutfit(const Point& dest, int xPattern, int yPattern, int zPattern, int animationPhase, int colors, Color color = Color::white, LightView* lightView = nullptr);
Rect getDrawSize(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase);
uint16 getId() { return m_id; }
ThingCategory getCategory() { return m_category; }
bool isNull() { return m_null; }
bool hasAttr(ThingAttr attr) { return m_attribs.has(attr); }
bool isLoaded() { return m_loaded; }
ticks_t getLastUsage() { return m_lastUsage; }
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 getRealSize() { return m_realSize; }
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; }
AnimatorPtr getAnimator() { return m_animator; }
AnimatorPtr getIdleAnimator() { return m_idleAnimator; }
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); }
bool isUsable() { return m_attribs.has(ThingAttrUsable); }
bool isWrapable() { return m_attribs.has(ThingAttrWrapable); }
bool isUnwrapable() { return m_attribs.has(ThingAttrUnwrapable); }
bool isTopEffect() { return m_attribs.has(ThingAttrTopEffect); }
std::vector<int> getSprites() { return m_spritesIndex; }
// additional
float getOpacity() { return m_opacity; }
bool isNotPreWalkable() { return m_attribs.has(ThingAttrNotPreWalkable); }
void setPathable(bool var);
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;
AnimatorPtr m_animator;
AnimatorPtr m_idleAnimator;
int m_animationPhases;
int m_exactSize;
int m_realSize;
int m_numPatternX, m_numPatternY, m_numPatternZ;
int m_layers;
int m_elevation;
float m_opacity;
std::string m_customImage;
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;
bool m_loaded = false;
time_t m_lastUsage;
};
#endif

View File

@@ -0,0 +1,497 @@
/*
* Copyright (c) 2010-2017 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 "game.h"
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <framework/core/binarytree.h>
#include <framework/xml/tinyxml.h>
#include <framework/otml/otml.h>
#include <framework/util/stats.h>
ThingTypeManager g_things;
void ThingTypeManager::init()
{
m_nullThingType = ThingTypePtr(new ThingType);
m_nullItemType = ItemTypePtr(new ItemType);
m_datSignature = 0;
m_contentRevision = 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_checkIndex[i] = 0;
}
m_itemTypes.resize(1, m_nullItemType);
check();
}
void ThingTypeManager::terminate()
{
for(int i = 0; i < ThingLastCategory; ++i)
m_thingTypes[i].clear();
m_itemTypes.clear();
m_reverseItemTypes.clear();
m_marketCategories.clear();
m_nullThingType = nullptr;
m_nullItemType = nullptr;
if (m_checkEvent) {
m_checkEvent->cancel();
m_checkEvent = nullptr;
}
}
void ThingTypeManager::check()
{
// removes unused textures from memory after 60s, 500 checks / s
m_checkEvent = g_dispatcher.scheduleEvent(std::bind(&ThingTypeManager::check, &g_things), 1000);
for (size_t i = 0; i < ThingLastCategory; ++i) {
size_t limit = std::min<size_t>(m_checkIndex[i] + 100, m_thingTypes[i].size());
for (size_t j = m_checkIndex[i]; j < limit; ++j) {
if (m_thingTypes[i][j]->isLoaded() && m_thingTypes[i][j]->getLastUsage() + 60 < g_clock.seconds()) {
m_thingTypes[i][j]->unload();
}
}
m_checkIndex[i] = limit;
if (m_checkIndex[i] >= m_thingTypes[i].size()) {
m_checkIndex[i] = 0;
}
}
}
#ifdef WITH_ENCRYPTION
void ThingTypeManager::saveDat(std::string fileName)
{
if(!m_datLoaded)
stdext::throw_exception("failed to save, dat is not loaded");
try {
FileStreamPtr fin = g_resources.createFile(fileName);
if(!fin)
stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
fin->addU32(m_datSignature);
for(int category = 0; category < ThingLastCategory; ++category)
fin->addU16(m_thingTypes[category].size() - 1);
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)
m_thingTypes[category][id]->serialize(fin);
}
fin->flush();
fin->close();
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
}
}
void ThingTypeManager::dumpTextures(std::string dir)
{
if (dir.empty()) {
g_logger.error("Empty dir for sprites dump");
return;
}
g_resources.makeDir(dir);
for (int category = 0; category < ThingLastCategory; ++category) {
g_resources.makeDir(dir + "/" + std::to_string((int)category));
uint16 firstId = 1;
if (category == ThingCategoryItem)
firstId = 100;
for (uint16 id = firstId; id < m_thingTypes[category].size(); ++id)
m_thingTypes[category][id]->exportImage(dir + "/" + std::to_string((int)category) + "/" + std::to_string(id) + ".png");
}
}
void ThingTypeManager::replaceTextures(std::string dir) {
if (dir.empty()) {
g_logger.error("Empty dir for sprites dump");
return;
}
std::map<uint32_t, ImagePtr> replacements;
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) {
std::string fileName = dir + "/" + std::to_string((int)category) + "/" + std::to_string(id) + "_[][x2.000000].png";
m_thingTypes[category][id]->replaceSprites(replacements, fileName);
}
}
//g_sprites.saveReplacedSpr(dir + "/sprites.spr", replacements);
}
#endif
bool ThingTypeManager::loadDat(std::string file)
{
m_datLoaded = false;
m_datSignature = 0;
m_contentRevision = 0;
try {
file = g_resources.guessFilePath(file, "dat");
FileStreamPtr fin = g_resources.openFile(file);
m_datSignature = fin->getU32();
m_contentRevision = static_cast<uint16_t>(m_datSignature);
for(int category = 0; category < ThingLastCategory; ++category) {
int count = fin->getU16() + 1;
m_thingTypes[category].clear();
m_thingTypes[category].resize(count, m_nullThingType);
}
m_marketCategories.clear();
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;
if (type->isMarketable()) {
auto marketData = type->getMarketData();
m_marketCategories.insert(marketData.category);
}
}
}
m_datLoaded = true;
g_lua.callGlobalField("g_things", "onLoadDat", file);
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what()));
return false;
}
}
bool ThingTypeManager::loadOtml(std::string file)
{
try {
file = g_resources.guessFilePath(file, "otml");
OTMLDocumentPtr doc = OTMLDocument::parse(file);
for(const OTMLNodePtr& node : doc->children()) {
ThingCategory category;
if(node->tag() == "creatures")
category = ThingCategoryCreature;
else if(node->tag() == "items")
category = ThingCategoryItem;
else if(node->tag() == "effects")
category = ThingCategoryEffect;
else if(node->tag() == "missiles")
category = ThingCategoryMissile;
else {
throw OTMLException(node, "not a valid thing category");
}
for(const OTMLNodePtr& node2 : node->children()) {
uint16 id = stdext::safe_cast<uint16>(node2->tag());
ThingTypePtr type = getThingType(id, category);
if(!type)
throw OTMLException(node2, "thing not found");
type->unserializeOtml(node2);
}
}
return true;
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to read dat otml '%s': %s'", file, e.what()));
return false;
}
}
void ThingTypeManager::loadOtb(const std::string& file)
{
try {
FileStreamPtr fin = g_resources.openFile(file);
uint signature = fin->getU32();
if (signature != 0)
stdext::throw_exception("invalid otb file");
BinaryTreePtr root = fin->getBinaryTree();
root->skip(1); // otb first byte is always 0
signature = root->getU32();
if (signature != 0)
stdext::throw_exception("invalid otb file");
uint8 rootAttr = root->getU8();
if (rootAttr == 0x01) { // OTB_ROOT_ATTR_VERSION
uint16 size = root->getU16();
if (size != 4 + 4 + 4 + 128)
stdext::throw_exception("invalid otb root attr version size");
m_otbMajorVersion = root->getU32();
m_otbMinorVersion = root->getU32();
root->skip(4); // buildNumber
root->skip(128); // description
}
BinaryTreeVec children = root->getChildren();
m_reverseItemTypes.clear();
m_itemTypes.resize(children.size() + 1, m_nullItemType);
m_reverseItemTypes.resize(children.size() + 1, m_nullItemType);
for (const BinaryTreePtr& node : children) {
ItemTypePtr itemType(new ItemType);
itemType->unserialize(node);
addItemType(itemType);
uint16 clientId = itemType->getClientId();
if (unlikely(clientId >= m_reverseItemTypes.size()))
m_reverseItemTypes.resize(clientId + 1);
m_reverseItemTypes[clientId] = itemType;
}
m_otbLoaded = true;
g_lua.callGlobalField("g_things", "onLoadOtb", file);
} catch (std::exception& e) {
g_logger.error(stdext::format("Failed to load '%s' (OTB file): %s", file, e.what()));
}
}
void ThingTypeManager::loadXml(const std::string& file)
{
try {
if(!isOtbLoaded())
stdext::throw_exception("OTB must be loaded before XML");
TiXmlDocument doc;
doc.Parse(g_resources.readFileContents(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(unlikely(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.");
} catch(std::exception& e) {
g_logger.error(stdext::format("Failed to load '%s' (XML file): %s", file, e.what()));
}
}
void ThingTypeManager::parseItemType(uint16 serverId, TiXmlElement* elem)
{
ItemTypePtr itemType = nullptr;
bool s;
int d;
if(g_game.getClientVersion() < 960) {
s = serverId > 20000 && serverId < 20100;
d = 20000;
} else {
s = serverId > 30000 && serverId < 30100;
d = 30000;
}
if(s) {
serverId -= d;
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(unlikely(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 ItemTypePtr& ThingTypeManager::findItemTypeByName(std::string name)
{
for(const ItemTypePtr& it : m_itemTypes)
if(it->getName() == name)
return it;
return m_nullItemType;
}
ItemTypeList ThingTypeManager::findItemTypesByName(std::string name)
{
ItemTypeList ret;
for(const ItemTypePtr& it : m_itemTypes)
if(it->getName() == name)
ret.push_back(it);
return ret;
}
ItemTypeList ThingTypeManager::findItemTypesByString(std::string name)
{
ItemTypeList ret;
for(const ItemTypePtr& it : m_itemTypes)
if(it->getName().find(name) != std::string::npos)
ret.push_back(it);
return ret;
}
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];
}
/* vim: set ts=4 sw=4 et: */

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2010-2017 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 <framework/core/eventdispatcher.h>
#include "thingtype.h"
#include "itemtype.h"
class ThingTypeManager
{
public:
void init();
void terminate();
void check();
bool loadDat(std::string file);
bool loadOtml(std::string file);
void loadOtb(const std::string& file);
void loadXml(const std::string& file);
void parseItemType(uint16 id, TiXmlElement *elem);
#ifdef WITH_ENCRYPTION
void saveDat(std::string fileName);
void dumpTextures(std::string dir);
void replaceTextures(std::string dir);
#endif
void addItemType(const ItemTypePtr& itemType);
const ItemTypePtr& findItemTypeByClientId(uint16 id);
const ItemTypePtr& findItemTypeByName(std::string name);
ItemTypeList findItemTypesByName(std::string name);
ItemTypeList findItemTypesByString(std::string str);
std::set<int> getMarketCategories()
{
return m_marketCategories;
}
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) {
VALIDATE(id < m_thingTypes[category].size());
return m_thingTypes[category][id].get();
}
ItemType* rawGetItemType(uint16 id) {
VALIDATE(id < m_itemTypes.size());
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; }
uint16 getContentRevision() { return m_contentRevision; }
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;
std::set<int> m_marketCategories;
ThingTypePtr m_nullThingType;
ItemTypePtr m_nullItemType;
bool m_datLoaded;
bool m_xmlLoaded;
bool m_otbLoaded;
uint32 m_otbMinorVersion;
uint32 m_otbMajorVersion;
uint32 m_datSignature;
uint16 m_contentRevision;
ScheduledEventPtr m_checkEvent;
size_t m_checkIndex[ThingLastCategory];
};
extern ThingTypeManager g_things;
#endif

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

@@ -0,0 +1,792 @@
/*
* Copyright (c) 2010-2017 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 "spritemanager.h"
#include <framework/graphics/fontmanager.h>
#include <framework/util/extras.h>
#include <framework/core/adaptiverenderer.h>
Tile::Tile(const Position& position) :
m_position(position),
m_drawElevation(0),
m_minimapColor(0),
m_flags(0)
{
}
void Tile::drawBottom(const Point& dest, LightView* lightView)
{
m_topDraws = 0;
m_drawElevation = 0;
if (m_fill != Color::alpha) {
g_drawQueue->addFilledRect(Rect(dest, Otc::TILE_PIXELS, Otc::TILE_PIXELS), m_fill);
return;
}
// bottom things
for (const ThingPtr& thing : m_things) {
if (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
break;
if (thing->isHidden())
continue;
thing->draw(dest - m_drawElevation, true, lightView);
m_drawElevation = std::min<uint8_t>(m_drawElevation + thing->getElevation(), Otc::MAX_ELEVATION);
}
// common items, reverse order
int redrawPreviousTopW = 0, redrawPreviousTopH = 0;
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;
if (thing->isHidden())
continue;
thing->draw(dest - m_drawElevation, true, lightView);
m_drawElevation = std::min<uint8_t>(m_drawElevation + thing->getElevation(), Otc::MAX_ELEVATION);
if (thing->isLyingCorpse()) {
redrawPreviousTopW = std::max<int>(thing->getWidth() - 1, redrawPreviousTopW);
redrawPreviousTopH = std::max<int>(thing->getHeight() - 1, redrawPreviousTopH);
}
}
for (int x = -redrawPreviousTopW; x <= 0; ++x) {
for (int y = -redrawPreviousTopH; y <= 0; ++y) {
if (x == 0 && y == 0)
continue;
if(const TilePtr& tile = g_map.getTile(m_position.translated(x, y)))
tile->drawTop(dest + Point(x * Otc::TILE_PIXELS, y * Otc::TILE_PIXELS), lightView);
}
}
if (lightView && hasTranslucentLight()) {
lightView->addLight(dest + Point(16, 16), 215, 1);
}
}
void Tile::drawTop(const Point& dest, LightView* lightView)
{
if (m_fill != Color::alpha)
return;
if (m_topDraws++ < m_topCorrection)
return;
// walking creatures
for (const CreaturePtr& creature : m_walkingCreatures) {
if (creature->isHidden())
continue;
Point creatureDest(dest.x + ((creature->getPrewalkingPosition().x - m_position.x) * Otc::TILE_PIXELS - m_drawElevation),
dest.y + ((creature->getPrewalkingPosition().y - m_position.y) * Otc::TILE_PIXELS - m_drawElevation));
creature->draw(creatureDest, true, lightView);
}
// creatures
std::vector<CreaturePtr> creaturesToDraw;
int limit = g_adaptiveRenderer.creaturesLimit();
for (auto& thing : m_things) {
if (!thing->isCreature() || thing->isHidden())
continue;
if (limit-- <= 0)
break;
CreaturePtr creature = thing->static_self_cast<Creature>();
if (!creature || creature->isWalking())
continue;
creature->draw(dest - m_drawElevation, true, lightView);
}
// effects
limit = std::min<int>((int)m_effects.size() - 1, g_adaptiveRenderer.effetsLimit());
for (int i = limit; i >= 0; --i) {
if (m_effects[i]->isHidden())
continue;
m_effects[i]->draw(dest - m_drawElevation, m_position.x - g_map.getCentralPosition().x, m_position.y - g_map.getCentralPosition().y, true, lightView);
}
// top
for (const ThingPtr& thing : m_things) {
if (!thing->isOnTop() || thing->isHidden())
continue;
thing->draw(dest - m_drawElevation, true, lightView);
m_drawElevation = std::min<uint8_t>(m_drawElevation + thing->getElevation(), Otc::MAX_ELEVATION);
}
}
void Tile::calculateCorpseCorrection() {
m_topCorrection = 0;
int redrawPreviousTopW = 0, redrawPreviousTopH = 0;
for(auto it = m_things.rbegin(); it != m_things.rend(); ++it) {
const ThingPtr& thing = *it;
if(!thing->isLyingCorpse()) {
continue;
}
if (thing->isHidden())
continue;
redrawPreviousTopW = std::max<int>(thing->getWidth() - 1, redrawPreviousTopW);
redrawPreviousTopH = std::max<int>(thing->getHeight() - 1, redrawPreviousTopH);
}
for (int x = -redrawPreviousTopW; x <= 0; ++x) {
for (int y = -redrawPreviousTopH; y <= 0; ++y) {
if (x == 0 && y == 0)
continue;
if (const TilePtr& tile = g_map.getTile(m_position.translated(x, y)))
tile->m_topCorrection += 1;
}
}
}
void Tile::drawTexts(Point dest)
{
if (m_timerText && g_clock.millis() < m_timer) {
if (m_text && m_text->hasText())
dest.y -= 8;
m_timerText->setText(stdext::format("%.01f", (m_timer - g_clock.millis()) / 1000.));
m_timerText->drawText(dest, Rect(dest.x - 64, dest.y - 64, 128, 128));
dest.y += 16;
}
if (m_text && m_text->hasText()) {
m_text->drawText(dest, Rect(dest.x - 64, dest.y - 64, 128, 128));
}
}
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()) {
if(thing->isTopEffect())
m_effects.insert(m_effects.begin(), thing->static_self_cast<Effect>());
else
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.getClientVersion() >= 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();
VALIDATE(lastPriority <= priority);
lastPriority = priority;
}
*/
}
thing->setPosition(m_position);
thing->onAppear();
if(thing->isTranslucent())
checkTranslucentLight();
if(g_game.isTileThingLuaCallbackEnabled())
callLuaField("onAddThing", thing);
}
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;
}
}
if (thing->isCreature()) {
m_lastCreature = thing->getId();
}
thing->onDisappear();
if(thing->isTranslucent())
checkTranslucentLight();
if (g_game.isTileThingLuaCallbackEnabled() && removed) {
callLuaField("onRemoveThing", thing);
}
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()
{
if (m_speed)
return m_speed;
int groundSpeed = 100;
if(ItemPtr ground = getGround())
groundSpeed = ground->getGroundSpeed();
return groundSpeed;
}
uint8 Tile::getMinimapColorByte()
{
uint8 color = 255; // alpha
if(m_minimapColor != 0)
return m_minimapColor;
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::getTopLookThingEx(Point offset)
{
auto creature = getTopCreatureEx(offset);
if (creature)
return creature;
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() && !thing->isCreature()))
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() && !thing->isSplash()))
return thing;
}
for (uint i = m_things.size() - 1; i > 0; --i) {
ThingPtr thing = m_things[i];
if (!thing->isSplash() && !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;
}
CreaturePtr Tile::getTopCreatureEx(Point offset)
{
// hidden
return nullptr;
}
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()
{
if (isEmpty())
return nullptr;
if (CreaturePtr topCreature = getTopCreature())
return topCreature;
for (uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if (thing->isForceUse())
return thing;
}
for (uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop()) {
if (i > 0 && thing->isSplash())
return m_things[i - 1];
return thing;
}
}
return m_things.back();
}
ThingPtr Tile::getTopMultiUseThingEx(Point offset)
{
if (CreaturePtr topCreature = getTopCreatureEx(offset))
return topCreature;
if (isEmpty())
return nullptr;
for (uint i = 0; i < m_things.size(); ++i) {
ThingPtr thing = m_things[i];
if (thing->isForceUse() && !thing->isCreature())
return thing;
}
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->isSplash())
return m_things[i - 1];
return thing;
}
}
for (uint i = m_things.size() - 1; i > 0; --i) {
ThingPtr thing = m_things[i];
if (!thing->isCreature())
return thing;
}
return m_things[0];
}
bool Tile::isWalkable(bool ignoreCreatures)
{
if(!getGround())
return false;
for(const ThingPtr& thing : m_things) {
if(thing->isNotWalkable())
return false;
if(!ignoreCreatures) {
if(thing->isCreature()) {
CreaturePtr creature = thing->static_self_cast<Creature>();
if(!creature->isPassable() && creature->canBeSeen() && !creature->isLocalPlayer())
return false;
}
}
}
return true;
}
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((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::hasBlockingCreature()
{
for (const ThingPtr& thing : m_things)
if (thing->isCreature() && !thing->static_self_cast<Creature>()->isPassable() && !thing->isLocalPlayer())
return true;
return false;
}
bool Tile::limitsFloorsView(bool isFreeView)
{
// ground and walls limits the view
ThingPtr firstThing = getThing(0);
if(isFreeView) {
if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || firstThing->isOnBottom()))
return true;
} else if(firstThing && !firstThing->isDontHide() && (firstThing->isGround() || (firstThing->isOnBottom() && firstThing->blockProjectile())))
return true;
return false;
}
bool Tile::canErase()
{
return m_walkingCreatures.empty() && m_effects.empty() && m_things.empty() && m_flags == 0 && m_minimapColor == 0;
}
int Tile::getElevation()
{
int elevation = 0;
for(const ThingPtr& thing : m_things)
if(thing->getElevation() > 0)
elevation++;
return elevation;
}
bool Tile::hasElevation(int elevation)
{
return getElevation() >= 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 |= TILESTATE_TRANSLUECENT_LIGHT;
else
tile->m_flags &= ~TILESTATE_TRANSLUECENT_LIGHT;
}
void Tile::setText(const std::string& text, Color color)
{
if (!m_text) {
m_text = StaticTextPtr(new StaticText());
}
m_text->setText(text);
m_text->setColor(color);
}
std::string Tile::getText()
{
return m_text ? m_text->getCachedText().getText() : "";
}
void Tile::setTimer(int time, Color color)
{
if (time > 60000) {
g_logger.warning("Max tile timer value is 300000 (300s)!");
return;
}
m_timer = time + g_clock.millis();
if (!m_timerText) {
m_timerText = StaticTextPtr(new StaticText());
}
m_timerText->setColor(color);
}
int Tile::getTimer()
{
return m_timerText ? std::max<int>(0, m_timer - g_clock.millis()) : 0;
}
void Tile::setFill(Color color)
{
m_fill = color;
}

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

@@ -0,0 +1,180 @@
/*
* Copyright (c) 2010-2017 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>
#include <framework/stdext/time.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,
TILESTATE_LAST = 1 << 24
};
class Tile : public LuaObject
{
public:
enum {
MAX_THINGS = 10
};
Tile(const Position& position);
void calculateCorpseCorrection();
void drawBottom(const Point& dest, LightView* lightView = nullptr);
void drawTop(const Point& dest, LightView* lightView = nullptr);
void drawTexts(Point dest);
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 getTopLookThingEx(Point offset);
ThingPtr getTopUseThing();
CreaturePtr getTopCreature();
CreaturePtr getTopCreatureEx(Point offset);
ThingPtr getTopMoveThing();
ThingPtr getTopMultiUseThing();
ThingPtr getTopMultiUseThingEx(Point offset);
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; }
std::vector<EffectPtr> getEffects() { return m_effects; }
ItemPtr getGround();
int getGroundSpeed();
bool isBlocking() { return m_blocking != 0; }
uint8 getMinimapColorByte();
int getThingCount() { return m_things.size() + m_effects.size(); }
bool isPathable();
bool isWalkable(bool ignoreCreatures = false);
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 hasBlockingCreature();
bool limitsFloorsView(bool isFreeView = false);
bool canErase();
int getElevation();
bool hasElevation(int elevation = 1);
void overwriteMinimapColor(uint8 color) { m_minimapColor = color; }
void remFlag(uint32 flag) { m_flags &= ~flag; }
void setFlag(uint32 flag) { m_flags |= flag; }
void setFlags(uint32 flags) { m_flags = flags; }
bool hasFlag(uint32 flag) { return (m_flags & flag) == flag; }
uint32 getFlags() { return m_flags; }
void setHouseId(uint32 hid) { m_houseId = hid; }
uint32 getHouseId() { return m_houseId; }
bool isHouseTile() { return m_houseId != 0 && (m_flags & TILESTATE_HOUSE) == TILESTATE_HOUSE; }
void select() { m_selected = true; }
void unselect() { m_selected = false; }
bool isSelected() { return m_selected; }
TilePtr asTile() { return static_self_cast<Tile>(); }
void setSpeed(uint16_t speed, uint8_t blocking) {
m_speed = speed;
m_blocking = blocking;
}
void setText(const std::string& text, Color color);
std::string getText();
void setTimer(int time, Color color);
int getTimer();
void setFill(Color color);
void resetFill() { m_fill = Color::alpha; }
private:
void checkTranslucentLight();
std::vector<CreaturePtr> m_walkingCreatures;
std::vector<EffectPtr> m_effects; // leave this outside m_things because it has no stackpos.
std::vector<ThingPtr> m_things;
Position m_position;
uint8 m_drawElevation;
uint8 m_minimapColor;
uint32 m_flags, m_houseId;
uint16 m_speed = 0;
uint8 m_blocking = 0;
uint32_t m_lastCreature = 0;
int m_topCorrection = 0;
int m_topDraws = 0;
stdext::boolean<false> m_selected;
ticks_t m_timer = 0;
StaticTextPtr m_timerText;
StaticTextPtr m_text;
Color m_fill = Color::alpha;
};
#endif

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

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2010-2017 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;
}
const TownPtr& TownManager::getTownByName(std::string name)
{
auto it = std::find_if(m_towns.begin(), m_towns.end(),
[=] (const TownPtr& town) -> bool { return town->getName() == name; } );
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; });
}
void TownManager::sort()
{
m_towns.sort([] (const TownPtr& lhs, const TownPtr& rhs) { return lhs->getName() < rhs->getName(); });
}

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

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2010-2017 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);
const TownPtr& getTownByName(std::string name);
void sort();
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

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

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2010-2017 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/drawqueue.h>
void UICreature::drawSelf(Fw::DrawPane drawPane)
{
if(drawPane != Fw::ForegroundPane)
return;
UIWidget::drawSelf(drawPane);
if(m_creature) {
if (m_autoRotating) {
auto ticks = (g_clock.millis() % 4000) / 4;
Otc::Direction new_dir;
if (ticks < 250)
{
new_dir = Otc::South;
}
else if (ticks < 500)
{
new_dir = Otc::East;
}
else if (ticks < 750)
{
new_dir = Otc::North;
}
else
{
new_dir = Otc::West;
}
if (new_dir != m_direction) {
m_direction = new_dir;
m_redraw = true;
}
}
if (m_creature->getOutfitNumber() != m_outfitNumber) {
m_outfitNumber = m_creature->getOutfitNumber();
m_redraw = true;
}
m_creature->drawOutfit(getPaddingRect(), m_direction, m_imageColor);
}
}
void UICreature::setOutfit(const Outfit& outfit)
{
if(!m_creature)
m_creature = CreaturePtr(new Creature);
m_direction = Otc::South;
m_creature->setOutfit(outfit);
m_redraw = true;
}
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>());
else if(node->tag() == "outfit-id") {
Outfit outfit = (m_creature ? m_creature->getOutfit() : Outfit());
outfit.setId(node->value<int>());
setOutfit(outfit);
}
else if(node->tag() == "outfit-head") {
Outfit outfit = (m_creature ? m_creature->getOutfit() : Outfit());
outfit.setHead(node->value<int>());
setOutfit(outfit);
}
else if(node->tag() == "outfit-body") {
Outfit outfit = (m_creature ? m_creature->getOutfit() : Outfit());
outfit.setBody(node->value<int>());
setOutfit(outfit);
}
else if(node->tag() == "outfit-legs") {
Outfit outfit = (m_creature ? m_creature->getOutfit() : Outfit());
outfit.setLegs(node->value<int>());
setOutfit(outfit);
}
else if(node->tag() == "outfit-feet") {
Outfit outfit = (m_creature ? m_creature->getOutfit() : Outfit());
outfit.setFeet(node->value<int>());
setOutfit(outfit);
}
else if (node->tag() == "scale") {
setScale(node->value<float>());
}
else if (node->tag() == "optimized") {
setOptimized(node->value<bool>());
}
}
}
void UICreature::onGeometryChange(const Rect& oldRect, const Rect& newRect)
{
UIWidget::onGeometryChange(oldRect, newRect);
m_redraw = true;
}

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

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-2017 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; m_redraw = true; }
void setFixedCreatureSize(bool fixed) { m_scale = fixed ? 1.0 : 0; m_redraw = true; }
void setOutfit(const Outfit& outfit);
CreaturePtr getCreature() { return m_creature; }
bool isFixedCreatureSize() { return m_scale > 0; }
void setAutoRotating(bool value) { m_autoRotating = value; }
void setDirection(Otc::Direction direction) { m_direction = direction; m_redraw = true; }
void setScale(float scale) { m_scale = scale; m_redraw = true; }
float getScale() { return m_scale; }
void setOptimized(bool value) { m_optimized = value; m_redraw = true; }
protected:
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
void onGeometryChange(const Rect& oldRect, const Rect& newRect) override;
CreaturePtr m_creature;
stdext::boolean<false> m_autoRotating;
stdext::boolean<false> m_redraw;
int m_outfitNumber = 0;
Otc::Direction m_direction = Otc::South;
float m_scale = 1.0;
bool m_optimized = false;
};
#endif

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

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2010-2017 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)
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_itemVisible && m_item) {
Rect drawRect = getPaddingRect();
int exactSize = std::max<int>(32, m_item->getExactSize());
if(exactSize == 0)
return;
m_item->setColor(m_color);
m_item->draw(drawRect);
if(m_font && m_showCount && (m_item->isStackable() || m_item->isChargeable()) && m_item->getCountOrSubType() > 1) {
g_drawQueue->addText(m_font, std::to_string(m_item->getCountOrSubType()), Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight, Color(231, 231, 231));
}
if (m_showId) {
g_drawQueue->addText(m_font, std::to_string(m_item->getServerId()), m_rect, Fw::AlignBottomRight, Color(231, 231, 231));
}
}
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);
}
callLuaField("onItemChange");
}
void UIItem::setItemCount(int count)
{
if (m_item)
m_item->setCount(count);
callLuaField("onItemChange");
}
void UIItem::setItemSubType(int subType)
{
if (m_item)
m_item->setSubType(subType);
callLuaField("onItemChange");
}
void UIItem::setItem(const ItemPtr& item)
{
m_item = item;
callLuaField("onItemChange");
}
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() == "item-visible")
setItemVisible(node->value<bool>());
else if(node->tag() == "virtual")
setVirtual(node->value<bool>());
else if(node->tag() == "show-id")
m_showId = node->value<bool>();
}
}

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

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-2017 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);
void setItemSubType(int subType);
void setItemVisible(bool visible) { m_itemVisible = visible; }
void setItem(const ItemPtr& item);
void setVirtual(bool virt) { m_virtual = virt; }
void clearItem() { setItemId(0); }
void setShowCount(bool value) { m_showCount = value; }
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; }
int getItemCountOrSubType() { return m_item ? m_item->getCountOrSubType() : 0; }
ItemPtr getItem() { return m_item; }
bool isVirtual() { return m_virtual; }
bool isItemVisible() { return m_itemVisible; }
protected:
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
ItemPtr m_item;
stdext::boolean<false> m_virtual;
stdext::boolean<true> m_itemVisible;
stdext::boolean<false> m_showId;
stdext::boolean<true> m_showCount;
};
#endif

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

@@ -0,0 +1,231 @@
/*
* Copyright (c) 2010-2017 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 <framework/util/extras.h>
#include "localplayer.h"
UIMap::UIMap()
{
m_draggable = true;
m_mapView = MapViewPtr(new MapView);
m_zoom = m_mapView->getVisibleDimension().height();
m_keepAspectRatio = true;
m_limitVisibleRange = false;
m_aspectRatio = m_mapView->getVisibleDimension().ratio();
m_maxZoomIn = 3;
m_maxZoomOut = 513;
m_mapRect.resize(1,1);
g_map.addMapView(m_mapView);
}
UIMap::~UIMap()
{
g_map.removeMapView(m_mapView);
}
bool UIMap::onMouseMove(const Point& mousePos, const Point& mouseMoved)
{
m_mousePosition = mousePos;
return UIWidget::onMouseMove(mousePos, mouseMoved);
}
void UIMap::drawSelf(Fw::DrawPane drawPane)
{
UIWidget::drawSelf(drawPane);
if(drawPane == Fw::ForegroundPane) {
g_drawQueue->addBoundingRect(m_mapRect.expanded(1), 1, Color::black);
g_drawQueue->markMapPosition();
} else if(drawPane == Fw::MapBackgroundPane) {
m_mapView->drawBackground(m_mapRect, getTile(m_mousePosition));
} else if (drawPane == Fw::MapForegroundPane) {
m_mapView->drawForeground(m_mapRect);
}
}
void UIMap::movePixels(int x, int y)
{
m_mapView->move(x, y);
}
bool UIMap::setZoom(int zoom)
{
m_zoom = stdext::clamp<int>(zoom, m_maxZoomIn, m_maxZoomOut);
updateVisibleDimension();
return false;
}
bool UIMap::zoomIn()
{
int delta = 2;
if(m_zoom - delta < m_maxZoomIn)
delta--;
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)
delta--;
if(m_zoom + delta > m_maxZoomOut)
return false;
m_zoom += 2;
updateVisibleDimension();
return true;
}
void UIMap::setVisibleDimension(const Size& visibleDimension)
{
m_mapView->setVisibleDimension(visibleDimension);
m_aspectRatio = visibleDimension.ratio();
if(m_keepAspectRatio)
updateMapSize();
}
void UIMap::setKeepAspectRatio(bool enable)
{
m_keepAspectRatio = enable;
if(enable)
m_aspectRatio = getVisibleDimension().ratio();
updateMapSize();
}
Position UIMap::getPosition(const Point& mousePos)
{
if (!m_mapRect.contains(mousePos))
return Position();
Point relativeMousePos = mousePos - m_mapRect.topLeft();
return m_mapView->getPosition(relativeMousePos, m_mapRect.size());
}
Point UIMap::getPositionOffset(const Point& mousePos)
{
if (!m_mapRect.contains(mousePos))
return Point(0, 0);
Point relativeMousePos = mousePos - m_mapRect.topLeft();
return m_mapView->getPositionOffset(relativeMousePos, m_mapRect.size());
}
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() == "draw-texts")
setDrawTexts(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 = m_aspectRatio;
if(!m_limitVisibleRange && !m_mapRect.isEmpty() && !m_keepAspectRatio)
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_keepAspectRatio)
updateMapSize();
callLuaField("onVisibleDimensionChange", dimensionWidth, dimensionHeight);
}
void UIMap::updateMapSize()
{
Rect clippingRect = getPaddingRect();
Size mapSize;
if(m_keepAspectRatio) {
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_keepAspectRatio)
updateVisibleDimension();
}
/* vim: set ts=4 sw=4 et: */

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

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2010-2017 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();
bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
void drawSelf(Fw::DrawPane drawPane);
void movePixels(int x, int y);
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 lockVisibleFloor(int floor) { m_mapView->lockFirstVisibleFloor(floor); }
void unlockVisibleFloor() { m_mapView->unlockFirstVisibleFloor(); }
void setVisibleDimension(const Size& visibleDimension);
void setDrawFlags(Otc::DrawFlags drawFlags) { m_mapView->setDrawFlags(drawFlags); }
void setDrawTexts(bool enable) { m_mapView->setDrawTexts(enable); }
void setDrawNames(bool enable) { m_mapView->setDrawNames(enable); }
void setDrawHealthBars(bool enable) { m_mapView->setDrawHealthBars(enable); }
void setDrawHealthBarsOnTop(bool enable) { m_mapView->setDrawHealthBarsOnTop(enable); }
void setDrawLights(bool enable) { m_mapView->setDrawLights(enable); }
void setDrawManaBar(bool enable) { m_mapView->setDrawManaBar(enable); }
void setDrawPlayerBars(bool enable) { m_mapView->setDrawPlayerBars(enable); }
void setAnimated(bool enable) { m_mapView->setAnimated(enable); }
void setKeepAspectRatio(bool enable);
void setMinimumAmbientLight(float intensity) { m_mapView->setMinimumAmbientLight(intensity); }
void setLimitVisibleRange(bool limitVisibleRange) { m_limitVisibleRange = limitVisibleRange; updateVisibleDimension(); }
void setFloorFading(int value) { m_mapView->setFloorFading(value); }
void setCrosshair(const std::string& type) { m_mapView->setCrosshair(type); }
bool isMultifloor() { return m_mapView->isMultifloor(); }
bool isDrawingTexts() { return m_mapView->isDrawingTexts(); }
bool isDrawingNames() { return m_mapView->isDrawingNames(); }
bool isDrawingHealthBars() { return m_mapView->isDrawingHealthBars(); }
bool isDrawingHealthBarsOnTop() { return m_mapView->isDrawingHealthBarsOnTop(); }
bool isDrawingLights() { return m_mapView->isDrawingLights(); }
bool isDrawingManaBar() { return m_mapView->isDrawingManaBar(); }
bool isAnimating() { return m_mapView->isAnimating(); }
bool isKeepAspectRatioEnabled() { return m_keepAspectRatio; }
bool isLimitVisibleRangeEnabled() { return m_limitVisibleRange; }
Size getVisibleDimension() { return m_mapView->getVisibleDimension(); }
CreaturePtr getFollowingCreature() { return m_mapView->getFollowingCreature(); }
Otc::DrawFlags getDrawFlags() { return m_mapView->getDrawFlags(); }
Position getCameraPosition() { return m_mapView->getCameraPosition(); }
Position getPosition(const Point& mousePos);
Point getPositionOffset(const Point& mousePos);
TilePtr getTile(const Point& mousePos);
int getMaxZoomIn() { return m_maxZoomIn; }
int getMaxZoomOut() { return m_maxZoomOut; }
int getZoom() { return m_zoom; }
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;
Point m_mousePosition;
float m_aspectRatio;
bool m_keepAspectRatio;
bool m_limitVisibleRange;
int m_maxZoomIn;
int m_maxZoomOut;
};
#endif

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2010-2017 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 "declarations.h"
#include "uimapanchorlayout.h"
#include "uiminimap.h"
#include <framework/ui/uiwidget.h>
int UIPositionAnchor::getHookedPoint(const UIWidgetPtr& hookedWidget, const UIWidgetPtr& parentWidget)
{
UIMinimapPtr minimap = hookedWidget->static_self_cast<UIMinimap>();
Rect hookedRect = minimap->getTileRect(m_hookedPosition);
int point = 0;
if(hookedRect.isValid()) {
switch(m_hookedEdge) {
case Fw::AnchorLeft:
point = hookedRect.left();
break;
case Fw::AnchorRight:
point = hookedRect.right();
break;
case Fw::AnchorTop:
point = hookedRect.top();
break;
case Fw::AnchorBottom:
point = hookedRect.bottom();
break;
case Fw::AnchorHorizontalCenter:
point = hookedRect.horizontalCenter();
break;
case Fw::AnchorVerticalCenter:
point = hookedRect.verticalCenter();
break;
default:
// must never happens
VALIDATE(false);
break;
}
}
return point;
}
void UIMapAnchorLayout::addPositionAnchor(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, Fw::AnchorEdge hookedEdge)
{
if(!anchoredWidget)
return;
VALIDATE(anchoredWidget != getParentWidget());
UIPositionAnchorPtr anchor(new UIPositionAnchor(anchoredEdge, hookedPosition, hookedEdge));
UIAnchorGroupPtr& anchorGroup = m_anchorsGroups[anchoredWidget];
if(!anchorGroup)
anchorGroup = UIAnchorGroupPtr(new UIAnchorGroup);
anchorGroup->addAnchor(anchor);
// layout must be updated because a new anchor got in
update();
}
void UIMapAnchorLayout::centerInPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition)
{
addPositionAnchor(anchoredWidget, Fw::AnchorHorizontalCenter, hookedPosition, Fw::AnchorHorizontalCenter);
addPositionAnchor(anchoredWidget, Fw::AnchorVerticalCenter, hookedPosition, Fw::AnchorVerticalCenter);
}
void UIMapAnchorLayout::fillPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition)
{
addPositionAnchor(anchoredWidget, Fw::AnchorLeft, hookedPosition, Fw::AnchorLeft);
addPositionAnchor(anchoredWidget, Fw::AnchorRight, hookedPosition, Fw::AnchorRight);
addPositionAnchor(anchoredWidget, Fw::AnchorTop, hookedPosition, Fw::AnchorTop);
addPositionAnchor(anchoredWidget, Fw::AnchorBottom, hookedPosition, Fw::AnchorBottom);
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2010-2017 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 UIMAPANCHORLAYOUT_H
#define UIMAPANCHORLAYOUT_H
#include "declarations.h"
#include <framework/ui/uianchorlayout.h>
class UIPositionAnchor : public UIAnchor
{
public:
UIPositionAnchor(Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, Fw::AnchorEdge hookedEdge) :
UIAnchor(anchoredEdge, std::string(), hookedEdge), m_hookedPosition(hookedPosition) { }
UIWidgetPtr getHookedWidget(const UIWidgetPtr& widget, const UIWidgetPtr& parentWidget) { return parentWidget; }
int getHookedPoint(const UIWidgetPtr& hookedWidget, const UIWidgetPtr& parentWidget);
private:
Position m_hookedPosition;
};
class UIMapAnchorLayout : public UIAnchorLayout
{
public:
UIMapAnchorLayout(UIWidgetPtr parentWidget) : UIAnchorLayout(parentWidget) { }
void addPositionAnchor(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge anchoredEdge,
const Position& hookedPosition, Fw::AnchorEdge hookedEdge);
void centerInPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition);
void fillPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition);
protected:
};
#endif

157
src/client/uiminimap.cpp Normal file
View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2010-2017 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 "uiminimap.h"
#include "minimap.h"
#include "game.h"
#include "uimapanchorlayout.h"
#include "luavaluecasts_client.h"
#include <framework/graphics/painter.h>
#include "uimapanchorlayout.h"
UIMinimap::UIMinimap()
{
m_zoom = 0;
m_scale = 1.0f;
m_minZoom = -5;
m_maxZoom = 5;
m_layout = UIMapAnchorLayoutPtr(new UIMapAnchorLayout(static_self_cast<UIWidget>()));
}
void UIMinimap::drawSelf(Fw::DrawPane drawPane)
{
UIWidget::drawSelf(drawPane);
if(drawPane != Fw::ForegroundPane)
return;
g_minimap.draw(getPaddingRect(), getCameraPosition(), m_scale, m_color);
}
bool UIMinimap::setZoom(int zoom)
{
if(zoom == m_zoom)
return true;
if(zoom < m_minZoom || zoom > m_maxZoom)
return false;
int oldZoom = m_zoom;
m_zoom = zoom;
if(m_zoom < 0)
m_scale = 1.0f / (1 << std::abs(zoom));
else if(m_zoom > 0)
m_scale = 1.0f * (1 << std::abs(zoom));
else
m_scale = 1;
m_layout->update();
onZoomChange(zoom, oldZoom);
return true;
}
void UIMinimap::setCameraPosition(const Position& pos)
{
Position oldPos = m_cameraPosition;
m_cameraPosition = pos;
m_layout->update();
onCameraPositionChange(pos, oldPos);
}
bool UIMinimap::floorUp()
{
Position pos = getCameraPosition();
if(!pos.up())
return false;
setCameraPosition(pos);
return true;
}
bool UIMinimap::floorDown()
{
Position pos = getCameraPosition();
if(!pos.down())
return false;
setCameraPosition(pos);
return true;
}
Point UIMinimap::getTilePoint(const Position& pos)
{
return g_minimap.getTilePoint(pos, getPaddingRect(), getCameraPosition(), m_scale);
}
Rect UIMinimap::getTileRect(const Position& pos)
{
return g_minimap.getTileRect(pos, getPaddingRect(), getCameraPosition(), m_scale);
}
Position UIMinimap::getTilePosition(const Point& mousePos)
{
return g_minimap.getTilePosition(mousePos, getPaddingRect(), getCameraPosition(), m_scale);
}
void UIMinimap::anchorPosition(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, Fw::AnchorEdge hookedEdge)
{
UIMapAnchorLayoutPtr layout = m_layout->static_self_cast<UIMapAnchorLayout>();
VALIDATE(layout);
layout->addPositionAnchor(anchoredWidget, anchoredEdge, hookedPosition, hookedEdge);
}
void UIMinimap::fillPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition)
{
UIMapAnchorLayoutPtr layout = m_layout->static_self_cast<UIMapAnchorLayout>();
VALIDATE(layout);
layout->fillPosition(anchoredWidget, hookedPosition);
}
void UIMinimap::centerInPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition)
{
UIMapAnchorLayoutPtr layout = m_layout->static_self_cast<UIMapAnchorLayout>();
VALIDATE(layout);
layout->centerInPosition(anchoredWidget, hookedPosition);
}
void UIMinimap::onZoomChange(int zoom, int oldZoom)
{
callLuaField("onZoomChange", zoom, oldZoom);
}
void UIMinimap::onCameraPositionChange(const Position& position, const Position& oldPosition)
{
callLuaField("onCameraPositionChange", position, oldPosition);
}
void UIMinimap::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "zoom")
setZoom(node->value<int>());
else if(node->tag() == "max-zoom")
setMaxZoom(node->value<int>());
else if(node->tag() == "min-zoom")
setMinZoom(node->value<int>());
}
}

76
src/client/uiminimap.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2010-2017 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 UIMINIMAP_H
#define UIMINIMAP_H
#include "declarations.h"
#include <framework/ui/uiwidget.h>
class UIMinimap : public UIWidget
{
public:
UIMinimap();
void drawSelf(Fw::DrawPane drawPane);
bool zoomIn() { return setZoom(m_zoom+1); }
bool zoomOut() { return setZoom(m_zoom-1); }
bool setZoom(int zoom);
void setMinZoom(int minZoom) { m_minZoom = minZoom; }
void setMaxZoom(int maxZoom) { m_maxZoom = maxZoom; }
void setCameraPosition(const Position& pos);
bool floorUp();
bool floorDown();
Point getTilePoint(const Position& pos);
Rect getTileRect(const Position& pos);
Position getTilePosition(const Point& mousePos);
Position getCameraPosition() { return m_cameraPosition; }
int getMinZoom() { return m_minZoom; }
int getMaxZoom() { return m_maxZoom; }
int getZoom() { return m_zoom; }
float getScale() { return m_scale; }
void anchorPosition(const UIWidgetPtr& anchoredWidget, Fw::AnchorEdge anchoredEdge, const Position& hookedPosition, Fw::AnchorEdge hookedEdge);
void fillPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition);
void centerInPosition(const UIWidgetPtr& anchoredWidget, const Position& hookedPosition);
protected:
virtual void onZoomChange(int zoom, int oldZoom);
virtual void onCameraPositionChange(const Position& position, const Position& oldPosition);
virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
private:
void update();
Rect m_mapArea;
Position m_cameraPosition;
float m_scale;
int m_zoom;
int m_minZoom;
int m_maxZoom;
};
#endif

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2010-2017 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)
return;
// 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<int>(m_percent - 0.0, 0.0) * (drawRect.right() - drawRect.horizontalCenter()) / 12.5, 0);
g_drawQueue->addFilledTriangle(drawRect.center(), drawRect.topRight() + Point(1,0), drawRect.topCenter() + var, m_backgroundColor);
}
// 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<int>(m_percent - 12.5, 0.0) * (drawRect.bottom() - drawRect.top()) / 25.0);
g_drawQueue->addFilledTriangle(drawRect.center(), drawRect.bottomRight() + Point(1,1), drawRect.topRight() + var + Point(1,0), m_backgroundColor);
}
// 37.5% - 62.5% (25)
// triangle from bottom right to bottom left (var x)
if(m_percent < 62.5) {
Point var = Point(std::max<int>(m_percent - 37.5, 0.0) * (drawRect.right() - drawRect.left()) / 25.0, 0);
g_drawQueue->addFilledTriangle(drawRect.center(), drawRect.bottomLeft() + Point(0,1), drawRect.bottomRight() - var + Point(1,1), m_backgroundColor);
}
// 62.5% - 87.5% (25)
// triangle from bottom left to top left
if(m_percent < 87.5) {
Point var = Point(0, std::max<int>(m_percent - 62.5, 0.0) * (drawRect.bottom() - drawRect.top()) / 25.0);
g_drawQueue->addFilledTriangle(drawRect.center(), drawRect.topLeft(), drawRect.bottomLeft() - var + Point(0,1), m_backgroundColor);
}
// 87.5% - 100% (12.5)
// triangle from top left to top center
if(m_percent < 100) {
Point var = Point(std::max<int>(m_percent - 87.5, 0.0) * (drawRect.horizontalCenter() - drawRect.left()) / 12.5, 0);
g_drawQueue->addFilledTriangle(drawRect.center(), drawRect.topCenter(), drawRect.topLeft() + var, m_backgroundColor);
}
drawImage(m_rect);
drawBorder(m_rect);
drawIcon(m_rect);
drawText(m_rect);
}
void UIProgressRect::setPercent(float percent)
{
m_percent = stdext::clamp<float>((double)percent, 0.0, 100.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-2017 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

86
src/client/uisprite.cpp Normal file
View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2010-2017 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 "uisprite.h"
#include <framework/otml/otml.h>
#include <framework/graphics/graphics.h>
#include <framework/graphics/texturemanager.h>
#include <client/spritemanager.h>
UISprite::UISprite() :
m_spriteId(0),
m_spriteColor(Color::white)
{ }
void UISprite::drawSelf(Fw::DrawPane drawPane)
{
if(drawPane != Fw::ForegroundPane)
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_spriteVisible && m_sprite) {
g_drawQueue->addTexturedRect(getPaddingRect(), m_sprite, Rect(Point(0, 0), m_sprite->getSize()), m_spriteColor);
}
drawBorder(m_rect);
drawIcon(m_rect);
drawText(m_rect);
}
void UISprite::setSpriteId(int id)
{
if(!g_sprites.isLoaded())
return;
m_spriteId = id;
if(id == 0)
m_sprite = nullptr;
else {
ImagePtr image = g_sprites.getSpriteImage(id);
if(image)
m_sprite = new Texture(image);
else
m_sprite = nullptr;
}
}
void UISprite::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
{
UIWidget::onStyleApply(styleName, styleNode);
for(const OTMLNodePtr& node : styleNode->children()) {
if(node->tag() == "sprite-id")
setSpriteId(node->value<int>());
else if(node->tag() == "sprite-visible")
setSpriteVisible(node->value<bool>());
else if(node->tag() == "sprite-color")
setSpriteColor(node->value<Color>());
}
}

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

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2017 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 UISPRITE_H
#define UISPRITE_H
#include "declarations.h"
#include <framework/ui/uiwidget.h>
class UISprite : public UIWidget
{
public:
UISprite();
void drawSelf(Fw::DrawPane drawPane);
void setSpriteId(int id);
int getSpriteId() { return m_spriteId; }
void clearSprite() { setSpriteId(0); }
void setSpriteColor(Color color) { m_spriteColor = color; }
bool isSpriteVisible() { return m_spriteVisible; }
void setSpriteVisible(bool visible) { m_spriteVisible = visible; }
bool hasSprite() { return m_sprite != nullptr; }
protected:
void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
TexturePtr m_sprite;
uint16 m_spriteId;
Color m_spriteColor;
stdext::boolean<true> m_spriteVisible;
};
#endif