//$reference parts/bob/partBob.dll
//$reference parts/core/core.dll
/// ---------------------------------------------------------------------------
/// Basic Script For Rearm And Refuel with
/// * checking for
/// - aircraft must be on the ground at an airfield
/// - aircraft may not be damaged
/// - fuel cocks must be closed
/// - magnetos must be off
/// - aircraft must not be moving (set chocks)
///
/// * Refuel time is adjusted for amount of fuel
///
/// Bonus: "3. Show damages"
/// * Shows a detailed list of damages of your aircraft
/// (Server log info window)
///
/// Inserts into Order Menu (aka TAB Menu):
///
/// 4. Mission
/// 1. Rearm
/// 1. Rearm all
/// 2. Rearm guns only
/// 2. Refuel
/// 1. Refuel 100%
/// 2. Refuel 75%
/// 3. Refuel 50%
/// 4. Refuel 40%
/// 5. Refuel 30%
/// 6. Refuel 25%
/// 7. Refuel 20%
/// 8. Refuel 15%
/// 9. Refuel 10%
/// 3. Show damages
///
///
/// @author ATAG_Oskar, Artist
/// @version 3.7
/// @date 2019-09-23
/// ---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Timers;
using maddox.game;
using maddox.game.world;
using maddox.GP;
using part;
/// ---------------------------------------------------------------------------
/// The Rearm/Refuel Configuration
/// ---------------------------------------------------------------------------
public static class RearmRefuelConfig {
/// Duration in seconds for full rearm
public static int REARM_DURATION = 150;
/// Duration in seconds for 100% refuel
/// Lesser fuel amounts result in relative fractions of that.
/// Note: see REFUEL_MIN_DURATION below
public static int REFUEL_DURATION = 270;
/// Minimum duration in seconds for refuel
/// Refuel time cannot be shorter than that
public static int REFUEL_MIN_DURATION = 150;
/// Interval of "... complete in Min:
ec messages
public static int MESSAGE_INTERVAL = 15;
/// Allowable factor for within airfield perimeter.
/// The visible airfields are sometimes bigger than the technical value configured.
/// Even spawn points may sometimes be outside of that technical perimeter
/// Technical airfield perimeter is multiplied with this.
public static double AIRFIELD_PERIMETER_ADJUST = 1.5;
/// Allowable deviation from airfield's elevation in meter.
/// To check if we're actually on the ground, we need to check plane's elevation
/// against the airfield's. Unfortunately airfield elevation is not homogenous, en
/// extreme is Maidstone with places up to 7m different from technical elevation.
/// Note: This is strictly not necessary, because speed=0 within airfield
/// perimeter would mean the same, but for user friendliness we say
/// 'land on airfield' first and 'set chokes' later
/// value in meters
public static double AIRFIELD_ELEVATION_ADJUST = 7;
/// maximum engines to check (tanks, fuelcocks, magnetos, etc.)
public static int MAX_ENGINE_COUNT = 2;
/// output debugging messages
public static bool DEBUG_MESSAGES = false;
}
/// ---------------------------------------------------------------------------
/// A single (Rearm/Refuel) Request
/// This class handles the delay and executing of the rearm/refuel for one player
/// ---------------------------------------------------------------------------
public class RearmRefuelRequest {
/// INTERNALS
private IGamePlay m_GamePlay;
private Player m_Player;
private System.Timers.Timer m_Timer;
private int m_nMessageElapsed = 0;
private bool m_bRearmRequest = false;
private bool m_bRearmGunsOnly = false;
private bool m_bRearmComplete = false;
private int m_RearmDuration = 0;
private int m_nRearmElapsed = 0;
private bool m_bRefuelRequest = false;
private int m_iRefuelPercent = 0;
private bool m_bRefuelComplete = false;
private int m_RefuelDuration = 0;
private int m_nRefuelElapsed = 0;
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// THE DELAY FUNCTIONS
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// Constructor: Creates a request for the player with rearm, refuel, or both
/// If this is constructed with one request (e.g. rearm) only, the other (refuel) can be added later.
/// </summary>
public RearmRefuelRequest(IGamePlay GamePlay, Player CurPlayer, bool bRearm, bool bRearmGunsOnly, bool bRefuel, int iRefuelPercent)
{
m_GamePlay = GamePlay;
m_Player = CurPlayer;
m_Timer = new Timer();
m_Timer.Interval = 1000;
m_Timer.Elapsed += onTick;
m_nMessageElapsed = 0;
if(bRearm)
{
addRearmRequest(bRearmGunsOnly);
}
if(bRefuel)
{
addRefuelRequest(iRefuelPercent);
}
}
/// <summary>
/// initiates rearm sequence
/// calculates time needed, displays initial message
/// </summary>
public bool addRearmRequest(bool bGunsOnly)
{
if(!m_bRearmRequest)
{
m_bRearmGunsOnly = bGunsOnly;
m_RearmDuration = RearmRefuelConfig.REARM_DURATION;
m_nRearmElapsed = 0;
m_bRearmRequest = true;
m_bRearmComplete = false;
if(!m_Timer.Enabled)
{
m_Timer.Start();
}
TimeSpan spanTmp = new TimeSpan(0, 0, m_RearmDuration);
m_GamePlay.gpHUDLogCenter(new Player[] {m_Player}, "Rearm complete in "+string.Format("{0:00}:{1:00}", spanTmp.Minutes, spanTmp.Seconds));
return true;
}
else
{
m_GamePlay.gpHUDLogCenter(new Player[] {m_Player}, "Rearm in progress ...");
}
return false;
}
/// <summary>
/// initiates refuel sequence
/// calculates time needed, displays initial message
/// </summary>
public bool addRefuelRequest(int iPercent)
{
if(!m_bRefuelRequest)
{
m_iRefuelPercent = iPercent;
m_RefuelDuration = Math.Max(RearmRefuelConfig.REFUEL_MIN_DURATION, (RearmRefuelConfig.REFUEL_DURATION * iPercent)/100);
m_nRefuelElapsed = 0;
/// empty the tank
execRefuel(m_Player, 0);
m_bRefuelRequest = true;
m_bRefuelComplete = false;
if(!m_Timer.Enabled)
{
m_Timer.Start();
}
TimeSpan spanTmp = new TimeSpan(0, 0, m_RefuelDuration);
m_GamePlay.gpHUDLogCenter(new Player[] {m_Player}, "Refuel complete in "+string.Format("{0:00}:{1:00}", spanTmp.Minutes, spanTmp.Seconds));
return true;
}
else
{
m_GamePlay.gpHUDLogCenter(new Player[] {m_Player}, "Refuel in progress ...");
}
return false;
}
/// <summary>
/// returns true if all requests have been completed.
/// </summary>
public bool isCompleted()
{
if(m_bRearmRequest && !m_bRearmComplete)
{
return false;
}
if(m_bRefuelRequest && !m_bRefuelComplete)
{
return false;
}
return true;
}
/// <summary>
/// returns true if this requests belongs to player CurPlayer.
/// </summary>
public bool isPlayer(Player CurPlayer)
{
return(m_Player == CurPlayer);
}
public void cancel()
{
m_Timer.Stop();
m_bRearmRequest = false;
m_bRearmComplete = false;
m_bRefuelRequest = false;
m_bRefuelComplete = false;
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// INTERNAL PROCESSING
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// Checks the initiated rearm/refuel sequences for status.
/// Executes Rearm or Refuel when delay time has elapsed.
/// Displays update messages.
/// <summary>
public void onTick(Object source, ElapsedEventArgs e)
{
ArrayList aMsg = new ArrayList();
if (m_bRearmRequest && !m_bRearmComplete)
{
if(++m_nRearmElapsed >= m_RearmDuration) {
execRearm(m_Player, m_bRearmGunsOnly);
m_bRearmComplete = true;
aMsg.Add("Rearm complete");
}
}
if (m_bRefuelRequest && !m_bRefuelComplete)
{
if(++m_nRefuelElapsed >= m_RefuelDuration) {
execRefuel(m_Player, m_iRefuelPercent);
m_bRefuelComplete = true;
aMsg.Add("Refuel complete");
}
}
/// ALL DONE
if(isCompleted())
{
m_Timer.Stop();
}
/// NOT ALL DONE, YET
else if(++m_nMessageElapsed >= RearmRefuelConfig.MESSAGE_INTERVAL)
{
if(m_bRearmRequest && !m_bRearmComplete)
{
TimeSpan spanTmp = new TimeSpan(0, 0, (int)(m_RearmDuration - m_nRearmElapsed));
aMsg.Add("Rearm complete in "+string.Format("{0:00}:{1:00}", spanTmp.Minutes, spanTmp.Seconds));
}
if(m_bRefuelRequest && !m_bRefuelComplete)
{
TimeSpan spanTmp = new TimeSpan(0, 0, (int)(m_RefuelDuration - m_nRefuelElapsed));
aMsg.Add("Refuel complete in "+string.Format("{0:00}:{1:00}", spanTmp.Minutes, spanTmp.Seconds));
}
m_nMessageElapsed = 0;
}
if(0 != aMsg.Count)
{
object[] oArr = aMsg.ToArray();
string sTxt = "";
for (int i = 0; i < oArr.Length; i++) {
sTxt += (string)oArr[i];
if(i+1 < oArr.Length) sTxt += ", ";
}
m_GamePlay.gpHUDLogCenter(new Player[] {m_Player}, sTxt);
}
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// THE +REAL* REARM / REFUEL FUNCTIONS
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// executes the rearm on the player's aircraft.
/// </summary>
private void execRearm(Player CurPlayer, bool bGunsOnly)
{
/// The player might have gone ...
try {
AiAircraft PlayersAircraft = CurPlayer.Place() as AiAircraft;
PlayersAircraft.RearmPlane(bGunsOnly);
}
catch(Exception e){}
}
/// <summary>
/// executes the refuel on the player's aircraft.
/// </summary>
private void execRefuel(Player CurPlayer, int iPercent)
{
/// The player might have gone ...
try {
AiAircraft PlayersAircraft = CurPlayer.Place() as AiAircraft;
PlayersAircraft.RefuelPlane(iPercent);
}
catch(Exception e){}
}
}
/// ---------------------------------------------------------------------------
/// Managing Rearm/Refuel Requests
/// This class handles the delay and executing of the rearm/refuel for all players
/// - Checking Requirements
/// - Starting the processes
/// ---------------------------------------------------------------------------
public class RearmRefuelManager {
/// All requests currently pending
private List<RearmRefuelRequest> m_aRequests = new List<RearmRefuelRequest>();
/// Constructor
public RearmRefuelManager()
{
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// THE REQUIREMENTS
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// returns true if all requirements are met
/// </summary>
public bool areRequirementsMet(IGamePlay GamePlay, Player CurPlayer, bool bShowFailMessage)
{
bool bMet = true;
ArrayList aFailMsg = new ArrayList();
if(RearmRefuelConfig.DEBUG_MESSAGES)
{
AiAircraft PlayersAircraft = CurPlayer.Place() as AiAircraft;
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Aircraft: "+PlayersAircraft.InternalTypeName(), null);
}
/// BASIC: MUST BE LANDED
if(!isLandedOnAirfield(GamePlay, CurPlayer))
{
aFailMsg.Add("land on an airfield to rearm or refuel.");
}
/// BASIC: MUST BE UNDAMAGED
else if(0!=listDamages(GamePlay, CurPlayer, false))
{
aFailMsg.Add("take another aircraft, this one is damaged.");
}
/// LIST: FUELCOCKS, MAGNETOS, NOT-MOVING
else
{
if(!hasClosedAllFuelCocks(GamePlay, CurPlayer))
{
aFailMsg.Add("close fuelcocks");
}
if(!hasAllMagnetosOff(GamePlay, CurPlayer))
{
aFailMsg.Add("switch off magnetos");
}
if(isMoving(GamePlay, CurPlayer))
{
aFailMsg.Add("set chocks");
}
}
if( 0 != aFailMsg.Count )
{
object[] oArr = aFailMsg.ToArray();
string sFailMessage = "Please ";
for (int i = 0; i < oArr.Length; i++) {
sFailMessage += (string)oArr[i];
if(i+1 < oArr.Length) sFailMessage += ", ";
}
GamePlay.gpHUDLogCenter(new Player[] {CurPlayer}, sFailMessage);
bMet = false;
}
return bMet;
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// INDIVIDUAL REQUIREMENTS
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// returns true if aircraft is on the ground on an airfield
/// </summary>
public bool isLandedOnAirfield(IGamePlay GamePlay, Player CurPlayer)
{
bool bOnAirfield = false;
try {
Point3d PlaneLoc = CurPlayer.Place().Pos();
AiAirport[] aPorts = GamePlay.gpAirports();
foreach(AiAirport Port in aPorts)
{
Point3d PortLoc = new Point3d(Port.Pos().x, Port.Pos().y, Port.Pos().z);
/// Is plane within airfield perimeter? We allow factor AIRFIELD_PERIMETER_ADJUST
if (PlaneLoc.distance(ref PortLoc) <= Port.FieldR()*RearmRefuelConfig.AIRFIELD_PERIMETER _ADJUST)
{
/// is plane +- X meters of airfield's elevation?
/// see notes on RearmRefuelConfig.AIRFIELD_ELEVATION_ADJUST
if(PlaneLoc.z <= PortLoc.z + RearmRefuelConfig.AIRFIELD_ELEVATION_ADJUST && PlaneLoc.z >= PortLoc.z - RearmRefuelConfig.AIRFIELD_ELEVATION_ADJUST)
{
bOnAirfield = true;
break;
}
break;
}
}
}
catch(Exception e)
{
bOnAirfield = true;
}
if(RearmRefuelConfig.DEBUG_MESSAGES)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Checking on airfield: "+bOnAirfield, null);
}
return bOnAirfield;
}
/// <summary>
/// returns number of damages to aircraft
/// lists damages in server log info window
/// shows HUD messages if desired
/// </summary>
public int listDamages(IGamePlay GamePlay, Player CurPlayer, bool bShowMessages)
{
int nDamages = 0;
AiAircraft PlayersAircraft = CurPlayer.Place() as AiAircraft;
string[] PartNames = Enum.GetNames(typeof(part.NamedDamageTypes));
part.NamedDamageTypes[] PartVals = (part.NamedDamageTypes[])Enum.GetValues(typeof(part.NamedDamageTypes));
double dDamage = 0;
if(bShowMessages)
{
GamePlay.gpHUDLogCenter(new Player[] {CurPlayer}, "Checking for damages (See chat/server info window) ...");
}
for(int i = 0; i < PartNames.Length; i++)
{
try
{
dDamage = PlayersAircraft.getParameter(part.ParameterTypes.M _NamedDamage, (int)(PartVals[i]));
if(0 != dDamage)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Damage: "+PartNames[i], null);
nDamages++;
}
}
catch (IndexOutOfRangeException e)
{
}
}
if(bShowMessages)
{
if(0==nDamages)
{
GamePlay.gpHUDLogCenter(new Player[] {CurPlayer}, "No damages");
}
else
{
GamePlay.gpHUDLogCenter(new Player[] {CurPlayer}, "Your aircraft has damages: See chat/server info window.");
}
}
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Checking for damages: "+nDamages, null);
return nDamages;
}
/// <summary>
/// returns true if all fuel cocks are closed
/// </summary>
public bool hasClosedAllFuelCocks(IGamePlay GamePlay, Player CurPlayer)
{
bool bAllClosed = true;
AiAircraft PlayersAircraft = CurPlayer.Place() as AiAircraft;
double dPos = 0;
/// The G.50 cannot close fuelcock
if(PlayersAircraft.InternalTypeName().Contains("Ai rcraft.G50"))
{
if(RearmRefuelConfig.DEBUG_MESSAGES)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Checking fuelcocks, G.50 has none", null);
}
}
else for(int i=0; bAllClosed && i < RearmRefuelConfig.MAX_ENGINE_COUNT; i++)
{
try
{
dPos = PlayersAircraft.getParameter(part.ParameterTypes.C _FuelTankSelector, i);
if(RearmRefuelConfig.DEBUG_MESSAGES)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Checking fuelcocks, engine "+i+": "+dPos, null);
}
/// Spitfire's values are reversed
/// 0: ON, 1: OFF
if(PlayersAircraft.InternalTypeName().Contains("Sp itfire"))
{
if(1!=dPos) bAllClosed=false;
}
/// Ju 87 B-2 values are reversed, too
/// 0: both, 1: left, 2: right, 3: close
else if(PlayersAircraft.InternalTypeName().Contains("Ju-87"))
{
if(3!=dPos) bAllClosed=false;
}
/// All others have 0: OFF and 1,2,3: something not OFF
else
{
if(0!=dPos) bAllClosed=false;
}
}
/// nor more fuelcocks
catch(IndexOutOfRangeException e)
{
if(i==0 && RearmRefuelConfig.DEBUG_MESSAGES)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Exception at "+i, null);
}
break;
}
}
return bAllClosed;
}
/// <summary>
/// returns true if all magnetos are turned off
/// </summary>
private bool hasAllMagnetosOff(IGamePlay GamePlay, Player CurPlayer)
{
bool bAllOff = true;
AiAircraft PlayersAircraft = CurPlayer.Place() as AiAircraft;
for(int i=0; bAllOff && i < RearmRefuelConfig.MAX_ENGINE_COUNT; i++)
{
try
{
double dVal = PlayersAircraft.getParameter(part.ParameterTypes.C _Magneto, i);
if(RearmRefuelConfig.DEBUG_MESSAGES)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Checking magnetos, engine "+i+": "+dVal, null);
}
if(0!=dVal)
{
bAllOff = false;
}
}
/// No more magnetos
catch(IndexOutOfRangeException e)
{
break;
}
}
return bAllOff;
}
/// <summary>
/// returns true if the plane is stationary
/// </summary>
private bool isMoving(IGamePlay GamePlay, Player CurPlayer)
{
bool bIsMoving = false;
AiAircraft aircraft = CurPlayer.Place() as AiAircraft;
try
{
double speed = 0;
speed = aircraft.getParameter(part.ParameterTypes.Z_Veloci tyTAS, -1);
if(RearmRefuelConfig.DEBUG_MESSAGES)
{
GamePlay.gpLogServer(new Player[] {CurPlayer}, "Checking speed: "+speed, null);
}
if (speed > 0)
{
bIsMoving = true;
}
}
catch (IndexOutOfRangeException e)
{
}
return bIsMoving;
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// THE DELAY FUNCTIONS
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// adds a rearm request to a pending refuel request - or creates a new request
/// </summary>
public void addRearmRequest(IGamePlay GamePlay, Player CurPlayer, bool bGunsOnly)
{
cleanup(GamePlay);
foreach(RearmRefuelRequest Req in m_aRequests)
{
if(Req.isPlayer(CurPlayer))
{
Req.addRearmRequest(bGunsOnly);
return;
}
}
RearmRefuelRequest reqNew = new RearmRefuelRequest(GamePlay, CurPlayer, true, bGunsOnly, false, 0);
m_aRequests.Add(reqNew);
}
/// <summary>
/// adds a refuel request to a pending rearm request - or creates a new request
/// </summary>
public void addRefuelRequest(IGamePlay GamePlay, Player CurPlayer, int iPercent)
{
cleanup(GamePlay);
foreach(RearmRefuelRequest Req in m_aRequests)
{
if(Req.isPlayer(CurPlayer))
{
Req.addRefuelRequest(iPercent);
return;
}
}
RearmRefuelRequest reqNew = new RearmRefuelRequest(GamePlay, CurPlayer, false, false, true, iPercent);
m_aRequests.Add(reqNew);
}
/// <summary>
/// remove all completed requests
/// </summary>
public void cleanup(IGamePlay GamePlay)
{
m_aRequests.RemoveAll(isRequestCompleted);
}
/// <summary>
/// callback for cleanup()
/// </summary>
private bool isRequestCompleted(RearmRefuelRequest Req)
{
return(Req.isCompleted());
}
/// <summary>
/// cancel request of player
/// </summary>
public void cancelOfPlayer(IGamePlay GamePlay, Player CurPlayer)
{
foreach(RearmRefuelRequest Req in m_aRequests)
{
if(Req.isPlayer(CurPlayer))
{
Req.cancel();
break;
}
}
cleanup(GamePlay);
}
/// <summary>
/// remove all requests
/// </summary>
public void cancelAll(IGamePlay GamePlay)
{
foreach(RearmRefuelRequest Req in m_aRequests)
{
Req.cancel();
}
m_aRequests.Clear();
GamePlay.gpLogServer(new Player[] {GamePlay.gpPlayer()}, "all rquests cancelled", null);
}
}
/// ---------------------------------------------------------------------------
/// INTEGRATE INTO THE MISSION
/// ---------------------------------------------------------------------------
public class Mission : AMission {
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// STEP 1/4: ADD THE REAR/REFUEL MANAGER
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
private RearmRefuelManager ManageRnr = new RearmRefuelManager();
public long Tick_Mission_Time { get; set; }// Sets the Mission Clock for Time Remaining in Mission.
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// STEP 2/4: INTEGRATE AND CONFIGURE
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
public override void OnBattleStarted()
{
MissionNumberListener = -1;
/// REARM/REFUEL: CONFIGURE
/// Duration in seconds for full rearm
// RearmRefuelConfig.REARM_DURATION = 150;
/// Duration in seconds for 100% refuel
/// Lesser fuel amounts result in relative fractions of that.
/// Note: see REFUEL_MIN_DURATION below
// RearmRefuelConfig.REFUEL_DURATION = 270;
/// Minimum duration in seconds for refuel
/// Refuel time cannot be shorter than that
// RearmRefuelConfig.REFUEL_MIN_DURATION = 150;
/// Interval in seconds of "... complete in Min:
ec messages
// RearmRefuelConfig.MESSAGE_INTERVAL = 15;
/// The visible airfields are sometimes bigger than the technical value configured.
/// Even spawn points may sometimes be outside of that technical perimeter
/// Technical airfield perimeter is multiplied with this.
// RearmRefuelConfig.AIRFIELD_PERIMETER_ADJUST = 1.5;
/// maximum engines to check (tanks, fuelcocks, magnetos, etc.)
// RearmRefuelConfig.MAX_ENGINE_COUNT = 2;
}
public override void OnBattleStoped()
{
/// REARM/REFUEL: CLEANUP ANY PENDING REQUESTS
ManageRnr.cancelAll(GamePlay);
}
public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceEnter(player, actor, placeIndex);
setMainMenu(player);
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// STEP 3/4: ADD TO / SETTING THE MENU "4. Mission"
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// Enable the Menu for the Player here
/// </summary>
/// <summary>
/// Fill "4. Mission" with "Rearm", "Refuel, Show damages" submenus
/// </summary>
private void setMainMenu(Player player)
{
GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] {"Rearm", "Refuel", "Show damages"}, new bool[] { true, true, true });
}
/// <summary>
/// Fill "4. Mission - 1. Rearm" with "Rearm all", "Rearm only guns" submenus
/// </summary>
private void setSubMenuOne(Player player)
{
GamePlay.gpSetOrderMissionMenu(player, true, 1, new string[] {"Rearm all", "Rearm only guns"}, new bool[] {false, false});
}
/// <summary>
/// Fill "4. Mission - 2. Refuel" with "100%", "75%", ... submenus
/// </summary>
private void setSubMenuTwo(Player player)
{
GamePlay.gpSetOrderMissionMenu(player, true, 2, new string[] {"Refuel 100%", "Refuel 75%", "Refuel 50%", "Refuel 40%", "Refuel 30%", "Refuel 25%", "Refuel 20%", "Refuel 15%", "Refuel 10%"}, new bool[] {false, false, false, false, false, false, false, false, false});
}
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// STEP 4/4: HANDLE MENU CHOICES
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
/// <summary>
/// Process the user input on menu.
/// </summary>
public override void OnOrderMissionMenuSelected(Player CurPlayer, int ID, int menuItemIndex)
{
/// Handle Mission menu, "1 Rearm", "2 Refuel"
/// If you don't do not setSubMenuRe...(), the menu will just stay at the MainMenu
if( ID == 0 ){
switch (menuItemIndex) {
/// "Rearm" selected
case 1:
/// show sub menu only when all requirements are met
if(ManageRnr.areRequirementsMet(GamePlay, CurPlayer, true))
{
setSubMenuOne(CurPlayer);
}
break;
/// "Refuel" selected
case 2:
/// show sub menu only when all requirements are met
if(ManageRnr.areRequirementsMet(GamePlay, CurPlayer, true))
{
setSubMenuTwo(CurPlayer);
}
break;
/// "Show damages" selected
case 3:
ManageRnr.listDamages(GamePlay, CurPlayer, true);
break;
}
}
/// Handle rearm sub menu: "1 Rearm all", "2 Rearm only guns"
else if(ID == 1)
{
switch (menuItemIndex) {
/// back up one level
case 0:
break;
/// exit menu (tab, escape, or other)
case 255:
break;
/// the options
case 1:
/// check requirements (again!)
if(ManageRnr.areRequirementsMet(GamePlay, CurPlayer, true))
{
ManageRnr.addRearmRequest(GamePlay, CurPlayer, false);
}
break;
case 2:
/// check requirements (again!)
if(ManageRnr.areRequirementsMet(GamePlay, CurPlayer, true))
{
ManageRnr.addRearmRequest(GamePlay, CurPlayer, true);
}
break;
default:
break;
}
/// without setMainMenu here the player, when pressing "4", would
/// find himself unexpectedly in *this* submenu again.
/// set 4. Mission Menu again (not showing!, just setting)
setMainMenu(CurPlayer);
}
/// Handle refule sub menu: "Refuel 100%", "Refuel ..."
else if(ID == 2)
{
if(
/// not: back up one level
0!=menuItemIndex
/// not: exit menu (tab, escape, or other)
&& 255!=menuItemIndex
/// check requirements (again!)
&& ManageRnr.areRequirementsMet(GamePlay, CurPlayer, true)
)
{
switch (menuItemIndex) {
case 1:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 100);
break;
case 2:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 75);
break;
case 3:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 50);
break;
case 4:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 40);
break;
case 5:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 30);
break;
case 6:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 25);
break;
case 7:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 20);
break;
case 8:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 15);
break;
case 9:
ManageRnr.addRefuelRequest(GamePlay, CurPlayer, 10);
break;
default:
break;
}
}
/// without setMainMenu here the player, when pressing "4", would
/// find himself unexpectedly in *this* submenu again.
/// set 4. Mission Menu again (not showing!, just setting)
setMainMenu(CurPlayer);
}
}
public override void OnPlaceLeave(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceLeave(player, actor, placeIndex);
Timeout(1, () =>
{ damageAiControlledPlane(actor); }
);
/// REARM/REFUEL: cancel possibly pending request of player
ManageRnr.cancelOfPlayer(GamePlay, player);
}
public override void OnActorDead(int missionNumber, string shortName, AiActor actor, List<DamagerScore> damages)
{
base.OnActorDead(missionNumber, shortName, actor, damages);
if (actor != null && actor is AiGroundActor)
Timeout(20, () => { (actor as AiGroundActor).Destroy(); ; });
if (actor is AiAircraft)
{ // remove killed aircraft
Timeout((2), () => // remove aircraft 2 seconds after killed, used to be two minutes: Timeout((2 * 60), ()
{
if (actor != null & actor is AiAircraft)
{
(actor as AiAircraft).Destroy();}
}
);
}
}
public override void OnAircraftCrashLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
Timeout(20, () =>
{ destroyPlane(aircraft);
//GamePlay.gpLogServer( null, "Crashed Aircraft:" + shortName , null);
}
);
}
public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftLanded(missionNumber, shortName, aircraft);
//April 27nd 2019: Changed to 120 from 360
//August 17th 2019: Changed to 2 from 120: To remove a/c stuck mid air after pilot bale out / leaving server
//August 20th 2019: Change of August 17th did not fix the issue.
//August 24th 2019: Reverted back to 120
double DespawnAfter = 120 ; // seconds after landing
Timeout(DespawnAfter, () => // despawn after specified seconds
{
if (aircraft.Player(0) == null) // no human pilot
{
try
{
//2019-08-24 Opened the GamePlay.log line, and closed it again
//GamePlay.gpLogServer( null, "Landed Aircraft:" + shortName , null);
aircraft.Destroy();
}
catch { }
} });
;
}
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 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;
//2019-08-24 Not needed? Closed down - start
//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"));
//}
//2019-08-24 Not needed? Closed down - end
//2019-08-24 Changed 120 to 1, but then back up to 30, as with 1, when one bales out, the ac gets removed immediately.
Timeout(60, () =>
{
//GamePlay.gpLogServer( null, "Removed Aircraft via damageAiControlledPlane:" + aircraft , null);
destroyPlane(aircraft);}
);
}
}
public override void OnTrigger(int missionNumber, string shortName, bool active)
{
base.OnTrigger(missionNumber, shortName, active);
}
}
Bookmarks