Ил-2 Штурмовик: Битва за Британию. Скрипты. FAQ

Материал из АвиаВики
Перейти к: навигация, поиск

Содержание

Инструменты отладки при работе со скриптами и .dll


Questionsymbol.png Вопрос: В случае более-менее сложного скрипта, какие инструменты отладки можно использовать?

Exclamationmark.png Ответ:

К сожалению, похоже, что кроме собственной головы - никаких. Если кто найдет обратное, буду очень признателен.
Почти наверняка влияет вот эта строчка - //-$debug, но я с ней пока не экспериментировал.
Я делаю так - запускаю студию, новый проект любой C#. Прилинковал к проекту:
...\Steam\SteamApps\common\il-2 sturmovik cliffs of dover\parts\core\part.dll
...\Steam\SteamApps\common\il-2 sturmovik cliffs of dover\parts\core\maddox.dll
...\Steam\SteamApps\common\il-2 sturmovik cliffs of dover\parts\core\gameWorld.dll
...\Steam\SteamApps\common\il-2 sturmovik cliffs of dover\parts\core\gamePlay.dll
...\Steam\SteamApps\common\il-2 sturmovik cliffs of dover\parts\bob\Campaign.dll
Подозреваю, что не все эти сборки необходимы, но особо туда не лез, пусть будут. Последняя же нужна только для миссий из кампании.
Создал класс, в using прописал необходимый минимум
using System;
using maddox.game;
using maddox.game.world;
После код просто копирую в игру. Единственное убираю неймспейс моего проекта. Не самая удобная штука, но писать вполне можно.



Обозначение групп с номерами I и V

Questionsymbol.png Вопрос: Как определить, имеется ли самолет какой-либо группы в данный момент или нет? У немцев названия группы содержат знаки (|, ||, |||, |V, V, V|) и так далее. Но, при написании скрипта игра подобные знаки игнорирует. С англичанами проблем нет, у них обозначения цифровые, например 218Sqn. А вот у немцев обозначения типа JG51_| и игра их не видит

Exclamationmark.png Ответ:

Пример из игры -"BoB_LW_JG53_I"
1 - латинская буква "I", 5 -латинская "V", 10 - латинская "X" и т.д... Собственно про эти римские цифры можно посмотреть на сайте wikipedia.org




Как отслеживать статики?

Questionsymbol.png Вопрос: Как отследить статики? Они не являются AiActor (по крайней мере события на них не реагируют - уничтожен, поврежден и т.д.). Ни в Battle, ни в GamePlay методов никаких похожих тоже нет. GamePlay.gpActorByName("StaticName") тоже ничего не дает. Отследить уничтожение статика(ов) удалось только повесив на них триггер.

Exclamationmark.png Ответ:

Да, статики, это не акторы, у них нет "мозга", и они для красоты стоят, событий не вызывают.

MissionNumberListener и присвоение номера миссии

Questionsymbol.png Вопрос: Что есть поле MissionNumberListener? Пробовал присваивать номер свежезагруженной миссии - вообще всякие события вызывать перестало (в этой миссии).

Exclamationmark.png Ответ:

Это поле, которое показывает события какой миссии скрипт миссии слушает - при загрузке миссии в это поле ставится её номер - т.е. она "слышит" только свои события. Если выставить номер другой миссии - будет "слушать" только её, чтобы все миссии слышать - поле в меньше нуля выставить надо (то есть "-1").



Как убирать с земли самолеты, которые сели на вынужденную или разбились?

Questionsymbol.png Вопрос: Как убирать с земли самолеты, которые сели на вынужденную, разбились не долетев до посадки?

Exclamationmark.png Ответ:

public override void OnAircraftCrashLanded(int missionNumber, string shortName, AiAircraft aircraft)
   {
       base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
       Timeout(5, () =>
       {
           aircraft.Destroy();
       });
   }

Подробнее скрипт удаления самолетов здесь.

Что такое airport.cpp

Questionsymbol.png Вопрос: Если увеличить радиус airport.cpp до 10000, будет ли это убирать обломки с земли/самолеты на вынужденной во всем радиусе действия? Чем грозит такое увеличение радиуса? Каков верхний предел? 50000, 100000 будет работать?

Exclamationmark.png Ответ:

naryv: airport.cpp не убирает самолёты и обломки, он должен машинки к севшим самолётам подвозить, но не уверен что работает, это очень старый скрипт, как реликт скорее всего остался.



Отправка сообщений для заданной армии и типа самолета (истребитель/бомбардировщик)

Questionsymbol.png Вопрос: Как видоизменить код, чтобы надписи в момент подгрузки под-миссий были разные для синей и для красной стороны, а также для истребителей и бомбардировщиков?

Exclamationmark.png Ответ:

Определить армию игрока и выдавать ему соответствующее сообщение:
if (aircraft != null)
       switch (aircraft.Army())
       {                
           case 1:
               if (aircraft.Type() == AircraftType.Bomber)
               { GamePlay.gpHUDLogCenter(new Player[] {player},"Red Bomber, Bomb it all, hitler caput"); }
               else { GamePlay.gpHUDLogCenter(new Player[] { player }, "Red Fighter, fight them all"); }
               break;
           case 2:
               if (aircraft.Type() == AircraftType.Bomber)
               { GamePlay.gpHUDLogCenter(new Player[] { player }, "Das bomber!"); }
               else { GamePlay.gpHUDLogCenter(new Player[] { player }, "Das jager!"); }
               break;
       }

Подробнее здесь.

Имена групп

Questionsymbol.png Вопрос: Имена групп. Проигрывается одна и та же миссия, получаем имя группы (например, убитого самолета)- в одних случаях получается имя как прописано в миссии, в других на том же самом самолете имя группы становится NoName. Игрок всегда определяется правильно. Запустить группу по action.Do() тоже получается как-то загадочно. В одной и той же миссии, не трогая ни саму миссию, ни скрипта, то стартует, то не стартует. Гарантированно лечится заходом в полный редактор, переназначением имени группы и переназначением стартуемой группы в действиях.

Exclamationmark.png Ответ:

Группа, которая стартует скриптом (с помощью действия, скажем), по сути относится уже к другой миссии. Попробуйте во-первых, назначить переменной MissionNumberListener значение -1, примерно вот так:
public override void OnBattleStarted()
{
    base.OnBattleStarted();
    MissionNumberListener = -1;
}
Во-вторых, имя группы состоит из собственно имени группы и префикса "принадлежности к миссии" (номер миссии с двоеточием). Получить правильно полное имя группы (например для использования в GamePlay.gpActorByName()) можно примерно вот так:
public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
{
   base.OnActorCreated(missionNumber, shortName, actor);
   string fullName = ActorName.Full(missionNumber, shortName);
}
В любом событии, относящемся к акторам, в первых двух параметрах передаются собственно номер миссии, где произошло событие, и короткое имя актора (как указано в файле миссии). Из двух этих параметров мы и получаем полное имя актора.



Удаление места появления группы (BirthPlaces)

Questionsymbol.png Вопрос: Как средствами редактора удалить старый спаун? Он же уже подгружен в миссию, нужен инструмент, чтобы его удалить.

Exclamationmark.png Ответ:

Средствами редактора это невозможно, скриптом так:
foreach (AiBirthPlace bp in GamePlay.gpBirthPlaces())
       {
           if (bp != null)
               bp.destroy();         
       }



Как во время миссии пересадить игрока в другой самолет?

Questionsymbol.png Вопрос: Как во время миссии пересадить игрока в другой самолет?

Exclamationmark.png Ответ:

Находим группу, в цикле перебираем самолеты группы и сажаем игрока в первый же самолет, где есть кабина пилота.
   AiActor actor = GamePlay.gpActorByName(ActorName.Full(MissionNumber, "BoB_LW_LG2_I.01"));
           if (actor is AiAirGroup && GamePlay.gpPlayer() != null)
           {
               Player player = GamePlay.gpPlayer();
               foreach (AiAircraft airc in (actor as AiAirGroup).GetItems())
               {
                   bool isFound = false;
                   for (int i = 0; i < airc.Places(); i++)
                   {
                       if (airc.ExistCabin(i))
                       {
                           if (airc.CrewFunctionPlace(i).Equals(CrewFunction.Pilot))
                           {
                               player.PlaceEnter(airc, i);
                               isFound = true;
                               break;
                           }
                       }
                   }
                   if (isFound) break;
               }
           }



Как задать периодические загрузки миссии без использования TickCounter()?

Questionsymbol.png Вопрос: Как задать периодические загрузки миссии без использования TickCounter()?

Exclamationmark.png Ответ:

Периодические загрузки миссии без использования TickCounter() осуществляются через MissionLoader:
//Запускаем единожды, когда миссия заружена
public override void Init(maddox.game.ABattle battle, int missionNumber)
{
base.Init(battle,missionNumber);
//Planned missions
MissionLoader(30,10,"missions/Multi/Dogfight/bombers1.mis");  // 10 секунд от начала основной миссии и повторяется каждые 30 секунд
MissionLoader(100,60,"missions/Multi/Dogfight/bombers2.mis"); // 60 секунд от начала основной миссии и повторяется каждые 100 секунд
}
public void MissionLoader(int period, int offset, string mission)
{
    if (offset > 0)
    Timeout(offset, () => {MissionLoader(period,0,mission);});
    else
    {
    GamePlay.gpPostMissionLoad(mission);
    Timeout(period, () => {MissionLoader(period,0,mission);});
    }
}



Какие параметры у GamePlay.gpHUDLogCenter?

Questionsymbol.png Вопрос: Как можно настраивать GamePlay.gpHUDLogCenter , чтобы писать мельче, другим цветом (ярко-синим, например) и внизу экрана. Как можно возврат каретки / перенос вставить, менять длительность показа?

Exclamationmark.png Ответ:

GamePlay.gpHUDLogCenter("",123) ,где 123 - длительность отображения надписи. Также можно показывать сообщение определённым игрокам, по остальным вопросам - пока никак, возможно позже добавится более широкое управление.


Относятся ли корабли к AiGroundActor?

Questionsymbol.png Вопрос: Относятся ли корабли к AiGroundActor?

Exclamationmark.png Ответ:

Да, корабль - это AiGroundActor и AiGroundGroup,с типом Ship, всех кораблей страны найти можно так:
foreach (AiGroundGroup gg in GamePlay.gpGroundGroups(army))
{
if (gg.Type == AiGroundGroupType.Ship)
   {// тут делаем с ними что нам нужно, например
        if (gg != null)
        (gg as AiGroundActor).Destroy();  // уничтожаем
   }
}



Как передать в лог сервера сообщения об уничтоженных объектах?

Questionsymbol.png Вопрос: Сейчас логи идут по принципу наземка=самолёт. Т.е если скажем ПВО убило самолёт - это документируется в логах сервера. Но вот обратный процесс, штурмовка и бомбежка никак не видны. Кроме того нет логов "наземка=наземка", т.е никаких данных по скажем уничтожению танками топливохранилищ на уровне логов сервера нет?

Exclamationmark.png Ответ:

Это сейчас уже можно, например в скрипте миссии:
public override void OnActorDead(int missionNumber, string shortName, AiActor actor, System.Collections.Generic.List<DamagerScore> damages)
   {
       base.OnActorDead(missionNumber, shortName, actor, damages);        
       GamePlay.gpLogServer(null, "{0} actor dead, 1st killer is {1} ", new object[] { actor.Name(),damages[0].initiator.Actor.Name()});
   }



Как открыть подмиссию, чтобы в ней отображались все объекты?

Questionsymbol.png Вопрос: При открытии подмиссий в полном редакторе не появляются ни танки, ни самолеты, ни точки маршрута (открывается чистая карта), хотя в тексте миссии они есть, если открыть ее блокнотом. Почему это происходит?

Exclamationmark.png Ответ:

Секция с описанием карты, времени и пр. начальных условий миссии не нужна в подмиссии - ведь она загружается к уже запущенной миссии - поэтому такую секцию я удалил - так подмиссия чуть-чуть, но быстрее грузится. Если надо в редакторе открыть - можно просто из основной эту секцию скопировать в файл подмиссии :
[PARTS]
 core.100
 bob.100
 [MAIN]
 MAP Land$Online_Cross_v_Roundel
 BattleArea 6000 6000 26000 26000 1000
 TIME 16
 WeatherIndex 0
 CloudsHeight 1000
 BreezeActivity 10
 ThermalActivity 10



Как можно суб-скрипт загружать из другого скрипта, на загружая .mis файл суб-миссии?

Questionsymbol.png Вопрос: Как можно суб-скрипт загружать из другого скрипта, на загружая .mis файл суб-миссии? Хочется разбивать большие скрипты на тематические кусочки, чтобы править только те, которые нужно.

Exclamationmark.png Ответ:

Создавать пустые подмиссии, в которых будут только нужные куски скрипта.



DamagerScore - параметры

Questionsymbol.png Вопрос:
1. В DamagerScore из maddox.game.world есть две числовые переменные score и time. Score - степень повреждения и в чем она измеряется?
2. Если смотреть список инициаторов сбитого самолета (как акторов) по функции OnActorDead (из AMission), то в нем всегда есть сам убитый актор, у которого score больше нуля. Как это понять? Типа повреждения, которые наносятся не напрямую противником, записываются на самого актора. Например, противник повредил систему охлаждения (записано противнику), из-за поврежденной системы охлаждения накрывается двигатель (а это уже пишут самому актору). Или на убитого актора просто записывают очки повреждения от самого падения?
3. Что показывает параметр time? Как я понимаю это время нанесения последнего повреждения для инициатора?

Exclamationmark.png Ответ:

1. Score - это степень участия инициатора в демадже, т.е. если игроки вдвоём уничтожали/расстреливали один самолёт, убили его и нанесли одинаковые повреждения, у score будет по 0.5, если втроём с тем же результатом - по 0.3(3) ну и т.д., если повреждения не одинаковые - то у кого повреждения более значительные, у того и score больше.
2. На убитого актора записывают оставшийся демадж от падения, если взорвать его в воздухе - ему ничего не запишется. Т.е. мы сломали ему мотор нам записали, допустим 0.6 демаджа, дальше он упал и разбился - ему 0.4 запишут.
3. Да, именно так.



Z_VelocityIAS и подобные - единицы измерения

Questionsymbol.png Вопрос:
1. В каких единицах возвращается значение по запросу Z_VelocityIAS и подобные? Получал с subtype=-1. Значение в среднем ниже на 2,36, если ориентироваться по прибору в км/ч на 500-х метрах.
2. Так как не совсем ясно, в каких единицах возвращается значение по вопросу выше, пробовал получать по Z_VelocityMach. Стало похоже на правду, но возник еще вопрос: конкретное значение ск. звука зависит от температуры воздуха?

Exclamationmark.png Ответ:

1. В метрах/секунду все подобные параметры.
2. Да, зависит.



Использование класса List(Of T) вместо массивов

Questionsymbol.png Вопрос: Есть массив данных, как заменить его на List?

Exclamationmark.png Ответ:

Было:
//Параметры меню
string[] descMainMenu;    //Описание пунктов главного меню
descMainMenu = new string[] { "Тест системы сообщений", "Конвои" };
private void setMainMenu( Player player )
   {
       GamePlay.gpSetOrderMissionMenu( player, false, 0, descMainMenu, new bool[] { false, true } );
   }
Стало:
   List<string> descMainMenu = new List<string>();
   descMainMenu.Add("Тест системы сообщений");
   descMainMenu.Add("Конвои");
   private void setMainMenu( Player player )
   {
       GamePlay.gpSetOrderMissionMenu( player, false, 0, descMainMenu.ToArray(), new bool[] { false, true } );
   }



Как удалить все юниты подмиссии

Questionsymbol.png Вопрос: Есть загруженная подмиссия с неизвестным номером. Как удалить все юниты именно этой подмиссии не перебирая в циклах всю наземку? Или может быть просто можно подмиссию выгрузить?

Exclamationmark.png Ответ:

Никак.

Что бы миссия не была неизвестной, надо перед ее загрузкой запомнить след. номер (NextMissionNumber или как то так). Частичное решение состоит в переборе наземных и воздушных групп для всех представленных армий и сверке запомненного номера миссии с номером, заключенном в полном имени юнита (формат примерно такое - номер миссии, двоеточие, shortName). Полное имя получается через AiActor.Name(). Почему частичное? Перебором групп ты не найдешь юнитов, которые групп не имеют (артиллерия и стат. корабли как минимум), т.е. по OnActorCreated надо еще и их запоминать. Похожее решение используется в морском льве. Домики, ящички и все что в разделе статический и т.д. не удалишь вообще никак.

Формат GamePlay.gpSetOrderMissionMenu

Questionsymbol.png Вопрос: Интересует формат GamePlay.gpSetOrderMissionMenu

Exclamationmark.png Ответ:

gpSetOrderMissionMenu( Player player, bool thisSubMenu, int ID, string[] keys, bool[] bSubMenu ); 

Player player - игрок которому выдаётся кастомное меню

bool thisSubMenu - является ли данный набор пунктов подменю

int ID - ID пункта по которому его можно идентифицировать

string[] keys массив строк-пунктов меню

bool[] bSubMenu массив bool показывающий есть ли у каждого пункта подменю

За что отвечают методы OnBattleStarted() и OnMissionLoaded() и что означает ключевое слово base?

Questionsymbol.png Вопрос: За что отвечают методы OnBattleStarted() и OnMissionLoaded()?

Exclamationmark.png Ответ:
OnBattleStarted()- Метод вызывается один раз при старте битвы. Точнее - как только битва уже стартовала.
OnMissionLoaded() - Вызывается как только загрузилась новая миссия. Причем вызывается во всех ранее загруженных миссиях.

Роль ключевого слова base. Вызывается переопределяемый метод класса-предка. На пример - у нас есть класс MyMission, предком которого является AMission. В классе MyMission переопределен OnBattleStarted(), в котором мы пишем на экран - "Битва началась!". Определим еще один класс RealMission, предком которого будет класс MyMission, и так же, переопределим в нем метод OnBattleStarted(), где на экран выведем - "Таки да, началась!" Что произойдет, если мы создадим экземпляр RealMission и вызовем в нем OnBattleStarted()? Как и предполагается, будет выведена надпись "Таки да, началась!". Получается, весь код, который мы писали в MyMission в том же методе, никак не используется. Для этого и существует base. Т.е. Этим мы вызовем метод предка. Т.е., если в реализации RealMission.OnBattleStarted() вначале дописать base.OnBattleStarted(), мы получим две последовательно выведенные надписи - "Битва началась!" и "Таки да, началась!".

Поясните использование метода String.Substring в скриптах

Questionsymbol.png Вопрос: Поясните использование метода String.Substring в скриптах

Exclamationmark.png Ответ:
Статья на MSDN
В многих случаях нумерация символов с строке начинается с нуля (в других языках может и с единицы) Соответственно первые двенадцать символов будут иметь индексы с 0 до 11. В данном случае первая цифра (0) означает индекс символа, с которого надо начинать отсчет. "12" означает кол-во символов, которые надо забрать.
Этот метод можно применить для оптимизации кода следующим образом:

Чтобы не копировать постоянно названия триггеров, мы можем использовать такой код:
if (shortName.Substring(0, 12).Equals("WinCondition") && active)
{
   WinConditionCounter++;
   GamePlay.gpGetTrigger(shortName).Enable = false;   
}

Имеются подмиссии, в каждой триггер с именем "WinCondition1", "WinCondition2", "WinCondition3" ... "WinConditionn". При срабатывании любого триггера, он проверяется в условии.

shortName.Substring(0, 12) позволяет учитывать только первые 12 символов названия триггеров. Т.е. мы можем добавлять сколь угодно подмиссий с именами типа "WinConditionn" и не портить при этом код главного скрипта.

Как переключить состояние триггера в скриптах?

Questionsymbol.png Вопрос: Как переключить состояние триггера в скриптах?

Exclamationmark.png Ответ:
Используйте следующий код:

GamePlay.gpGetTrigger(shortName).Enable = false;  - переключает триггер в состояние OFF.
GamePlay.gpGetTrigger(shortName).Enable = enable; - переключает триггер в состояние ON.
, где shortName - имя триггера



Как удалить все юниты заданной подмиссиии не перебирая в циклах всю наземку?

Questionsymbol.png Вопрос: Как удалить все юниты заданной подмиссиии не перебирая в циклах всю наземку?

Exclamationmark.png Ответ:
Пока никак.Чтобы миссия не была неизвестной, надо перед ее загрузкой запомнить след. номер.Частичное решение состоит в переборе наземных и воздушных групп для всех представленных армий и сверке запомненного номера миссии с номером, заключенном в полном имени юнита (формат примерно такое - номер миссии, двоеточие, shortName). Полное имя получается через AiActor.Name().Почему частичное? Перебором групп ты не найдешь юнитов, которые групп не имеют (артиллерия и стат. корабли как минимум), т.е. по OnActorCreated надо еще и их запоминать. Похожее решение используется в морском льве. Домики, ящички и все что в разделе статический и т.д. не удалишь вообще никак.

Почему при старте миссии техника(корабли, танки и т.п.) не двигаются, хотя им всем задан маршрут?

Questionsymbol.png Вопрос: Почему при старте миссии техника(корабли, танки и т.п.) на внешних видах не двигаются, хотя им всем задан маршрут? Когда пролетаешь над ними они двигаются как и положено.

Exclamationmark.png Ответ:
Они для игрока находящегося дальше радиуса видимости( ~20км) "спят", игрок о них не получает информацию, для сервера они перемещаются, когда игрок приблизится на расстояние ближе радиуса видимости, они у него на машине "проснутся" и переместятся туда, где они находятся у сервера и дальше будут двигаться синхронно. Сделано это, чтобы не грузить сеть ненужной информацией о дальних объектах и машину-клиента ненужными расчётами. Если в воздухе Вы появляетесь ближе радиуса видимости - техника "просыпается" сразу.





Questionsymbol.png Вопрос:

Exclamationmark.png Ответ:



Вернуться на страницу "Скрипты"