diff --git a/modules/client_options/control.otui b/modules/client_options/control.otui index c789a1f51f..9d01a8e841 100644 --- a/modules/client_options/control.otui +++ b/modules/client_options/control.otui @@ -43,19 +43,6 @@ Panel !text: tr('Enable smart walking') !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: preciseControl - !text: tr('Enable precise control') - !tooltip: tr('You will have more precision over the character walking,\nbut it can feel more abrupt or unnatural') - @onCheckChange: g_game.setScheduleLastWalk(not self:isChecked()) - SmallReversedQtPanel anchors.left: parent.left anchors.right: parent.right diff --git a/modules/client_options/data_options.lua b/modules/client_options/data_options.lua index f2c7c8ff8d..d1f5e4f36a 100644 --- a/modules/client_options/data_options.lua +++ b/modules/client_options/data_options.lua @@ -25,12 +25,6 @@ return { }, classicControl = false, smartWalk = false, - preciseControl = { - value = false, - action = function(value, options, controller, panels, extraWidgets) - g_game.setScheduleLastWalk(not value) - end - }, autoChaseOverride = true, moveStack = false, showStatusMessagesInConsole = true, diff --git a/modules/client_options/styles/controls/general.otui b/modules/client_options/styles/controls/general.otui index 15fa6d23c0..0622def3c3 100644 --- a/modules/client_options/styles/controls/general.otui +++ b/modules/client_options/styles/controls/general.otui @@ -56,19 +56,6 @@ UIWidget !text: tr('Enable smart walking') !tooltip: tr('Will detect when to use diagonal step based on the\nkeys you are pressing') - SmallReversedQtPanel - anchors.left: parent.left - anchors.right: parent.right - anchors.top: prev.bottom - margin-top: 7 - height: 22 - - OptionCheckBoxMarked - id: preciseControl - !text: tr('Enable precise control') - !tooltip: tr('You will have more precision over the character walking,\nbut it can feel more abrupt or unnatural') - @onCheckChange: g_game.setScheduleLastWalk(not self:isChecked()) - SmallReversedQtPanel anchors.left: parent.left anchors.right: parent.right diff --git a/modules/game_interface/gameinterface.lua b/modules/game_interface/gameinterface.lua index cfb69c4201..7e480ff2b7 100644 --- a/modules/game_interface/gameinterface.lua +++ b/modules/game_interface/gameinterface.lua @@ -25,14 +25,12 @@ limitedZoom = false currentViewMode = 0 smartWalkDirs = {} smartWalkDir = nil -firstStep = false leftIncreaseSidePanels = nil leftDecreaseSidePanels = nil rightIncreaseSidePanels = nil rightDecreaseSidePanels = nil hookedMenuOptions = {} lastDirTime = g_clock.millis() -lastManualWalk = 0 function init() g_ui.importStyle('styles/countwindow') @@ -132,7 +130,7 @@ function init() end function bindKeys() - gameRootPanel:setAutoRepeatDelay(200) + gameRootPanel:setAutoRepeatDelay(50) bindWalkKey('Up', North) bindWalkKey('Right', East) @@ -184,6 +182,7 @@ function bindWalkKey(key, dir) onWalkKeyDown(dir) end, gameRootPanel, true) g_keyboard.bindKeyUp(key, function() + g_game.getLocalPlayer():setNextWalkDir(Directions.Invalid) changeWalkDir(dir, true) end, gameRootPanel, true) g_keyboard.bindKeyPress(key, function() @@ -455,7 +454,6 @@ function onWalkKeyDown(dir) g_game.setChaseMode(DontChase) end end - firstStep = true changeWalkDir(dir) end @@ -496,10 +494,13 @@ function smartWalk(dir) return false end + local dire = smartWalkDir or dir - g_game.walk(dire, firstStep) - firstStep = false - lastManualWalk = g_clock.millis() + + g_game.getLocalPlayer():setNextWalkDir(dire) + + g_game.walk(dire) + return true end diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index ffeec9cbcf..73c15dedbb 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -41,7 +41,8 @@ Directions = { NorthEast = 4, SouthEast = 5, SouthWest = 6, - NorthWest = 7 + NorthWest = 7, + Invalid = 8 } Skill = { @@ -197,7 +198,7 @@ GameContainerFilter = 113 GameEnterGameShowAppearance = 114 GameSmoothWalkElevation = 115 GameNegativeOffset = 116 -GameItemTooltipV8 = 117 +GameItemTooltipV8 = 117 GameWingsAurasEffectsShader = 118 GameForgeConvergence = 119 GameAllowCustomBotScripts = 120 diff --git a/src/client/creature.cpp b/src/client/creature.cpp index 380c8ab79e..c40cdba319 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -389,6 +389,7 @@ void Creature::walk(const Position& oldPos, const Position& newPos) // starts counting walk m_walking = true; + m_walkSteps = std::max(++m_walkSteps, 1); m_walkTimer.restart(); m_walkedPixels = 0; @@ -644,12 +645,12 @@ void Creature::nextWalkUpdate() if (!m_walking) return; - // schedules next update - auto self = static_self_cast(); - m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] { + auto action = [self = static_self_cast()] { self->m_walkUpdateEvent = nullptr; self->nextWalkUpdate(); - }, m_stepCache.walkDuration); + }; + + m_walkUpdateEvent = isLocalPlayer() ? g_dispatcher.addEvent(action) : g_dispatcher.scheduleEvent(action, m_stepCache.walkDuration); } void Creature::updateWalk(const bool isPreWalking) @@ -666,7 +667,7 @@ void Creature::updateWalk(const bool isPreWalking) updateWalkingTile(); if (m_walkedPixels == g_gameConfig.getSpriteSize()) { - if (isPreWalking) resetWalkAnimationPhase(true); + if (isPreWalking) resetWalkAnimationPhase(false); else terminateWalk(); } } @@ -694,6 +695,15 @@ void Creature::terminateWalk() m_walkOffset = {}; m_walking = false; + if (isLocalPlayer() && !static_self_cast()->isAutoWalking() && getWalkSteps() > 1) { + g_dispatcher.addEvent([] { + g_dispatcher.deferEvent([] { + if (g_game.getLocalPlayer()) + g_game.walk(g_game.getLocalPlayer()->getNextWalkDir()); + }); + }); + } + resetWalkAnimationPhase(true); } @@ -705,6 +715,7 @@ void Creature::resetWalkAnimationPhase(bool toSchedule) { const auto self = static_self_cast(); m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] { + self->m_walkSteps = 0; self->m_walkAnimationPhase = 0; self->m_walkFinishAnimEvent = nullptr; }, g_game.getServerBeat()); @@ -944,7 +955,11 @@ uint16_t Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir) stepDuration = ((stepDuration + serverBeat - 1) / serverBeat) * serverBeat; } - m_stepCache.duration = stepDuration + 10; + if (isLocalPlayer() && stepDuration <= 100) + stepDuration += 10; + + m_stepCache.duration = stepDuration; + m_stepCache.walkDuration = std::min(stepDuration / g_gameConfig.getSpriteSize(), DrawPool::FPS60); m_stepCache.diagonalDuration = stepDuration * (g_game.getClientVersion() > 810 || g_gameConfig.isForcingNewWalkingFormula() diff --git a/src/client/creature.h b/src/client/creature.h index 6cdc4cc129..f52e8af5b3 100644 --- a/src/client/creature.h +++ b/src/client/creature.h @@ -94,6 +94,8 @@ class Creature : public Thing void hideStaticSquare() { m_showStaticSquare = false; } // walk related + int getWalkSteps() const { return m_walkSteps; } + void setWalkSteps(uint8_t step) { m_walkSteps = step; } void turn(Otc::Direction direction); void jump(int height, int duration); void allowAppearWalk() { m_allowAppearWalk = true; } @@ -148,6 +150,7 @@ class Creature : public Thing bool isPassable() const { return m_passable; } bool isWalking() { return m_walking; } + bool isRemoved() { return m_removed; } bool isInvisible() { return m_outfit.isEffect() && m_outfit.getAuxId() == 13; } bool isDead() { return m_healthPercent <= 0; } @@ -194,6 +197,7 @@ class Creature : public Thing void onPositionChange(const Position& newPos, const Position& oldPos) override; bool m_walking{ false }; + Point m_walkOffset; Otc::Direction m_direction{ Otc::South }; @@ -232,7 +236,7 @@ class Creature : public Thing TexturePtr m_iconTexture; TexturePtr m_typingIconTexture; - ScheduledEventPtr m_walkUpdateEvent; + EventPtr m_walkUpdateEvent; ScheduledEventPtr m_walkFinishAnimEvent; ScheduledEventPtr m_outfitColorUpdateEvent; @@ -291,6 +295,8 @@ class Creature : public Thing uint8_t m_disableWalkAnimation{ 0 }; + uint8_t m_walkSteps{ 0 }; + // Mount Shader uint8_t m_mountShaderId{ 0 }; diff --git a/src/client/game.cpp b/src/client/game.cpp index 9897e2993d..7528ca10fd 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -34,6 +34,10 @@ #include "tile.h" #include "framework/core/graphicalapplication.h" + // create an option in the ui to configure the delay of the first step. +constexpr auto firstStepDelay = 200; +constexpr auto turnDelay = 0; + Game g_game; void Game::init() @@ -66,7 +70,6 @@ void Game::resetGameStates() m_pingSent = 0; m_pingReceived = 0; m_unjustifiedPoints = UnjustifiedPoints(); - m_nextScheduledDir = Otc::InvalidDirection; for (const auto& it : m_containers) { const auto& container = it.second; @@ -79,11 +82,6 @@ void Game::resetGameStates() m_pingEvent = nullptr; } - if (m_walkEvent) { - m_walkEvent->cancel(); - m_walkEvent = nullptr; - } - if (m_checkConnectionEvent) { m_checkConnectionEvent->cancel(); m_checkConnectionEvent = nullptr; @@ -506,7 +504,7 @@ void Game::processBestiaryRaces(const std::vector& besti g_lua.callGlobalField("g_game", "onParseBestiaryRaces", bestiaryRaces); } -void Game::processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills, +void Game::processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills, const std::vector>& combats) { g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterGeneralStats", stats, skills, combats); @@ -519,7 +517,7 @@ void Game::processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombat g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterCombatStats", data, mitigation, additionalSkillsArray, forgeSkillsArray, perfectShotDamageRangesArray, combatsArray, concoctionsArray); } -void Game::processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium, +void Game::processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium, const std::string_view loyaltyTitle, const std::vector>& badgesVector) { g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterBadges", showAccountInformation, playerOnline, playerPremium, loyaltyTitle, badgesVector); @@ -530,7 +528,7 @@ void Game::processCyclopediaCharacterItemSummary(const CyclopediaCharacterItemSu g_lua.callGlobalField("g_game", "onUpdateCyclopediaCharacterItemSummary", data); } -void Game::processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits, +void Game::processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits, const std::vector& mounts, std::vector& familiars) { g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterAppearances", currentOutfit, outfits, mounts, familiars); @@ -636,44 +634,34 @@ void Game::safeLogout() m_protocolGame->sendLogout(); } -bool Game::walk(const Otc::Direction direction, const bool isKeyDown /*= false*/) +bool Game::walk(const Otc::Direction direction) { - if (!canPerformGameAction()) + if (!canPerformGameAction() || direction == Otc::InvalidDirection) return false; + if (m_localPlayer->getWalkSteps() == 1) { + const auto delay = std::max(direction != m_localPlayer->getDirection() ? turnDelay : firstStepDelay, 50); + g_dispatcher.scheduleEvent([this] { + if (m_localPlayer && m_localPlayer->getNextWalkDir() != Otc::InvalidDirection) { + m_localPlayer->setWalkSteps(2); + walk(m_localPlayer->getNextWalkDir()); + } + }, delay); + return false; + } + // must cancel auto walking, and wait next try if (m_localPlayer->isAutoWalking()) { m_protocolGame->sendStop(); - m_localPlayer->autoWalk(m_localPlayer->getPosition().translatedToDirection(direction)); + m_localPlayer->stopAutoWalk(); return false; } // check we can walk and add new walk event if false if (!m_localPlayer->canWalk()) { - if (m_nextScheduledDir != direction) { - const float ticks = std::clamp(m_localPlayer->getStepTicksLeft(), 1, 2000); - if (isKeyDown || (m_scheduleLastWalk && ticks < std::min(m_localPlayer->getStepDuration() / 3, 250))) { - // must add a new walk event - if (m_walkEvent) { - m_walkEvent->cancel(); - m_walkEvent = nullptr; - } - - m_walkEvent = g_dispatcher.scheduleEvent([this, direction] { walk(direction); }, ticks); - m_nextScheduledDir = direction; - } - } return false; } - m_nextScheduledDir = Otc::InvalidDirection; - - // if it's going to walk, but there is another scheduled event, cancel it - if (m_walkEvent && !m_walkEvent->isExecuted()) { - m_walkEvent->cancel(); - m_walkEvent = nullptr; - } - const auto& toPos = m_localPlayer->getPosition().translatedToDirection(direction); // only do prewalks to walkable tiles (like grounds and not walls) @@ -719,8 +707,6 @@ bool Game::walk(const Otc::Direction direction, const bool isKeyDown /*= false*/ forceWalk(direction); - m_lastWalkDir = direction; - return true; } @@ -744,7 +730,6 @@ void Game::autoWalk(const std::vector& dirs, const Position& sta } const Otc::Direction direction = *dirs.begin(); - if (const auto& toTile = g_map.getTile(startPos.translatedToDirection(direction))) { if (startPos == m_localPlayer->m_lastPrewalkDestination && toTile->isWalkable() && m_localPlayer->canWalk(true)) { m_localPlayer->preWalk(direction); @@ -752,7 +737,6 @@ void Game::autoWalk(const std::vector& dirs, const Position& sta } g_lua.callGlobalField("g_game", "onAutoWalk", dirs); - m_protocolGame->sendAutoWalk(dirs); } @@ -1042,13 +1026,6 @@ void Game::cancelAttackAndFollow() if (isAttacking()) setAttackingCreature(nullptr); - if (m_walkEvent) { - m_walkEvent->cancel(); - m_walkEvent = nullptr; - } - - m_nextScheduledDir = Otc::InvalidDirection; - m_localPlayer->stopAutoWalk(); m_protocolGame->sendCancelAttackAndFollow(); @@ -1889,7 +1866,7 @@ void Game::inspectionObject(const Otc::InspectObjectTypes inspectionType, const if (!canPerformGameAction()) return; - m_protocolGame->sendInspectionObject(inspectionType , itemId, itemCount); + m_protocolGame->sendInspectionObject(inspectionType, itemId, itemCount); } void Game::requestBestiary() @@ -1954,7 +1931,6 @@ void Game::requestBossSlotAction(const uint8_t action, const uint32_t raceId) return; m_protocolGame->sendRequestBossSlotAction(action, raceId); - } void Game::sendStatusTrackerBestiary(const uint16_t raceId, const bool status) @@ -1962,4 +1938,4 @@ void Game::sendStatusTrackerBestiary(const uint16_t raceId, const bool status) enableBotCall(); m_protocolGame->sendStatusTrackerBestiary(raceId, status); disableBotCall(); -} +} \ No newline at end of file diff --git a/src/client/game.h b/src/client/game.h index 745ee2e356..751b4bedbf 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -508,18 +508,18 @@ class Game // cyclopedia static void processItemDetail(const uint32_t itemId, const std::vector>& descriptions); static void processBestiaryRaces(const std::vector& bestiaryRaces); - static void processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills, + static void processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills, const std::vector>& combats); - static void processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombatStats& data, const double mitigation, + static void processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombatStats& data, const double mitigation, const std::vector>& additionalSkillsArray, const std::vector>& forgeSkillsArray, const std::vector& perfectShotDamageRangesArray, - const std::vector>& combatsArray, + const std::vector>& combatsArray, const std::vector>& concoctionsArray); - static void processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium, + static void processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium, const std::string_view loyaltyTitle, const std::vector>& badgesVector); static void processCyclopediaCharacterItemSummary(const CyclopediaCharacterItemSummary& data); - static void processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits, + static void processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits, const std::vector& mounts, std::vector& familiars); static void processCyclopediaCharacterRecentDeaths(const CyclopediaCharacterRecentDeaths& data); static void processCyclopediaCharacterRecentPvpKills(const CyclopediaCharacterRecentPvPKills& data); @@ -541,12 +541,11 @@ class Game void safeLogout(); // walk related - bool walk(const Otc::Direction direction, const bool isKeyDown = false); + bool walk(const Otc::Direction direction); void autoWalk(const std::vector& dirs, const Position& startPos); void forceWalk(const Otc::Direction direction); void turn(const Otc::Direction direction); void stop(); - void setScheduleLastWalk(const bool scheduleLastWalk) { m_scheduleLastWalk = scheduleLastWalk; } // item related void look(const ThingPtr& thing, const bool isBattleList = false); @@ -606,7 +605,7 @@ class Game void addVip(const std::string_view name); void removeVip(const uint32_t playerId); void editVip(const uint32_t playerId, const std::string_view description, const uint32_t iconId, const bool notifyLogin, const std::vector& groupID = {}); - void editVipGroups(const Otc::GroupsEditInfoType_t action,const uint8_t groupId, const std::string_view groupName); + void editVipGroups(const Otc::GroupsEditInfoType_t action, const uint8_t groupId, const std::string_view groupName); // fight modes related void setChaseMode(const Otc::ChaseModes chaseMode); void setFightMode(const Otc::FightModes fightMode); @@ -734,7 +733,6 @@ class Game std::string getWorldName() { return m_worldName; } std::vector getGMActions() { return m_gmActions; } bool isGM() { return !m_gmActions.empty(); } - Otc::Direction getLastWalkDir() { return m_lastWalkDir; } std::string formatCreatureName(const std::string_view name); int findEmptyContainerId(); @@ -802,12 +800,9 @@ class Game Otc::FightModes m_fightMode{ Otc::FightBalanced }; Otc::ChaseModes m_chaseMode{ Otc::DontChase }; Otc::PVPModes m_pvpMode{ Otc::WhiteDove }; - Otc::Direction m_lastWalkDir; - Otc::Direction m_nextScheduledDir; Otc::OperatingSystem_t m_clientCustomOs{ Otc::CLIENTOS_NONE }; UnjustifiedPoints m_unjustifiedPoints; ScheduledEventPtr m_pingEvent; - ScheduledEventPtr m_walkEvent; ScheduledEventPtr m_checkConnectionEvent; bool m_tileThingsLuaCallback{ false }; diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index 420aef8b02..22646267fa 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -41,7 +41,7 @@ bool LocalPlayer::canWalk(bool ignoreLock) if (isWalkLocked() && !ignoreLock) return false; - return m_walkTimer.ticksElapsed() >= (getStepDuration() - 9); + return m_walkTimer.ticksElapsed() >= getStepDuration(); } void LocalPlayer::walk(const Position& oldPos, const Position& newPos) diff --git a/src/client/localplayer.h b/src/client/localplayer.h index 0dd4488656..f68240eec1 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -59,11 +59,14 @@ class LocalPlayer : public Player void setSpells(const std::vector& spells); void setBlessings(uint16_t blessings); void setResourceBalance(Otc::ResourceTypes_t type, uint64_t value); + void setNextWalkDir(Otc::Direction dir) { m_nextWalkDir = dir; } void takeScreenshot(uint8_t type); uint32_t getFreeCapacity() { return m_freeCapacity; } uint32_t getTotalCapacity() { return m_totalCapacity; } + auto getNextWalkDir() { return m_nextWalkDir; } + uint8_t getVocation() { return m_vocation; } uint8_t getMagicLevel() { return m_magicLevel; } uint8_t getMagicLevelPercent() { return m_magicLevelPercent; } @@ -182,4 +185,6 @@ class LocalPlayer : public Player uint16_t m_stamina{ 0 }; uint16_t m_regenerationTime{ 0 }; uint16_t m_offlineTrainingTime{ 0 }; + + Otc::Direction m_nextWalkDir{ Otc::InvalidDirection }; }; diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index 6f776ebc48..36b4207a70 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -225,7 +225,6 @@ void Client::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "forceLogout", &Game::forceLogout, &g_game); g_lua.bindSingletonFunction("g_game", "safeLogout", &Game::safeLogout, &g_game); g_lua.bindSingletonFunction("g_game", "walk", &Game::walk, &g_game); - g_lua.bindSingletonFunction("g_game", "setScheduleLastWalk", &Game::setScheduleLastWalk, &g_game); g_lua.bindSingletonFunction("g_game", "autoWalk", &Game::autoWalk, &g_game); g_lua.bindSingletonFunction("g_game", "forceWalk", &Game::forceWalk, &g_game); g_lua.bindSingletonFunction("g_game", "turn", &Game::turn, &g_game); @@ -339,7 +338,6 @@ void Client::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "answerModalDialog", &Game::answerModalDialog, &g_game); g_lua.bindSingletonFunction("g_game", "browseField", &Game::browseField, &g_game); g_lua.bindSingletonFunction("g_game", "seekInContainer", &Game::seekInContainer, &g_game); - g_lua.bindSingletonFunction("g_game", "getLastWalkDir", &Game::getLastWalkDir, &g_game); g_lua.bindSingletonFunction("g_game", "buyStoreOffer", &Game::buyStoreOffer, &g_game); g_lua.bindSingletonFunction("g_game", "requestTransactionHistory", &Game::requestTransactionHistory, &g_game); g_lua.bindSingletonFunction("g_game", "requestStoreOffers", &Game::requestStoreOffers, &g_game); @@ -849,6 +847,8 @@ void Client::registerLuaFunctions() g_lua.bindClassMemberFunction("getResourceBalance", &LocalPlayer::getResourceBalance); g_lua.bindClassMemberFunction("setResourceBalance", &LocalPlayer::setResourceBalance); g_lua.bindClassMemberFunction("getTotalMoney", &LocalPlayer::getTotalMoney); + g_lua.bindClassMemberFunction("setNextWalkDir", &LocalPlayer::setNextWalkDir); + g_lua.bindClassMemberFunction("getNextWalkDir", &LocalPlayer::getNextWalkDir); g_lua.registerClass(); g_lua.bindClassMemberFunction("clean", &Tile::clean);