Many enhancements in client API
* Fix issues in item use * Stack animated texts values * Add utility functions for changing creature color and jumping * Add some new extended functionality * Improve map shader API
This commit is contained in:
parent
aeb31f0669
commit
cce2976156
|
@ -284,7 +284,7 @@ function onUseWith(clickedWidget, mousePosition)
|
|||
if clickedWidget:getClassName() == 'UIMap' then
|
||||
local tile = clickedWidget:getTile(mousePosition)
|
||||
if tile then
|
||||
g_game.useWith(selectedThing, tile:getTopMultiUseThing(false))
|
||||
g_game.useWith(selectedThing, tile:getTopMultiUseThing())
|
||||
end
|
||||
elseif clickedWidget:getClassName() == 'UIItem' and not clickedWidget:isVirtual() then
|
||||
g_game.useWith(selectedThing, clickedWidget:getItem())
|
||||
|
@ -450,7 +450,7 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
|||
menu:display(menuPosition)
|
||||
end
|
||||
|
||||
function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, multiUseThing)
|
||||
function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing)
|
||||
local keyboardModifiers = g_keyboard.getModifiers()
|
||||
|
||||
if not Options.getOption('classicControl') then
|
||||
|
@ -482,20 +482,20 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
|
|||
|
||||
-- classic control
|
||||
else
|
||||
if multiUseThing and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
|
||||
if useThing and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
|
||||
local player = g_game.getLocalPlayer()
|
||||
if creatureThing and creatureThing ~= player then
|
||||
g_game.attack(creatureThing)
|
||||
return true
|
||||
elseif multiUseThing:isContainer() then
|
||||
if multiUseThing:getParentContainer() then
|
||||
g_game.open(multiUseThing, multiUseThing:getParentContainer())
|
||||
elseif useThing:isContainer() then
|
||||
if useThing:getParentContainer() then
|
||||
g_game.open(useThing, useThing:getParentContainer())
|
||||
return true
|
||||
else
|
||||
g_game.open(multiUseThing)
|
||||
g_game.open(useThing)
|
||||
return true
|
||||
end
|
||||
elseif multiUseThing:isMultiUse() then
|
||||
elseif useThing:isMultiUse() then
|
||||
startUseWith(useThing)
|
||||
return true
|
||||
else
|
||||
|
|
|
@ -81,10 +81,9 @@ function UIGameMap:onMouseRelease(mousePosition, mouseButton)
|
|||
lookThing = tile:getTopLookThing()
|
||||
useThing = tile:getTopUseThing()
|
||||
creatureThing = tile:getTopCreature()
|
||||
multiUseThing = tile:getTopMultiUseThing()
|
||||
end
|
||||
|
||||
local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, multiUseThing)
|
||||
local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing)
|
||||
if ret then
|
||||
self.cancelNextRelease = true
|
||||
end
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "animatedtext.h"
|
||||
#include "map.h"
|
||||
#include "game.h"
|
||||
#include <framework/core/clock.h>
|
||||
#include <framework/core/eventdispatcher.h>
|
||||
#include <framework/graphics/graphics.h>
|
||||
|
@ -34,14 +35,31 @@ AnimatedText::AnimatedText()
|
|||
|
||||
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();
|
||||
p.x += 20 - textSize.width() / 2;
|
||||
p.y += (-20 * m_animationTimer.ticksElapsed()) / Otc::ANIMATED_TEXT_DURATION;
|
||||
float t = m_animationTimer.ticksElapsed();
|
||||
p.x += (24 - textSize.width() / 2);
|
||||
|
||||
if(g_game.getFeature(Otc::GameDiagonalAnimatedText)) {
|
||||
p.x -= (4 * t / tf) + (8 * t * t / tftf);
|
||||
}
|
||||
|
||||
p.y += 8 + (-48 * t) / tf;
|
||||
p += m_offset;
|
||||
Rect rect(p, textSize);
|
||||
|
||||
if(visibleRect.contains(rect)) {
|
||||
//TODO: cache into a framebuffer
|
||||
float t0 = tf / 1.2;
|
||||
if(t > t0) {
|
||||
Color color = m_color;
|
||||
color.setAlpha((float)(1 - (t - t0) / (tf - t0)));
|
||||
g_painter->setColor(color);
|
||||
}
|
||||
else
|
||||
g_painter->setColor(m_color);
|
||||
m_cachedText.draw(rect);
|
||||
}
|
||||
|
@ -65,3 +83,27 @@ 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());
|
||||
|
||||
std::string text = stdext::format("%d", number + otherNumber);
|
||||
m_cachedText.setText(text);
|
||||
return true;
|
||||
}
|
||||
catch(...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,14 @@ public:
|
|||
|
||||
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; }
|
||||
|
@ -49,6 +57,7 @@ private:
|
|||
Color m_color;
|
||||
Timer m_animationTimer;
|
||||
CachedText m_cachedText;
|
||||
Point m_offset;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,7 @@ void Client::init(std::vector<std::string>& args)
|
|||
// register needed lua functions
|
||||
registerLuaFunctions();
|
||||
|
||||
g_map.init();
|
||||
g_game.init();
|
||||
g_shaders.init();
|
||||
g_things.init();
|
||||
|
|
|
@ -32,15 +32,7 @@ namespace Otc
|
|||
SEA_FLOOR = 7,
|
||||
MAX_Z = 15,
|
||||
UNDERGROUND_FLOOR = SEA_FLOOR+1,
|
||||
VISIBLE_X_TILES = 15,
|
||||
VISIBLE_Y_TILES = 11,
|
||||
AWARE_UNDEGROUND_FLOOR_RANGE = 2,
|
||||
AWARE_X_TILES = VISIBLE_X_TILES + 3,
|
||||
AWARE_Y_TILES = VISIBLE_Y_TILES + 3,
|
||||
AWARE_X_LEFT_TILES = AWARE_X_TILES/2 - 1,
|
||||
AWARE_X_RIGHT_TILES = AWARE_X_TILES/2,
|
||||
AWARE_Y_TOP_TILES = AWARE_Y_TILES/2 - 1,
|
||||
AWARE_Y_BOTTOM_TILES = AWARE_Y_TILES/2,
|
||||
|
||||
INVISIBLE_TICKS_PER_FRAME = 500,
|
||||
ITEM_TICKS_PER_FRAME = 500,
|
||||
|
@ -343,9 +335,18 @@ namespace Otc
|
|||
GameFormatCreatureName = 22,
|
||||
GameSpellList = 23,
|
||||
GameClientPing = 24,
|
||||
GameLoginPending = 25,
|
||||
GameNewSpeedLaw = 26,
|
||||
// 23-50 unused yet
|
||||
GameExtendedClientPing = 25,
|
||||
GameUpdater = 26,
|
||||
GameLoginLocale = 27,
|
||||
GameDoubleHealth = 28,
|
||||
GameDoubleSkills = 29,
|
||||
GameChangeMapAwareRange = 30,
|
||||
GameMapMovePosition = 31,
|
||||
GameAttackSeq = 32,
|
||||
GameBlueNpcNameColor = 33,
|
||||
GameDiagonalAnimatedText = 34,
|
||||
GameLoginPending = 35,
|
||||
GameNewSpeedLaw = 36,
|
||||
// 51-100 reserved to be defined in lua
|
||||
LastGameFeature = 101
|
||||
};
|
||||
|
|
|
@ -58,6 +58,7 @@ Creature::Creature() : Thing()
|
|||
m_nameCache.setAlign(Fw::AlignTopCenter);
|
||||
m_footStep = 0;
|
||||
m_speedFormula.fill(-1);
|
||||
m_outfitColor = Color::white;
|
||||
}
|
||||
|
||||
void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
|
||||
|
@ -89,7 +90,7 @@ void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightVie
|
|||
|
||||
// local player always have a minimum light in complete darkness
|
||||
if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
|
||||
light.intensity = std::max<uint8>(light.intensity, 2);
|
||||
light.intensity = std::max<uint8>(light.intensity, 3);
|
||||
if(light.color == 0 || light.color > 215)
|
||||
light.color = 215;
|
||||
}
|
||||
|
@ -101,6 +102,8 @@ void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightVie
|
|||
|
||||
void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
|
||||
{
|
||||
g_painter->setColor(m_outfitColor);
|
||||
|
||||
// outfit is a real creature
|
||||
if(m_outfit.getCategory() == ThingCategoryCreature) {
|
||||
int animationPhase = animateWalk ? m_walkAnimationPhase : 0;
|
||||
|
@ -128,6 +131,9 @@ void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWal
|
|||
zPattern = 1;
|
||||
}
|
||||
|
||||
PointF jumpOffset = m_jumpOffset * scaleFactor;
|
||||
dest -= Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));
|
||||
|
||||
// yPattern => creature addon
|
||||
for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
|
||||
|
||||
|
@ -181,6 +187,8 @@ void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWal
|
|||
|
||||
type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
|
||||
}
|
||||
|
||||
g_painter->resetColor();
|
||||
}
|
||||
|
||||
void Creature::drawOutfit(const Rect& destRect, bool resize)
|
||||
|
@ -250,6 +258,11 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par
|
|||
g_painter->setColor(Color::black);
|
||||
g_painter->drawFilledRect(backgroundRect);
|
||||
|
||||
if(g_game.getFeature(Otc::GameBlueNpcNameColor) && isNpc() && m_healthPercent == 100 && !useGray)
|
||||
g_painter->setColor(Color(0x66, 0xcc, 0xff));
|
||||
else
|
||||
g_painter->setColor(fillColor);
|
||||
|
||||
g_painter->setColor(fillColor);
|
||||
g_painter->drawFilledRect(healthRect);
|
||||
|
||||
|
@ -320,6 +333,58 @@ void Creature::stopWalk()
|
|||
terminateWalk();
|
||||
}
|
||||
|
||||
void Creature::jump(int height, int duration)
|
||||
{
|
||||
if(!m_jumpOffset.isNull())
|
||||
return;
|
||||
|
||||
m_jumpTimer.restart();
|
||||
m_jumpHeight = height;
|
||||
m_jumpDuration = duration;
|
||||
|
||||
updateJump();
|
||||
}
|
||||
|
||||
void Creature::updateJump()
|
||||
{
|
||||
int t = m_jumpTimer.ticksElapsed();
|
||||
double a = -4 * m_jumpHeight / (m_jumpDuration * m_jumpDuration);
|
||||
double b = +4 * m_jumpHeight / (m_jumpDuration);
|
||||
|
||||
double height = a*t*t + b*t;
|
||||
int roundHeight = stdext::round(height);
|
||||
int halfJumpDuration = m_jumpDuration / 2;
|
||||
|
||||
// schedules next update
|
||||
if(m_jumpTimer.ticksElapsed() < m_jumpDuration) {
|
||||
m_jumpOffset = PointF(height, height);
|
||||
|
||||
int diff = 0;
|
||||
if(m_jumpTimer.ticksElapsed() < halfJumpDuration)
|
||||
diff = 1;
|
||||
else if(m_jumpTimer.ticksElapsed() > halfJumpDuration)
|
||||
diff = -1;
|
||||
|
||||
int nextT, i = 1;
|
||||
do {
|
||||
nextT = stdext::round((-b + std::sqrt(std::max(b*b + 4*a*(roundHeight+diff*i), 0.0)) * diff) / (2*a));
|
||||
++i;
|
||||
|
||||
if(nextT < halfJumpDuration)
|
||||
diff = 1;
|
||||
else if(nextT > halfJumpDuration)
|
||||
diff = -1;
|
||||
} while(nextT - m_jumpTimer.ticksElapsed() == 0 && i < 3);
|
||||
|
||||
auto self = static_self_cast<Creature>();
|
||||
g_dispatcher.scheduleEvent([self] {
|
||||
self->updateJump();
|
||||
}, nextT - m_jumpTimer.ticksElapsed());
|
||||
}
|
||||
else
|
||||
m_jumpOffset = PointF(0, 0);
|
||||
}
|
||||
|
||||
void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
|
||||
{
|
||||
callLuaField("onPositionChange", newPos, oldPos);
|
||||
|
@ -560,6 +625,37 @@ void Creature::setOutfit(const Outfit& outfit)
|
|||
callLuaField("onOutfitChange", m_outfit, oldOutfit);
|
||||
}
|
||||
|
||||
void Creature::setOutfitColor(const Color& color, int duration)
|
||||
{
|
||||
if(m_outfitColorUpdateEvent) {
|
||||
m_outfitColorUpdateEvent->cancel();
|
||||
m_outfitColorUpdateEvent = nullptr;
|
||||
}
|
||||
|
||||
if(duration > 0) {
|
||||
Color delta = (color - m_outfitColor) / (float)duration;
|
||||
m_outfitColorTimer.restart();
|
||||
updateOutfitColor(m_outfitColor, color, delta, duration);
|
||||
}
|
||||
else
|
||||
m_outfitColor = color;
|
||||
}
|
||||
|
||||
void Creature::updateOutfitColor(Color color, Color finalColor, Color delta, int duration)
|
||||
{
|
||||
if(m_outfitColorTimer.ticksElapsed() < duration) {
|
||||
m_outfitColor = color + delta * m_outfitColorTimer.ticksElapsed();
|
||||
|
||||
auto self = static_self_cast<Creature>();
|
||||
m_outfitColorUpdateEvent = g_dispatcher.scheduleEvent([=] {
|
||||
self->updateOutfitColor(color, finalColor, delta, duration);
|
||||
}, 100);
|
||||
}
|
||||
else {
|
||||
m_outfitColor = finalColor;
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::setSpeed(uint16 speed)
|
||||
{
|
||||
uint16 oldSpeed = m_speed;
|
||||
|
@ -707,11 +803,15 @@ int Creature::getStepDuration(bool ignoreDiagonal)
|
|||
if(g_game.getProtocolVersion() >= 900)
|
||||
interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();
|
||||
|
||||
float factor = 3;
|
||||
if(g_game.getProtocolVersion() <= 810)
|
||||
factor = 2;
|
||||
|
||||
interval = std::max(interval, g_game.getServerBeat());
|
||||
|
||||
if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
|
||||
m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
|
||||
interval *= 3;
|
||||
interval *= factor;
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
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 setSkull(uint8 skull);
|
||||
|
@ -98,11 +99,13 @@ public:
|
|||
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
|
||||
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() { m_allowAppearWalk = true; }
|
||||
|
@ -129,6 +132,9 @@ protected:
|
|||
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;
|
||||
|
@ -152,6 +158,9 @@ protected:
|
|||
stdext::boolean<true> m_removed;
|
||||
CachedText m_nameCache;
|
||||
Color m_informationColor;
|
||||
Color m_outfitColor;
|
||||
ScheduledEventPtr m_outfitColorUpdateEvent;
|
||||
Timer m_outfitColorTimer;
|
||||
|
||||
std::array<double, Otc::LastSpeedFormula> m_speedFormula;
|
||||
|
||||
|
@ -173,6 +182,12 @@ protected:
|
|||
Position m_lastStepFromPosition;
|
||||
Position m_lastStepToPosition;
|
||||
Position m_oldPosition;
|
||||
|
||||
// jump related
|
||||
float m_jumpHeight;
|
||||
float m_jumpDuration;
|
||||
PointF m_jumpOffset;
|
||||
Timer m_jumpTimer;
|
||||
};
|
||||
|
||||
// @bindclass
|
||||
|
|
|
@ -39,6 +39,7 @@ Game g_game;
|
|||
Game::Game()
|
||||
{
|
||||
m_protocolVersion = 0;
|
||||
m_clientCustomOs = -1;
|
||||
m_clientVersion = 0;
|
||||
m_online = false;
|
||||
m_denyBotCall = false;
|
||||
|
@ -98,6 +99,7 @@ void Game::resetGameStates()
|
|||
m_containers.clear();
|
||||
m_vips.clear();
|
||||
m_gmActions.clear();
|
||||
g_map.resetAwareRange();
|
||||
}
|
||||
|
||||
void Game::processConnectionError(const boost::system::error_code& ec)
|
||||
|
@ -123,6 +125,11 @@ void Game::processDisconnect()
|
|||
}
|
||||
}
|
||||
|
||||
void Game::processUpdateNeeded(const std::string& signature)
|
||||
{
|
||||
g_lua.callGlobalField("g_game", "onUpdateNeeded", signature);
|
||||
}
|
||||
|
||||
void Game::processLoginError(const std::string& error)
|
||||
{
|
||||
g_lua.callGlobalField("g_game", "onLoginError", error);
|
||||
|
@ -164,7 +171,7 @@ void Game::processGameStart()
|
|||
g_lua.callGlobalField("g_game", "onGameStart");
|
||||
disableBotCall();
|
||||
|
||||
if(g_game.getFeature(Otc::GameClientPing)) {
|
||||
if(g_game.getFeature(Otc::GameClientPing) || g_game.getFeature(Otc::GameExtendedClientPing)) {
|
||||
m_protocolGame->sendPing();
|
||||
m_pingEvent = g_dispatcher.cycleEvent([this] {
|
||||
if(m_protocolGame && m_protocolGame->isConnected()) {
|
||||
|
@ -464,7 +471,7 @@ void Game::processWalkCancel(Otc::Direction direction)
|
|||
m_localPlayer->cancelWalk(direction);
|
||||
}
|
||||
|
||||
void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName)
|
||||
void Game::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& locale)
|
||||
{
|
||||
if(m_protocolGame || isOnline())
|
||||
stdext::throw_exception("Unable to login into a world while already online or logging.");
|
||||
|
@ -479,7 +486,7 @@ void Game::loginWorld(const std::string& account, const std::string& password, c
|
|||
m_localPlayer->setName(characterName);
|
||||
|
||||
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
|
||||
m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
|
||||
m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName, locale);
|
||||
m_characterName = characterName;
|
||||
m_worldName = worldName;
|
||||
}
|
||||
|
@ -608,15 +615,13 @@ void Game::autoWalk(std::vector<Otc::Direction> dirs)
|
|||
if(isFollowing())
|
||||
cancelFollow();
|
||||
|
||||
auto it = dirs.begin();
|
||||
Otc::Direction direction = *it;
|
||||
Otc::Direction direction = dirs.front();
|
||||
if(m_localPlayer->canWalk(direction)) {
|
||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
|
||||
if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking())
|
||||
{
|
||||
if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking()) {
|
||||
m_localPlayer->preWalk(direction);
|
||||
forceWalk(direction);
|
||||
dirs.erase(it);
|
||||
//forceWalk(direction);
|
||||
//dirs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,7 +779,7 @@ void Game::useWith(const ItemPtr& item, const ThingPtr& toThing)
|
|||
if(!pos.isValid()) // virtual item
|
||||
pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
|
||||
|
||||
if(toThing->isCreature() && g_game.getProtocolVersion() >= 860)
|
||||
if(toThing->isCreature())
|
||||
m_protocolGame->sendUseOnCreature(pos, item->getId(), item->getStackpos(), toThing->getId());
|
||||
else
|
||||
m_protocolGame->sendUseItemWith(pos, item->getId(), item->getStackpos(), toThing->getPosition(), toThing->getId(), toThing->getStackpos());
|
||||
|
@ -793,10 +798,10 @@ void Game::useInventoryItemWith(int itemId, const ThingPtr& toThing)
|
|||
m_protocolGame->sendUseItemWith(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toThing->getStackpos());
|
||||
}
|
||||
|
||||
void Game::open(const ItemPtr& item, const ContainerPtr& previousContainer)
|
||||
int Game::open(const ItemPtr& item, const ContainerPtr& previousContainer)
|
||||
{
|
||||
if(!canPerformGameAction() || !item)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
int id = 0;
|
||||
if(!previousContainer)
|
||||
|
@ -805,6 +810,7 @@ void Game::open(const ItemPtr& item, const ContainerPtr& previousContainer)
|
|||
id = previousContainer->getId();
|
||||
|
||||
m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackpos(), id);
|
||||
return id;
|
||||
}
|
||||
|
||||
void Game::openParent(const ContainerPtr& container)
|
||||
|
@ -1218,6 +1224,13 @@ void Game::ping()
|
|||
m_denyBotCall = true;
|
||||
}
|
||||
|
||||
void Game::changeMapAwareRange(int xrange, int yrange)
|
||||
{
|
||||
if(!canPerformGameAction())
|
||||
return;
|
||||
m_protocolGame->sendChangeMapAwareRange(xrange, yrange);
|
||||
}
|
||||
|
||||
bool Game::checkBotProtection()
|
||||
{
|
||||
#ifdef BOT_PROTECTION
|
||||
|
@ -1269,6 +1282,10 @@ void Game::setProtocolVersion(int version)
|
|||
enableFeature(Otc::GameCreatureEmblems);
|
||||
}
|
||||
|
||||
if(version >= 860) {
|
||||
enableFeature(Otc::GameAttackSeq);
|
||||
}
|
||||
|
||||
if(version >= 862) {
|
||||
enableFeature(Otc::GamePenalityOnDeath);
|
||||
}
|
||||
|
@ -1350,8 +1367,18 @@ void Game::setFollowingCreature(const CreaturePtr& creature)
|
|||
std::string Game::formatCreatureName(const std::string& name)
|
||||
{
|
||||
std::string formatedName = name;
|
||||
if(getFeature(Otc::GameFormatCreatureName) && name.length() > 0)
|
||||
formatedName[0] = stdext::upchar(formatedName[0]);
|
||||
if(getFeature(Otc::GameFormatCreatureName) && name.length() > 0) {
|
||||
bool upnext = true;
|
||||
for(uint i=0;i<formatedName.length();++i) {
|
||||
char ch = formatedName[i];
|
||||
if(upnext) {
|
||||
formatedName[i] = stdext::upchar(ch);
|
||||
upnext = false;
|
||||
}
|
||||
if(ch == ' ')
|
||||
upnext = true;
|
||||
}
|
||||
}
|
||||
return formatedName;
|
||||
}
|
||||
|
||||
|
@ -1362,3 +1389,16 @@ int Game::findEmptyContainerId()
|
|||
id++;
|
||||
return id;
|
||||
}
|
||||
|
||||
int Game::getOs()
|
||||
{
|
||||
if(m_clientCustomOs >= 0)
|
||||
return m_clientCustomOs;
|
||||
|
||||
if(g_app.getOs() == "windows")
|
||||
return 10;
|
||||
else if(g_app.getOs() == "mac")
|
||||
return 12;
|
||||
else
|
||||
return 10;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ protected:
|
|||
void processPing();
|
||||
void processPingBack(int elapsed);
|
||||
|
||||
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);
|
||||
|
@ -134,7 +135,7 @@ protected:
|
|||
|
||||
public:
|
||||
// login related
|
||||
void loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName);
|
||||
void 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& locale);
|
||||
void cancelLogin();
|
||||
void forceLogout();
|
||||
void safeLogout();
|
||||
|
@ -157,7 +158,7 @@ public:
|
|||
void useInventoryItemWith(int itemId, const ThingPtr& toThing);
|
||||
|
||||
// container related
|
||||
void open(const ItemPtr& item, const ContainerPtr& previousContainer);
|
||||
int open(const ItemPtr& item, const ContainerPtr& previousContainer);
|
||||
void openParent(const ContainerPtr& container);
|
||||
void close(const ContainerPtr& container);
|
||||
void refreshContainer(const ContainerPtr& container);
|
||||
|
@ -246,6 +247,9 @@ public:
|
|||
//void reportRuleViolation2();
|
||||
void ping();
|
||||
|
||||
// otclient only
|
||||
void changeMapAwareRange(int xrange, int yrange);
|
||||
|
||||
// dynamic support for game features
|
||||
void enableFeature(Otc::GameFeature feature) { m_features.set(feature, true); }
|
||||
void disableFeature(Otc::GameFeature feature) { m_features.set(feature, false); }
|
||||
|
@ -258,6 +262,12 @@ public:
|
|||
void setClientVersion(int version);
|
||||
int getClientVersion() { return m_clientVersion; }
|
||||
|
||||
void setCustomOs(int os) { m_clientCustomOs = os; }
|
||||
int getOs();
|
||||
|
||||
void setUpdaterSignature(const std::string& sig) { m_clientSignature = sig; }
|
||||
std::string getUpdaterSignature() { return m_clientSignature; }
|
||||
|
||||
bool canPerformGameAction();
|
||||
bool checkBotProtection();
|
||||
|
||||
|
@ -281,6 +291,7 @@ public:
|
|||
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; }
|
||||
|
||||
std::string formatCreatureName(const std::string &name);
|
||||
int findEmptyContainerId();
|
||||
|
@ -319,6 +330,8 @@ private:
|
|||
ScheduledEventPtr m_walkEvent;
|
||||
int m_protocolVersion;
|
||||
int m_clientVersion;
|
||||
std::string m_clientSignature;
|
||||
int m_clientCustomOs;
|
||||
};
|
||||
|
||||
extern Game g_game;
|
||||
|
|
|
@ -513,5 +513,5 @@ void LocalPlayer::setSpells(const std::vector<int>& spells)
|
|||
|
||||
bool LocalPlayer::hasSight(const Position& pos)
|
||||
{
|
||||
return m_position.isInRange(pos, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
|
||||
return m_position.isInRange(pos, g_map.getAwareRange().left - 1, g_map.getAwareRange().top - 1);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_things", "loadDat", &ThingTypeManager::loadDat, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "loadOtb", &ThingTypeManager::loadOtb, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "loadXml", &ThingTypeManager::loadXml, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "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);
|
||||
|
@ -205,6 +206,7 @@ void Client::registerLuaFunctions()
|
|||
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", "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);
|
||||
|
@ -225,12 +227,17 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_game", "setProtocolVersion", &Game::setProtocolVersion, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "getClientVersion", &Game::getClientVersion, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "setClientVersion", &Game::setClientVersion, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "setUpdaterSignature", &Game::setUpdaterSignature, &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", "isGM", &Game::isGM, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "answerModalDialog", &Game::answerModalDialog, &g_game);
|
||||
|
||||
g_lua.registerSingletonClass("g_shaders");
|
||||
|
@ -278,6 +285,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<Thing>("getPosition", &Thing::getPosition);
|
||||
g_lua.bindClassMemberFunction<Thing>("getStackPriority", &Thing::getStackPriority);
|
||||
g_lua.bindClassMemberFunction<Thing>("getAnimationPhases", &Thing::getAnimationPhases);
|
||||
g_lua.bindClassMemberFunction<Thing>("getTile", &Thing::getTile);
|
||||
g_lua.bindClassMemberFunction<Thing>("isItem", &Thing::isItem);
|
||||
g_lua.bindClassMemberFunction<Thing>("isMonster", &Thing::isMonster);
|
||||
g_lua.bindClassMemberFunction<Thing>("isNpc", &Thing::isNpc);
|
||||
|
@ -364,6 +372,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<Creature>("getEmblem", &Creature::getEmblem);
|
||||
g_lua.bindClassMemberFunction<Creature>("setOutfit", &Creature::setOutfit);
|
||||
g_lua.bindClassMemberFunction<Creature>("getOutfit", &Creature::getOutfit);
|
||||
g_lua.bindClassMemberFunction<Creature>("setOutfitColor", &Creature::setOutfitColor);
|
||||
g_lua.bindClassMemberFunction<Creature>("getDirection", &Creature::getDirection);
|
||||
g_lua.bindClassMemberFunction<Creature>("getStepDuration", &Creature::getStepDuration);
|
||||
g_lua.bindClassMemberFunction<Creature>("getStepProgress", &Creature::getStepProgress);
|
||||
|
@ -378,6 +387,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<Creature>("isWalking", &Creature::isWalking);
|
||||
g_lua.bindClassMemberFunction<Creature>("isInvisible", &Creature::isInvisible);
|
||||
g_lua.bindClassMemberFunction<Creature>("canBeSeen", &Creature::canBeSeen);
|
||||
g_lua.bindClassMemberFunction<Creature>("jump", &Creature::jump);
|
||||
|
||||
g_lua.registerClass<ItemType>();
|
||||
g_lua.bindClassMemberFunction<ItemType>("getServerId", &ItemType::getServerId);
|
||||
|
@ -407,6 +417,10 @@ void Client::registerLuaFunctions()
|
|||
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>("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.registerClass<AnimatedText, Thing>();
|
||||
|
||||
|
@ -469,6 +483,8 @@ void Client::registerLuaFunctions()
|
|||
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>("getItems", &Tile::getItems);
|
||||
g_lua.bindClassMemberFunction<Tile>("getThingStackpos", &Tile::getThingStackpos);
|
||||
g_lua.bindClassMemberFunction<Tile>("getThingCount", &Tile::getThingCount);
|
||||
g_lua.bindClassMemberFunction<Tile>("getTopThing", &Tile::getTopThing);
|
||||
|
@ -495,6 +511,7 @@ void Client::registerLuaFunctions()
|
|||
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>("clearItem", &UIItem::clearItem);
|
||||
|
@ -503,6 +520,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<UIItem>("getItemSubType", &UIItem::getItemSubType);
|
||||
g_lua.bindClassMemberFunction<UIItem>("getItem", &UIItem::getItem);
|
||||
g_lua.bindClassMemberFunction<UIItem>("isVirtual", &UIItem::isVirtual);
|
||||
g_lua.bindClassMemberFunction<UIItem>("isItemVisible", &UIItem::isItemVisible);
|
||||
|
||||
g_lua.registerClass<UICreature, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UICreature>("create", []{ return UICreaturePtr(new UICreature); } );
|
||||
|
|
|
@ -35,6 +35,11 @@
|
|||
Map g_map;
|
||||
TilePtr Map::m_nulltile;
|
||||
|
||||
void Map::init()
|
||||
{
|
||||
resetAwareRange();
|
||||
}
|
||||
|
||||
void Map::terminate()
|
||||
{
|
||||
clean();
|
||||
|
@ -100,14 +105,39 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
|
|||
|
||||
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>());
|
||||
thing->onAppear();
|
||||
} 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) {
|
||||
if(prevAnimatedText) {
|
||||
Point offset = prevAnimatedText->getOffset();
|
||||
float t = prevAnimatedText->getTimer().ticksElapsed();
|
||||
if(t < Otc::ANIMATED_TEXT_DURATION / 4.0) { // didnt move 12 pixels
|
||||
int y = 12 - 48 * t / (float)Otc::ANIMATED_TEXT_DURATION;
|
||||
offset += Point(0, y);
|
||||
}
|
||||
offset.y = std::min(offset.y, 12);
|
||||
animatedText->setOffset(offset);
|
||||
}
|
||||
m_animatedTexts.push_back(animatedText);
|
||||
}
|
||||
} else if(thing->isStaticText()) {
|
||||
StaticTextPtr staticText = thing->static_self_cast<StaticText>();
|
||||
bool mustAdd = true;
|
||||
|
@ -119,10 +149,10 @@ void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos)
|
|||
}
|
||||
}
|
||||
|
||||
if(mustAdd) {
|
||||
if(mustAdd)
|
||||
m_staticTexts.push_back(staticText);
|
||||
staticText->onAppear();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
thing->setPosition(pos);
|
||||
|
@ -181,6 +211,16 @@ bool Map::removeThingByPos(const Position& pos, int stackPos)
|
|||
return false;
|
||||
}
|
||||
|
||||
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())
|
||||
|
@ -251,6 +291,13 @@ void Map::cleanTile(const Position& pos)
|
|||
notificateTileUpdateToMapViews(pos);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void Map::addCreature(const CreaturePtr& creature)
|
||||
|
@ -276,10 +323,8 @@ void Map::removeCreatureById(uint32 id)
|
|||
m_knownCreatures.erase(it);
|
||||
}
|
||||
|
||||
void Map::setCentralPosition(const Position& centralPosition)
|
||||
void Map::removeUnawareThings()
|
||||
{
|
||||
m_centralPosition = centralPosition;
|
||||
|
||||
// remove creatures from tiles that we are not aware anymore
|
||||
for(const auto& pair : m_knownCreatures) {
|
||||
const CreaturePtr& creature = pair.second;
|
||||
|
@ -287,6 +332,25 @@ void Map::setCentralPosition(const Position& centralPosition)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -313,9 +377,14 @@ void Map::setCentralPosition(const Position& centralPosition)
|
|||
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 getSpectatorsInRange(centerPos, multiFloor, (Otc::VISIBLE_X_TILES - 1)/2, (Otc::VISIBLE_Y_TILES - 1)/2);
|
||||
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)
|
||||
|
@ -410,10 +479,26 @@ bool Map::isAwareOfPosition(const Position& pos)
|
|||
else
|
||||
groundedPos.coveredDown();
|
||||
}
|
||||
return m_centralPosition.isInRange(groundedPos, Otc::AWARE_X_LEFT_TILES,
|
||||
Otc::AWARE_X_RIGHT_TILES,
|
||||
Otc::AWARE_Y_TOP_TILES,
|
||||
Otc::AWARE_Y_BOTTOM_TILES);
|
||||
return m_centralPosition.isInRange(groundedPos, m_awareRange.left,
|
||||
m_awareRange.right,
|
||||
m_awareRange.top,
|
||||
m_awareRange.bottom);
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
|
@ -119,10 +119,22 @@ 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; }
|
||||
};
|
||||
|
||||
//@bindsingleton g_map
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
void terminate();
|
||||
|
||||
void addMapView(const MapViewPtr& mapView);
|
||||
|
@ -157,6 +169,8 @@ public:
|
|||
bool removeThing(const ThingPtr& thing);
|
||||
bool removeThingByPos(const Position& pos, int stackPos);
|
||||
|
||||
StaticTextPtr getStaticText(const Position& pos);
|
||||
|
||||
// tile related
|
||||
const TilePtr& createTile(const Position& pos);
|
||||
template <typename... Items>
|
||||
|
@ -169,6 +183,7 @@ public:
|
|||
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);
|
||||
|
@ -181,6 +196,10 @@ public:
|
|||
bool isCompletelyCovered(const Position& pos, int firstFloor = 0);
|
||||
bool isAwareOfPosition(const Position& pos);
|
||||
|
||||
void setAwareRange(const AwareRange& range);
|
||||
void resetAwareRange();
|
||||
AwareRange getAwareRange() { return m_awareRange; }
|
||||
|
||||
Light getLight() { return m_light; }
|
||||
Position getCentralPosition() { return m_centralPosition; }
|
||||
int getFirstAwareFloor();
|
||||
|
@ -193,6 +212,7 @@ public:
|
|||
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps, int flags = 0);
|
||||
|
||||
private:
|
||||
void removeUnawareThings();
|
||||
uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); }
|
||||
|
||||
std::unordered_map<uint, TileBlock> m_tileBlocks[Otc::MAX_Z+1];
|
||||
|
@ -208,6 +228,7 @@ private:
|
|||
Rect m_tilesRect;
|
||||
|
||||
stdext::packed_storage<uint8> m_attribs;
|
||||
AwareRange m_awareRange;
|
||||
static TilePtr m_nulltile;
|
||||
};
|
||||
|
||||
|
|
|
@ -57,8 +57,10 @@ MapView::MapView()
|
|||
m_cachedFirstVisibleFloor = 7;
|
||||
m_cachedLastVisibleFloor = 7;
|
||||
m_updateTilesPos = 0;
|
||||
m_fadeOutTime = 0;
|
||||
m_fadeInTime = 0;
|
||||
m_minimumAmbientLight = 0;
|
||||
m_optimizedSize = Size(Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES) * Otc::TILE_PIXELS;
|
||||
m_optimizedSize = Size(g_map.getAwareRange().horizontal(), g_map.getAwareRange().vertical()) * Otc::TILE_PIXELS;
|
||||
|
||||
m_framebuffer = g_framebuffers.createFrameBuffer();
|
||||
setVisibleDimension(Size(15, 11));
|
||||
|
@ -155,6 +157,21 @@ void MapView::draw(const Rect& rect)
|
|||
m_mustDrawVisibleTilesCache = false;
|
||||
}
|
||||
|
||||
|
||||
float fadeOpacity = 1.0f;
|
||||
if(!m_shaderSwitchDone && m_fadeOutTime > 0) {
|
||||
fadeOpacity = 1.0f - (m_fadeTimer.timeElapsed() / m_fadeOutTime);
|
||||
if(fadeOpacity < 0.0f) {
|
||||
m_shader = m_nextShader;
|
||||
m_nextShader = nullptr;
|
||||
m_shaderSwitchDone = true;
|
||||
m_fadeTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
if(m_shaderSwitchDone && m_shader && m_fadeInTime > 0)
|
||||
fadeOpacity = std::min(m_fadeTimer.timeElapsed() / m_fadeInTime, 1.0f);
|
||||
|
||||
Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * m_tileSize;
|
||||
if(isFollowingCreature())
|
||||
drawOffset += m_followingCreature->getWalkOffset() * scaleFactor;
|
||||
|
@ -166,9 +183,20 @@ void MapView::draw(const Rect& rect)
|
|||
drawOffset.y += (srcVisible.height() - srcSize.height()) / 2;
|
||||
Rect srcRect = Rect(drawOffset, srcSize);
|
||||
|
||||
g_painter->setColor(Color::white);
|
||||
glDisable(GL_BLEND);
|
||||
if(m_shader && g_painter->hasShaders() && g_graphics.shouldUseShaders() && m_viewMode == NEAR_VIEW) {
|
||||
Rect framebufferRect = Rect(0,0, m_drawDimension * m_tileSize);
|
||||
Point center = srcRect.center();
|
||||
Point globalCoord = Point(cameraPosition.x - m_drawDimension.width()/2, -(cameraPosition.y - m_drawDimension.height()/2)) * m_tileSize;
|
||||
m_shader->bind();
|
||||
m_shader->setUniformValue(ShaderManager::MAP_CENTER_COORD, center.x / (float)framebufferRect.width(), 1.0f - center.y / (float)framebufferRect.height());
|
||||
m_shader->setUniformValue(ShaderManager::MAP_GLOBAL_COORD, globalCoord.x / (float)framebufferRect.height(), globalCoord.y / (float)framebufferRect.height());
|
||||
m_shader->setUniformValue(ShaderManager::MAP_ZOOM, scaleFactor);
|
||||
g_painter->setShaderProgram(m_shader);
|
||||
}
|
||||
|
||||
g_painter->setColor(Color::white);
|
||||
g_painter->setOpacity(fadeOpacity);
|
||||
glDisable(GL_BLEND);
|
||||
#if 0
|
||||
// debug source area
|
||||
g_painter->saveAndResetState();
|
||||
|
@ -182,6 +210,7 @@ void MapView::draw(const Rect& rect)
|
|||
m_framebuffer->draw(rect, srcRect);
|
||||
#endif
|
||||
g_painter->resetShaderProgram();
|
||||
g_painter->resetOpacity();
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
|
||||
|
@ -198,10 +227,11 @@ void MapView::draw(const Rect& rect)
|
|||
if(!creature->canBeSeen())
|
||||
continue;
|
||||
|
||||
PointF jumpOffset = creature->getJumpOffset() * scaleFactor;
|
||||
Point creatureOffset = Point(16 - creature->getDisplacementX(), -3 - creature->getDisplacementY());
|
||||
Position pos = creature->getPosition();
|
||||
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
|
||||
p += (creature->getDrawOffset() + creatureOffset) * scaleFactor;
|
||||
p += (creature->getDrawOffset() + creatureOffset) * scaleFactor - Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
p.y = p.y * verticalStretchFactor;
|
||||
p += rect.topLeft();
|
||||
|
@ -222,6 +252,9 @@ void MapView::draw(const Rect& rect)
|
|||
//if(pos.z != cameraPosition.z && !staticText->isYell())
|
||||
// continue;
|
||||
|
||||
if(pos.z != cameraPosition.z && staticText->getMessageMode() == Otc::MessageNone)
|
||||
continue;
|
||||
|
||||
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
p.y = p.y * verticalStretchFactor;
|
||||
|
@ -232,6 +265,7 @@ void MapView::draw(const Rect& rect)
|
|||
for(const AnimatedTextPtr& animatedText : g_map.getAnimatedTexts()) {
|
||||
Position pos = animatedText->getPosition();
|
||||
|
||||
/*
|
||||
// only draw animated texts from visible floors
|
||||
if(pos.z < m_cachedFirstVisibleFloor || pos.z > m_cachedLastVisibleFloor)
|
||||
continue;
|
||||
|
@ -239,6 +273,9 @@ void MapView::draw(const Rect& rect)
|
|||
// dont draw animated texts from covered tiles
|
||||
if(pos.z != cameraPosition.z && g_map.isCovered(pos, m_cachedFirstVisibleFloor))
|
||||
continue;
|
||||
*/
|
||||
if(pos.z != cameraPosition.z)
|
||||
continue;
|
||||
|
||||
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
|
||||
p.x = p.x * horizontalStretchFactor;
|
||||
|
@ -408,7 +445,7 @@ void MapView::updateVisibleTilesCache(int start)
|
|||
}
|
||||
|
||||
if(start == 0 && m_viewMode <= NEAR_VIEW)
|
||||
m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false);
|
||||
m_cachedFloorVisibleCreatures = g_map.getSightSpectators(cameraPosition, false);
|
||||
}
|
||||
|
||||
void MapView::updateGeometry(const Size& visibleDimension, const Size& optimizedSize)
|
||||
|
@ -656,10 +693,30 @@ void MapView::setDrawMinimapColors(bool enable)
|
|||
m_framebuffer->setSmooth(m_smooth);
|
||||
}
|
||||
|
||||
void MapView::setShader(const PainterShaderProgramPtr& shader, float fadein, float fadeout)
|
||||
{
|
||||
if((m_shader == shader && m_shaderSwitchDone) || (m_nextShader == shader && !m_shaderSwitchDone))
|
||||
return;
|
||||
|
||||
if(fadeout > 0.0f && m_shader) {
|
||||
m_nextShader = shader;
|
||||
m_shaderSwitchDone = false;
|
||||
} else {
|
||||
m_shader = shader;
|
||||
m_nextShader = nullptr;
|
||||
m_shaderSwitchDone = true;
|
||||
}
|
||||
m_fadeTimer.restart();
|
||||
m_fadeInTime = fadein;
|
||||
m_fadeOutTime = fadeout;
|
||||
}
|
||||
|
||||
|
||||
void MapView::setDrawLights(bool enable)
|
||||
{
|
||||
if(enable == m_drawLights)
|
||||
return;
|
||||
|
||||
if(enable)
|
||||
m_lightView = LightViewPtr(new LightView);
|
||||
else
|
||||
|
|
|
@ -107,10 +107,9 @@ public:
|
|||
void setDrawLights(bool enable);
|
||||
bool isDrawingLights() { return m_drawLights; }
|
||||
|
||||
void setShader(const PainterShaderProgramPtr& shader) { m_shader = shader; }
|
||||
void setShader(const PainterShaderProgramPtr& shader, float fadein, float fadeout);
|
||||
PainterShaderProgramPtr getShader() { return m_shader; }
|
||||
|
||||
|
||||
MapViewPtr asMapView() { return static_self_cast<MapView>(); }
|
||||
|
||||
private:
|
||||
|
@ -153,6 +152,11 @@ private:
|
|||
std::vector<Point> m_spiral;
|
||||
LightViewPtr m_lightView;
|
||||
float m_minimumAmbientLight;
|
||||
Timer m_fadeTimer;
|
||||
PainterShaderProgramPtr m_nextShader;
|
||||
float m_fadeInTime;
|
||||
float m_fadeOutTime;
|
||||
stdext::boolean<true> m_shaderSwitchDone;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,7 +33,8 @@ namespace Proto {
|
|||
LoginServerCharacterList = 100
|
||||
};
|
||||
|
||||
enum CreatureOpcode {
|
||||
enum ItemOpcode {
|
||||
StaticText = 96,
|
||||
UnknownCreature = 97,
|
||||
OutdatedCreature = 98,
|
||||
Creature = 99
|
||||
|
@ -44,6 +45,7 @@ namespace Proto {
|
|||
GameServerInitGame = 10,
|
||||
GameServerGMActions = 11,
|
||||
GameServerEnterGame = 15,
|
||||
GameServerUpdateNeeded = 17,
|
||||
GameServerLoginError = 20,
|
||||
GameServerLoginAdvice = 21,
|
||||
GameServerLoginWait = 22,
|
||||
|
@ -61,6 +63,7 @@ namespace Proto {
|
|||
|
||||
// NOTE: add any custom opcodes in this range
|
||||
// 51 - 99
|
||||
GameServerChangeMapAwareRange = 51,
|
||||
|
||||
// original tibia ONLY
|
||||
GameServerFullMap = 100,
|
||||
|
@ -156,6 +159,7 @@ namespace Proto {
|
|||
|
||||
// otclient ONLY
|
||||
ClientExtendedOpcode = 50,
|
||||
ClientChangeMapAwareRange = 51,
|
||||
|
||||
// NOTE: add any custom opcodes in this range
|
||||
// 51 - 99
|
||||
|
|
|
@ -26,11 +26,12 @@
|
|||
#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)
|
||||
void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& locale)
|
||||
{
|
||||
m_accountName = accountName;
|
||||
m_accountPassword = accountPassword;
|
||||
m_characterName = characterName;
|
||||
m_locale = locale;
|
||||
|
||||
connect(host, port);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
class ProtocolGame : public Protocol
|
||||
{
|
||||
public:
|
||||
void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName);
|
||||
void login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName, const std::string& locale);
|
||||
void send(const OutputMessagePtr& outputMessage);
|
||||
|
||||
void sendExtendedOpcode(uint8 opcode, const std::string& buffer);
|
||||
|
@ -107,6 +107,7 @@ public:
|
|||
void sendNewNewRuleViolation(int reason, int action, const std::string& characterName, const std::string& comment, const std::string& translation);
|
||||
void sendRequestItemInfo(int itemId, int subType, int index);
|
||||
void sendAnswerModalDialog(int dialog, int button, int choice);
|
||||
void sendChangeMapAwareRange(int xrange, int yrange);
|
||||
|
||||
protected:
|
||||
void onConnect();
|
||||
|
@ -124,6 +125,7 @@ private:
|
|||
void parseEnterGame(const InputMessagePtr& msg);
|
||||
void parseInitGame(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);
|
||||
|
@ -205,6 +207,7 @@ private:
|
|||
void parsePlayerInventory(const InputMessagePtr& msg);
|
||||
void parseShowModalDialog(const InputMessagePtr& msg);
|
||||
void parseExtendedOpcode(const InputMessagePtr& msg);
|
||||
void parseChangeMapAwareRange(const InputMessagePtr& msg);
|
||||
|
||||
public:
|
||||
void setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height);
|
||||
|
@ -215,6 +218,7 @@ public:
|
|||
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);
|
||||
Position getPosition(const InputMessagePtr& msg);
|
||||
|
||||
|
@ -226,6 +230,7 @@ private:
|
|||
std::string m_accountName;
|
||||
std::string m_accountPassword;
|
||||
std::string m_characterName;
|
||||
std::string m_locale;
|
||||
stdext::timer m_pingTimer;
|
||||
LocalPlayerPtr m_localPlayer;
|
||||
};
|
||||
|
|
|
@ -72,6 +72,9 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||
case Proto::GameServerGMActions:
|
||||
parseGMActions(msg);
|
||||
break;
|
||||
case Proto::GameServerUpdateNeeded:
|
||||
parseUpdateNeeded(msg);
|
||||
break;
|
||||
case Proto::GameServerLoginError:
|
||||
parseLoginError(msg);
|
||||
break;
|
||||
|
@ -314,13 +317,16 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||
case Proto::GameServerPlayerDataBasic:
|
||||
parsePlayerInfo(msg);
|
||||
break;
|
||||
// PROTOCOL>=970
|
||||
case Proto::GameServerShowModalDialog:
|
||||
parseShowModalDialog(msg);
|
||||
break;
|
||||
// otclient ONLY
|
||||
case Proto::GameServerExtendedOpcode:
|
||||
parseExtendedOpcode(msg);
|
||||
break;
|
||||
// PROTOCOL>=970
|
||||
case Proto::GameServerShowModalDialog:
|
||||
parseShowModalDialog(msg);
|
||||
case Proto::GameServerChangeMapAwareRange:
|
||||
parseChangeMapAwareRange(msg);
|
||||
break;
|
||||
default:
|
||||
stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
|
||||
|
@ -386,6 +392,12 @@ void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
|
|||
g_game.processGMActions(actions);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseUpdateNeeded(const InputMessagePtr& msg)
|
||||
{
|
||||
std::string signature = msg->getString();
|
||||
g_game.processUpdateNeeded(signature);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseLoginError(const InputMessagePtr& msg)
|
||||
{
|
||||
std::string error = msg->getString();
|
||||
|
@ -441,7 +453,9 @@ void ProtocolGame::parseMapDescription(const InputMessagePtr& msg)
|
|||
m_localPlayer->setPosition(pos);
|
||||
|
||||
g_map.setCentralPosition(pos);
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES);
|
||||
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), range.vertical());
|
||||
|
||||
if(!m_mapKnown) {
|
||||
g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapKnown"); });
|
||||
|
@ -453,37 +467,57 @@ void ProtocolGame::parseMapDescription(const InputMessagePtr& msg)
|
|||
|
||||
void ProtocolGame::parseMapMoveNorth(const InputMessagePtr& msg)
|
||||
{
|
||||
Position pos = g_map.getCentralPosition();
|
||||
Position pos;
|
||||
if(g_game.getFeature(Otc::GameMapMovePosition))
|
||||
pos = getPosition(msg);
|
||||
else
|
||||
pos = g_map.getCentralPosition();
|
||||
pos.y--;
|
||||
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, 1);
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), 1);
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseMapMoveEast(const InputMessagePtr& msg)
|
||||
{
|
||||
Position pos = g_map.getCentralPosition();
|
||||
Position pos;
|
||||
if(g_game.getFeature(Otc::GameMapMovePosition))
|
||||
pos = getPosition(msg);
|
||||
else
|
||||
pos = g_map.getCentralPosition();
|
||||
pos.x++;
|
||||
|
||||
setMapDescription(msg, pos.x + Otc::AWARE_X_RIGHT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
setMapDescription(msg, pos.x + range.right, pos.y - range.top, pos.z, 1, range.vertical());
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseMapMoveSouth(const InputMessagePtr& msg)
|
||||
{
|
||||
Position pos = g_map.getCentralPosition();
|
||||
Position pos;
|
||||
if(g_game.getFeature(Otc::GameMapMovePosition))
|
||||
pos = getPosition(msg);
|
||||
else
|
||||
pos = g_map.getCentralPosition();
|
||||
pos.y++;
|
||||
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y + Otc::AWARE_Y_BOTTOM_TILES, pos.z, Otc::AWARE_X_TILES, 1);
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
setMapDescription(msg, pos.x - range.left, pos.y + range.bottom, pos.z, range.horizontal(), 1);
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseMapMoveWest(const InputMessagePtr& msg)
|
||||
{
|
||||
Position pos = g_map.getCentralPosition();
|
||||
Position pos;
|
||||
if(g_game.getFeature(Otc::GameMapMovePosition))
|
||||
pos = getPosition(msg);
|
||||
else
|
||||
pos = g_map.getCentralPosition();
|
||||
pos.x--;
|
||||
|
||||
setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, 1, range.vertical());
|
||||
g_map.setCentralPosition(pos);
|
||||
}
|
||||
|
||||
|
@ -914,8 +948,16 @@ void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
|
|||
|
||||
void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
||||
{
|
||||
double health = msg->getU16();
|
||||
double maxHealth = msg->getU16();
|
||||
double health;
|
||||
double maxHealth;
|
||||
|
||||
if(g_game.getFeature(Otc::GameDoubleHealth)) {
|
||||
health = msg->getU32();
|
||||
maxHealth = msg->getU32();
|
||||
} else {
|
||||
health = msg->getU16();
|
||||
maxHealth = msg->getU16();
|
||||
}
|
||||
|
||||
double freeCapacity;
|
||||
if(g_game.getFeature(Otc::GameDoubleFreeCapacity))
|
||||
|
@ -935,8 +977,17 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||
|
||||
double level = msg->getU16();
|
||||
double levelPercent = msg->getU8();
|
||||
double mana = msg->getU16();
|
||||
double maxMana = msg->getU16();
|
||||
double mana;
|
||||
double maxMana;
|
||||
|
||||
if(g_game.getFeature(Otc::GameDoubleHealth)) {
|
||||
mana = msg->getU32();
|
||||
maxMana = msg->getU32();
|
||||
} else {
|
||||
mana = msg->getU16();
|
||||
maxMana = msg->getU16();
|
||||
}
|
||||
|
||||
double magicLevel = msg->getU8();
|
||||
|
||||
double baseMagicLevel;
|
||||
|
@ -979,10 +1030,16 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||
void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
||||
{
|
||||
for(int skill = 0; skill < Otc::LastSkill; skill++) {
|
||||
int level = msg->getU8();
|
||||
int level;
|
||||
|
||||
if(g_game.getFeature(Otc::GameDoubleSkills))
|
||||
level = msg->getU16();
|
||||
else
|
||||
level = msg->getU8();
|
||||
|
||||
int baseLevel;
|
||||
if(g_game.getFeature(Otc::GameSkillsBase))
|
||||
baseLevel = msg->getU8(); // base
|
||||
baseLevel = msg->getU8();
|
||||
else
|
||||
baseLevel = level;
|
||||
|
||||
|
@ -1002,7 +1059,7 @@ void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
|
|||
void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
|
||||
{
|
||||
uint seq = 0;
|
||||
if(g_game.getProtocolVersion() >= 860)
|
||||
if(g_game.getFeature(Otc::GameAttackSeq))
|
||||
seq = msg->getU32();
|
||||
|
||||
g_game.processAttackCancel(seq);
|
||||
|
@ -1234,15 +1291,20 @@ void ProtocolGame::parseWalkWait(const InputMessagePtr& msg)
|
|||
|
||||
void ProtocolGame::parseFloorChangeUp(const InputMessagePtr& msg)
|
||||
{
|
||||
Position pos = g_map.getCentralPosition();
|
||||
Position pos;
|
||||
if(g_game.getFeature(Otc::GameMapMovePosition))
|
||||
pos = getPosition(msg);
|
||||
else
|
||||
pos = g_map.getCentralPosition();
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
pos.z--;
|
||||
|
||||
int skip = 0;
|
||||
if(pos.z == Otc::SEA_FLOOR)
|
||||
for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
|
||||
skip = setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 8 - i, skip);
|
||||
skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), 8 - i, skip);
|
||||
else if(pos.z > Otc::SEA_FLOOR)
|
||||
skip = setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 3, skip);
|
||||
skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), 3, skip);
|
||||
|
||||
pos.x++;
|
||||
pos.y++;
|
||||
|
@ -1251,17 +1313,22 @@ void ProtocolGame::parseFloorChangeUp(const InputMessagePtr& msg)
|
|||
|
||||
void ProtocolGame::parseFloorChangeDown(const InputMessagePtr& msg)
|
||||
{
|
||||
Position pos = g_map.getCentralPosition();
|
||||
Position pos;
|
||||
if(g_game.getFeature(Otc::GameMapMovePosition))
|
||||
pos = getPosition(msg);
|
||||
else
|
||||
pos = g_map.getCentralPosition();
|
||||
AwareRange range = g_map.getAwareRange();
|
||||
pos.z++;
|
||||
|
||||
int skip = 0;
|
||||
if(pos.z == Otc::UNDERGROUND_FLOOR) {
|
||||
int j, i;
|
||||
for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
|
||||
skip = setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, j, skip);
|
||||
skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), j, skip);
|
||||
}
|
||||
else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
|
||||
skip = setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, -3, skip);
|
||||
skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), -3, skip);
|
||||
|
||||
pos.x--;
|
||||
pos.y--;
|
||||
|
@ -1458,10 +1525,27 @@ void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
|
|||
|
||||
if(opcode == 0)
|
||||
m_enableSendExtendedOpcode = true;
|
||||
else if(opcode == 2)
|
||||
parsePingBack(msg);
|
||||
else
|
||||
callLuaField("onExtendedOpcode", opcode, buffer);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg)
|
||||
{
|
||||
int xrange = msg->getU8();
|
||||
int yrange = msg->getU8();
|
||||
|
||||
AwareRange range;
|
||||
range.left = xrange/2 - ((xrange+1) % 2);
|
||||
range.right = xrange/2;
|
||||
range.top = yrange/2 - ((yrange+1) % 2);
|
||||
range.bottom = yrange/2;
|
||||
|
||||
g_map.setAwareRange(range);
|
||||
g_lua.callGlobalField("g_game", "onMapChangeAwareRange", xrange, yrange);
|
||||
}
|
||||
|
||||
void ProtocolGame::setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height)
|
||||
{
|
||||
int startz, endz, zstep;
|
||||
|
@ -1502,7 +1586,7 @@ int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position positi
|
|||
{
|
||||
g_map.cleanTile(position);
|
||||
|
||||
bool gotEffect = 0;
|
||||
bool gotEffect = false;
|
||||
for(int stackPos=0;stackPos<256;stackPos++) {
|
||||
if(msg->peekU16() >= 0xff00)
|
||||
return msg->getU16() & 0xff;
|
||||
|
@ -1558,6 +1642,7 @@ Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
|
|||
int mount = msg->getU16();
|
||||
outfit.setMount(mount);
|
||||
}
|
||||
|
||||
return outfit;
|
||||
}
|
||||
|
||||
|
@ -1571,6 +1656,8 @@ ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
|
|||
stdext::throw_exception("invalid thing id");
|
||||
else if(id == Proto::UnknownCreature || id == Proto::OutdatedCreature || id == Proto::Creature)
|
||||
thing = getCreature(msg, id);
|
||||
else if(id == Proto::StaticText) // otclient only
|
||||
thing = getStaticText(msg, id);
|
||||
else // item
|
||||
thing = getItem(msg, id);
|
||||
|
||||
|
@ -1745,6 +1832,19 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
|
|||
return item;
|
||||
}
|
||||
|
||||
StaticTextPtr ProtocolGame::getStaticText(const InputMessagePtr& msg, int id)
|
||||
{
|
||||
int colorByte = msg->getU8();
|
||||
Color color = Color::from8bit(colorByte);
|
||||
std::string fontName = msg->getString();
|
||||
std::string text = msg->getString();
|
||||
StaticTextPtr staticText = StaticTextPtr(new StaticText);
|
||||
staticText->setText(text);
|
||||
staticText->setFont(fontName);
|
||||
staticText->setColor(color);
|
||||
return staticText;
|
||||
}
|
||||
|
||||
Position ProtocolGame::getPosition(const InputMessagePtr& msg)
|
||||
{
|
||||
uint16 x = msg->getU16();
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "protocolgame.h"
|
||||
#include "game.h"
|
||||
#include "client.h"
|
||||
#include <framework/core/application.h>
|
||||
|
||||
void ProtocolGame::send(const OutputMessagePtr& outputMessage)
|
||||
{
|
||||
|
@ -50,7 +52,16 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
|
|||
|
||||
msg->addU8(Proto::ClientPendingGame);
|
||||
|
||||
msg->addU16(g_lua.callGlobalField<int>("g_game", "getOsType"));
|
||||
msg->addU16(g_game.getOs());
|
||||
|
||||
if(g_game.getFeature(Otc::GameUpdater)) {
|
||||
msg->addString(g_app.getOs());
|
||||
msg->addString(g_game.getUpdaterSignature());
|
||||
}
|
||||
|
||||
if(g_game.getFeature(Otc::GameLoginLocale))
|
||||
msg->addString(m_locale);
|
||||
|
||||
msg->addU16(g_game.getProtocolVersion());
|
||||
|
||||
if(g_game.getProtocolVersion() >= 971) {
|
||||
|
@ -92,6 +103,12 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
|
|||
paddingBytes -= 5;
|
||||
}
|
||||
|
||||
if(paddingBytes < 0) {
|
||||
g_game.processLoginError("AccountName or Password or CharacterName are too big!\nPlease contact game support.");
|
||||
g_game.processDisconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
// complete the 128 bytes for rsa encryption with zeros
|
||||
msg->addPaddingBytes(paddingBytes);
|
||||
|
||||
|
@ -119,10 +136,14 @@ void ProtocolGame::sendLogout()
|
|||
|
||||
void ProtocolGame::sendPing()
|
||||
{
|
||||
if(g_game.getFeature(Otc::GameExtendedClientPing))
|
||||
sendExtendedOpcode(2, "");
|
||||
else {
|
||||
OutputMessagePtr msg(new OutputMessage);
|
||||
msg->addU8(Proto::ClientPing);
|
||||
m_pingTimer.restart();
|
||||
Protocol::send(msg);
|
||||
}
|
||||
m_pingTimer.restart();
|
||||
}
|
||||
|
||||
void ProtocolGame::sendPingBack()
|
||||
|
@ -774,6 +795,18 @@ void ProtocolGame::sendAnswerModalDialog(int dialog, int button, int choice)
|
|||
send(msg);
|
||||
}
|
||||
|
||||
void ProtocolGame::sendChangeMapAwareRange(int xrange, int yrange)
|
||||
{
|
||||
if(!g_game.getFeature(Otc::GameChangeMapAwareRange))
|
||||
return;
|
||||
|
||||
OutputMessagePtr msg(new OutputMessage);
|
||||
msg->addU8(Proto::ClientChangeMapAwareRange);
|
||||
msg->addU8(xrange);
|
||||
msg->addU8(yrange);
|
||||
send(msg);
|
||||
}
|
||||
|
||||
void ProtocolGame::addPosition(const OutputMessagePtr& msg, const Position& position)
|
||||
{
|
||||
msg->addU16(position.x);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <framework/graphics/paintershaderprogram.h>
|
||||
#include <framework/graphics/graphics.h>
|
||||
#include <framework/graphics/painterogl2_shadersources.h>
|
||||
#include <framework/core/resourcemanager.h>
|
||||
|
||||
ShaderManager g_shaders;
|
||||
|
||||
|
@ -59,12 +60,14 @@ PainterShaderProgramPtr ShaderManager::createShader(const std::string& name)
|
|||
return shader;
|
||||
}
|
||||
|
||||
PainterShaderProgramPtr ShaderManager::createFragmentShader(const std::string& name, const std::string& file)
|
||||
PainterShaderProgramPtr ShaderManager::createFragmentShader(const std::string& name, std::string file)
|
||||
{
|
||||
PainterShaderProgramPtr shader = createShader(name);
|
||||
if(!shader)
|
||||
return nullptr;
|
||||
|
||||
file = g_resources.guessFileType(file, "frag");
|
||||
|
||||
shader->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
|
||||
if(!shader->addShaderFromSourceFile(Shader::Fragment, file)) {
|
||||
g_logger.error(stdext::format("unable to load fragment shader '%s' from source file '%s'", name, file));
|
||||
|
@ -109,6 +112,14 @@ PainterShaderProgramPtr ShaderManager::createItemShader(const std::string& name,
|
|||
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)
|
||||
|
@ -116,6 +127,15 @@ void ShaderManager::setupItemShader(const PainterShaderProgramPtr& shader)
|
|||
shader->bindUniformLocation(ITEM_ID_UNIFORM, "u_ItemId");
|
||||
}
|
||||
|
||||
void ShaderManager::setupMapShader(const PainterShaderProgramPtr& shader)
|
||||
{
|
||||
if(!shader)
|
||||
return;
|
||||
shader->bindUniformLocation(MAP_CENTER_COORD, "u_MapCenterCoord");
|
||||
shader->bindUniformLocation(MAP_GLOBAL_COORD, "u_MapGlobalCoord");
|
||||
shader->bindUniformLocation(MAP_ZOOM, "u_MapZoom");
|
||||
}
|
||||
|
||||
PainterShaderProgramPtr ShaderManager::getShader(const std::string& name)
|
||||
{
|
||||
auto it = m_shaders.find(name);
|
||||
|
@ -123,3 +143,4 @@ PainterShaderProgramPtr ShaderManager::getShader(const std::string& name)
|
|||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,18 +31,21 @@ class ShaderManager
|
|||
{
|
||||
public:
|
||||
enum {
|
||||
ITEM_ID_UNIFORM = 10
|
||||
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, const std::string& file);
|
||||
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) { return createFragmentShader(name, file); }
|
||||
PainterShaderProgramPtr createMapShader(const std::string& name, const std::string& file);
|
||||
|
||||
const PainterShaderProgramPtr& getDefaultItemShader() { return m_defaultItemShader; }
|
||||
const PainterShaderProgramPtr& getDefaultMapShader() { return m_defaultMapShader; }
|
||||
|
@ -51,6 +54,7 @@ public:
|
|||
|
||||
private:
|
||||
void setupItemShader(const PainterShaderProgramPtr& shader);
|
||||
void setupMapShader(const PainterShaderProgramPtr& shader);
|
||||
|
||||
PainterShaderProgramPtr m_defaultItemShader;
|
||||
PainterShaderProgramPtr m_defaultMapShader;
|
||||
|
@ -61,3 +65,4 @@ private:
|
|||
extern ShaderManager g_shaders;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -39,12 +39,14 @@ void SpriteManager::terminate()
|
|||
unload();
|
||||
}
|
||||
|
||||
bool SpriteManager::loadSpr(const std::string& file)
|
||||
bool SpriteManager::loadSpr(std::string file)
|
||||
{
|
||||
m_spritesCount = 0;
|
||||
m_signature = 0;
|
||||
m_loaded = false;
|
||||
try {
|
||||
file = g_resources.guessFileType(file, "spr");
|
||||
|
||||
m_spritesFile = g_resources.openFile(file);
|
||||
// cache file buffer to avoid lags from hard drive
|
||||
m_spritesFile->cache();
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
|
||||
void terminate();
|
||||
|
||||
bool loadSpr(const std::string& file);
|
||||
bool loadSpr(std::string file);
|
||||
void unload();
|
||||
|
||||
uint32 getSignature() { return m_signature; }
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
StaticText::StaticText()
|
||||
{
|
||||
m_mode = Otc::MessageNone;
|
||||
m_color = Color::white;
|
||||
m_cachedText.setFont(g_fonts.getFont("verdana-11px-rounded"));
|
||||
m_cachedText.setAlign(Fw::AlignCenter);
|
||||
}
|
||||
|
@ -47,6 +49,16 @@ void StaticText::drawText(const Point& dest, const Rect& parentRect)
|
|||
//}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//TODO: this could be moved to lua
|
||||
|
|
|
@ -41,11 +41,16 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
StaticTextPtr asStaticText() { return static_self_cast<StaticText>(); }
|
||||
bool isStaticText() { return true; }
|
||||
|
||||
void setColor(const Color& color) { m_color = color; }
|
||||
Color getColor() { return m_color; }
|
||||
|
||||
private:
|
||||
void update();
|
||||
void scheduleUpdate();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <framework/graphics/image.h>
|
||||
#include <framework/graphics/texturemanager.h>
|
||||
#include <framework/core/filestream.h>
|
||||
#include <framework/otml/otml.h>
|
||||
|
||||
ThingType::ThingType()
|
||||
{
|
||||
|
@ -41,6 +42,7 @@ ThingType::ThingType()
|
|||
m_animationPhases = 0;
|
||||
m_layers = 0;
|
||||
m_elevation = 0;
|
||||
m_opacity = 1.0f;
|
||||
}
|
||||
|
||||
void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin)
|
||||
|
@ -139,6 +141,16 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS
|
|||
m_texturesFramesOffsets.resize(m_animationPhases);
|
||||
}
|
||||
|
||||
void ThingType::unserializeOtml(const OTMLNodePtr& node)
|
||||
{
|
||||
for(const OTMLNodePtr& node2 : node->children()) {
|
||||
if(node2->tag() == "opacity")
|
||||
m_opacity = node2->value<float>();
|
||||
if(node2->tag() == "notprewalkable")
|
||||
m_attribs.set(ThingAttrNotPreWalkable, node2->value<bool>());
|
||||
}
|
||||
}
|
||||
|
||||
void ThingType::draw(const Point& dest, float scaleFactor, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, LightView *lightView)
|
||||
{
|
||||
if(m_null)
|
||||
|
@ -160,6 +172,7 @@ void ThingType::draw(const Point& dest, float scaleFactor, int layer, int xPatte
|
|||
Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * 32) * scaleFactor,
|
||||
textureRect.size() * scaleFactor);
|
||||
|
||||
g_painter->setOpacity(m_opacity);
|
||||
g_painter->drawTexturedRect(screenRect, texture, textureRect);
|
||||
|
||||
if(lightView && hasLight()) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "declarations.h"
|
||||
|
||||
#include <framework/core/declarations.h>
|
||||
#include <framework/otml/declarations.h>
|
||||
#include <framework/graphics/texture.h>
|
||||
#include <framework/graphics/coordsbuffer.h>
|
||||
#include <framework/luaengine/luaobject.h>
|
||||
|
@ -75,6 +76,11 @@ enum ThingAttr : uint8 {
|
|||
ThingAttrLook = 31,
|
||||
ThingAttrCloth = 32,
|
||||
ThingAttrMarket = 33,
|
||||
|
||||
// additional
|
||||
ThingAttrOpacity = 100,
|
||||
ThingAttrNotPreWalkable = 101,
|
||||
|
||||
ThingAttrChargeable = 254, // deprecated
|
||||
ThingLastAttr = 255
|
||||
};
|
||||
|
@ -107,6 +113,7 @@ public:
|
|||
ThingType();
|
||||
|
||||
void unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin);
|
||||
void unserializeOtml(const OTMLNodePtr& node);
|
||||
|
||||
void draw(const Point& dest, float scaleFactor, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, LightView *lightView = nullptr);
|
||||
|
||||
|
@ -172,6 +179,10 @@ public:
|
|||
bool isCloth() { return m_attribs.has(ThingAttrCloth); }
|
||||
bool isMarketable() { return m_attribs.has(ThingAttrMarket); }
|
||||
|
||||
// additional
|
||||
float getOpacity() { return m_opacity; }
|
||||
bool isNotPreWalkable() { return m_attribs.has(ThingAttrNotPreWalkable); }
|
||||
|
||||
private:
|
||||
const TexturePtr& getTexture(int animationPhase);
|
||||
Size getBestTextureDimension(int w, int h, int count);
|
||||
|
@ -190,6 +201,7 @@ private:
|
|||
int m_animationPhases;
|
||||
int m_layers;
|
||||
int m_elevation;
|
||||
float m_opacity;
|
||||
|
||||
std::vector<int> m_spritesIndex;
|
||||
std::vector<TexturePtr> m_textures;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <framework/core/filestream.h>
|
||||
#include <framework/core/binarytree.h>
|
||||
#include <framework/xml/tinyxml.h>
|
||||
#include <framework/otml/otml.h>
|
||||
|
||||
ThingTypeManager g_things;
|
||||
|
||||
|
@ -60,11 +61,13 @@ void ThingTypeManager::terminate()
|
|||
m_nullItemType = nullptr;
|
||||
}
|
||||
|
||||
bool ThingTypeManager::loadDat(const std::string& file)
|
||||
bool ThingTypeManager::loadDat(std::string file)
|
||||
{
|
||||
m_datLoaded = false;
|
||||
m_datSignature = 0;
|
||||
try {
|
||||
file = g_resources.guessFileType(file, "dat");
|
||||
|
||||
FileStreamPtr fin = g_resources.openFile(file);
|
||||
|
||||
m_datSignature = fin->getU32();
|
||||
|
@ -95,6 +98,41 @@ bool ThingTypeManager::loadDat(const std::string& file)
|
|||
}
|
||||
}
|
||||
|
||||
bool ThingTypeManager::loadOtml(std::string file)
|
||||
{
|
||||
try {
|
||||
file = g_resources.guessFileType(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)
|
||||
{
|
||||
FileStreamPtr fin = g_resources.openFile(file);
|
||||
|
|
|
@ -35,7 +35,8 @@ public:
|
|||
void init();
|
||||
void terminate();
|
||||
|
||||
bool loadDat(const std::string& file);
|
||||
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);
|
||||
|
|
|
@ -278,14 +278,13 @@ bool Tile::hasThing(const ThingPtr& thing)
|
|||
|
||||
int Tile::getThingStackpos(const ThingPtr& thing)
|
||||
{
|
||||
for(uint stackpos = 0; stackpos < m_things.size(); ++stackpos) {
|
||||
for(uint stackpos = 0; stackpos < m_things.size(); ++stackpos)
|
||||
if(thing == m_things[stackpos])
|
||||
return stackpos;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ThingPtr Tile:: getTopThing()
|
||||
ThingPtr Tile::getTopThing()
|
||||
{
|
||||
if(isEmpty())
|
||||
return nullptr;
|
||||
|
@ -374,6 +373,12 @@ ThingPtr Tile::getTopUseThing()
|
|||
return thing;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < m_things.size(); ++i) {
|
||||
ThingPtr thing = m_things[i];
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isCreature())
|
||||
return thing;
|
||||
}
|
||||
|
||||
return m_things[0];
|
||||
}
|
||||
|
||||
|
@ -434,31 +439,35 @@ ThingPtr Tile::getTopMoveThing()
|
|||
return m_things[0];
|
||||
}
|
||||
|
||||
ThingPtr Tile::getTopMultiUseThing(bool ignoreCreature)
|
||||
ThingPtr Tile::getTopMultiUseThing()
|
||||
{
|
||||
// this is related to classic controls, getting top item, forceuse for creature
|
||||
if(isEmpty())
|
||||
return nullptr;
|
||||
|
||||
for(uint i = 0; i < m_things.size(); ++i) {
|
||||
ThingPtr thing = m_things[i];
|
||||
if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) {
|
||||
if(thing->isCreature() && ignoreCreature)
|
||||
continue;
|
||||
if(thing->isForceUse())
|
||||
return thing;
|
||||
}
|
||||
|
||||
if(CreaturePtr topCreature = getTopCreature())
|
||||
return topCreature;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(uint i = 0; i < m_things.size(); ++i) {
|
||||
ThingPtr thing = m_things[i];
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnTop()) {
|
||||
if(thing->isCreature() && ignoreCreature)
|
||||
continue;
|
||||
if(!thing->isGround() && !thing->isGroundBorder() && !thing->isOnTop())
|
||||
return thing;
|
||||
}
|
||||
}
|
||||
|
||||
return m_things[0];
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public:
|
|||
ThingPtr getTopUseThing();
|
||||
CreaturePtr getTopCreature();
|
||||
ThingPtr getTopMoveThing();
|
||||
ThingPtr getTopMultiUseThing(bool ignoreCreature = true);
|
||||
ThingPtr getTopMultiUseThing();
|
||||
|
||||
const Position& getPosition() { return m_position; }
|
||||
int getDrawElevation() { return m_drawElevation; }
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void setDrawLights(bool enable) { m_mapView->setDrawLights(enable); }
|
||||
void setAnimated(bool enable) { m_mapView->setAnimated(enable); }
|
||||
void setKeepAspectRatio(bool enable);
|
||||
void setMapShader(const PainterShaderProgramPtr& shader) { m_mapView->setShader(shader); }
|
||||
void setMapShader(const PainterShaderProgramPtr& shader, float fadeout, float fadein) { m_mapView->setShader(shader, fadein, fadeout); }
|
||||
void setMinimumAmbientLight(float intensity) { m_mapView->setMinimumAmbientLight(intensity); }
|
||||
|
||||
bool isMultifloor() { return m_mapView->isMultifloor(); }
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Try to find the ICU library
|
||||
# ICU_FOUND - system has ICU
|
||||
# ICU_INCLUDE_DIR - the ICU include directory
|
||||
# ICU_LIBRARY - the ICU library
|
||||
|
||||
FIND_PATH(ICU_INCLUDE_DIR NAMES unicode/utf8.h)
|
||||
SET(_ICUI18N_STATIC_LIBS libicui18n.a)
|
||||
SET(_ICUI18N_SHARED_LIBS libicui18n.dll.a icui18n)
|
||||
SET(_ICUUC_STATIC_LIBS libicuuc.a)
|
||||
SET(_ICUUC_SHARED_LIBS libicuuc.dll.a icuuc)
|
||||
IF(USE_STATIC_LIBS)
|
||||
FIND_LIBRARY(ICUI18N_LIBRARY NAMES ${_ICUI18N_STATIC_LIBS} ${_ICUI18N_SHARED_LIBS})
|
||||
FIND_LIBRARY(ICUUC_LIBRARY NAMES ${_ICUUC_STATIC_LIBS} ${_ICUUC_SHARED_LIBS})
|
||||
ELSE()
|
||||
FIND_LIBRARY(ICUI18N_LIBRARY NAMES ${_ICUI18N_SHARED_LIBS} ${_ICUI18N_STATIC_LIBS})
|
||||
FIND_LIBRARY(ICUUC_LIBRARY NAMES ${_ICUUC_SHARED_LIBS} ${_ICUUC_STATIC_LIBS})
|
||||
ENDIF()
|
||||
SET(ICU_LIBRARIES ${ICUI18N_LIBRARY} ${ICUUC_LIBRARY})
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICU DEFAULT_MSG ICU_LIBRARY ICU_INCLUDE_DIR)
|
||||
MARK_AS_ADVANCED(ICU_LIBRARIES ICU_INCLUDE_DIR)
|
|
@ -32,6 +32,7 @@
|
|||
#include <framework/core/resourcemanager.h>
|
||||
#include <framework/graphics/texturemanager.h>
|
||||
#include <framework/stdext/net.h>
|
||||
#include <framework/platform/platform.h>
|
||||
|
||||
#ifdef FW_GRAPHICS
|
||||
#include <framework/graphics/graphics.h>
|
||||
|
@ -68,6 +69,17 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindGlobalFunction("listSubnetAddresses", [](uint32 a, uint8 b) { return stdext::listSubnetAddresses(a, b); });
|
||||
g_lua.bindGlobalFunction("ucwords", [](std::string s) { return stdext::ucwords(s); });
|
||||
|
||||
// Platform
|
||||
g_lua.registerSingletonClass("g_platform");
|
||||
g_lua.bindSingletonFunction("g_platform", "spawnProcess", &Platform::spawnProcess, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "getProcessId", &Platform::getProcessId, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "copyFile", &Platform::copyFile, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "getTempPath", &Platform::getTempPath, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "openUrl", &Platform::openUrl, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "getCPUName", &Platform::getCPUName, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "getTotalSystemMemory", &Platform::getTotalSystemMemory, &g_platform);
|
||||
g_lua.bindSingletonFunction("g_platform", "getOSName", &Platform::getOSName, &g_platform);
|
||||
|
||||
// Application
|
||||
g_lua.registerSingletonClass("g_app");
|
||||
g_lua.bindSingletonFunction("g_app", "setName", &Application::setName, static_cast<Application*>(&g_app));
|
||||
|
@ -85,6 +97,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_app", "getBuildType", &Application::getBuildType, static_cast<Application*>(&g_app));
|
||||
g_lua.bindSingletonFunction("g_app", "getBuildArch", &Application::getBuildArch, static_cast<Application*>(&g_app));
|
||||
g_lua.bindSingletonFunction("g_app", "getOs", &Application::getOs, static_cast<Application*>(&g_app));
|
||||
g_lua.bindSingletonFunction("g_app", "getStartupOptions", &Application::getStartupOptions, static_cast<Application*>(&g_app));
|
||||
g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, static_cast<Application*>(&g_app));
|
||||
|
||||
// Crypt
|
||||
|
@ -160,6 +173,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_resources", "getWorkDir", &ResourceManager::getWorkDir, &g_resources);
|
||||
g_lua.bindSingletonFunction("g_resources", "getSearchPaths", &ResourceManager::getSearchPaths, &g_resources);
|
||||
g_lua.bindSingletonFunction("g_resources", "listDirectoryFiles", &ResourceManager::listDirectoryFiles, &g_resources);
|
||||
g_lua.bindSingletonFunction("g_resources", "readFileContents", &ResourceManager::readFileContents, &g_resources);
|
||||
|
||||
// Module
|
||||
g_lua.registerClass<Module>();
|
||||
|
@ -212,6 +226,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_window", "resize", &PlatformWindow::resize, &g_window);
|
||||
g_lua.bindSingletonFunction("g_window", "show", &PlatformWindow::show, &g_window);
|
||||
g_lua.bindSingletonFunction("g_window", "hide", &PlatformWindow::hide, &g_window);
|
||||
g_lua.bindSingletonFunction("g_window", "poll", &PlatformWindow::poll, &g_window);
|
||||
g_lua.bindSingletonFunction("g_window", "maximize", &PlatformWindow::maximize, &g_window);
|
||||
g_lua.bindSingletonFunction("g_window", "restoreMouseCursor", &PlatformWindow::restoreMouseCursor, &g_window);
|
||||
g_lua.bindSingletonFunction("g_window", "showMouse", &PlatformWindow::showMouse, &g_window);
|
||||
|
@ -261,6 +276,8 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_graphics", "selectPainterEngine", &Graphics::selectPainterEngine, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "canCacheBackbuffer", &Graphics::canCacheBackbuffer, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "canUseShaders", &Graphics::canUseShaders, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "shouldUseShaders", &Graphics::shouldUseShaders, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "setShouldUseShaders", &Graphics::setShouldUseShaders, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "getPainterEngine", &Graphics::getPainterEngine, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "getViewportSize", &Graphics::getViewportSize, &g_graphics);
|
||||
g_lua.bindSingletonFunction("g_graphics", "getVendor", &Graphics::getVendor, &g_graphics);
|
||||
|
@ -607,6 +624,7 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<UIGridLayout>("getNumColumns", &UIGridLayout::getNumColumns);
|
||||
g_lua.bindClassMemberFunction<UIGridLayout>("getNumLines", &UIGridLayout::getNumLines);
|
||||
g_lua.bindClassMemberFunction<UIGridLayout>("getCellSize", &UIGridLayout::getCellSize);
|
||||
g_lua.bindClassMemberFunction<UIGridLayout>("getCellSpacing", &UIGridLayout::getCellSpacing);
|
||||
g_lua.bindClassMemberFunction<UIGridLayout>("isUIGridLayout", &UIGridLayout::isUIGridLayout);
|
||||
|
||||
// UIAnchorLayout
|
||||
|
@ -756,8 +774,10 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<DBResult>("getDataInt", &DBResult::getDataInt);
|
||||
g_lua.bindClassMemberFunction<DBResult>("getDataLong", &DBResult::getDataLong);
|
||||
g_lua.bindClassMemberFunction<DBResult>("getDataString", &DBResult::getDataString);
|
||||
g_lua.bindClassMemberFunction<DBResult>("getRowCount", &DBResult::getRowCount);
|
||||
g_lua.bindClassMemberFunction<DBResult>("next", &DBResult::next);
|
||||
|
||||
|
||||
// Mysql
|
||||
g_lua.registerClass<DatabaseMySQL, Database>();
|
||||
g_lua.bindClassStaticFunction<DatabaseMySQL>("create", []{ return DatabaseMySQLPtr(new DatabaseMySQL); });
|
||||
|
|
|
@ -57,4 +57,9 @@ float random_range(float min, float max)
|
|||
return min + (max - min)*dis(gen);
|
||||
}
|
||||
|
||||
double round(double r)
|
||||
{
|
||||
return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
|
||||
}
|
||||
|
||||
}
|
|
@ -43,6 +43,8 @@ uint32_t adler32(const uint8_t *buffer, size_t size);
|
|||
long random_range(long min, long max);
|
||||
float random_range(float min, float max);
|
||||
|
||||
double round(double r);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue