Относятся ли корабли к AiGroundActor?
Данный скрипт должен по идее дестроить всю наземку кроме ААА, но корабли остаются (или их обломки). Обломки ведь по прежнему считаются кораблем?
Картина на сервере через 3-4 часа работыКод://Ground objects (except AA Guns) will die after 55 min when counted from their birth public override void OnActorCreated(int missionNumber, string shortName, AiActor actor) { base.OnActorCreated(missionNumber, shortName, actor); //Ground objects (except AA Guns) will die after 55 min when counted from their birth if (actor is AiGroundActor) if ((actor as AiGroundActor).Type() != maddox.game.world.AiGroundActorType.AAGun) Timeout(3300, () => { if (actor != null) { (actor as AiGroundActor).Destroy(); } } ); }
https://lh4.googleusercontent.com/_S...5-21_00016.jpg
Полный код скрипта
http://forum.1cpublishing.eu/showpos...5&postcount=41
Может быть стоит для кораблей такой же скрипт отдельно прописать? Как корабли в коде называются?
...зелёные горят.
----------------------
i7-860@3.8, 4GB, ati4890-2GB, 1680x1050, Win7-64.
naryv,
Двигатель миссий должн быть изолирован как можно скорее. В настоящее время можно получить доступ к файловой системе, сети и т.д. из скрипта, и это очень опасно, потому что люди могут получить неприятный сюрприз вместе с скачаны миссии из WWW. Однако, возможность отключения изоляции должно присутствовать, потому что обычно она не понадобится для серверов.
Как в текущем патче (1.01.14588) заставить ботов-истребителей гарантированно вступить в бой с другими истребителями? У меня они теперь игнорируют даже команду "Вступит в бой с истребителями" с указанием приоритетной группы для атаки. По рации кричат, что атакуем, но пролетают спокойно мимо и далее летят по своим контрольным точкам.
Позже - это значит в следующем патче?
А можно сдетать так, чтобы по ним и Логи шли?
Сейчас логи идут по принципу намемка=самолёт. Т.е если скажем ПВО убило самолёт - это документируется в логах сервера. Но вот обратный процесс, штурмовка и бобрёшка никак не видны. Кроме того нет логов "наземка=наземка", т.е никаких данных по скажем уничтожению танками топливохранилищь на уровне логов сервера нет. Это очень мешает работе. Если это возможно, пожалуйста поправьте.
Вот таким образом корабли уничтожит, или уж если игра их к AiGroundActor не причисляет, то и (actor as AiGroundActor).Type() и maddox.game.world.AiGroundActorType.ShipTransport не заработает для кораблей?
Код:public override void OnActorCreated(int missionNumber, string shortName, AiActor actor) { base.OnActorCreated(missionNumber,shortName,actor); //Ground objects (except AA Guns) will die after 55 min when counted from their birth if (actor is AiGroundActor || (actor as AiGroundActor).Type() = maddox.game.world.AiGroundActorType.ShipMisc || (actor as AiGroundActor).Type() = maddox.game.world.AiGroundActorType.ShipTransport) if ((actor as AiGroundActor).Type() != maddox.game.world.AiGroundActorType.AAGun) Timeout (3300, () => { if (actor != null) { (actor as AiGroundActor).Destroy(); } } ); }
...зелёные горят.
----------------------
i7-860@3.8, 4GB, ati4890-2GB, 1680x1050, Win7-64.
Вопрос такой, есть ли возможность из кода скрипта изменять количество сбитых самолетов, обозначенных на киле? Сейчас это доступно в настройках самого самолета, хотелось бы делать это динамически.
И еще такой вопрос, как у нас обстоят дела с динамическим износом самолета (и его скина соответственно тоже)? Он есть, его нет, или его надо прописывать в скрипте, есть доступные функции для этого?
AMD Phenom(tm) II X4 955 3.21ГГц, Gigabyte GA-MA770-US3, 4Гб DDR2-800, ATI Radeon HD 5850 1Гб DDR5 256-бит, Microsoft Windows 7 Home SP1 x64, 1920х1080 24"
да, корабль - это AiGroundActor и AiGroundGroup ,с типом Ship , всех кораблей страны найти можно так :
боюсь что изолировать не получится, наверное сделаем предупреждение, что пользователь запускает потенциально опасный скрипт для таких миссий. Скрипт на сервере, клиентом не закачивается и повредить что-то у клиента не сможет .Код:foreach (AiGroundGroup gg in GamePlay.gpGroundGroups(army)) { if (gg.Type == AiGroundGroupType.Ship) {// тут делаем с ними что нам нужно, например if (gg != null) (gg as AiGroundActor).Destroy(); // уничтожаем } }
попробуйте, как ув. Trident написал поставить им "охоту", с "вступить в бой" будем разбираться.
скорее всего - да.
это сейчас уже можно, например в скрипте миссии:
в лог сервера и чат будет скидываться кто убит и первый из нанёсших повреждения, можно и всех повреждателей перечислить из damages - это массив с акторами наносившими повреждения.Код: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()}); }
тут как выяснилось - ситуация такая - в движке параметры физ. износа есть и учитываются, но при загрузке миссии сейчас не подгружаются. Сделаем следующее - расширим интерфейс самолёта так, что в скрипте миссии можно будет прочитать повреждения на этот износ влияющие, а потом для следующей миссии эти параметры (ну или с какой-то обработкой - например техники что-то починили) можно будет подгрузить, так-же как и количество сбитых. Так подойдёт? Визуальный износ и сейчас из миссии подгружается, если я ничего не путаю. - строчка Aging0 74 - 74% износ 0-го самолёта, в описании группы:
с остальными самолётами так-же, только индекс меняется.Код:[BoB_RAF_F_FatCat_Early.03] Flight0 1 2 3 4 5 6 Flight1 11 12 13 14 15 16 Class Aircraft.SpitfireMkIIa Formation VIC3 CallSign 26 Fuel 100 Weapons 1 Skill 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 Aging0 74 Skin0 Standard_41A.jpg Serial0 145
Don't happy, be worry
Вопросы по поводу CTF_cross_roundel миссии.
При открытии подмиссий в полном редакторе не появляются ни танки, ни самолеты, ни точки маршрута (открывается чистая карта), хотя в тексте миссии они есть, если открыть ее блокнотом. Почему это происходит?
Я правильно понимаю, что чтобы скрипт работал на другой карте, достаточно в нем поменять координаты MissionMarker?
Обязательно ли MissionMarker должны стоять на аэродромах или можно их ставить в любую точку, перенеся на эту точку радиус триггеров changearmy? Не будет ли скрипт создавать в этих местах BirthPlace_? Хотелось бы повоевать за населенные пункты тоже, не только за аэродромы. BirthPlace в этом случае, оказываясь за линией фронта будут менять сторону или необходимо, чтобы их координаты совпадали с MissionMarker?
Можно ли увеличить количество MissionMarker до 8-12 без внесения изменений в скрипт, а только внеся их координаты вначале скрипта? В идеале, конечно желательно, чтобы скрипт сам считывал первоначальные координаты маркеров из главного файла миссии, чтобы создателю миссии даже не приходилось открывать скрипт, а просто создать подмиссии, назвав их по соответствующей схеме.
Как следствие возникнет вопрос не только изменения цвета MissionMarker, но и их движения. Можно ли, например 1 раз в 5 минут рассчитывать новые положения MissionMarker по координатам танковых групп и скоплений арты\ААА? Скажем, танковая группа является маркером пока она не уничтожена более, чем на 50%? Тогда линия фронта будет двигаться автоматически за танками, а филды перекрашиваться, как только они попадут за линию фронта. Создателю миссий останется только нарисовать подмиссии с техникой и назвать триггеры по определенной схеме, не вникая в основной скрипт.
Пока необходимость знания C# является препятствием для создания миссий. Например, создатель миссий известного сервера Синдикат не имеет представления о программировании, как и большинство других в этом разделе http://forum.1cpublishing.eu/forumdisplay.php?f=203 . Учитывая это, желательно предложить коммюнити набор готовых скриптов, которые сами будут считывать данные из файлов миссий, созданных в редакторе и обеспечивать определенный функционал (движение ЛФ, перекрас филдов, генерация вейпойнтов...), чтобы создатель миссий мог просто забросить несколько таких скриптов в папку с миссией в зависимости от потребностей и заполнить небольшой mission.ini с их списком и необходимыми вводными данными, не открывая сами скрипты в Студии. Т.е. желательно разделить труд программистов и создателей миссий с помощью удобных инструментов.
Крайний раз редактировалось -atas-; 24.05.2011 в 22:59.
...зелёные горят.
----------------------
i7-860@3.8, 4GB, ati4890-2GB, 1680x1050, Win7-64.
секция с описанием карты, времени и пр. начальных условий миссии не нужна в подмиссии - ведь она загружается к уже запущенной миссии - поэтому такую секцию я удалил - так подмиссия чуть-чуть, но быстрее грузится. Если надо в редакторе открыть - можно просто из основной эту секцию скопировать в файл подмиссии :
да, верноКод:[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
нет, конечно не обязательно, аэродромы я для наглядности сделал. В принципе - триггер и маркер могут не совпадать, но мне кажется так удобнее.
именно этот, который сейчас - будет, т.к. он берёт координаты birthPlace-ов из координат маркеров . Но можно сделать отдельный массив для birthPlace-ов - и рожать их по координатам из этого массива.
в общем случае нет, не необходимо, в этом скрипте т.к. маркеры совпадают с БП - я брал армию из маркеров, чтобы сделать как Вы хотите - надо загрузку разделить - сначала по триггеру загружаем новые маркеры фронта, а после их загрузки - уничтожаем все bP и загружаем их в новой миссии - координаты берём из массива с bP, а армию - через такую ф-цию :
GamePlay.gpFrontArmy(bP.Pos().x, bP.Pos().y) - после загрузки маркеров линия фронта пересчитается - и эта ф-ция выдаст на чьей территории стоят наши bP. Дальше генерируем миссию с bP и загружаем её.
да, конечно, везде стоят циклы которые по всей длине массива пробегают, т.е. изменение кол-ва элементов на работу никак не повлияет.
я сейчас не помню, есть ли маркеры как объекты при загрузке миссии, наверное можно и так , либо прочитать файл с миссией начальной и там маркеры найти, в принципе , должно так работать.
с группами можно, конечно - для этого не нужен будет массив с маркерами - просто пробегаем по всем AiGroundGroup с их страной и генерируем миссию с фронтмаркерами с координатами в этих группах - для такого подхода и триггеры не нужны, разве только, чтобы новые атакующие силы спаунить при уничтожении предыдущих. Со скоплениями артиллерии хуже - она в группы не входит, там надо позамороченнее как-то определять куда маркер ставить.
ну, тут, наверное, можно посоветовать только собирать удачные куски скриптов где-то, чтобы создатель миссий подбирал скрипты подходящие для его задач и вставлял его в свои миссии, как Вы понимаете, этот движок настолько мощный, что можно создать скрипт практически на все случаи жизни и сделать это сотней способов - мы сами просто не сможем сделать большим такой набор - большая надежда на заинтересованное сообщество. Насчёт вышеописанного, постараюсь по этим моментам скрипт накидать, но не обещаю быстро.
Да, кстати, сегодня заглянул на жёлтый форум, есть негугловый перевод описания к миссии с захватом аэродромов:
может иностранцам попонятнее будет.There are four airfields on the map. They are your primary capture locations.
An aircraft is considered captured once the opposing sides armor enters its perimeter. The airfield perimeter is defended with artillery and flak. Once attacking armor is destroyed, a new group of armor will be spawned to continue the assault. Destroyed artillery and flak are not restored.
Once an airfield is captured, the front line will move and the airfield will change sides allowing the new owner to spawn there. Defending artillery will also spawn for the new owner, while the old owner will spawn an attacking armor group. Finally, capturing an airfield will spawn an AI-controlled aircraft group for the enemy, attacking both air and ground targets.
Capturing the most airfields is the overall objective for this mode.
The score system is simple. Capturing an airfield awards 10 points to the victorious side. Defending an airfield, that is, destroying an enemy armor group, awards 1 point.
и ещё в скрипте некритичную ошибку нашёл, ф-ция FindOurAirfield(int army, AiActor actor) должна так выглядеть:
Код:internal AiAirport FindOurAirfield(int army, AiActor actor) { AiAirport result = null; Point3d attackerPos = actor.Pos(); AiAirport[] airports = GamePlay.gpAirports(); if (airports != null) { foreach (AiAirport airport in airports) { if (GamePlay.gpFrontArmy(airport.Pos().x, airport.Pos().y) == army) { if (result != null) { if (result.Pos().distance(ref attackerPos) > airport.Pos().distance(ref attackerPos)) result = airport; } else result = airport; } } } return result; }
да не за что
Don't happy, be worry
AMD Phenom(tm) II X4 955 3.21ГГц, Gigabyte GA-MA770-US3, 4Гб DDR2-800, ATI Radeon HD 5850 1Гб DDR5 256-бит, Microsoft Windows 7 Home SP1 x64, 1920х1080 24"
тут смотря что имеется ввиду под "на лету" - это просто кусок из миссии в котором описана группа самолётов. Если Вы этот кусок генерируете сами и потом подгружаете сгенерённую миссию - тогда да, конечно миссия подгрузится со всеми теми изменениями, которые Вы внесли. Если имелась ввиду возможность менять эти параметры у уже загруженных и летящих самолётов - тогда нет, менять номера, кол-во топлива, оружие и т.д. у уже летящих самолётов нельзя.
Don't happy, be worry
В общем интересная фишка получилась с ботами. Никакие типы задания для истребителей не заставляли их начать атаковать, даже добавление бомбера с заданием его эскортировать.
Решение было найдено методом тыка. В миссии присутствовал садящийся при старте хуряшка, садился он на другом конце карты. Стоило его убрать - боты сразу стали себя вести адекватно.
А как можно суб-скрипт загружать из скрипта, на загружая .mis файл суб-миссии? Хочется разбивать большие скрипты на тематические кусочки, чтобы править только те, которые нужно.
...зелёные горят.
----------------------
i7-860@3.8, 4GB, ati4890-2GB, 1680x1050, Win7-64.
AMD Phenom(tm) II X4 955 3.21ГГц, Gigabyte GA-MA770-US3, 4Гб DDR2-800, ATI Radeon HD 5850 1Гб DDR5 256-бит, Microsoft Windows 7 Home SP1 x64, 1920х1080 24"
По отзывам бомберов скрипт, который используется на Repka, а также был растиражирован на Синдикат и другие серверы повреждает многоместные самолеты не только при покидании игроком, как было задумано, но и при переходе игрока на место штурмана или стрелка. Как бы это можно было поправить для совместимости с многоместными машинами?
(Еще говорят у 110х нет ботов-стрелков в онлайне, но это видимо к скрипту не относится).
Выделено синим.
Код:// v.1_17_05. script by FG28_Kodiak, ZaltysZ, Oreva, Small_Bee using System; using maddox.game; using maddox.game.world; using System.Collections.Generic; public class Mission : AMission { int LastMissionLoaded = 0; double initTime; // loading sub-missions public override void OnTickGame() { if (Time.tickCounter() % 45000 == 9000) // 45000=25 min repeat. 9000=5 min delay. { // randomly selects 1 of several submissions excluding the recent one Random RandomIncident = new Random(); int CurrentMissionSelected; do { CurrentMissionSelected = RandomIncident.Next(1, 4); } while (LastMissionLoaded == CurrentMissionSelected); LastMissionLoaded = CurrentMissionSelected; switch (CurrentMissionSelected) { case 1: GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air01.mis"); //GamePlay.gpHUDLogCenter("Intel: Enemy activity is expected at E3!"); //600 initTime = 0.0; Timeout(initTime += 600, () => { GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E3!"); }); //600+600 Timeout(initTime += 600, () => { GamePlay.gpHUDLogCenter("Attention! Help is needed at E3/D4!"); }); break; case 2: GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_sea01.mis"); //GamePlay.gpHUDLogCenter("Intel: Cover your shipping at C4!"); //500 initTime = 0.0; Timeout(initTime += 450, () => { GamePlay.gpHUDLogCenter("Attention! Cover your shipping at C4!"); }); //500+300 Timeout(initTime += 300, () => { GamePlay.gpHUDLogCenter("Attention! Ships are under attack at C4!"); }); break; case 3: GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air02.mis"); //GamePlay.gpHUDLogCenter("Intel: Enemy activity is expected at E2!"); //600 initTime = 0.0; Timeout(initTime += 600, () => { GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E2!"); }); //600+300 Timeout(initTime += 300, () => { GamePlay.gpHUDLogCenter("Attention! All fighters please proceed to E2/D3!"); }); break; } } /////////////////////// //loads small submissions w/o messages if (Time.tickCounter() % 216000 == 108000) // 216000=120 min repeat. 108000=60 min delay. { GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_small01.mis"); } if (Time.tickCounter() % 216000 == 215999) // 216000=120 min repeat. 215999=120 min delay. { GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_small02.mis"); } } //////////////////////////////////////////////////////////////////////////////////////////////////// // destroys aircraft abandoned by a player. private bool isAiControlledPlane (AiAircraft aircraft) { if (aircraft == null) { return false; } Player [] players = GamePlay.gpRemotePlayers (); foreach (Player p in players) { if (p != null && (p.Place () is AiAircraft) && (p.Place () as AiAircraft) == aircraft) { return false; } } return true; } private void destroyPlane (AiAircraft aircraft) { if (aircraft != null) { aircraft.Destroy (); } } private void explodeFuelTank (AiAircraft aircraft) { if (aircraft != null) { aircraft.hitNamed (part.NamedDamageTypes.FuelTank0Exploded); } } private void destroyAiControlledPlane (AiAircraft aircraft) { if (isAiControlledPlane (aircraft)) { destroyPlane (aircraft); } } private void damageAiControlledPlane (AiActor actor) { if (actor == null || !(actor is AiAircraft)) { return; } AiAircraft aircraft = (actor as AiAircraft); if (!isAiControlledPlane (aircraft)) { return; } if (aircraft == null) { return; } aircraft.hitNamed (part.NamedDamageTypes.ControlsElevatorDisabled); aircraft.hitNamed (part.NamedDamageTypes.ControlsAileronsDisabled); aircraft.hitNamed (part.NamedDamageTypes.ControlsRudderDisabled); aircraft.hitNamed (part.NamedDamageTypes.FuelPumpFailure); int iNumOfEngines = (aircraft.Group() as AiAirGroup).aircraftEnginesNum(); for (int i = 0; i < iNumOfEngines; i++) { aircraft.hitNamed((part.NamedDamageTypes)Enum.Parse(typeof(part.NamedDamageTypes), "Eng" + i.ToString() + "TotalFailure")); } /***Timeout (240, () => {explodeFuelTank (aircraft);} ); * ***/ Timeout (300, () => {destroyPlane (aircraft);} ); } ////////////////////////////////////////// public override void OnPlaceLeave (Player player, AiActor actor, int placeIndex) { base.OnPlaceLeave (player, actor, placeIndex); Timeout (1, () => {damageAiControlledPlane (actor);} ); } public override void OnAircraftCrashLanded (int missionNumber, string shortName, AiAircraft aircraft) { base.OnAircraftCrashLanded (missionNumber, shortName, aircraft); Timeout (300, () => { destroyPlane(aircraft); } ); } public override void OnAircraftLanded (int missionNumber, string shortName, AiAircraft aircraft) { base.OnAircraftLanded(missionNumber, shortName, aircraft); Timeout(300, () => { destroyPlane(aircraft); } ); } ////////////////////////////////////////////////////////////////////////////////////////////////// //Listen to events of every mission public override void Init(maddox.game.ABattle battle, int missionNumber) { base.Init(battle, missionNumber); MissionNumberListener = -1; //Listen to events of every mission } ////////////////////////////////////////////////////////////////////////////////////////////////// //Ground objects (except AA Guns) will die after 55 min when counted from their birth public override void OnActorCreated(int missionNumber, string shortName, AiActor actor) { base.OnActorCreated(missionNumber, shortName, actor); //Ground objects (except AA Guns) will die after 55 min when counted from their birth if (actor is AiGroundActor) if ((actor as AiGroundActor).Type() != maddox.game.world.AiGroundActorType.AAGun) Timeout(3300, () => { if (actor != null) { (actor as AiGroundActor).Destroy(); } } ); } /**** //Ground objects will die after 55 min when counted from their birth public override void OnActorCreated(int missionNumber, string shortName, AiActor actor) { base.OnActorCreated(missionNumber, shortName, actor); //Ground objects will die after 55 min when counted from their birth if (actor is AiGroundActor) Timeout(3300, () => { if (actor != null) { (actor as AiGroundActor).Destroy(); } } ); } ****/ }
...зелёные горят.
----------------------
i7-860@3.8, 4GB, ati4890-2GB, 1680x1050, Win7-64.
да не за что
мне кажется наоборот - с открытым кодом есть возможность проверки - что делает скрипт, с закрытым больше возможностей сделать что-то нехорошее.
так вот же - http://www.sukhoi.ru/forum/showthrea...=1#post1608824 скрипт с проверкой в многоместных самолётах. Оттуда проверку можно взять.
Don't happy, be worry
С открытым кодом ЛЮБОЙ может туда дописать все что угодно, а потом выдать за оригинальную кампанию(то есть заняться распространением уже своего скрипта под видом оригинального). То есть теоретически любой может получить доступ к чужому ПК.
И еще такой вопрос, МГ имеет возможность помогать тем кто делает Офф-лайн кампании? Помощь нужна такого плана, чтобы сама кампания хранилась на сервере Стима. А то сейчас во-первых при обновлении кэша все нестандартные кампании удаляются. Во-вторых пользователям приходится руками править ini-файлы. Что как бы не есть Юзер-френдли.
И спасибо за консультации.
С Уважением!
AMD Phenom(tm) II X4 955 3.21ГГц, Gigabyte GA-MA770-US3, 4Гб DDR2-800, ATI Radeon HD 5850 1Гб DDR5 256-бит, Microsoft Windows 7 Home SP1 x64, 1920х1080 24"
Такой открытый код можно проверить, а с закрытым - нельзя, т.е. опять же любой возьмёт Вашу кампанию, напишет вместо Вашего скрипта свой - и увидеть это нельзя будет никак.
На стиме, к сожалению, хранить кампании не получится, почему - попробуйте у Лютьера уточнить. А можно детали про удаление нестандартных кампаний? По идее кампания хранящаяся в своей папке не должна удаляться, если удаляется может быть баг какой-то, постараемся исправить.
всегда пожалуйста
2 -atas- вот скрипт для движения ЛФ со списком маркеров для любой карты - при инициализации из основной миссии берутся начальные маркеры, к ним делаются триггеры смены фронта и дальше маркеры переключаются. Я комментарии написал, думаю понятно должно быть как и что там делается.
Код:using System; using System.Collections; using maddox.game; using maddox.game.world; using maddox.GP; using System.Collections.Generic; public class Mission : AMission { internal class MissionMarker { internal double x; internal double y; internal int army; internal MissionMarker(double x, double y, int army) { this.x = x; this.y = y; this.army = army; } } private List <MissionMarker> MissionMarkers = new List<MissionMarker> (); string BPMaxPlanesAllowed = "3"; // количество макс. возможно создаваемых самолётов на спаунточке string BPSpawnParked = "1"; // рожать ли самолёты на спауне запаркованными 1 - да, 0 - нет int MissionsCount = 1; // счётчик миссий - для вычисления полных имён стат. объектов, например артиллерии int NextMissionNum = 2; // флажок номера следующей миссии - для рефреша спаун точек, после смены линии фронта int ScoreRed = 0; // "счёт" int ScoreBlue = 0; private string[] RedPlanesSet = new string[] // описание наборов самолётов на спаунточках разных стран { "Aircraft.SpitfireMkIIa", "Aircraft.SpitfireMkI", "Aircraft.BlenheimMkIV", "Aircraft.SpitfireMkIa", "Aircraft.DH82A", "Aircraft.HurricaneMkI_dH5-20", "Aircraft.HurricaneMkI" }; private string[] BluePlanesSet = new string[] { "Aircraft.Bf-110C-7", "Aircraft.Bf-110C-4", "Aircraft.Bf-109E-3B", "Aircraft.Ju-88A-1", "Aircraft.G50", "Aircraft.He-111P-2", "Aircraft.He-111H-2", "Aircraft.Bf-109E-3", "Aircraft.BR-20M", "Aircraft.Ju-87B-2" }; public ISectionFile triggersFile ; // объявление файла для генерации миссии с триггерами смены линии фронта public override void Init(ABattle battle, int missionNumber) { base.Init(battle, missionNumber); ISectionFile missFile = GamePlay.gpLoadSectionFile("missions\\Multi\\Dogfight\\xxxxx.mis"); // загружаем в missFile основную миссию, для того, чтобы найти в ней маркеры фронта triggersFile = GamePlay.gpCreateSectionFile(); //заодно создаём файл для генерации миссии с триггерами string section, key, value; string sectionTr, keyTr, valueTr; section = "FrontMarker"; sectionTr = "Trigger"; int n = missFile.lines(section); // определяем, сколько маркеров фронта в миссии for (int i = 0 ; i < n; i++) { // в этом цикле пробегаем по всем маркерам key = "FrontMarker"+i.ToString(); if (missFile.exist(section,key)) // проверяем, что маркер есть { value = missFile.get(section, key); string[] strs = value.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries); // и парсим строку с маркером, берём его координаты и страну if (strs.Length == 3) { double x; double.TryParse( strs[0], out x); double y; double.TryParse( strs[1], out y); int army; int.TryParse( strs[2], out army); MissionMarker mMarker = new MissionMarker(x,y,army); MissionMarkers.Add(mMarker); // добавляем в список маркеров MissionMarkers проверенный маркер keyTr = "changeArmy" + i.ToString()+"_1"; // попутно на маркере делаем два триггера - для каждой стороны valueTr = " TPassThrough 3 1 " + strs[0] + " " + strs[1] + " 500"; // "TPassThrough 3" - триггер сработает при заезде в него наземки, "1" красной, strs[0] + " " + strs[1] координаты, "500"- радиус триггера triggersFile.add(sectionTr, keyTr, valueTr); // сохраняем триггер в файле триггерной миссии keyTr = "changeArmy" + i.ToString() + "_2"; // то же самое для синей стороны valueTr = " TPassThrough 3 2 " + strs[0] + " " + strs[1] + " 500"; triggersFile.add(sectionTr, keyTr, valueTr); // сохраняем триггер в файле триггерной миссии } } } } public override void OnBattleStarted() { base.OnBattleStarted(); MissionNumberListener = -1; // ставим MissionNumberListener = -1 , чтобы основная миссия "слышала" все триггеры и события в битве GamePlay.gpPostMissionLoad(triggersFile); // подгружаем миссию с триггерами созданую раньше, в Init RefreshBirthPlaces(); // и запускаем рефреш спаунов - чтобы они рассчитались } private void RefreshBirthPlaces() { foreach (AiBirthPlace bp in GamePlay.gpBirthPlaces()) // сначала - очистим существующие спауны { if (bp != null) bp.destroy(); } ISectionFile f = GamePlay.gpCreateSectionFile(); // создаём файл миссии в котором переопределим спауны в соответствии с линиями фронта string sect; string key; string value; for (int i = 0; i < GamePlay.gpAirports().Length; i++) // сделаем спауны на всех аэродромах карты { Point3d airpPos = GamePlay.gpAirports()[i].Pos(); // координаты аэродрома int armyAtPos = GamePlay.gpFrontArmy(airpPos.x, airpPos.y); // текущая армия в точке с аэродромом sect = "BirthPlace"; key = "BirthPlace_" + i.ToString(); // дальше заполняем инфо для спаунов string Country = "."; if (armyAtPos == 1) Country = "gb"; if (armyAtPos == 2) Country = "de"; value = " " + armyAtPos.ToString() + " " + ((int)airpPos.x).ToString() + " " + ((int)airpPos.y).ToString() + " 0 " + BPMaxPlanesAllowed + " " + BPSpawnParked + " 0 " + Country + " . ."; f.add(sect, key, value); sect = "BirthPlace" + i.ToString(); // и для каждого заполняем списком разрешённых самолётов string[] PlaneSet = new string[0]; if (armyAtPos == 1) PlaneSet = RedPlanesSet; if (armyAtPos == 2) PlaneSet = BluePlanesSet; if (PlaneSet.Length > 0) for (int j = 0; j < PlaneSet.Length; j++) { key = PlaneSet[j]; value = ""; f.add(sect, key, value); } } GamePlay.gpPostMissionLoad(f); // загружаем новые спауны } private void DestroyEnemyAtCaptured(int markerNum, int army) { // если надо уничтожить всех врагов на захваченном маркере - уничтожаем в этой процедуре Point3d AirportPos; AirportPos.x = MissionMarkers[markerNum].x; AirportPos.y = MissionMarkers[markerNum].y; AirportPos.z = 1; foreach (AiGroundGroup gg in GamePlay.gpGroundGroups(army)) { if (gg != null) if (gg.Pos().distance(ref AirportPos) < 2000) // 2000 это расстояние от маркера на котором уничтожим врагов { string triggerName = gg.Name().Substring(0,gg.Name().IndexOf(":"))+":"+markerNum.ToString()+"_" + army .ToString()+ "_attack"; AiTrigger trigger = GamePlay.gpGetTrigger(triggerName); if (trigger != null) trigger.Enable = false; foreach (AiActor ggActor in gg.GetItems()) { if ((ggActor as AiGroundActor) != null) (ggActor as AiGroundActor).Destroy(); } } } for (int i = 0; i < MissionsCount; i++) { AiGroundActor curActor; for (int j = 0; j < 10; j++) { string nameActor = i.ToString() + ":Static" + j.ToString(); curActor = GamePlay.gpActorByName(nameActor) as AiGroundActor; if (curActor != null) { if ( (curActor.Army() == army) && (curActor.Pos().distance(ref AirportPos) < 2000) && ((curActor.Type() == AiGroundActorType.AAGun)||(curActor.Type() == AiGroundActorType.Artillery) ) ) { curActor.Destroy(); } } } } } internal ISectionFile CreateNewFrontLineMission(int markerNum, int newArmy) // создаём новый файл миссии с фронтмаркерами { DestroyEnemyAtCaptured(markerNum, MissionMarkers[markerNum].army); // если надо - уничтожаем врагов MissionMarkers[markerNum].army = newArmy; // в списке маркеров задаём новую армию на захваченном маркере ISectionFile f = GamePlay.gpCreateSectionFile(); string sect; string key; string value; for (int i = 0; i < MissionMarkers.Capacity; i++) // и для всего списка маркеров пробегаем и записываем в файл их координаты и армии { sect = "FrontMarker"; key = "FrontMarker" + i.ToString(); value = MissionMarkers[i].x.ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat) + " " + MissionMarkers[i].y.ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat) + " " + MissionMarkers[i].army.ToString(); f.add(sect, key, value); } return f; } public override void OnMissionLoaded(int missionNumber) { base.OnMissionLoaded(missionNumber); MissionsCount++; // счётчик миссий обновляем if (missionNumber == NextMissionNum) // проверяем флажок номера следующей миссии - для рефреша спаун точек, после смены линии фронта RefreshBirthPlaces(); // и обновляем спауны если надо } public override void OnTrigger(int missionNumber, string shortName, bool active) // обрабатываем триггеры сработавшие { base.OnTrigger(missionNumber, shortName, active); int n = MissionMarkers.Capacity; //пробегаем по списку маркеров, чтобы выяснить - не сработал ли наш триггер на смену линии фронта for (int i = 0; i < n; i++) { for (int j = 1; j < 3; j++) { string str = "changeArmy" + i.ToString() + "_" + (j).ToString(); if (str.Equals(shortName)) // если сработал - тогда обрабатываем его - счёт обновляем, пишем что фрмия сменилась { if (MissionMarkers[i].army != j) { string armyOwner; if (j == 1) { armyOwner = " Red army"; ScoreRed += 10; } else { armyOwner = " Blue army"; ScoreBlue += 10; } GamePlay.gpHUDLogCenter("Front turn to " + armyOwner + " at sector " + GamePlay.gpSectorName(MissionMarkers[i].x, MissionMarkers[i].y).ToString() + "; Red " + ScoreRed.ToString() + ":" + ScoreBlue.ToString() + " Blue"); NextMissionNum = GamePlay.gpNextMissionNumber(); // ставим флажок номера следующей миссии - чтобы после загрузки новых линий фронта пересчитались спауны GamePlay.gpPostMissionLoad(CreateNewFrontLineMission(i, j)); // грузим миссию с обновлёнными маркерами ЛФ // ну и можно как в предыдущей версии загрузить подмиссию на изменённый маркер, у меня это были подмиссии с защищающимися артами вида "x_y_defend.mis", где x - номер маркера, y - защищающаяся страна : GamePlay.gpPostMissionLoad("missions\\Multi\\Dogfight\\CTF_submissions\\" + i.ToString() + "_" + (j).ToString() + "_defend.mis"); } break; } // ну и заодно проверяем не уничтожили ли атакующих из подмиссий в каждой такой подмисси был триггер вида "x_y_attack" срабатывавший на уничтожение атакующей группы str = i.ToString() + "_" + (j).ToString() + "_attack"; string addStr = " ground group eliminated at sector " + GamePlay.gpSectorName(MissionMarkers[i].x, MissionMarkers[i].y).ToString(); if (str.Equals(shortName)) // соответственно если сработал такой триггер, обрабатываем его , счёт меняем, пишем что группу уничтожили и запускаем ещё одну атакующую миссию { if (j == 2) { ScoreRed++; addStr = "Blue" + addStr; } else { ScoreBlue++; addStr = "Red" + addStr; } GamePlay.gpHUDLogCenter(addStr + ",and the score is Red " + ScoreRed.ToString() + ":" + ScoreBlue.ToString() + " Blue"); GamePlay.gpPostMissionLoad("missions\\Multi\\Dogfight\\CTF_submissions\\" + str + ".mis"); break; } // если логика битвы другая , тогда этот блок с проверкой убираем } } } }
Don't happy, be worry