Auto walker update must be done from C++ not lua due to bot protection.

* Moved the auto walk checker to the source.
* Implemented a temporary fix for findPath method (will now choose other tiles over null tiles).
This commit is contained in:
BeniS 2013-01-09 04:32:37 +13:00
parent 493202afcf
commit a1a8d28f5c
11 changed files with 84 additions and 105 deletions

View File

@ -31,15 +31,9 @@ function init()
connect(g_game, { connect(g_game, {
onGameStart = show, onGameStart = show,
onGameEnd = hide, onGameEnd = hide,
onLoginAdvice = onLoginAdvice, onLoginAdvice = onLoginAdvice
onWalk = onWalk
}, true) }, true)
connect(LocalPlayer, {
onCancelWalk = onCancelWalk,
onPositionChange = onPositionChange
})
gameRootPanel = g_ui.displayUI('gameinterface.otui') gameRootPanel = g_ui.displayUI('gameinterface.otui')
gameRootPanel:hide() gameRootPanel:hide()
gameRootPanel:lower() gameRootPanel:lower()
@ -92,13 +86,12 @@ function bindKeys()
g_keyboard.bindKeyPress('Ctrl+Numpad6', function() g_game.turn(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY) g_keyboard.bindKeyPress('Ctrl+Numpad6', function() g_game.turn(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
g_keyboard.bindKeyPress('Ctrl+Numpad2', function() g_game.turn(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY) g_keyboard.bindKeyPress('Ctrl+Numpad2', function() g_game.turn(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
g_keyboard.bindKeyPress('Ctrl+Numpad4', function() g_game.turn(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY) g_keyboard.bindKeyPress('Ctrl+Numpad4', function() g_game.turn(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
g_keyboard.bindKeyPress('Escape', function() cancelAutoWalkCheck() g_game.cancelAttackAndFollow() end, gameRootPanel, WALK_AUTO_REPEAT_DELAY) g_keyboard.bindKeyPress('Escape', function() g_game.cancelAttackAndFollow() end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
g_keyboard.bindKeyPress('Ctrl+=', function() gameMapPanel:zoomIn() end, gameRootPanel, 250) g_keyboard.bindKeyPress('Ctrl+=', function() gameMapPanel:zoomIn() end, gameRootPanel, 250)
g_keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel, 250) g_keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel, 250)
g_keyboard.bindKeyDown('Ctrl+Q', logout, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+Q', logout, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+L', logout, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+L', logout, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+W', function() g_map.cleanTexts() modules.game_textmessage.clearMessages() end, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+W', function() g_map.cleanTexts() modules.game_textmessage.clearMessages() end, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+;', toggleDash, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+.', toggleAspectRatio, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+.', toggleAspectRatio, gameRootPanel)
g_keyboard.bindKeyDown('Ctrl+N', function() gameMapPanel:setDrawTexts(not gameMapPanel:isDrawingTexts()) end, gameRootPanel) g_keyboard.bindKeyDown('Ctrl+N', function() gameMapPanel:setDrawTexts(not gameMapPanel:isDrawingTexts()) end, gameRootPanel)
end end
@ -193,45 +186,6 @@ function tryLogout()
anchor=AnchorHorizontalCenter}, yesCallback, noCallback) anchor=AnchorHorizontalCenter}, yesCallback, noCallback)
end end
function onWalk(dir)
cancelAutoWalkCheck()
end
function onPositionChange(newPos, oldPos)
checkAutoWalking()
end
function onCancelWalk(dir)
checkAutoWalking(true)
end
function checkAutoWalking(stepCancelled)
local stepCancelled = stepCancelled or false
local player = g_game.getLocalPlayer()
if not player:isAutoWalking() then
player:clearWalkSteps()
end
local lastDestination = player:getLastDestination()
if not lastDestination then
return -- auto walk has been cancelled
end
player:setWalkStep(lastDestination)
local playerPos = player:getPosition()
local walkSteps = player:getWalkSteps(lastDestination)
if (not table.empty(walkSteps) and #walkSteps >= WALK_STEPS_RETRY) or stepCancelled then
if lastDestination then player:autoWalk(lastDestination) end
end
end
function cancelAutoWalkCheck()
local player = g_game.getLocalPlayer()
player:setLastDestination(nil) -- cancel retries
player:clearWalkSteps()
end
function smartWalk(defaultDir) function smartWalk(defaultDir)
local rebindKey = false local rebindKey = false
local lastKey = arrowKeys[lastWalkDir] local lastKey = arrowKeys[lastWalkDir]
@ -281,7 +235,6 @@ function smartWalk(defaultDir)
else else
g_game.walk(dir) g_game.walk(dir)
end end
cancelAutoWalkCheck() -- cancel the auto walker check
if rebindKey then if rebindKey then
g_keyboard.bindKeyPress(lastKey, function() smartWalk(lastWalkDir) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY) g_keyboard.bindKeyPress(lastKey, function() smartWalk(lastWalkDir) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
@ -565,12 +518,14 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
end end
end end
local player = g_game.getLocalPlayer()
player:stopAutoWalkUpdate()
if autoWalkPos and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then if autoWalkPos and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then
local player = g_game.getLocalPlayer()
if not player:autoWalk(autoWalkPos) then if not player:autoWalk(autoWalkPos) then
return false modules.game_textmessage.displayStatusMessage(tr('There is no way.'))
return true
end end
return true
end end
return false return false

View File

@ -86,7 +86,6 @@ function UIGameMap:onMouseRelease(mousePosition, mouseButton)
local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, multiUseThing) local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, multiUseThing)
if ret then if ret then
modules.game_interface.cancelAutoWalkCheck()
self.cancelNextRelease = true self.cancelNextRelease = true
end end

View File

@ -87,7 +87,6 @@ function UIItem:onMouseRelease(mousePosition, mouseButton)
self.cancelNextRelease = true self.cancelNextRelease = true
return true return true
elseif modules.game_interface.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, item) then elseif modules.game_interface.processMouseAction(mousePosition, mouseButton, nil, item, item, nil, item) then
modules.game_interface.cancelAutoWalkCheck()
return true return true
end end
return false return false

View File

@ -383,7 +383,10 @@ function onMinimapMouseRelease(self, mousePosition, mouseButton)
local pos = self:getPosition(mousePosition) local pos = self:getPosition(mousePosition)
if pos and mouseButton == MouseLeftButton and self:isPressed() then if pos and mouseButton == MouseLeftButton and self:isPressed() then
local player = g_game.getLocalPlayer() local player = g_game.getLocalPlayer()
if not player:autoWalk(pos) then return false end if not player:autoWalk(pos) then
modules.game_textmessage.displayStatusMessage(tr('There is no way.'))
return false
end
return true return true
end end
return false return false

View File

@ -98,47 +98,3 @@ function Player:dismount()
g_game.mount(false) g_game.mount(false)
end end
end end
function Player:getLastDestination()
return self.lastDestination
end
function Player:setLastDestination(destination)
self.lastDestination = destination
end
function Player:getWalkSteps(destination)
if not self.walkSteps or not destination then
return nil
end
return self.walkSteps[destination]
end
function Player:setWalkStep(destination)
if not self.walkSteps then
self.walkSteps = {}
end
if destination then
if not self.walkSteps[destination] then
self.walkSteps[destination] = {}
end
table.insert(self.walkSteps[destination], true)
end
end
function Player:clearWalkSteps()
self.walkSteps = {}
end
function Player:autoWalk(destination)
self:clearWalkSteps()
self:setLastDestination(destination)
local dirs = g_map.findPath(self:getPosition(), destination, 127, PathFindFlags.AllowNullTiles)
if #dirs == 0 then
modules.game_textmessage.displayStatusMessage(tr('There is no way.'))
return false
end
g_game.autoWalk(dirs)
return true
end

View File

@ -47,7 +47,8 @@ namespace Otc
ANIMATED_TEXT_DURATION = 1000, ANIMATED_TEXT_DURATION = 1000,
STATIC_DURATION_PER_CHARACTER = 60, STATIC_DURATION_PER_CHARACTER = 60,
MIN_STATIC_TEXT_DURATION = 3000, MIN_STATIC_TEXT_DURATION = 3000,
MAX_STATIC_TEXT_WIDTH = 200 MAX_STATIC_TEXT_WIDTH = 200,
MAX_AUTOWALK_STEPS_RETRY = 10
}; };
enum DrawFlags { enum DrawFlags {

View File

@ -158,7 +158,7 @@ void Game::processGameStart()
m_protocolGame->sendPing(); m_protocolGame->sendPing();
disableBotCall(); disableBotCall();
} }
}, 3000); }, 2000);
} }
} }
@ -564,6 +564,8 @@ bool Game::walk(Otc::Direction direction)
return false; return false;
} }
m_localPlayer->stopAutoWalkUpdate();
g_lua.callGlobalField("g_game", "onWalk", direction); g_lua.callGlobalField("g_game", "onWalk", direction);
forceWalk(direction); forceWalk(direction);
@ -824,6 +826,7 @@ void Game::attack(CreaturePtr creature)
cancelFollow(); cancelFollow();
setAttackingCreature(creature); setAttackingCreature(creature);
m_localPlayer->stopAutoWalkUpdate();
if(m_protocolVersion >= 963) { if(m_protocolVersion >= 963) {
if(creature) if(creature)
@ -847,6 +850,7 @@ void Game::follow(CreaturePtr creature)
cancelAttack(); cancelAttack();
setFollowingCreature(creature); setFollowingCreature(creature);
m_localPlayer->stopAutoWalkUpdate();
if(m_protocolVersion >= 963) { if(m_protocolVersion >= 963) {
if(creature) if(creature)
@ -867,6 +871,8 @@ void Game::cancelAttackAndFollow()
if(isAttacking()) if(isAttacking())
setAttackingCreature(nullptr); setAttackingCreature(nullptr);
m_localPlayer->stopAutoWalkUpdate();
m_protocolGame->sendCancelAttackAndFollow(); m_protocolGame->sendCancelAttackAndFollow();
g_lua.callGlobalField("g_game", "onCancelAttackAndFollow"); g_lua.callGlobalField("g_game", "onCancelAttackAndFollow");

View File

@ -161,12 +161,54 @@ void LocalPlayer::cancelWalk(Otc::Direction direction)
if(direction != Otc::InvalidDirection) if(direction != Otc::InvalidDirection)
setDirection(direction); setDirection(direction);
updateAutoWalkSteps(true);
callLuaField("onCancelWalk", direction); callLuaField("onCancelWalk", direction);
} }
void LocalPlayer::updateAutoWalkSteps(bool walkFailed)
{
if(!m_autoWalking) {
m_autoWalkSteps.clear();
return;
}
if(!m_lastAutoWalkDestination.isValid()) {
return;
}
// for now this cannot be done from lua, due to bot protection
m_autoWalkSteps.push_back(m_lastAutoWalkDestination);
if(m_autoWalkSteps.size() >= Otc::MAX_AUTOWALK_STEPS_RETRY || walkFailed) {
autoWalk(m_lastAutoWalkDestination);
}
}
bool LocalPlayer::autoWalk(const Position& destination)
{
m_autoWalkSteps.clear();
m_lastAutoWalkDestination = destination;
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> result = g_map.findPath(m_position, destination, 127, Otc::PathFindAllowNullTiles);
std::vector<Otc::Direction> dirs = std::get<0>(result);
if(dirs.size() == 0)
return false;
g_game.autoWalk(dirs);
return true;
}
void LocalPlayer::stopAutoWalkUpdate()
{
m_lastAutoWalkDestination = Position();
m_autoWalkSteps.clear();
}
void LocalPlayer::stopWalk() void LocalPlayer::stopWalk()
{ {
Creature::stopWalk(); // will call terminateWalk Creature::stopWalk(); // will call terminateWalk
m_lastPrewalkDone = true; m_lastPrewalkDone = true;
m_lastPrewalkDestionation = Position(); m_lastPrewalkDestionation = Position();
} }
@ -231,6 +273,13 @@ void LocalPlayer::onAppear()
lockWalk(); lockWalk();
} }
void LocalPlayer::onPositionChange(const Position& newPos, const Position& oldPos)
{
Creature::onPositionChange(newPos, oldPos);
updateAutoWalkSteps();
}
void LocalPlayer::setStates(int states) void LocalPlayer::setStates(int states)
{ {
if(m_states != states) { if(m_states != states) {

View File

@ -37,6 +37,9 @@ public:
void unlockWalk() { m_walkLockExpiration = 0; } void unlockWalk() { m_walkLockExpiration = 0; }
void lockWalk(int millis = 250); void lockWalk(int millis = 250);
void stopAutoWalkUpdate();
void updateAutoWalkSteps(bool walkFailed = false);
bool autoWalk(const Position& destination);
bool canWalk(Otc::Direction direction); bool canWalk(Otc::Direction direction);
void setStates(int states); void setStates(int states);
@ -87,6 +90,7 @@ public:
double getOfflineTrainingTime() { return m_offlineTrainingTime; } double getOfflineTrainingTime() { return m_offlineTrainingTime; }
std::vector<int> getSpells() { return m_spells; } std::vector<int> getSpells() { return m_spells; }
ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; } ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; }
std::vector<Position> getAutoWalkSteps() { return m_autoWalkSteps; }
bool hasSight(const Position& pos); bool hasSight(const Position& pos);
bool isKnown() { return m_known; } bool isKnown() { return m_known; }
@ -99,6 +103,7 @@ public:
bool isLocalPlayer() { return true; } bool isLocalPlayer() { return true; }
virtual void onAppear(); virtual void onAppear();
virtual void onPositionChange(const Position& newPos, const Position& oldPos);
protected: protected:
void walk(const Position& oldPos, const Position& newPos); void walk(const Position& oldPos, const Position& newPos);
@ -117,6 +122,7 @@ private:
// walk related // walk related
Timer m_walkPingTimer; Timer m_walkPingTimer;
Position m_lastPrewalkDestionation; Position m_lastPrewalkDestionation;
Position m_lastAutoWalkDestination;
ScheduledEventPtr m_autoWalkEndEvent; ScheduledEventPtr m_autoWalkEndEvent;
ticks_t m_walkLockExpiration; ticks_t m_walkLockExpiration;
int m_lastWalkPing; int m_lastWalkPing;
@ -136,6 +142,7 @@ private:
std::array<int, Otc::LastSkill> m_skillsBaseLevel; std::array<int, Otc::LastSkill> m_skillsBaseLevel;
std::array<int, Otc::LastSkill> m_skillsLevelPercent; std::array<int, Otc::LastSkill> m_skillsLevelPercent;
std::vector<int> m_spells; std::vector<int> m_spells;
std::vector<Position> m_autoWalkSteps;
int m_states; int m_states;
int m_vocation; int m_vocation;

View File

@ -459,6 +459,10 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking); g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("hasSight", &LocalPlayer::hasSight); g_lua.bindClassMemberFunction<LocalPlayer>("hasSight", &LocalPlayer::hasSight);
g_lua.bindClassMemberFunction<LocalPlayer>("isAutoWalking", &LocalPlayer::isAutoWalking); g_lua.bindClassMemberFunction<LocalPlayer>("isAutoWalking", &LocalPlayer::isAutoWalking);
g_lua.bindClassMemberFunction<LocalPlayer>("stopAutoWalkUpdate", &LocalPlayer::stopAutoWalkUpdate);
g_lua.bindClassMemberFunction<LocalPlayer>("updateAutoWalkSteps", &LocalPlayer::updateAutoWalkSteps);
g_lua.bindClassMemberFunction<LocalPlayer>("autoWalk", &LocalPlayer::autoWalk);
g_lua.bindClassMemberFunction<LocalPlayer>("getAutoWalkSteps", &LocalPlayer::getAutoWalkSteps);
g_lua.registerClass<Tile>(); g_lua.registerClass<Tile>();
g_lua.bindClassMemberFunction<Tile>("clean", &Tile::clean); g_lua.bindClassMemberFunction<Tile>("clean", &Tile::clean);

View File

@ -506,6 +506,7 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
Position neighborPos = currentNode->pos.translated(i, j); Position neighborPos = currentNode->pos.translated(i, j);
const TilePtr& tile = getTile(neighborPos); const TilePtr& tile = getTile(neighborPos);
float walkFactor = 0;
if(neighborPos != goalPos) { if(neighborPos != goalPos) {
/* /*
Known Issue with Otc::PathFindAllowNullTiles flag: Known Issue with Otc::PathFindAllowNullTiles flag:
@ -514,7 +515,7 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
but it is breaking normal path finding. but it is breaking normal path finding.
*/ */
if(!(flags & Otc::PathFindAllowNullTiles) && !tile) if(!(flags & Otc::PathFindAllowNullTiles) && !tile)
continue; walkFactor = 1.0f;
if(tile) { if(tile) {
if(!(flags & Otc::PathFindAllowCreatures) && tile->hasCreature()) if(!(flags & Otc::PathFindAllowCreatures) && tile->hasCreature())
continue; continue;
@ -525,12 +526,11 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
} }
} }
float walkFactor;
Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos); Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos);
if(walkDir >= Otc::NorthEast) if(walkDir >= Otc::NorthEast)
walkFactor = 3.0f; walkFactor += 3.0f;
else else
walkFactor = 1.0f; walkFactor += 1.0f;
int groundSpeed = tile ? tile->getGroundSpeed() : 100; int groundSpeed = tile ? tile->getGroundSpeed() : 100;
float cost = currentNode->cost + (groundSpeed * walkFactor) / 100.0f; float cost = currentNode->cost + (groundSpeed * walkFactor) / 100.0f;