Читайте тему выше:
http://www.sukhoi.ru/forum/showthrea...=1#post1616450
car.cpp гоняет машинку по сплайновой дороге туда-сюда. Для поезда нужно проверять как будет работать, он же не развернется сам на рельсах )
Вид для печати
Читайте тему выше:
http://www.sukhoi.ru/forum/showthrea...=1#post1616450
car.cpp гоняет машинку по сплайновой дороге туда-сюда. Для поезда нужно проверять как будет работать, он же не развернется сам на рельсах )
Нет, он разрушает даже самолеты, которые приземлились на аэродроме, но эти самолеты должны быть созданы в той же миссии. Потому что вы создаете самолеты в других миссиях, скрипт не может получить OnPlaneLanded() и OnPlaneCrashLanded() для этих самолетов. Есть 2 решения:
1) Создать отдельный скрипт для уничтожения самолета в каждой миссии.
2) Сделать скрипт так, что он слушал события каждой миссии. В этом случае, необходимо добавить:
Код:public override void Init(maddox.game.ABattle battle, int missionNumber)
{
base.Init(battle,missionNumber);
MissionNumberListener=-1; //Listen to events of every mission
}
--- Добавлено ---
Этот код дает вам много ошибок типа "Out of bounds", потому что он пытается убить второго двигателя и на самолете с одним двигателем.
Попробуйте изменить эти строки на:
Код: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"));
}
Спасибо большое!!! Завтра потестирую в оффлайне и загружу на сервер. Вставлять MissionNumberListener=-1, как понимаю, лучше в начало файла?
Out of bounds мы получали по-моему именно для 2х-моторных 110х емнип (и только для них). Но в любом случае исправим.
Не подскажете, как корабли, танки, дымы минут через 50 - 75 убрать после их загрузки подмиссией?
Если объекты создаются только во время загрузки миссий, мы можем уменьшить эту проблему до: объекты должны умереть после минут XXX от их создания. Тогда, мы можем использовать:
Код:public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
{
base.OnActorCreated(missionNumber,shortName,actor);
//Ground objects will die after 50 min when counted from their birth
if (actor is AiGroundActor)
Timeout (3000, () =>
{ if (actor != null)
{ (actor as AiGroundActor).Destroy(); }
}
);
}
--- Добавлено ---
В методе Init (). Он выполняется, когда миссия начинается. Нет никакой разницы, в каком порядке методы определены в классе, так что вы можете поместить его в начале, конце или середине.
Давайте брать пример. Игрок покидает Spitfire в воздухе, скрипт пытается сделать некоторые повреждения. Spitfire имеет только один двигатель, поэтому скрипт успешно убивает двигателя № 1. Тогда скрипт продолжается, и пытается убить двигатель № 2, которой не существует, и в результате появляется ошибка "Out of bounds".
Я просто предложили такие изменения кода, что скрипт будет убивать не более двигателей, чем есть в самолете.
Периодические загрузки миссии без использования TickCounter():
Код://Runs once, when mission is loaded
public override void Init(maddox.game.ABattle battle, int missionNumber)
{
base.Init(battle,missionNumber);
//Planned missions
MissionLoader(30,10,"missions/Multi/Dogfight/bombers1.mis"); // 10s from main mission start and repeatedly every 30s
MissionLoader(100,60,"missions/Multi/Dogfight/bombers2.mis"); // 60s from main mission start and repeatedly every 100s
}
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);});
}
}
Спасибо, а как туда отложенные по времени текстовые сообщения вставить как здесь:
Мне трудно что-то менять в коде. Лучше вставлять целый работающий кусок в готовый скрипт, если есть такая возможность.Код:// v.1_17_00. bot-destroying script based on one by oreva
using System;
using maddox.game;
using maddox.game.world;
using System.Collections.Generic;
public class Mission : AMission
{
// loading sub-missions
public override void OnTickGame()
{
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");
}
/////////////////////////////////////////////////////////////////////////////////////
if (Time.tickCounter() % 135000 == 9000) // 135000=75 min repeat. 9000=5 min delay.
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air01.mis");
// GamePlay.gpHUDLogCenter("mis1 loaded!");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E3!");
});
Timeout(initTime += 300, () =>
{
GamePlay.gpHUDLogCenter("Attention! Help is needed at D4!");
});
}
if (Time.tickCounter() % 135000 == 54000) // ; 135000=75 min repeat, 54000 - 30 min delay.
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_ground01.mis");
// GamePlay.gpHUDLogCenter("mis2 loaded");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Cover your shipping at C4!");
});
Timeout(initTime += 300, () =>
{
GamePlay.gpHUDLogCenter("Attention! All airgroups please proceed to C4!");
});
}
if (Time.tickCounter() % 135000 == 99000) // 135000 == 99000 = 75 min repeat, 55 min delay
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air02.mis");
// GamePlay.gpHUDLogCenter("mis3 loaded!");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E2!");
});
Timeout(initTime += 300, () =>
{
GamePlay.gpHUDLogCenter("Attention! Friendly aircrafts are under attack at D2!");
});
}
}
// destroys aircraft abandoned by a player. script by oreva
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);
aircraft.hitNamed (part.NamedDamageTypes.Eng0TotalFailure);
aircraft.hitNamed (part.NamedDamageTypes.Eng1TotalFailure);
/***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); }
);
}
}
ps. Пока не было времени интегрировать предыдущие изменения, надеюсь займусь вечером.
Можно ли каким-то образом исключить отсюда артиллерию? Т.е. чтобы зенитки оставались.Код:public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
{
base.OnActorCreated(missionNumber,shortName,actor);
//Ground objects will die after 50 min when counted from their birth
if (actor is AiGroundActor)
Timeout (3000, () =>
{ if (actor != null)
{ (actor as AiGroundActor).Destroy(); }
}
);
}
Или вы можете просто удалить объекты, созданные в подмиссиях. В этом случае, вы должны поставить все зенитки в основной миссии.Код:public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
{
base.OnActorCreated(missionNumber,shortName,actor);
//Ground objects (except AA Guns) will die after 50 min when counted from their birth
if (actor is AiGroundActor)
if ((actor as AiGroundActor).Type() != maddox.game.world.AiGroundActorType.AAGun)
Timeout (3000, () =>
{ if (actor != null)
{ (actor as AiGroundActor).Destroy(); }
}
);
}
Код:public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
{
base.OnActorCreated(missionNumber,shortName,actor);
HUDmsg("Actor "+actor.Name()+" was created.");
//Ground objects (except ones created in main mission) will die after 50 min when counted from their birth
if (actor is AiGroundActor && missionNumber > 0)
Timeout (3000, () =>
{ if (actor != null)
{ (actor as AiGroundActor).Destroy(); }
}
);
}
Спасибо большое! Возьмем 1й вариант, т.к. в подмиссиях иногда зенитки немного добавляем, где нужно.
Противотанковые пушки удалятся? (их лучше удалять, хотя не так принципиально пока их мало у нас совсем).
upd. Вот так получилось. Тестируем. Спасибо за помощь.
Код:// v.1_17_04. script by oreva, zaltys, small_bee
using System;
using maddox.game;
using maddox.game.world;
using System.Collections.Generic;
public class Mission : AMission
{
// loading sub-missions
public override void OnTickGame()
{
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");
}
///////////////////////
if (Time.tickCounter() % 162000 == 9000) // 162000=90 min repeat. 9000=5 min delay.
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air01.mis");
// GamePlay.gpHUDLogCenter("mis1 loaded!");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E3!");
});
Timeout(initTime += 500, () =>
{
GamePlay.gpHUDLogCenter("Attention! Help is needed at D4!");
});
}
if (Time.tickCounter() % 162000 == 63000) // ; 162000=90 min repeat, 63000 - 35 min delay.
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_sea01.mis");
// GamePlay.gpHUDLogCenter("mis2 loaded");
double initTime = 0.0;
Timeout(initTime += 500, () =>
{
GamePlay.gpHUDLogCenter("Attention! Cover your shipping at C4!");
});
Timeout(initTime += 300, () =>
{
GamePlay.gpHUDLogCenter("Attention! Friendly ships are under attack at C4!");
});
}
if (Time.tickCounter() % 162000 == 117000) // 162000 == 117000 = 90 min repeat, 65 min delay
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air02.mis");
// GamePlay.gpHUDLogCenter("mis3 loaded!");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E3!");
});
Timeout(initTime += 300, () =>
{
GamePlay.gpHUDLogCenter("Attention! All airgroups please proceed to D2!");
});
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// 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(); }
}
);
}
****/
}
Возможно, да. Я думаю, PT оружие будет maddox.game.world.AiGroundActorType.Artillery. Это список актеров наземных объектов:
Если вы хотите сохранить артиллерийских орудий и зенитных орудий, вам необходимо изменить так:Код:Unknown,
Medic,
Motorcycle,
ArmoredCar,
Tractor,
Car,
Amphibian,
SPG,
Tank,
Bus,
LightTruck,
Truck,
Trailer,
Balloon,
Generator,
Predictor,
Radar,
RadioBeacon,
RadioBeamProjector,
Listener,
AmmoComposition,
ContainerShort,
ContainerLong,
Artillery,
AAGun,
Plane,
EngineWagon,
FreightWagon,
PassengerWagon,
ShipMisc,
ShipTransport,
ShipSmallWarship,
ShipDestroyer,
ShipCruiser,
ShipBattleship,
ShipCarrier,
ShipSubmarine,
Bridge,
House
Код:if ((actor as AiGroundActor).Type() != maddox.game.world.AiGroundActorType.AAGun &&
(actor as AiGroundActor).Type() != maddox.game.world.AiGroundActorType.Artillery)
Спасибо! Поднял тестовую Repka #3 с этим скриптом.
Подскажите, пожалуйста, танкеры вот таким образом по сплайнновой дороге, которая просто "дорога" (это невидимый путь?) будут бегать?
[NPC]
18_Chief Ship.Tanker_Medium1 gb /posx 264072.63/posy 205404.94 /script car.cpp/target 0_SplineRoad /sleep 0/skill 2/slowfire 10/tow00_00 1_Static
19_Chief Ship.Tanker_Medium1 de /posx 258181.84/posy 208404.95 /script car.cpp/target 1_SplineRoad /sleep 0/skill 2/slowfire 10/tow00_00 2_Static
Что означают параметры /sleep 0/skill 2/slowfire 10 ?
Какие для них предельные значения?
Прошу проверить часть скрипта, рандомно загружающую одну из 3х подмиссий, на предмет ошибки. не работает, миссии не грузит.
Заранее благодарствую.
upd. fixed http://www.sukhoi.ru/forum/showthrea...=1#post1621945Код:using System;
using maddox.game;
using maddox.game.world;
using System.Collections.Generic;
public class Mission : AMission
{
// loading sub-missions
public override void OnTickGame()
{
if (Time.tickCounter() % 54000 == 12600) // 54000=30 min repeat. 12600=7 min delay.
{
// randomly selects 1 of several submissions
Random RandomIncident = new Random();
switch (RandomIncident.Next(1, 3))
{
case 1:
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/BoF1/BoF1_air01.mis");
// GamePlay.gpHUDLogCenter("mis1 loaded!");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E3!");
});
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("mis2 loaded");
double initTime = 0.0;
Timeout(initTime += 500, () =>
{
GamePlay.gpHUDLogCenter("Attention! Cover your shipping at C4!");
});
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("mis3 loaded!");
double initTime = 0.0;
Timeout(initTime += 600, () =>
{
GamePlay.gpHUDLogCenter("Attention! Enemy activity is expected at E2!");
});
Timeout(initTime += 300, () =>
{
GamePlay.gpHUDLogCenter("Attention! All airgroups 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");
}
}
}
--- Добавлено ---
Подскажите, как можно настраивать GamePlay.gpHUDLogCenter , чтобы писать мельче, другим цветом (ярко-синим, например) и внизу экрана. Как можно возврат каретки / перенос вставить, менять длительность показа?
Было бы неплохо все-таки дать игроку возможность по нажатию клавиши посмотреть текущие цели миссии, которые могут меняться в реальном времени. Например, можно на карте 2ю вкладку сделать для текущих целей и 3ю для общего брифинга, который был в начале миссии. Назначить горячие клавиши ALT-1, 2, 3 например. Для "онлайн-битвы за ресурсы" вещь необходимая.
Несколько вопросов возникло
1. Можно ли как-то узнать локаль игрока, подключившегося к серверу (язык его копии игры), что бы отправлять ему сообщения на его языке?
2. Можно ли отключить в чате сообщения о появлении самолетов в таком-то квадрате, а также сообщения кто куда упал и кто ему в этом помог?
3. И присоединяюсь к вопросу - было бы неплохо для HUD сообщения регулировать его позицию и цвет, а также сделать его многострочным (у меня не получилось). И аналогично, регулировать цвет сообщения в чате (по примеру сообщений о повреждениях).
4. Было бы классно добавить в онлайне что-то вроде таблицы с игроками (по кнопке S который), но содержимое такого окна мог бы регулировать сервер или миссия.
GamePlay.gpHUDLogCenter("",123); 123 - длительность показывания, ещё можно показывать определённым игрокам сообщение , по остальным вопросам - пока никак, возможно позже добавится более широкое управление.
угу, передал, вместе с улучшением карты будут думать как сделать.
погляжу, если можно.
в настройке инфоокна, емнип это сообщения сервера - убрать и не будут показываться. Или как сделать чтобы сам сервер не писал их?
насчёт худ-а согласен, надо что-то придумывать, а цвет сообщений в чате вроде и так настраивается, при настройке инфоокна.
ага, это планируется вроде.
Да, именно сервер. Сейчас он работает как хороший разведчик - скажем я хочу поднять "108-й со старшими офицерами", а сервер красным услужливо подсказывает, что такое дело там-то и там-то появилось.
Аналогично, что бы из миссии можно было задать цвет - скажем сообщение не настолько важное, что бы писать его перед носом большими красными буквами, но тем не менее достаточно полезное для того, что бы его выделить. К тому же чат можно промотать, что бы посмотреть, что приходило ранее, в отличие от HUD сообщений.
угу, понятно, надо наверное фильтр сделать с настройками из сервера.
ясно, в принципе к чату надо доступ наверное сделать серверу, это решит часть вопросов.
По поводу локали игрока - нельзя, но если SayToGroup() использовать с уже существующими сообщениями - они на языке игрока будут.
В режиме с включенными маркерами(иконками) самолетов можно ли как-то убрать с сервера (или скриптом) стрелки по краям экрана или сделать их абсолютно прозрачными для клиентов?
Можно ли настроить дальность, отображаемую сторону (свои/чужие) и цвет иконок самолетов?
Подскажите плз, как вращать обьекты в редакторе?
А можно ли сделать иконки для наземных целей? :-)
Относятся ли корабли к 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
Может быть стоит для кораблей такой же скрипт отдельно прописать? Как корабли в коде называются?
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(); }
}
);
}
Вопрос такой, есть ли возможность из кода скрипта изменять количество сбитых самолетов, обозначенных на киле? Сейчас это доступно в настройках самого самолета, хотелось бы делать это динамически.
И еще такой вопрос, как у нас обстоят дела с динамическим износом самолета (и его скина соответственно тоже)? Он есть, его нет, или его надо прописывать в скрипте, есть доступные функции для этого?
да, корабль - это 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
Вопросы по поводу 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 с их списком и необходимыми вводными данными, не открывая сами скрипты в Студии. Т.е. желательно разделить труд программистов и создателей миссий с помощью удобных инструментов.
секция с описанием карты, времени и пр. начальных условий миссии не нужна в подмиссии - ведь она загружается к уже запущенной миссии - поэтому такую секцию я удалил - так подмиссия чуть-чуть, но быстрее грузится. Если надо в редакторе открыть - можно просто из основной эту секцию скопировать в файл подмиссии :
да, верноКод:[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;
}
да не за что :)
тут смотря что имеется ввиду под "на лету" - это просто кусок из миссии в котором описана группа самолётов. Если Вы этот кусок генерируете сами и потом подгружаете сгенерённую миссию - тогда да, конечно миссия подгрузится со всеми теми изменениями, которые Вы внесли. Если имелась ввиду возможность менять эти параметры у уже загруженных и летящих самолётов - тогда нет, менять номера, кол-во топлива, оружие и т.д. у уже летящих самолётов нельзя.
В общем интересная фишка получилась с ботами. Никакие типы задания для истребителей не заставляли их начать атаковать, даже добавление бомбера с заданием его эскортировать.
Решение было найдено методом тыка. В миссии присутствовал садящийся при старте хуряшка, садился он на другом конце карты. Стоило его убрать - боты сразу стали себя вести адекватно. :D
А как можно суб-скрипт загружать из скрипта, на загружая .mis файл суб-миссии? Хочется разбивать большие скрипты на тематические кусочки, чтобы править только те, которые нужно.
По отзывам бомберов скрипт, который используется на 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(); }
}
);
}
****/
}
да не за что:)
мне кажется наоборот - с открытым кодом есть возможность проверки - что делает скрипт, с закрытым больше возможностей сделать что-то нехорошее.
так вот же - http://www.sukhoi.ru/forum/showthrea...=1#post1608824 скрипт с проверкой в многоместных самолётах. Оттуда проверку можно взять.
С открытым кодом ЛЮБОЙ может туда дописать все что угодно, а потом выдать за оригинальную кампанию(то есть заняться распространением уже своего скрипта под видом оригинального). То есть теоретически любой может получить доступ к чужому ПК.
И еще такой вопрос, МГ имеет возможность помогать тем кто делает Офф-лайн кампании? Помощь нужна такого плана, чтобы сама кампания хранилась на сервере Стима. А то сейчас во-первых при обновлении кэша все нестандартные кампании удаляются. Во-вторых пользователям приходится руками править ini-файлы. Что как бы не есть Юзер-френдли.
И спасибо за консультации.
С Уважением!
Такой открытый код можно проверить, а с закрытым - нельзя, т.е. опять же любой возьмёт Вашу кампанию, напишет вместо Вашего скрипта свой - и увидеть это нельзя будет никак.
На стиме, к сожалению, хранить кампании не получится, почему - попробуйте у Лютьера уточнить. А можно детали про удаление нестандартных кампаний? По идее кампания хранящаяся в своей папке не должна удаляться, если удаляется может быть баг какой-то, постараемся исправить.
всегда пожалуйста :)
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;
}
// если логика битвы другая , тогда этот блок с проверкой убираем
}
}
}
}