/************************************************************ * * handle airport bombing * most credit/script idea for airport bombing & destruction goes to reddog/Storm of War * * We give credit (points) for any bomb that hits within the radius of an airfield. * Also, these bomb hits are marked with a plume of smoke and additionally a bomb crater is added that is dangerous/will kill aircraft taxiing on the ground * * Craters are different sizes, depending on tonnage of bomb dropped. Also, craters will be repaired, taking a shorter time for smaller craters & a longer time for bigger craters * Additionally, the more craters dropped on an airport the longer it will take to get to the next crater & repair it. * Also, if a threshold of tonnage (counted as points, which are proportional to damage done) is reached, the airport is put out of commission by severely cratering it * * //Version for -MAIN.cs// *************************************************************/ public Dictionary> AirfieldTargets = new Dictionary>(); //Tuple is: bool airfield disabled, string name, double pointstoknockout, double damage point total, DateTime time of last damage hit, double airfield radius, Point3d airfield center (position) //TODO: it would nice to have a struct or something to hold this instead of a tuple . . . public void SetAirfieldTargets() { foreach (AiAirport ap in GamePlay.gpAirports()) //Loop through all airfields in the game { //We're just going to add ALL airfields as targets, but then make sure there are no duplicates (bec. built-in & .mis-added airports sometimes overlap). //It's going to take blue pilots more points/bombs to knock out an airfield, vs Red (Blenheims very limited as far as the # of bombs they can carry) ////Use this for TACTICAL SERVER (where Reds only have Blenheims) //UPDATE 2017/11/06: We don't need this adjustment bec. we have adjusted the points received //so that blenheims receive relatively more & the blue bombers relatively less. So this //should handle the discrepancy between the sides with no further adjustment necessary //int pointstoknockout = 30; //if (ap.Army() != null && ap.Army() == 1) pointstoknockout = 65; ////Use this for MISSION SERVER (where Reds have access to HE111 and JU88) ////Use this for MISSION SERVER && TACTICAL SERVER int pointstoknockout = 65; //This is about two HE111 or JU88 loads (or 1 full load & just a little more) and about 4 Blennie loads, but it depends on how accurate the bombs are, and how large double radius = ap.FieldR(); Point3d center = ap.Pos(); //GamePlay.gpAirports() includes both built-in airports and any new airports we have added in our .mis files. This results in duplication since //most .mis airports are placed on top of an existing built-in airport. We check whether this airport has already been added & skip adding it if so. Point3d pos = ap.Pos(); bool add = true; foreach (AiAirport apk in AirfieldTargets.Keys)//Loop through the targets { if (apk != null & apk.Pos().distance(ref pos) <= apk.FieldR()) { //AirfieldTargets[apk].Item3 add = false; // if (apk.FieldR() != null && apk.FieldR() > 1) radius = apk.FieldR(); //The field radius set in the .mis file becomes operative if it exists & is reasonable center = apk.Pos(); //We use the position of the airport set i nthe .mis file for the center, if it exists - thus we can change/move the center position as we wish break; } } //We'll get the NAME of the airport from the birthplace/spawn point declare in a .mis file, if it exists string apName = ap.Name(); foreach (AiBirthPlace bp in GamePlay.gpBirthPlaces()) { if (bp != null & bp.Pos().distance(ref pos) <= ap.FieldR()) { if (bp.Name() != null && !(bp.Name().ToUpper().Contains("BIRTHPLACE"))) apName = bp.Name(); //We will use the spawn point/birthplace name UNLESS it is just "BirthPlace0" or whatever break; } } if (add) AirfieldTargets.Add(ap, new Tuple(false, apName, pointstoknockout, 0, DateTime.Now, radius, center)); //Adds airfield to dictionary, requires approx 2 loads of 32 X 50lb bombs of bombs to knock out. //Tuple is: bool airfield disabled, string name, double pointstoknockout, double damage point total, DateTime time of last damage hit, double airfield radius //if you want to add only some airfields as targets, use something like: if (ap.Name().Contains("Manston")) { } } GamePlay.gpLogServer(null, "SetAirfieldTargets initialized.", null); } public string ListAirfieldTargetDamage(Player player = null, int army = -1, bool all = false, bool display = true) { int count = 0; string returnmsg = ""; if (AirfieldTargets != null) foreach (AiAirport ap in AirfieldTargets.Keys) { double PointsTaken = AirfieldTargets[ap].Item4; bool disabled = AirfieldTargets[ap].Item1; if (!all && PointsTaken == 0 && !disabled) continue; //we'll list only airports damaged or disabled, skipping those with no damage at all, unless called with all=true if (army != -1 & army != ap.Army()) continue; //List only the army requested, skipping the others. army = -1 means list both/all armies count++; double PointsToKnockOut = AirfieldTargets[ap].Item3; string Mission = AirfieldTargets[ap].Item2; DateTime lastBombHit = AirfieldTargets[ap].Item5; double percent = 0; if (PointsToKnockOut > 0) { percent = PointsTaken / PointsToKnockOut; } double timereduction = 0; if (percent > 0) { timereduction = (DateTime.Now - lastBombHit).TotalSeconds; } double timetofix = PointsTaken * 20 * 60 - timereduction; //50 lb bomb scores 0.5 so will take 10 minutes to repair. Larger bombs will take longer; 250 lb about 1.4 points so 28 minutes to repeari //But . . . it is ADDITIVE. So the first 50 lb bomb takes 10 minutes, the 2nd another 10, the 3rd another 10, and so on on. So if you drop 32 50 bl bombs it will take 320 minutes before the 32nd bomb crater is repaired. //Sources: "A crater from a 500lb bomb could be repaired and resurfaced in about 40 minutes" says one 2nd hand source. That seems about right, depending on methods & surface. https://www.airspacemag.com/multimedia/these-portable-runways-helped-win-war-pacific-180951234/ //unfortunately we can repair only the bomb crater; the SMOKE will remain for the entire mission because clod internals don't allow its removal. //TODO: We could keep track of when the last bomb was dropped at each airport and deduct time here depending on how much repair had been done since the last bomb dropped if (PointsTaken >= PointsToKnockOut) //airport knocked out { percent = 1; timetofix = 24 * 60 * 60; //24 hours to repair . . . } string msg = Mission + " " + (percent * 100).ToString("n0") + "% destroyed; last hit " + (timereduction / 60).ToString("n0") + " minutes ago"; returnmsg += msg + "\n"; if (display) GamePlay.gpLogServer(new Player[] { player }, msg , new object[] { }); } if (count == 0) { string msg = "No airports damaged or destroyed yet"; if (display) GamePlay.gpLogServer(new Player[] { player }, msg, new object[] { }); returnmsg = ""; //In case of display == false we just don't return any message at all, allowing this bit to simply be omitted } return returnmsg; } //stamps a rectangular pattern of craters over an airfield to disable it public void AirfieldDisable(AiAirport ap) { string apName = ap.Name(); double radius = ap.FieldR(); Point3d pos = ap.Pos(); if (AirfieldTargets.ContainsKey(ap)) { apName = AirfieldTargets[ap].Item2; radius = AirfieldTargets[ap].Item6; pos = AirfieldTargets[ap].Item7; } GamePlay.gpHUDLogCenter(null, "Airfield " + apName + " has been disabled"); ISectionFile f = GamePlay.gpCreateSectionFile(); string sect = "Stationary"; string val1 = "Stationary"; string type = "BombCrater_firmSoil_largekg"; int count = 0; string value = ""; for (double x = pos.x - radius * 1.1; x < pos.x + radius * 1.1; x = x + 80) { for (double y = pos.y - radius * 1.1; y < pos.y + radius * 1.1; y = y + 80) { string key = "Static" + count.ToString(); value = val1 + ".Environment." + type + " nn " + (x - 100 + 200 * stb_random.NextDouble()).ToString("0.00") + " " + (y - 100 + 200 * stb_random.NextDouble()).ToString("0.00") + " " + stb_random.Next(0, 181).ToString("0.0") + " /height " + pos.z.ToString("0.00"); f.add(sect, key, value); count++; } } //f.save(CLOD_PATH + FILE_PATH + "airfielddisableMAIN-ISectionFile.txt"); //testing GamePlay.gpPostMissionLoad(f); //Timeout(stb_random.NextDouble() * 5, () => { GamePlay.gpPostMissionLoad(f); }); } /* public void LoadAirfieldSpawns() { return; //Ok, this part would need to be placed in -MAIN.cs to work, and also know that mission ID and also we would need to set up special .mis files with each airport. //so, maybe we will do all that later, and maybe not //For now we are just skipping this part altogether (return;) //Instead we just disable the destroyed airport in-game by covering it with the dangerous type of bomb crater foreach (AiBirthPlace bp in GamePlay.gpBirthPlaces()) { bp.destroy();//Removes all spawnpoints } // GamePlay.gpPostMissionLoad("missions/London Raids/nondestroyable.mis"); foreach (AiAirport ap in AirfieldTargets.Keys) { if (AirfieldTargets[ap].Item1) { //Airfield still active so load mission GamePlay.gpPostMissionLoad(CLOD_PATH + FILE_PATH + "YOUR MISSION FOLDER/" + AirfieldTargets[ap].Item2 + ".mis"); } } } */