API UO NewMoveXY - LIHACHTETAN/ClassicUO-BadNewbie-BasicIDE GitHub Wiki

UO.NewMoveXY

Оглавление · Алфавитный указатель · Movement

ClassicUO • Runtime API

Перемещает персонажа к X/Y, ожидает окончание и проверяет достижение цели; поддерживает дополнительные ограничения и callback.

Точный синтаксис

UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any, maxSteps:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any, maxSteps:Any, maxDistance:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any, maxSteps:Any, maxDistance:Any, AccuracyZ:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any, maxSteps:Any, maxDistance:Any, AccuracyZ:Any, avoidMobiles:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any, maxSteps:Any, maxDistance:Any, AccuracyZ:Any, avoidMobiles:Any, openDoors:Any) -> Integer
UO.NewMoveXY(Xdst:Any, Ydst:Any, Optimized:Any, Accuracy:Any, Running:Any, StepCallback:Any, timeout:Any, maxSteps:Any, maxDistance:Any, AccuracyZ:Any, avoidMobiles:Any, openDoors:Any, stopOnStuck:Any) -> Integer

Выберите одну из зарегистрированных форм. Параметры передаются позиционно. Any означает значение BASIC с преобразованием внутри команды; Unit — отсутствие возвращаемого значения.

Параметры

  • Xdst / x — Мировая координата X назначения, 0..65535. Это не serial и не позиция внутри гампа.
  • Ydst / y — Мировая координата Y назначения, 0..65535.
  • Optimized — TRUE — обычный режим поиска и проверки пути вперёд; FALSE — уменьшенная эвристика и проверка ближайшего шага. FALSE не отключает обход препятствий.
  • Accuracy — Допуск по X и Y в клетках: оба отклонения должны укладываться в него. Значение ограничивается диапазоном 0..20; 0 требует точных X/Y.
  • Running — TRUE/1 — запрос бега, FALSE/0 — шаг. Серверные задержки движения сохраняются; это не множитель скорости.
  • StepCallback — Необязательное имя SUB/функции строкой. Получает фактические x,y,z как три Integer после замеченного изменения позиции; над ними можно сразу выполнять арифметику. 0 или пустая строка отключают вызов. Unit или ненулевой числовой результат продолжают движение; 0 останавливает. Другое ненулевое число вместо имени является ошибкой.
  • timeout — Необязательный предел ожидания в миллисекундах; отсутствующий аргумент, 0 и отрицательное значение означают отсутствие этого дополнительного предела.
  • maxSteps — Необязательный предел замеченных изменений позиции, не сетевых пакетов. 0/отрицательное/отсутствие — без этого лимита. Между опросами может пройти несколько шагов, поэтому это не точный счётчик клеток.
  • maxDistance — Необязательный предел исходного расстояния max(abs(dx),abs(dy)) до цели. 0/отсутствие отключают его. Это не разрешённое отклонение при обходе и не длина найденного пути.
  • AccuracyZ — Допуск высоты: abs(фактическая Z - требуемая Z), ограничивается 0..255. Ноль требует точной высоты; 255 практически отключает ограничение Z. Для NewMoveXY целевой Z равен Z персонажа при вызове; по умолчанию допуск 255.
  • avoidMobiles — Необязательный флаг: TRUE запрещает проход сквозь учитываемых персонажей; FALSE разрешает попытку. Без аргумента используется moveThroughNPC. Сервер всё равно может запретить проход.
  • openDoors — Необязательный флаг открывания дверей по пути. Без аргумента используется moveOpenDoor; TRUE не предоставляет доступ к запертым дверям.
  • stopOnStuck — TRUE завершает движение с 0, если после планирования примерно 1000 мс не менялись X/Y/Z. Активные порции поиска и пересчёта сбрасывают этот таймер; отдельный timeout продолжает действовать. По умолчанию FALSE.

Возвращает

Integer 1 — в конце проверки персонаж находится в заданном допуске X/Y/Z, в том числе когда уже был там до вызова. Integer 0 — недопустимые координаты, отказ запуска, недостигнутая точка или сработавшее условие остановки. Это не число шагов и не serial; при аварийной отмене процедура прерывается вместо обычного возврата 0.

Это логический результат: 1 = TRUE, 0 = FALSE. После VAR result = команда(...) можно писать IF result = TRUE THEN или IF result = 1 THEN; для отрицательного результата — IF result = FALSE THEN или IF result = 0 THEN. TRUE/FALSE пишутся без кавычек. Вызовите команду один раз и сохраните результат: повторный вызов может повторить действие или прочитать уже изменившееся состояние.

Поведение

  • Полный маршрут A* строится до первого шага, короткими порциями между обновлениями клиента. При Optimized=TRUE проверяются следующие 4 клетки пути; при FALSE — ближайший шаг. Это проверка уже рассчитанного пути, а не дальность всего маршрута и не ползунки обхода при движении мышью.
  • Отказ сервера DenyWalk или новое препятствие запрашивает перерасчёт от текущей позиции после завершения очереди шагов. Число повторов и частота перерасчёта ограничены; отсутствие пути может завершить движение с 0.
  • Маршрут принадлежит запустившей его процедуре: её аварийная остановка отменяет оставшийся автоматический путь. Если другой запуск или пользователь уже заменил маршрут, отмена прежнего владельца новый маршрут не трогает. Уже отправленные шаги не отзываются.
  • SetBadLocation и SetBadObject применяются как снимок запретов текущего runtime при запуске маршрута. Они сохраняются при его внутреннем перерасчёте. Изменение или очистка списков влияет на следующий маршрут, а не переписывает уже выполняющийся.
  • После принятия запроса вызов ждёт на потоке скрипта. Первоначальный поиск и пересчёт выполняются на игровом потоке порциями: максимум 32 раскрытия узлов и мягкий бюджет около 1 мс за порцию. Одна сложная проверка клетки или чтение карты может превысить этот бюджет. Между порциями клиент продолжает обновления; полный лимит поиска остаётся 10000 узлов.
  • timeout отсчитывается после принятия запроса и включает последующие порции поиска и пересчёта. stopOnStuck не считает работающий поиск застреванием персонажа; после завершения планирования отсутствие изменений позиции снова учитывается. Итоговый 1/0 проверяет фактические координаты, а не только готовность пути.
  • Результат учитывает локальную позицию клиента; последующая серверная коррекция всё ещё возможна. Запуск конкурирующих команд движения из разных процедур меняет общий маршрут персонажа.
  • Настройки moveCheckStamina, moveExitOnDisconnect, moveOpenDoor, moveThroughCorner, moveThroughNPC, moveHeuristicMult, moveTurnCost и moveBetweenTwoCorners влияют на исполнение. Явные avoidMobiles/openDoors заменяют соответствующие значения для этого вызова.
  • Результат 0 не сообщает точную причину. Проверяйте координаты, соединение, выносливость и журнал; не повторяйте движение бесконечно без WAIT и лимита попыток.

Внутренние функции: от вызова до результата

Ниже разобрана реальная цепочка клиента. Это описание внутренних C#-функций, а не дополнительные команды BASIC. Запускаемые функции примеров, включая GoToPoint и AfterStep, объявлены целиком в разделе «Примеры».

1. CompactNewMoveXY

Разбирает 5..13 позиционных аргументов. Берёт целевую Z из текущей позиции, проверяет имя callback; отсутствующие лимиты равны 0, accuracyZ по умолчанию 255.

Передаёт подготовленные значения в MoveToCanonical. Это внутренний C#-метод; его имя нельзя вызвать как UO-команду.

Исходник проекта: external/InjectionScript/src/InjectionScript/Runtime/InjectionApiUO.cs; функция CompactNewMoveXY.

2. MoveToCanonical

Принимает X/Y/Z, допуски и ограничения вызова. Проверяет диапазон координат, соединение, выносливость и maxDistance; ограничивает accuracy до 0..20, accuracyZ до 0..255. Уже достигнутая цель даёт 1 без нового поиска.

После bridge.MoveTo ждёт bridge.Move(), читает положение, проверяет timeout, callback, maxSteps и stopOnStuck. Между проверками вызывает bridge.Wait(5). После окончания сравнивает фактические координаты с допусками. Возврат 1/0 относится к достижению, а не к принятию маршрута.

Исходник проекта: external/InjectionScript/src/InjectionScript/Runtime/InjectionApiUO.cs; функция MoveToCanonical.

3. MoveTo

Передаёт параметры из потока скрипта на игровой поток через Invoke. Создаёт снимок SetBadLocation/SetBadObject, вызывает Pathfinder.WalkTo и запоминает поколение маршрута для отмены владельцем.

Возвращает 1, если WalkTo принял маршрут, иначе 0. Это промежуточный результат: сама команда ещё ждёт завершения и проверяет цель.

Исходник проекта: src/ClassicUO.Client/Game/Managers/ClassicUOInjectionApiBridge.cs; функция MoveTo.

4. WalkTo

Принимает цель, допуск, ходьбу/бег, правила дверей/углов/персонажей, стоимость и запреты. Отклоняет отсутствие персонажа, паралич и недостаточную выносливость. Останавливает предыдущий маршрут, очищает поиск, выбирает старт, сохраняет параметры.

Вызовы из скрипта, интерфейса, следования и серверного запроса включают incremental: BeginPathSearch готовит поиск, AdvancePathSearch выполняет первую порцию. true может означать принятый незавершённый поиск; передвижение начинается только после полного пути. Старый синхронный режим C# сохранён для совместимости нативного PluginHost.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция WalkTo.

5. ResetSearchNodes

Аргументов нет. Сбрасывает использованные узлы, индексы открытых/закрытых состояний, очередь приоритетов, свободные слоты и длину пути.

Возвращаемого значения нет. Уже выделенные объекты узлов переиспользуются; это уменьшает повторные выделения памяти, но не меняет проходимость.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция ResetSearchNodes.

6. SetSearchStart

Аргументов нет. Получает GetEndPosition — положение после уже поставленных в очередь шагов и текущее направление.

Сохраняет старт X/Y/Z/направление и карту. При пересчёте ProcessAutoWalk сначала дожидается освобождения очереди; если исходная позиция или карта изменились между порциями, поиск запускается заново от актуальной точки.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция SetSearchStart.

7. FindPath

Принимает maxNodes. Синхронная совместимая обёртка: вызывает BeginPathSearch, затем AdvancePathSearch до завершения. Основные клиентские вызовы используют порции через ProcessAutoWalk и не вызывают эту обёртку.

true — полный путь построен; false — путь не найден в пределах лимитов. Этот C#-режим может занимать весь поиск за один вызов и сохранён для существующего контракта нативных плагинов.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция FindPath.

8. BeginPathSearch

Принимает общий maxNodes. Очищает признак результата, создаёт стартовый узел с X/Y/Z/направлением, задаёт оценку и сохраняет текущую позицию поиска.

Возвращаемого значения нет: состояние становится pending. Если старт уже в допусках X/Y/Z, сразу сохраняет одноточечный путь и состояние успеха. Пакеты движения здесь не отправляются.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция BeginPathSearch.

9. AdvancePathSearch

Аргументов нет: продолжает сохранённый поиск. Раскрывает максимум 32 узла через OpenNodes/FindCheapestNode. После примерно 1 мс возвращается между раскрытиями, оставляя очередь, родителей и текущий узел для следующего обновления.

При извлечении цели восстанавливает полный путь по Parent, включая старт, и отмечает успех. При исчерпании очереди или общего лимита отмечает неудачу. До завершения оставляет pending. Бюджет времени мягкий: текущее раскрытие и чтение геометрии сначала заканчиваются.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция AdvancePathSearch.

10. OpenNodes

Принимает текущий PathNode. Пробует восемь направлений через CanWalk. Если проверка сменила направление вместо запрошенного, такой сосед не добавляется.

Для допустимого соседа вызывает AddNodeToList; true означает, что хотя бы одно добавление не сообщило переполнение. Это не признак достижения конечной цели.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция OpenNodes.

11. CanWalk

Принимает направление и X/Y/Z по ссылке. GetNewXY выбирает соседнюю клетку; CalculateNewZ проверяет высоту и объекты, затем учитываются правила диагональных углов.

Возвращает bool проходимости и может изменить направление/координаты. Поэтому OpenNodes и ValidatePathLookahead проверяют не только true, но и совпадение с требуемым направлением и точкой.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция CanWalk.

12. GetNewXY

Принимает числовое направление, X и Y по ссылке. По таблице направлений добавляет смещение на одну клетку.

Меняет X/Y; ничего не отправляет серверу и не проверяет высоту или препятствия.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция GetNewXY.

13. CalculateNewZ

Принимает X/Y назначения, исходную Z по ссылке и направление. Учитывает прикладной запрет клетки и режим персонажа: обычный, мёртвый/GM, полёт или морской конёк. CalculateMinMaxZ вычисляет границы подъёма, CreateItemList собирает поверхности и препятствия.

Проверяет допустимый просвет и поверхность, при успехе записывает подходящую Z и возвращает true. false означает отсутствие допустимого локального прохода; сервер может иметь дополнительные правила.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция CalculateNewZ.

14. CalculateMinMaxZ

Получает границы высоты по ссылке, координаты/высоту, направление и режим движения. По исходной клетке, поверхностям и мостам уточняет нижнюю и верхнюю границы шага.

Возвращает вычисленную верхнюю границу и обновляет аргументы minZ/maxZ; при отсутствии исходной геометрии возвращает 0. Это вспомогательный расчёт геометрии, а не номер этажа или готовая команда движения.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция CalculateMinMaxZ.

15. CreateItemList

Получает переиспользуемый список PathObject, клетку и режим движения. Собирает землю, статики и загруженные предметы/персонажей с высотой и флагами прохода, поверхности, моста и диагоналей.

false — исходная клетка не получена из карты; true — сбор завершён, наполнение списка проверяется отдельно. Фильтры зависят от флагов персонажа, tiledata, настроек прохода и открывания дверей; функция не загружает весь неизвестный серверный мир.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция CreateItemList.

16. NodeKey

Получает X/Y/Z и направление. Формирует ключ состояния для словаря и множества.

При ненулевой цене поворота включает направление; иначе направление в ключе равно 0. Так одинаковые координаты с разным будущим штрафом поворота не объединяются ошибочно.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция NodeKey.

17. MovementCost

Получает родительский узел, направление нового шага и вид ребра. Для скриптов прямой шаг стоит 10, диагональный — 14. Если направление изменилось, добавляет moveTurnCost, ограниченный внутри WalkTo до 100000.

Возвращает стоимость одного ребра. Это внутренние весовые единицы, не миллисекунды, не число уже сделанных шагов и не скорость бега.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция MovementCost.

18. GetGoalDistCost

Получает точку-кандидат. dx=max(0,abs(goalX-X)-accuracy), dy=max(0,abs(goalY-Y)-accuracy). Для скриптов h=(10max(dx,dy)+4min(dx,dy))*multiplier/100 с целочисленным делением и ограничением сверху.

При Optimized=TRUE берётся moveHeuristicMult (по умолчанию 93, минимум 1); при FALSE используется 1. Высота проверяется при выборе цели и проходимости, а не прибавляется к этой эвристике. При значении выше 100 оптимальность по стоимости уже не гарантируется.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция GetGoalDistCost.

19. AddNodeToList

Получает тип списка, направление, X/Y/Z, родителя и вид ребра. Закрытые состояния не добавляет повторно. Для открытого состояния оставляет меньшую стоимость g; для нового выделяет или переиспользует слот. При закрытии переносит данные в стабильный закрытый узел.

Сохраняет Parent и f=g+h, добавляет приоритет в очередь. Возвращает индекс, -1 при нехватке места. Словарь/множество заменяют линейный поиск по 10000 ячейкам.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция AddNodeToList.

20. FindCheapestNode

Извлекает минимальный приоритет из очереди, пропускает устаревшие записи после уменьшения стоимости или переиспользования слота. Проверяет актуальный индекс состояния.

Закрывает узел; только теперь отмечает достигнутую цель. Возвращает индекс закрытого узла либо -1. Обнаружить цель среди соседей недостаточно для выбора лучшего маршрута.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция FindCheapestNode.

21. ValidatePathLookahead

Принимает индекс пути и прогнозируемое положение X/Y/Z. Проверяет до 4 следующих клеток при Optimized=TRUE, одну при FALSE, последовательно вызывая CanWalk.

true — все проверенные направления и X/Y/Z совпали с планом; false — нужен пересчёт. Это проверка части уже построенного пути, а не ограничение дальности всей цели.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция ValidatePathLookahead.

22. NotifyWalkDenied

Вызывается обработчиком отказа/коррекции шага. Если маршрут активен, выставляет флаг необходимости пересчёта.

Сам путь здесь не рассчитывается и новый пакет движения не отправляется.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция NotifyWalkDenied.

23. RebuildPathFromCurrentPosition

Аргументов нет. При отсутствии персонажа или восьми попытках без продвижения возвращает false. Сбрасывает поиск, обновляет старт, увеличивает счётчик и назначает следующий пересчёт не раньше чем через 40 мс.

Сохраняет цель и правила. В incremental-режиме начинает новый поиск через BeginPathSearch и возвращает true как принятие пересчёта; ProcessAutoWalk позже завершает его порциями. Синхронная ветка вызывает FindPath. false — повтор не принят либо синхронный поиск не удался. Изменение X/Y/Z сбрасывает счётчик попыток.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция RebuildPathFromCurrentPosition.

24. ProcessAutoWalk

Проверяет наличие персонажа, соединение/выносливость, актуальность старта и карты; при пересчёте ждёт окончания очереди и cooldown. Выполняет одну порцию незавершённого поиска. Пока путь не готов, шагов не отправляет. Затем соблюдает лимит Walker, выравнивает индекс по GetEndPosition и вызывает ValidatePathLookahead.

При openDoors пытается открыть соседнюю дверь через TryOpenDoor, затем делает Player.Walk. Отказ локального шага запрашивает пересчёт. Эта процедура вызывается клиентом при обновлениях; она не раскручивает бесконечный цикл отправки пакетов.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция ProcessAutoWalk.

25. InvokeStepCallback

Получает строковое имя функции скрипта и замеченные X/Y/Z. Вызывает runtime.CallSubrutineValues с тремя Integer; координаты сохраняют числовой тип, поэтому x-startX и сравнение высоты работают без преобразования строк.

Unit или ненулевой числовой результат означает продолжить; 0 — остановить. Callback вызывается после замеченного изменения, а не гарантированно после каждого сетевого пакета. Полный код AfterStep приведён в примере команды.

Исходник проекта: src/ClassicUO.Client/Game/Managers/ClassicUOInjectionApiBridge.cs; функция InvokeStepCallback.

26. StopAutoWalk

Останавливает автопуть и незавершённый поиск, меняет поколение, очищает параметры, запреты и флаг пересчёта. Последующие обновления не могут возобновить отменённый поиск.

Не отзывает уже отправленные серверу шаги. Поэтому остановка запроса не равна мгновенному откату позиции.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция StopAutoWalk.

27. StopAutoWalkIfGeneration

Получает сохранённый номер поколения маршрута.

Останавливает путь только при совпадении поколения. Отмена старого скрипта не отменяет новый маршрут другого владельца.

Исходник проекта: src/ClassicUO.Client/Game/Pathfinder.cs; функция StopAutoWalkIfGeneration.

Оптимизации здесь имеют конкретный смысл: очередь приоритетов, индексы состояний, повторное использование узлов, проверка ближайших клеток и ограниченный пересчёт. Они не увеличивают разрешённую сервером скорость. Ползунки обхода при ручном движении мышью относятся к другому механизму; Optimized и moveHeuristicMult не заменяют эти ползунки.

Примеры

Пример 1. Дойти до соседней точки и проверить результат

# Дойти до соседней точки и проверить результат
#
# Перемещает персонажа к X/Y, ожидает окончание и проверяет достижение цели; поддерживает
# дополнительные ограничения и callback.
#
# Integer 1 — в конце проверки персонаж находится в заданном допуске X/Y/Z, в том числе когда
# уже был там до вызова. Integer 0 — недопустимые координаты, отказ запуска, недостигнутая точка
# или сработавшее условие остановки. Это не число шагов и не serial; при аварийной отмене
# процедура прерывается вместо обычного возврата 0.
#
# Это логический результат: 1 = TRUE, 0 = FALSE. После VAR result = команда(...) можно писать IF
# result = TRUE THEN или IF result = 1 THEN; для отрицательного результата — IF result = FALSE
# THEN или IF result = 0 THEN. TRUE/FALSE пишутся без кавычек. Вызовите команду один раз и
# сохраните результат: повторный вызов может повторить действие или прочитать уже изменившееся
# состояние.

SUB Main()
    # x/y — мировая цель; Optimized=TRUE, Accuracy=0 требуют точных X/Y, Running=FALSE задаёт
    # ходьбу.
    # ok — Integer 1 или 0, а не количество пройденных клеток. Цель должна быть доступна на текущей
    # карте.

    VAR x = UO.GetX() + 3
    VAR y = UO.GetY()
    VAR ok = UO.NewMoveXY(x, y, TRUE, 0, FALSE)
    IF ok THEN
        UO.Print('Destination reached')
    ELSE
        UO.Print('Destination not reached')
    END IF
END SUB

Разбор параметров и выполнения:

  • x/y — мировая цель; Optimized=TRUE, Accuracy=0 требуют точных X/Y, Running=FALSE задаёт ходьбу.
  • ok — Integer 1 или 0, а не количество пройденных клеток. Цель должна быть доступна на текущей карте.

Пример 2. Бег с пределом времени и расстояния

# Бег с пределом времени и расстояния
#
# Перемещает персонажа к X/Y, ожидает окончание и проверяет достижение цели; поддерживает
# дополнительные ограничения и callback.
#
# Integer 1 — в конце проверки персонаж находится в заданном допуске X/Y/Z, в том числе когда
# уже был там до вызова. Integer 0 — недопустимые координаты, отказ запуска, недостигнутая точка
# или сработавшее условие остановки. Это не число шагов и не serial; при аварийной отмене
# процедура прерывается вместо обычного возврата 0.
#
# Это логический результат: 1 = TRUE, 0 = FALSE. После VAR result = команда(...) можно писать IF
# result = TRUE THEN или IF result = 1 THEN; для отрицательного результата — IF result = FALSE
# THEN или IF result = 0 THEN. TRUE/FALSE пишутся без кавычек. Вызовите команду один раз и
# сохраните результат: повторный вызов может повторить действие или прочитать уже изменившееся
# состояние.

SUB Main()
    # 1445/1690 — пример цели; Accuracy=1 разрешает остановку рядом. Running=TRUE. StepCallback=0
    # отключает callback.
    # timeout=5000 мс; maxSteps=100 наблюдаемых перемещений; maxDistance=30 проверяется от исходной
    # точки.
    # AccuracyZ=255 не требует этажа; avoidMobiles=TRUE, openDoors=TRUE, stopOnStuck=TRUE включают
    # эти условия.

    VAR ok = UO.NewMoveXY(1445, 1690, TRUE, 1, TRUE, 0, 5000, 100, 30, 255, TRUE, TRUE, TRUE)
    UO.Print('Move result: ' + STR(ok))
END SUB

Разбор параметров и выполнения:

  • 1445/1690 — пример цели; Accuracy=1 разрешает остановку рядом. Running=TRUE. StepCallback=0 отключает callback.
  • timeout=5000 мс; maxSteps=100 наблюдаемых перемещений; maxDistance=30 проверяется от исходной точки.
  • AccuracyZ=255 не требует этажа; avoidMobiles=TRUE, openDoors=TRUE, stopOnStuck=TRUE включают эти условия.

Пример 3. Проверять выносливость в callback

# Проверять выносливость в callback
#
# Перемещает персонажа к X/Y, ожидает окончание и проверяет достижение цели; поддерживает
# дополнительные ограничения и callback.
#
# Integer 1 — в конце проверки персонаж находится в заданном допуске X/Y/Z, в том числе когда
# уже был там до вызова. Integer 0 — недопустимые координаты, отказ запуска, недостигнутая точка
# или сработавшее условие остановки. Это не число шагов и не serial; при аварийной отмене
# процедура прерывается вместо обычного возврата 0.
#
# Это логический результат: 1 = TRUE, 0 = FALSE. После VAR result = команда(...) можно писать IF
# result = TRUE THEN или IF result = 1 THEN; для отрицательного результата — IF result = FALSE
# THEN или IF result = 0 THEN. TRUE/FALSE пишутся без кавычек. Вызовите команду один раз и
# сохраните результат: повторный вызов может повторить действие или прочитать уже изменившееся
# состояние.

SUB AfterStep(x, y, z)
    UO.Print('Position: ' + STR(x) + ',' + STR(y) + ',' + STR(z))
    RETURN UO.Stamina > 10
END SUB

SUB Main()
    # StepCallback="AfterStep" получает три координаты. RETURN 0 при Stamina<=10 прекращает
    # движение; ненулевое значение продолжает.
    # timeout=5000 мс ограничивает ожидание. Callback вызывается после замеченного изменения, а не
    # гарантированно на каждый сетевой шаг; не выполняйте в нём долгое ожидание или новый маршрут.

    VAR ok = UO.NewMoveXY(UO.GetX() + 5, UO.GetY(), TRUE, 0, FALSE, 'AfterStep', 5000)
    UO.Print('Move result: ' + STR(ok))
END SUB

Разбор параметров и выполнения:

  • StepCallback="AfterStep" получает три координаты. RETURN 0 при Stamina<=10 прекращает движение; ненулевое значение продолжает.
  • timeout=5000 мс ограничивает ожидание. Callback вызывается после замеченного изменения, а не гарантированно на каждый сетевой шаг; не выполняйте в нём долгое ожидание или новый маршрут.

Пример 4. GoToPoint: полный код вспомогательной функции и Main

# GoToPoint объявлена в этом скрипте; это не встроенная команда UO.
# Скопируйте ВЕСЬ пример в .sc: функция и Main нужны вместе.
# Цепочка вызовов: Main -> GoToPoint -> встроенная UO.NewMoveXY.
# Других скрытых функций или файлов Include у этого примера нет.

# x, y: мировые координаты цели, 0..65535.
# accuracy: допуск по X/Y в клетках; NewMoveXY ограничивает его 0..20.
# running: TRUE — бег, FALSE — ходьба.
# Возврат: 1 = TRUE — цель в допуске; 0 = FALSE — цель не достигнута.
FUNCTION GoToPoint(x, y, accuracy, running)
    # 1. Подготавливаем дополнительные параметры NewMoveXY.
    VAR optimized = TRUE
    # callback=0: пользовательская функция после шагов не вызывается.
    VAR callback = 0
    # timeout — 8000 мс ожидания после принятия маршрута.
    VAR timeout = 8000
    # Лимит замеченных изменений позиции, не точный счётчик клеток.
    VAR maxSteps = 100

    # 2. Встроенная команда строит и исполняет маршрут.
    # При препятствии она может пересчитать его с текущей позиции.
    # Этот вызов ждёт результата. Весь A* здесь не переписывается.
    VAR reached = UO.NewMoveXY(x, y, optimized, accuracy, running, callback, timeout, maxSteps)

    # 3. Передаём полученный 1/0 обратно в Main без повторного движения.
    RETURN reached
END FUNCTION

SUB Main()
    # Учебная цель: три клетки восточнее на текущей карте.
    VAR x = UO.GetX() + 3
    VAR y = UO.GetY()
    # accuracy=0 требует точных X/Y, TRUE запрашивает бег.
    VAR reached = GoToPoint(x, y, 0, TRUE)

    # = TRUE равнозначно = 1. Для отрицания: = FALSE или = 0.
    IF reached = TRUE THEN
        UO.Print('Destination reached')
    ELSE
        UO.Print('Destination not reached')
    END IF
END SUB

Разбор параметров и выполнения:

  • GoToPoint — вспомогательная функция только этого примера. Её четыре параметра x/y/accuracy/running описаны над FUNCTION; полное тело функции находится в том же копируемом блоке.
  • Main вычисляет цель и вызывает GoToPoint. Она добавляет optimized=TRUE, callback=0, timeout=8000 и maxSteps=100, вызывает NewMoveXY один раз и передаёт возвращённый Integer обратно в Main.
  • NewMoveXY является встроенной командой клиента. Её поиск A*, проверка проходимости и обработка серверных шагов реализованы в клиенте, а не в дополнительных скрытых процедурах этого скрипта.
  • В этом примере callback отключён. Если в другом примере задаётся имя callback или вызывается дополнительная функция скрипта, её определение также должно быть приведено целиком.
  • IF reached = TRUE и IF reached = 1 одинаково проверяют успех. FALSE и 0 — отрицательный результат. Аварийная отмена прерывает исполнение и не обязана возвращать FALSE.

Пример 5. Как считаются допуск и стоимость: полный учебный скрипт

# manual-check: movement-cost
# Это учебные вычисления по формулам клиента, а не второй A*.
# Функции ниже НЕ двигают персонажа и НЕ проверяют карту.
# Они объясняют отдельные действия внутри встроенной NewMoveXY.

# Проверка допуска из MoveToCanonical.
# x/y/z — наблюдаемая точка; goalX/goalY/goalZ — цель.
# accuracy: 0..20, accuracyZ: 0..255; здесь они уже подготовлены.
# Возврат: 1=TRUE только при выполнении всех трёх ограничений.
FUNCTION DestinationReached(x, y, z, goalX, goalY, goalZ, accuracy, accuracyZ)
    RETURN ABS(goalX-x) <= accuracy AND ABS(goalY-y) <= accuracy AND ABS(goalZ-z) <= accuracyZ
END FUNCTION

# Формула Pathfinder.GetGoalDistCost для скриптового движения.
# multiplier: минимум 1; Optimized=TRUE берёт moveHeuristicMult,
# по умолчанию 93. Optimized=FALSE передаёт сюда 1.
# Возврат — целая оценка оставшейся стоимости, НЕ число шагов.
FUNCTION GoalEstimate(x, y, goalX, goalY, accuracy, multiplier)
    VAR dx = ABS(goalX-x)-accuracy
    VAR dy = ABS(goalY-y)-accuracy
    IF dx < 0 THEN
        dx = 0
    END IF
    IF dy < 0 THEN
        dy = 0
    END IF
    VAR larger = dx
    VAR smaller = dy
    IF dy > dx THEN
        larger = dy
        smaller = dx
    END IF
    # Прямой шаг: 10; диагональный: 14, отсюда добавка 4.
    # 10.0 и 4.0 не дают переполнить 32-битное целое в умножении.
    # FIX убирает дробную часть как целочисленное деление C#.
    VAR estimate = FIX((10.0*larger + 4.0*smaller)*multiplier/100.0)
    # Такое же ограничение оценки сверху, как внутри клиента.
    IF estimate > 1073741823 THEN
        RETURN 1073741823
    END IF
    RETURN CInt(estimate)
END FUNCTION

# Формула Pathfinder.MovementCost для одного ребра маршрута.
# Направления: 0..7; diagonal: TRUE/FALSE; turnCost: 0..100000.
# Возврат — стоимость ребра. Бег эту формулу не ускоряет.
FUNCTION EdgeCost(previousDirection, nextDirection, diagonal, turnCost)
    VAR cost = 10
    IF diagonal THEN
        cost = 14
    END IF
    IF previousDirection <> nextDirection THEN
        cost = cost + turnCost
    END IF
    RETURN cost
END FUNCTION

SUB Main()
    # (10,10) -> (15,13), accuracy=1: dx=4, dy=2.
    # h = FIX((10*4+4*2)*93/100) = 44.
    VAR estimate = GoalEstimate(10, 10, 15, 13, 1, 93)
    # Поворот 0->1, диагональ и штраф 10: 14+10=24.
    VAR edge = EdgeCost(0, 1, TRUE, 10)
    # Клетка (14,12,20) в допуске цели (15,13,20).
    VAR reached = DestinationReached(14, 12, 20, 15, 13, 20, 1, 0)
    UO.Print('Estimate=44: ' + STR(estimate))
    UO.Print('Edge cost=24: ' + STR(edge))
    UO.Print('Reached=1: ' + STR(reached))
END SUB

Разбор параметров и выполнения:

  • Весь пример самодостаточен: DestinationReached, GoalEstimate, EdgeCost и Main объявлены в одном блоке. ABS/FIX/CInt/STR и UO.Print — зарегистрированные функции runtime.
  • DestinationReached получает восемь параметров и показывает точную проверку допуска. Совпадение X/Y при другой Z не даёт TRUE, если отклонение высоты превышает accuracyZ.
  • GoalEstimate получает X/Y кандидата, X/Y цели, подготовленный допуск и множитель. Убирает уже разрешённый допуск, считает нижнюю оценку стоимости и отбрасывает дробь. Это эвристика h, а не расчёт полного пути: реальные препятствия здесь отсутствуют.
  • EdgeCost получает два направления, признак диагонали и подготовленную цену поворота. При изменении направления добавляется штраф. В клиенте полная стоимость кандидата f = g + h, где g — сумма пройденных рёбер.
  • Main использует условные числа, поэтому пример можно изучать без маршрута и серверных объектов. Вывод должен показать 44, 24 и 1. Он ничего не открывает и не отправляет команд движения.
  • Упрощение явно ограничено тремя формулами. Здесь нет чтения карты, очереди A*, серверного подтверждения или пересчёта. Их реальные внутренние функции разобраны в разделе поведения; сам маршрут выполняйте через NewMoveXY.