void Game::autoWalk(const std::vector<Otc::Direction>& dirs) { if(!canPerformGameAction()) return; // protocol limits walk path up to 255 directions if(dirs.size() > 127) { g_logger.error("Auto walk path too great, the maximum number of directions is 127"); return; } if(dirs.size() == 0) return; // must cancel follow before any new walk if(isFollowing()) cancelFollow(); Otc::Direction direction = dirs.front(); if(m_localPlayer->canWalk(direction)) { TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction)); if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking()) m_localPlayer->preWalk(direction); } m_protocolGame->sendAutoWalk(dirs); g_lua.callGlobalField("g_game", "onAutoWalk", dirs); }
uint32_t Monster::getMoveFlags() const { auto flags = (Creature::getMoveFlags() | FLAG_PATHFINDING); if (isFollowing()) { flags |= FLAG_IGNOREFIELDDAMAGE; } return flags; }
void Game::stop() { if(!canPerformGameAction()) return; if(isFollowing()) cancelFollow(); m_protocolGame->sendStop(); }
void Game::cancelAttackAndFollow() { if(!canPerformGameAction()) return; if(isAttacking()) setAttackingCreature(nullptr); if(isFollowing()) setFollowingCreature(nullptr); m_protocolGame->sendCancelAttackAndFollow(); }
void Game::attack(const CreaturePtr& creature) { if(!canPerformGameAction() || creature == m_localPlayer) return; if(creature && creature == m_attackingCreature) { cancelAttack(); return; } if(creature && isFollowing()) cancelFollow(); setAttackingCreature(creature); m_protocolGame->sendAttack(creature ? creature->getId() : 0, ++m_seq); }
void Game::cancelAttackAndFollow() { if(!canPerformGameAction()) return; if(isFollowing()) setFollowingCreature(nullptr); if(isAttacking()) setAttackingCreature(nullptr); m_localPlayer->stopAutoWalk(); m_protocolGame->sendCancelAttackAndFollow(); g_lua.callGlobalField("g_game", "onCancelAttackAndFollow"); }
void Game::attack(CreaturePtr creature) { if(!canPerformGameAction() || creature == m_localPlayer) return; // cancel when attacking again if(creature && creature == m_attackingCreature) creature = nullptr; if(creature && isFollowing()) cancelFollow(); setAttackingCreature(creature); m_localPlayer->stopAutoWalk(); if(m_protocolVersion >= 963) { if(creature) m_seq = creature->getId(); } else m_seq++; m_protocolGame->sendAttack(creature ? creature->getId() : 0, m_seq); }
void Game::autoWalk(std::vector<Otc::Direction> dirs) { if(!canPerformGameAction()) return; // protocol limits walk path up to 255 directions if(dirs.size() > 127) { g_logger.error("Auto walk path too great, the maximum number of directions is 127"); return; } if(dirs.size() == 0) return; // must cancel follow before any new walk if(isFollowing()) cancelFollow(); auto it = dirs.begin(); Otc::Direction direction = *it; if(!m_localPlayer->canWalk(direction)) return; TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction)); if(toTile && toTile->isWalkable() && !m_localPlayer->isServerWalking()) { m_localPlayer->preWalk(direction); if(getFeature(Otc::GameForceFirstAutoWalkStep)) { forceWalk(direction); dirs.erase(it); } } g_lua.callGlobalField("g_game", "onAutoWalk", dirs); m_protocolGame->sendAutoWalk(dirs); }
void Game::walk(Otc::Direction direction) { if(!canPerformGameAction()) return; // must cancel follow before any new walk if(isFollowing()) cancelFollow(); // msut cancel auto walking and wait next try if(m_localPlayer->isAutoWalking()) { m_protocolGame->sendStop(); return; } if(!m_localPlayer->canWalk(direction)) return; Position toPos = m_localPlayer->getPosition().translatedToDirection(direction); TilePtr toTile = g_map.getTile(toPos); // only do prewalks to walkable tiles (like grounds and not walls) if(toTile && toTile->isWalkable()) m_localPlayer->preWalk(direction); // check walk to another floor (e.g: when above 3 parcels) else { // check if can walk to a lower floor auto canChangeFloorDown = [&]() -> bool { Position pos = toPos; if(!pos.down()) return false; TilePtr toTile = g_map.getTile(pos); if(toTile && toTile->hasElevation(3)) return true; return false; }; // check if can walk to a higher floor auto canChangeFloorUp = [&]() -> bool { TilePtr fromTile = m_localPlayer->getTile(); if(!fromTile || !fromTile->hasElevation(3)) return false; Position pos = toPos; if(!pos.up()) return false; TilePtr toTile = g_map.getTile(pos); if(!toTile || !toTile->isWalkable()) return false; return true; }; if(canChangeFloorDown() || canChangeFloorUp() || (!toTile || toTile->isEmpty())) { m_localPlayer->lockWalk(); } else return; } forceWalk(direction); g_lua.callGlobalField("g_game", "onWalk", direction); }
bool Game::walk(Otc::Direction direction, bool dash) { if(!canPerformGameAction()) return false; // must cancel follow before any new walk if(isFollowing()) cancelFollow(); // must cancel auto walking, and wait next try if(m_localPlayer->isAutoWalking() || m_localPlayer->isServerWalking()) { m_protocolGame->sendStop(); if(m_localPlayer->isAutoWalking()) m_localPlayer->stopAutoWalk(); return false; } if(dash) { if(m_localPlayer->isWalking() && m_dashTimer.ticksElapsed() < std::max<int>(m_localPlayer->getStepDuration(false, direction) - m_ping, 30)) return false; } else { // check we can walk and add new walk event if false if(!m_localPlayer->canWalk(direction)) { if(m_lastWalkDir != direction) { // must add a new walk event float ticks = m_localPlayer->getStepTicksLeft(); if(ticks <= 0) { ticks = 1; } if(m_walkEvent) { m_walkEvent->cancel(); m_walkEvent = nullptr; } m_walkEvent = g_dispatcher.scheduleEvent([=] { walk(direction, false); }, ticks); } return false; } } Position toPos = m_localPlayer->getPosition().translatedToDirection(direction); TilePtr toTile = g_map.getTile(toPos); // only do prewalks to walkable tiles (like grounds and not walls) if(toTile && toTile->isWalkable()) { m_localPlayer->preWalk(direction); // check walk to another floor (e.g: when above 3 parcels) } else { // check if can walk to a lower floor auto canChangeFloorDown = [&]() -> bool { Position pos = toPos; if(!pos.down()) return false; TilePtr toTile = g_map.getTile(pos); if(toTile && toTile->hasElevation(3)) return true; return false; }; // check if can walk to a higher floor auto canChangeFloorUp = [&]() -> bool { TilePtr fromTile = m_localPlayer->getTile(); if(!fromTile || !fromTile->hasElevation(3)) return false; Position pos = toPos; if(!pos.up()) return false; TilePtr toTile = g_map.getTile(pos); if(!toTile || !toTile->isWalkable()) return false; return true; }; if(canChangeFloorDown() || canChangeFloorUp() || (!toTile || toTile->isEmpty())) { m_localPlayer->lockWalk(); } else return false; } m_localPlayer->stopAutoWalk(); g_lua.callGlobalField("g_game", "onWalk", direction, dash); forceWalk(direction); if(dash) m_dashTimer.restart(); m_lastWalkDir = direction; return true; }
bool Game::dashWalk(Otc::Direction direction) { if(!canPerformGameAction()) return false; // must cancel follow before any new walk if(isFollowing()) cancelFollow(); // must cancel auto walking if(m_localPlayer->isAutoWalking()) { m_protocolGame->sendStop(); m_localPlayer->stopAutoWalk(); } if(m_localPlayer->isWalking() && m_dashTimer.ticksElapsed() < std::max<int>(m_localPlayer->getStepDuration(false, direction) - m_ping, 30)) return false; Position toPos = m_localPlayer->getPosition().translatedToDirection(direction); TilePtr toTile = g_map.getTile(toPos); // only do prewalks to walkable tiles (like grounds and not walls) if(toTile && toTile->isWalkable()) { if(!m_localPlayer->isWalking() && m_localPlayer->getWalkTicksElapsed() >= m_localPlayer->getStepDuration() + 100) m_localPlayer->preWalk(direction); // check walk to another floor (e.g: when above 3 parcels) } else { // check if can walk to a lower floor auto canChangeFloorDown = [&]() -> bool { Position pos = toPos; if(!pos.down()) return false; TilePtr toTile = g_map.getTile(pos); if(toTile && toTile->hasElevation(3)) return true; return false; }; // check if can walk to a higher floor auto canChangeFloorUp = [&]() -> bool { TilePtr fromTile = m_localPlayer->getTile(); if(!fromTile || !fromTile->hasElevation(3)) return false; Position pos = toPos; if(!pos.up()) return false; TilePtr toTile = g_map.getTile(pos); if(!toTile || !toTile->isWalkable()) return false; return true; }; if(canChangeFloorDown() || canChangeFloorUp() || (!toTile || toTile->isEmpty())) { m_localPlayer->lockWalk(); } else return false; } forceWalk(direction); m_dashTimer.restart(); m_lastWalkDir = direction; return true; }