rework walk
This commit is contained in:
parent
4491ee8bdd
commit
6ce92a1a64
3
BUGS
3
BUGS
|
@ -1,7 +1,8 @@
|
|||
2x2 corpses is drawn above players
|
||||
animatedtext is displayed in non visible floors
|
||||
attack while walking cancels the walk
|
||||
trying to walking in follow doesn't cancel de walk
|
||||
trying to walking while following doesn't cancel de walk
|
||||
attacked/followed creatures are not cleared when it goes out of range
|
||||
if a spell is used while pressing arrows keys the walk is canceled and it doesnt starts walking again
|
||||
game map text message boxes is not displayed like tibia
|
||||
name/shields doesnt follow the creature when walking on parcels
|
||||
|
|
1
TODO
1
TODO
|
@ -61,6 +61,7 @@ rework win32 key input system
|
|||
[bart] check for recursive anchors and print a error instead of crashing
|
||||
[bart] make api to enable/disable capture of events to avoid massive event processing
|
||||
[bart] review style apply system
|
||||
rework styles rendering order
|
||||
|
||||
== Client
|
||||
make possible to reload modules
|
||||
|
|
|
@ -29,3 +29,7 @@ function debugContainersItems()
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
function quit()
|
||||
exit()
|
||||
end
|
|
@ -16,3 +16,11 @@ function UIWindow:onKeyPress(keyCode, keyboardModifiers, wouldFilter)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UIWindow:onMousePress(mousePos, mouseButton)
|
||||
|
||||
end
|
||||
|
||||
function UIWindow:onGeometryChange(oldRect, newRect)
|
||||
|
||||
end
|
||||
|
|
|
@ -71,7 +71,7 @@ end
|
|||
local function onApplicationClose()
|
||||
print('close app')
|
||||
if Game.isOnline() then
|
||||
Game.logout(false)
|
||||
Game.logout(true)
|
||||
else
|
||||
exit()
|
||||
end
|
||||
|
|
|
@ -81,8 +81,7 @@ end
|
|||
|
||||
-- hooked events
|
||||
local function onGameDeath()
|
||||
TextMessage.displayEventAdvance('You are dead.', 10)
|
||||
scheduleEvent(function() Game.logout(true) end, 10*1000)
|
||||
TextMessage.displayEventAdvance('You are dead.', 60)
|
||||
end
|
||||
|
||||
local function onGameTextMessage(msgtype, msg)
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
#include <framework/global.h>
|
||||
|
||||
class Module;
|
||||
class Event;
|
||||
class ScheduledEvent;
|
||||
|
||||
typedef std::shared_ptr<Module> ModulePtr;
|
||||
typedef std::shared_ptr<Event> EventPtr;
|
||||
typedef std::shared_ptr<ScheduledEvent> ScheduledEventPtr;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,29 +37,34 @@ void EventDispatcher::flush()
|
|||
void EventDispatcher::poll()
|
||||
{
|
||||
while(!m_scheduledEventList.empty()) {
|
||||
if(g_clock.ticks() < m_scheduledEventList.top().ticks)
|
||||
ScheduledEventPtr scheduledEvent = m_scheduledEventList.top();
|
||||
if(scheduledEvent->reamaningTicks() > 0)
|
||||
break;
|
||||
SimpleCallback callback = std::move(m_scheduledEventList.top().callback);
|
||||
m_scheduledEventList.pop();
|
||||
callback();
|
||||
scheduledEvent->execute();
|
||||
}
|
||||
|
||||
while(!m_eventList.empty()) {
|
||||
m_eventList.front()();
|
||||
EventPtr event = m_eventList.front();
|
||||
m_eventList.pop_front();
|
||||
event->execute();
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::scheduleEvent(const SimpleCallback& callback, int delay)
|
||||
ScheduledEventPtr EventDispatcher::scheduleEvent(const SimpleCallback& callback, int delay)
|
||||
{
|
||||
assert(delay >= 0);
|
||||
m_scheduledEventList.push(ScheduledEvent(g_clock.ticksFor(delay), callback));
|
||||
ScheduledEventPtr scheduledEvent(new ScheduledEvent(callback, delay));
|
||||
m_scheduledEventList.push(scheduledEvent);
|
||||
return scheduledEvent;
|
||||
}
|
||||
|
||||
void EventDispatcher::addEvent(const SimpleCallback& callback, bool pushFront)
|
||||
EventPtr EventDispatcher::addEvent(const SimpleCallback& callback, bool pushFront)
|
||||
{
|
||||
EventPtr event(new Event(callback));
|
||||
if(pushFront)
|
||||
m_eventList.push_front(callback);
|
||||
m_eventList.push_front(event);
|
||||
else
|
||||
m_eventList.push_back(callback);
|
||||
m_eventList.push_back(event);
|
||||
return event;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,49 @@
|
|||
#define EVENTDISPATCHER_H
|
||||
|
||||
#include "declarations.h"
|
||||
#include "clock.h"
|
||||
#include <framework/luascript/luaobject.h>
|
||||
|
||||
struct ScheduledEvent {
|
||||
ScheduledEvent(ticks_t ticks, const SimpleCallback& callback) : ticks(ticks), callback(callback) { }
|
||||
bool operator<(const ScheduledEvent& other) const { return ticks > other.ticks; }
|
||||
ticks_t ticks;
|
||||
SimpleCallback callback;
|
||||
class Event : public LuaObject
|
||||
{
|
||||
public:
|
||||
Event(const SimpleCallback& callback) : m_callback(callback), m_canceled(false), m_executed(false) { }
|
||||
|
||||
void execute() {
|
||||
if(!m_canceled) {
|
||||
m_callback();
|
||||
m_executed = true;
|
||||
}
|
||||
}
|
||||
void cancel() { m_canceled = true; }
|
||||
|
||||
bool isCanceled() { return m_canceled; }
|
||||
bool isExecuted() { return m_executed; }
|
||||
|
||||
protected:
|
||||
SimpleCallback m_callback;
|
||||
bool m_canceled;
|
||||
bool m_executed;
|
||||
};
|
||||
|
||||
class ScheduledEvent : public Event
|
||||
{
|
||||
public:
|
||||
ScheduledEvent(const SimpleCallback& callback, int delay) : Event(callback) {
|
||||
m_ticks = g_clock.ticksFor(delay);
|
||||
}
|
||||
|
||||
int ticks() const { return m_ticks; }
|
||||
int reamaningTicks() const { return m_ticks - g_clock.ticks(); }
|
||||
|
||||
private:
|
||||
ticks_t m_ticks;
|
||||
};
|
||||
|
||||
struct lessScheduledEvent : std::binary_function<ScheduledEventPtr, ScheduledEventPtr&, bool> {
|
||||
bool operator()(const ScheduledEventPtr& a, const ScheduledEventPtr& b) const {
|
||||
return b->ticks() < a->ticks();
|
||||
}
|
||||
};
|
||||
|
||||
class EventDispatcher
|
||||
|
@ -38,12 +75,12 @@ public:
|
|||
void flush();
|
||||
void poll();
|
||||
|
||||
void addEvent(const SimpleCallback& callback, bool pushFront = false);
|
||||
void scheduleEvent(const SimpleCallback& callback, int delay);
|
||||
EventPtr addEvent(const SimpleCallback& callback, bool pushFront = false);
|
||||
ScheduledEventPtr scheduleEvent(const SimpleCallback& callback, int delay);
|
||||
|
||||
private:
|
||||
std::list<SimpleCallback> m_eventList;
|
||||
std::priority_queue<ScheduledEvent> m_scheduledEventList;
|
||||
std::list<EventPtr> m_eventList;
|
||||
std::priority_queue<ScheduledEventPtr, std::vector<ScheduledEventPtr>, lessScheduledEvent> m_scheduledEventList;
|
||||
};
|
||||
|
||||
extern EventDispatcher g_dispatcher;
|
||||
|
|
|
@ -43,6 +43,14 @@ void Application::registerLuaFunctions()
|
|||
g_lua.bindGlobalFunction("colortostring", [](const Color& v) { return Fw::tostring(v); });
|
||||
g_lua.bindGlobalFunction("sizetostring", [](const Size& v) { return Fw::tostring(v); });
|
||||
|
||||
// Event
|
||||
g_lua.registerClass<Event>();
|
||||
g_lua.bindClassMemberFunction<Event>("isCanceled", &Event::isCanceled);
|
||||
g_lua.bindClassMemberFunction<Event>("isExecuted", &Event::isExecuted);
|
||||
|
||||
// ScheduledEvent
|
||||
g_lua.registerClass<ScheduledEvent, Event>();
|
||||
|
||||
// UIWidget
|
||||
g_lua.registerClass<UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIWidget>("create", []{ return UIWidgetPtr(new UIWidget); });
|
||||
|
|
|
@ -351,16 +351,12 @@ void *WIN32Window::getExtensionProcAddress(const char *ext)
|
|||
|
||||
void WIN32Window::move(const Point& pos)
|
||||
{
|
||||
RECT windowRect = {pos.x, pos.y, m_pos.x + m_size.width(), m_pos.y + m_size.height()};
|
||||
AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
|
||||
MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
|
||||
MoveWindow(m_window, pos.x, pos.y, m_size.width(), m_size.height(), TRUE);
|
||||
}
|
||||
|
||||
void WIN32Window::resize(const Size& size)
|
||||
{
|
||||
RECT windowRect = {m_pos.x, m_pos.y, m_pos.x + size.width(), m_pos.y + size.height()};
|
||||
AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
|
||||
MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
|
||||
MoveWindow(m_window, m_pos.x, m_pos.y, size.width(), size.height(), TRUE);
|
||||
}
|
||||
|
||||
void WIN32Window::show()
|
||||
|
@ -400,7 +396,6 @@ void WIN32Window::poll()
|
|||
|
||||
LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
m_inputEvent.reset();
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_ACTIVATE: {
|
||||
|
@ -411,6 +406,8 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
if(wParam >= 32 && wParam <= 255) {
|
||||
m_inputEvent.reset(Fw::KeyTextInputEvent);
|
||||
m_inputEvent.keyText = wParam;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -429,31 +426,43 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
case WM_LBUTTONDOWN: {
|
||||
m_inputEvent.reset(Fw::MousePressInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseLeftButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_LBUTTONUP: {
|
||||
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseLeftButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MBUTTONDOWN: {
|
||||
m_inputEvent.reset(Fw::MousePressInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MBUTTONUP: {
|
||||
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_RBUTTONDOWN: {
|
||||
m_inputEvent.reset(Fw::MousePressInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseRightButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_RBUTTONUP: {
|
||||
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseRightButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEMOVE: {
|
||||
|
@ -461,11 +470,15 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
Point newMousePos(LOWORD(lParam), HIWORD(lParam));
|
||||
m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos;
|
||||
m_inputEvent.mousePos = newMousePos;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEWHEEL: {
|
||||
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||
m_inputEvent.wheelDirection = HIWORD(wParam) > 0 ? Fw::MouseWheelUp : Fw::MouseWheelDown;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOVE: {
|
||||
|
@ -494,8 +507,6 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
if(m_onInputEvent && m_inputEvent.type != Fw::NoInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -193,26 +193,27 @@ void UIWidget::removeChild(const UIWidgetPtr& child)
|
|||
|
||||
void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason)
|
||||
{
|
||||
if(child == m_focusedChild)
|
||||
return;
|
||||
|
||||
if(child && !hasChild(child)) {
|
||||
logError("Attempt to focus an unknown child in a UIWidget");
|
||||
logError("attempt to focus an unknown child in a UIWidget");
|
||||
return;
|
||||
}
|
||||
|
||||
if(child != m_focusedChild) {
|
||||
UIWidgetPtr oldFocused = m_focusedChild;
|
||||
m_focusedChild = child;
|
||||
UIWidgetPtr oldFocused = m_focusedChild;
|
||||
m_focusedChild = child;
|
||||
|
||||
if(child) {
|
||||
child->setLastFocusReason(reason);
|
||||
child->updateState(Fw::FocusState);
|
||||
child->updateState(Fw::ActiveState);
|
||||
}
|
||||
if(child) {
|
||||
child->setLastFocusReason(reason);
|
||||
child->updateState(Fw::FocusState);
|
||||
child->updateState(Fw::ActiveState);
|
||||
}
|
||||
|
||||
if(oldFocused) {
|
||||
oldFocused->setLastFocusReason(reason);
|
||||
oldFocused->updateState(Fw::FocusState);
|
||||
oldFocused->updateState(Fw::ActiveState);
|
||||
}
|
||||
if(oldFocused) {
|
||||
oldFocused->setLastFocusReason(reason);
|
||||
oldFocused->updateState(Fw::FocusState);
|
||||
oldFocused->updateState(Fw::ActiveState);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,6 +390,8 @@ void UIWidget::addAnchor(Fw::AnchorEdge anchoredEdge, const std::string& hookedW
|
|||
{
|
||||
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout())
|
||||
anchorLayout->addAnchor(asUIWidget(), anchoredEdge, hookedWidgetId, hookedEdge);
|
||||
else
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
}
|
||||
|
||||
void UIWidget::centerIn(const std::string& hookedWidgetId)
|
||||
|
@ -396,7 +399,8 @@ void UIWidget::centerIn(const std::string& hookedWidgetId)
|
|||
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) {
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter);
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorVerticalCenter, hookedWidgetId, Fw::AnchorVerticalCenter);
|
||||
}
|
||||
} else
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
}
|
||||
|
||||
void UIWidget::fill(const std::string& hookedWidgetId)
|
||||
|
@ -406,7 +410,8 @@ void UIWidget::fill(const std::string& hookedWidgetId)
|
|||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight);
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop);
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorBottom, hookedWidgetId, Fw::AnchorBottom);
|
||||
}
|
||||
} else
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
}
|
||||
|
||||
void UIWidget::breakAnchors()
|
||||
|
@ -732,17 +737,10 @@ Rect UIWidget::getChildrenRect()
|
|||
UIAnchorLayoutPtr UIWidget::getAnchoredLayout()
|
||||
{
|
||||
UIWidgetPtr parent = getParent();
|
||||
if(!parent) {
|
||||
logError("cannot add anchors to widget ", m_id, ": there is no parent");
|
||||
if(!parent)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UIAnchorLayoutPtr anchorLayout = parent->getLayout()->asUIAnchorLayout();
|
||||
if(!anchorLayout) {
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
return nullptr;
|
||||
}
|
||||
return anchorLayout;
|
||||
return parent->getLayout()->asUIAnchorLayout();
|
||||
}
|
||||
|
||||
UIWidgetPtr UIWidget::getRootParent()
|
||||
|
@ -1190,38 +1188,38 @@ bool UIWidget::propagateOnKeyUp(uchar keyCode, int keyboardModifiers)
|
|||
bool UIWidget::propagateOnMousePress(const Point& mousePos, Fw::MouseButton button)
|
||||
{
|
||||
// do a backup of children list, because it may change while looping it
|
||||
UIWidgetList children;
|
||||
UIWidgetPtr clickedChild;
|
||||
for(const UIWidgetPtr& child : m_children) {
|
||||
// events on hidden or disabled widgets are discarded
|
||||
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
||||
continue;
|
||||
|
||||
// mouse press events only go to children that contains the mouse position
|
||||
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos))
|
||||
children.push_back(child);
|
||||
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) {
|
||||
clickedChild = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(const UIWidgetPtr& child : children) {
|
||||
// when a focusable item is focused it must gain focus
|
||||
if(child->isFocusable())
|
||||
focusChild(child, Fw::MouseFocusReason);
|
||||
if(clickedChild) {
|
||||
// focusable child gains focus when clicked
|
||||
if(clickedChild->isFocusable())
|
||||
focusChild(clickedChild, Fw::MouseFocusReason);
|
||||
|
||||
bool mustEnd = child->propagateOnMousePress(mousePos, button);
|
||||
|
||||
if(button == Fw::MouseLeftButton && !child->isPressed()) {
|
||||
UIWidgetPtr clickedChild = child->getChildByPos(mousePos);
|
||||
if(!clickedChild || clickedChild->isPhantom())
|
||||
child->setPressed(true);
|
||||
}
|
||||
|
||||
if(mustEnd)
|
||||
// stop propagating if the child accept the event
|
||||
if(clickedChild->propagateOnMousePress(mousePos, button))
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!isPhantom())
|
||||
return onMousePress(mousePos, button);
|
||||
else
|
||||
return false;
|
||||
// only non phatom widgets receives mouse press events
|
||||
if(!isPhantom()) {
|
||||
onMousePress(mousePos, button);
|
||||
if(button == Fw::MouseLeftButton && !isPressed())
|
||||
setPressed(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button)
|
||||
|
@ -1239,12 +1237,12 @@ void UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton bu
|
|||
|
||||
for(const UIWidgetPtr& child : children) {
|
||||
child->propagateOnMouseRelease(mousePos, button);
|
||||
|
||||
if(child->isPressed() && button == Fw::MouseLeftButton)
|
||||
child->setPressed(false);
|
||||
}
|
||||
|
||||
onMouseRelease(mousePos, button);
|
||||
|
||||
if(isPressed() && button == Fw::MouseLeftButton)
|
||||
setPressed(false);
|
||||
}
|
||||
|
||||
bool UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved)
|
||||
|
|
|
@ -44,17 +44,14 @@ Creature::Creature() : Thing()
|
|||
m_showVolatileSquare = false;
|
||||
m_showStaticSquare = false;
|
||||
m_direction = Otc::South;
|
||||
m_walkTimePerPixel = 1000.0/32.0;
|
||||
|
||||
m_walking = false;
|
||||
m_preWalking = false;
|
||||
|
||||
m_walkInterval = 0;
|
||||
m_walkTurnDirection = Otc::InvalidDirection;
|
||||
m_skull = Otc::SkullNone;
|
||||
m_shield = Otc::ShieldNone;
|
||||
m_emblem = Otc::EmblemNone;
|
||||
m_shieldBlink = false;
|
||||
m_showShieldTexture = true;
|
||||
|
||||
m_informationFont = g_fonts.getFont("verdana-11px-rounded");
|
||||
}
|
||||
|
||||
|
@ -187,110 +184,133 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe
|
|||
}
|
||||
}
|
||||
|
||||
void Creature::walk(const Position& oldPos, const Position& newPos, bool preWalk)
|
||||
void Creature::turn(Otc::Direction direction)
|
||||
{
|
||||
// if is not walking change the direction right away
|
||||
if(!m_walking)
|
||||
setDirection(direction);
|
||||
// schedules to set the new direction when walk ends
|
||||
else
|
||||
m_walkTurnDirection = direction;
|
||||
}
|
||||
|
||||
void Creature::walk(const Position& oldPos, const Position& newPos)
|
||||
{
|
||||
// get walk direction
|
||||
Otc::Direction direction = oldPos.getDirectionFromPosition(newPos);
|
||||
|
||||
// already pre walking to the same direction
|
||||
if(m_preWalking && preWalk && direction == m_direction)
|
||||
return;
|
||||
|
||||
// pre walking was already going on, just change to normal waking
|
||||
if(m_preWalking && !preWalk && direction == m_direction) {
|
||||
m_preWalking = false;
|
||||
m_walking = true;
|
||||
updateWalk();
|
||||
return;
|
||||
}
|
||||
|
||||
// set current walking direction
|
||||
setDirection(direction);
|
||||
|
||||
// diagonal walking lasts 3 times more.
|
||||
int walkTimeFactor = 1;
|
||||
if(direction == Otc::NorthWest || direction == Otc::NorthEast || direction == Otc::SouthWest || direction == Otc::SouthEast)
|
||||
walkTimeFactor = 3;
|
||||
|
||||
// calculate walk interval
|
||||
int groundSpeed = g_map.getTile(oldPos)->getGroundSpeed();
|
||||
float walkInterval = 1000.0 * (float)groundSpeed / m_speed;
|
||||
walkInterval = (walkInterval == 0) ? 1000 : walkInterval;
|
||||
walkInterval = std::ceil(walkInterval / g_game.getServerBeat()) * g_game.getServerBeat();
|
||||
|
||||
m_walkTimePerPixel = walkInterval / 32.0;
|
||||
m_walkOffset = Point();
|
||||
m_walkStart = g_clock.ticks();
|
||||
m_walkEnd = m_walkStart + walkInterval * walkTimeFactor;
|
||||
// starts counting walk
|
||||
m_walking = true;
|
||||
m_preWalking = preWalk;
|
||||
m_turnDirection = m_direction;
|
||||
updateWalk();
|
||||
m_walkTimer.restart();
|
||||
|
||||
// calculates walk interval
|
||||
float walkInterval = 1000;
|
||||
int groundSpeed = g_map.getTile(oldPos)->getGroundSpeed();
|
||||
if(groundSpeed != 0)
|
||||
walkInterval = (1000.0f * groundSpeed) / m_speed;
|
||||
|
||||
// diagonal walking lasts 3 times more.
|
||||
//if(direction == Otc::NorthWest || direction == Otc::NorthEast || direction == Otc::SouthWest || direction == Otc::SouthEast)
|
||||
// walkInterval *= 3;
|
||||
|
||||
m_walkInterval = (walkInterval / g_game.getServerBeat()) * g_game.getServerBeat();
|
||||
|
||||
// no direction needs to be changed when the walk ends
|
||||
m_walkTurnDirection = Otc::InvalidDirection;
|
||||
|
||||
// starts updating walk
|
||||
nextWalkUpdate();
|
||||
}
|
||||
|
||||
void Creature::turn(Otc::Direction direction)
|
||||
void Creature::stopWalk()
|
||||
{
|
||||
if(!m_walking)
|
||||
setDirection(direction);
|
||||
else
|
||||
m_turnDirection = direction;
|
||||
return;
|
||||
|
||||
// reset walk animation states
|
||||
updateWalkAnimation(0);
|
||||
updateWalkOffset(0);
|
||||
|
||||
// stops the walk right away
|
||||
terminateWalk();
|
||||
}
|
||||
|
||||
void Creature::updateWalkAnimation(int totalPixelsWalked)
|
||||
{
|
||||
// update outfit animation
|
||||
if(m_outfit.getCategory() == ThingsType::Creature) {
|
||||
if(totalPixelsWalked == 32 || totalPixelsWalked == 0 || m_type->dimensions[ThingType::AnimationPhases] <= 1)
|
||||
m_animation = 0;
|
||||
else if(m_type->dimensions[ThingType::AnimationPhases] > 1)
|
||||
m_animation = 1 + ((totalPixelsWalked * 4) / Map::NUM_TILE_PIXELS) % (m_type->dimensions[ThingType::AnimationPhases] - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::updateWalkOffset(int totalPixelsWalked)
|
||||
{
|
||||
m_walkOffset = Point(0,0);
|
||||
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
|
||||
m_walkOffset.y = 32 - totalPixelsWalked;
|
||||
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.y = totalPixelsWalked - 32;
|
||||
|
||||
if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
|
||||
m_walkOffset.x = totalPixelsWalked - 32;
|
||||
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.x = 32 - totalPixelsWalked;
|
||||
}
|
||||
|
||||
void Creature::nextWalkUpdate()
|
||||
{
|
||||
// remove any previous scheduled walk updates
|
||||
if(m_walkUpdateEvent)
|
||||
m_walkUpdateEvent->cancel();
|
||||
|
||||
// do the update
|
||||
updateWalk();
|
||||
|
||||
// schedules next update
|
||||
if(m_walking) {
|
||||
auto self = asCreature();
|
||||
m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
|
||||
self->m_walkUpdateEvent = nullptr;
|
||||
self->nextWalkUpdate();
|
||||
}, m_walkInterval / 32);
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::updateWalk()
|
||||
{
|
||||
if(!m_walking)
|
||||
return;
|
||||
float walkTicksPerPixel = m_walkInterval / 32.0f;
|
||||
int totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
|
||||
|
||||
int elapsedTicks = g_clock.ticksElapsed(m_walkStart);
|
||||
int totalPixelsWalked = std::min((int)round(elapsedTicks / m_walkTimePerPixel), 32);
|
||||
// update walk animation and offsets
|
||||
updateWalkAnimation(totalPixelsWalked);
|
||||
updateWalkOffset(totalPixelsWalked);
|
||||
|
||||
if(!m_preWalking) {
|
||||
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
|
||||
m_walkOffset.y = 32 - totalPixelsWalked;
|
||||
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.y = totalPixelsWalked - 32;
|
||||
|
||||
if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
|
||||
m_walkOffset.x = totalPixelsWalked - 32;
|
||||
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.x = 32 - totalPixelsWalked;
|
||||
} else {
|
||||
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
|
||||
m_walkOffset.y = -totalPixelsWalked;
|
||||
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.y = totalPixelsWalked;
|
||||
|
||||
if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
|
||||
m_walkOffset.x = totalPixelsWalked;
|
||||
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.x = -totalPixelsWalked;
|
||||
}
|
||||
|
||||
if(m_outfit.getCategory() == ThingsType::Creature) {
|
||||
if(totalPixelsWalked == 32 || m_type->dimensions[ThingType::AnimationPhases] <= 1)
|
||||
m_animation = 0;
|
||||
else if(m_type->dimensions[ThingType::AnimationPhases] > 1)
|
||||
m_animation = 1 + totalPixelsWalked * 4 / Map::NUM_TILE_PIXELS % (m_type->dimensions[ThingType::AnimationPhases] - 1);
|
||||
}
|
||||
|
||||
if(g_clock.ticks() > m_walkEnd) {
|
||||
cancelWalk(m_turnDirection);
|
||||
} else
|
||||
g_dispatcher.scheduleEvent(std::bind(&Creature::updateWalk, asCreature()), m_walkTimePerPixel);
|
||||
// terminate walk
|
||||
if(m_walking && m_walkTimer.ticksElapsed() >= m_walkInterval)
|
||||
terminateWalk();
|
||||
}
|
||||
|
||||
void Creature::cancelWalk(Otc::Direction direction, bool force)
|
||||
void Creature::terminateWalk()
|
||||
{
|
||||
if(force) {
|
||||
m_walkOffset = Point();
|
||||
m_preWalking = false;
|
||||
} else if(!m_preWalking)
|
||||
m_walkOffset = Point();
|
||||
// remove any scheduled walk update
|
||||
if(m_walkUpdateEvent) {
|
||||
m_walkUpdateEvent->cancel();
|
||||
m_walkUpdateEvent = nullptr;
|
||||
}
|
||||
|
||||
// now the walk has ended, do any scheduled turn
|
||||
if(m_walkTurnDirection != Otc::InvalidDirection) {
|
||||
setDirection(m_walkTurnDirection);
|
||||
m_walkTurnDirection = Otc::InvalidDirection;
|
||||
}
|
||||
|
||||
m_walking = false;
|
||||
|
||||
if(direction != Otc::InvalidDirection)
|
||||
setDirection(direction);
|
||||
|
||||
m_animation = 0;
|
||||
}
|
||||
|
||||
void Creature::setName(const std::string& name)
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "thing.h"
|
||||
#include "outfit.h"
|
||||
#include <framework/core/declarations.h>
|
||||
#include <framework/core/timer.h>
|
||||
#include <framework/graphics/fontmanager.h>
|
||||
|
||||
class Creature : public Thing
|
||||
|
@ -79,18 +81,21 @@ public:
|
|||
ThingType *getType();
|
||||
|
||||
// walk related
|
||||
void walk(const Position& oldPos, const Position& newPos, bool preWalk = false);
|
||||
void turn(Otc::Direction direction);
|
||||
void cancelWalk(Otc::Direction direction = Otc::InvalidDirection, bool force = false);
|
||||
virtual void walk(const Position& oldPos, const Position& newPos);
|
||||
virtual void stopWalk();
|
||||
Point getWalkOffset() { return m_walkOffset; }
|
||||
|
||||
bool isWalking() { return m_walking; }
|
||||
bool isPreWalking() { return m_preWalking; }
|
||||
|
||||
CreaturePtr asCreature() { return std::static_pointer_cast<Creature>(shared_from_this()); }
|
||||
|
||||
protected:
|
||||
void updateWalk();
|
||||
virtual void updateWalkAnimation(int totalPixelsWalked);
|
||||
virtual void updateWalkOffset(int totalPixelsWalked);
|
||||
virtual void nextWalkUpdate();
|
||||
virtual void updateWalk();
|
||||
virtual void terminateWalk();
|
||||
|
||||
std::string m_name;
|
||||
Size m_nameSize;
|
||||
|
@ -98,7 +103,7 @@ protected:
|
|||
Otc::Direction m_direction;
|
||||
Outfit m_outfit;
|
||||
Light m_light;
|
||||
uint16 m_speed;
|
||||
int m_speed;
|
||||
uint8 m_skull, m_shield, m_emblem;
|
||||
TexturePtr m_skullTexture, m_shieldTexture, m_emblemTexture;
|
||||
bool m_showShieldTexture, m_shieldBlink;
|
||||
|
@ -109,11 +114,13 @@ protected:
|
|||
FontPtr m_informationFont;
|
||||
Color m_informationColor;
|
||||
|
||||
ticks_t m_walkStart, m_walkEnd;
|
||||
bool m_walking, m_preWalking;
|
||||
float m_walkTimePerPixel;
|
||||
// walk related
|
||||
Timer m_walkTimer;
|
||||
int m_walkInterval;
|
||||
bool m_walking;
|
||||
ScheduledEventPtr m_walkUpdateEvent;
|
||||
Point m_walkOffset;
|
||||
Otc::Direction m_turnDirection;
|
||||
Otc::Direction m_walkTurnDirection;
|
||||
};
|
||||
|
||||
class Npc : public Creature {
|
||||
|
|
|
@ -35,7 +35,6 @@ Game g_game;
|
|||
|
||||
void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldHost, int worldPort, const std::string& characterName)
|
||||
{
|
||||
m_online = false;
|
||||
m_dead = false;
|
||||
m_selectedThing = nullptr;
|
||||
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
|
||||
|
@ -49,7 +48,7 @@ void Game::cancelLogin()
|
|||
|
||||
void Game::logout(bool force)
|
||||
{
|
||||
if(!m_protocolGame || !m_online)
|
||||
if(!m_protocolGame || !isOnline())
|
||||
return;
|
||||
|
||||
m_protocolGame->sendLogout();
|
||||
|
@ -77,7 +76,6 @@ void Game::processConnectionError(const boost::system::error_code& error)
|
|||
void Game::processLogin(const LocalPlayerPtr& localPlayer, int serverBeat)
|
||||
{
|
||||
m_localPlayer = localPlayer;
|
||||
m_online = true;
|
||||
m_serverBeat = serverBeat;
|
||||
|
||||
// NOTE: the entire map description is not known yet
|
||||
|
@ -86,17 +84,18 @@ void Game::processLogin(const LocalPlayerPtr& localPlayer, int serverBeat)
|
|||
|
||||
void Game::processLogout()
|
||||
{
|
||||
if(m_online) {
|
||||
if(isOnline()) {
|
||||
g_lua.callGlobalField("Game", "onLogout", m_localPlayer);
|
||||
|
||||
m_localPlayer.reset();
|
||||
m_online = false;
|
||||
m_localPlayer = nullptr;
|
||||
}
|
||||
|
||||
if(m_protocolGame) {
|
||||
m_protocolGame->disconnect();
|
||||
m_protocolGame.reset();
|
||||
m_protocolGame = nullptr;
|
||||
}
|
||||
|
||||
g_map.clean();
|
||||
}
|
||||
|
||||
void Game::processDeath()
|
||||
|
@ -145,8 +144,7 @@ void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldP
|
|||
// teleport
|
||||
} else {
|
||||
// stop walking on teleport
|
||||
if(creature->isWalking() || creature->isPreWalking())
|
||||
creature->cancelWalk();
|
||||
creature->stopWalk();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +156,8 @@ void Game::processAttackCancel()
|
|||
|
||||
void Game::processWalkCancel(Otc::Direction direction)
|
||||
{
|
||||
m_localPlayer->cancelWalk(direction, true);
|
||||
logTraceDebug();
|
||||
m_localPlayer->cancelWalk(direction);
|
||||
}
|
||||
|
||||
void Game::walk(Otc::Direction direction)
|
||||
|
@ -208,7 +207,7 @@ void Game::forceWalk(Otc::Direction direction)
|
|||
|
||||
void Game::turn(Otc::Direction direction)
|
||||
{
|
||||
if(!m_online)
|
||||
if(!isOnline())
|
||||
return;
|
||||
|
||||
switch(direction) {
|
||||
|
@ -229,7 +228,7 @@ void Game::turn(Otc::Direction direction)
|
|||
|
||||
void Game::look(const ThingPtr& thing)
|
||||
{
|
||||
if(!m_online || !thing || !checkBotProtection())
|
||||
if(!isOnline() || !thing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
|
@ -239,7 +238,7 @@ void Game::look(const ThingPtr& thing)
|
|||
|
||||
void Game::open(const ThingPtr& thing, int containerId)
|
||||
{
|
||||
if(!m_online || !thing || !checkBotProtection())
|
||||
if(!isOnline() || !thing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
|
@ -249,9 +248,11 @@ void Game::open(const ThingPtr& thing, int containerId)
|
|||
|
||||
void Game::use(const ThingPtr& thing)
|
||||
{
|
||||
if(!m_online || !thing || !checkBotProtection())
|
||||
if(!isOnline() || !thing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
m_localPlayer->lockWalk();
|
||||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
if(stackpos != -1)
|
||||
m_protocolGame->sendUseItem(thing->getPos(), thing->getId(), stackpos, 0);
|
||||
|
@ -259,7 +260,7 @@ void Game::use(const ThingPtr& thing)
|
|||
|
||||
void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing)
|
||||
{
|
||||
if(!m_online || !fromThing || !toThing || !checkBotProtection())
|
||||
if(!isOnline() || !fromThing || !toThing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
Position pos = fromThing->getPos();
|
||||
|
@ -267,6 +268,8 @@ void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing)
|
|||
if(fromStackpos == -1)
|
||||
return;
|
||||
|
||||
m_localPlayer->lockWalk();
|
||||
|
||||
if(CreaturePtr creature = toThing->asCreature()) {
|
||||
m_protocolGame->sendUseOnCreature(pos, fromThing->getId(), fromStackpos, creature->getId());
|
||||
} else {
|
||||
|
@ -280,9 +283,11 @@ void Game::useWith(const ThingPtr& fromThing, const ThingPtr& toThing)
|
|||
|
||||
void Game::useInventoryItem(int itemId, const ThingPtr& toThing)
|
||||
{
|
||||
if(!m_online || !toThing || !checkBotProtection())
|
||||
if(!isOnline() || !toThing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
m_localPlayer->lockWalk();
|
||||
|
||||
Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
|
||||
int toStackpos = getThingStackpos(toThing);
|
||||
if(toStackpos == -1)
|
||||
|
@ -297,9 +302,11 @@ void Game::useInventoryItem(int itemId, const ThingPtr& toThing)
|
|||
|
||||
void Game::attack(const CreaturePtr& creature)
|
||||
{
|
||||
if(!m_online || !creature || !checkBotProtection())
|
||||
if(!isOnline() || !creature || !checkBotProtection())
|
||||
return;
|
||||
|
||||
m_localPlayer->lockWalk();
|
||||
|
||||
if(m_localPlayer->isFollowing())
|
||||
cancelFollow();
|
||||
|
||||
|
@ -309,13 +316,15 @@ void Game::attack(const CreaturePtr& creature)
|
|||
|
||||
void Game::cancelAttack()
|
||||
{
|
||||
m_localPlayer->lockWalk();
|
||||
|
||||
m_localPlayer->setAttackingCreature(nullptr);
|
||||
m_protocolGame->sendAttack(0);
|
||||
}
|
||||
|
||||
void Game::follow(const CreaturePtr& creature)
|
||||
{
|
||||
if(!m_online || !creature || !checkBotProtection())
|
||||
if(!isOnline() || !creature || !checkBotProtection())
|
||||
return;
|
||||
|
||||
if(m_localPlayer->isAttacking())
|
||||
|
@ -333,7 +342,7 @@ void Game::cancelFollow()
|
|||
|
||||
void Game::rotate(const ThingPtr& thing)
|
||||
{
|
||||
if(!m_online || !thing || !checkBotProtection())
|
||||
if(!isOnline() || !thing || !checkBotProtection())
|
||||
return;
|
||||
|
||||
int stackpos = getThingStackpos(thing);
|
||||
|
@ -361,42 +370,42 @@ void Game::talk(const std::string& message)
|
|||
|
||||
void Game::talkChannel(const std::string& speakTypeDesc, int channelId, const std::string& message)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendTalk(speakTypeDesc, channelId, "", message);
|
||||
}
|
||||
|
||||
void Game::talkPrivate(const std::string& speakTypeDesc, const std::string& receiver, const std::string& message)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendTalk(speakTypeDesc, 0, receiver, message);
|
||||
}
|
||||
|
||||
void Game::requestChannels()
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendGetChannels();
|
||||
}
|
||||
|
||||
void Game::joinChannel(int channelId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendJoinChannel(channelId);
|
||||
}
|
||||
|
||||
void Game::leaveChannel(int channelId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendLeaveChannel(channelId);
|
||||
}
|
||||
|
||||
void Game::closeNpcChannel()
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendCloseNpcChannel();
|
||||
}
|
||||
|
@ -404,21 +413,21 @@ void Game::closeNpcChannel()
|
|||
|
||||
void Game::partyInvite(int creatureId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendInviteToParty(creatureId);
|
||||
}
|
||||
|
||||
void Game::partyJoin(int creatureId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendJoinParty(creatureId);
|
||||
}
|
||||
|
||||
void Game::partyRevokeInvitation(int creatureId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendRevokeInvitation(creatureId);
|
||||
}
|
||||
|
@ -426,49 +435,49 @@ void Game::partyRevokeInvitation(int creatureId)
|
|||
|
||||
void Game::partyPassLeadership(int creatureId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendPassLeadership(creatureId);
|
||||
}
|
||||
|
||||
void Game::partyLeave()
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendLeaveParty();
|
||||
}
|
||||
|
||||
void Game::partyShareExperience(bool active)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendShareExperience(active, 0);
|
||||
}
|
||||
|
||||
void Game::requestOutfit()
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendGetOutfit();
|
||||
}
|
||||
|
||||
void Game::setOutfit(const Outfit& outfit)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendSetOutfit(outfit);
|
||||
}
|
||||
|
||||
void Game::addVip(const std::string& name)
|
||||
{
|
||||
if(!m_online || name.empty() || !checkBotProtection())
|
||||
if(!isOnline() || name.empty() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendAddVip(name);
|
||||
}
|
||||
|
||||
void Game::removeVip(int playerId)
|
||||
{
|
||||
if(!m_online || !checkBotProtection())
|
||||
if(!isOnline() || !checkBotProtection())
|
||||
return;
|
||||
m_protocolGame->sendRemoveVip(playerId);
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ public:
|
|||
|
||||
bool checkBotProtection();
|
||||
|
||||
bool isOnline() { return m_online; }
|
||||
bool isOnline() { return !!m_localPlayer; }
|
||||
bool isDead() { return m_dead; }
|
||||
|
||||
void setSelectedThing(const ThingPtr& thing) { m_selectedThing = thing; }
|
||||
|
@ -118,7 +118,6 @@ public:
|
|||
private:
|
||||
LocalPlayerPtr m_localPlayer;
|
||||
ProtocolGamePtr m_protocolGame;
|
||||
bool m_online;
|
||||
bool m_dead;
|
||||
int m_serverBeat;
|
||||
ThingPtr m_selectedThing;
|
||||
|
|
|
@ -25,24 +25,75 @@
|
|||
#include "game.h"
|
||||
#include "tile.h"
|
||||
|
||||
LocalPlayer::LocalPlayer()
|
||||
{
|
||||
m_preWalking = false;
|
||||
m_canReportBugs = false;
|
||||
m_known = false;
|
||||
m_walkLocked = false;
|
||||
m_lastPrewalkDone = true;
|
||||
m_icons = 0;
|
||||
}
|
||||
|
||||
void LocalPlayer::lockWalk()
|
||||
{
|
||||
// prevents double locks
|
||||
if(m_walkLocked)
|
||||
return;
|
||||
|
||||
m_walkLocked = true;
|
||||
m_walkLockTimer.restart();
|
||||
}
|
||||
|
||||
void LocalPlayer::walk(const Position& oldPos, const Position& newPos)
|
||||
{
|
||||
Otc::Direction direction = oldPos.getDirectionFromPosition(newPos);
|
||||
|
||||
// a prewalk was going on
|
||||
if(m_preWalking) {
|
||||
// switch to normal walking
|
||||
m_preWalking = false;
|
||||
m_lastPrewalkDone = true;
|
||||
// if is to the destination, updates it preserving the animation
|
||||
if(newPos == m_lastPrewalkDestionation) {
|
||||
// walk started by prewalk could already be finished by now
|
||||
updateWalk();
|
||||
// was to another direction, replace the walk
|
||||
} else
|
||||
Creature::walk(oldPos, newPos);
|
||||
} else
|
||||
Creature::walk(oldPos, newPos);
|
||||
}
|
||||
|
||||
void LocalPlayer::preWalk(Otc::Direction direction)
|
||||
{
|
||||
// we're not walking, so start a client walk.
|
||||
// start walking to direction
|
||||
Position newPos = m_pos + Position::getPosFromDirection(direction);
|
||||
walk(m_pos, newPos, true);
|
||||
m_preWalking = true;
|
||||
m_lastPrewalkDone = false;
|
||||
m_lastPrewalkDestionation = newPos;
|
||||
Creature::walk(m_pos, newPos);
|
||||
}
|
||||
|
||||
bool LocalPlayer::canWalk(Otc::Direction direction)
|
||||
{
|
||||
if(m_walking || (m_preWalking && g_clock.ticksElapsed(m_walkEnd) < 1000))
|
||||
// cannot walk while already walking
|
||||
if(m_walking)
|
||||
return false;
|
||||
|
||||
// avoid doing more walks than wanted when receiving a lot of walks from server
|
||||
if(!m_lastPrewalkDone)
|
||||
return false;
|
||||
|
||||
// cannot walk while locked
|
||||
if(m_walkLocked && m_walkLockTimer.ticksElapsed() <= WALK_LOCK_INTERVAL)
|
||||
return false;
|
||||
else
|
||||
m_walkLocked = false;
|
||||
|
||||
// check for blockable tiles in the walk direction
|
||||
TilePtr tile = g_map.getTile(m_pos + Position::getPosFromDirection(direction));
|
||||
if(!tile)
|
||||
return false;
|
||||
|
||||
if(!tile->isWalkable()) {
|
||||
if(!tile || !tile->isWalkable()) {
|
||||
g_game.processTextMessage("statusSmall", "Sorry, not possible.");
|
||||
return false;
|
||||
}
|
||||
|
@ -50,6 +101,63 @@ bool LocalPlayer::canWalk(Otc::Direction direction)
|
|||
return true;
|
||||
}
|
||||
|
||||
void LocalPlayer::cancelWalk(Otc::Direction direction)
|
||||
{
|
||||
// only cancel client side walks
|
||||
if(m_walking && m_preWalking)
|
||||
stopWalk();
|
||||
|
||||
m_lastPrewalkDone = true;
|
||||
|
||||
// turn to the cancel direction
|
||||
if(direction != Otc::InvalidDirection)
|
||||
setDirection(direction);
|
||||
}
|
||||
|
||||
void LocalPlayer::stopWalk()
|
||||
{
|
||||
Creature::stopWalk();
|
||||
m_lastPrewalkDestionation = Position();
|
||||
}
|
||||
|
||||
void LocalPlayer::updateWalkOffset(int totalPixelsWalked)
|
||||
{
|
||||
// pre walks offsets are calculated in the oposite direction
|
||||
if(m_preWalking) {
|
||||
m_walkOffset = Point(0,0);
|
||||
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
|
||||
m_walkOffset.y = -totalPixelsWalked;
|
||||
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.y = totalPixelsWalked;
|
||||
|
||||
if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
|
||||
m_walkOffset.x = totalPixelsWalked;
|
||||
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
|
||||
m_walkOffset.x = -totalPixelsWalked;
|
||||
} else
|
||||
Creature::updateWalkOffset(totalPixelsWalked);
|
||||
}
|
||||
|
||||
void LocalPlayer::updateWalk()
|
||||
{
|
||||
float walkTicksPerPixel = m_walkInterval / 32.0f;
|
||||
int totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
|
||||
|
||||
// update walk animation and offsets
|
||||
updateWalkAnimation(totalPixelsWalked);
|
||||
updateWalkOffset(totalPixelsWalked);
|
||||
|
||||
// terminate walk only when client and server side walk are complated
|
||||
if(m_walking && !m_preWalking && m_walkTimer.ticksElapsed() >= m_walkInterval)
|
||||
terminateWalk();
|
||||
}
|
||||
|
||||
void LocalPlayer::terminateWalk()
|
||||
{
|
||||
Creature::terminateWalk();
|
||||
m_preWalking = false;
|
||||
}
|
||||
|
||||
void LocalPlayer::setAttackingCreature(const CreaturePtr& creature)
|
||||
{
|
||||
// clear current attacking creature
|
||||
|
|
|
@ -27,13 +27,18 @@
|
|||
|
||||
class LocalPlayer : public Player
|
||||
{
|
||||
enum {
|
||||
WALK_LOCK_INTERVAL = 250
|
||||
};
|
||||
public:
|
||||
LocalPlayer();
|
||||
|
||||
void setCanReportBugs(uint8 canReportBugs) { m_canReportBugs = (canReportBugs != 0); }
|
||||
void setSkill(Otc::Skill skill, Otc::SkillType skillType, int value) { m_skills[skill][skillType] = value; }
|
||||
void setStatistic(Otc::Statistic statistic, double value) { m_statistics[statistic] = value; }
|
||||
void setAttackingCreature(const CreaturePtr& creature);
|
||||
void setFollowingCreature(const CreaturePtr& creature);
|
||||
void setIcons(Otc::PlayerIcons icons) { m_icons = icons; }
|
||||
void setIcons(int icons) { m_icons = icons; }
|
||||
void setKnown(bool known) { m_known = known; }
|
||||
|
||||
bool getCanReportBugs() { return m_canReportBugs; }
|
||||
|
@ -41,14 +46,19 @@ public:
|
|||
double getStatistic(Otc::Statistic statistic) { return m_statistics[statistic]; }
|
||||
CreaturePtr getAttackingCreature() { return m_attackingCreature; }
|
||||
CreaturePtr getFollowingCreature() { return m_followingCreature; }
|
||||
Otc::PlayerIcons getIcons() { return m_icons; }
|
||||
int getIcons() { return m_icons; }
|
||||
|
||||
bool isKnown() { return m_known; }
|
||||
bool isAttacking() { return m_attackingCreature != nullptr; }
|
||||
bool isFollowing() { return m_followingCreature != nullptr; }
|
||||
|
||||
void unlockWalk() { m_walkLocked = false; }
|
||||
void lockWalk();
|
||||
void walk(const Position& oldPos, const Position& newPos);
|
||||
void preWalk(Otc::Direction direction);
|
||||
bool canWalk(Otc::Direction direction);
|
||||
void cancelWalk(Otc::Direction direction = Otc::InvalidDirection);
|
||||
void stopWalk();
|
||||
|
||||
LocalPlayerPtr asLocalPlayer() { return std::static_pointer_cast<LocalPlayer>(shared_from_this()); }
|
||||
|
||||
|
@ -65,11 +75,24 @@ public:
|
|||
double getSoul() { return getStatistic(Otc::Soul); }
|
||||
double getStamina() { return getStatistic(Otc::Stamina); }
|
||||
|
||||
protected:
|
||||
void updateWalkOffset(int totalPixelsWalked);
|
||||
void updateWalk();
|
||||
void terminateWalk();
|
||||
|
||||
private:
|
||||
// walk related
|
||||
bool m_preWalking;
|
||||
bool m_lastPrewalkDone;
|
||||
bool m_walkLocked;
|
||||
Position m_lastPrewalkDestionation;
|
||||
Timer m_walkLockTimer;
|
||||
|
||||
bool m_canReportBugs;
|
||||
bool m_known;
|
||||
CreaturePtr m_attackingCreature, m_followingCreature;
|
||||
Otc::PlayerIcons m_icons;
|
||||
CreaturePtr m_attackingCreature;
|
||||
CreaturePtr m_followingCreature;
|
||||
int m_icons;
|
||||
int m_skills[Otc::LastSkill][Otc::LastSkillType];
|
||||
double m_statistics[Otc::LastStatistic];
|
||||
};
|
||||
|
|
|
@ -150,6 +150,11 @@ void Map::draw(const Rect& rect)
|
|||
void Map::clean()
|
||||
{
|
||||
m_tiles.clear();
|
||||
m_creatures.clear();
|
||||
for(int i=0;i<MAX_Z-1;++i)
|
||||
m_missilesAtFloor[i].clear();
|
||||
m_animatedTexts.clear();
|
||||
m_staticTexts.clear();
|
||||
}
|
||||
|
||||
int Map::getFirstVisibleFloor()
|
||||
|
|
|
@ -83,8 +83,10 @@ private:
|
|||
|
||||
Light m_light;
|
||||
Position m_centralPosition;
|
||||
Size m_size, m_visibleSize;
|
||||
Point m_centralOffset, m_drawOffset;
|
||||
Size m_size;
|
||||
Size m_visibleSize;
|
||||
Point m_centralOffset;
|
||||
Point m_drawOffset;
|
||||
|
||||
FrameBufferPtr m_framebuffer;
|
||||
PainterShaderProgramPtr m_shaderProgram;
|
||||
|
|
|
@ -1141,7 +1141,7 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
|||
if(emblem != -1)
|
||||
creature->setEmblem(emblem);
|
||||
creature->setPassable(passable);
|
||||
creature->cancelWalk(direction);
|
||||
creature->setDirection(direction);
|
||||
|
||||
if(creature == m_localPlayer) {
|
||||
m_localPlayer->setKnown(true);
|
||||
|
|
Loading…
Reference in New Issue