Гайд по написанию скриптов для гомункулусов
-
Aiko Star, должен отключаться полностью, но у нас это видимо не введено. Не заметил у моей ванили разницы в скорости регена.
-
как сделать так чтоб ванилка атаковал магией до упора а не только один раз?
Стоит рэмпедж. Агрит магией моментально но потом только кусает((( -
LisandreL
Скачал твои настройки для танцующей атаки , да скорость атаки повыше (думаю будет особенно заметно на больших лвл ,при большом атак спиде),но есть и минусы.
Например реньше он сходу кастовал как подходил теперь непонятно когда каст кинет,правда если начнёт то не остановиться пока СП не кончиться. И ещо он напрач отказыватся атаковать чужих мобов,даже принудительно ничего не выдаёт по мобам.
Ну а вообще конечно респект за скирипт :good: и за то что написал не поленился и выложил на растрзание таким дуракам как я,которые будут вечно чем то недовольны и винить автора. А ведь могбы просто забить и всё...
Разницы в регене СП не заметил.
В идеале хотелось бы достать где нибудь скрипты что бы сказу при виде моба кидал каст. -
@"megar":
Ну а вообще конечно респект за скирипт :good: и за то что написал не поленился и выложил на растрзание таким дуракам как я,которые будут вечно чем то недовольны и винить автора. А ведь могбы просто забить и всё...Спасибо, конечно, на добром слове, но это не я писал:-- Fast attack Mod by Des, aka Zenia-chanМой вариант вылядит так:[code:j72lblfg]function ModInit()
StdOnATTACK_ST = OnATTACK_ST
OnATTACK_ST = FastOnATTACK_ST
end
function FastOnATTACK_ST()
local ex, ey = GetV(V_POSITION, MyEnemy)
local mx, my = GetV(V_POSITION, MyID)
if ((ey + 1) == my) then
Move(MyID,ex,ey-1)
else
Move(MyID,ex,ey+1)
end
StdOnATTACK_ST ()
end[/code:j72lblfg]@"megar":
В идеале хотелось бы достать где нибудь скрипты что бы сказу при виде моба кидал каст.Rampage AI, нэ? -
Покурила наконец-то.
Класс.
Научила ванила автохиляться, когда хп неполные (мелочь, 2.5 строчки, а приятно), осталось научить, когда почти полные хп и сп и делать нечего, леших грызть по одному x) И можно будет уже афкать (пока что всё то же самое тупо вручную делаю, заглядывая время от времени).В рамках подгонки под суровые условия Московии, 55 уровень :pardon:
upd: Я это сделала XD
-
И если кому-нибудь вдруг пригодится.
Знаю, что корявенько, но надо-то оно, пока хом относительно маленький, так ведь? А делать влом. Я себя еле заставила.На базе МирАи, правда. Им, вроде бы, сейчас не очень пользуются? И ещё - не уверена, что после указанных изменений будет корректно работать config.exe. На всякий советую перед экспериментами заархивировать папочку, чтобы потом можно было спокойно всё спасти. Может быть, в каком-нибудь Rampage Ai такие настройки и так есть.
Другими словами, as is, пригодится - хорошо, нет - так нет ^^
Итак...
Вносим интересующих мобов обычным способом. Через конфиг или вручную.
Далее вручную вносим следующие изменения в файлы:Атака с полными хп и сп.
(добавляем строчку в const.lua, которая будет характеризовать новое поведение)
@"const.lua":
BEHA_avoid = 0 -- Escape everytime and don't even help the ownerBEHA_coward = 1 -- Escape when hit, but come to help the owner
BEHA_react_1st = 2 -- Defend only (highest priority) or cooperate
BEHA_react = 3 -- Defend only (medium priority) or cooperate
BEHA_react_last = 4 -- Defend only (low priority) or cooperate
BEHA_attack_1st = 5 -- Aggressive (when HPs are OK), highest priority
BEHA_attack = 6 -- Aggressive (when HPs are OK), medium priority
BEHA_attack_last = 7 -- Aggressive (when HPs are OK), low priority
BEHA_attack_weak = 8 -- Aggressive (weak monster: ignore his attacks), low priority
BEHA_attack_full = 9 -- Agressive, attacks with full hp and sp
Комментарий: наша цель, чтобы хом атаковал именно данный тип "особо сильных" мобов, только будучи как следует живым и здоровым, хотя мелочь мог бы грызть хоть в полудохлом состоянии.(добавляем в config.lua новые управляющие параметры)
@"config.lua":
--------------------------------------------------
-- My Modifiers
--------------------------------------------------
FULL_HP = 700 -- if HP>=MaxHP-FULL_HP then it counts as full
FULL_SP = 40 -- if SP>=MaxSP-FULL_SP then it counts as full
Комментарий:
FULL_HP - если хп хома меньше максимального не более, чем на указанное значение, он будет считать себя достаточно здоровым для атаки на "особо сильного" моба.
FULL_SP - аналогично, но для сп.
Эти параметры можно менять, конечно же.(изменяем поведение для "особо сильных" мобов на созданное нами)
@"config.lua":
Tact[1880] = {"Leshij", BEHA_attack_full, WITH_full_power, 5, 0}(осталось прописать собственно свойства этого поведения в ai.lua. Делаем это в функции "GetMyEnemy_AnyNoKS")
@"ai.lua":
local result = 0
local actors = GetActors ()
local players = {}
local player_idx = 1
local enemy_1st = {} -- primary targets
local index_1st = 1
local enemy_std = {} -- normal targets
local index_std = 1
local enemy_lss = {} -- last targets
local index_lss = 1
local mob_type, mob_target, mobBehav, ListedType
local EnemyMaxHP
local HomunMaxHP = GetV(V_MAXHP, MyID)
local HomunHP = GetV(V_HP, MyID)
local HomunMaxSP = GetV(V_MAXSP, MyID)
local HomunSP = GetV(V_SP, MyID)
Комментарий: задаём используемые переменные.@"ai.lua":
for i,v in ipairs(actors) do
if (v ~= OwnerID) and (v ~= MyID) then -- owner and homunculus aren't valid target, of course
if (IsMonster(v) == 1) and (BlockedPathToEnemyID ~= v) then -- if target is a (reachable) monsterlocal isOKToAttack = false mob_type = GetV(V_HOMUNTYPE, v) -- get tact data mobBehav = GetTact(V_TACTBEHAV, mob_type) %(#FF0000)[-- My!!! Special behavior]
if (mobBehav == BEHA_attack_full) then
if (HomunHP<HomunMaxHP-FULL_HP)
or (HomunSP<HomunMaxSP-FULL_SP) then
mobBehav = BEHA_react
else
mobBehav = BEHA_attack_last
end
endif( (mobBehav == BEHA_attack_1st) or (mobBehav == BEHA_attack) or (mobBehav == BEHA_attack_last) or (mobBehav == BEHA_attack_weak)
Комментарий: здесь мы проверяем: если хому установлено поведение для данного моба, как "атаковать только здоровым", то
- Если хом полон сил, то помечаем моба равносильным мобам "attack_last" (атаковать в последнюю очередь).
- Если хому нездоровится, то моб помечается равносильным мобам "react" (атаковать если атакован или помогая хозяину).
Всё.
С автохилом проще.
В config.lua дописывается строчка:@"config.lua":
-- My Modifiers
FULL_HP = 700 -- if HP>=MaxHP-FULL_HP then it counts as full
FULL_SP = 40 -- if SP>=MaxSP-FULL_SP then it counts as full
AUTOHEAL_HP = 700 -- if HP<MaxHP-FULL_HP then tries to autoheal
Комментарий: хом будет пытаться хиляться, если хп меньше максимума на указанную величину или более.И в функцию ai.lua OnIDLE_ST():
@"ai.lua":
local HomunHP = GetV(V_HP, MyID)
local HomunMaxHP = GetV(V_MAXHP, MyID)
local HomunHPPerc = (HomunHP / HomunMaxHP) * 100
local HomunSP = GetV(V_SP, MyID)
local HomunMaxSP = GetV(V_MAXSP, MyID)
OwnerMotion = GetV(V_MOTION, OwnerID)%(#FF0000)[-- My!!! AutoHeal]
if (HomunHP < HomunMaxHP - AUTOHEAL_HP) and (HomunSP > 41) then
SkillObject(MyID, 5, 8014, MyID)
endКомментарий: тут по-хорошему нужно бы ещё проверить, что мы ваниль ^^' Ну да ладно.
-
Имхо, несколько по-дурацки заданы константы. Во-первых, лучше делать их не абсолютными, а относительными (указывать в процентах, а не в числах). Во-вторых, не проще ли (учитывая "во-первых") не считать разницу, а просто сравнивать текущее хп с константой?
Проверку на ваниль в автохил надо добавить обязательно. Не уверена, но может выдавать ошибки, если другой хомяк.
PS Исправила бы с учетом своих замечаний лично, но очень хочу спать, поэтому креативьте сами х_х -
Aiko Star, не совсем. Самый логичный метод задавать "полноту" (как по мне) - это задавать её как некоторое число недостачи до максимума, поскольку оно характеризует количество тиков регена (того или иного рода), до него необходимых.
Ещё лучше было бы в таком случае задавать её в количестве этих самых тиков и привязать непосредственно к регену (для хп - к хилу) хитрой формулой, но тут уже мне было лень корячиться ^^
Но, конечно, это всё по вкусу, если кому-то логичнее/удобнее/нужнее использовать этот параметр иначе, никто не запретит.
Ах, да. Забыла скопировать. Ещё же задать используемые переменные в ai.lua "GetMyEnemy_AnyNoKS". Сейчас добавлю. Иначе точно ругаться будет ^^Проверка, если кому-нибудь нужно, добавляется, вроде бы, так:
@"ai.lua":
local HomunHP = GetV(V_HP, MyID)
local HomunMaxHP = GetV(V_MAXHP, MyID)
local HomunHPPerc = (HomunHP / HomunMaxHP) * 100
local HomunSP = GetV(V_SP, MyID)
local HomunMaxSP = GetV(V_MAXSP, MyID)
local HomunType = GetV(V_HOMUNTYPE, MyID)
OwnerMotion = GetV(V_MOTION, OwnerID)-- My!!! AutoHeal
if (HomunHP < HomunMaxHP - AUTOHEAL_HP)
and (HomunSP > 41)
and ((HomunType == VANILMIRTH)
or (HomunType == VANILMIRTH2)
or (HomunType == VANILMIRTH_H)
or (HomunType == VANILMIRTH_H2)) then
SkillObject(MyID, 5, 8014, MyID)
end -
Вот, собственно, аналогичная добавочка для настройки % хп и сп, при которых следует атаковать моба.
@"const.lua":
-- Constant |Value|DescriptionBEHA_avoid = 0 -- Escape everytime and don't even help the owner
BEHA_coward = 1 -- Escape when hit, but come to help the owner
BEHA_react_1st = 2 -- Defend only (highest priority) or cooperate
BEHA_react = 3 -- Defend only (medium priority) or cooperate
BEHA_react_last = 4 -- Defend only (low priority) or cooperate
BEHA_attack_1st = 5 -- Aggressive (when HPs are OK), highest priority
BEHA_attack = 6 -- Aggressive (when HPs are OK), medium priority
BEHA_attack_last = 7 -- Aggressive (when HPs are OK), low priority
BEHA_attack_weak = 8 -- Aggressive (weak monster: ignore his attacks), low priority
BEHA_attack_full = 9 -- Agressive, attacks with full hp and sp
BEHA_attack_perc_1st = 10 -- Agressive, attacks monster only when has specified hp and sp level
BEHA_attack_perc = 11 -- Agressive, attacks monster only when has specified hp and sp level
BEHA_attack_perc_last = 12 -- Agressive, attacks monster only when has specified hp and sp level
Комментарий: ещё 3 типа поведения. Чую, надо добавлять численные приоритеты для мобов, чтобы не мучиться, и переписать под них. Всё равно настраиваю без конфига.@"const.lua":
V_TACTBEHAV = 2
V_TACTSKILL = 3
V_TACTLEVEL = 4
V_TACTALCHE = 5
V_TACTHP = 6
V_TACTSP = 7@"config.lua":
Tact[1880] = {"Leshij", BEHA_attack_perc_last, WITH_full_power, 5, 0, 85, 75}
Комментарий: преимущество в том, что можно добавить настройки требуемых хп и сп для каждого моба. Они не используются, если стоит любой из "старых" типов поведения, и их можно не добавлять к каждому мобу (ценой того, что проверка массива Tact производится вне функции MirAI "GetTact", вызываемой для каждого моба).@"ai.lua":
-- My!!! Special behavior
if (mobBehav == BEHA_attack_full) then
if (HomunHP < HomunMaxHP-FULL_HP)
or (HomunSP < HomunMaxSP-FULL_SP) then
mobBehav = BEHA_react
else
mobBehav = BEHA_attack_last
end
end%(#FF0000)[if (mobBehav == BEHA_attack_perc_1st) then]
if (HomunHP100/HomunMaxHP < Tact[mob_type[V_TACTHP])]
or (HomunSP100/HomunMaxSP < Tact[mob_type[V_TACTSP]) then]
mobBehav = BEHA_react_1st
else
mobBehav = BEHA_attack_1st
end
end
%(#FF0000)[]
if (mobBehav == BEHA_attack_perc) then
if (HomunHP100/HomunMaxHP < Tact[mob_type[V_TACTHP])]
or (HomunSP100/HomunMaxSP < Tact[mob_type[V_TACTSP]) then]
mobBehav = BEHA_react
else
mobBehav = BEHA_attack
end
end
%(#FF0000)[]
if (mobBehav == BEHA_attack_perc_last) then
if (HomunHP100/HomunMaxHP < Tact[mob_type[V_TACTHP])]
or (HomunSP100/HomunMaxSP < Tact[mob_type[V_TACTSP]) then]
mobBehav = BEHA_react_last
else
mobBehav = BEHA_attack_last
end
end
Комментарий: то есть, атаковать при набранных хп/сп соответственно, с повышенным/нормальным/пониженным приоритетом. И реагировать с тем же приоритетом. -
Смотрим на позапредыдущий свой пост и видим
local HomunHPPerc = (HomunHP / HomunMaxHP) * 100
После чего с радостью заменяем
if (HomunHP*100/HomunMaxHP < Tact[mob_type][V_TACTHP])
or (HomunSP*100/HomunMaxSP < Tact[mob_type][V_TACTSP]) then
на использование уже созданных переменных.
PS Числовые приоритеты атаки есть в рэмпейдже. -
Aiko Star, она объявлена в другой функции. Интуиция подсказывает мне, что переменная, объявленная, как local, вне пределов функции не выживает x)
Хотя переобъявить её никто не мешает, да. -
Loneliness, интуиция, соглашения о программировании и просто здравый смысл (вместе с капитаном) подсказывают, что многократно (больше одного раза?) повторяющиеся или громоздкие вычисления лучше сводить к переменным
А если эти переменные перетащить куда-нибудь в файл Const.lua и убрать local - ничто не помешает ими пользоваться в любом месте скрипта.
-
Согласна, когда соберусь переписывать MirAi более капитально - займусь.
перетащить куда-нибудь в файл Const.lua и убрать local - ничто не помешает ими пользоваться в любом месте скрипта
Только вот тут не согласна - этим, вообще говоря, лучше не увлекаться. А то можно дойти до того, что все переменные вытащатся наружу, как глобальные, приняв вид OnIDLE_ST_HomunHP. Зато всё везде доступно =_=
-
С константами, собственно, так и поступают. С процентами уже не прокатит (а жаль), т.к. пересчитывать надо постоянно переменную, тут локальные будут лучше.
-
Aiko Star, написала с приоритетами ^^
Переделанная из МирАИшной функция GetMyEnemy_AnyNoKS.
Пока тестирую, но, вроде бы, работает.
Может быть, тоже будут интересные комментарии?..upd: Как бы их с форматированием отобразить ><
@"ai.lua":
function GetMyEnemy_AnyNoKS(myid)
-- Log(string.format("---- AGGRESSIVE SCAN STARTED for ID (%d)", myid)) local result = 0 local actors = GetActors () local players = {} local player_idx = 1 local enemy = {} -- targets local priorities = {} -- target priorities local enemy_idx = 1 local enemy_mp = {} -- targets with maximal priority local enemy_mpidx = 1 local mob_type, mob_target, mobBehav, ListedType local EnemyMaxHP local HomunMaxHP = GetV(V_MAXHP, MyID) local HomunHP = GetV(V_HP, MyID) local HomunMaxSP = GetV(V_MAXSP, MyID) local HomunSP = GetV(V_SP, MyID) local HomunHPPerc = HomunHP*100/HomunMaxHP local HomunSPPerc = HomunSP*100/HomunMaxSP local AttackFlag local AttackPriority local AttackPriorityMax = 0 local AttackDistance for i,v in ipairs(actors) do -- fill the (not "friend") player list if (v ~= OwnerID and v ~= MyID) then if (0 == IsMonster(v)) then if isNotFriend(v) then players[player_idx] = v player_idx = player_idx + 1 end end end end for i,v in ipairs(actors) do if (v ~= OwnerID) and (v ~= MyID) then -- owner and homunculus aren't valid target, of course if (IsMonster(v) == 1) and (BlockedPathToEnemyID ~= v) then -- if target is a (reachable) monster local isOKToAttack = false mob_type = GetV(V_HOMUNTYPE, v) -- get tact data mobBehav = GetTact(V_TACTBEHAV, mob_type) -- Check if we want to attack that dangerous thing AttackFlag = GetAttackFlag(mobBehav) AttackPriority = GetAttackPriority(mobBehav,mob_type) -- AttackFlag = 1 -- Check if that's dangerous to attack in such condition if (mobBehav == BEHA_attack_full) and ((HomunHP < HomunMaxHP-FULL_HP) or (HomunSP < HomunMaxSP-FULL_SP)) then AttackFlag = 0 end if ((mobBehav == BEHA_attack_perc_1st) or (mobBehav == BEHA_attack_perc) or (mobBehav == BEHA_attack_perc_last)) then if ((HomunHPPerc < Tact[mob_type][V_TACTHP]) or (HomunSPPerc < Tact[mob_type][V_TACTSP])) then AttackFlag = 0 end end if (AttackFlag == 1) then -- OK, this a type of monster to attack if isMobMotionOK(v, players) then mob_target = GetV(V_TARGET, v) -- check for the monster's target if (mob_target == 0) then -- if the monster is not in battle isOKToAttack = true -- he/she can be attacked, unless... for i2,v2 in ipairs(players) do if (v == GetV(V_TARGET, v2)) then isOKToAttack = false -- ...another player is already aiming at him/her (anti-KS) break end end else -- else, if the monster is already in battle if (mob_target == MyID) or (mob_target == OwnerID) or (not isNotFriend(mob_target)) or IsMonster2(mob_target) then isOKToAttack = true -- but with me/my owner/a friend, it's OK (anti-KS) end end end end -- AttackPriority = tonumber(0) -- Saving new enemy and its priority to deal later if (isOKToAttack) then AttackPriorityMax = AttackPriority enemy[enemy_idx] = v priorities[enemy_idx] = AttackPriority enemy_idx = enemy_idx + 1 end end end end -- Creating list of priority enemies for i = 1, enemy_idx-1, 1 do if (priorities** >= AttackPriorityMax) then**
** enemy_mp[enemy_mpidx] = enemy****
** enemy_mpidx = enemy_mpidx + 1**
** end**
** end**
** -- Searches for nearest target ---------------**
** result = GetClosest(enemy_mp)**
** if (result == 0) then**
** -- Log("No target in range")**
** else**
** Log(string.format("<aggressive scan> Target found (ID %d):", result))**
** HTact = GetFullTact(GetV(V_HOMUNTYPE, result))**
** end**
** BlockedPathToEnemyID = 0**
** -- Log("---- END OF AGGRESSIVE SCAN")**
** return result**
end
Ну, и вспомогательные. Первая возвращает 1 или 0 в зависимости от того, должен ли хом проявлять к данному типу мобов агрессию, вторая - приоритет моба (вне зависимости от пассивного или агрессивного отношения к оному, пригодится, если соберусь и остальные функции выбора цели переписать):
**> > **@"utils.lua": **--------------------------------------------------
function GetAttackFlag(behav)
-- do we want to attack such a mob
--------------------------------------------------
local AttackFlag = 0
** if ((behav == BEHA_attack_1st) **
** or (behav == BEHA_attack) **
** or (behav == BEHA_attack_last)) then**
** return 1**
** end**
** if (behav == BEHA_attack_full) then**
** return 1**
** end**
** if ((behav == BEHA_attack_perc_1st) **
** or (behav == BEHA_attack_perc) **
** or (behav == BEHA_attack_perc_last)) then**
** return 1**
** end**
** if (behav == BEHA_attack_priority) then**
** return 1**
** end**
return AttackFlag
end
--------------------------------------------------
function GetAttackPriority(behav,mob_id)
-- how much do we want to attack that mob
--------------------------------------------------
local AttackPriority = 0
** if (behav == BEHA_attack_1st) **
** or (behav == BEHA_react_1st)**
** or (behav == BEHA_attack_perc_1st) then**
** return 30**
** end**
** if (behav == BEHA_attack) **
** or (behav == BEHA_react)**
** or (behav == BEHA_attack_perc) then**
** return 20**
** end**
** if (behav == BEHA_attack_last) **
** or (behav == BEHA_react_last)**
** or (behav == BEHA_attack_perc_last)**
** or (behav == BEHA_attack_full) then**
** return 10**
** end**
** if (behav == BEHA_attack_priority) then**
** AttackPriority = Tact[mob_id][V_TACTPRIORITY]**
** end**
return AttackPriority
end
C behav и mob_id, то получаемыми, то раскидываемыми обратно, конечно, не очень красиво. Может, потом причешу. Наследие переделки.
В процессе отладки, поскольку отлаживала по сообщениям из клиента в блокноте, а это неудобно, ещё снесла одну небольшую оптимизацию (и использование двумерного массива 2хN), потом добавлю обратно, как соберусь. Просто опасалась, что именно в этих местах вылеты ^^
Идея такая: сначала создаётся список вражин и их приоритетов, потом из него отфильтровываются вражины с высшим приоритетом (это однозначно быстрее сортировки) и уже они скармливаются МирАИшной GetClosest.
Далее; в оригинальной МирАИ оно ищет ближайших последовательно по всем приоритетам (не находит на старших - ищет на младших). Восстановление этого, видимо, требует введения не if (result == 0), а while (result == 0) - но работает и так, в каких случаях не будет работать - не знаю (функию GetClosest даже не смотрела ещё). Если в итоге так всё же сделаю, проще будет отсортировать ^^
-
подскажите, можно ли сделать в мир аи так, чтоб ванилька не бежала ко мне, а атаковала моба? Пример - я сагрил на себя сирому (которая довольно часто попадает по моему голому химу), как только я пытаюсь кайтить эту сирому, ванилка перестаёт его бить и начинает бегать за мной до моей остановки и только потом начинает бить моба заного. Причём я кайчу не по всей карте естественно а в пределах 5 клеток от ванилки.
-
avs, можно. В файле config.exe на вкладке "дополнительно" сними галочку с пункта "сразу следовать за алхимиком".
-
хм, может тогда кто подскажет, как сделать чтоб сделать аналогичную галочку в Аззи Аи? Т.к. хотя там и есть радиус, при выходе за который гом все бросает и бежит обратно, но при маленьком этом радиусе и достаточно большом радиусе атаки хомяк при атаке цели бегает от алхмика к мобу, а при большом, если хомяк атакует моба, он не успевает нормально среагировать и часто просто напрсто совсем отстает и еряется, приходится за ним возвращаться.
-
Такой вопросик. Как лифку докормлю, конечно, сама потестирую, но всё же вдруг кто (Aiko Star, например :)) знает.
При винге скрипт перегружается - это значит, что глобальные переменные вернутся к дефолтным значениям? Хочу использовать для сбрасывания таймера задержки MC при винге.
Вообще, ещё буду экспериментировать, когда будет, на чём, но было бы интересно попробовать научить лифку со всей возможной эффективностью пользоваться своими 5 минутами из 20 даже без посторонней помощи ^^ Понятно, что полноценного афк-кача от неё вряд ли можно добиться, но пропадать имеющемуся потенциалу тоже не дело.
-
Loneliness, можно сделать сохранение состояния через короткие промежутки времени в отдельный файл и считывания его при перезапуске АИ, чтобы она не смотря на винг помнила когда последний раз кастовался МС. Но это повысит нагрузку на жесткий диск конечно. Когда-то у меня такая вещь под RampageAI для лиф была, но найти смогу наверное только к середине сентября, сейчас нет возможности.
А вообще идет полный перезапуск скрипта, так что должны сбрасываться, если не сохраняются как я описал.