PDA

View Full Version : A better despawn script



9./JG52 Hans Gruber
Jan-17-2014, 20:17
A project for the talented scripters in the community based on feedback in this thread: http://theairtacticalassaultgroup.com/forum/showthread.php?t=8009

It's happened to us all I'm sure. You bounce an opponent at high altitude and either kill the pilot or cripple his aircraft. For whatever reason, your opponent decides to quit the server, hit alt+F2, or maybe even bail out and his now abandoned aircraft continues on. If his aircraft was trimmed for level flight it might take several minutes for it to fall back to earth and award you the kill. However, the clock is already ticking. By exiting the aircraft the despawn timer has started and in moments his plane will simply vanish like nothing ever happened. The only evidence of the encounter being the ammunition you wasted.

To me this is one of the biggest problems in the sim. An air combat game which does not record kills accurately is simply mind boggling. But can we fix it or at least improve the situation? Every mission file has a despawn script but is it even doing anything or is the despawn behavior now hard coded? I know originally there was no despawn behavior and the server would fill with AI controlled planes buzzing all over. One of the patches changed this so landed and crash landed planes would now disappear without a script.

I use the following code in my missions which can be found on 1c forums:



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())
{

}
}

Timeout(1, () => { damageAiControlledPlane(actor); } );
}

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)
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(300, () => { destroyPlane(aircraft); });
}
}


Now I can't write code to save my life and everything I use in my missions comes from those more talented. But if I understand this correctly when a player leaves his aircraft after 1 second the game disables all control surfaces and kills the fuel pump. 300 seconds later the aircraft would despawn. However, in real world testing the aircraft in air despawn much sooner, probably a minute or two.

So the question to the coders is how can this be improved? Obviously, a balance is required to keep abandoned aircraft from stacking up on the airfields and clogging up the server but there has to be a way keep aircraft in the air from simply disappearing.

I remember a mission ATAG used to run long ago, either the work of Salmo or Wolf, but in that mission when a player quit his aircraft in air it exploded after a few seconds. I thought this was a pretty good solution as everybody got what they wanted. The plane was removed and the attacker got the kill. I would love to hear what thoughts Salmo, Reddog, or Colander have on this problem.

Salmo
Jan-17-2014, 23:36
..... You bounce an opponent at high altitude and either kill the pilot or cripple his aircraft. For whatever reason, your opponent decides to quit the server, hit alt+F2, or maybe even bail out and his now abandoned aircraft continues on. If his aircraft was trimmed for level flight it might take several minutes for it to fall back to earth and award you the kill. However, the clock is already ticking. By exiting the aircraft the despawn timer has started and in moments his plane will simply vanish like nothing ever happened. The only evidence of the encounter being the ammunition you wasted....

Why would you want to despawn a plane when an opponent quits the server, hit alt+F2, or bails out? Just despawn planes after they land, that way a despawn timer despawning planes in the air & before they're counted as kills won't occur.



I use the following code in my missions which can be found on 1c forums:



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())
{

}
}

Timeout(1, () => { damageAiControlledPlane(actor); } );
}

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)
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(300, () => { destroyPlane(aircraft); });
}
}




I don't understand why you're damaging planes in the OnPlaceLeave event? if I move from the pilot to the gunner seat, the OnPlaceLeave event is triggered & the plane will be damaged. Surely, your not aiming to damage planes when players change places?

Does this help? Just despawn Ai aircraft a short time after they land ....



public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
// remove Ai's after landing
if (isAiControlledPlane(aircraft))
{
Timeout(120, () =>
{ // remove aircraft after 2 minutes
if (aircraft != null) aircraft.Destroy();
});
}
}

9./JG52 Hans Gruber
Jan-18-2014, 06:18
Why would you want to despawn a plane when an opponent quits the server, hit alt+F2, or bails out? Just despawn planes after they land, that way a despawn timer despawning planes in the air & before they're counted as kills won't occur.

Because if you don't at least disable the aircraft after the player quits the AI takes over and will keep flying. Based on your responses I'm guessing you don't use any kind of despawn script which might explain why on some missions after a player lands and exits, the plane takes off again and circles the airfield. Soon enough your server is bogged down with abandoned aircraft which are now being flown by the AI. This script has been used by mission makers to disable AI planes since the games release.

http://www.airwarfare.com/sow/index.php/forumsocial/43-full-mission-builders-design-and-discussion-forum/539-how-to-script-to-remove-ai



I don't understand why you're damaging planes in the OnPlaceLeave event? if I move from the pilot to the gunner seat, the OnPlaceLeave event is triggered & the plane will be damaged. Surely, your not aiming to damage planes when players change places?

That's not how it functions. There is no problem changing positions in aircraft.


Does this help? Just despawn Ai aircraft a short time after they land ....



public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
// remove Ai's after landing
if (isAiControlledPlane(aircraft))
{
Timeout(120, () =>
{ // remove aircraft after 2 minutes
if (aircraft != null) aircraft.Destroy();
});
}
}


The game will despawn a/c automatically after OnAircraftLanded & OnAircraftCrashLanded.

Perhaps the answer is to simply remove Timeout(300, () => { destroyPlane(aircraft); });?

SoW Reddog
Jan-18-2014, 06:30
My understanding is that the despawn script is on the SERVER, not in the mission here at ATAG.

9./JG52 Hans Gruber
Jan-18-2014, 08:54
My understanding is that the despawn script is on the SERVER, not in the mission here at ATAG.

There is despawn hard coded in the game for landed and crash landed aircrafts, this much I am certain. If you do not have any code in your missions to despawn aircraft OnPlaceLeave that could explain unexplained build ups of AI you are experiencing in your missions.

I did some testing with the despawn timer commented out in a mission and learned the following:

- Nothing happens until the player exits the aircraft (bail out, alt +F2, spawns a new new aircraft, exits server, etc..)
- Aircraft spawned and then abandoned will disappear after ~50 seconds.
- Aircraft landed and then abandoned will disappear after ~70 seconds.
- Aircraft crash landed and then abandoned will disappear after ~12 seconds.
- Occasionally an aircraft will crash land and no event is triggered. This aircraft will never disappear. Ex. I took an He 111 up to 6km trimmed for level flight, set autopilot then bailed out. Per the damage AI script the engines immediately died and the a/c began a lazy corkscrew with elevators locked up. After 10 minutes the a/c eventually glided down into a field making a surprisingly soft landing. I waited for a few minutes then walked away. 20 mintues later the a/c was still sitting in the field. This is why you need the despawn timer.

Then I had an epiphany. Instead of fighting the despawn timer why not find the correct combination of damages to cause the a/c to crash quicker? I began experimenting with different types of damage and the only way I could get the a/c down quickly was to chop off a wing.



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);
aircraft.hitNamed(part.NamedDamageTypes.Eng0FuelSe condariesFire);
///aircraft.hitNamed(part.NamedDamageTypes.FuelTank0F ire);

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);

///aircraft.cutLimb(part.LimbNames.AileronL0);
///aircraft.cutLimb(part.LimbNames.AileronR0);
///aircraft.cutLimb(part.LimbNames.ElevatorL0);
///aircraft.cutLimb(part.LimbNames.ElevatorR0);
///aircraft.cutLimb(part.LimbNames.Rudder0);

///aircraft.cutLimb(part.LimbNames.StabilizerL0);
///aircraft.cutLimb(part.LimbNames.StabilizerL1);
///aircraft.cutLimb(part.LimbNames.StabilizerR0);
///aircraft.cutLimb(part.LimbNames.StabilizerR1);

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(300, () => { destroyPlane(aircraft); });
}
}


As you can see I tried several different types of damage but none worked as well. Cutting off the elevators caused the a/c to enter a dive but the a/c ends up inverted and it looked really corny. I tested this with every a/c in the game and it worked. The pilot leaves, a second later the wing breaks off, the engine smokes, the a/c enters a tight spiral all the way to the ground. From 6km it's over in less than 30 seconds. The only negative is on aircraft with wing tanks in a certain position (Br.20, G.50, Ju87, Ju88) there is a secondary fuel explosion. Unless somebody can find a better combination of damages this might be as good as it gets. For example if there was a method to lock one aileron up and the other down you could accomplish the same thing. I also tested against a formation of AI bombers and their behavior was unaffected. They bailed out as normal with no additional damage enforced. Thoughts?

SoW Reddog
Jan-18-2014, 11:01
There's no build up of AI in my missions. I have in-mission despawn in a variety of methods. However, I believe that there is an additional layer of despawn being applied by the server.

Your suggestion looks fine, but I personally don't see the need to worry about it. It must be a minute proportion of the kills on the server?

Klaus_Kaltherzig
Jan-18-2014, 16:41
Hans is correct it is a problem - it may not be a high % of total kills on the server but it is a significant % of all high altitude PKs especially if pilot is flying level when he is killed - couldn't even count the # of times I have chased a dead pilot plane bumper to bumper wasting all my ammo trying to shoot it up bad enough that it will start to go down:banghead:
Anything that can be done script wise would IMHO be a step in the right direction

9./JG52 Hans Gruber
Jan-18-2014, 23:34
Yes Klaus, it is a most most frustrating problem. But I have a solution and hopefully other mission makers choose to include it. Building off what I posted earlier I was worried about removing the wing to make the aircraft crash. This was an extreme method and as I suspected the wings do not despawn so over time severed wings begin to build-up floating in the air and around airfields. So I dig a little deeper into damage system and discover hitLimb, which can be used to inflict damage on specific parts. This is what I put together:



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.FuelPumpFa ilure);
aircraft.hitNamed(part.NamedDamageTypes.Eng0OilSec ondariesFire);
aircraft.hitNamed(part.NamedDamageTypes.Eng0TotalS eizure);
aircraft.hitNamed(part.NamedDamageTypes.Eng0Govern orSeizure);
aircraft.hitNamed(part.NamedDamageTypes.ControlsGe nericKickdown);
aircraft.hitNamed(part.NamedDamageTypes.ControlsEl evatorDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsAi leronsDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsRu dderDisabled);

aircraft.hitLimb(part.LimbNames.WingL1, -0.5);
aircraft.hitLimb(part.LimbNames.WingL2, -0.5);
aircraft.hitLimb(part.LimbNames.WingL3, -0.5);
aircraft.hitLimb(part.LimbNames.WingL4, -0.5);
aircraft.hitLimb(part.LimbNames.WingL5, -0.5);
aircraft.hitLimb(part.LimbNames.WingL6, -0.5);
aircraft.hitLimb(part.LimbNames.WingL7, -0.5);


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(120, () => { destroyPlane(aircraft); });

}
}


Basically, what happens now is that 1 second after player leaves aircraft this script is called which kills engine & controls. It also causes small engine fire which forces the AI pilot to bail out, important for alt+F2 or when player exits server. The fire often goes out but if not leaves a feint grey smoke trail which is a nice effect not often seen. Now the important part, damage is applied all along the left wing, which will cause the wing to drop & the aircraft to roll departing from level flight and beginning its quick descent to the ground. This wing damage is not visible to the player. The damage value can be increased but anything above 0.5 causes the damage to be visible (i.e. big holes in the wing) which does cause the aircraft to roll quicker but is a little obtrusive. I have tested this on all aircraft models in game and it works like a charm. From altitudes of 7km aircraft trimmed for level flight will crash in 10-15 seconds after the player exits. The only odd thing about this method is that if aircraft is abandoned on the ground it's engine will smoke but in less than a minute it despawns anyway so no harm is done.

So now in those high altitude scenarios if the opposition quits on you there will be instant feedback to the player. Belch of smoke from the engine, AI pilot bails out, and a/c rolls into death dive. Problem solved. :D

ATAG_Bliss
Jan-19-2014, 07:30
That's a great idea putting the AI out of the flight. I'll get with Colander (after TF 4.01 is out) and see if he has some magic up his sleeve regarding keeping people in the plane. I do agree that it should be like 1946 where you should have to bailout or land before exiting the aircraft. The problem, of course, is that Clod lets you switch to different aircraft, tanks, guns etc. so the issue is somehow allowing people to still do that but only while not on the ground.

There is even a realism setting for this server side called "enable plane switching". And it would keep people in their planes just as the old game did. The issue though, is that you are only allowed one plane spawn while this is enabled. So even after you have landed or bailed out, the only way to take another plane is to reconnect to the server. So they almost had it right :D But your idea is a great one in the meantime.

Salmo
Jan-19-2014, 21:00
... I'll get with Colander (after TF 4.01 is out) and see if he has some magic up his sleeve regarding keeping people in the plane. .....

I believe you can 'force' players back into their plane using script, something like ....



public override void OnPlaceLeave(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceLeave(player, actor, placeIndex);
if (actor is AiAircraft)
{
Player.Place() = (Actor as AiAircraft).Place(placeIndex);
}
}

Nephilim
Jan-19-2014, 21:10
I believe you can 'force' players back into their plane using script, something like ....



public override void OnPlaceLeave(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceLeave(player, actor, placeIndex);
if (actor is AiAircraft)
{
Player.Place() = (Actor as AiAircraft).Place(placeIndex);
}
}


Yes there is option to do that, its already implemented in SoW Campaigns....It is a little bit more complicated than that because of events being called after Player wants to leave aircraft or create new one...
Notice that You can re spawn two ways, once click on flag in mission menu or just create new plane by clicking on map...





private int[] AFL = new int[200];
private int bob = 0;
private List<string> restrictedPlanes = new List<string>();
private List<string> restrictedName = new List<string>();
private String CurPlane, CurPilot;

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


for (int i = 0; i < aircraft.Places(); i++)
if (aircraft.Player(i) != null)
return false;

return true;
}

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

AiAircraft aircraft = actor as AiAircraft;

base.OnPlaceLeave(player, actor, placeIndex);


#region cockpit lock
Player a = player;
Player[] aa = { a };


if (!(player.IsConnected())) return;
if (!(isAiControlledPlane(actor as AiAircraft))) return;

bool lnd = false;
bool hm = false;
bool jp = false;

if (((actor as AiAircraft).Person(0) == null) && ((actor as AiAircraft) != null))
jp = true;

if (jp)
{
if (restrictedName.Contains(a.Name()))
{
restrictedName.Remove(a.Name());
}

return;
}

if (!((actor as AiAircraft).Person(0).Health > 0))
{
if (restrictedName.Contains(a.Name()))
{
restrictedName.Remove(a.Name());
}

return;
}


double x = (actor as AiAircraft).Pos().x;
double y = (actor as AiAircraft).Pos().y;
double z = (actor as AiAircraft).Pos().z;

//if ((actor as AiAircraft).IsAirborne())
{
if (isAiControlledPlane(actor as AiAircraft))
{
Timeout((a.Ping() + 50) * 0.002, () =>
{


string name = (actor as AiAircraft).Name();
double xxx = ((actor as AiAircraft).Pos().x - x) * ((actor as AiAircraft).Pos().x - x);
double yyy = ((actor as AiAircraft).Pos().y - y) * ((actor as AiAircraft).Pos().y - y);
///-----------------------------------------------


if ((xxx < 1) && (yyy < 1))
{
if (restrictedPlanes.Contains(name))
{
restrictedPlanes.Remove(name);
}
if (restrictedName.Contains(a.Name()))
{
restrictedName.Remove(a.Name());
}
}



if (restrictedPlanes.Contains(name))
{
//restrictedName.Remove(a.Name());
if (((actor as AiAircraft) != null) && (player != null))
{

a.PlaceEnter((actor as AiAircraft), 0);
//serverMessage(a.Name() + " Not Allowed to leave airplane in the air");
if (player != null)
{
GamePlay.gpHUDLogCenter(aa, "Not Allowed to leave airplane in the air");
}


if ((CurPilot == a.Name()) && (CurPlane != name)) bob++;
else bob = 0;
if (bob > 10)
{
(actor as AiAircraft).Destroy();
bob = 0;
restrictedPlanes.Remove(name);
}
CurPilot = a.Name();
CurPlane = name;

}
}
});
}

}
#endregion
}

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

#region plane escape lock
if (!restrictedPlanes.Contains((actor as AiAircraft).Name()))
{
if (restrictedName.Contains(player.Name()))
{
if ((actor as AiAircraft) != null) (actor as AiAircraft).Destroy();
restrictedName.Add(player.Name());
return;
}
restrictedName.Add(player.Name());
restrictedPlanes.Add((actor as AiAircraft).Name());
}

#endregion
}









It works flawless, i took it more less from old Repka server missions, and added few bits and pieces but idea stayed the same .....

Vogler...

9./JG52 Ziegler
Jan-20-2014, 08:27
Gruber's despawn tweek works like a champ. I also tested several types from 6k+ and they were all down in short order. :thumbsup:

9./JG52 Hans Gruber
Jan-23-2014, 20:56
The full code is below. It works like a champ. Please put it in your missions until TF comes up with a better solution. ATAG should make it mandatory. :D



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())
{

}
}

Timeout(1, () => { damageAiControlledPlane(actor); } );
}

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(300, () => { (actor as AiGroundActor).Destroy(); ; });
}

public override void OnAircraftCrashLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
// COLANDER
//Timeout(120, () => { destroyPlane(aircraft); } );
}
public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftLanded(missionNumber, shortName, aircraft);
// COLANDER
//Timeout(120, () => { destroyPlane(aircraft); } );
}

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)
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);
aircraft.hitNamed(part.NamedDamageTypes.Eng0TotalF ailure);
aircraft.hitNamed(part.NamedDamageTypes.ElecPrimar yFailure);
aircraft.hitNamed(part.NamedDamageTypes.ElecBatter yFailure);

aircraft.hitLimb(part.LimbNames.WingL1, -0.5);
aircraft.hitLimb(part.LimbNames.WingL2, -0.5);
aircraft.hitLimb(part.LimbNames.WingL3, -0.5);
aircraft.hitLimb(part.LimbNames.WingL4, -0.5);
aircraft.hitLimb(part.LimbNames.WingL5, -0.5);
aircraft.hitLimb(part.LimbNames.WingL6, -0.5);
aircraft.hitLimb(part.LimbNames.WingL7, -0.5);


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(300, () => { destroyPlane(aircraft); });

}
}

56RAF_klem
Feb-19-2014, 18:38
The full code is below. It works like a champ. Please put it in your missions until TF comes up with a better solution. ATAG should make it mandatory. :D



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())
{

}
}

Timeout(1, () => { damageAiControlledPlane(actor); } );
}

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(300, () => { (actor as AiGroundActor).Destroy(); ; });
}

public override void OnAircraftCrashLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
// COLANDER
//Timeout(120, () => { destroyPlane(aircraft); } );
}
public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
{
base.OnAircraftLanded(missionNumber, shortName, aircraft);
// COLANDER
//Timeout(120, () => { destroyPlane(aircraft); } );
}

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)
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.FuelPumpFa ilure);
aircraft.hitNamed(part.NamedDamageTypes.Eng0OilSec ondariesFire);
aircraft.hitNamed(part.NamedDamageTypes.Eng0TotalS eizure);
aircraft.hitNamed(part.NamedDamageTypes.Eng0Govern orSeizure);
aircraft.hitNamed(part.NamedDamageTypes.ControlsGe nericKickdown);
aircraft.hitNamed(part.NamedDamageTypes.ControlsEl evatorDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsAi leronsDisabled);
aircraft.hitNamed(part.NamedDamageTypes.ControlsRu dderDisabled);

aircraft.hitLimb(part.LimbNames.WingL1, -0.5);
aircraft.hitLimb(part.LimbNames.WingL2, -0.5);
aircraft.hitLimb(part.LimbNames.WingL3, -0.5);
aircraft.hitLimb(part.LimbNames.WingL4, -0.5);
aircraft.hitLimb(part.LimbNames.WingL5, -0.5);
aircraft.hitLimb(part.LimbNames.WingL6, -0.5);
aircraft.hitLimb(part.LimbNames.WingL7, -0.5);


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(180, () => { destroyPlane(aircraft); });

}
}


Hi Gruber,

this is exactly what I want for our training server missions, a simple despawn script to clear the debris. I have one problem which goes away if I rem out this part because the console reports a 'List not known in this context' error:

public override void OnActorDead(int missionNumber, string shortName, AiActor actor, List<DamagerScore> damages)
{......
}

Any thoughts? My only plagiarised additions for the entire script are:

using System;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.core;
using maddox.GP;
using part;


public class Mission : AMission
{
....despawn script as your post.....

}

Salmo
Feb-19-2014, 22:12
Hi Gruber,

this is exactly what I want for our training server missions, a simple despawn script to clear the debris. I have one problem which goes away if I rem out this part because the console reports a 'List not known in this context' error:

public override void OnActorDead(int missionNumber, string shortName, AiActor actor, List<DamagerScore> damages)
{......
}

Any thoughts? My only plagiarised additions for the entire script are:

using System;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.core;
using maddox.GP;
using part;


public class Mission : AMission
{
....despawn script as your post.....

}

Klem,
You could try removing the redundant semicolon ....

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(300, () => { (actor as AiGroundActor).Destroy(); ; });
}

9./JG52 Hans Gruber
Feb-25-2014, 20:36
After a month of real world testing the script is working as well I could hope. On the missions using it incidents of unawarded kills has dropped dramatically. The only change I am making is the removal of "aircraft.hitNamed(part.NamedDamageTypes.Eng0OilSec ondariesFire);" from the inflicted damages. On aircraft with canopies which could be jettisoned, it was discovered that the canopies do not despawn with the rest of the aircraft. So at airfields where a/c were often abandoned on the ground a large amount of canopies were building up around the spawn points over several hours. This did not impact performance, it was just an odd sight. I have updated my earlier post (#13) to correct this.

Klemm, I apologize as I did not see your post till now. Did you figure it out?

56RAF_klem
Feb-26-2014, 02:44
After a month of real world testing the script is working as well I could hope. On the missions using it incidents of unawarded kills has dropped dramatically. The only change I am making is the removal of "aircraft.hitNamed(part.NamedDamageTypes.Eng0OilSec ondariesFire);" from the inflicted damages. On aircraft with canopies which could be jettisoned, it was discovered that the canopies do not despawn with the rest of the aircraft. So at airfields where a/c were often abandoned on the ground a large amount of canopies were building up around the spawn points over several hours. This did not impact performance, it was just an odd sight. I have updated my earlier post (#13) to correct this.

Klemm, I apologize as I did not see your post till now. Did you figure it out?

I'm afraid not. I get an error message in console at line 29: "The Type or Namespace 'List' could not be found....". Am I missing a reference in my post #14? I just copied them from another mission.

9./JG52 Hans Gruber
Mar-15-2014, 09:24
Post #13 has been updated. If a human player abandons their bomber on the ground the AI would arm bombs and jettison the bomb load. If the airfield was an objective this would blow up the airfield. I have revised the damage types inflicted after a human quits the a/c to disable the electrical systems and prevent the arming & release of bombs.

trademe900
Mar-17-2014, 02:53
Post #13 has been updated. If a human player abandons their bomber on the ground the AI would arm bombs and jettison the bomb load. If the airfield was an objective this would blow up the airfield. I have revised the damage types inflicted after a human quits the a/c to disable the electrical systems and prevent the arming & release of bombs.

Very nice work.

TWC_Flug
Dec-29-2016, 20:29
I believe you can 'force' players back into their plane using script, something like ....



public override void OnPlaceLeave(Player player, AiActor actor, int placeIndex)
{
base.OnPlaceLeave(player, actor, placeIndex);
if (actor is AiAircraft)
{
Player.Place() = (Actor as AiAircraft).Place(placeIndex);
}
}



I believe it is more like this:


AiAircraft aircraft
Player player
int place

player.PlaceEnter(aircraft, place);

Also I believe you can do player.PlaceLeave() & some other similar.

The following code has the effect of killing the player, though it may not be the preferred/best way to do it:


Battle.OnActorDead(0, player.Name(), actor, null);

You can see more similar "things you can do" (possibly!) by looking at the reference here (http://theairtacticalassaultgroup.com/forum/showthread.php?t=11576) and searching for "OnEventGame" and "GameEventId".

Karaya
Dec-10-2020, 07:42
Does this script still work with 5.0 or is there a newer, better way to handle this?

I'm asking because there are issues with aircraft kills not being tracked in the ITAF run campaigns (BoB, Tobruk). Reason for this seems to be that when someone (player, AI) bails the aircraft despawns immediately and isn't tracked as destroyed/shot down.