#1
|
|||
|
|||
Script limiting aircraft types (including multilingual messages)
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. Code:
allowed109s = (X% * (enmyFgtrs + enmyBmbrs/2) * objCompleted) / curTeamBalance 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. Code:
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.Eng0TotalFailure); 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.Eng0TotalFailure); 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.Eng0TotalFailure); // 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.Parse(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(playerlanguage)) // 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(playerlanguage)) // 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. Last edited by Ataros; 10-06-2011 at 10:04 AM. |
#2
|
|||
|
|||
Quote:
Ok my fault , have forgotten to handle different languages if send on all. Corrected version: Code:
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(playerlanguage)) 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(playerlanguage)) 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); } } Quote:
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. Last edited by FG28_Kodiak; 10-06-2011 at 10:33 AM. |
#3
|
|||
|
|||
Quote:
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. |
#4
|
|||
|
|||
German KünstlicheInteligenz = English ArtificialIntelligence
just a little language mismatch |
#5
|
|||
|
|||
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. Last edited by FG28_Kodiak; 10-06-2011 at 01:35 PM. |
#6
|
|||
|
|||
Quote:
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. Last edited by Ataros; 10-06-2011 at 02:23 PM. |
#7
|
|||
|
|||
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 Code:
(actor as AiAircraft).hitNamed(part.NamedDamageTypes.Eng0TotalFailure); 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. Code:
//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; } Code:
#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.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, () => { 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.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(60, () => // { destroyPlayerPlane(aircraft); } // ); } } } } #endregion Last edited by Ataros; 10-12-2011 at 09:43 PM. |
#8
|
|||
|
|||
Its a bug in dedi. As Workaround i use in my penalty script:
Code:
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); } } 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. |
#9
|
|||
|
|||
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. Code:
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")); } |
#10
|
|||
|
|||
1.11 version up on Repka #3 for testing
|
|
|