walk and key event system rework with some regressions

This commit is contained in:
Eduardo Bart 2012-01-15 19:19:52 -02:00
parent 9ec40f016d
commit 44a20222bb
52 changed files with 542 additions and 346 deletions

6
TODO
View File

@ -1,7 +1,6 @@
==================================================== ====================================================
High priority TODO in order (before first public disclose) High priority TODO in order (before first public disclose)
[bart] tab widgets
[bart] chat with tabs [bart] chat with tabs
[bart] scrollbar [bart] scrollbar
[bart] scrollable widgets [bart] scrollable widgets
@ -62,8 +61,10 @@ change win32 mouse cursor icon
[bart] review and make more error prone with more warnings [bart] review and make more error prone with more warnings
[bart] reapply anchor styles when adding new childs [bart] reapply anchor styles when adding new childs
[bart] ui text selection [bart] ui text selection
[bart] find styles by scope
[bart] make set of background/icon/image width alone work [bart] make set of background/icon/image width alone work
[bart] check for recursive anchors and print a error instead of crashing [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
== Client modules == Client modules
[bart] make possible to reload modules [bart] make possible to reload modules
@ -73,11 +74,12 @@ change win32 mouse cursor icon
[bart] clean sprites cache periodically [bart] clean sprites cache periodically
[bart] create a shader manager [bart] create a shader manager
[bart] find a way to load map rendering styles [bart] find a way to load map rendering styles
[bart] move redering of creatures names, skulls, etc to UI
[bart] cache screen creatures in a list on map [bart] cache screen creatures in a list on map
[bart] handle corrupt errors in dat/spr [bart] handle corrupt errors in dat/spr
[bart] remake spr/dat using OTML and image files [bart] remake spr/dat using OTML and image files
[bart] rework map tile rendering (cache visible tiles, etc) [bart] rework map tile rendering (cache visible tiles, etc)
[bart] minimap windows [bart] minimap window
[bart] draw lights using shaders [bart] draw lights using shaders
[bart] limit FPS in options [bart] limit FPS in options
[bart] resize map, right panel [bart] resize map, right panel

View File

@ -8,7 +8,7 @@ function PingBar.init()
pingLabel:applyStyle({ ['anchors.left'] = 'prev.right', pingLabel:applyStyle({ ['anchors.left'] = 'prev.right',
['anchors.top'] = 'parent.top', ['anchors.top'] = 'parent.top',
['margin-top'] = 12, ['margin-top'] = 12,
['margin-left'] = 10, ['margin-left'] = 20,
font = 'verdana-11px-rounded', font = 'verdana-11px-rounded',
color = '#FE6500', color = '#FE6500',
width = 120, width = 120,

View File

@ -4,7 +4,7 @@ Module
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
autoLoad: false autoLoad: true
autoLoadAntecedence: 1000 autoLoadAntecedence: 1000
onLoad: | onLoad: |

View File

@ -108,16 +108,16 @@ function Terminal.init()
terminalWidget:setVisible(false) terminalWidget:setVisible(false)
terminalButton = TopMenu.addButton('terminalButton', 'Terminal (Ctrl + T)', '/core_styles/icons/terminal.png', Terminal.toggle) terminalButton = TopMenu.addButton('terminalButton', 'Terminal (Ctrl + T)', '/core_styles/icons/terminal.png', Terminal.toggle)
Hotkeys.bind('Ctrl+T', Terminal.toggle) Hotkeys.bindKeyDown('Ctrl+T', Terminal.toggle)
commandHistory = Settings.getList('terminal-history') commandHistory = Settings.getList('terminal-history')
commandLineEdit = terminalWidget:getChildById('commandLineEdit') commandLineEdit = terminalWidget:getChildById('commandLineEdit')
Hotkeys.bind('Up', function() navigateCommand(1) end, commandLineEdit) Hotkeys.bindKeyDown('Up', function() navigateCommand(1) end, commandLineEdit)
Hotkeys.bind('Down', function() navigateCommand(-1) end, commandLineEdit) Hotkeys.bindKeyDown('Down', function() navigateCommand(-1) end, commandLineEdit)
Hotkeys.bind('Tab', completeCommand, commandLineEdit) Hotkeys.bindKeyDown('Tab', completeCommand, commandLineEdit)
Hotkeys.bind('Enter', doCommand, commandLineEdit) Hotkeys.bindKeyDown('Enter', doCommand, commandLineEdit)
Hotkeys.bind('Return', doCommand, commandLineEdit) Hotkeys.bindKeyDown('Return', doCommand, commandLineEdit)
terminalBuffer = terminalWidget:getChildById('terminalBuffer') terminalBuffer = terminalWidget:getChildById('terminalBuffer')
Logger.setOnLog(onLog) Logger.setOnLog(onLog)
@ -126,7 +126,7 @@ end
function Terminal.terminate() function Terminal.terminate()
Settings.setList('terminal-history', commandHistory) Settings.setList('terminal-history', commandHistory)
Hotkeys.unbind('Ctrl+T') Hotkeys.unbindKeyDown('Ctrl+T')
Logger.setOnLog(nil) Logger.setOnLog(nil)
terminalButton:destroy() terminalButton:destroy()
terminalButton = nil terminalButton = nil

View File

@ -6,7 +6,8 @@ local loadBox
local characterList local characterList
-- private functions -- private functions
local function onCharactersWindowKeyPress(self, keyCode, keyText, keyboardModifiers) local function onCharactersWindowKeyPress(self, keyCode, keyboardModifiers, wouldFilter)
if wouldFilter then return end
if keyboardModifiers == KeyboardNoModifier then if keyboardModifiers == KeyboardNoModifier then
if keyCode == KeyUp then if keyCode == KeyUp then
characterList:focusPreviousChild(ActiveFocusReason) characterList:focusPreviousChild(ActiveFocusReason)

View File

@ -57,7 +57,7 @@ end
-- public functions -- public functions
function EnterGame.init() function EnterGame.init()
enterGameButton = TopMenu.addButton('enterGameButton', 'Login (Ctrl + G)', '/core_styles/icons/login.png', EnterGame.openWindow) enterGameButton = TopMenu.addButton('enterGameButton', 'Login (Ctrl + G)', '/core_styles/icons/login.png', EnterGame.openWindow)
Hotkeys.bind('Ctrl+G', EnterGame.openWindow) Hotkeys.bindKeyDown('Ctrl+G', EnterGame.openWindow)
motdButton = TopMenu.addButton('motdButton', 'Message of the day', '/core_styles/icons/motd.png', EnterGame.displayMotd) motdButton = TopMenu.addButton('motdButton', 'Message of the day', '/core_styles/icons/motd.png', EnterGame.displayMotd)
motdButton:hide() motdButton:hide()
enterGame = displayUI('entergame.otui') enterGame = displayUI('entergame.otui')
@ -82,7 +82,7 @@ function EnterGame.init()
end end
function EnterGame.terminate() function EnterGame.terminate()
Hotkeys.unbind('Ctrl+G') Hotkeys.unbindKeyDown('Ctrl+G')
enterGame:destroy() enterGame:destroy()
enterGame = nil enterGame = nil
enterGameButton:destroy() enterGameButton:destroy()

View File

@ -25,11 +25,11 @@ function Options.init()
optionsWindow = displayUI('options.otui') optionsWindow = displayUI('options.otui')
optionsWindow:setVisible(false) optionsWindow:setVisible(false)
optionsButton = TopMenu.addButton('settingsButton', 'Options (Ctrl+O)', '/core_styles/icons/settings.png', Options.toggle) optionsButton = TopMenu.addButton('settingsButton', 'Options (Ctrl+O)', '/core_styles/icons/settings.png', Options.toggle)
Hotkeys.bind('Ctrl+O', Options.toggle) Hotkeys.bindKeyDown('Ctrl+O', Options.toggle)
end end
function Options.terminate() function Options.terminate()
Hotkeys.unbind('Ctrl+O') Hotkeys.unbindKeyDown('Ctrl+O')
optionsWindow:destroy() optionsWindow:destroy()
optionsWindow = nil optionsWindow = nil
optionsButton:destroy() optionsButton:destroy()

View File

@ -23,11 +23,11 @@ function TopMenu.init()
gameButtonsPanel = topMenu:getChildById('gameButtonsPanel') gameButtonsPanel = topMenu:getChildById('gameButtonsPanel')
TopMenu.addRightButton('logoutButton', 'Logout (Ctrl+Q)', '/core_styles/icons/logout.png', onLogout) TopMenu.addRightButton('logoutButton', 'Logout (Ctrl+Q)', '/core_styles/icons/logout.png', onLogout)
Hotkeys.bind('Ctrl+Q', onLogout) Hotkeys.bindKeyDown('Ctrl+Q', onLogout)
end end
function TopMenu.terminate() function TopMenu.terminate()
Hotkeys.unbind('Ctrl+Q') Hotkeys.unbindKeyDown('Ctrl+Q')
leftButtonsPanel = nil leftButtonsPanel = nil
rightButtonsPanel = nil rightButtonsPanel = nil
topMenu:destroy() topMenu:destroy()

View File

@ -45,6 +45,15 @@ AlignTopCenter = 20
AlignBottomCenter = 24 AlignBottomCenter = 24
AlignCenter = 48 AlignCenter = 48
North = 0
East = 1
South = 2
West = 3
NorthEast = 4
SouthEast = 5
SouthWest = 6
NorthWest = 7
KeyUnknown = 0 KeyUnknown = 0
KeyEscape = 1 KeyEscape = 1

View File

@ -58,10 +58,10 @@ local function determineKeyComboDesc(keyCode, keyboardModifiers)
return translateKeyCombo(keyCombo) return translateKeyCombo(keyCombo)
end end
local function onWidgetKeyPress(widget, keyCode, keyText, keyboardModifiers) local function onWidgetKeyDown(widget, keyCode, keyboardModifiers)
if keyCode == KeyUnknown then return end if keyCode == KeyUnknown then return end
local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers) local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
local callback = widget.boundKeyCombos[keyComboDesc] local callback = widget.boundKeyDownCombos[keyComboDesc]
if callback then if callback then
callback() callback()
return true return true
@ -69,29 +69,57 @@ local function onWidgetKeyPress(widget, keyCode, keyText, keyboardModifiers)
return false return false
end end
local function connectWidgetHotkeyEvent(widget) local function onWidgetKeyPress(widget, keyCode, keyboardModifiers, wouldFilter)
if widget.boundKeyCombos then return end local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
if keyCode == KeyUnknown then return end
local callback = widget.boundKeyPressCombos[keyComboDesc]
if callback then
callback()
return true
end
return false
end
local function connectKeyDownEvent(widget)
if widget.boundKeyDownCombos then return end
connect(widget, { onKeyDown = onWidgetKeyDown })
widget.boundKeyDownCombos = {}
end
local function connectKeyPressEvent(widget)
if widget.boundKeyPressCombos then return end
connect(widget, { onKeyPress = onWidgetKeyPress }) connect(widget, { onKeyPress = onWidgetKeyPress })
widget.boundKeyCombos = {} widget.boundKeyPressCombos = {}
end end
-- public functions -- public functions
function Hotkeys.bind(keyComboDesc, callback, widget) function Hotkeys.bindKeyDown(keyComboDesc, callback, widget)
widget = widget or rootWidget widget = widget or rootWidget
connectWidgetHotkeyEvent(widget) connectKeyDownEvent(widget)
local keyComboDesc = retranslateKeyComboDesc(keyComboDesc) local keyComboDesc = retranslateKeyComboDesc(keyComboDesc)
if keyComboDesc then if keyComboDesc then
widget.boundKeyCombos[keyComboDesc] = callback widget.boundKeyDownCombos[keyComboDesc] = callback
else else
error('key combo \'' .. keyComboDesc .. '\' is failed') error('key combo \'' .. keyComboDesc .. '\' is failed')
end end
end end
function Hotkeys.unbind(keyComboDesc, widget) function Hotkeys.bindKeyPress(keyComboDesc, callback, widget)
widget = widget or rootWidget widget = widget or rootWidget
if widget.boundKeyCombos == nil then return end connectKeyPressEvent(widget)
local keyComboDesc = retranslateKeyComboDesc(keyComboDesc) local keyComboDesc = retranslateKeyComboDesc(keyComboDesc)
if keyComboDesc then if keyComboDesc then
widget.boundKeyCombos[keyComboDesc] = nil widget.boundKeyPressCombos[keyComboDesc] = callback
else
error('key combo \'' .. keyComboDesc .. '\' is failed')
end
end
function Hotkeys.unbindKeyDown(keyComboDesc, widget)
widget = widget or rootWidget
if widget.boundKeyDownCombos == nil then return end
local keyComboDesc = retranslateKeyComboDesc(keyComboDesc)
if keyComboDesc then
widget.boundKeyDownCombos[keyComboDesc] = nil
end end
end end

View File

@ -5,7 +5,7 @@ local displayedMenuList = {}
function UIPopupMenu.create() function UIPopupMenu.create()
local menu = UIPopupMenu.internalCreate() local menu = UIPopupMenu.internalCreate()
local layout = UIVerticalLayout.create(menu) local layout = UIVerticalLayout.create(menu)
layout:setFitParent(true) layout:setFitChildren(true)
menu:setLayout(layout) menu:setLayout(layout)
return menu return menu
end end
@ -53,7 +53,8 @@ function UIPopupMenu:onMousePress(mousePos, mouseButton)
return false return false
end end
function UIPopupMenu:onKeyPress(keyCode, keyText, keyboardModifiers) function UIPopupMenu:onKeyPress(keyCode, keyboardModifiers, wouldFilter)
if wouldFilter then return end
if keyCode == KeyEscape then if keyCode == KeyEscape then
self:destroy() self:destroy()
return true return true

View File

@ -6,7 +6,8 @@ function UIWindow.create()
return window return window
end end
function UIWindow:onKeyPress(keyCode, keyText, keyboardModifiers) function UIWindow:onKeyPress(keyCode, keyboardModifiers, wouldFilter)
if wouldFilter then return end
if keyboardModifiers == KeyboardNoModifier then if keyboardModifiers == KeyboardNoModifier then
if keyCode == KeyReturn or keyCode == KeyEnter then if keyCode == KeyReturn or keyCode == KeyEnter then
signalcall(self.onEnter, self) signalcall(self.onEnter, self)

View File

@ -1,5 +1,6 @@
-- private functions -- private functions
local function onGameKeyPress(self, keyCode, keyText, keyboardModifiers) local function onGameKeyPress(self, keyCode, keyboardModifiers, wouldFilter)
if wouldFilter then return end
if keyboardModifiers == KeyboardCtrlModifier then if keyboardModifiers == KeyboardCtrlModifier then
if keyCode == KeyG then if keyCode == KeyG then
CharacterList.show() CharacterList.show()
@ -17,6 +18,17 @@ function Game.createInterface()
Background.hide() Background.hide()
CharacterList.destroyLoadBox() CharacterList.destroyLoadBox()
Game.gameUi = displayUI('game.otui') Game.gameUi = displayUI('game.otui')
--Hotkeys.bindKeyPress('Up', function() Game.walk(North) end)
--Hotkeys.bindKeyPress('Down', function() Game.walk(South) end)
--Hotkeys.bindKeyPress('Left', function() Game.walk(West) end)
--Hotkeys.bindKeyPress('Right', function() Game.walk(East) end)
Hotkeys.bindKeyPress('Ctrl+Shift+Up', function() Game.forceWalk(North) end)
Hotkeys.bindKeyPress('Ctrl+Shift+Down', function() Game.forceWalk(South) end)
Hotkeys.bindKeyPress('Ctrl+Shift+Left', function() Game.forceWalk(West) end)
Hotkeys.bindKeyPress('Ctrl+Shift+Right', function() Game.forceWalk(East) end)
rootWidget:moveChildToIndex(Game.gameUi, 1) rootWidget:moveChildToIndex(Game.gameUi, 1)
Game.gameMapPanel = Game.gameUi:getChildById('gameMapPanel') Game.gameMapPanel = Game.gameUi:getChildById('gameMapPanel')
Game.gameRightPanel = Game.gameUi:getChildById('gameRightPanel') Game.gameRightPanel = Game.gameUi:getChildById('gameRightPanel')

View File

@ -48,10 +48,10 @@ function Console.create()
Console.addChannel('Default', 0) Console.addChannel('Default', 0)
Console.addTab('Server Log') Console.addTab('Server Log')
Hotkeys.bind('Tab', function() consoleTabBar:selectNextTab() end, consolePanel) Hotkeys.bindKeyDown('Tab', function() consoleTabBar:selectNextTab() end, consolePanel)
Hotkeys.bind('Shift+Tab', function() consoleTabBar:selectPrevTab() end, consolePanel) Hotkeys.bindKeyDown('Shift+Tab', function() consoleTabBar:selectPrevTab() end, consolePanel)
Hotkeys.bind('Enter', Console.sendCurrentMessage, consolePanel) Hotkeys.bindKeyDown('Enter', Console.sendCurrentMessage, consolePanel)
Hotkeys.bind('Return', Console.sendCurrentMessage, consolePanel) Hotkeys.bindKeyDown('Return', Console.sendCurrentMessage, consolePanel)
end end
function Console.destroy() function Console.destroy()

View File

@ -1,18 +1,18 @@
-- this file use loaded after everything is loaded and initialized -- this file use loaded after everything is loaded and initialized
-- you can place any custom user code here -- you can place any custom user code here
Hotkeys.bind('F1', function() Game.talk('exura gran') end) Hotkeys.bindKeyDown('F1', function() Game.talk('exura gran') end)
Hotkeys.bind('F2', function() Game.talk('exori mort') end) Hotkeys.bindKeyDown('F2', function() Game.talk('exori mort') end)
Hotkeys.bind('F3', function() Game.talk('exori frigo') end) Hotkeys.bindKeyDown('F3', function() Game.talk('exori frigo') end)
Hotkeys.bind('F4', function() Game.talk('exevo vis hur') end) Hotkeys.bindKeyDown('F4', function() Game.talk('exevo vis hur') end)
Hotkeys.bind('F5', function() Game.talk('utani gran hur') end) Hotkeys.bindKeyDown('F5', function() Game.talk('utani gran hur') end)
Hotkeys.bind('F6', function() Game.talk('exani tera') end) Hotkeys.bindKeyDown('F6', function() Game.talk('exani tera') end)
local function reload() local function reload()
runscript('otclientrc.lua') runscript('otclientrc.lua')
TextMessage.displayEventAdvance('Script otclientrc.lua reloaded.') TextMessage.displayEventAdvance('Script otclientrc.lua reloaded.')
print('Script otclient.rc lua reloaded') print('Script otclient.rc lua reloaded')
end end
Hotkeys.bind('Ctrl+R', reload) Hotkeys.bindKeyDown('Ctrl+R', reload)
rcloaded = true rcloaded = true

View File

@ -228,6 +228,8 @@ namespace Fw
enum InputEventType { enum InputEventType {
NoInputEvent = 0, NoInputEvent = 0,
KeyTextInputEvent,
KeyDownInputEvent,
KeyPressInputEvent, KeyPressInputEvent,
KeyReleaseInputEvent, KeyReleaseInputEvent,
MousePressInputEvent, MousePressInputEvent,

View File

@ -76,10 +76,8 @@ void ConfigManager::setList(const std::string& key, const std::vector<std::strin
return; return;
OTMLNodePtr child = OTMLNode::create(key, true); OTMLNodePtr child = OTMLNode::create(key, true);
for(const std::string& value : list) { for(const std::string& value : list)
child->writeIn(value); child->writeIn(value);
dump << "insert" << value;
}
m_confsDoc->addChild(child); m_confsDoc->addChild(child);
} }

View File

@ -26,14 +26,30 @@
#include "declarations.h" #include "declarations.h"
struct InputEvent { struct InputEvent {
InputEvent() {
reset();
keyboardModifiers = 0;
}
void reset(Fw::InputEventType eventType = Fw::NoInputEvent) {
type = eventType;
wheelDirection = Fw::MouseNoWheel;
mouseButton = Fw::MouseNoButton;
keyCode = Fw::KeyUnknown;
keyText = "";
mouseMoved = Point();
wouldFilter = false;
};
Fw::InputEventType type; Fw::InputEventType type;
Fw::MouseWheelDirection wheelDirection; Fw::MouseWheelDirection wheelDirection;
Fw::MouseButton mouseButton; Fw::MouseButton mouseButton;
int keyboardModifiers;
std::string keyText;
Fw::Key keyCode; Fw::Key keyCode;
std::string keyText;
int keyboardModifiers;
Point mousePos; Point mousePos;
Point mouseMoved; Point mouseMoved;
bool wouldFilter;
}; };
#endif #endif

View File

@ -29,7 +29,7 @@ Particle::Particle(const Point& pos, const Size& startSize, const Size& finalSiz
m_colors = colors; m_colors = colors;
m_colorsStops = colorsStops; m_colorsStops = colorsStops;
m_position = PointF(pos.x, pos.y); m_pos = PointF(pos.x, pos.y);
m_startSize = startSize; m_startSize = startSize;
m_finalSize = finalSize; m_finalSize = finalSize;
m_velocity = velocity; m_velocity = velocity;
@ -80,18 +80,18 @@ void Particle::updatePosition(double elapsedTime)
PointF delta = m_velocity * elapsedTime; PointF delta = m_velocity * elapsedTime;
delta.y *= -1; // painter orientate Y axis in the inverse direction delta.y *= -1; // painter orientate Y axis in the inverse direction
PointF position = m_position + delta; PointF position = m_pos + delta;
if(m_position != position) { if(m_pos != position) {
mustRedraw = true; mustRedraw = true;
m_position += delta; m_pos += delta;
} }
// update acceleration // update acceleration
m_velocity += m_acceleration * elapsedTime; m_velocity += m_acceleration * elapsedTime;
} }
m_rect.move((int)m_position.x - m_size.width() / 2, (int)m_position.y - m_size.height() / 2); m_rect.move((int)m_pos.x - m_size.width() / 2, (int)m_pos.y - m_size.height() / 2);
} }
void Particle::updateSize() void Particle::updateSize()

View File

@ -36,10 +36,10 @@ public:
bool hasFinished() { return m_finished; } bool hasFinished() { return m_finished; }
PointF getPos() { return m_position; } PointF getPos() { return m_pos; }
PointF getVelocity() { return m_velocity; } PointF getVelocity() { return m_velocity; }
void setPos(const PointF& position) { m_position = position; } void setPos(const PointF& position) { m_pos = position; }
void setVelocity(const PointF& velocity) { m_velocity = velocity; } void setVelocity(const PointF& velocity) { m_velocity = velocity; }
private: private:
@ -51,7 +51,7 @@ private:
std::vector<Color> m_colors; std::vector<Color> m_colors;
std::vector<float> m_colorsStops; std::vector<float> m_colorsStops;
TexturePtr m_texture; TexturePtr m_texture;
PointF m_position; PointF m_pos;
PointF m_velocity; PointF m_velocity;
PointF m_acceleration; PointF m_acceleration;
Size m_size, m_startSize, m_finalSize; Size m_size, m_startSize, m_finalSize;

View File

@ -115,7 +115,7 @@ bool AttractionAffector::load(const OTMLNodePtr& node)
for(const OTMLNodePtr& childNode : node->children()) { for(const OTMLNodePtr& childNode : node->children()) {
if(childNode->tag() == "position") if(childNode->tag() == "position")
m_position = childNode->value<Point>(); m_pos = childNode->value<Point>();
else if(childNode->tag() == "acceleration") else if(childNode->tag() == "acceleration")
m_acceleration = childNode->value<float>(); m_acceleration = childNode->value<float>();
else if(childNode->tag() == "velocity-reduction-percent") else if(childNode->tag() == "velocity-reduction-percent")
@ -132,7 +132,7 @@ void AttractionAffector::updateParticle(const ParticlePtr& particle, double elap
return; return;
PointF pPosition = particle->getPos(); PointF pPosition = particle->getPos();
PointF d = PointF(m_position.x - pPosition.x, pPosition.y - m_position.y); PointF d = PointF(m_pos.x - pPosition.x, pPosition.y - m_pos.y);
if(d.length() == 0) if(d.length() == 0)
return; return;

View File

@ -57,7 +57,7 @@ public:
void updateParticle(const ParticlePtr& particle, double elapsedTime); void updateParticle(const ParticlePtr& particle, double elapsedTime);
private: private:
Point m_position; Point m_pos;
float m_acceleration, m_reduction; float m_acceleration, m_reduction;
bool m_repelish; bool m_repelish;
}; };

View File

@ -31,7 +31,7 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent)
{ {
m_parent = parent; m_parent = parent;
m_position = Point(0, 0); m_pos = Point(0, 0);
m_duration = -1; m_duration = -1;
m_delay = 0; m_delay = 0;
m_burstRate = 1; m_burstCount = 32; m_burstRate = 1; m_burstCount = 32;
@ -65,7 +65,7 @@ bool ParticleEmitter::load(const OTMLNodePtr& node)
for(const OTMLNodePtr& childNode : node->children()) { for(const OTMLNodePtr& childNode : node->children()) {
// self related // self related
if(childNode->tag() == "position") if(childNode->tag() == "position")
m_position = childNode->value<Point>(); m_pos = childNode->value<Point>();
else if(childNode->tag() == "duration") else if(childNode->tag() == "duration")
m_duration = childNode->value<float>(); m_duration = childNode->value<float>();
else if(childNode->tag() == "delay") else if(childNode->tag() == "delay")
@ -199,7 +199,7 @@ void ParticleEmitter::update(double elapsedTime)
float pRadius = Fw::randomRange(m_pMinPositionRadius, m_pMaxPositionRadius); float pRadius = Fw::randomRange(m_pMinPositionRadius, m_pMaxPositionRadius);
float pAngle = Fw::randomRange(m_pMinPositionAngle, m_pMaxPositionAngle); float pAngle = Fw::randomRange(m_pMinPositionAngle, m_pMaxPositionAngle);
Point pPosition = m_position + Point(pRadius * cos(pAngle), pRadius * sin(pAngle)); Point pPosition = m_pos + Point(pRadius * cos(pAngle), pRadius * sin(pAngle));
for(int p = 0; p < m_burstCount; ++p) { for(int p = 0; p < m_burstCount; ++p) {

View File

@ -44,7 +44,7 @@ private:
ParticleSystemWeakPtr m_parent; ParticleSystemWeakPtr m_parent;
// self related // self related
Point m_position; Point m_pos;
float m_duration, m_delay; float m_duration, m_delay;
double m_elapsedTime; double m_elapsedTime;
bool m_finished, m_active; bool m_finished, m_active;

View File

@ -294,12 +294,12 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UIBoxLayout>("setFitChildren", &UIBoxLayout::setFitChildren); g_lua.bindClassMemberFunction<UIBoxLayout>("setFitChildren", &UIBoxLayout::setFitChildren);
// UIVerticalLayout // UIVerticalLayout
g_lua.registerClass<UIVerticalLayout, UILayout>(); g_lua.registerClass<UIVerticalLayout, UIBoxLayout>();
g_lua.bindClassStaticFunction<UIVerticalLayout>("create", [](UIWidgetPtr parent){ return UIVerticalLayoutPtr(new UIVerticalLayout(parent)); } ); g_lua.bindClassStaticFunction<UIVerticalLayout>("create", [](UIWidgetPtr parent){ return UIVerticalLayoutPtr(new UIVerticalLayout(parent)); } );
g_lua.bindClassMemberFunction<UIVerticalLayout>("setAlignBottom", &UIVerticalLayout::setAlignBottom); g_lua.bindClassMemberFunction<UIVerticalLayout>("setAlignBottom", &UIVerticalLayout::setAlignBottom);
// UIHorizontalLayout // UIHorizontalLayout
g_lua.registerClass<UIHorizontalLayout, UILayout>(); g_lua.registerClass<UIHorizontalLayout, UIBoxLayout>();
g_lua.bindClassStaticFunction<UIHorizontalLayout>("create", [](UIWidgetPtr parent){ return UIHorizontalLayoutPtr(new UIHorizontalLayout(parent)); } ); g_lua.bindClassStaticFunction<UIHorizontalLayout>("create", [](UIWidgetPtr parent){ return UIHorizontalLayoutPtr(new UIHorizontalLayout(parent)); } );
g_lua.bindClassMemberFunction<UIHorizontalLayout>("setAlignRight", &UIHorizontalLayout::setAlignRight); g_lua.bindClassMemberFunction<UIHorizontalLayout>("setAlignRight", &UIHorizontalLayout::setAlignRight);
@ -404,6 +404,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassStaticFunction("g_window", "getY", std::bind(&PlatformWindow::getY, &g_window)); g_lua.bindClassStaticFunction("g_window", "getY", std::bind(&PlatformWindow::getY, &g_window));
g_lua.bindClassStaticFunction("g_window", "getMousePos", std::bind(&PlatformWindow::getMousePos, &g_window)); g_lua.bindClassStaticFunction("g_window", "getMousePos", std::bind(&PlatformWindow::getMousePos, &g_window));
g_lua.bindClassStaticFunction("g_window", "getKeyboardModifiers", std::bind(&PlatformWindow::getKeyboardModifiers, &g_window)); g_lua.bindClassStaticFunction("g_window", "getKeyboardModifiers", std::bind(&PlatformWindow::getKeyboardModifiers, &g_window));
g_lua.bindClassStaticFunction("g_window", "isKeyPressed", std::bind(&PlatformWindow::isKeyPressed, &g_window, _1));
g_lua.bindClassStaticFunction("g_window", "isVisible", std::bind(&PlatformWindow::isVisible, &g_window)); g_lua.bindClassStaticFunction("g_window", "isVisible", std::bind(&PlatformWindow::isVisible, &g_window));
g_lua.bindClassStaticFunction("g_window", "isFullscreen", std::bind(&PlatformWindow::isFullscreen, &g_window)); g_lua.bindClassStaticFunction("g_window", "isFullscreen", std::bind(&PlatformWindow::isFullscreen, &g_window));
g_lua.bindClassStaticFunction("g_window", "isMaximized", std::bind(&PlatformWindow::isMaximized, &g_window)); g_lua.bindClassStaticFunction("g_window", "isMaximized", std::bind(&PlatformWindow::isMaximized, &g_window));

View File

@ -27,6 +27,7 @@
WIN32Window window; WIN32Window window;
#else #else
#include "x11window.h" #include "x11window.h"
#include <framework/core/clock.h>
X11Window window; X11Window window;
#endif #endif
@ -39,3 +40,83 @@ void PlatformWindow::updateUnmaximizedCoords()
m_unmaximizedSize = m_size; m_unmaximizedSize = m_size;
} }
} }
void PlatformWindow::processKeyDown(Fw::Key keyCode)
{
if(keyCode == Fw::KeyUnknown || m_keysState[keyCode])
return;
m_keysState[keyCode] = true;
m_lastKeysPress[keyCode] = -1;
if(keyCode == Fw::KeyCtrl)
m_inputEvent.keyboardModifiers |= Fw::KeyboardCtrlModifier;
else if(keyCode == Fw::KeyAlt)
m_inputEvent.keyboardModifiers |= Fw::KeyboardAltModifier;
else if(keyCode == Fw::KeyShift)
m_inputEvent.keyboardModifiers |= Fw::KeyboardShiftModifier;
m_inputEvent.reset();
m_inputEvent.type = Fw::KeyDownInputEvent;
m_inputEvent.keyCode = keyCode;
if(m_onInputEvent) {
m_onInputEvent(m_inputEvent);
m_inputEvent.reset(Fw::KeyPressInputEvent);
m_inputEvent.keyCode = keyCode;
m_lastKeysPress[keyCode] = g_clock.ticks();
m_firstKeysPress[keyCode] = g_clock.ticks();
m_onInputEvent(m_inputEvent);
}
}
void PlatformWindow::processKeyRelease(Fw::Key keyCode)
{
if(keyCode == Fw::KeyUnknown || !m_keysState[keyCode])
return;
m_keysState[keyCode] = false;
if(keyCode == Fw::KeyCtrl)
m_inputEvent.keyboardModifiers &= ~Fw::KeyboardCtrlModifier;
else if(keyCode == Fw::KeyAlt)
m_inputEvent.keyboardModifiers &= ~Fw::KeyboardAltModifier;
else if(keyCode == Fw::KeyShift)
m_inputEvent.keyboardModifiers &= ~Fw::KeyboardShiftModifier;
if(m_onInputEvent) {
m_inputEvent.reset(Fw::KeyReleaseInputEvent);
m_onInputEvent(m_inputEvent);
}
}
void PlatformWindow::fireKeysPress()
{
// avoid massive checks
if(m_keyPressTimer.ticksElapsed() < 10)
return;
m_keyPressTimer.restart();
for(auto it : m_keysState) {
Fw::Key keyCode = it.first;
bool pressed = it.second;
if(!pressed)
continue;
ticks_t lastPressTicks = m_lastKeysPress[keyCode];
ticks_t firstKeyPress = m_firstKeysPress[keyCode];
if(g_clock.ticksElapsed(lastPressTicks) >= KEY_PRESS_REPEAT_INTERVAL) {
if(m_onInputEvent) {
m_inputEvent.reset();
m_inputEvent.type = Fw::KeyPressInputEvent;
m_inputEvent.keyCode = keyCode;
m_inputEvent.wouldFilter = g_clock.ticksElapsed(firstKeyPress) < KEY_PRESS_REPEAT_DELAY;
m_onInputEvent(m_inputEvent);
}
m_lastKeysPress[keyCode] = g_clock.ticks();
}
}
}

View File

@ -25,9 +25,15 @@
#include <framework/global.h> #include <framework/global.h>
#include <framework/core/inputevent.h> #include <framework/core/inputevent.h>
#include <framework/core/timer.h>
class PlatformWindow class PlatformWindow
{ {
enum {
KEY_PRESS_REPEAT_INTERVAL = 30,
KEY_PRESS_REPEAT_DELAY = 500
};
typedef std::function<void(const Size&)> OnResizeCallback; typedef std::function<void(const Size&)> OnResizeCallback;
typedef std::function<void(const InputEvent&)> OnInputEventCallback; typedef std::function<void(const InputEvent&)> OnInputEventCallback;
@ -72,6 +78,7 @@ public:
int getY() { return m_pos.y; } int getY() { return m_pos.y; }
Point getMousePos() { return m_inputEvent.mousePos; } Point getMousePos() { return m_inputEvent.mousePos; }
int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; } int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; }
bool isKeyPressed(Fw::Key keyCode) { return m_keysState[keyCode]; }
bool isVisible() { return m_visible; } bool isVisible() { return m_visible; }
bool isFullscreen() { return m_fullscreen; } bool isFullscreen() { return m_fullscreen; }
@ -85,6 +92,16 @@ public:
protected: protected:
void updateUnmaximizedCoords(); void updateUnmaximizedCoords();
void processKeyDown(Fw::Key keyCode);
void processKeyRelease(Fw::Key keyCode);
void fireKeysPress();
std::map<int, Fw::Key> m_keyMap;
std::map<Fw::Key, Boolean<false>> m_keysState;
std::map<Fw::Key, ticks_t> m_firstKeysPress;
std::map<Fw::Key, ticks_t> m_lastKeysPress;
Timer m_keyPressTimer;
Size m_size; Size m_size;
Point m_pos; Point m_pos;
Size m_unmaximizedSize; Size m_unmaximizedSize;

View File

@ -35,7 +35,6 @@ WIN32Window::WIN32Window()
m_maximized = false; m_maximized = false;
m_minimumSize = Size(16,16); m_minimumSize = Size(16,16);
m_size = m_minimumSize; m_size = m_minimumSize;
m_inputEvent.keyboardModifiers = 0;
m_keyMap[VK_ESCAPE] = Fw::KeyEscape; m_keyMap[VK_ESCAPE] = Fw::KeyEscape;
m_keyMap[VK_TAB] = Fw::KeyTab; m_keyMap[VK_TAB] = Fw::KeyTab;

View File

@ -82,7 +82,6 @@ private:
HGLRC m_glContext; HGLRC m_glContext;
bool m_maximized; bool m_maximized;
Size m_minimumSize; Size m_minimumSize;
std::map<int, Fw::Key> m_keyMap;
}; };
#endif #endif

View File

@ -39,7 +39,6 @@ X11Window::X11Window()
m_screen = 0; m_screen = 0;
m_wmDelete = 0; m_wmDelete = 0;
m_size = Size(16,16); m_size = Size(16,16);
m_inputEvent.keyboardModifiers = 0;
#ifndef OPENGL_ES2 #ifndef OPENGL_ES2
m_glxContext = 0; m_glxContext = 0;
@ -526,33 +525,41 @@ void X11Window::poll()
while(XPending(m_display) > 0) { while(XPending(m_display) > 0) {
XNextEvent(m_display, &event); XNextEvent(m_display, &event);
// check for repeated key releases
bool repatedKeyRelease = false;
if(event.type == KeyRelease && XPending(m_display)) {
XPeekEvent(m_display, &peekEvent);
if((peekEvent.type == KeyPress) && (peekEvent.xkey.keycode == event.xkey.keycode) && ((peekEvent.xkey.time-event.xkey.time) < 2))
repatedKeyRelease = true;
}
// process keydown and keyrelease events first
if(event.type == KeyPress || (event.type == KeyRelease && !repatedKeyRelease)) {
// remove caps lock and shift maks
XKeyEvent xkey = event.xkey;
xkey.state &= ~(ShiftMask | LockMask);
// lookup keysym and translate it
KeySym keysym;
char buf[32];
int len = XLookupString(&xkey, buf, sizeof(buf), &keysym, 0);
Fw::Key keyCode = Fw::KeyUnknown;
if(m_keyMap.find(keysym) != m_keyMap.end())
keyCode = m_keyMap[keysym];
if(event.type == KeyPress)
processKeyDown(keyCode);
else if(event.type == KeyRelease)
processKeyRelease(keyCode);
}
// call filter because xim will discard KeyPress events when keys still composing // call filter because xim will discard KeyPress events when keys still composing
if(XFilterEvent(&event, m_window)) if(XFilterEvent(&event, m_window))
continue; continue;
// discard events of repeated key releases // discard repated key releases
if(event.type == KeyRelease && XPending(m_display)) { if(repatedKeyRelease)
XPeekEvent(m_display, &peekEvent); continue;
if((peekEvent.type == KeyPress) &&
(peekEvent.xkey.keycode == event.xkey.keycode) &&
((peekEvent.xkey.time-event.xkey.time) < 2))
continue;
}
// reset inputEvent values, except keyboardModifiers and mousePos
m_inputEvent.type = Fw::NoInputEvent;
m_inputEvent.mouseButton = Fw::MouseNoButton;
m_inputEvent.keyCode = Fw::KeyUnknown;
m_inputEvent.keyText = "";
m_inputEvent.mouseMoved = Point();
m_inputEvent.wheelDirection = Fw::MouseNoWheel;
m_inputEvent.keyboardModifiers = 0;
if(event.xkey.state & ControlMask)
m_inputEvent.keyboardModifiers |= Fw::KeyboardCtrlModifier;
if(event.xkey.state & ShiftMask)
m_inputEvent.keyboardModifiers |= Fw::KeyboardShiftModifier;
if(event.xkey.state & Mod1Mask)
m_inputEvent.keyboardModifiers |= Fw::KeyboardAltModifier;
switch(event.type) { switch(event.type) {
case ClientMessage: { case ClientMessage: {
@ -614,55 +621,44 @@ void X11Window::poll()
XFlush(m_display); XFlush(m_display);
break; break;
} }
case KeyPress: // process text events
case KeyRelease: { case KeyPress: {
// text cant be insert while holding ctrl or alt
if(event.xkey.state & ControlMask || event.xkey.state & Mod1Mask)
break;
// process key text events
KeySym keysym; KeySym keysym;
char buf[32]; char buf[32];
memset(buf, 0, 32); memset(buf, 0, 32);
int len; int len;
// lookup for keyText // lookup for keyText
if(event.type == KeyPress && !(event.xkey.state & ControlMask) && !(event.xkey.state & Mod1Mask)) { if(m_xic) { // with xim we can get latin1 input correctly
if(m_xic) { // with xim we can get latin1 input correctly Status status;
Status status; len = XmbLookupString(m_xic, &event.xkey, buf, sizeof(buf), &keysym, &status);
len = XmbLookupString(m_xic, &event.xkey, buf, sizeof(buf), &keysym, &status); } else { // otherwise use XLookupString, but often it doesn't work right with dead keys
} else { // otherwise use XLookupString, but often it doesn't work right with dead keys static XComposeStatus compose = {NULL, 0};
static XComposeStatus compose = {NULL, 0}; len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose);
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose);
}
if(len > 0 &&
// these keys produces characters that we don't want to capture
keysym != XK_BackSpace &&
keysym != XK_Return &&
keysym != XK_Delete &&
keysym != XK_Escape &&
(uchar)(buf[0]) >= 32
) {
//logDebug("char: ", buf[0], " code: ", (uint)buf[0]);
m_inputEvent.keyText = buf;
}
} }
XKeyEvent xkey = event.xkey; // filter unwanted characters
xkey.state = xkey.state & ~(ShiftMask); if(len == 0 || (uchar)(buf[0]) < 32 || keysym == XK_BackSpace || keysym == XK_Return || keysym == XK_Delete || keysym == XK_Escape)
len = XLookupString(&xkey, buf, sizeof(buf), &keysym, 0); break;
if(len > 0 && m_inputEvent.keyText.length() == 0 && keysym != XK_BackSpace && std::string text = buf;
keysym != XK_Return &&
keysym != XK_Delete &&
keysym != XK_Escape)
m_inputEvent.keyText = buf;
if(m_keyMap.find(keysym) != m_keyMap.end()) //logDebug("char: ", buf[0], " code: ", (int)((uchar)buf[0]));
m_inputEvent.keyCode = m_keyMap[keysym];
m_inputEvent.type = (event.type == KeyPress) ? Fw::KeyPressInputEvent : Fw::KeyReleaseInputEvent; if(m_onInputEvent && text.length() > 0) {
if(m_inputEvent.keyCode != Fw::KeyUnknown || !m_inputEvent.keyText.empty()) m_inputEvent.reset(Fw::KeyTextInputEvent);
m_inputEvent.keyText = text;
m_onInputEvent(m_inputEvent); m_onInputEvent(m_inputEvent);
}
break; break;
} }
case ButtonPress: case ButtonPress:
case ButtonRelease: { case ButtonRelease: {
m_inputEvent.reset();
m_inputEvent.type = (event.type == ButtonPress) ? Fw::MousePressInputEvent : Fw::MouseReleaseInputEvent; m_inputEvent.type = (event.type == ButtonPress) ? Fw::MousePressInputEvent : Fw::MouseReleaseInputEvent;
switch(event.xbutton.button) { switch(event.xbutton.button) {
case Button1: case Button1:
@ -694,6 +690,7 @@ void X11Window::poll()
} }
case MotionNotify: { case MotionNotify: {
m_inputEvent.reset();
m_inputEvent.type = Fw::MouseMoveInputEvent; m_inputEvent.type = Fw::MouseMoveInputEvent;
Point newMousePos(event.xbutton.x, event.xbutton.y); Point newMousePos(event.xbutton.x, event.xbutton.y);
m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos; m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos;
@ -722,6 +719,8 @@ void X11Window::poll()
if(needsResizeUpdate && m_onResize) if(needsResizeUpdate && m_onResize)
m_onResize(m_size); m_onResize(m_size);
fireKeysPress();
} }
void X11Window::swapBuffers() void X11Window::swapBuffers()

View File

@ -93,7 +93,6 @@ private:
int m_screen; int m_screen;
Atom m_wmDelete; Atom m_wmDelete;
std::string m_clipboardText; std::string m_clipboardText;
std::map<int, Fw::Key> m_keyMap;
#ifndef OPENGL_ES2 #ifndef OPENGL_ES2
GLXContext m_glxContext; GLXContext m_glxContext;

View File

@ -389,6 +389,8 @@ void UILineEdit::onStyleApply(const std::string& styleName, const OTMLNodePtr& s
setTextHorizontalMargin(node->value<int>()); setTextHorizontalMargin(node->value<int>());
else if(node->tag() == "always-active") else if(node->tag() == "always-active")
setAlwaysActive(node->value<bool>()); setAlwaysActive(node->value<bool>());
//else if(node->tag() == "disable-arrow-navitation")
// setArrowNavigation(node->value<bool>());
} }
} }
@ -409,34 +411,41 @@ void UILineEdit::onFocusChange(bool focused, Fw::FocusReason reason)
UIWidget::onFocusChange(focused, reason); UIWidget::onFocusChange(focused, reason);
} }
bool UILineEdit::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers) bool UILineEdit::onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter)
{ {
if(UIWidget::onKeyPress(keyCode, keyText, keyboardModifiers)) if(UIWidget::onKeyPress(keyCode, keyboardModifiers, wouldFilter))
return true; return true;
if(keyCode == Fw::KeyDelete) // erase right character if(!wouldFilter) {
removeCharacter(true); if(keyCode == Fw::KeyDelete) // erase right character
else if(keyCode == Fw::KeyBackspace) // erase left character { removeCharacter(true);
removeCharacter(false); else if(keyCode == Fw::KeyBackspace) // erase left character {
else if(keyCode == Fw::KeyRight) // move cursor right removeCharacter(false);
moveCursor(true); else if(keyCode == Fw::KeyRight) // move cursor right
else if(keyCode == Fw::KeyLeft) // move cursor left moveCursor(true);
moveCursor(false); else if(keyCode == Fw::KeyLeft) // move cursor left
else if(keyCode == Fw::KeyHome) // move cursor to first character moveCursor(false);
setCursorPos(0); else if(keyCode == Fw::KeyHome) // move cursor to first character
else if(keyCode == Fw::KeyEnd) // move cursor to last character setCursorPos(0);
setCursorPos(m_text.length()); else if(keyCode == Fw::KeyEnd) // move cursor to last character
else if(keyCode == Fw::KeyV && keyboardModifiers == Fw::KeyboardCtrlModifier) setCursorPos(m_text.length());
appendText(g_window.getClipboardText()); else if(keyCode == Fw::KeyV && keyboardModifiers == Fw::KeyboardCtrlModifier)
else if(keyCode == Fw::KeyTab) { appendText(g_window.getClipboardText());
if(!m_alwaysActive) { else if(keyCode == Fw::KeyTab) {
if(UIWidgetPtr parent = getParent()) if(!m_alwaysActive) {
parent->focusNextChild(Fw::TabFocusReason); if(UIWidgetPtr parent = getParent())
} parent->focusNextChild(Fw::TabFocusReason);
} else if(!keyText.empty() && (keyboardModifiers == Fw::KeyboardNoModifier || keyboardModifiers == Fw::KeyboardShiftModifier)) }
appendText(keyText); } else
else return false;
return false; return true;
}
return false;
}
bool UILineEdit::onKeyText(const std::string& keyText)
{
appendText(keyText);
return true; return true;
} }

View File

@ -61,7 +61,8 @@ protected:
virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode); virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect); virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect);
virtual void onFocusChange(bool focused, Fw::FocusReason reason); virtual void onFocusChange(bool focused, Fw::FocusReason reason);
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers); virtual bool onKeyText(const std::string& keyText);
virtual bool onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter);
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button); virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
private: private:

View File

@ -59,11 +59,17 @@ void UIManager::inputEvent(const InputEvent& event)
{ {
m_isOnInputEvent = true; m_isOnInputEvent = true;
switch(event.type) { switch(event.type) {
case Fw::KeyTextInputEvent:
m_keyboardReceiver->propagateOnKeyText(event.keyText);
break;
case Fw::KeyDownInputEvent:
m_keyboardReceiver->propagateOnKeyDown(event.keyCode, event.keyboardModifiers);
break;
case Fw::KeyPressInputEvent: case Fw::KeyPressInputEvent:
m_keyboardReceiver->propagateOnKeyPress(event.keyCode, event.keyText, event.keyboardModifiers); m_keyboardReceiver->propagateOnKeyPress(event.keyCode, event.keyboardModifiers, event.wouldFilter);
break; break;
case Fw::KeyReleaseInputEvent: case Fw::KeyReleaseInputEvent:
m_keyboardReceiver->propagateOnKeyRelease(event.keyCode, event.keyText, event.keyboardModifiers); m_keyboardReceiver->propagateOnKeyRelease(event.keyCode, event.keyboardModifiers);
break; break;
case Fw::MousePressInputEvent: case Fw::MousePressInputEvent:
m_keyboardReceiver->propagateOnMousePress(event.mousePos, event.mouseButton); m_keyboardReceiver->propagateOnMousePress(event.mousePos, event.mouseButton);

View File

@ -1053,14 +1053,24 @@ void UIWidget::onHoverChange(bool hovered)
g_ui.getRootWidget()->updateState(Fw::HoverState); g_ui.getRootWidget()->updateState(Fw::HoverState);
} }
bool UIWidget::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers) bool UIWidget::onKeyText(const std::string& keyText)
{ {
return callLuaField<bool>("onKeyPress", keyCode, keyText, keyboardModifiers); return callLuaField<bool>("onKeyText", keyText);
} }
bool UIWidget::onKeyRelease(uchar keyCode, std::string keyText, int keyboardModifiers) bool UIWidget::onKeyDown(uchar keyCode, int keyboardModifiers)
{ {
return callLuaField<bool>("onKeyRelease", keyCode, keyText, keyboardModifiers); return callLuaField<bool>("onKeyDown", keyCode, keyboardModifiers);
}
bool UIWidget::onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter)
{
return callLuaField<bool>("onKeyPress", keyCode, keyboardModifiers, wouldFilter);
}
bool UIWidget::onKeyRelease(uchar keyCode, int keyboardModifiers)
{
return callLuaField<bool>("onKeyRelease", keyCode, keyboardModifiers);
} }
bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button) bool UIWidget::onMousePress(const Point& mousePos, Fw::MouseButton button)
@ -1086,7 +1096,7 @@ bool UIWidget::onMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direc
return callLuaField<bool>("onMouseWheel", mousePos, direction); return callLuaField<bool>("onMouseWheel", mousePos, direction);
} }
bool UIWidget::propagateOnKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers) bool UIWidget::propagateOnKeyText(const std::string& keyText)
{ {
// do a backup of children list, because it may change while looping it // do a backup of children list, because it may change while looping it
UIWidgetList children; UIWidgetList children;
@ -1101,14 +1111,58 @@ bool UIWidget::propagateOnKeyPress(uchar keyCode, std::string keyText, int keybo
} }
for(const UIWidgetPtr& child : children) { for(const UIWidgetPtr& child : children) {
if(child->propagateOnKeyPress(keyCode, keyText, keyboardModifiers)) if(child->propagateOnKeyText(keyText))
return true; return true;
} }
return onKeyPress(keyCode, keyText, keyboardModifiers); return onKeyText(keyText);
} }
bool UIWidget::propagateOnKeyRelease(uchar keyCode, std::string keyText, int keyboardModifiers) bool UIWidget::propagateOnKeyDown(uchar keyCode, int keyboardModifiers)
{
// do a backup of children list, because it may change while looping it
UIWidgetList children;
for(const UIWidgetPtr& child : m_children) {
// events on hidden or disabled widgets are discarded
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
continue;
// key events go only to containers or focused child
if(child->isFocused())
children.push_back(child);
}
for(const UIWidgetPtr& child : children) {
if(child->propagateOnKeyDown(keyCode, keyboardModifiers))
return true;
}
return onKeyDown(keyCode, keyboardModifiers);
}
bool UIWidget::propagateOnKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter)
{
// do a backup of children list, because it may change while looping it
UIWidgetList children;
for(const UIWidgetPtr& child : m_children) {
// events on hidden or disabled widgets are discarded
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
continue;
// key events go only to containers or focused child
if(child->isFocused())
children.push_back(child);
}
for(const UIWidgetPtr& child : children) {
if(child->propagateOnKeyPress(keyCode, keyboardModifiers, wouldFilter))
return true;
}
return onKeyPress(keyCode, keyboardModifiers, wouldFilter);
}
bool UIWidget::propagateOnKeyRelease(uchar keyCode, int keyboardModifiers)
{ {
// do a backup of children list, because it may change while looping it // do a backup of children list, because it may change while looping it
UIWidgetList children; UIWidgetList children;
@ -1123,11 +1177,11 @@ bool UIWidget::propagateOnKeyRelease(uchar keyCode, std::string keyText, int key
} }
for(const UIWidgetPtr& child : children) { for(const UIWidgetPtr& child : children) {
if(child->propagateOnKeyRelease(keyCode, keyText, keyboardModifiers)) if(child->propagateOnKeyRelease(keyCode, keyboardModifiers))
return true; return true;
} }
return onKeyRelease(keyCode, keyText, keyboardModifiers); return onKeyRelease(keyCode, keyboardModifiers);
} }
bool UIWidget::propagateOnMousePress(const Point& mousePos, Fw::MouseButton button) bool UIWidget::propagateOnMousePress(const Point& mousePos, Fw::MouseButton button)

View File

@ -161,15 +161,19 @@ protected:
virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect); virtual void onGeometryChange(const Rect& oldRect, const Rect& newRect);
virtual void onFocusChange(bool focused, Fw::FocusReason reason); virtual void onFocusChange(bool focused, Fw::FocusReason reason);
virtual void onHoverChange(bool hovered); virtual void onHoverChange(bool hovered);
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers); virtual bool onKeyText(const std::string& keyText);
virtual bool onKeyRelease(uchar keyCode, std::string keyText, int keyboardModifiers); virtual bool onKeyDown(uchar keyCode, int keyboardModifiers);
virtual bool onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter);
virtual bool onKeyRelease(uchar keyCode, int keyboardModifiers);
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button); virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
virtual void onMouseRelease(const Point& mousePos, Fw::MouseButton button); virtual void onMouseRelease(const Point& mousePos, Fw::MouseButton button);
virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved); virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
virtual bool onMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction); virtual bool onMouseWheel(const Point& mousePos, Fw::MouseWheelDirection direction);
bool propagateOnKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers); bool propagateOnKeyText(const std::string& keyText);
bool propagateOnKeyRelease(uchar keyCode, std::string keyText, int keyboardModifiers); bool propagateOnKeyDown(uchar keyCode, int keyboardModifiers);
bool propagateOnKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter);
bool propagateOnKeyRelease(uchar keyCode, int keyboardModifiers);
bool propagateOnMousePress(const Point& mousePos, Fw::MouseButton button); bool propagateOnMousePress(const Point& mousePos, Fw::MouseButton button);
void propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button); void propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button);
bool propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved); bool propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved);

View File

@ -47,7 +47,7 @@ Creature::Creature() : Thing()
m_walkTimePerPixel = 1000.0/32.0; m_walkTimePerPixel = 1000.0/32.0;
m_walking = false; m_walking = false;
m_inverseWalking = true; m_preWalking = false;
m_skull = Otc::SkullNone; m_skull = Otc::SkullNone;
m_shield = Otc::ShieldNone; m_shield = Otc::ShieldNone;
@ -189,51 +189,44 @@ void Creature::drawInformation(int x, int y, bool useGray, const Rect& visibleRe
} }
} }
void Creature::walk(const Position& position, bool inverse) void Creature::walk(const Position& oldPos, const Position& newPos, bool preWalk)
{ {
// We're walking // get walk direction
if(m_position.isInRange(position, 1, 1, 0)) { Otc::Direction direction = oldPos.getDirectionFromPosition(newPos);
Otc::Direction direction = m_position.getDirectionFromPosition(position);
setDirection(direction);
if(inverse) { // already pre walking to the same direction
Position positionDelta = m_position - position; if(m_preWalking && preWalk && direction == m_direction)
m_walkOffset = Point(positionDelta.x * Map::NUM_TILE_PIXELS, positionDelta.y * Map::NUM_TILE_PIXELS); return;
}
else
m_walkOffset = Point(0, 0);
// Diagonal walking lasts 3 times more. // pre walking was already going on, just change to normal waking
int walkTimeFactor = 1; if(m_preWalking && !preWalk && direction == m_direction) {
if(direction == Otc::NorthWest || direction == Otc::NorthEast || direction == Otc::SouthWest || direction == Otc::SouthEast) m_preWalking = false;
walkTimeFactor = 3;
// Get walking speed
int groundSpeed = 100;
if(ItemPtr ground = g_map.getTile(position)->getGround())
groundSpeed = ground->getType()->parameters[ThingType::GroundSpeed];
float walkTime = 1000.0 * (float)groundSpeed / m_speed;
walkTime = (walkTime == 0) ? 1000 : walkTime;
walkTime = std::ceil(walkTime / g_game.getServerBeat()) * g_game.getServerBeat();
bool sameWalk = m_walking && !m_inverseWalking && inverse;
m_inverseWalking = inverse;
m_walking = true; m_walking = true;
m_walkTimePerPixel = walkTime / 32.0;
m_walkStart = sameWalk ? m_walkStart : g_clock.ticks();
m_walkEnd = m_walkStart + walkTime * walkTimeFactor;
m_turnDirection = m_direction;
updateWalk(); updateWalk();
return;
} }
// Teleport
else { setDirection(direction);
m_walking = false;
m_walkOffset = Point(0, 0); // diagonal walking lasts 3 times more.
m_animation = 0; 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;
m_walking = true;
m_preWalking = preWalk;
m_turnDirection = m_direction;
updateWalk();
} }
void Creature::turn(Otc::Direction direction) void Creature::turn(Otc::Direction direction)
@ -252,7 +245,7 @@ void Creature::updateWalk()
int elapsedTicks = g_clock.ticksElapsed(m_walkStart); int elapsedTicks = g_clock.ticksElapsed(m_walkStart);
int totalPixelsWalked = std::min((int)round(elapsedTicks / m_walkTimePerPixel), 32); int totalPixelsWalked = std::min((int)round(elapsedTicks / m_walkTimePerPixel), 32);
if(m_inverseWalking) { if(!m_preWalking) {
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest) if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
m_walkOffset.y = 32 - totalPixelsWalked; m_walkOffset.y = 32 - totalPixelsWalked;
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest) else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
@ -262,8 +255,7 @@ void Creature::updateWalk()
m_walkOffset.x = totalPixelsWalked - 32; m_walkOffset.x = totalPixelsWalked - 32;
else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest) else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
m_walkOffset.x = 32 - totalPixelsWalked; m_walkOffset.x = 32 - totalPixelsWalked;
} } else {
else {
if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest) if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
m_walkOffset.y = -totalPixelsWalked; m_walkOffset.y = -totalPixelsWalked;
else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest) else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
@ -282,20 +274,26 @@ void Creature::updateWalk()
m_animation = 1 + totalPixelsWalked * 4 / Map::NUM_TILE_PIXELS % (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) if(g_clock.ticks() > m_walkEnd) {
cancelWalk(m_turnDirection); cancelWalk(m_turnDirection);
else } else
g_dispatcher.scheduleEvent(std::bind(&Creature::updateWalk, asCreature()), m_walkTimePerPixel); g_dispatcher.scheduleEvent(std::bind(&Creature::updateWalk, asCreature()), m_walkTimePerPixel);
} }
void Creature::cancelWalk(Otc::Direction direction, bool) void Creature::cancelWalk(Otc::Direction direction, bool force)
{ {
if(force) {
m_walkOffset = Point();
m_preWalking = false;
} else if(!m_preWalking)
m_walkOffset = Point();
m_walking = false; m_walking = false;
m_walkStart = 0;
if(direction != Otc::InvalidDirection)
setDirection(direction);
if(m_outfit.getCategory() == ThingsType::Creature) if(m_outfit.getCategory() == ThingsType::Creature)
m_animation = 0; m_animation = 0;
m_walkOffset = Point(0, 0);
setDirection(direction);
} }
void Creature::setName(const std::string& name) void Creature::setName(const std::string& name)
@ -345,8 +343,7 @@ void Creature::setDirection(Otc::Direction direction)
m_xPattern = Otc::West; m_xPattern = Otc::West;
else else
m_xPattern = direction; m_xPattern = direction;
} } else {
else {
m_xPattern = 0; m_xPattern = 0;
} }
@ -358,7 +355,7 @@ void Creature::setOutfit(const Outfit& outfit)
if(m_outfit.getCategory() != ThingsType::Effect && outfit.getCategory() == ThingsType::Effect) { if(m_outfit.getCategory() != ThingsType::Effect && outfit.getCategory() == ThingsType::Effect) {
auto self = asCreature(); auto self = asCreature();
g_dispatcher.scheduleEvent([self]() { g_dispatcher.scheduleEvent([self]() {
self->updateAnimation(); self->updateInvisibleAnimation();
}, INVISIBLE_TICKS); }, INVISIBLE_TICKS);
m_xPattern = 0; m_xPattern = 0;
@ -433,7 +430,7 @@ void Creature::addVolatileSquare(uint8 color)
}, VOLATILE_SQUARE_DURATION); }, VOLATILE_SQUARE_DURATION);
} }
void Creature::updateAnimation() void Creature::updateInvisibleAnimation()
{ {
if(m_animation == 1) if(m_animation == 1)
m_animation = 2; m_animation = 2;
@ -447,7 +444,7 @@ void Creature::updateAnimation()
if(g_game.isOnline() && m_outfit.getCategory() == ThingsType::Effect) { if(g_game.isOnline() && m_outfit.getCategory() == ThingsType::Effect) {
auto self = asCreature(); auto self = asCreature();
g_dispatcher.scheduleEvent([self]() { g_dispatcher.scheduleEvent([self]() {
self->updateAnimation(); self->updateInvisibleAnimation();
}, INVISIBLE_TICKS); }, INVISIBLE_TICKS);
} }
} }
@ -470,3 +467,4 @@ ThingType *Creature::getType()
{ {
return g_thingsType.getThingType(m_outfit.getId(), m_outfit.getCategory()); return g_thingsType.getThingType(m_outfit.getId(), m_outfit.getCategory());
} }

View File

@ -73,18 +73,19 @@ public:
uint8 getEmblem() { return m_emblem; } uint8 getEmblem() { return m_emblem; }
bool getPassable() { return m_passable; } bool getPassable() { return m_passable; }
void updateAnimation(); void updateInvisibleAnimation();
void updateShield(); void updateShield();
ThingType *getType(); ThingType *getType();
//virtual void walk(const Position& oldPos, const Position& newPos, bool inverse = true); // walk related
virtual void walk(const Position& position, bool inverse = true); void walk(const Position& oldPos, const Position& newPos, bool preWalk = false);
void turn(Otc::Direction direction); void turn(Otc::Direction direction);
virtual void cancelWalk(Otc::Direction direction, bool force = false); void cancelWalk(Otc::Direction direction = Otc::InvalidDirection, bool force = false);
Point getWalkOffset() { return m_walkOffset; } Point getWalkOffset() { return m_walkOffset; }
bool isWalking() { return m_walking; } bool isWalking() { return m_walking; }
bool isPreWalking() { return m_preWalking; }
CreaturePtr asCreature() { return std::static_pointer_cast<Creature>(shared_from_this()); } CreaturePtr asCreature() { return std::static_pointer_cast<Creature>(shared_from_this()); }
@ -109,7 +110,7 @@ protected:
Color m_informationColor; Color m_informationColor;
ticks_t m_walkStart, m_walkEnd; ticks_t m_walkStart, m_walkEnd;
bool m_walking, m_inverseWalking; bool m_walking, m_preWalking;
float m_walkTimePerPixel; float m_walkTimePerPixel;
Point m_walkOffset; Point m_walkOffset;
Otc::Direction m_turnDirection; Otc::Direction m_turnDirection;

View File

@ -140,23 +140,22 @@ void Game::processInventoryChange(int slot, const ItemPtr& item)
void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos) void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos)
{ {
/*
// walk // walk
if(oldPos.isInRange(newPos, 1, 1, 0)) { if(oldPos.isInRange(newPos, 1, 1, 0)) {
Otc::Direction direction = oldPos.getDirectionFromPosition(newPos); creature->walk(oldPos, newPos);
creature->setDirection(direction);
// teleport // teleport
} else { } else {
// stop animation on teleport // stop walking on teleport
if(creature->isWalking()) if(creature->isWalking())
creature->cancelWalk(); creature->cancelWalk();
} }
*/
if(!m_walkFeedback && creature == m_localPlayer) { if(creature == m_localPlayer) {
updateWalkPing(); if(!m_walkFeedback) {
m_walkFeedback = true; updateWalkPing();
m_walkFeedback = true;
}
} }
creature->walk(newPos);
} }
void Game::processAttackCancel() void Game::processAttackCancel()
@ -176,18 +175,23 @@ void Game::processWalkCancel(Otc::Direction direction)
void Game::walk(Otc::Direction direction) void Game::walk(Otc::Direction direction)
{ {
if(m_localPlayer->isFollowing()) { if(!isOnline() || isDead() || !checkBotProtection())
return;
if(m_localPlayer->isFollowing())
cancelFollow(); cancelFollow();
return;
}
if(!isOnline() || isDead() || !checkBotProtection() || !m_localPlayer->canWalk(direction)) if(!m_localPlayer->canWalk(direction))
return; return;
m_localPlayer->clientWalk(direction); m_localPlayer->preWalk(direction);
forceWalk(direction);
}
// ping calculation restarts when the local players try to walk one tile void Game::forceWalk(Otc::Direction direction)
{
m_walkPingTimer.restart(); m_walkPingTimer.restart();
m_walkFeedback = false;
switch(direction) { switch(direction) {
case Otc::North: case Otc::North:
@ -215,8 +219,6 @@ void Game::walk(Otc::Direction direction)
m_protocolGame->sendWalkNorthWest(); m_protocolGame->sendWalkNorthWest();
break; break;
} }
m_walkFeedback = false;
} }
void Game::turn(Otc::Direction direction) void Game::turn(Otc::Direction direction)
@ -334,6 +336,7 @@ void Game::rotate(const ThingPtr& thing)
m_protocolGame->sendRotateItem(thing->getPos(), thing->getId(), stackpos); m_protocolGame->sendRotateItem(thing->getPos(), thing->getId(), stackpos);
} }
//TODO: move this to Thing class
int Game::getThingStackpos(const ThingPtr& thing) int Game::getThingStackpos(const ThingPtr& thing)
{ {
// thing is at map // thing is at map

View File

@ -56,6 +56,7 @@ public:
// walk related // walk related
void walk(Otc::Direction direction); void walk(Otc::Direction direction);
void forceWalk(Otc::Direction direction);
void turn(Otc::Direction direction); void turn(Otc::Direction direction);
// item related // item related

View File

@ -25,79 +25,20 @@
#include "game.h" #include "game.h"
#include "tile.h" #include "tile.h"
LocalPlayer::LocalPlayer() void LocalPlayer::preWalk(Otc::Direction direction)
{ {
m_clientWalking = false; // we're not walking, so start a client walk.
m_nextWalkDirection = Otc::InvalidDirection; Position newPos = m_pos + Position::getPosFromDirection(direction);
} walk(m_pos, newPos, true);
void LocalPlayer::clientWalk(Otc::Direction direction)
{
// We're not walking, so start a client walk.
assert(!m_walking);
Position newPos = m_position + Position::getPosFromDirection(direction);
Creature::walk(newPos, false);
m_clientWalking = true;
}
void LocalPlayer::walk(const Position& position, bool inverse)
{
// This can only be received by protocol, so its always inverse.
// If we're already walking, just finish it.
if(m_clientWalking) {
m_clientWalking = false;
Position pos = Position::getPosFromDirection(m_direction);
Point walkOffset = Point(m_walkOffset.x - pos.x * 32,
m_walkOffset.y - pos.y * 32);
Creature::walk(position, inverse);
// Restore walk offset, because we were already walking.
m_walkOffset = walkOffset;
}
// If we're not client walking, we'll just walk like every NPC. Ie: When player is pushed.
else
Creature::walk(position, inverse);
}
void LocalPlayer::cancelWalk(Otc::Direction direction, bool force)
{
// Server said we cant walk. Ie: houses, vip areas.
if(force) {
m_clientWalking = false;
Creature::cancelWalk(direction);
}
else {
// Walk finished, and we already received the confirmation from server.
if(m_walking && !m_clientWalking) {
m_clientWalking = false;
Creature::cancelWalk(direction);
if(m_nextWalkDirection != Otc::InvalidDirection) {
g_game.walk(m_nextWalkDirection);
m_nextWalkDirection = Otc::InvalidDirection;
}
}
//else..
// Walk finished, however we havent received the confirmation from server. So wait for it.
}
} }
bool LocalPlayer::canWalk(Otc::Direction direction) bool LocalPlayer::canWalk(Otc::Direction direction)
{ {
if(m_walking) { if(m_walking || (m_preWalking && g_clock.ticksElapsed(m_walkEnd) < 1000))
if(direction != m_direction && m_nextWalkDirection != direction)
m_nextWalkDirection = direction;
else if(direction == m_direction && m_nextWalkDirection != Otc::InvalidDirection)
m_nextWalkDirection = Otc::InvalidDirection;
return false; return false;
}
Position newPos = m_position + Position::getPosFromDirection(direction); // check for blockable tiles in the walk direction
TilePtr tile = g_map.getTile(newPos); TilePtr tile = g_map.getTile(m_pos + Position::getPosFromDirection(direction));
if(!tile->isWalkable()) { if(!tile->isWalkable()) {
g_game.processTextMessage("statusSmall", "Sorry, not possible."); g_game.processTextMessage("statusSmall", "Sorry, not possible.");
return false; return false;
@ -108,11 +49,13 @@ bool LocalPlayer::canWalk(Otc::Direction direction)
void LocalPlayer::setAttackingCreature(const CreaturePtr& creature) void LocalPlayer::setAttackingCreature(const CreaturePtr& creature)
{ {
// clear current attacking creature
if(m_attackingCreature) { if(m_attackingCreature) {
m_attackingCreature->hideStaticSquare(); m_attackingCreature->hideStaticSquare();
m_attackingCreature = nullptr; m_attackingCreature = nullptr;
} }
// set the new attacking creature
if(creature) { if(creature) {
creature->showStaticSquare(Fw::red); creature->showStaticSquare(Fw::red);
m_attackingCreature = creature; m_attackingCreature = creature;
@ -121,11 +64,13 @@ void LocalPlayer::setAttackingCreature(const CreaturePtr& creature)
void LocalPlayer::setFollowingCreature(const CreaturePtr& creature) void LocalPlayer::setFollowingCreature(const CreaturePtr& creature)
{ {
// clear current following creature
if(m_followingCreature) { if(m_followingCreature) {
m_followingCreature->hideStaticSquare(); m_followingCreature->hideStaticSquare();
m_followingCreature = nullptr; m_followingCreature = nullptr;
} }
// set the new attacking creature
if(creature) { if(creature) {
creature->showStaticSquare(Fw::green); creature->showStaticSquare(Fw::green);
m_followingCreature = creature; m_followingCreature = creature;

View File

@ -28,8 +28,6 @@
class LocalPlayer : public Player class LocalPlayer : public Player
{ {
public: public:
LocalPlayer();
void setCanReportBugs(uint8 canReportBugs) { m_canReportBugs = (canReportBugs != 0); } void setCanReportBugs(uint8 canReportBugs) { m_canReportBugs = (canReportBugs != 0); }
void setSkill(Otc::Skill skill, Otc::SkillType skillType, int value) { m_skills[skill][skillType] = value; } 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 setStatistic(Otc::Statistic statistic, double value) { m_statistics[statistic] = value; }
@ -42,25 +40,21 @@ public:
double getStatistic(Otc::Statistic statistic) { return m_statistics[statistic]; } double getStatistic(Otc::Statistic statistic) { return m_statistics[statistic]; }
CreaturePtr getAttackingCreature() { return m_attackingCreature; } CreaturePtr getAttackingCreature() { return m_attackingCreature; }
CreaturePtr getFollowingCreature() { return m_followingCreature; } CreaturePtr getFollowingCreature() { return m_followingCreature; }
Otc::Direction getNextWalkDirection() { return m_nextWalkDirection; }
Otc::PlayerIcons getIcons() { return m_icons; } Otc::PlayerIcons getIcons() { return m_icons; }
bool isAttacking() { return m_attackingCreature != nullptr; } bool isAttacking() { return m_attackingCreature != nullptr; }
bool isFollowing() { return m_followingCreature != nullptr; } bool isFollowing() { return m_followingCreature != nullptr; }
void clientWalk(Otc::Direction direction); void preWalk(Otc::Direction direction);
void walk(const Position& position, bool inverse);
void cancelWalk(Otc::Direction direction, bool force = false);
bool canWalk(Otc::Direction direction); bool canWalk(Otc::Direction direction);
LocalPlayerPtr asLocalPlayer() { return std::static_pointer_cast<LocalPlayer>(shared_from_this()); } LocalPlayerPtr asLocalPlayer() { return std::static_pointer_cast<LocalPlayer>(shared_from_this()); }
double getLevel() { return getStatistic(Otc::Level); } double getLevel() { return getStatistic(Otc::Level); }
//TODO: more gets
private: private:
bool m_canReportBugs; bool m_canReportBugs;
bool m_clientWalking;
Otc::Direction m_nextWalkDirection;
CreaturePtr m_attackingCreature, m_followingCreature; CreaturePtr m_attackingCreature, m_followingCreature;
Otc::PlayerIcons m_icons; Otc::PlayerIcons m_icons;
int m_skills[Otc::LastSkill][Otc::LastSkillType]; int m_skills[Otc::LastSkill][Otc::LastSkillType];

View File

@ -35,7 +35,7 @@ Missile::Missile() : Thing()
void Missile::draw(const Point& p, const Rect&) void Missile::draw(const Point& p, const Rect&)
{ {
float time = (g_clock.ticks() - m_startTicks) / m_duration; float time = (g_clock.ticks() - m_startTicks) / m_duration;
internalDraw(p + Point(m_positionDelta.x * time, m_positionDelta.y * time), 0); internalDraw(p + Point(m_posDelta.x * time, m_posDelta.y * time), 0);
} }
void Missile::setPath(const Position& fromPosition, const Position& toPosition) void Missile::setPath(const Position& fromPosition, const Position& toPosition)
@ -79,12 +79,12 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition)
m_yPattern = 1; m_yPattern = 1;
} }
m_position = fromPosition; m_pos = fromPosition;
m_positionDelta = toPosition - fromPosition; m_posDelta = toPosition - fromPosition;
m_startTicks = g_clock.ticks(); m_startTicks = g_clock.ticks();
m_duration = 150 * std::sqrt(Point(m_positionDelta.x, m_positionDelta.y).length()); m_duration = 150 * std::sqrt(Point(m_posDelta.x, m_posDelta.y).length());
m_positionDelta.x *= Map::NUM_TILE_PIXELS; m_posDelta.x *= Map::NUM_TILE_PIXELS;
m_positionDelta.y *= Map::NUM_TILE_PIXELS; m_posDelta.y *= Map::NUM_TILE_PIXELS;
// schedule removal // schedule removal
auto self = asMissile(); auto self = asMissile();

View File

@ -47,7 +47,7 @@ public:
private: private:
ticks_t m_startTicks; ticks_t m_startTicks;
Position m_positionDelta; Position m_posDelta;
float m_duration; float m_duration;
}; };

View File

@ -44,13 +44,14 @@ public:
virtual void draw(const Point& p, const Rect&) = 0; virtual void draw(const Point& p, const Rect&) = 0;
void setId(uint32 id); void setId(uint32 id);
virtual void setPos(const Position& position) { m_position = position; } virtual void setPos(const Position& position) { m_pos = position; }
uint32 getId() const { return m_id; } uint32 getId() const { return m_id; }
Position getPos() const { return m_position; } Position getPos() const { return m_pos; }
int getStackPriority(); int getStackPriority();
virtual ThingType *getType(); virtual ThingType *getType();
int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; } int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; }
int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; }
void setXPattern(int xPattern) { m_xPattern = xPattern; } void setXPattern(int xPattern) { m_xPattern = xPattern; }
void setYPattern(int yPattern) { m_yPattern = yPattern; } void setYPattern(int yPattern) { m_yPattern = yPattern; }
@ -87,7 +88,7 @@ protected:
void internalDraw(const Point& p, int layer); void internalDraw(const Point& p, int layer);
uint32 m_id; uint32 m_id;
Position m_position; Position m_pos;
ThingType *m_type; ThingType *m_type;
int m_xPattern, m_yPattern, m_zPattern, m_animation; int m_xPattern, m_yPattern, m_zPattern, m_animation;

View File

@ -33,7 +33,7 @@
Tile::Tile(const Position& position) Tile::Tile(const Position& position)
{ {
m_drawElevation = 0; m_drawElevation = 0;
m_position = position; m_pos = position;
} }
void Tile::draw(const Point& p, const Rect& visibleRect) void Tile::draw(const Point& p, const Rect& visibleRect)
@ -67,7 +67,7 @@ void Tile::draw(const Point& p, const Rect& visibleRect)
//TODO: this algorithm is slowing down render too much, but it could be cached to improve framerate //TODO: this algorithm is slowing down render too much, but it could be cached to improve framerate
for(int xi = -1; xi <= 1; ++xi) { for(int xi = -1; xi <= 1; ++xi) {
for(int yi = -1; yi <= 1; ++yi) { for(int yi = -1; yi <= 1; ++yi) {
for(CreaturePtr creature : g_map.getTile(m_position + Position(xi, yi, 0))->getCreatures()) { for(CreaturePtr creature : g_map.getTile(m_pos + Position(xi, yi, 0))->getCreatures()) {
ThingType *type = creature->getType(); ThingType *type = creature->getType();
Rect creatureRect(p.x + xi*32 + creature->getWalkOffset().x - type->parameters[ThingType::DisplacementX], p.y + yi*32 + creature->getWalkOffset().y - type->parameters[ThingType::DisplacementY], 32, 32); Rect creatureRect(p.x + xi*32 + creature->getWalkOffset().x - type->parameters[ThingType::DisplacementX], p.y + yi*32 + creature->getWalkOffset().y - type->parameters[ThingType::DisplacementY], 32, 32);
Rect thisTileRect(p.x, p.y, 32, 32); Rect thisTileRect(p.x, p.y, 32, 32);
@ -197,6 +197,14 @@ ItemPtr Tile::getGround()
return nullptr; return nullptr;
} }
int Tile::getGroundSpeed()
{
int groundSpeed = 100;
if(ItemPtr ground = getGround())
groundSpeed = ground->getGroundSpeed();
return groundSpeed;
}
ThingPtr Tile::getTopLookThing() ThingPtr Tile::getTopLookThing()
{ {
if(isEmpty()) if(isEmpty())

View File

@ -50,10 +50,11 @@ public:
CreaturePtr getTopCreature(); CreaturePtr getTopCreature();
ThingPtr getTopMultiUseThing(); ThingPtr getTopMultiUseThing();
const Position& getPos() { return m_position; } const Position& getPos() { return m_pos; }
int getDrawElevation() { return m_drawElevation; } int getDrawElevation() { return m_drawElevation; }
std::vector<CreaturePtr> getCreatures(); std::vector<CreaturePtr> getCreatures();
ItemPtr getGround(); ItemPtr getGround();
int getGroundSpeed();
bool isWalkable(); bool isWalkable();
bool isFullGround(); bool isFullGround();
bool isFullyOpaque(); bool isFullyOpaque();
@ -67,7 +68,7 @@ public:
private: private:
std::vector<EffectPtr> m_effects; // Leave this outside m_things because it has no stackpos. std::vector<EffectPtr> m_effects; // Leave this outside m_things because it has no stackpos.
std::vector<ThingPtr> m_things; std::vector<ThingPtr> m_things;
Position m_position; Position m_pos;
int m_drawElevation; int m_drawElevation;
}; };

View File

@ -186,6 +186,8 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassStaticFunction<Game>("open", std::bind(&Game::open, &g_game, _1, _2)); g_lua.bindClassStaticFunction<Game>("open", std::bind(&Game::open, &g_game, _1, _2));
g_lua.bindClassStaticFunction<Game>("use", std::bind(&Game::use, &g_game, _1)); g_lua.bindClassStaticFunction<Game>("use", std::bind(&Game::use, &g_game, _1));
g_lua.bindClassStaticFunction<Game>("useWith", std::bind(&Game::useWith, &g_game, _1, _2)); g_lua.bindClassStaticFunction<Game>("useWith", std::bind(&Game::useWith, &g_game, _1, _2));
g_lua.bindClassStaticFunction<Game>("walk", std::bind(&Game::walk, &g_game, _1));
g_lua.bindClassStaticFunction<Game>("forceWalk", std::bind(&Game::forceWalk, &g_game, _1));
g_lua.bindClassStaticFunction<Game>("attack", std::bind(&Game::attack, &g_game, _1)); g_lua.bindClassStaticFunction<Game>("attack", std::bind(&Game::attack, &g_game, _1));
g_lua.bindClassStaticFunction<Game>("cancelAttack", std::bind(&Game::cancelAttack, &g_game)); g_lua.bindClassStaticFunction<Game>("cancelAttack", std::bind(&Game::cancelAttack, &g_game));
g_lua.bindClassStaticFunction<Game>("follow", std::bind(&Game::follow, &g_game, _1)); g_lua.bindClassStaticFunction<Game>("follow", std::bind(&Game::follow, &g_game, _1));

View File

@ -419,13 +419,11 @@ void ProtocolGame::parseCreatureMove(InputMessage& msg)
return; return;
} }
g_game.processCreatureMove(creature, oldPos, newPos);
// update map tiles // update map tiles
g_map.removeThing(thing); g_map.removeThing(thing);
g_map.addThing(thing, newPos); g_map.addThing(thing, newPos);
//g_game.processCreatureMove(creature, oldPos, newPos); g_game.processCreatureMove(creature, oldPos, newPos);
} }
void ProtocolGame::parseOpenContainer(InputMessage& msg) void ProtocolGame::parseOpenContainer(InputMessage& msg)

View File

@ -25,9 +25,9 @@
#include <framework/ui/uilineedit.h> #include <framework/ui/uilineedit.h>
#include <framework/platform/platformwindow.h> #include <framework/platform/platformwindow.h>
bool UIGame::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers) bool UIGame::onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter)
{ {
if(UIWidget::onKeyPress(keyCode, keyText, keyboardModifiers)) if(UIWidget::onKeyPress(keyCode, keyboardModifiers, wouldFilter))
return true; return true;
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("consoleLineEdit")); UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("consoleLineEdit"));
@ -106,10 +106,15 @@ bool UIGame::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifier
} }
} }
if(!keyText.empty() && (keyboardModifiers == Fw::KeyboardNoModifier || keyboardModifiers == Fw::KeyboardShiftModifier)) {
chatLineEdit->appendText(keyText);
return true;
}
return false; return false;
} }
bool UIGame::onKeyText(const std::string& keyText)
{
if(UIWidget::onKeyText(keyText))
return true;
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("consoleLineEdit"));
chatLineEdit->appendText(keyText);
return true;
}

View File

@ -29,8 +29,8 @@
class UIGame : public UIWidget class UIGame : public UIWidget
{ {
protected: protected:
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers); bool onKeyPress(uchar keyCode, int keyboardModifiers, bool wouldFilter);
bool onKeyText(const std::string& keyText);
}; };
#endif #endif

View File

@ -109,7 +109,7 @@ public:
bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; } bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }
bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; } bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; }
bool isInRange(const Position& pos, int xdif, int ydif, int zdif = 1) { bool isInRange(const Position& pos, int xdif, int ydif, int zdif = 1) const {
return std::abs(x-pos.x) <= xdif && std::abs(y-pos.y) <= ydif && std::abs(pos.z-z) <= zdif; return std::abs(x-pos.x) <= xdif && std::abs(y-pos.y) <= ydif && std::abs(pos.z-z) <= zdif;
} }