![]() |
#33
|
|||
|
|||
![]()
Here is part 1/2 of the actual .cs code for FILE: auto-generate-vehicles.cs
Code:
// //Various emergency & service cars script created by posters at http://forum.1cpublishing.eu/showthread.php?t=26112 and by naryv //Hacked extensively by flug //$reference parts/core/Strategy.dll //$reference parts/core/gamePlay.dll //$reference System.Core.dll using System; //using System.Core; using System.Collections; using maddox.game; using maddox.game.world; using maddox.GP; using part; using System.Collections.Generic; using System.IO; using System.Text; using System.ComponentModel; using System.Threading; using System.Diagnostics; public class Mission : AMission { public bool DEBUG=false; public int VEHICLE_LIFE_SEC = 120; public double CAR_POS_RADIUS = 80; //distance vehicles will be positioned from the center point of the Birthplace, Airfield, etc where cars are positioned public int TICKS_PER_MINUTE=1986; //empirically, based on a timeout test. This is approximate & varies slightly. //for landing or crash, they start SPAWN_START_DISTANCE_M away from the plane in the direction of the nearest BirthPlace or Airport point. They end SPAWN_END_DISTANCE_M away from the a/c. (Distances are approx., various randomness & functions added on top of these values.) public int SPAWN_START_DISTANCE_M = 100; //how far away they start from the a/c when approaching after landing public int SPAWN_END_DISTANCE_M = 20; //how close they approach you upon (eg) landing //For spawn-in, the vehicles start this close to the a/c and proceed to // the birthplace or airport point. public int SPAWN_START_DISTANCE_REVERSE_M = 12; //how close they start when spawning in onPlaceEnter private List<AiActor> actorPlaceEnterList; //HashSet doesn't work for some reason; it would be a better solution private List<AiAircraft> aircraftDamagedList; private List<AiAircraft> aircraftActiveList; maddox.game.ABattle Battle; public Mission () { //HashSet<int> evenNumbers = new HashSet<int>(); actorPlaceEnterList = new List<AiActor>(); aircraftDamagedList = new List<AiAircraft>(); aircraftActiveList = new List<AiAircraft>(); } //Listen to events of every mission public override void Init(maddox.game.ABattle battle, int missionNumber) { base.Init(battle, missionNumber); Battle=battle; MissionNumberListener = -1; //Listen to events of every mission //This is what allows you to catch all the OnTookOff, OnAircraftDamaged, and other similar events. Vitally important to make this mission/cs file work! //If we load missions as sub-missions, as we often do, it is vital to have this in Init, not in "onbattlestarted" or some other place where it may never be detected or triggered if this sub-mission isn't loaded at the very start. if (DEBUG) GamePlay.gpLogServer(null, ".Net framework: " + Environment.Version, new object[] { }); } public override void OnBattleStarted() { base.OnBattleStarted(); //MissionNumberListener = -1; } Random rnd = new Random(); [Flags] internal enum ServiceType // ??? ????????????? ??????? //note that all these types don't work; the actual type is determined by //createemrgcarmission depending on a/c type, army, and a few other things. //So it's not really determined by the settings in the curTechCar.CarType field { NONE = 0, EMERGENCY = 1, FIRE = 2, FUEL = 4, AMMO = 8, BOMBS = 16, PRISONERCAPTURE = 32, SPAWNIN = 64 } //Like AiActor or AiBirthplace but only has .Name() & .Loc() internal class BasePos { internal string _Name; internal Point3d _Pos; public BasePos (string name, Point3d pos) { if (name!=null) this._Name=name; else this._Name=""; //if (pos!=null) this._Pos=pos; //else this.Pos=new Point3d(0,0,0); } public BasePos (BasePos bp) { this._Name=bp.Name(); this._Pos=bp.Pos(); Console.WriteLine ("BasePos inited: " + this.ToString ("F2")); } //a default constructor . . . public BasePos (object o=null) { this._Name=""; this._Pos=new Point3d(0,0,0); } public string Name(string name=null) { if (name==null) return this._Name; else { this._Name=name; return null; } } public Point3d Pos(Point3d pos) { this._Pos=pos; return this._Pos; } public Point3d Pos() { return this._Pos; } public string ToString (string format){ return _Name + " " + _Pos.x.ToString( format ) + " " + _Pos.y.ToString( format ) + " " + _Pos.z.ToString( format ); } } internal class TechCars { internal AiGroundGroup TechCar { get; set; } internal BasePos basePos { get; set; } internal IRecalcPathParams cur_rp { get; set; } internal int RouteFlag = 0; internal int cartype = 0; internal int servPlaneNum = -1; internal int MAX_CARS = 100; internal ServiceType CarType { get { return (ServiceType)cartype; } set { cartype = (int)value; } } public TechCars(AiGroundGroup car, BasePos airoport, IRecalcPathParams rp) { this.TechCar = car; this.basePos = airoport; this.cur_rp = rp; Console.WriteLine("TechCars created. basePos: " + this.basePos.ToString("F2")); } } internal class PlanesQueue { internal AiAircraft aircraft { get; set; } internal BasePos basePos { get; set; } internal int state = 0; internal ServiceType State { get { return (ServiceType)state; } set { state = (int)value; } } internal int Lifetime = 0; internal float health = 1; public PlanesQueue(AiAircraft aircraft, BasePos basePos, int state) { this.aircraft = aircraft; this.basePos = basePos as BasePos; this.state = state; } } internal List<TechCars> CurTechCars = new List<TechCars>(); internal List<PlanesQueue> CurPlanesQueue = new List<PlanesQueue>(); TechCars TmpCar = null; bool MissionLoading = false; int MissionLoadingAircraftNumber = -1; internal double PseudoRnd(double MinValue, double MaxValue) { return rnd.NextDouble() * (MaxValue - MinValue) + MinValue; } public override void OnActorTaskCompleted(int missionNumber, string shortName, AiActor actor) { base.OnActorTaskCompleted(missionNumber, shortName, actor); if (DEBUG) GamePlay.gpLogServer(null, "OnActorTaskComplete", new object[] { }); AiActor ai_actor = actor as AiActor; if (ai_actor != null) { if (ai_actor is AiGroundGroup) for (int i = 0; i < CurTechCars.Count; i++) // ???? ????????????? ??????? ??????? ?? ?????????????? ????????, ????????? ?? ???????????? { if (CurTechCars[i].TechCar == ai_actor as AiGroundGroup) { //if (CurTechCars[i].RouteFlag == 1) TechCars car = CurTechCars[i] as TechCars; if (DEBUG) GamePlay.gpLogServer(null, "OnActorTaskComplete - ending plane service for " + i.ToString() + " in 120 sec.", new object[] { }); //this is basically to ensure that AI objects don't just hang around indefinitely when their tasks are done. //In normal behavior, they may complete several tasks in the course of moving abou the airport, so we don't just want //to destroy them immediately when task is done Timeout(VEHICLE_LIFE_SEC, () => { if (DEBUG) GamePlay.gpLogServer(null, "OnActorTaskComplete - ending plane service for " + i.ToString() + " now", new object[] { }); EndPlaneService(car, ai_actor as AiGroundGroup); }); } //we're just destroying them @ this point // else // CheckNotServicedPlanes(i); }; } } internal void CheckNotServicedPlanes(int techCarIndex) { for (int j = 0; j < CurPlanesQueue.Count; j++) { if (CurTechCars[techCarIndex].TechCar.IsAlive() && (CurPlanesQueue[j].basePos == CurTechCars[techCarIndex].basePos) && ((CurTechCars[techCarIndex].CarType & CurPlanesQueue[j].State) != 0) && (CurTechCars[techCarIndex].servPlaneNum == -1)) { if (SetEmrgCarRoute(j, techCarIndex)) // ?????????? ??????? ??????????? ????????? ??????? { return; } } } } //Removes the ground vehicle from the CurTechCars list & also destroys the AI object //We call it with the List item (not the index) because the index can change between call & execution, esp. if call via a timeout, which is common //We also include the TechCar field, (an AiGroundGroup) because sometimes the List item can be destroyed but the actual Ai Airgroup is still floating around undead // internal void EndPlaneService(TechCars tC, AiGroundGroup ground=null) { try { if (DEBUG) GamePlay.gpLogServer(null, "EndPlaneService/despawning now", new object[] { }); if (DEBUG) GamePlay.gpLogServer(null, "EndPlaneService/despawning " + tC.servPlaneNum.ToString(), new object[] { }); if (tC != null) { if (DEBUG) GamePlay.gpLogServer(null, " Number of objects: " + tC.TechCar.GetItems().Length, new object[] { }); //if (CurTechCars[techCarIndex].cur_rp == null) return; tC.cur_rp = null; // ?????????? ??????? //Just destroy the ground items at this point. if (tC.TechCar.GetItems() != null && tC.TechCar.GetItems().Length > 0) { if (DEBUG) GamePlay.gpLogServer(null, "EndPlaneService/despawning 1 ", new object[] { }); foreach (AiActor actor in tC.TechCar.GetItems()) { if (DEBUG) GamePlay.gpLogServer(null, "EndPlaneService/despawning 2 " , new object[] { }); (actor as AiGroundActor).Destroy(); } } CurTechCars.Remove(tC); } if (ground != null) { if (DEBUG) GamePlay.gpLogServer(null, "EndPlaneService/despawning 3 ", new object[] { }); foreach (AiActor actor in ground.GetItems()) { if (DEBUG) GamePlay.gpLogServer(null, "EndPlaneService/despawning 4 " , new object[] { }); (actor as AiGroundActor).Destroy(); } } } catch (Exception e) {System.Console.WriteLine (e.ToString());} } internal bool MoveFromRWay(int carNum) { bool result = false; if (DEBUG) GamePlay.gpLogServer(null, "Removing aircraft from runway at " + CurTechCars[carNum].basePos.Name(), new object[] { }); if ((GamePlay.gpLandType(CurTechCars[carNum].TechCar.Pos().x, CurTechCars[carNum].TechCar.Pos().y) & LandTypes.ROAD) == 0) return result; Point3d TmpPos = CurTechCars[carNum].TechCar.Pos(); while (((GamePlay.gpLandType(TmpPos.x, TmpPos.y) & LandTypes.ROAD) != 0)) { TmpPos.x += 10f; TmpPos.y += 10f; }; Point2d EmgCarStart, EmgCarFinish; EmgCarStart.x = CurTechCars[carNum].TechCar.Pos().x; EmgCarStart.y = CurTechCars[carNum].TechCar.Pos().y; EmgCarFinish.x = TmpPos.x; EmgCarFinish.y = TmpPos.y; CurTechCars[carNum].servPlaneNum = -1; CurTechCars[carNum].RouteFlag = 0; CurTechCars[carNum].cur_rp = null; CurTechCars[carNum].cur_rp = GamePlay.gpFindPath(EmgCarStart, 10f, EmgCarFinish, 10f, PathType.GROUND, CurTechCars[carNum].TechCar.Army()); result = true; return result; } public bool SetEmrgCarRoute(int aircraftNumber,int carNum) { bool result = false; if (DEBUG) GamePlay.gpLogServer(null, "Setting a Car Route "+aircraftNumber.ToString() + " " + carNum.ToString() + " at " + CurTechCars[carNum].basePos.Name() , new object[] { }); if (CurTechCars[carNum].TechCar != null) { CurTechCars[carNum].servPlaneNum = aircraftNumber; // ????????????? ????? ?????????????? ???????? if (CurTechCars[carNum].cur_rp == null) { Point2d EmgCarStart, EmgCarFinish, LandedPos; LandedPos.x = CurPlanesQueue[aircraftNumber].aircraft.Pos().x; LandedPos.y = CurPlanesQueue[aircraftNumber].aircraft.Pos().y; int Sign = ((carNum % 2) == 0) ? 2 : -2; EmgCarStart.x = CurTechCars[carNum].TechCar.Pos().x; EmgCarStart.y = CurTechCars[carNum].TechCar.Pos().y; //Drive the car from where it is to the point located in the direction of the aircraft position but 20 meters short of it. double disx, disy; disx=Math.Abs(EmgCarStart.x - LandedPos.x) - 20; if (disx<10) disx=20; disy=Math.Abs(EmgCarStart.y - EmgCarStart.y) - 20; if (disy<10) disy=20; EmgCarFinish.x = EmgCarStart.x - disx * ((EmgCarStart.x - LandedPos.x) / Math.Abs(EmgCarStart.x - LandedPos.x)); EmgCarFinish.y = EmgCarStart.x - disy * ((EmgCarStart.y - LandedPos.y) / Math.Abs(EmgCarStart.y - LandedPos.y)); //EmgCarFinish.x = LandedPos.x - PseudoRnd(0f, 1f) * ((LandedPos.x - EmgCarStart.x) / (Math.Abs(LandedPos.x - EmgCarStart.x))) - Sign; //EmgCarFinish.y = LandedPos.y - PseudoRnd(0f, 1f) * ((LandedPos.y - EmgCarStart.y) / (Math.Abs(LandedPos.y - EmgCarStart.y))) - Sign; //For spawn-in, we want the cars to start in close to the a/c & drive away CurTechCars[carNum].cur_rp = GamePlay.gpFindPath(EmgCarStart, 15f, EmgCarFinish, 15f, PathType.GROUND, CurTechCars[carNum].TechCar.Army()); if (DEBUG) GamePlay.gpLogServer(null, "Setting a Car Route "+aircraftNumber.ToString() + " " + carNum.ToString() + " " + EmgCarStart.ToString() + " to " + EmgCarFinish.ToString() + " at " + CurTechCars[carNum].basePos.Name() , new object[] { }); result = true; } } return result; } public override void OnMissionLoaded(int missionNumber) { base.OnMissionLoaded(missionNumber); if (missionNumber > 0) //whenever a new mission loads, this slurps up any matching groundcars into the curTechCars list so they can be manipulated etc //if (missionNumber==MissionNumber ) // important check! { if (DEBUG) GamePlay.gpLogServer(null, "Starting vehicle sub-mission loaded", new object[] { }); List<string> CarTypes = new List<string>(); CarTypes.Add(":0_Chief_Emrg_"); CarTypes.Add(":0_Chief_Fire_"); CarTypes.Add(":0_Chief_Fuel_"); CarTypes.Add(":0_Chief_Ammo_"); CarTypes.Add(":0_Chief_Bomb_"); CarTypes.Add(":0_Chief_Prisoner_"); AiGroundGroup MyCar = null; for (int i = 0; i < 3; i++) { for (int j = 0; j < CarTypes.Count; j++) { MyCar = GamePlay.gpActorByName(missionNumber.ToString() + CarTypes[j] + i.ToString()) as AiGroundGroup; //if (DEBUG) GamePlay.gpLogServer(null, "Creating groundcar group for " +missionNumber.ToString() + CarTypes[j] + i.ToString(), new object[] { }); if (MyCar != null) { TmpCar = new TechCars(MyCar, FindNearestAirport(MyCar), null); if (DEBUG) GamePlay.gpLogServer(null, "Creating groundcar group at " + FindNearestAirport(MyCar).Name() + " " + MissionLoadingAircraftNumber.ToString(), new object[] { }); TmpCar.CarType = (ServiceType)(1 << j); TmpCar.cur_rp = null; TmpCar.servPlaneNum=MissionLoadingAircraftNumber; if (!CurTechCars.Contains(TmpCar)) CurTechCars.Add(TmpCar); //if (CurTechCars.count < MAX_CARS) CurTechCars.Add(TmpCar); //These things are unruly, so we're setting a max life on them. Timeout(2*VEHICLE_LIFE_SEC, () => { (MyCar as AiGroundActor).Destroy(); }); MissionLoading = false; }; } } } } public override void OnTickGame() { base.OnTickGame(); //try { if ( (Time.tickCounter()) == 0) { // if (DEBUG) GamePlay.gpLogServer(null, "Ground vehicles started ", new object[] { }); } if ((Time.tickCounter() % (TICKS_PER_MINUTE/6)) == 12 ) { checkForStoppedAircraft(aircraftActiveList); } if (Time.tickCounter() % 64 == 0) { //if (DEBUG) GamePlay.gpLogServer(null, "Ground vehicles continues . . . ", new object[] { }); for (int i = 0; i < CurPlanesQueue.Count; i++) { CurPlanesQueue[i].Lifetime++; if (DEBUG) GamePlay.gpLogServer(null, "Lifetime: " + CurPlanesQueue[i].Lifetime, new object[] { }); if ((CurPlanesQueue[i].State == ServiceType.NONE) || (CurPlanesQueue[i].aircraft == null) || (CurPlanesQueue[i].Lifetime > (int)((double)VEHICLE_LIFE_SEC*TICKS_PER_MINUTE/64/60))) { foreach ( TechCars car in CurTechCars ) //don't use a for count/index loop here as we are destroying some of the objects mid-loop . . . arghh { if (car.servPlaneNum == i) { if (DEBUG) GamePlay.gpLogServer(null, "Removing ground car for plane " + car.servPlaneNum + " " + car.CarType + " in 5 seconds", new object[] { }); //EndPlaneService(j); Timeout ( 5f, () => { EndPlaneService(car, car.TechCar); }); } } CurPlanesQueue.RemoveAt(i); } }; foreach ( TechCars car in CurTechCars ) // (int i = 0; i < CurTechCars.Count; i++) //again ix-nay on the loop-for-ay . . . . { if (DEBUG) GamePlay.gpLogServer(null, "Ground car at " + car.basePos.Name(), new object[] { }); //TechCars car = CurTechCars[i]; if ((car.TechCar != null && car.cur_rp != null) && (car.cur_rp.State == RecalcPathState.SUCCESS) ) { if (car.TechCar.IsAlive()) // && (car.RouteFlag == 0)) // && (car.servPlaneNum != -1)) { car.RouteFlag = 1; car.cur_rp.Path[0].P.x = car.TechCar.Pos().x; car.cur_rp.Path[0].P.y = car.TechCar.Pos().y; car.TechCar.SetWay(car.cur_rp.Path); //if (car.servPlaneNum != -1) car.RouteFlag = 0; } //The code below avoids the current plane, right? But, I'm worried about these ground vehicles hitting **all the other planes** that might be about this particular airport . . . . maybe some fixup needed double Dist = Math.Sqrt((car.cur_rp.Path[car.cur_rp.Path.Length - 1].P.x - car.TechCar.Pos().x) * (car.cur_rp.Path[car.cur_rp.Path.Length - 1].P.x - car.TechCar.Pos().x) + (car.cur_rp.Path[car.cur_rp.Path.Length - 1].P.y - car.TechCar.Pos().y) * (car.cur_rp.Path[car.cur_rp.Path.Length - 1].P.y - car.TechCar.Pos().y)); if (car.servPlaneNum != -1) { if (Dist < ((CurPlanesQueue[car.servPlaneNum].aircraft.Type() == AircraftType.Bomber) ? 20f : 10f)) //EndPlaneService(i); EndPlaneService(car, car.TechCar); } else if (Dist < 15f) { //EndPlaneService(i); EndPlaneService(car, car.TechCar); } } if ((car.cur_rp == null) && (car.RouteFlag == 0) && (car.servPlaneNum != -1)) { //EndPlaneService(car, car.TechCar); }; if (car.servPlaneNum == -1 || car.TechCar == null) //EndPlaneService(i); //Once it is no longer serving a plane, we just zap it. EndPlaneService(car, car.TechCar); }; } //} catch (Exception e) {System.Console.WriteLine (e.ToString());} } internal BasePos FindNearestAirport(AiActor actor) { try { if (actor==null) return null; Point3d pd = actor.Pos(); if (DEBUG) GamePlay.gpLogServer(null, "Checking airport " + actor.Name(), new object[] { }); return FindNearestAirport(pd) as BasePos; } catch (Exception e) {System.Console.WriteLine (e.ToString()); BasePos ret3=null; return ret3; } } internal BasePos FindNearestAirport(Point3d pd) { try{ AiActor aMin = null; AiBirthPlace aMinB = null; double d2Min = 0; BasePos ret= new BasePos (); BasePos ret2=new BasePos (); Point3d retpd; //If we find a birthplace (ie, spawnpoint) closer than 2km we return that //otherwise we'll search all airports for something closer //And . . AiBirthPlace & AiAirport & AiActor are ALMOST the same thing but then again not quite so we have to dance a bit. aMinB=FindNearestBirthplace(pd); //if (DEBUG) GamePlay.gpLogServer(null, "Checking airport (Birthplace) found " + aMinB.Name() + " " + aMinB.Pos().distance(ref pd).ToString("F0"), new object[] { }); //if (1==0 && aMinB!= null) { if (aMinB!= null) { d2Min=aMinB.Pos().distance(ref pd); //if (DEBUG) GamePlay.gpLogServer(null, "Checking airport (Birthplace) found " + aMinB.Name() + " " + aMinB.Pos().distance(ref pd).ToString("F0") //+ " " + aMinB.Pos().ToString(), new object[] { }); if (d2Min<2000) { retpd=aMinB.Pos(); if (retpd.z==0) retpd.z = pd.z; //BirthPlaces usu. have elevation 0 which makes the ai route finder die horribly ret= new BasePos (aMinB.Name(), retpd); return ret; } } if (DEBUG) GamePlay.gpLogServer(null, "Checking airport (Birthplace) NOfound " + d2Min.ToString("F0"), new object[] { }); int n = GamePlay.gpAirports().Length; for (int i = 0; i < n; i++) { AiActor a = (AiActor)GamePlay.gpAirports()[i]; if (a==null) continue; if (!a.IsAlive()) continue; //if (DEBUG) GamePlay.gpLogServer(null, "Checking airport " + a.Name(), new object[] { }); Point3d pp; pp = a.Pos(); pd.z = pp.z; double d2 = pd.distanceSquared(ref pp); if ((aMin == null) || (d2 < d2Min) ) { aMin = a; d2Min = d2; } } if (DEBUG) GamePlay.gpLogServer(null, "CAirport Found: " + aMin.Name() + " " + aMin.Pos().ToString() + " dist " + d2Min.ToString("F2"), new object[] { }); //Hmm, with our new scheme it doesn't really matter if aMin is very //distant or what. The cars always start relatively close to the a/c //and **in the direction of** the airport, but not *at* the airport //if (d2Min > 2250000.0) // aMin = null; //return aMin as BasePos if (aMin != null) ret2= new BasePos (aMin.Name(), aMin.Pos()); if (DEBUG) GamePlay.gpLogServer(null, "CAirport Returning: " + ret2.Name() + " " + ret2.Pos().ToString() + " dist " + d2Min.ToString("F2") + " " + ret2.ToString("F0"), new object[] { }); return ret2; } catch (Exception e) {System.Console.WriteLine (e.ToString()); BasePos ret3=null; return ret3; } } public AiBirthPlace GetBirthPlaceByName(string birthPlaceName) { foreach (AiBirthPlace bp in GamePlay.gpBirthPlaces()) { if (DEBUG) GamePlay.gpLogServer(null, "Checking airport " + bp.Name(), new object[] { }); if (bp.Name() == birthPlaceName) return bp; } return null; } public AiBirthPlace FindNearestBirthplace(AiActor actor) { //AiBirthPlace nearestBirthplace = null; //AiBirthPlace[] birthPlaces = GamePlay.gpBirthPlaces(); Point3d pos = actor.Pos(); return FindNearestBirthplace(pos); } public AiBirthPlace FindNearestBirthplace (Point3d pos) { AiBirthPlace nearestBirthplace = null; AiBirthPlace[] birthPlaces = GamePlay.gpBirthPlaces(); if (birthPlaces != null) { foreach (AiBirthPlace airport in birthPlaces) { if (nearestBirthplace != null) { //if (DEBUG) GamePlay.gpLogServer(null, "Checking airport " + airport.Name() + " " // + airport.Pos().distance(ref pos).ToString("F0"), new object[] { }); if (nearestBirthplace.Pos().distance(ref pos) > airport.Pos().distance(ref pos)) nearestBirthplace = airport; } else nearestBirthplace = airport; } } //AiActor ret=new AiActor(); //ret.Pos( nearestBirthplace.Pos()); //ret.Name(nearestBirthplace.Name()); if (DEBUG) GamePlay.gpLogServer(null, "Checking airport FOUND" + nearestBirthplace.Name() + " " + nearestBirthplace.Pos().distance(ref pos).ToString("F0"), new object[] { }); return nearestBirthplace; } //CONTINUED IN PART 2! Note that I trimmed down some comments, debugging code, etc to make it fit on the forum better. Full code is in the ZIP file with script & mission files, sample code, instructions all in one Last edited by flug32; 05-22-2016 at 07:39 AM. |
|
|