Seaward.ru

Здравствуйте, гость ( Вход | Регистрация )

> Для программистов, вопросы по скриптам ПКМ
igor_pol
сообщение Aug 24 2005, 21:00
Сообщение #1


боцман
****


Группа: форумчанин
Сообщений: 140
Регистрация: 3-December 04
Пользователь №: 169



Первое что я хотел написать "АДМИНЫ!!!!" НЕ ЗВЕРЕЙТЕ ЗА "НЕНУЖНУЮ ТЕМУ"
**************************************************
на вопрос зачем создал эту тему отвечу так "Я например НЕ ПРОСТО ЮЗВЕРЬ А КОЕ ЧТО И САМ НАПИСАТЬ МОГУ.
И хотел бы чтобы на форуме была тема для тех кто сам хочет что-то добавить в игру.
На сайте аддона Алекс вікинул ссылку на описание скриптов ПКМ на английском.
Я хотел бы узнать где можно нарыть больше инфы по этом скриптам.
И кстати на каком языке они пишуться.
Если кто-то знает ----- пишите.
И вообще всем програмерам на форуме нужна своя тема.
так что ГОСПОДА ПРОГРАМЕРЫ ВАЛИТЕ СЮДА !!!!
Может из этого что небудь интересное выйдет!!!!!!(Если тему не УТРУТ)
Жду сообщений (может у когот есть идеи на эту тему )

Сообщение отредактировал Догева - Apr 24 2006, 13:36
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
34 страниц V « < 32 33 34  
Reply to this topicStart new topic
Ответов(660 - 669)
ALexusB
сообщение Oct 16 2020, 09:11
Сообщение #661


Разработчик игры К:ВЛ
*******

Seaward TeamЖелезный Профессор
Группа: Admin
Сообщений: 15,410
Регистрация: 2-November 04
Пользователь №: 3



Поиск по коду рулил
Set_My_Cabin()

User is online!Profile CardPM
Go to the top of the page
+Quote Post
BUKA_E}l{EBUKA
сообщение Oct 16 2020, 09:33
Сообщение #662


юнга
**


Группа: форумчанин
Сообщений: 31
Регистрация: 20-July 20
Пользователь №: 194,252



Чтобы найти Set_My_Cabin, нужно искать по Set_My_Cabin biggrin.gif

Если не горит вотпрямщас, то почему бы не спросить, и заниматься другими делами. Вдруг кто-то знает нужное место/название или поможет сузить круг поиска.

Вот вы сэкономили мне час-два поисков вслепую по словам типа 'cabin' и 'каюта' с просмотром контекста каждой строки из сотен выданных на предмет соответствия искомому. Спасибо!
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
ALexusB
сообщение Oct 16 2020, 09:37
Сообщение #663


Разработчик игры К:ВЛ
*******

Seaward TeamЖелезный Профессор
Группа: Admin
Сообщений: 15,410
Регистрация: 2-November 04
Пользователь №: 3



нужно искать по ключевым словам "Cabin", или открыть Интерфейсы, найти там захват корабля и покопать в сторону его захвата.
"то почему бы не спросить, и заниматься другими делами."
Я пожалуй тоже так буду делать smile.gif

Т.к. "я даю вам не рыбу, а учу ее ловить"
И на аналогичные вопросы ответ будет, как найти, а не сам ответ (или буду заниматься другими делами, что тоже хорошо) smile.gif

Лень - оружие в обе стороны.
User is online!Profile CardPM
Go to the top of the page
+Quote Post
BUKA_E}l{EBUKA
сообщение Oct 16 2020, 11:02
Сообщение #664


юнга
**


Группа: форумчанин
Сообщений: 31
Регистрация: 20-July 20
Пользователь №: 194,252



Цитата
"то почему бы не спросить, и заниматься другими делами."
Я пожалуй тоже так буду делать

Мой мессадж был "ткните меня носом, если знаете куда" а не "найдите за меня, а то мне впадлу". Если я сформулировала так как вы это прочитали, примите мои извинения. Русский не мой родной и я не всегда чувствую дух текста. Не хотела вас обидеть.

Цитата
И на аналогичные вопросы ответ будет, как найти, а не сам ответ

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

В зависимости от направления сайта, его аудитории, возраста/пола/душевного состояния отвечающего, наличия Нептуна в Водолее, тебе могут:
. дать заведомо неверный ответ
. послать нах
. предложить доказать причастность к женскому полу (посему во многих местах я пишу от мужского лица)
. ответить через 3 дня, 2 недели, месяц, 10 лет
. не ответить вообще
Спрашивая в интернете, ты как бы принимаешь подобные условия.
Я не считаю это чем-то ужасным, так уж исторически сложилось. По ту сторону экрана тебе никто ничего не должен.


Цитата
или открыть Интерфейсы, найти там захват корабля и покопать в сторону его захвата

Давайте попробуем, может это и правда легко и быстро.

1. Начнем с Program\INTERFACE\transfer_main.c как самого логичного претендента, т.к. именно там у нас обмен кораблями
2. void SwapProcess(), где-то здесь то что нам нужно
3. Среди ее содержимого три неизвестных функции (SeaAI_SwapShipsAttributes, SeaAI_SwapShipAfterAbordage, WasChangeData), какая-то из них ведет куда надо
4. void WasChangeData сразу смотрим и отметаем
5. void SeaAI_SwapShipsAttributes состоит только из CopyAttributes и DeleteAttribute, никакой информации это нам не несет
6. В bool SeaAI_SwapShipAfterAbordage два пути - UpdateRelations и AI_MESSAGE_SWAP_SHIPS в SendMessage
7. AI_MESSAGE_SWAP_SHIPS - ведет в тупик "#define AI_MESSAGE_SWAP_SHIPS 51014"
8. UpdateRelations - аналогично, к череде #define
9. DEAD END

Ради интереса, пойдем от противного.
Попробуем раскопать цепь событий ведущих к Set_My_Cabin от нее самой
1. Поиск по функции - 3 результата, дебаг исключаем
2. Варианты - void Sea_CabinStartNow() в Cabin.c и void Sea_DeckStartNow() в Deck.c
3. Копаем от Sea_CabinStartNow, ведь в названии фигурирует каюта
4. Вызывается она в двух местах: void BI_LaunchCommand() (BattleInterface.c) и void QuestComplete (quests_reaction.c). По идее, нам нужна первая
5. В void BI_LaunchCommand() нужная нам Sea_CabinStartNow вызывается через switch(commandName) кейсом BI_Cabin.
Откуда берется commandName? Из EventData, конечно!
Сама BI_LaunchCommand вызывается одноименным ивентом, поиск по котором выдает единственное совпадение в которм присутствуют параметры - Event("BI_LaunchCommand","lsls", charIdx, "BI_SailTo", targetNum, locName); что нам по идее не очень подходит.
DEAD END

Я конечно могла где-то свернуть не туда или что-то упустить, но я и не знакома ни с кодом ВМЛ, ни с языком его скриптов настолько хорошо насколько знакомы с этим вы.

Так что мне бы оставалось только искать нотепадом++ по cabin в папке Program, перебирая все 394 hits in 29 files в надежде что нужный мне кейворд именно cabin.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Verdugo
сообщение Oct 21 2020, 20:39
Сообщение #665


новичок
*


Группа: форумчанин (*)
Сообщений: 9
Регистрация: 22-August 20
Пользователь №: 198,224



Цитата
Доброго времени суток!
Я случайно увидел твои сообщения на сивардовском форуме, где ты описываешь непонятную работу эвента NPC_Event_EnableStun в ККС.
Дело в том, что у меня тоже трудности с этим местом, а логи выдают информацию, которая с трудом поддаётся интерпретации.
В общем, я хотел бы поинтересоваться, не получилось ли у тебя в итоге разобраться с обработкой этого эвента?


Здравствуйте. Нет, способа как это сделать я не нашел.
Вероятно, для того чтобы сделать динамическое изменение стана ГГ, без правок в движке не обойтись. Надеюсь, что это будет добавлено в грядущем патче от БМС.
Я тогда заметил, что NPC_Event_EnableStun действует на анимации hit_attack и hit_fire, но не действует на hit_feint. Но поиск по скриптам, опять же, ничего не дал.

Там рядом еще был момент интересный, связан с распределением атакующих весов для NPC. Эти функции опрашиваются разово при загрузке локации, для всех персонажей в локации (включая ГГ) То есть, если ваш абордажник зайдет в локацию с топором, ему будут прописаны веса согласно chr_ai.fencingtype = FencingH. Если после этого вы оденете ему рапиру и вступите в бой, до смены локации абордажник будет намахивать шпагой как топором.

CODE

float npc_return_tmp;
bool npc_return_tmpb;

//Вес выбора удара "fast", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightFast","LAi_NPC_GetAttackWeightFast");
float LAi_NPC_GetAttackWeightFast()
{
aref chr = GetEventData();
npc_return_tmp = 20.0 * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingL", 1.0, 3.0);
npc_return_tmp = npc_return_tmp * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingH", 1.0, 0.5);
npc_return_tmp = npc_return_tmp * (0.8 + (0.1 * MOD_SKILL_ENEMY_RATE));
return npc_return_tmp;
}

//Вес выбора удара "force", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightForce","LAi_NPC_GetAttackWeightForce");
float LAi_NPC_GetAttackWeightForce()
{
aref chr = GetEventData();
npc_return_tmp = 50.0 * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingS", 1.0, 3.0);
npc_return_tmp = npc_return_tmp * (0.8 + (0.1 * MOD_SKILL_ENEMY_RATE));
return npc_return_tmp;
}

// boal 20.01.08 коммент - забавно, что спустя два года, понал как и что с вероятностями.
Они все приводятся к 0-1 от веса общей суммы, то есть фактически
умножение на сложность или цифры распределяют сумму по другим акшенам, а не усиливают этот
// Экшены идут парами - все атаки и защита (блок + пари)


Интересно, что в ККС "fast" - это рубящие атаки, а "force" - атаки выпадом.
При расчете дамага это учтено, а здесь выходит, что саблист - самый часто колющий NPC.
Может быть, есть знающий человек, кто сможет подсказать как работают эти веса?

CODE

Смелый флибустьер:

Рапиры/Шпаги - Fight Level: 1.00
Рубящий (fast) 84.0
Колющий (force) 70.0
Круговой (round) 28.0
Пробивающий (break) 12.0
Финт (feint) 12.0

Сабли/Тесаки - Fight Level: 1.00
Рубящий (fast) 28.0
Колющий (force) 210.0
Круговой (round) 28.0
Пробивающий (break) 24.0
Финт (feint) 12.0

Палаши/Топоры - Fight Level: 1.00
Рубящий (fast) 14.0
Колющий (force) 70.0
Круговой (round) 28.0
Пробивающий (break) 72.0
Финт (feint) 12.0

Отчаянный корсар:

Рапиры/Шпаги - Fight Level: 1.00
Рубящий (fast) 108.0
Колющий (force) 90.0
Круговой (round) 36.0
Пробивающий (break) 16.0
Финт (feint) 16.0

Сабли/Тесаки - Fight Level: 1.00
Рубящий (fast) 36.0
Колющий (force) 270.0
Круговой (round) 36.0
Пробивающий (break) 32.0
Финт (feint) 16.0

Палаши/Топоры - Fight Level: 1.00
Рубящий (fast) 18.0
Колющий (force) 90.0
Круговой (round) 36.0
Пробивающий (break) 96.0
Финт (feint) 16.0


У саблиста сумма весов на треть больше, чем у других классов.
Тестировал на даньке с анимацией К3/КСМ, т.к. на дефолтной анимации нельзя просто взять и отличить колющий от рубящего.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Stor
сообщение Oct 21 2020, 23:34
Сообщение #666


новичок
*


Группа: Members
Сообщений: 2
Регистрация: 21-October 20
Пользователь №: 205,686



Цитата(Verdugo @ Oct 21 2020, 20:39) *

Здравствуйте. Нет, способа как это сделать я не нашел.
Вероятно, для того чтобы сделать динамическое изменение стана ГГ, без правок в движке не обойтись. Надеюсь, что это будет добавлено в грядущем патче от БМС.
Спасибо за ответ. С этой функцией вообще много странностей. К примеру, при выводе логов для нпс всё выводится корректно, а вот если поставить принудительный вызов эвента каждый фрейм для ГГ, то для него в логах будет выводиться попеременно истина и ложь, без повторений. То есть, даже если вероятность значения "истина" равна одной десятитысячной, на экран будет выведено только одно сообщение "ложь" (а не тысячи подряд), а следующее за ним будет обязательно "истина", пусть и через заметный промежуток времени, и сразу опять "ложь".
Также наблюдается проблема с проверкой условий типа (chr == GetMainCharacter()) - они просто пробрасываются, автоматически считаясь в этой функции за истинные. Мало того, если условие объединено логическим оператором && с другим, пробрасываются оба условия. При этом условие типа (sti(chr.index) == GetMainCharacterIndex()) обрабатывается нормально. Я понимаю, что ресурсы для вызова этих функций требуются разные, но вместо ошибки памяти или тормозов вся строчка if просто игнорируется.

То, что в случае ГГ эта функция после загрузки локации уже ни на что не влияет, ещё объяснимо: возможно, "загрузочное" значение перезаписывается в другую переменную, и в дальнейшем при обработке эвента на получение удара берётся уже оттуда. Но получается, этот эвент с MainCharacter в принципе не дружит и что-то там лочит, вызывая, например, помимо этой функции ещё и ряд других, прописанных в движке.
Цитата

Я тогда заметил, что NPC_Event_EnableStun действует на анимации hit_attack и hit_fire, но не действует на hit_feint. Но поиск по скриптам, опять же, ничего не дал.
Ну да, это анимации, вызов которых происходит где-то в движковой части. Тут даже для функции расчёта возможности стана свой эвент прописан.
Цитата

Там рядом еще был момент интересный, связан с распределением атакующих весов для NPC. Эти функции опрашиваются разово при загрузке локации, для всех персонажей в локации (включая ГГ) То есть, если ваш абордажник зайдет в локацию с топором, ему будут прописаны веса согласно chr_ai.fencingtype = FencingH. Если после этого вы оденете ему рапиру и вступите в бой, до смены локации абордажник будет намахивать шпагой как топором.
Вот этой особенности не заметил, спасибо)
Цитата
Интересно, что в ККС "fast" - это рубящие атаки, а "force" - атаки выпадом.
При расчете дамага это учтено, а здесь выходит, что саблист - самый часто колющий NPC.
Думаю, это обычная ошибка или недоработка. Эта функция вообще особо ни к чему реальному не привязана. Она не определяет оптимальный тип удара, не проверяет ни параметры оружия, ни что-либо ещё, только тип оружия, да ещё и близко не с теми коэффициентами, что указаны в формулах урона. До ККС у оружия не было профильного типа удара, поэтому и учитывать было нечего, были только базовые значения 20/50/20/20/10 и ничего не меняющая привязка к сложности.

В коде есть ещё пара мест, странным образом привязывающих тип клинка к непрофильному удару. Например, перк HardHitter, дающий бонусы выпадам для СТ и рубящим для РШ. Хотя, может, таким образом хотели отвести внимание игроков от профильных ударов? Чтобы, мол, игрок мог выбрать, потратить свою энергию на нанесение урона рубящим ударом или на снятие 10% энергии противника выпадом практически без урона. Ну, по такой логике можно и преобладание выпадов для нпс-саблистов обосновать тем, что это и так самый быстрый удар, а подкреплённый высоким уровнем навыка и хорошим клинком, ещё и с увеличенной вероятностью от ГГ просто куски мяса отрезать будет.
Цитата

У саблиста сумма весов на треть больше, чем у других классов.
Тестировал на даньке с анимацией К3/КСМ, т.к. на дефолтной анимации нельзя просто взять и отличить колющий от рубящего.
Сумма весов ни на что особо не влияет, такая система обычно используется для более удобного задания соотношений связанных общей суммой параметров. На реальные проценты выпадения влияет именно соотношение весов. И 100 из 200, и 150 из 300 приведутся к 50% - никакой разницы математически нет.
Цитата

Может быть, есть знающий человек, кто сможет подсказать как работают эти веса?
Ну, программировал их, судя по всему, AlexusB, так что теоретически он мог бы прояснить нам абсолютно всю базу. Но пока он не ответил, могу выложить свою статистику. Расчётный вес немного не соответствует наблюдаемым соотношениям в самой игре, очевидно, где-то ещё в движке дообрабатываясь. У меня, например, получилась такая картина с учётом типа оружия и уровня энергии атакующего персонажа (прошу прощения, спойлеров на форуме не нашёл):
Изображение
Эта статистика (также прошу прощения за вырвиглазное оформление, у меня на тот момент гигнулся d3d8, поэтому я быстренько перенастроил вывод на стандартные переменные) вызывает пару вопросов.

Во-первых, при низком (<=20%) уровне энергии идёт резкое преобладание выпадов. Это можно объяснить тем, что выпад тратит меньше энергии, поэтому в ситуации, когда для остальных ударов энергии ещё недостаточно, их использование пробрасывается, тогда как выпавшие выпады (невольный каламбур) спокойненько проходят. Также каждую секунду желание (то есть, вероятность) атаковать возрастает (в зависимости от навыка владения оружием, кстати), поэтому очередь выпада если и пропускается, то крайне редко. А ещё есть небольшая вероятность (8,6%), что при невозможности добраться до близкой цели нпс наугад совершит выпад, что тоже может влиять на мою статистику.

Во-вторых, соотношения ударов для остальных уровней энергии хоть и идут весьма ровно, но всё равно отличаются от теоретических значений в пользу выпадов для РШ и пробивающих для ПТ. Для наглядности я скомпоновал данные в процентах для энергии >20%, а в скобках привёл теоретические вероятности:
РШ рубящий - 42% (51%), выпад - 48% (42%), пробивающий - 10% (7%);
СТ рубящий - 8% (11%), выпад - 82% (80%), пробивающий - 10% (9%);
ПТ рубящий - 6% (10%), выпад - 45% (45%), пробивающий - 49% (45%).
В процентах разница небольшая, но для выборки в пару тысяч ударов каждым типом оружия это всё же ощутимо. Можно было бы попытаться объяснить это заложенным преимуществом для "родного" типа удара, если бы не удручающая статистика по СТ, где никакого бонуса для рубящего удара нет и в помине. Что, конечно, тоже может объясняться ошибкой перепутывания fast и force, но сколько можно на это сваливать)
В любом случае, либо я просто недостаточно стоял под градом ударов в Ле Франсуа, либо чего-то не учёл, либо эти функции для определения веса - ещё не всё, что влияет на выбор удара (хоть и имеют явно определяющее значение).
Однако в целом всё довольно понятно, хоть и жаль, что реально вызывается только при загрузке локации. Будет время, поменяю формулы на заготовленные (с показательной функцией для сложности) и ещё попроверяю.

Да, всё описанное - моё имхо, и я вполне могу ошибаться в любом из своих выводов, так что людей, реально знающих то, что я лишь предполагаю, призываю не серчать, а объяснить мне мою ошибку.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
AVL
сообщение Oct 22 2020, 08:46
Сообщение #667


новичок
*


Группа: форумчанин (*)
Сообщений: 4
Регистрация: 19-October 20
Пользователь №: 205,436



Доброго времени суток!

Крик о помощи. smile.gif
Опытные и бывалые, помогите, пожалуйста, неофиту. Мой вопрос в теме КВЛ.

P.S. Прошу модераторов и админов простить меня за оффтоп - поиск у меня почему-то не работает, личное сообщение тоже отправить не смог. То ли не разобрался, то ли у меня эти функции не работают. Поэтому нашёл живую тему и запостил здесь.
Очень прошу не убивать этот пост сразу, потерпеть его пару дней - за это время, надеюсь, кто-нибудь подскажет мне в той теме.
Спасибо.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Verdugo
сообщение Oct 23 2020, 00:16
Сообщение #668


новичок
*


Группа: форумчанин (*)
Сообщений: 9
Регистрация: 22-August 20
Пользователь №: 198,224



Цитата

Также наблюдается проблема с проверкой условий типа (chr == GetMainCharacter()) - они просто пробрасываются, автоматически считаясь в этой функции за истинные.

Если честно, не понимаю, как это должно работать. ref GetMainCharacter возвращает ссылку на characters[1].
Цитата

int CreateEntity(object& object_reference, string class_name); // bind entity to object, return 0 if failed
Code send entity id "i" to script and it cames as aref variable into script (GetEventData())

А что такое chr? В syntax.txt написано, что id сущности, (связанной с объектом characters, по всей видимости) поступающий в скрипты как aref GetEventData().
Можно ли их вообще проверять на равенство?
Цитата

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

Когда тестировал, все гадал - учитывается ли значение для кругового удара, если противник один. Или же он до расчета не допускается вообще.
Цитата

В любом случае, либо я просто недостаточно стоял под градом ударов в Ле Франсуа, либо чего-то не учёл, либо эти функции для определения веса - ещё не всё, что влияет на выбор удара (хоть и имеют явно определяющее значение).

Я так досконально не тестировал.) Мне хотелось, чтобы данька научилась махать стортой как следует. По дефолту она машинку зингер включает. biggrin.gif
И чтобы NPC с топорами/секирами не атаковали выпадом. Пока так оставил:

feint - - break - - thrust - - cut - - round

FencingL - - 15 - - 15 - - 60 - - 10 - - "10"

FencingS - - 10 - - 30 - - 10 - - 50 - - "10"

FencingH - - 10 - - 40 - - 25 - - 25 - - "10"

Axe Type - - 10 - - 50 - - 00 - - 40 - - "10"


CODE


bool is_weapon_axe(aref actor)
{
if(CheckAttribute(actor, "equip.blade"))
{
string blade_type = actor.equip.blade;
return HasSubStr(blade_type, "topor");
}
return false;
}

float pref;

//Вес выбора рубящего удара "fast", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightFast","LAi_NPC_GetAttackWeightFast");
float LAi_NPC_GetAttackWeightFast()
{
aref chr = GetEventData();
switch(chr.chr_ai.fencingtype)
{
case "FencingL": pref = 10.0; break;
case "FencingH": pref = 25.0; break;
default: pref = 50.0; break;
}
if(is_weapon_axe(chr)) pref = 40.0;
return pref;
}

/* if(chr.chr_ai.group == "player")
{
log_info(GetFullName(chr) + " - Fencing: " + XIStr(chr.chr_ai.fencingtype) +
" - Fight Level: " + FloatToString(LAi_GetCharacterFightLevel(chr),2));
log_info("is weapon axe: " + is_weapon_axe(chr));
log_info("Рубящий: " + FloatToString(pref,1));
} */

//Вес выбора колющего удара "force", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightForce","LAi_NPC_GetAttackWeightForce");
float LAi_NPC_GetAttackWeightForce()
{
aref chr = GetEventData();
switch(chr.chr_ai.fencingtype)
{
case "FencingL": pref = 60.0; break;
case "FencingH": pref = 25.0; break;
default: pref = 10.0; break;
}
if(is_weapon_axe(chr)) pref = 0.0;
return pref;
}

// if(chr.chr_ai.group == "player") log_info("Колющий: " + FloatToString(pref,1));

//Вес выбора удара "round", 0 - никогда не выбирать, если врагов <3 то удар не выбирается
#event_handler("NPC_Event_GetAttackWeightRound","LAi_NPC_GetAttackWeightRound");
float LAi_NPC_GetAttackWeightRound()
{
aref chr = GetEventData();
pref = 10.0;
return pref;
}

//Вес выбора удара "break", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightBreak","LAi_NPC_GetAttackWeightBreak");
float LAi_NPC_GetAttackWeightBreak()
{
aref chr = GetEventData();
switch(chr.chr_ai.fencingtype)
{
case "FencingL": pref = 15.0; break;
case "FencingH": pref = 40.0; break;
default: pref = 30.0; break;
}
if(is_weapon_axe(chr)) pref = 50.0;
return pref;
}

// if(chr.chr_ai.group == "player") log_info("Пробивающий: " + FloatToString(pref,1));

//Вес выбора удара "feint", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightFeint","LAi_NPC_GetAttackWeightFeint");
float LAi_NPC_GetAttackWeightFeint()
{
aref chr = GetEventData();

if(LAi_GetBladeFencingType(chr) == "FencingL") pref = 15.0;
else pref = 10.0;
return pref;
}
// if(chr.chr_ai.group == "player") log_info("Финт: " + FloatToString(pref,1));

User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Slayer
сообщение Oct 27 2020, 21:08
Сообщение #669


юнга
**


Группа: форумчанин (*)
Сообщений: 11
Регистрация: 2-September 20
Пользователь №: 199,708



=== Я так досконально не тестировал.) Мне хотелось, чтобы данька научилась махать стортой как следует.===
=================================================================
ну вот я например сделал выбор ударов так - ( если я вас правильно понял)
Код
//Вес выбора удара "fast", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightFast","LAi_NPC_GetAttackWeightFast");
float LAi_NPC_GetAttackWeightFast()
{
    aref chr = GetEventData();
    if (chr.chr_ai.group == LAI_GROUP_PLAYER && chr.chr_ai.FencingType == "FencingL")// лесник . приоритет для абордажников
    {
    npc_return_tmp = 40.0 * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingL", 1.0, 3.0);
    npc_return_tmp = npc_return_tmp * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingH", 1.0, 0.5);
    npc_return_tmp = npc_return_tmp * (0.8 + (0.1 * MOD_SKILL_ENEMY_RATE));
    }
    else
    {        
    npc_return_tmp = 20.0 * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingL", 1.0, 3.0);
    npc_return_tmp = npc_return_tmp * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingH", 1.0, 0.5);
    npc_return_tmp = npc_return_tmp * (0.8 + (0.1 * MOD_SKILL_ENEMY_RATE));
    }
    return npc_return_tmp;
}
Код
//Вес выбора удара "break", 0 - никогда не выбирать
#event_handler("NPC_Event_GetAttackWeightBreak","LAi_NPC_GetAttackWeightBreak");
float LAi_NPC_GetAttackWeightBreak()
{
    aref chr = GetEventData(); // лесник приоритет для абордажников
    if (chr.chr_ai.group == LAI_GROUP_PLAYER && GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE) == "topor_01" || GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE) == "topor_02" ||
         GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE) == "topor_03" || GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE) == "topor_04" ||
         GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE) == "topor_05" || GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE) == "topor_06")    
    {
    npc_return_tmp = 100.0 * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingH", 1.0, 3.0);
    npc_return_tmp = npc_return_tmp * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingL", 1.0, 0.5);
    npc_return_tmp = npc_return_tmp * (0.6 + (0.1 * MOD_SKILL_ENEMY_RATE));
    }    
    else
    {    
    npc_return_tmp = 40.0 * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingH", 1.0, 3.0);
    npc_return_tmp = npc_return_tmp * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingL", 1.0, 0.5);
    npc_return_tmp = npc_return_tmp * (0.6 + (0.1 * MOD_SKILL_ENEMY_RATE));
    }
    return npc_return_tmp;
}
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Stor
сообщение Oct 29 2020, 09:40
Сообщение #670


новичок
*


Группа: Members
Сообщений: 2
Регистрация: 21-October 20
Пользователь №: 205,686



Цитата
Если честно, не понимаю, как это должно работать. ref GetMainCharacter возвращает ссылку на characters[1].
А что такое chr? В syntax.txt написано, что id сущности, (связанной с объектом characters, по всей видимости) поступающий в скрипты как aref GetEventData().
Можно ли их вообще проверять на равенство?

Интересное предположение. Вообще как только мы обращаемся к уже определённой ссылке, мы обращаемся к объекту напрямую. И если сущность связана с объектом, то при проверке на равенство ссылок на них должна выводиться истина, поскольку адрес объекта одинаковый. Честно говоря, не вижу никаких препятствий сравнивать их адреса.
В chr же явно записывается ссылка не на конкретный атрибут id, а на сам объект, иначе проверка на равенство дочерних атрибутов тоже выдавала бы ошибку. Да и в других местах такое сравнение работает, проблемы возникают только при слишком частом обращении, как я понял. Например, можно поставить в LAi_CharacterAttack() в файле LAi_events следующие строчки:
CODE
void LAi_CharacterAttack()
{
aref attack = GetEventData();
aref enemy = GetEventData();
if (attack == GetMainCharacter())
{
Log_SetStringToLog("Атакует ГГ");
}
...
}

- и этот лог будет действительно выводиться только при атаке ГГ.
Если бы сравнение было в принципе некорректным, могла бы выползти ошибка или автоматом выдавалась бы ложь, но вместо этого вся строчка с if пропускается вообще. Хотя это может быть особенностью Шторма.
Полагаю, что это пояснение насчёт id сущности говорит только о том, что происходит до действия функции GetEventData(), а в ней ссылка на id преобразуется в ссылку на сам объект. Единственное, странно, что в таких случаях используется aref, а не ref, потому что синтаксис такого не допускает.

Цитата
Когда тестировал, все гадал - учитывается ли значение для кругового удара, если противник один. Или же он до расчета не допускается вообще.

Никакой практической разницы между этими подходами нет. Соотношение весов остальных ударов будет одинаковым, а следовательно, и теоретическая вероятность их выпадения. Если ты, например, вытягиваешь из колоды карты по одной и говоришь какое-то отдельное слово для каждой конкретной масти, а для бубновых карт никаких действий нет, то на выходе последовательность произнесённых слов будет одинаковой вне зависимости от того, есть ли бубновые карты в колоде.
Так что любая реализация - сначала вычисляется вес кругового, потом проверяется количество противников, или сначала проверяется количество противников, и в случае истины вычисляется вес кругового - ведёт к одинаковому результату.


Цитата
Я так досконально не тестировал.) Мне хотелось, чтобы данька научилась махать стортой как следует. По дефолту она машинку зингер включает. biggrin.gif
И чтобы NPC с топорами/секирами не атаковали выпадом. Пока так оставил:

feint - - break - - thrust - - cut - - round

FencingL - - 15 - - 15 - - 60 - - 10 - - "10"

FencingS - - 10 - - 30 - - 10 - - 50 - - "10"

FencingH - - 10 - - 40 - - 25 - - 25 - - "10"

Axe Type - - 10 - - 50 - - 00 - - 40 - - "10"

Я ещё изрядно потестировал это дело и выявил все проблемы своей предыдущей статистики. Дело в том, что я вёл учёт ударов на этапе вычисления урона, поэтому удары, не пришедшиеся в хитбокс, не учитывались. А в гуще сражения это приводило к тому, что у противников, стоящих на небольшом расстоянии от цели, рубящие удары немного не доставали до ГГ и не входили в статистику, тогда как выпады и пробивающие доставали и проходили. Также сыграло роль то, что я стоял в окружении врагов с убранным в ножны оружием. При этом физический размер уменьшается, и бывают случаи, когда противник одним пробивающим или выпадом задевал сразу ГГ и стоящего за ним коллегу - в итоге для этих типов ударов засчитывалось сразу два попадания подряд. И ещё одна проблема заключалась в том, что в момент первоначальной генерации персонажей их оружие автоматически считается за среднее, и только повторная загрузка локации присваивала каждому персонажу его действительный расчётный вес.
Как только я от этих проблем избавился, то статистика по рубящим, пробивающим и выпадам сразу стала соответствовать матожиданию)

А для себя лично я ввёл систему, которая, во-первых, отталкивается от реальных формул урона и пытается вычислить самый эффективный тип удара, во-вторых, с повышением уровня сложности учитывает всё больше влияющих на урон факторов, и, в-третьих, с увеличением сложности увеличивает относительный вес более эффективных ударов, чтобы персонажи чаще пользовались ими. Раньше модификаторы уровня сложности не работали, поскольку являлись множителями (и, соответственно, не изменяли соотношение весов), и я сделал их показателями степени. Также я ради интереса поменял оптимальные значения баланса в формулах на когда-то упомянутые 0.0-0.35-1.2-1.65-2.0.

CODE
float LAi_NPC_GetAttackWeightForce()
{
aref chr = GetEventData();
npc_return_tmp = 100.0;
ref blade = ItemsFromID(GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE));
float degDifficulty = 1.0 + 0.1*MOD_SKILL_ENEMY_RATE; // ВП - 1.2, ОП - 1.4, СФ - 1.6, БК - 1.8, ОК - 2.0
float kFencingType = 1.0;
float kLengthCurve = 1.0;
float kBalance = 1.0;
float kPerk = 1.0;
float kItem = 1.0;
if (MOD_SKILL_ENEMY_RATE >= 4)
{
kFencingType = kFencingType * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingS", 1.0, 0.6);
kFencingType = kFencingType * LAi_NPC_GetAttackPreferenceWeight(chr, "FencingH", 1.0, 0.5);
}
// if (MOD_SKILL_ENEMY_RATE >= 6)
// {
// if(CheckCharacterPerk(chr, "<название способности, влияющей на урон выпадом>"))
// {
// kPerk = kPerk*<эффект способности>;
// }
// }
if (MOD_SKILL_ENEMY_RATE >= 8)
{
kLengthCurve = stf(blade.lenght) / stf(blade.curve);
}
if (MOD_SKILL_ENEMY_RATE == 10)
{
kBalance = 1.25 - abs(stf(blade.Balance) - 0.35) * 0.3;
// if(IsEquipCharacterByArtefact(chr, "<название предмета, влияющего на урон выпадом>"))
// {
// kItem = kItem*<эффект предмета>;
// }
}
npc_return_tmp = npc_return_tmp*pow(kFencingType*kPerk*kLengthCurve*kBalance*kItem, degDifficulty); // возведение коэффициентов в степень degDifficulty
return npc_return_tmp;
}
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

34 страниц V « < 32 33 34
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 17th January 2021 - 21:55
Яндекс цитирования Rambler's Top100
Rambler's Top100