PDA

View Full Version : Script limiting aircraft types (including multilingual messages)


Ataros
10-06-2011, 09:43 AM
Here is a current WIP script version from Repka Steppe map. Kodiak and TheEnlightenedFlorist, thank you for your help. Without you it would not be possible.

The script runs on Repka #1 ATM please try it and let me know what you think.

Kodiak, when you have time I would like to ask you for advice how to calculate number of enemy fighter and bomber planes. Ideally I see aircraft limiting script as follows:

Declare percentages for limited aircraft types = X%.
OnPlaceEnter recalculate number of human-controlled enemy fighter and bomber planes (enmyFgtrs & enmyBmbrs) - this is the difficult part :)
Set curTeamBalance = (friendlyFgtrs + friendlyBmbrs/2) / (enmyFgtrs + enmyBmbrs/2)
Check if
if curTeamBalance > allowedTeamBalance then deny a limited aircraft (with RU and international message).
else Set e.g. allowed109s = (X% * (enmyFgtrs + enmyBmbrs/2) * objCompleted) / curTeamBalance
double objCompleted = 1 for now (to be used in the future with triggers probably as a bonus for completing objectives).

Check if (current109s > allowed109s) then deny an aircraft.
Leave a window of opportunity for other players to take a limited aircraft after a player that just flew a limited aircraft takes it again (I do it in code reducing current109s by 1 for 20 seconds and then increasing it again).

I know that other servers experience huge issues trying to find balance between SpitIIs and 109s and this script may be very useful for everyone flying online.


using System;
using System.Collections;
using maddox.game;
using maddox.game.world;
using System.Collections.Generic;

using System.Diagnostics;


/**
* Parts of the script were taken from:
* Operation Dynamo v2.0 by TheEnlightenedFlorist http://forum.1cpublishing.eu/showthread.php?t=23579&highlight=operation+dynamo
* Messages script by FG28_Kodiak http://forum.1cpublishing.eu/showthread.php?t=26623
*
* * */


public class Mission : AMission
{

//allowed and currently flying aircraft
int allowed109s = 12;
int current109s = 0;

int allowedSpit2s = 7;
int currentSpit2s = 0;

int allowed110s = 5;
int current110s = 0;
//double allowedTeamBalance = 1.2;
//double currentTeamBalance = 1;

public override void OnBattleStarted()
{
base.OnBattleStarted();
//listen to events from all missions.
MissionNumberListener = -1;

}


public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceEnter(player, actor, placeIndex);

if (actor != null && actor is AiAircraft)
{
clickFlagMsg(player); // reminds to click flag to change an aircraft

//checks limited aircraft
switch ((actor as AiAircraft).InternalTypeName())
{
case "bob:Aircraft.Bf-109E-4":
{
current109s++;
// test
//GamePlay.gpHUDLogCenter(String.Format("current109s = {0}", current109s));

if (current109s > allowed109s)
{
(actor as AiAircraft).hitNamed(part.NamedDamageTypes.Eng0Tot alFailure);
notAvailableMsg(player);
}
else
// Возможность для других взять самолет. Window of opportunity for others.
current109s--;
// test
//Timeout(10, () =>
// {
// GamePlay.gpHUDLogCenter(String.Format("current109s = {0}", current109s));
// });

Timeout(20, () =>
{
current109s++;
//GamePlay.gpHUDLogCenter(String.Format("current109s = {0}", current109s));
});

break;
}
case "bob:Aircraft.SpitfireMkIIa":
{
currentSpit2s++;
if (currentSpit2s > allowedSpit2s)
{
(actor as AiAircraft).hitNamed(part.NamedDamageTypes.Eng0Tot alFailure);
notAvailableMsg(player);
//GamePlay.gpHUDLogCenter(new Player[] { player }, "Aircraft not available! Choose another aircraft.");
}
else
// Возможность для других взять самолет. Window of opportunity for others.
currentSpit2s--;
// test
//Timeout(10, () =>
// {
// GamePlay.gpHUDLogCenter(String.Format("currentSpit2s = {0}", currentSpit2s));
// });

Timeout(20, () =>
{
currentSpit2s++;
//GamePlay.gpHUDLogCenter(String.Format("currentSpit2s = {0}", currentSpit2s));
});

break;
}
case "bob:Aircraft.Bf-110C-7":
{
current110s++;
if (current110s > allowed110s)
{
//(actor as AiAircraft).hitNamed(part.NamedDamageTypes.Eng0Tot alFailure); // Is this line for single-engined only? только для одномоторных?

// Will this do for multi-engine?
int iNumOfEngines = ((actor as AiAircraft).Group() as AiAirGroup).aircraftEnginesNum();
for (int i = 0; i < iNumOfEngines; i++)
{
(actor as AiAircraft).hitNamed((part.NamedDamageTypes)Enum.P arse(typeof(part.NamedDamageTypes), "Eng" + i.ToString() + "TotalFailure"));
}

notAvailableMsg(player);
//GamePlay.gpHUDLogCenter(new Player[] { player }, "Aircraft not available! Choose another aircraft.");
}
else
// Возможность для других взять самолет. Window of opportunity for others.
current110s--;
// test
//Timeout(10, () =>
// {
// GamePlay.gpHUDLogCenter(String.Format("current110s = {0}", current110s));
// });

Timeout(20, () =>
{
current110s++;
//GamePlay.gpHUDLogCenter(String.Format("current110s = {0}", current110s));
});
break;
}
}
}
}


public override void OnPlaceLeave(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceLeave(player, actor, placeIndex);

if (actor != null && actor is AiAircraft)
{

//check limited aircraft
switch ((actor as AiAircraft).InternalTypeName())
{
case "bob:Aircraft.Bf-109E-4":
current109s--;
break;
case "bob:Aircraft.SpitfireMkIIa":
currentSpit2s--;
break;
case "bob:Aircraft.Bf-110C-7":
current110s--;
break;
}

}
}

//public override void OnTickGame()
// {
// // Reminders (UPD: not needed now.)
// if (Time.tickCounter() % 9000 == 0)
// {
// sendChatMessageTo(-1, null, "Attention! To change an aircraft first click on the side flag in the top right corner of the menu or press ALT-F2 in game!", null);
// sendChatMessageTo(0, null, "Attention! To change an aircraft first click on the side flag in the top right corner of the menu or press ALT-F2 in game!", null);
// // Have to separate armies below to make the message show only to RU users. Otherwise it shows to everyone if army=-1.
// // Приходится разделять армии, иначе иностранцам тоже текст покажется.
// sendChatMessageTo(1, "ru", "Внимание! Чтобы сменить самолет, сначала кликните на флаге стороны в правом верхнем углу меню или нажмите ALT-F2 в игре!", null);
// sendChatMessageTo(2, "ru", "Внимание! Чтобы сменить самолет, сначала кликните на флаге стороны в правом верхнем углу меню или нажмите ALT-F2 в игре!", null);
// sendChatMessageTo(0, "ru", "Внимание! Чтобы сменить самолет, сначала кликните на флаге стороны в правом верхнем углу меню или нажмите ALT-F2 в игре!", null);
// }
// }

// Messages
private void notAvailableMsg(Player player)
{
switch (player.LanguageName())
{
case "de":
GamePlay.gpHUDLogCenter(new Player[] { player }, "Limit für diesen Flugzeugtyp erreicht! Wähle ein anderes Muster!");
break;
case "ru":
GamePlay.gpHUDLogCenter(new Player[] { player }, "Слишком много самолетов данного типа! Выберите другой самолет.");
break;
default:
GamePlay.gpHUDLogCenter(new Player[] { player }, "Too many aircrafts of this type! Choose another aircraft.");
break;
}
}

private void clickFlagMsg(Player player)
{
switch (player.LanguageName())
{
case "de":
GamePlay.gpLogServer(new Player[] { player }, "Attention! To change an aircraft first click on the side flag in the top right corner of the menu or press ALT-F2 in game!", null);
break;
case "ru":
GamePlay.gpLogServer(new Player[] { player }, "Внимание! Чтобы сменить самолет, сначала кликните на флаге стороны в правом верхнем углу меню или нажмите ALT-F2 в игре!", null);
break;
default:
GamePlay.gpLogServer(new Player[] { player }, "Attention! To change an aircraft first click on the side flag in the top right corner of the menu or press ALT-F2 in game!", null);
break;
}
}


// Temporary desabled. Messages script by FG28_Kodiak http://forum.1cpublishing.eu/showthread.php?t=26623

//private void sendChatMessageTo(int army, string playerlanguage, string msg, object[] parms)
//{
// if (army != -1)
// {
// //Singleplayer (for Testing)
// if (GamePlay.gpRemotePlayers() == null || GamePlay.gpRemotePlayers().Length <= 0)
// {
// if (GamePlay.gpPlayer() != null && GamePlay.gpPlayer().Army() == army && GamePlay.gpPlayer().LanguageName().Equals(playerla nguage))
// GamePlay.gpLogServer(null, msg, parms);
// }
// else // Multiplayer
// {
// List<Player> Players = new List<Player>();

// foreach (Player p in GamePlay.gpRemotePlayers())
// {
// if (p.Army() == army && p.LanguageName().Equals(playerlanguage))
// Players.Add(p);
// }
// GamePlay.gpLogServer(Players.ToArray(), msg, parms);
// }
// }
// else GamePlay.gpLogServer(null, msg, parms); // this shows Russian text to everyone. Покажет иностранцам русский текст
//}


//private void sendScreenMessageTo(int army, string playerlanguage, string msg, object[] parms)
//{
// if (army != -1)
// {
// //Singleplayer (for Testing)
// if (GamePlay.gpRemotePlayers() == null || GamePlay.gpRemotePlayers().Length <= 0)
// {
// if (GamePlay.gpPlayer() != null && GamePlay.gpPlayer().Army() == army && GamePlay.gpPlayer().LanguageName().Equals(playerla nguage))
// GamePlay.gpHUDLogCenter(null, msg, parms);

// }
// else // Multiplayer
// {
// List<Player> Players = new List<Player>();

// foreach (Player p in GamePlay.gpRemotePlayers())
// {
// if (p.Army() == army && p.LanguageName().Equals(playerlanguage))
// Players.Add(p);
// }
// GamePlay.gpHUDLogCenter(Players.ToArray(), msg, parms);
// }
// }
// else GamePlay.gpHUDLogCenter(null, msg, parms);
//}

}



Regarding messages script it looks like a RU message would be shown to everyone if using sendChatMessageTo(-1, ru, ...)

sendChatMessageTo(-1, null, ...) shows international message to RU users. Ideally I would like to separate messages to RU and international users completely if possible.

FG28_Kodiak
10-06-2011, 10:06 AM
Regarding messages script it looks like a RU message would be shown to everyone if using sendChatMessageTo(-1, ru, ...)

sendChatMessageTo(-1, void, ...) shows international message to RU users. Ideally I would like to separate messages to RU and international users completely if possible.



Ok my fault :sad:, have forgotten to handle different languages if send on all.

Corrected version:

private void sendScreenMessageTo(int army, string playerlanguage, string msg, object[] parms)
{
if (army != -1)
{
//Singleplayer (for Testing)
if (GamePlay.gpRemotePlayers() == null || GamePlay.gpRemotePlayers().Length <= 0)
{
if (GamePlay.gpPlayer() != null && GamePlay.gpPlayer().Army() == army && GamePlay.gpPlayer().LanguageName().Equals(playerla nguage))
GamePlay.gpHUDLogCenter(null, msg, parms);

}
else // Multiplayer
{
List<Player> Players = new List<Player>();

foreach (Player p in GamePlay.gpRemotePlayers())
{
if (p.Army() == army && p.LanguageName().Equals(playerlanguage))
Players.Add(p);
}
GamePlay.gpHUDLogCenter(Players.ToArray(), msg, parms);
}
}
else
{
List<Player> Players = new List<Player>();

foreach (Player p in GamePlay.gpRemotePlayers())
{
if (p.LanguageName().Equals(playerlanguage))
Players.Add(p);
}
GamePlay.gpHUDLogCenter(Players.ToArray(), msg, parms);
}
}


private void sendChatMessageTo(int army, string playerlanguage, string msg, object[] parms)
{
if (army != -1)
{
//Singleplayer (for Testing)
if (GamePlay.gpRemotePlayers() == null || GamePlay.gpRemotePlayers().Length <= 0)
{
if (GamePlay.gpPlayer() != null && GamePlay.gpPlayer().Army() == army && GamePlay.gpPlayer().LanguageName().Equals(playerla nguage))
GamePlay.gpLogServer(null, msg, parms);
}
else // Multiplayer
{
List<Player> Players = new List<Player>();

foreach (Player p in GamePlay.gpRemotePlayers())
{
if (p.Army() == army && p.LanguageName().Equals(playerlanguage))
Players.Add(p);
}
GamePlay.gpLogServer(Players.ToArray(), msg, parms);
}
}
else
{
List<Player> Players = new List<Player>();

foreach (Player p in GamePlay.gpRemotePlayers())
{
if (p.LanguageName().Equals(playerlanguage))
Players.Add(p);
}
GamePlay.gpLogServer(Players.ToArray(), msg, parms);
}
}



Kodiak, when you have time I would like to ask you for advice how to calculate number of enemy fighter and bomber planes. Ideally I see aircraft limiting script as follows:

Declare percentages for limited aircraft types = X%.
OnPlaceEnter recalculate number of human-controlled enemy fighter and bomber planes (enmyFgtrs & enmyBmbrs) - this is the difficult part
Set curTeamBalance = (friendlyFgtrs + friendlyBmbrs/2) / (enmyFgtrs + enmyBmbrs/2)
Check if
if curTeamBalance > allowedTeamBalance then deny a limited aircraft (with RU and international message).
else Set e.g.


Nothing difficult ;).
Should the script calculate all in game planes too, or only the player controlled? So it should be possible to disable KI Starts if many Players are online.

Ataros
10-06-2011, 12:39 PM
Should the script calculate all in game planes too, or only the player controlled? So it should be possible to disable KI Starts if many Players are online.

IMO it is reasonable to balance player controlled planes only.
Sorry did not get what you mean by KI Starts? If you mean AI, I do not want to limit AI flights.

Thank you very much again.

FG28_Kodiak
10-06-2011, 12:43 PM
German KünstlicheInteligenz = English ArtificialIntelligence
just a little language mismatch ;)

FG28_Kodiak
10-06-2011, 01:33 PM
I see a little problem
How to handle if one side don't have human pilots. Then your formula tries a division by zero and this will results in an error.

Ataros
10-06-2011, 02:12 PM
I see a little problem
How to handle if one side don't have human pilots. Then your formula tries a division by zero and this will results in an error.

Maybe it is possible to check if human pilots > 0 first.

Or maybe divide (1 + friendlyFgtrs + friendlyBmbrs/2) / (1+ enmyFgtrs + enmyBmbrs/2). It will do.

Or we can deny premium planes at all if say other side has less than 2 human players.

edit
What I do not know is how to handle other side players which are still in the menu and not flying. Can they be taken into account? If yes, probably 80% of them should be accounted as fighters and 20% as bombers if you do not mind. But it is not very important I think.

Ataros
10-12-2011, 09:40 PM
It looks I am in trouble with my script here too.

Again it works for hosted server killing my engine when required but does not work on dedicated server.

First I used this line as you can see above in my message
(actor as AiAircraft).hitNamed(part.NamedDamageTypes.Eng0Tot alFailure);

It did not work online on a dedicated server.

Then I tried to modify actor-damaging script to destroy player plane. The same thing happens. On a dedicated server this script damages abondoned aircrat but my modified methods do not work. But work on hosted server (when I am the server).

OnPlaceEnter check where damagePlayerGroup((actor as AiAircraft)) does not work on a dedi.
//checks limited aircraft

showTestMsg(player);

if (actor != null && actor is AiAircraft)
{
windowOfOp = 10;
switch ((actor as AiAircraft).InternalTypeName())
{
case "bob:Aircraft.Bf-109E-4":
{
current109s++;
showTestMsg(player);

// !!! test !!!
if (current109s > allowed109s) // || current109s > 1) // !!! test !!!
{
damagePlayerGroup((actor as AiAircraft));
Timeout(12, () =>
{
msgTooManyAircraft(player);
showTestMsg(player);
});

}
break;
}

Methods (my methods are in the end)
#region Destroy Actors Methods
// by TheEnlightenedFlorist http://www.airwarfare.com/sow/index.php?option=com_kunena&func=view&catid=43&id=539&Itemid=54

private bool isAiControlledPlane(AiAircraft aircraft)
{
if (aircraft == null)
return false;

//check if a player is in any of the "places"
for (int i = 0; i < aircraft.Places(); i++)
if (aircraft.Player(i) != null)
return false;

return true;
}

private void destroyPlane(AiAircraft aircraft)
{
if (aircraft != null && isAiControlledPlane(aircraft))
aircraft.Destroy();
}

private void damageAiControlledPlane(AiActor actorMain)
{
foreach (AiActor actor in actorMain.Group().GetItems())
{
if (actor == null || !(actor is AiAircraft))
return;

AiAircraft aircraft = (actor as AiAircraft);

if (!isAiControlledPlane(aircraft))
return;

if (aircraft == null)
return;

aircraft.hitNamed(part.NamedDamageTypes.ControlsEl evatorDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsAi leronsDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsRu dderDisabled);
aircraft.hitNamed(part.NamedDamageTypes.FuelPumpFa ilure);
int iNumOfEngines = (aircraft.Group() as AiAirGroup).aircraftEnginesNum();
for (int i = 0; i < iNumOfEngines; i++)
{
aircraft.hitNamed((part.NamedDamageTypes)Enum.Pars e(typeof(part.NamedDamageTypes), "Eng" + i.ToString() + "TotalFailure"));
}


Timeout(240, () =>
{ destroyPlane(aircraft); }
);
}
}
// Ataros method
private void destroyPlayerPlane(AiAircraft aircraft)
{
if (aircraft != null)
aircraft.Destroy();
}

private void damagePlayerGroup(AiActor actorMain)
{
foreach (AiActor actor in actorMain.Group().GetItems())
{
if (actor == null ) // || !(actor is AiAircraft))
return;

AiAircraft aircraft = (actor as AiAircraft);

if (!isAiControlledPlane(aircraft))
{
if (aircraft != null)
{
aircraft.hitNamed(part.NamedDamageTypes.ControlsEl evatorDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsAi leronsDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsRu dderDisabled);
aircraft.hitNamed(part.NamedDamageTypes.FuelPumpFa ilure);
int iNumOfEngines = (aircraft.Group() as AiAirGroup).aircraftEnginesNum();
for (int i = 0; i < iNumOfEngines; i++)
{
aircraft.hitNamed((part.NamedDamageTypes)Enum.Pars e(typeof(part.NamedDamageTypes), "Eng" + i.ToString() + "TotalFailure"));
}

//Timeout(60, () =>
// { destroyPlayerPlane(aircraft); }
// );
}
}
}
}

#endregion

Sure it must be something basic that I can not see with my eyes. Attached a complete script.

FG28_Kodiak
10-13-2011, 04:37 AM
Its a bug in dedi. As Workaround i use in my penalty script:

private void DoDamageToAirplane(AiAircraft aircraft)
{
if (!aircraft.IsAirborne())
{
// plane on ground Undercarriage cut off
aircraft.cutLimb(part.LimbNames.WingL0);
aircraft.cutLimb(part.LimbNames.WingL1);
aircraft.cutLimb(part.LimbNames.WingL2);
aircraft.cutLimb(part.LimbNames.WingL3);
aircraft.cutLimb(part.LimbNames.WingL4);
aircraft.cutLimb(part.LimbNames.WingL5);
aircraft.cutLimb(part.LimbNames.WingL6);
aircraft.cutLimb(part.LimbNames.WingL7);
aircraft.cutLimb(part.LimbNames.WingR0);
aircraft.cutLimb(part.LimbNames.WingR1);
aircraft.cutLimb(part.LimbNames.WingR2);
aircraft.cutLimb(part.LimbNames.WingR3);
aircraft.cutLimb(part.LimbNames.WingR4);
aircraft.cutLimb(part.LimbNames.WingR5);
aircraft.cutLimb(part.LimbNames.WingR6);
aircraft.cutLimb(part.LimbNames.WingR7);
}
else
{
// plane in Air Tail cut off
aircraft.cutLimb(part.LimbNames.Tail0);
aircraft.cutLimb(part.LimbNames.Tail1);
aircraft.cutLimb(part.LimbNames.Tail2);
aircraft.cutLimb(part.LimbNames.Tail3);
aircraft.cutLimb(part.LimbNames.Tail4);
aircraft.cutLimb(part.LimbNames.Tail5);
aircraft.cutLimb(part.LimbNames.Tail6);
aircraft.cutLimb(part.LimbNames.Tail7);
}
}

Its not the best solution but it works on dedi, sometimes you get a index out of bound error in console, it depends on aircrafttype you use, not figuered out at the moment ;), normaly you must test every aircraft which parts could be damaged, but its not a critical error.

At the moment i working on a script, which remove and add planes (on the fly) to the birthplaces, so its no longer nessesary to damage 'overused' planes. But in the moment its in a early stage.

Ataros
10-13-2011, 06:28 AM
Thank you!
Maybe you can get Length of LimbNames.Tail from the game same as with engines here and run a loop? Tail would do the job in the air too I think.

int iNumOfEngines = (aircraft.Group() as AiAirGroup).aircraftEnginesNum();
for (int i = 0; i < iNumOfEngines; i++)
{
aircraft.hitNamed((part.NamedDamageTypes)Enum.Pars e(typeof(part.NamedDamageTypes), "Eng" + i.ToString() + "TotalFailure"));
}

Ataros
10-19-2011, 04:01 PM
1.11 version up on Repka #3 for testing

Ataros
10-20-2011, 09:49 AM
I have a more general question which I hope someone can answer:

My mission loads submission with some parameters (attacker army, mission type, attack sector, etc), then gets trigger status, calculates mission results and shows results messages using the same parameters. It goes fine when submissions are loaded one by one.

I want to add different types of submissions and make them overlap in time. Naturally I have to store parameters of every submissions as different variables to prevent them mixing up.

How can I do this? Should I create a list for each parameter and send it to array when each new submission loads or there is a more elegant way to do this. I will not have more then 10 submissions going on simultaneously and do not have to create arrays with the length of total past submissions quantity.

FG28_Kodiak
10-20-2011, 01:56 PM
Make a class with all infos you need and then store the objects in a list.

For example :

using System;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;

public class Mission : AMission
{
public static string SubMissionsPath = @"missions\Multi\Dogfight\test\subs\";


public class Mis
{
public string Missionfilename {get; set;}
public string PathToMission { get; set; }
public DateTime MissionBegin{get; set;}
public DateTime MissionEnd{get; set;}
public double MissionLengh{get; set;}
public bool IsMissionRunning { get; set; }

public Mis(string Filename, string Path, double Lengh)
{
this.Missionfilename = Filename;
this.PathToMission = Path;
this.MissionLengh = Lengh;
}

}

public List<Mis> MissionPool = new List<Mis>()
{
new Mis ("Mission1.mis",SubMissionsPath ,1000.0),
new Mis ("Mission2.mis",SubMissionsPath ,1000.0),
};


public override void OnBattleStarted()
{
base.OnBattleStarted();


MissionNumberListener = -1;

try
{
foreach (Mis mi in MissionPool)
GamePlay.gpPostMissionLoad(mi.PathToMission + mi.Missionfilename);

}
catch
{

GamePlay.gpLogServer(null, "File not found", null);
}
}


public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceEnter(player, actor, placeIndex);

}
}

Ataros
10-20-2011, 04:40 PM
Thank yoг for a good example. I will try creating a class for my needs and will come back with more questions if any.

S!

Ataros
10-21-2011, 02:41 PM
I did the exercise, sure with many mistakes but will do some reading on classes creation to correct them.

However I am stuck in OnTrigger method completely.

I have several submissions running at the same time with the same filenames and the same trigger names. This happens because they are randomly loaded and the same submission can be loaded 2-4 times within an hour.

How can I identify which trigger of which submission is triggered OnTrigger? I number my missions as "mi.MisMissionNumber" but their numbers are different from OnTrigger "missionNumber".

The file is renamed to a .txt.

If you have time to answer other questions I will appreciate it.

FG28_Kodiak
10-21-2011, 04:43 PM
Will take a look at it.

Short answers:

public static string SubMissionsPath = @"missions\Multi\Dogfight\r_steppe\subs\";
// is @ necessary here? did not use it in other missions.

With @ at the beginning you must not write \\ every time. The \ is a special character in C# (C, C++) and normaly for escape sequences \n newline for example. If you want to use \ in your string you must write \\ and to avoid the double use you can set a @ at the beginning of your string so \ is a normal character.


// what does this block do?
public Mis(string Filename, string misType, int Lengh) // should I include all the above variables here?
{
this.Missionfilename = Filename; // You use mi.Missionfilename instead of mi.Filename in your example when load missions. Why?
this.MissionLengh = Lengh;
this.MissionType = misType;
this.TrgWasTriggered = wasTriggered;
}

this is a constructor of the class (you can also use more of them overloaded). It's usefull if you like to initialize more variables or making calculations etc.

So i can use

public List<Mis> MissionPool = new List<Mis>()
{
new Mis ("Mission1.mis",SubMissionsPath ,1000.0),
new Mis ("Mission2.mis",SubMissionsPath ,1000.0),
};

to create several entries at one time.

// You use mi.Missionfilename instead of mi.Filename in your example when load missions. Why?
I use the public method Missionfilename to get access to the variable in the object. Filename is only used in the constructor to give the value to the variable Missionfilename.

More to come, must take a deeper look at it, but no time at the moment.
But it seems you think a bit too complicated ;)

Ataros
10-21-2011, 05:09 PM
Filename is only used in the constructor to give the value to the variable Missionfilename.

Does it mean I can initialize variables in this block, replacing e.g. Length with a value I want to assign?
this.MissionLengh = 30;

Ah, it looks like the only purpose of it is to allow data input like here:
public List<Mis> MissionPool = new List<Mis>()
{
new Mis ("Mission1.mis",SubMissionsPath ,1000.0),
new Mis ("Mission2.mis",SubMissionsPath ,1000.0),
};

So when I create a new Mis I can enter data there from e.g. parsed filename in one line only, not having to use 3 lines like
mi.Missionfilename = ...;
mi.SubMissionsPath = ...;
mi.MissionLengh = ...;

Instead after parsing a file name I can:

string[] MisParams;
MisParams = (mi.Missionfilename).Split('_');

Mis mi = new Mis (MisParams[1], MisParams[2],MisParams[3]);

Thanks a lot!

pupo162
05-20-2012, 03:45 PM
first sorry for bumping an old thread.

im facing an issue implementing a "similar" (based) on this method script.

my issue is, with multi-sit aircriaft. when you spawn in one of those and change seats with will result in decrease of 1 to the pool by each seat.


much of the following CODE is not mine (around 90%) so no credit for it. Credit goes for Ataros, Kodiak, and some other guys, i cant recall everyone i steal from :grin:


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using maddox.GP;
using maddox.game;
using maddox.game.world;
using part;
using System.Diagnostics;
using System.Collections;


public class Mission : AMission
{

//-------------SCORE---------------------------------------
int redscore = 0;
int bluescore = 0;
//-------------TEAMS--------------------------------------
const int ArmyRed = 1;
const int ArmyBlue = 2;
//-------------TIME----------------------------------------
private double timeValue = 60;
private double time;
private double timeValue2 = 600;
//----------------------------------------------


Dictionary<string, int> lwa = new Dictionary<string, int>()
{
//Internaltypename, Startcount
{"bob:Aircraft.Bf-109E-3",6},
{"bob:Aircraft.Bf-109E-3B",2},
{"bob:Aircraft.Bf-109E-1",9999},
// {"bob:Aircraft.Bf-109E-4",0},
{"bob:Aircraft.Bf-109E-4B",0},
//{"bob:Aircraft.Bf-110C-4",0},
{"bob:Aircraft.Bf-110C-7",4},
{"bob:Aircraft.Ju-87B-2",9999},
{"bob:Aircraft.Ju-88A-1",4},
//{"bob:Aircraft.He-111H-2",0},
//{"bob:Aircraft.He-111P-2",0},
};


Dictionary<string, int> lwv = new Dictionary<string, int>()
{
//Internaltypename, Startcount
{"bob:Aircraft.Bf-109E-3",60},
{"bob:Aircraft.Bf-109E-3B",24},
{"bob:Aircraft.Bf-109E-1",40},
{"bob:Aircraft.Bf-109E-4",50},
{"bob:Aircraft.Bf-109E-4B",24},
{"bob:Aircraft.Bf-110C-4",24},
{"bob:Aircraft.Bf-110C-7",24},
{"bob:Aircraft.Ju-87B-2",60},
{"bob:Aircraft.Ju-88A-1",40},
{"bob:Aircraft.He-111H-2",60},
{"bob:Aircraft.He-111P-2",20},
};


Dictionary<string, int> rafa = new Dictionary<string, int>()
{
//Internaltypename, Startcount
{"bob:Aircraft.SpitfireMkI",6},
{"bob:Aircraft.SpitfireMkIa",4},
//{"bob:Aircraft.SpitfireMkIIa",0},
{"bob:Aircraft.HurricaneMkI",9999},
{"bob:Aircraft.HurricaneMkI_dH5-20",9999},
//{"bob:Aircraft.BlenheimMkIV",0},
//{"bob:Aircraft.SpitfireMkIIa",0},
};


Dictionary<string, int> rafv = new Dictionary<string, int>()
{
//Internaltypename, Startcount
{"bob:Aircraft.SpitfireMkIa",30},
{"bob:Aircraft.SpitfireMkI",60},
{"bob:Aircraft.HurricaneMkI",50},
{"bob:Aircraft.HurricaneMkI_dH5-20",50},
{"bob:Aircraft.BlenheimMkIV",40},
{"bob:Aircraft.SpitfireMkIIa",120},
};


//----------------------CLASS----------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
public override void OnBattleStarted()
{
base.OnBattleStarted();

//listen to events from all missions.
MissionNumberListener = -1;
}
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
public override void OnTickGame()
{
base.OnTickGame();




if (Time.current() >= time & Time.current() < 300)
{
GamePlay.gpHUDLogCenter("TIME UNTIL START: " + (5 - (time / 60)) + " minutes");
time = time + timeValue;
}




if (Time.current() > 300 & Time.current() < 310)
{
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/USL/mission1.mis");
GamePlay.gpHUDLogCenter("MISSION START! GO!");
//time = 300 + timeValue2;
time = 300 + 15;
}



if (Time.current() > time & Time.current() < 2400 & Time.current() > 300)
{
GamePlay.gpHUDLogCenter("Mission time: " + time / 60 + " minutes, score: reds-" + redscore + "blue-" + bluescore + "");
//time = time + timeValue2;
time = time + 30;
}



if (Time.current() >= time & Time.current() >= 3000 & Time.current() < 3600)
{
GamePlay.gpHUDLogCenter("TIME LEFT UNTILL MISSION END: " + (65 - (time / 60)) + " minutes, score: red- " + redscore + " blue- " + bluescore + "");
// time = time + 2 * timeValue;
time = time + 30;
}


if (Time.current() == 3600)
{
GamePlay.gpHUDLogCenter("MISSION IS OVER!");
}

}
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
private void destroyPlane(AiAircraft aircraft)
{
if (aircraft != null)
{
aircraft.Destroy();
}
}
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
private string SplitName(string tmpstring)
{

string[] temp = tmpstring.Split(':', '.', '_');

string lt = "";
string ausgabe = "";

ausgabe = temp[1] + ": ";

for (int i = 2; i < temp.Length; i++)
{
lt = temp[i] + " ";

ausgabe += lt;
}
return ausgabe;
}
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceEnter(player, actor, placeIndex);

AiAircraft aircraft = actor as AiAircraft;

int value, CurrentCount = 0;

if (aircraft != null)


switch (aircraft.Army())
{
case 1:
if (rafa.TryGetValue((actor as AiAircraft).InternalTypeName(), out value))
CurrentCount = rafa[(actor as AiAircraft).InternalTypeName()];

if (CurrentCount <= 0)
{

GamePlay.gpHUDLogCenter(new Player[] { player }, "{0} not available", new object[] { SplitName((actor as AiAircraft).InternalTypeName()) });
Timeout(10, () =>
{ destroyPlane(actor as AiAircraft); });
}
else
{
rafa[(actor as AiAircraft).InternalTypeName()]--;
GamePlay.gpHUDLogCenter(new Player[] { player }, "{0} : " + CurrentCount + " left", new object[] { SplitName((actor as AiAircraft).InternalTypeName()) });
}
break;



case 2:
if (lwa.TryGetValue((actor as AiAircraft).InternalTypeName(), out value))
CurrentCount = lwa[(actor as AiAircraft).InternalTypeName()];

if (CurrentCount <= 0)
{
GamePlay.gpHUDLogCenter(new Player[] { player }, " {0} not available", new object[] { SplitName((actor as AiAircraft).InternalTypeName()) });
Timeout(10, () =>
{ destroyPlane(actor as AiAircraft); });
}
else
{
lwa[(actor as AiAircraft).InternalTypeName()]--;
GamePlay.gpHUDLogCenter(new Player[] { player }, "{0} : " + CurrentCount + " left", new object[] { SplitName((actor as AiAircraft).InternalTypeName()) });
}
break;


}
}

FG28_Kodiak
05-20-2012, 05:50 PM
You can check if a player is already in a plane


public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceEnter(player, actor, placeIndex);

int playercount = 0;

if (actor != null && actor is AiAircraft)
{
AiAircraft aircraft = actor as AiAircraft;

for (int i = 0; i < aircraft.Places(); i++)
{
if (aircraft.Player(i) != null)
{
if (aircraft.Player(i) == player) playercount++;
}
}
}


if (playercount == 1) ..

}


A Player can have two places in an aircraft (PlacePrimary() and PlaceSecondary()) so if playercount is > 1 (2 ;)) the player has changed his place in the aircraft.


or you check PlaceSecondary, PlaceSecondary is -1 if a player is 'new' in a plane, if not new PlaceSecondary gets the value of the last secondary place.

if (player.PlaceSecondary() != -1)
..

Blackdog_kt
05-20-2012, 07:11 PM
A bit unrelated to the actual discussion, but what you say about primary and secondary places confirms my observations about AI gunners.

We all know that if you switch to a gunner position the AI no longer mans the turret. Flying a Blenheim on ATAG one night, i happened to find out completely by chance that if your aircraft has a bombardier position you can give back gun control to the AI: simply cycle between pilot and bombardier once and your gunners will revert to AI control.

This was also reflected on the net stats overlay, where next to my nickname i could see "pilot, gunner" initially and "pilot, bombardier" after cycling positions.

Thanks for confirming my suspicions ;)

pupo162
05-20-2012, 07:43 PM
thank you!

Worked like a charm!

pupo162
05-22-2012, 07:57 PM
Hi, still on the same topic, yet a differente type of code, im tryign to get a submenu to have an option to refly.

code

public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
{
base.OnOrderMissionMenuSelected(player, ID, menuItemIndex);

if (player != null)
{
if (menuItemIndex == 1)
{
GamePlay.gpHUDLogCenter(new Player[] { player }, "Red - {0} blue - {1}", new object[] { redscore, bluescore });

}
if (menuItemIndex == 2)
{
GamePlay.gpHUDLogCenter(new Player[] { player }, "Ainda nao funciona");
}
if (menuItemIndex == 3)
{
GamePlay.gpHUDLogCenter(new Player[] { player }, "You will refly in 5 seconds!");
Timeout(20, () =>
{ destroyPlane(aircraft); });
}
}
}

The clear problem is, aircraft used in destroy plane, does not exist i nthis function, pnly player. how do i get over this?

sorry, but im really noob in C#

FG28_Kodiak
05-23-2012, 07:02 AM
you get the Aircraft via player.Place()


if (player.Place() != null && player.Place() is AiAircraft)
{
AiAircraft aircraft = player.Place() as AiAircraft;


}

pupo162
05-23-2012, 09:53 AM
Thnak you Kodiak, will try that when i get home.

Where do you get all of this info? of what info is stored in wich class? and wich classes can be converted to others?

from trial and error, and from seeing other people i get to learn some of them ( actor can be used as aircraft and such), but where does this knowledge comes from? trial and error?

FG28_Kodiak
05-23-2012, 10:04 AM
Object-Explorer in Visual Studio and try and error (sometimes Cliffs don't react as expected :rolleyes:).

_79_dev
05-29-2012, 02:58 PM
Can any of You guys update "plane limit" script that`s working 100% on dedi server pleas...

FG28_Kodiak
06-07-2012, 10:57 AM
Don't know if this script working 100% at Dedi Server (theoretical it should :rolleyes:), have not the time to test it properly so it's on you ;):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using maddox.GP;
using maddox.game;
using maddox.game.world;
using part;

public class Mission : AMission
{

/// <summary>
/// This Dictionary contains the InternalTypeName of the limited actor and the number of available actors
/// </summary>
/// <remarks>Actors which are not in List are not limited</remarks>
internal Dictionary<string, int> AircraftLimitations = new Dictionary<string, int>
{
//{"bob:Aircraft.Bf-109E-3",10},
//{"bob:Aircraft.Bf-109E-3B",10},
//{"bob:Aircraft.Bf-109E-1",10},
{"bob:Aircraft.Bf-109E-4",5},
{"bob:Aircraft.Bf-109E-4B",5},
//{"bob:Aircraft.Bf-110C-4",10},
//{"bob:Aircraft.Bf-110C-7",10},
//{"bob:Aircraft.Ju-87B-2",10},
//{"bob:Aircraft.Ju-88A-1",10},
//{"bob:Aircraft.He-111H-2",10},
//{"bob:Aircraft.He-111P-2",10},
//{"bob:Aircraft.DH82A",10},
//{"bob:Aircraft.HurricaneMkI",10},
//{"bob:Aircraft.HurricaneMkI_dH5-20",10},
//{"bob:Aircraft.BlenheimMkIV",10},
//{"bob:Aircraft.SpitfireMkI",10},
{"bob:Aircraft.SpitfireMkIa",5},
{"bob:Aircraft.SpitfireMkIIa",5},
//{"bob:Aircraft.SpitfireMkI_Heartbreaker",10},
//{"bob:Aircraft.G50",10},
//{"bob:Aircraft.BR-20M",10}
};


private bool IsLimitReached(AiActor actor)
{
bool limitReached = false;
AiCart cart = actor as AiCart;

if (cart != null)
if (AircraftLimitations.ContainsKey(cart.InternalType Name()))
if (AircraftLimitations[cart.InternalTypeName()] < 1)
limitReached = true;

return limitReached;
}


private void CheckActorOut(AiActor actor)
{
AiCart cart = actor as AiCart;

if (cart != null)
if (AircraftLimitations.ContainsKey(cart.InternalType Name()))
AircraftLimitations[cart.InternalTypeName()]--;
}


private void CheckActorIn(AiActor actor)
{
AiCart cart = actor as AiCart;

if (cart != null)
if (AircraftLimitations.ContainsKey(cart.InternalType Name()))
AircraftLimitations[cart.InternalTypeName()]++;
}


private void DebugPrintNumberOfAvailablePlanes()
{
foreach (KeyValuePair<string, int> current in AircraftLimitations)
{
GamePlay.gpLogServer(new Player[] { GamePlay.gpPlayer()},"InternalTypeName: {0}, Available: {1}", new object[]{current.Key, current.Value.ToString(CultureInfo.InvariantCultur e)});
}
}


private int NumberPlayerInActor(AiActor actor)
{
int number = 0;

AiCart cart = actor as AiCart;

if(cart != null)
for (int i = 0; i < cart.Places(); i++)
if (cart.Player(i) != null)
number++;

return number;
}


private AiAirport GetNearestAirfield(AiActor actor)
{
if (actor == null) return null;

AiAirport nearestAirfield = null;
AiAirport[] airports = GamePlay.gpAirports();

Point3d actorPos = actor.Pos();

if (airports != null)
{
foreach (AiAirport airport in airports)
{
if (nearestAirfield != null)
{
if (nearestAirfield.Pos().distance(ref actorPos) > airport.Pos().distance(ref actorPos))
nearestAirfield = airport;
}
else nearestAirfield = airport;
}
}
return nearestAirfield;
}


private bool LandedOnAirfield(AiActor actor, AiAirport airport, double maxdistance)
{
if (actor == null || airport == null || !IsActorGrounded(actor)) return false;

Point3d ActorPos = actor.Pos();

if (airport.Pos().distance(ref ActorPos) < maxdistance)
return true;
return false;
}


private bool IsActorGrounded(AiActor actor)
{
bool onGround = false;
AiAircraft aircraft = actor as AiAircraft;

if (aircraft != null)
if (aircraft.getParameter(ParameterTypes.Z_AltitudeAG L, -1) <= 2.0
|| aircraft.getParameter(ParameterTypes.Z_VelocityTAS , -1) <= 1.0)
onGround = true;

return onGround;
}


private bool IsActorDamaged(AiActor actor)
{
foreach (AiActor ac in Battle.GetDamageVictims())
if (ac == actor)
return true;

return false;
}


private string ParseTypeName(string typeName)
{
string[] tempString = null;
string parsedName = "";
tempString = typeName.Split('.');

parsedName = tempString[1].Replace("_", " ");

return parsedName;
}


public void CheckActorAvailibility(Player player, AiActor actor, int placeIndex)
{
if (actor != null)
{
if (NumberPlayerInActor(actor) == 1)
{
if (!IsLimitReached(actor))
CheckActorOut(actor);
else
{
AiCart cart = actor as AiCart;

if (cart != null)
{
GamePlay.gpHUDLogCenter(new Player[] { player }, "Planetype: {0} no longer available", new object[] { ParseTypeName(cart.InternalTypeName()) });

if (AircraftLimitations.ContainsKey(cart.InternalType Name()))
AircraftLimitations[cart.InternalTypeName()] = -1; // after leaving the plane +1 is added via CheckActorIn

player.PlaceLeave(placeIndex); // does not work on Dedi correctly
Timeout(2, cart.Destroy); // so destroy the plane
}
}
}
}
}


private bool OverEnemyTeritory(AiActor actor)
{
if (actor == null) return false;
if (!GamePlay.gpFrontExist()) return false;

if (GamePlay.gpFrontArmy(actor.Pos().x, actor.Pos().y) != actor.Army())
return true;
return false;
}


public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceEnter(player, actor, placeIndex);

CheckActorAvailibility(player, actor, placeIndex);

DebugPrintNumberOfAvailablePlanes(); // for testing
}


public override void OnPlaceLeave(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceLeave(player, actor, placeIndex);

if (actor != null)
{
if (NumberPlayerInActor(actor) == 0 && LandedOnAirfield(actor, GetNearestAirfield(actor), 2000.0) && !OverEnemyTeritory(actor) /*&& !IsActorDamaged(actor)*/)
{
CheckActorIn(actor);
}

if (NumberPlayerInActor(actor) == 0)
if (actor is AiCart)
Timeout(5, ()=>
{
if (actor as AiCart != null)
(actor as AiCart).Destroy();
});
}
}

}

_79_dev
06-07-2012, 11:41 AM
thanx Kodiak will check it today evening...

_79_dev
06-08-2012, 08:58 PM
Tested, works fine so far. You cant spawn the plane so it`s not causing spamming on the runway.... Thanx again Kodiak