M28AI – Devlog 1) Introduction/background This is a devlog for the development of a new AI for forged alliance forever, named M28. Having developed M27 for about 18 months, I was running into a number of issues that wouldn’t be easy to solve with the way M27 was built, in particular: ● ● ● Late game slowdown ACU being too easy to flank/ambush with tanks General land combat unit management (for non-skirmisher units) having poor decisions on where to send the units. This is partly because M27 was built bit by bit, starting off as an AI intended to use T1 land, only for 5km land maps, with more logic added piecemeal as it got built up to a fully functional AI. In addition, some of the fundamental logic it was built off (how it reads maps and pathing) was based on a simple check of whether a unit could path from A to B, and straight line distances ignoring any blocking terrain. Meanwhile Jip has recently released integrated pathfinding logic into the core FAF for AI, which while not perfect allows calculation of pathing routes from A to B and how long it would take a land unit to travel between them. I was originally considering creating a basic AI to test out redoing how M27 manages its land units, but in the course of doing this I decided there were so many fundamental changes I wanted to try out with how the AI logic worked that it would make more sense to do it as a standalone AI. The M27 devlog charting how it developed can be viewed here: https://docs.google.com/document/d/1uQlEoN-kti7G2MnhwD60uaaHwVevPNYH/edit?usp=sharing &ouid=100973959280546778272&rtpof=true&sd=true Development on M28 started around 13 November 2022, although for a couple of weeks little was done as I was focusing mostly on M27 updates to resolve significant issues highlighted by replays, with most of my AI development time spent on M28 from around 26 November 2022. This is intended to document my progress and some of my thought process with creating M28, as well as functioning as a todo list of ideas of potential things to look at in the future for M28 (although many of these won’t be implemented – M27 has a vast todo list of points that are now unlikely to be implemented). To help track things for myself, I colour code items with yellow for htings I want to work on soon, red for points Im focused on immediately, green for points I’ve implemented but haven’t tested fully, and blue for things I’ve implemented and have tested to confirm they’re working (many changes will stay at the green state as I rely on general running of games to hopefully flag up errors with them, usually because I’m too lazy to create a replay scenario and lots of logs just to test one point). M28 v1 ended up being released on 12 May 2023. 2) Pre-v1 release My hope is to get a reasonably functioning AI in 3-6 months. 2.1) Pre-release goals In contrast to the approach taken for M27, I don’t think I can get away with releasing a really basic AI that can only do T1 tank landspam with a guncom since the moment I release it it will likely be 1 compared to M27. I therefore want it to be able to cover some of the main things M27 can handle, even if it wont do everything (and also is unlikely to do these things as well as M27), with the hope of the AI on initial release being relatively compatible with most maps and also being a better than average AI (i.e. able to beat the AI other than DilliDalli, RNG, and M27). 2.1.1) Map related ● ● Generate land zones Reclaim is recorded for the map and incorporated into land zones to be accessible for all M28 AI 2.1.2) ACU related ● ● ● ACU builds initial build order ACU used offensively initially and defensively later, building on mexes, getting reclaim and upgrading If ACU attacked or has nearby enemies while doing initial build order it will temporarily stop to deal with attackers 2.1.3) Engineer related ● ● ● ● ● Engineers build mexes based on land zones Engineers build basic buildings (factories, power) Engineers reclaim, with logic linked to land zones (eg. Reclaim safe zones first) Experimental construction Special engineer logic for: o Extra factories o Radar o TMD o SMD o SAMs o Shields to defend from arti/novax 2.1.4) Factory/other building related ● ● ● Mex and factory upgrade basic logic Factory build decisions are linked to land zones Build logic for: o Factoring in ‘teammate can build this unit and its better so get them to build it’ o Engineers o Land tanks o Skirmishers o Mobile shields o Land scouts o MAA 2.1.5) Land unit management ● ● ● Basic land unit management by land zone Land tanks basic unit management MAA management 2 ● ● Mobile shield and mobile stealth unit management Skirmisher unit management 2.1.6) Intel – land scouts ● ● Patrol paths for each land zone recorded System of requesting land scouts for a particular zone and then having the land scout patrol that zone while avoiding enemies. 2.1.7) Experimental level and building unit management ● ● ● ● ● ● ● ● Fatboy GC/Monkey/Ythotha/Megalith Novax Nuke launcher TMLs Rushing T2 land and getting T2 PD in response to an approaching enemy guncom Ahwassa T3 and experimental arti 2.1.8) Naval unit management ● ● ● ● ● Rework M27 naval logic to work on a subteam or water zone basis instead of a centralised team basis Use water zones for naval logic similar to land zones Implement basic unit management Naval factory production to make use of the above Better use of amphibious and hover units as part of naval logic (i.e. integrated with naval forces and assaulting islands in groups instead of single file). 2.1.9) Air unit management ● ● ● ● ● ● AirAA management Gunship management Torpedo bomber management Air scout management Transports for plateaus Air factory production to make use of the above 2.1.10) Compatibility ● ● ● ● ● ● ● Support for norush Support for survival gamemode where no enemy Support for maps where cant path to enemy amphibiously (e.g. air wars) in terms of more refined build order Unit cap considered/used to adjust what units are built No issues on maps with partial playable area (e.g. the circle type playable area maps, and air scouting logic) Support for water start points and maps with no water Playing with M28 enabled but no M28AI doesn’t result in LOG error messages/warnings 2.1.11) Other 3 ● ● Effective island attacks and building logic Dodge shot micro 2.1.12) Competitiveness and performance CPU performance ● Runs significantly faster than M27 on an Africa UEF vs UEF mirror AI game (i.e. vs the M27 performance benchmarks on this map) Competitiveness ● Manage to beat RNG and DilliDalli at least once on every M27 pre-release map plus a selection of maps where RNG is expected to do well (Crash site, Inquisition, Osiris) ● Beat Sorian AIX and adaptive AIX with max AiX build and eco boost as AiX nomads ● Beat M27 on Astro Craters 2.1.13) Possible future goals ● ● ● ● ● ● ● 2.2) Confirming 100% win rate vs adaptive AI on every M27 pre-release map >50% win rate vs RNG and vs DD on every M27 pre-release map (plus Osiris (won UEF mirror) – to avoid too many games, if I win the first time then I’ll treat it as a win, if I lose then I’ll do a ‘best of 3’. – Im not sure if this was met or not, but possibly not and I don’t have the motivation to spend weeks making tiny tweaks to potentially achieve – instead I’ll just assess this at a later date o At release M28 was capable of beating RNG and DD, but only had >50% win rate on the majority of maps tested (rather than all of them). Beating M27 on more maps T1 bomber engi hunters T3 strat mex hunters Czar Re-running the AI tourney for CPU benchmarking to see how M28 compares Land zone generation: Note that the approach used for land zone generation changed slightly just prior to release (see the Pathing Optimisation section) – it mostly followed the same logic, except for the logic for recording the area around a mex as being part of the same zone as the mex (where a faster method was used). ● ● Incorporate M27 logic for recording plateaus: o https://github.com/FAForever/fa/blob/deploy/fafdevelop/lua/sim/NavUtils.lua o Make use of Jips tool for determining pathing o Check navgen not already generated before running again o Integrate M27 reclaim segment recording (since reclaim is required to record plateaus) Record all mexes that are near each other in the same plateau group: o I’ll cycle through each plateau, then through each mex that is part of that plateau, and then check the distance to each other mex in the plateau and assign it to the same land zone as the first mex. o This requires making sure I don’t add the same mex multiple times, and also avoiding adding a mex already assigned to a land zone 4 o ● Since I’m dividing first by plateau and then by land pathability, it also means I need to check the mexes are pathable between each other by land (since they may only be pathable by hover). o I need to do this via a recursive method to ensure mexes in a similar area are all grouped together. o I also need to import an alternative to M27’s approach of determining the water height so I can determine if mexes are underwater for these purposes (in part because I’ll be using this functionality later on for other code, as I could just determine if a mex is pathable by land for now), so will cycle through every point on the map to identify those where the surface height is greater than the terrain height. Divide map into grids, and assign each grid either to a land zone, or nil if it isnt pathable by land: o When assigning a mex to a land zone, also assign the segment the mex is in to that same zone. o Decide on a segment size to search (roughly equal to a distance of 50x50). o Cycle through each mex, and for all the segments around it if the pathing distance is less than approximately 50, then assign the segment to the zone that is closest to it. o Go through each segment in map; if midpoint is landpathable and it has no assigned land zone, then record in temporary table o Then go through the segments with no zone that are land pathable (ie rhe temprary rable) and search +\- higher of 4 and 50/segment size times; if no nearby land zones are identified, then create a new zone o Then go through each segment with no land zone that is pathable by land, and assign it to the nearest zone. o This should mean every segment is assigned a land zone Doing some testing with my initial approach, it took 75.6s to complete. I then tried adjusting the approach so I only consider creating new land zones at the corners of each large square on the map (e.g. at position 14,14; 14, 28, etc.), and automatically adding locations within a short area around these to the same pathing group. This reduced the time from 75.6s to 64.0s. Analysing this, by the time it had finished assigning land zones to mexes and the ‘corner’ places it had taken 20.9s, and then the step when it had created land zones for any remaining locations with no zone got to a time of 63.99s, i.e. 43s of time was caused by this final step (after creating land zones for both mexes and the corners of each large square), i.e. of going through all segments on the map, checking if they had an assigned land zone, and if not then searching for the nearest pathable land zone and assigning them to this. Changing the logic to allow me to send a true/false variable on whether to use the distance determined by the FAF built in pathing function (instead of manually recalculating) and then using this ‘rough’ calculation for this final step that took longer changed the overall time to 119.8 (which I don’t really understand as it is doing fewer calculations for the distance – I’m assuming that the system time is starting from when FAF is loaded, and if I’ve had it on the menu screen for a while it means it gives a longer value). Checking the detail, instead of 20.9 and 63.99s it took 85.48 and 119.79, i.e. 34.31s (so an improvement on the previous 43s). 5 Changing the segment size so it targets a table size of 25k (instead of 50k). This gives the following results: ● ● ● Pre long step: 29.019920349121 Long step: 40.017868041992 End: 40.022773742676 i.e. this has reduced the delay from 34.31s to just 11s for this step which is acceptable for me, although this is only on a 10km map so I expect it will be slower on a larger map. I also then discovered a bug where I was only covering ¼ of the area around a mex (i.e. within a 90 degree range), so fixing this will impact on the times I expect. The results of the draft after fixing this are: Open palms Vya-3 Protectorate: 6 Frostmill Ruins: 7 Function localisations and subfunctions One side-note – I wanted to try and write this where possible in a format that would make it easier to have as a base FAF AI (as Jip had posted various criteria for this). A few suggestions Jip made on the initial draft were: ● ● ● Localising functions that aren’t used outside the file (by putting local at the start of them) Adding comments with @param VarName VarType and @return VarType to give more information on the function Not using subfunctions While I’ve done the first two, the third caused a massive performance hit, resulting in the land zone creation logic taking more than 4 times as long as before, so I’ve kept the subfunctions (I only use them sparingly anyway for the most intensive functions, so I hope this wont be a blocker given the massive performance impact from it). 8 2.3) Unit orders I want to have custom functions for issuing any orders, to ensure I can track orders effectively and avoid reissuing an order if a unit has already been given it. Relent0r pointed me towards spread attack for how to translate a unit’s current commands: https://github.com/FAForever/fa/blob/deploy/fafdevelop/lua/spreadattack.lua I wasn’t able to make this work in that while I could get a unit’s command queue and see how many entries it had (i.e. how many queued up orders), I couldn’t get details on the order type and position. Jip mentioned the code is a mix of sim side and UI side so I don’t know if this is the reason why, but I can still do what I want I think with a mix of tracking when a unit is given an order, tracking when its orders are cleared, and comparing the size of its command queue to the size of the tracked order queue. 2.4) Information – economy Gross income M27 would update information on each brain’s economy every second, in order to have values that wouldn’t be affected by reclaim. However, I want to use a more efficient approach, and update the economy information for mass and energy separately, and to have these update both once every 30s (as a general backup) and whenever we construct an energy or mass producing unit or have one destroyed that was constructed. This way I can hopefully be quicker and more accurate most of the time, while the 30s update should serve as a backup. I’ll also have the 30s update only check if each mex/PGen/Mass fab/RAS SACU’s brtain that it was updated against is not the same as its current brain owner, to cover scenarios where they are gifted. Net income My net income will still need to be updated every second, but hopefully will be quicker than before. 2.5) Predefined locations to build One issue M27’s engineer build logic had would be that it would for many buildings default to looking at random locations around the start position. While this had some advantages, it also led to potential performance issues where it was unable to find somewhere to build a large building, which would get progressively worse as the game goes on (which is when performance is needed more). My hope is that by using predefined locations to build and frontloading some of the logic for identifying these, it might be better (although it could also be significantly worse performance wise – e.g. if a land zone is 70x70 size, that could be almost 5k locations to consider. If I am considering 10 different building sizes, then I could end up doing 50k calculations every time I try to find somewhere to build). One downside of this approach is it also will (initially unless I figure out a better approach) lead to buildings being clumped around land zone centres. Recording locations by size ● When building construction started check for every size in the same radius as above for every size that has a non nil value, and see if the location is still valid for a unit of the relevant size 9 ● ● ● Also search more segments for the land zone in question to increase the number of buildable locations. Redundancy: refresh over a long period of time, only for land zones where we have a -1 result for valid locations of a particular size, only for size 8 and lower, and only every 5m: o cycle through each plateau and land zone o wait 1 tick between each land zone even if no values o if have a zone we want to refresh (ie it has -1 size values) then wait 1 tick every 8 segments considered o Track the time waited in aggregate; if it is less than 1000 then halve the number of segments before waiting, rounded up, to min of 2 o If it is more than 3000 then double the segments considered to a maximum of 32 When a building is destroyed: o Cycle through each size that we have previously search for for the land zone o Figure out the segments that if we were to try and building something of that size would be affected by the building being destroyed o Create a shortlist of locations that are now buildable for that size o Cycle through each location in the shortlist and see if it is already recorded for that land zone as buildable; if it isnt, then insert it Selecting a location to build at ● Use similar approach to currently for adjacency, but only for buildings in the land zone we are in, i.e.: o If we want to build adjacent: ▪ Identify all buildings of the desired adjacency in the land zone that we own, and consider each of these for adjacency where they are also within the distance required. ▪ Run through similar logic re checking if the planned build location is valid and generate a shortlist of locations o ▪ Run through logic to pick the best of these locations ▪ If cant find any location, then refer to the zone’s assigned build location of that size If we don’t want to build adjacent: ▪ 2.6) Refer to the zone’s assigned build location of that size Land Zones – recording units by zone My initial logic for finding adjacent locations wants to refer to units recorded against the land zone in question and cycle through these for adjacency. This means I need to record these units against each land zone. My plan was to do something similar to M27’s naval logic where it will record units when they’re first detected by any brain. However M27 took a shortcut and assumed all M28 brains are on the same team (so only recorded a single ‘last known position’ variable for each unit) whereas I want to go with the more accurate approach of recording the last known position for each team (with an active M28 brain) so if a human allies with M28 against other M28, the M28 shouldn’t get an unfair intel advantage. 10 For now I’ll record units by team (one possibility I was considering was to split teams into subteams based on their location on the map, but the main use case would be assessing how important something is and I could use subteam just for that part, since if I have a far away allied units in a land zone I want to factor them in to decisions on whether that zone is safe/has enough force to beat nearby enemies. 2.6.1) Setting up teams For now this will be a copy of M27’s logic for creating teams and subteams. Subteams will be setup based on how close they are to each other and the direction to the nearest enemy, so if M28 players are in opposite corners of the map they should end up on different subteams. 2.6.2) Recording and updating units Whenever the intel event is triggered on a unit, it should record it in a land zone/other table based on the type of unit, if it hasn’t previously been recorded for that team/subteam (depending on which is being used). I expect air and navy will use subteams, while land will use teams Similarly, when construction is started or completed on a unit, it should trigger an update. In addition to recording the unit in a table of units based on the particular type (if it hasn’t previously been recorded), I also want it to update the unit’s last known position if we can see it (independent of a non-event based check). For this, every second I’ll loop through every land zone and if there are enemy or allied units recorded then the last known position of these units will be refreshed, the unit’s plateau and land zone will be checked and if there’s a difference then the unit will be moved to a different land zone. 2.7) ACU – initial build order I want my ACU to have its own dedicated logic since I ended up with lots of ACU specific logic before that cluttered the main land unit logic. However I’ll want to take the ACU into account when deciding land unit orders in a zone, so I expect there will be some overlap with the zone logic. 2.7.1) Overview This will be similar to M27 in that the ACU should try and build a land factory, and then build PGens, Mexes and/or assist construction of hydro based on what is most appropriate. This makes use of the logic noted previously for identifying preferred adjacency locations and having predefined locations to build. For now I’ll set it up so every second I consider the ACU’s best action, and if it doesn’t have that action it will be refreshed (similar to how M27 works with platoons). To also help keep the code a bit tidier, I’ll separate it out so early game it has a specific initial build order set of actions to consider, and once these are complete it switches to a more combat focused set of orders. 11 While logic for building factory and power gens is relatively straightforward once the underlying engineer location logic is setup, building mexes and hydros requires more work on underlying systems. 2.7.2) Building initial mexes For the initial build order, the decision on whether to bild a mex should be based on whether a hydro is nearby and how much power the AI has (similar to M27). ● ● ● ● If there is a nearby hydro then up to 4 mexes in the land zone should be built on before assisting the hydro with the ACU If the ACU is outside build range then it should be given a combined order, ‘MoveNearTargetAndBuild’, so it can check that it only has 2 orders and both of these align. If instead the ACU is within build range it should just be given an order to build (or to assist if the unit it wants to build is already being built) If the ACU doesn’t have any orders after trying to build a mex, then resort to backup logic (as it may be the mexes are too far away) 2.7.3) Assisting hydro – initial logic If the ACU is in build range then it should repair the hydro if it’s under construction If there’s no hydro under construction then it should wait up to 20 seconds and then give up on assisting the hydro where it isnt under construction To progress the ACU logic further, I first need to get some basic logic in place for land factories to build engineers, and engineers to build hydrocarbons. For the land factory I will just use a placeholder and adopt a similar approach to M27 except I’ll scrap the ‘check every tick’ approach for all land factories and work mainly off callbacks, and just have a backup that cycles through a max of 1 factory a tick to check if they are idle. If a factory is identified with no building or upgrading status, and no active command queue, and it is completed, then the logic should see if it wants to build something, and if so it should be sent the order to build the unit. To get engineers to build hydrocarbons will require a lot more work, as I need to setup the framework for managing engineers and giving them orders, which in turn requires setting up more of the framework for managing land zone units. 2.8) Land Zones – initial management/information In order for my engineer logic to work, I want to manage engineers via my land zone logic. I’ve already got logic for recording all enemy and allied units by land zone, so now want to expand this to eventually handle engineer usage. To do this I want to be able to do the following: ● ● On creation of land zones, record all adjacent land zones (so I can consider these for threat) Once per tick cycle through a land zone, and record its value to my team, based on the mexes, reclaim and mass cost of friendly buildings; Also record if the land zone is considered part of the ‘core’ base o To be part of a core base, the LZ must either be in the starting point, or both adjacent to a core base LZ and contain a factory of our team’s highest tech level. 12 o ● i.e. on large maps this means I’ll refresh land zones much less frequently, which should hopefully help with performance Cycle through each land zone and record the threat values for enemy units and my units for that land zone, split between mobile and fixed threats, and between direct fire and indirect fire (with mobile and fixed AA grouped together), and split by enemy and ally. Available hydro locations M27s engineer logic would spend a lot of time each cycle identifying mex and hydro locations that are available to build on. However I want to come up with an efficient way of doing this since I’ll be running the logic on every zone, so I’ll use events/callbacks to flag when a hydro is built on, and when a hydro dies, and toggle the hydro location as being available/unavailable accordingly. I’ll also run logic for deciding what tobuild for each land zone separately, based on the engineers it has. 2.9) Engineers 2.9.1) Initial approach I may well change how this works, but for a starting point will introduce engineer build logic as follows: ● ● ● ● As part of logic of cycling through zones and deciding what to do with units in them, decide on what engineer actions the zone wants to do (regardless of whether it has engineers in it). The zone will record the build power that it wants where it doesn’t have enough engineers available in the zone to carry out the actions that it wants. o [Flaw with current approach – wont be factoring in build power already assigned by action?] Any available engineers will be assigned to actions, and reduce the build power that the zone wants. Logic for what to build at a zone will depend on if it is a ‘core base’ zone, or not. o For core bases, a more detailed set of engineer actions should be considered to decide on engineers wanted. Initially I’ll just set these up to build mexes or power with engineers. Other misc changes ● If a unit is given order to repair a building, I’ll record against the building to be repaired the unit that is assisting it; if that unit is then built or dies, it will clear orders from all the units logged as repairing it. 2.9.2) Unclaimed mexes and hydros M27 used an approach of checking every ‘cycle’ where it was assigning engineers (/every second) which mexes and hydros on the map were ‘unclaimed’. I want something hopefully quicker, so instead I’ll record at the start of the game which mexes and hydros can be built on. Then whenever a mex or hydro starts construction it’ll flag the location as unavailable, and then when a mex/hydro dies it’ll flag that location as being available again. I’ll assign this information by land zone, so I can then refer for any land zone to whether that zone has mexes/hydro locations that have no buildings on, and if so have an engineer action to build a mex/hydro accordingly. 13 2.9.3) Moving engineers between land zones I want to have a pull type system for allocating engineers to adjacent land zones – each land zone should record the total build power by tech that it wants for engineers. I then want my normal land zone engineer assignment logic to check for land zones that want an engineer, and to send an engineer on assignment to move to that land zone. ● ● This requires tracking the target land zone, and treating the engineer as available as soon as it reaches the target land zone. Introduce tracking to see how many engineers assigned to a LZ (that aren’t in the LZ), and then update the BP wanted for ‘move to LZ’ to be based on the tech level wanted, and the number already assigned for that action from the cur LZ, so we can have multiple adjacent LZs all receiving engineers at the same time. Pathing backup ● Pathing backup – the pathing generater Jip’s implemented’s resolution isn’t as good as 1x1 meaning units can pass over a location that is pathable but that the marker generator shows as unpathable. As a basic backup, I’ll take the following approach: o If the unit already has a plateau group and land zone assigned, and its location shows as having no plateau, then it will assume it is part of its previous plateau group, and record the location in a table of ‘pathing overrides’ o If a unit has no plateau, it will then first check to the table of pathing overrides and if an entry has been made there, it’ll use that plateau and land zone. o If no land zone is found still, then tracking will be done of the unit every second to see if it gets an actual land zone. o As part of this, if the unit has no orders, and is an M28 unit, then it will be told to move to a random location. ● So that further away land zones can be built on, I also want to have a lower priority ‘builder’ that will check for any land zones in the plateau that have requested engineers, and will send an engineer to this directly. ● Similarly, non-core zones will send engineers to adjacent zones and then as a lower priority further away zones. Progress illustration As an illustration of where m28 is with its expansion logic, running a simple replay (where it’s against an opponent that does nothing) on Theta passage, this was the map position after 4m08: 14 I’m fairly happy with this – an engineer is queued up to cover every land zone, while the nearest land zones are generally being prioritised first. For contrast, M27 at 4m08 is: 15 Obviously M27 is better with building more factories and combat units (whereas M28 is just building engineers and not even bothering with extra power), and M28 actually only has a 1 mex lead (although it has more engineers about to build another mex), but as a general sense check that it can expand at a reasonable rate it looks like it’s doing ok. Related changes ● ● If unit given order to repair a building, record against the building to be repaired the unit that is assisting it; if that unit is then built or dies, it will clear orders from all the units logged as repairing it. When choosing what non-adjacent zone to send an engineer to, the closest zone should be chosen (based on travel distance). 16 Nearby enemies ● For both non-core and core basis, if there are enemies in the current or adjacent zone, then for each engineer check for nearby enemies, and reclaim if the enemy is nearby, otherwise: o If we are within 10 of being in range of static enemy, or 50 of being in range of a mobile enemy, then run to an adjacent zone that has no enemies in it; if all adjacent zones have enemies then just try running away from the nearest enemy. o Otherwise, if enemy in current zone and non-core zone, and adjacent zone with no enemies, move to that adjacent zone o Otherwise, proceed as normal. o Also adjust BP wanted in a non-core LZ: If enemies in curzone, set to 0; if in adjacent then cap at 5 BP. ● If we have no BP wanted for a LZ before factoring in engineers traveling to it, then clear all those travelling engineers (assuming their action is still to travel there) – so e.g. if we send an engineer to build a mex far away, and then later come across enemies in that land zone that makes it dangerous, the engineer will stop trying to go there straight away instead of waiting until enemies get near it. ● When picking a LZ to send an engineer to, first check that if we get the full movement path we wont pass through any land zones with enemy direct or indirect fire units. 2.9.4) Misc changes related to above ● If a structure completes the construction of a building, check if there are enemy M28Brains that had ever seen the completed unit, and if so then add the newly constructed unit to the land zone (so e.g. we will know if the enemy has got t2 air when they upgrade a t1 air factory). 2.10) Economy and upgrades One thing I want to try and get working fairly well on first release is M28’s economy – since I don’t yet have combat logic I’ll be limited in some of the things I can do, but it also makes for an easy sandbox testing environment for how well my AI can do when under 0 pressure and trying to eco, so hopefully I can get its ecoing ability (when under no pressure) to a similar level as M27s (or possibly even better, but Im not sure yet if ill want to introduce some of the ‘tryhard’ M27 mechanics such as ctrl-King mexes or reclaiming old engineers). 2.10.1) Overview ● ● ● ● I’m not entirely sure on the best way to approach economy upgraders. M27’s approach works relatively well where it is brain based. However, with my engineer logic being team and land zone based I want to try a more team based approach. For now much rough plan is to decide on upgrades based on my overall team eco, and to consider the threat of land zones that units are in when deciding if they are safe to upgrade. I’ll also structure it differently to M27 – M27 split up logic into one part that would decide how many units to be upgrading at once, and then a separate piece of code to decide what category to upgrade (if we wanted to upgrade more than we were), and then a separate piece of code to get a unit of that category. This led to a fair amount of duplication by the end, so now I’ll divide things up as follows: o Do a basic resource check (i.e. that we aren’t stalling energy) o Consider high priority cases where we want an upgrade – for now these will consider, land, air and mex upgrades. 17 o After this, consider a more general upgrade logic which will look to upgrade if we have spare resources, and not if we don’t. 2.10.2) Factory tech levels ● ● ● One key piece of information when deciding on whether to get an upgrade and what upgrade to get is what tech level I have for land and air. I’ll track this both at a brain level, and also at a team level (with the team tracking the brain with the best and worst HQ levels). This will be done via callbacks, so whenever a factory HQ is created or destroyed it will trigger a refresh/check of the values. 2.10.3) Priority upgrades ● ● ● Land factories – prioritise if the enemy can path to us with land units, and has a higher land factory HQ than we do Air factories – prioritise if the enemy has T3 air and we don’t Mexes – If the enemy has T2/T3 mexes, then make sure all our core land zone mexes are at T2/T3, with 1 mex in the team upgrading regardless of how badly we are mass stalling, and low thresholds for having 1 mex in each active M28 brain’s start position upgrading. 2.10.4) General upgrade logic I highly expect I’ll need to refine my logic for upgrading a mex vs a factory, but for now I’ll go with something simple: ● ● ● ● Always try to be upgrading 1 mex If we’re already upgrading a mex and not upgrading a factory, and have a certain level of mass income (40 for T2, 80 for T3, adjusted for player count if we already have an active upgrade) then upgrade a factory. Don’t upgrade a factory if we are already upgrading a factory of that type. ‘Safe’ units should be prioritised first (based on if enemies are in the current or adjacent land zone for now), with unsafe units only considered if we have a high % of mass stored. 2.10.5) Improvements to ecoing Limiting engineer production when we have idle engineers ● Record for each zone how much idle BP we have in that zone by tech level ● For factories, don’t build engineers if we have idle engineers in the existing LZ of the same tech level Build more power sooner if needed for upgrades ● If we don’t have low mass, look to get a slight power buffer, where the aim is to get net power income of the following: o Highest tech is T1: E: 10% o Highest tech is T2: E15% o Highest tech is T3: E20% ● If we aren’t considering upgrades due to lack of energy and have at least 15% mass stored, then more power should be built as well. 18 Engineer higher tech power ● Prioritise highest tech power - Once I have access to T2+ tech on the team, I want to stop building T1 power and only build T2 power, and similarly only build T3 power once I have T3 tech. Assisting upgrades ● If there is an active Mex or factory upgrade in the land zone then assist the unit that is closest to completion. Building mass storage ● When land zones are setup, and any time a building dies in a land zone, I’ll refresh all the buildable locations for that land zone. ● Whenever a building is built in a land zone, then I’ll check if all of the previously recorded locations are still valid. ● If a land zone’s mexes are all T2+, then engineers should try and build mass storage. o The mass storage should only be built on one of these defined locations. ● I also don’t want to assist an upgrade if I’m about to power stall. Reclaiming wrecks ● Similar to M27, I’ll divide the map into ‘reclaim segments’, whose size is chosen to mean that most of the time an engineer at the middle of the segment can reclaim anything in the segment. ● I’ll record the reclaim segments whose midpoints are in a land zone against each land zone, and also record the total mass of these reclaim segments against the land zone, meaning I can quickly work out how much reclaim is in a land zone. ● Since I spent a lot of time with M27 coming up with a reclaim system that I reworked a few times to improve its performance/speed for recording what reclaim is on the map, I’ll use something similar: o As before, whenever a wreck is destroyed or created I want to flag the segment it is in to be updated for reclaim, and cycle through these segments each tick. o I’ll scrap M27’s process of backup logic that will refresh each zone in addition to this, and instead replace by just delaying the logic for updating reclaim segments at the start of the game, in the hopes of improving performance slightly. ● However I’ll be scrapping M27’s logic of prioritising reclaim areas to identify those of interest, and instead relying on the land zone logic (and later when I implement navy I’ll need to figure out a way of factoring in reclaim in the sea). ● For each land zone assigning engineers, if the land zone has reclaim mass/energy, then engineers should be ordered to reclaim, with tracking done of which reclaim segments have engineers assigned so hopefully they don’t all go to the same place (unless it has lots of mass reclaim). ● For giving orders, for now I’ll experiment with just telling engineers to reclaim one item in the segment, and then using a callback to reclaim more – I may end up switching back to M27’s approach of checking every second/tick for if there’s enough reclaim in the engineer build range to stop and reclaim it all manually (which I expect will be better overall, but I fear the performance implications). ● As a backup, if I want to get energy/mass reclaim but cant find any, then I’ll revert to trying mass/energy reclaim respectively in the same area. 19 I considered having backup logic where if my engineers have nothing to do in a non-core land zone and there was reclaim then they’d get the reclaim, but this ended up producing a worse outcome overall so I’ll leave it for now. ● One issue that this revealed witih the integrated FAF pathfinding was that reclaim is typically scattered on cliff edges, and these are often shown as impathable. Toe nsure engineers are likely to try and obtain reclaim that they can reach, where I record reclaim that appears to be in an impathable segment, I’ll see if the reclaim itself is impathable; if the reclaim is also impathable, then I’ll look in a 2x2 square around that reclaim to see if any of those points are pathable; if so, then the reclaim segment will be assigned to the land zone for that position (if there is a land zone). Reclaiming T1 PGens ● Add logic to reclaim T1 PGens (and later T2): ● Unlike M27, I want to run logic to consider reclaiming PGens only when T2+ power is constructed, and to then loop every second if I have enough gross income to reclaim but I’m not low on mass and/or I need the energy, and I don’t already have an active loop. ● The list of units to consider reclaiming should be assigned against each land zone. Energy storage ● For now I’ll just build 1 energy storage (since I don’t yet have combat logic for my ACU and want to link the decision to build extra storage to whether my ACU is being used in combat). 2.10.6) Power and mass stall managers ● ● ● ● These will be similar to M27 but on a team basis instead of aiBrain basis. One improvement I make is to calculate more accurately the likely energy usage of engineers based on what they are building (previously hardcoded values were used estimating this). When an engineer has its orders cleared, if it was paused then it should be unpaused. T2 upgrading mexes should be paused in priority to T1 upgrading mexes. 2.10.7) Team resource sharer ● ● ● Given how much of my logic is based on the team position, sharing resources is far more important than with M27. I therefore want to reassess resource values every tick, instead of every second, due to the worry late-game that the amount of power generated could be greater than an AI’s individual storage capacity, and so waiting an entire second could lead to unexpected/incorrect conclusions and resource allocations. I’ll also go with a simpler approach than M27 for now – instead of sharing with non-M28 teammates and considering prioritising certain scenarios, I’ll just share to even out mass and energy to M28 teammates, but ignoring giving resources to an M28 brain that has at least 95% storage. 2.10.8) Misc ● ● Prioritise 1st T2 land: Made a land factory more likely to be prioritised, and for a T1 land factory to be upgraded to T2 even if we have low(ish) power depending on total energy and mass levels. A base level of power by tech level is required before considering upgrades 20 ● ● ● ● ● ● Lower tech engineers can assist a higher tech engineer even if a minimum engineer requirement has been specified. Wanting more power and building more power – if have just built power of a tech level equal to our highest tech, and which represents >=15% of our gross energy, then flag that we have just built a lot of power, and turn the flag off after 3 seonds. During that time, have any ‘need more power’ checks act as though we have enough energy. When a unit is upgraded, clear any engineers that were assisting it (e.g. engis assisting a factory) When mass storage is built, check if it is adjacent to a mex owned by another player on the same team (doesn’t have to be M28AI), and if so gift the storage to them. When mex is built, check if it has any adjacent storage owned by another M28AI on the same team and if so gift the storage over. Only allow engineers to go to a core base zone if they aren’t adjacent to the LZ to the extent that the core LZ needs more than 3 * EngBP * its cur tech level, or there are no engineers already travelling to the LZ 2.10.9) Tracking ecoing progress: Theta passage as Seraphim: 15m46: ● M27 (when giving enemy a shielded minibase): M173 E2800, T3 land o M27 also had as part of this an ACU with gun+T2, T2 radar, T2 air, a handful of T2 MAA, energy storage, and land scouts at almost every mex (in addition to some less relevant stuff such as a couple of tanks, inties, bomber and air staging), with a T2 mex 45% of thew ay to T3. M28 eco progress during various changes: ● ● ● ● ● ● ● ● ● ● After got factory and mex upgrades implemented (first draft): M113 E920, T2 land After not overbuilding engineers: M113 E860, T2 land – at this point I was overflowing mass most of the time and not building enough power. After increasing power production: M133 E1400; After fixing a bug on starting mex upgrades: M181 E1500, 1 T2 Land Changing mass income check to use a 6s average instead of 1s snapshot: M205, E2000 (T2 land?) Tweaks to have a land factory upgrade start sooner: M180 E2000, T3 at 98% (while at face value this is worse than before, previously the AI was power stalling much more and overflowing mass). After assisting upgrades: M169, E1400, T3 Land After assisting upgrades outside the core zone: M119, E1400, T3 land! Checking the replay I think the issue was lots of engineers started assisting a T2 mex upgrading to T3, while T1 mexes elsewhere on the map were still trying to upgrade to T2. After adding mass storage: M180 E1900, T3 Land After adding reclaim, and limiting assistance of upgrades and storage during power stall: M113 E3500, T3 land (which changed to M174 E1500 T3 Land after requiring a greater level of power before starting a T3 upgrade) After fixing a but that was causing build locations to be overwritten (meaning the furthest away locations from a LZ that had been identified would be built on), this changed to M221 E1500, T3, with a T3 PGen 40% done. Allowing T1 engineers to assist T2 etc. changed to M225 E2000 with T3 (but no T3 PGen – as had enough power) 21 ● ● ● ● ● ● After fixing some bugs, this changed to M182 E3500 with T3 o Adding in logic to reclaim T1 PGens didn’t change this noticeably (it became M182 E3300); making some minor change I couldn’t even remember resulted in M213 E3200 After building an energy storage relatively early, this changed to M200 E1700 (the T3 PGen was 70% done) – this was expected as the main reason for energy storage is to support the ACU overcharging. After adding a power stall manager: M182, E3700 (and T3 HQ) After adding mass stall manager: M234, E3700 (and T3 HQ) After other tweaks (including fixing a bug with identification of some reclaim): M205 E3700 (with T3 HQ) To show how fickle this is, I re-worked my logic for assigning engineers to adjacent zones to in theory take an almost identical approach but in a much more performant way, and the result was M254 E1700 (and T3 HQ), with another minor tweak resulting in M216 E4200. 2.11) Performance check and optimisation One thing I noticed with the above approach is that performance is terrible on larger maps, and much moreso than with M27. On twin rivers, there was noticeable stuttering when running at +10 speed. Trying on point of reach, by the 5m mark (1v1) the game was stuttering to the extent it was slower than once per second (despite showing as +15 sim rate speed). After investigation (and integrating M27’s profiling logic), it was clear the cause of this was the engineer assignment logic for sending engineers to alternative land zones. I therefore reworked the approach, to record at the start of the game ‘land zone travel paths’ – for land zones where a player starts, these will consider the pathing travel time and zomes passed through for every land zone. For other land zones, it’ll consider up to 3 adjacencies away. The results before and after this change are shown: 2.11.1) Before change Extracts of the profiling logs are below – the manage land zone function callse the function considerlandzoneengineerassignment, which then calls a function depending on whether it is dealing with a ‘core’ land zone or a non-core land zone. Theta passage: 5m into game ● info: ProfilerOutput: No.3=ManageLandZone; TimesRun=8112; Time=1.1920318603516 ● info: ProfilerOutput: No.4=ConsiderLandZoneEngineerAssignment; TimesRun=8112; Time=1.0997047424316 ● info: ProfilerOutput: No.5=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=311; Time=0.89172172546387 ● info: ProfilerOutput: No.6=ConsiderMinorLandZoneEngineerAssignment; TimesRun=7801; Time=0.18868446350098 22 Just over 5m into point of reach: ● info: ProfilerOutput: No.1=ManageAllLandZones; TimesRun=3170; Time=48.018821716309 ● info: ProfilerOutput: No.2=ManageLandZone; TimesRun=26939; Time=47.939094543457 ● info: ProfilerOutput: No.3=ConsiderLandZoneEngineerAssignment; TimesRun=26939; Time=47.746963500977 ● info: ProfilerOutput: No.4=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=313; Time=33.53755569458 I added further profiling within the function on point of reach which confirmed the cause as the land zone travel time: ● ● ● ● info: ProfilerOutput: No.4=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=311; Time=30.959344863892 info: ProfilerOutput: No.5=ConsiderCoreBaseLandZoneEngineerAssignmentPreTravel; TimesRun=622; Time=30.9339427948 info: ProfilerOutput: No.6=IsItSafeToPathBetweenLandZones; TimesRun=2314; Time=21.246597290039 I.e. considering core base engineer assignment from the point of considering other land zones took 30.93s of the 30.96 total time (so everything else was taking just 0.03s), and calculating whether it was safe to path between land zones took 21.2s of time. 2.11.2) After change I checked on theta passage to make sure I was getting similar eco performance to before (which I was). The profiling results are: Theta passage: info: ProfilerOutput: No.3=ManageLandZone; TimesRun=8237; Time=0.28305816650391 info: ProfilerOutput: No.4=ConsiderLandZoneEngineerAssignment; TimesRun=8237; Time=0.19707679748535 info: ProfilerOutput: No.5=ConsiderMinorLandZoneEngineerAssignment; TimesRun=7921; Time=0.12686347961426 Point of reach: ● info: ProfilerOutput: No.1=DecideAndBuildUnitForFactory; TimesRun=61; Time=1.4297122955322 ● info: ProfilerOutput: No.2=ManageAllLandZones; TimesRun=3561; Time=0.63579940795898 ● info: ProfilerOutput: No.3=ManageLandZone; TimesRun=22665; Time=0.57160568237305 ● info: ProfilerOutput: No.4=ConsiderLandZoneEngineerAssignment; TimesRun=22665; Time=0.43894386291504 ● info: ProfilerOutput: No.5=ConsiderMinorLandZoneEngineerAssignment; TimesRun=22344; Time=0.32414436340332 I.e. the time taken to manage all land zones has decreased from 48s to just 0.6s. 23 2.12) Land scouts M27 took the approach of having a line of land scouts that would provide (in theory) 100% coverage across the land section of an island. It’d then supplement this with land scouts for every mex (e.g. for if the enemy got units past its land scout line). For M28 I want a ‘land zone’ based approach instead – each land zone should ideally have a land scout assigned to it, which will patrol that land zone to pick up on enemy movements. Ideally I want to also have it prioritise land scouts of a particular faction, since Aeon land scouts are far superior to seraphim land scouts for gathering intel. 2.12.1) Land zone patrol paths ● At the start of the game, for each land zone calculate a path to patrol the land zone outer segments: o Travel in a straight line from the land zone midpoint to the midpoint of each adjacent land zone at intervals of 4 o Record the 3rd last valid location that is in the desired land zone o If there is more than a 90 degree angle from the midpoint that is not covered by any of the points from above, then starting with the middle of the zone move in this direction in intervals of 4 starting at 12, keeping track of the 3 valid locations. If at least 3 valid locations are found, then add the 3rd last valid location to the path (i.e. the idea is that in a land zone/island with no adjacent zones, land scouts will still patrol the zone rather than staying in the centre) o To avoid this resulting in pathing locations by the edge of the map, if the land zone is within 80 of a map edge then I’ll ignore looking at a pathing point in that direction. o Have the start point as the middle of the land zone o Have the next point as the closest of the recorded locations to this, and repeat until have allocated all of the patrol locations 2.12.2) Land scout assignment and orders ● ● ● ● ● ● I’ve decided for managing units traveling to a land zone I’ll group the tables by unit type to avoid needing to filter them each time, and because the logic for handling them will probably be different, so I’ll have a table just for land scouts moving between land zones. I’ll also have the logic work similarly to engineer assignment – each land zone will identify any land scouts in the zone, and then determine which of these are ‘available’ to the land zone. Any available land scouts should be assigned to adjacent land zones if they are flagged as wanting a land scout. Any remaining land scouts should then patrol the current land zone (which should be flagged as not then wanting any land scouts). If there are enemies nearby, then the scout should instead run away in the opposite direction (or run to base if it cant find anywhere after a brief bit of searching). To patrol the land zone: o If the scout’s last order is to the first patrol point, then do nothing; otherwise: o clear the scout’s orders, check which point in the patrol path it is closest to, and then issue every point in the patrol path from this point to the end, and then issue the first point in the patrol path 24 o ● ● To help with this I add a new order type to patrol a path, which will hopefully avoid reissing patrol orders when theyre still being carried out. Don’t assign land scouts to land zones with no mexes and a small number of segments. If a land zone doesn’t have a path for it (e.g. a very small one) then backup logic will be used to send the land scout elsewhere. 2.12.3) Land scout production ● ● If our current land zone wants a land scout, then build one Have a high priority engineer builder if we don’t have x number of engineers of that tech level yet (which takes priority over land scouts). Prioritising a particular faction’s land scouts ● One option – whenever a factory is built for a particular faction, check if that land zone has considered unit preferences for that particular faction and tech level (or better than that tech level). ● If not, then consider whether we want to limit what we build at other factories nearby in the same land zone: o Consider any land zone in the same plateau that is within 300 of the land zone where the factory was built. ● When a factory is destroyed, then if we have no other factoires of that faction and >= that tech in the same land zone or within 300 of the factory (using getunitsaroundpoint), then revisit the unit restrictions. This feels like it could get complicated (e.g. if a factory is destroyed, I also need to consider if I still have another factory of that type nearby), so an alternative is to use subteams on the same plateau, e.g.: ● ● ● ● For each subteam record the number of factories by plateau, faction, factory type, and tech level Whenever we increase this from 0 to 1, or 1 to 0, then refresh logic of any unit BP overrides to do for that plateau and subteam Only consider factory HQs for this purpose, not support factories Whenever choosing a BP tobuild, check if there are any faction overrides present, and change the BP to nil if there are., with an optional flag to ignore faction overrides (so e.g. if an air unit is threatening our base we will build AA regardless of faction override) Initial prioritisation: I want to prioritise land scouts in the following order: ● ● ● ● Aeon Cybran UEF No prioritisation This is done in the above way so I can easily add to it in the future for other units where one faction has a far superior option. 2.12.4) Land subteam 25 As part of the above unit prioritisation logic, I will create ‘land subteams’ and ‘air subteams’ (instead of just subteams). The land subteams will be for any players that form part of an air subteam and are also on the same island. I’ll then consider blueprint restrictions based on the tech available by faction in the land subteam/island. Other changes ● Only allow engineers to go to a core base zone if they aren’t adjacent to the LZ to the extent that the core LZ needs more than 3 * EngBP * its cur tech level, or there are no engineers already travelling to the LZ 2.13) Land Zone tank management 2.13.1) Planning/overview Land zone management goals I want to come up with some way of managing land units that ideally achieves the following: ● ● ● ● ● Fights that should be easily won are taken Fights that are likely to be lost are avoided Skirmisher units kite the enemy even when heavily outnumbered (if they outrange the enemy) More valuable land zones are prioritised by units when deciding where to reinforce/attack/defend The land zones track what units are needed and land factories take this into account when deciding on the unit mix, so e.g. if the enemy sets up a firebase near M28’s base, then M28 will try and build MMLs/Mobile arti to try and break the firebase. I went through a few different ideas on how to approach this, and I expect once implemented significant revisions will be required as there will likely be flaws/unintended results from the planned approach. Potential approach 1 (discarded) Sort land zone by highest value to lowest value/priority Decide on the zone strategy based on available air and land options and enemy threat. Potential zone strategy options: ● ● ● ● Consolidate in zone – e.g. for where the nearby enemy threat isnt so great that we want to run, but where the current force isnt strong enough to attack an adjacent zone. Can pull in all forces from this and adjacent zones that are available to help with preparing for the attack. Fight – where enemy has units in this zone and our force is strong enough (factoring in enemies in adjacent zones) Retreat – enemy force is too great so want to fall back to a zone that is closer to a core base o e.g. could have zone ‘rally points’ for a plateau, and will look for the nearest rally point and retreat to this Attack adjacent zone – pull in all available units from this and adjacent zones to attack the enemy zone. 26 ● Move to zone – e.g. if there are no threats in this zone or an adjacent zone, then pick the best priority zone to send troops to, and move to an adjacent zone that is closer to that? Will need more thinking on how this will work Preferred approach for combat unit management Come up with order references for each scenario below, record against the land zone, and then implement these orders when come to the main manage specific land zone logic. In terms of deciding on approach to take, either: 1) Cycle through land zones sorted by priority in turn, and decide the approach to be taken for units; or 2) Decide on the approach for the land zone, and units as available to that land zone based on if our priority is greater than the priority ranking those units were previously assigned to zone’s previous priority ranking a. i.e. When a unit is given orders, it is assigned a plateau, land zone and value reference b. When a LZ then considers if that unit is available, it treats it as available if the value is < the current value, or alternatively the land zone and plateau reference is equal to the current plateau and land zone reference c. The benefit of this approach is I don’t need a separate loop between land zones in order of value, and so ● If we outrange enemy mobile and fixed DF with our DF (or they have defensive structures in the LZ which we outrange with our indirect units): o Have our DF units that outrange the enemy attack-move in range of the closest enemy unit, or do a kiting retreat if they are already in range, and to stay out of range of any enemy direct fire structures. o Other DF units that have <= the range of enemy: If enemy units are within 2 of getting in range of our higher range DF units, then move these to be inbetween the enemy units and our higher range DF units, otherwise keep them 10 behind our higher range DF units. o If we have IF units that outrange enemy DF structures, have those IF units with sufficient range try to get in range of enemy direct fire structures, and to retreat if they are about to get in range of enemy mobile units. o Other indirect fire units: If outrange enemy DF then kite enemy, otherwise treat the same as ‘Other DF units that have <= the range of enemy’ ● If we don’t outrange with DF, but we have significantly more threat than them, then attack move to the nearest enemy unit. ● Otherwise (i.e. we don’t outrange enemy, and we don’t have more mobile threat than them) retreat to the nearest land zone rally point Moving units between land zones ● If instead there are no enemies: Decide on best adjacent land zone to move units to: o If a land zone is set to retreat, or has no friendly units, then record it in a table of land zones wanting support: ▪ If the enemy has structures in it, then flag that it wants indirect fire support ▪ If the enemy has mobile DF units that we don’t outrange, or that have significantly more threat, flag that we want DF support 27 o o o o Even if we have units that outrange the enemy, if they have more threat than us also flag that we want support. If a land zone has an adjacent land zone that wants support, then send the units here If there are no adjacent land zones wanting support, then search for the highest priority land zone in our land subteam wanting support, and send the units here. If there are no land zones wanting support, then send the units to the nearest rally point. Nearest rally point For now (as I suspect I’ll want to see how the AI performs before spending too long writing code that may need rewriting anyway) I’ll keep things simple and just have the rally points as being the core bases of the team. Identifying available units for use by a land zone For now units will be included for combat logic as follows: ● ● ● ● Only include units that are mobile with a DF or IF range, whose fraction complete is >= 1 Record such units in a table for the land zone just for the combat units For any adjacent land zones with a lower value than our land zone: o Cycle through any units listed in the table, and add to our land zone as available units if they have a higher priority I’ll therefore use two tables, one for all combat units to be considered (which will include adjacent zone units with a lower priority assignment), and one for combat units to be considered that are just in the current land zone. Other related changes ● Land travel distances between each land zone on the same plateau should be calculated upfront at the start of the game and recorded in a table, so I can do more accurate distance checks when e.g. getting the nearest rally point. 2.13.2) Linking in to production I want some sort of logic that flags what types of units we need to defend/take a particular land zone, so those units can be built, e.g. factoring in if we need more indirect fire units to break the enemy, or more indirect fire units. For now I’ll try a very simple approach: ● Check both the current land zone, and then the pre-recorded engineer zones that are considered in order of distance to see if any of them need direct fire or indirect fire units. o If we can path to enemy base with land and the LZ is within half the distance to the enemy base, or we don’t have low mass, or the LZ is in the same island and we cant path to the enemy base with land, then build indirect fire if it needs it, and if not then direct fire. Land factory production Again for now I want something simple which I expect will need expanding greatly as I refine the logic: ● If it’s early game (<10m and no T2) and I have at least 5% mass stored, or I don’t have low mass and (I either need more units to secure 50% of the map, or I have at least 40% mass stored) then I want to build another factory. 28 ● ● ● Since I don’t yet have air logic integrated, this will be a land factory. If I have a higher tech factory in the same land zone, I don’t want to build tanks (so T1 factories are idle). However if I have fairly high mass then the factory should be upgraded to a support factory. Units an adjacent zones shouldn’t be given an order if the order would be to retreat. 2.13.3) Logic refinements based on in-game results Now that I have the barebones functionality in place (which works against the base game AI, but not well), I want to try and refine it so that it’s in a good state before worrying about adding in other logic such as air and PD – i.e. one flaw M27 has is it’s core land logic is weak at the T1-T2 stage (excluding cybran T2), and it survives vs other AI such as DilliDalli by relying on other areas where it’s much better (ACU management, navy, air, turtling). However, I want M28 to be decent at land combat before I work on integrating logic for other areas. Since my AI currently is only building tanks, engineers and land scouts, and for its base not much other than factories and power, DilliDalli should prove a decent benchmark, since DilliDalli wont attack with air units and doesn’t use its ACU aggressively that much (particularly on maps like Theta Passage). Therefore, if I can get M28 to a position where it can consistently beat DilliDalli without using its ACU, air or PD, on an early game map like theta passage, I will hopefully have it in a good state (and can start to test on other maps to cover any flaws in the logic). I also want to start by making Aeon work, since their increased range should lend themselves to skirmisher/kiting tactics. I’ll try vs Cybran, since the mantis have the best speed so Im assuming their mantis will be better than other factions at dealing with auroras. DilliDalli progress tracking – initial check ● Initially: Survived c.20m – at the start of the game M28 did ok, getting favourable trades, but it was slow to press the advantage where it had significantly more tanks, leading DD to outpace it quickly on eco and overwhelm. Reviewing in more detail though, M28 suffers from a few flaws: ● ● ● ● It’s reliance on a unit’s last known position leads to it trying to kite a unit that isn’t there – I need some logic that will recognise if it has intel of a unit’s last known position, but it can’t see that unit, and hence treat the last known position as actually being further away than it is. It currently sends every unit in the current land zone and all adjacent land zones to deal with a threat. While this means it takes good fights, it fails to fight on multiple fronts and ends up building a large force that can alternate between chasing one enemy, and (when that enemy retreats) chasing another enemy. It fails to target vulnerable enemy mexes, instead focusing on the units The approach of attack-moving results in T1 arti crushing units like auroras which end up tighly packed where 5+ can die to a single t1 arti shell. Sending all units to deal with a threat is by far the biggest issue, and is more pronounced when I tried testing with AiX 1.0 (to remove the intel issues as a factor). However, the danger going too far the 29 other way is that I end up thinking I’ll win a fight, only sending some of the tanks, and losing due to the enemy having a concealed force. One potential approach for this: ● Calculate the maximum amount of threat that we want to commit to an attack for a land zone o This will be 3x the enemy mobile DF threat for DF units in that zone only, and 1.5 times their structure threat for indirect units in that zone only. ▪ ● ● ● i.e. we shouldn’t factor in enemy threat in adjacent land zones, since we can always send units directly to that land zone Don’t requisition adjacent land zone units if we already have this amount, but still send all units in a land zone to attack the nearest enemy threat. To the extent we have units exceeding this amount in our current zone, then send them to an adjacent zone that needs units The DF and IF units wanted for a LZ should be reduced by the amount of threat already in that LZ (but not in adjacent LZs) DD progress tracking – post update The revised approach above achieved a dramatic turnaround in M28’s fortunes on Theta passage, with a replay where it was utterly crushed changing into M28 dominating DD by the 15m mark (when the replay ended) with DD shut into its base with ¼ the eco and fewer tanks. Interestingly prior to this there was a bug causing M28 to build lots of T1 arti with a few tanks, and this got beaten (not quickly but gradually), but I think this is partly due to DD’s micro proving very effective against T1 arti as few shots ever land on tanks. Most obvious was after making the above changes M28’s forces split into two large masses (previously there was a single mass), and attacked DD from both sides. I should note M28 still has an unfair advantage in that it wont build any AA or air units whereas DD builds inties, but it at least gives me hope that the work to date on M28 hasn’t been wasted (as if I couldn’t beat DD in a pure tank battle then one of the biggest points for M28 outside of possibly running faster which may not even be achieved would have been lost). Re-doing the replay as a full length game M28 again won (so it wasn’t a fluke). Misc changes/enhancements based on replays Further changes made based on checking replays against DD on Theta Passage and Eye of the Storm: ● ● ● ● ● ‘Shot is blocked’ logic added: o If we are managing combat units for a land zone, we have twice the enemy threat, and the unit’s a DF unit whose last shot was blocked, and it isn’t a skirmisher unit, then move towards the enemy instead of attack-moving Land scouts were’t retreating properly (due to some bugs in the code) Testing against Cybran M28 initially got slaughtered, leading me to tone down the values for taking a battle where we don’t have a range advantage so the units are more likely to attack. On Eye of the Storm M28 threw away a winning position by upgrading a T2 factory to T3 when it only had T1 factories (who built nothing as they thought the tech level had moved on), this was resolved by having T1 factories upgrade to T2 support factories even if we don’t have high mass. A few bugs were fixed relating to identifying land zones, and building skirmisher units. 30 ● ● ● ● ● ● ● ● ● ● ● On theta passage my tanks would run away despite outnumbering the enemy more than 2:1 – checking the logs it turned out they were including the enemy ACU in an adjacent land zone, despite the enemy ACU being miles away from battle. I’ve improved on this by only including enemy units in adjacent land zones as part of the threat calculation if they are relatively close in distance to the current land zone. When deciding whether to retreat, the threat of friendly combat units in the current land zone that are on orders from an adjacent land zone should still be included (to avoid cases where e.g. we outnumber the enemy but still run because some of the units are heading to a nearby land zone). When considering if a mex is safe to upgrade, mexes in the core base will be considered safe even if there are enemies in an adjacent land zone, to reduce the risk (which happened on one replay on theta passage) where a T2 mex well away from the main base was upgraded to T3 ahead of all the core T2 mexes (because of a nearby enemy unit in an adjacent land zone to the core base). Engineers shouldn’t retreat from the core zone Added tracking of engineer reclaim unit orders so all reclaiming engineers can be reclaimed when the reclaim order finishes (in part to fix a strange bug where engineers could end up reclaiming a cybran flying building drone). Factories will build T1 arti if there are enemies near an adjacent land zone and we don’t have low mass (mainly to deal with scenarios where we have T2/T3 factories and the T1 factories sit idle while the enemy pushes back the main forces, since T1 arti can do ok against poorly micro’d units even in the mid-game). The low mass flag will now factor in how long since we last mass stalled. Sniper bots wont be built if the enemy is still at T2 and we have built fewer than 15 T3 tanks. A % of units should be indirect fire units to help with things like cliffs where both armies cant hit with direct fire units and/or the enemy getting PD to defend; while this makes performance vs DilliDalli slightly worse (since it doesn’t built PD), I’m hopeful it’ll make it slightly better vs players. After seeing the repeated poor performance of loyalists compared with bricks, I’ll now only build 2 before moving on to bricks as Cybran. T3 land factory should be prioritised after we have built 15+ T2 combat units even if the enemy doesn’t have T3. 2.14) Construction – radar and queued buildings 2.14.1) Radar coverage Testing out how my AI does vs DilliDalli with and without skirmishers, Cybran performs similarly, whereas Aeon (with sniperbots) does much worse. One reason is that sniper bots need much better intel and are punished far more for getting near the front line/near an unseen enemy. One solution to this hopefully will be to build radar, and have T3+ skirmishers stay within radar coverage. M27 had a fairly poor performance approach to this where it would get every radar building and land scout unit within a certain range, check its intel coverage, and use that to decide what intel coverage a particular unit had. I want to for now just have something that tells me my radar coverage, and I could potentially expand to also allow T3 skirmishers to consider attacking if there’s a land scout in both the current and all adjacent land zones where radar coverage is lacking. 31 Tracking radar coverage To track radar coverage, I’ll use callbacks/events as follows: ● ● Whenever a radar is built by a player with M28 active players on its team, get the radar intel range. Cycle through every land zone on the map for every plateau, calculating the distance of the land zone midpoint to the radar. Record that land zone intel coverage as being the higher of its existing coverage, and the radar. Also record against the land zone the radar providing the best intel for it, and against the radar the land zones that it is affecting. o If the land zone already had a radar unit recorded, then update that radar to remove that land zone from the list of land zones that it was affecting . When a radar is destroyed, go through the list of land zones that it was affecting (as providing the highest radar coverage), for each one clear the list of the radar giving the best intel, then get all radar buildings within a 600 radius (size of omni) and calculate which one provides the best intel (if there are any), and record the intel coverage and best radar (if any) accordingly. Building radar For now I’ll build radar as a lower priority similar to M27’s lower priority builders, which require a certain level of power and mass before building. 2.14.2) Queued buildings by land zone One thing I’d been meaning to add for a while when I started on my engineer logic was similar functionality to M27 where I can consider queued orders when choosing where to build (so I don’t queue two buildings at the same location). I’ll do this on a land zone basis (in contrast to M27 which did it on an aiBrain basis), so each land zone will track any queued buildings, and clear this tracking when construction is started. This way I hopefully will have a fairly small number of queued buildings to consider, so I’ll just do a distance check with each building whenever checking a location for now (M27 went with the potentially quicker approach of recording every square that a queued building covered, and marking such locations as having a queued building, and then checking for all squares that a new planned building would cover to see if they were available). 2.15) Pathfinding optimisation – Winter Duel For some reason winter duel takes ages to complete its pathfinding, compared with Theta Passage (despite being half the map size). The below is the profiling results of the most expensive functions at the start of the game (with the function RecordTemporaryTravelDistanceForBaseSegment being the cause): info: ProfilerOutput: No.1=SetupMap; TimesRun=1; Time=62.206245422363 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=62.002670288086 info: ProfilerOutput: No.3=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=55.184494018555 info: ProfilerOutput: No.4=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=1161; Time=54.731185913086 32 info: ProfilerOutput: No.5=AssignSegmentsNearMexesToLandZones; TimesRun=1; Time=6.5957374572754 info: ProfilerOutput: No.6=RecordPathingBetweenZones; TimesRun=1; Time=0.110107421875 The first potential solution I tried was to simplify the approach for plateaus with no mexes. If a plateau has no mexes, then every segment on that plateau will be assigned to a land zone based on the NavUtils label result for land pathing (i.e. each unique island on the plateau). To do this I temporarily store a table showing how to get from this land pathing label to the land zone count recorded against the plateau. This means I can avoid using the temporary travel distance checks for any such plateaus (since I suspect the cliffs around the edge of winter duel are causing a strain). This helps, but not by much, as the below log (after this change) shows – it’s reduced the time by about 20%: info: ProfilerOutput: No.4=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=604; Time=44.68595123291 I then increase the ‘abort threshold’ on this logic which was brought in to optimise it – essentially the function is searching for multiple adjacent segments that have been assigned a land zone, calculating how long it takes to path to each of them, and if it finds a ‘close enough’ match to a likely fast result it stops looking. The higher the abort threshold, the more of a detour it allows to be ‘close enough’. I change this threshold from adding an additional travel time of half of a segment size, to adding an additional travel time of 30% of the total segment size * the segment search range (so if we are looking 10 segments away, it will allow a detour of 3 segments to there to be acceptable). This improves things by a similar amount to before: info: ProfilerOutput: No.4=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=604; Time=31.810440063477 Increasing this slightly more so it will be 30% * segment search size + 1 improves things slightly more to: info: ProfilerOutput: No.4=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=604; Time=28.87996673584 I don’t want to increase the value too much since it’s intended to stop places with cliffs between them being assigned to the same land zone. Analysing map, this may take a minute message takes too long to appear 2.15.1) Other changes No enemy support When testing on winter duel I forgot to setup the teams correctly (having M28 with no enemies) which unsurprisingly resulted in errors, and caused M28 to do nothing. It will now display a chat message to the player warning them if it can’t find any enemies, and will operate as though the furthest away player is the nearest enemy to it in order that some of the basic logic (mainly base building) works. Debuging – structure names Structures should now display their plateau and land zone to make debugging slightly easier 33 Power stall timing is taken into account when deciding how many units to be upgrading if we already have 1 mex (so if we have e..g 90% mass stored we wont get 4+ mex upgrades when we suddenly have energy income); in addition, mass upgrades should factor in how quickly we will use up the stored mass and limit upgrades to 1 at a time if we don’t have enough stored mass to fund an upgrade. 2.16) MAA, further map setup optimisation, and other tweaks 2.16.1) Tracking enemy air units and threat My current tracking only handles units in land zones, and also refers to if the location is pathable amphibiously, which is a problem for air units who can travel on unpathable areas. Since games can potentially feature huge numbers of air units, I also need to be careful that any tracking system wont be too heavy/intensive. However, I also like the idea of trying to use the last known position as a more accurate version of M27’s IMAP approach to better assign MAA to areas and calculate air threats (and whether they’re more urgent than land threats). I’ll therefore try the following: ● ● ● ● If dealing with an air unit for assignment, it should be assigned to both a table of enemy air units (separate tables for AirAA, AirScouts, and OtherAir for enemy and ally air units), i.e. globally on a team basis. In addition, it should also be assigned to a land zone if it is in one. If it isn’t in a land zone, then it should be assigned to a table of units without a land zone. This table should then be checked every cycle to see if any of the units are now in a land zone (similarly to how land zone units are updated). This logic should all be done as part of the main land zone cycler, to try and spread out the load of updating units. 2.16.2) MAA builder logic ● ● ● Don’t consider getting MAA until either the enemy has air to ground threat, or we have T2 land. Get a minimum level of MAA of 5% of the total DF and indirect threat (regardless of if a LZ wants more MAA) o Increase to 10% if enemy air to ground threat is 6k or greater Also added a cpa on the ratio of MAA to have relative to other units 2.16.3) MAA management ● ● If there are enemy air units in a land zone, then move any MAA towards them, unless the enemy has a direct fire threat that is almost in range of the MAA. If there are enemy air units in a land zone, and there are friendly units in the land zone, or no enemy ground units, then request MAA equal to 50% of the air to ground threat + 20% of the airaa threat, or (if higher) 10% of the DF+Indirect threat After introducing this I tried M28 out against RNG and M27 – it got slaughtered, but against M27 after fixing some bugs with MAA over-production it managed to sneak in a win (it was behind on eco 34 about 2:1 on open palms but M27’s ACU got overexposed and died despite M28 not having any snipe type logic). 2.16.4) Status and performance check Testing the new logic against the 3 main AI (DilliDalli, RNG, M27) gave the following results: Open Palms Generally speaking M28 was outclassed by all 3 AI, suffering convincing defeats ● ● ● Vs M27 – outclassed (e.g. gets to about 100 mass income to M27’s 200), but M28 was able to sneak in a win once when M27’s ACU overextended Vs RNG – outclassed, similarly to M27 it’s main chance is that RNG overextends its ACU. Vs DilliDalli – Faction dependent, e.g. Aeon M28 can often beat Cybran DD, but other matches favour DD Refinements from replays ● Idle T1 facs – if no other T1 facs are upgrading in the LZ, and we have 2+ T1 facs in the LZ, and we have 3+ buildings upgrading in the LZ, then upgrade a T1 fac regardless of mass income. ● If have 3+ active upgrades per player and need more engineers for a land zone, and it would otherwise have an idle factory, then engineers should be built. ● More engineers should assist upgrades in a land zone if there are 2+ units upgrading (and even more if there are 3+ units upgrading) ● MAA shouldn’t be built until we have T2 land or enemy has an air presence. ● If we have mass to spare and the normal builders don’t build anything, instead of building T1 arti we should built direct fire/skirmisher units if we have the highest factory tech level. CPU performance Although I don’t have any air logic yet, I also want to get a sense of if my AI is likely to be better or worse CPU performance wise than M27. M27 would run a 4v4 UEF mirror against itself on the Africa map, and ignore the time taken to generate the initial pathfinding. Doing the same with M28, gave the result: info: ProfilerOutput: Total time taken to get to 6001= 49.483154296875; Total time of any freezes = 0.092045590281487; Longest tick time=0.14840698242188; tick ref = 139 to 140 For comparison, M27 v61 was: info: ProfilerOutput: Total time taken to get to 6001= 155.51567077637; Total time of any freezes = 19.898599624634; Longest tick time=0.43302917480469; tick ref = 4690 to 4691 It’s too early to say if M28 will remain faster, but it’s very reassuring to see it dramatically faster at this stage, as I was worried the land management logic could end up by itself taking longer. However, the biggest time requirements for M27 were its engineer logic and land combat unit management (the latter of which is almost fully implemented for M28). I then did 1 match with random factions for Eye of the Storm and Astro craters: 35 Astro craters ● Cybran vs UEF DilliDalli – Win in 31m19 - an incredibly close game where DilliDalli spent most of it fighting in M28’s core base and M28 lost 1/3 of its starting mexes and almost all engineers yet somehow held on and once its bricks hit the field was able to push DilliDalli back ● UEF vs Seraphim RNG – Win in c.25m (after fixing a bug causing M28’s units to retreat from wall segments) ● UEF vs Aeon M27 – Loss in 37m - M28 was actually ontop for much of the game, but failed to produce MAA pre-emptively meaning M27 was able to wipe out most of M28’s army with a Czar Improvements made based on astro replay: ● ● ● ● ● ● ● T3 MAA will be built once we have 50+ MAA Wall segments shouldn’t be recorded by the land zone logic. When deciding what units to get for a LZ, consider MAA as a higher priority than indirect fire if enemy has air to ground threat (generally) and we have a low MAA to indirect ratio; also treat MAA as higher priority if there is any air to ground threat in that land zone and MAA is needed Adjusted MAA reinforcement logic so if multiple adjacent zones want MAA they will go to the one with the biggest need. Added several higher priority factory and second factory builders to reduce the risk of mass overflow, along with a lower priority power builder for if we have lots of mass (since if we scale up our BP we are likely to want to have more power). Engineers building a 2nd factory will no longer search for existing factories to assist Aeon and UEF land scouts should be ignored when deciding if an enemy unit is almost in range of our combat units. 2.16.5) Map pathing optimisation Frostmill ruins optimisation detour I want to have every land zone record the pathing to every other land zone given the limitations revealed with the MAA logic. However to check I can afford to do this at the start of the game I need to see how it works on the largest of maps. Running on Frostmill ruins took the following time: info: ProfilerOutput: No.1=SetupMap; TimesRun=2; Time=506.27749633789 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=494.5608215332 info: ProfilerOutput: No.3=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=435.4938659668 info: ProfilerOutput: No.4=AssignNearbySegmentsToSameLandZone; TimesRun=100; Time=435.24127197266 info: ProfilerOutput: No.5=AssignMexesALandZone; TimesRun=1; Time=52.065399169922 info: ProfilerOutput: No.6=RecordPathingBetweenZones; TimesRun=1; Time=6.5401000976563 36 Optimisation 1 – increasing number of segments considered around mexes I expect the RecordPathingBetweenZones would take much longer if I was to change from doing just start zones to doing every zone. However I first need to improve things for larger maps by e.g. making land zones larger, and any other adjustments I can think of (e.g. expanding the area around mexes for a land zone by more than currently). Increasing the threshold on larger maps from considering a minimum of 4 segments around a mex to a minimum of 10 results in: info: ProfilerOutput: No.1=SetupMap; TimesRun=2; Time=75.100631713867 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=63.43140411377 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=53.929103851318 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=4.9164123535156 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=1230; Time=4.9073867797852 info: ProfilerOutput: No.6=AssignSegmentsNearMexesToLandZones; TimesRun=1; Time=4.1664352416992 info: ProfilerOutput: No.7=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.39918518066406 info: ProfilerOutput: No.8=AssignNearbySegmentsToSameLandZone; TimesRun=15; Time=0.3031005859375 Increased accuracy – calculating every pathing option If I then change to consider the pathing from every land zone (as opposed to only adjacent land zones) for non-start position locations (to allow better options for managing MAA units and potentially other units) this results in: info: ProfilerOutput: No.1=SetupMap; TimesRun=2; Time=147.52470397949 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=136.01202392578 info: ProfilerOutput: No.3=RecordPathingBetweenZones; TimesRun=1; Time=79.005805969238 info: ProfilerOutput: No.4=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=5550; Time=78.990165710449 info: ProfilerOutput: No.5=AssignMexesALandZone; TimesRun=1; Time=52.511100769043 info: ProfilerOutput: No.6=AssignSegmentsNearMexesToLandZones; TimesRun=1; Time=4.0892791748047 info: ProfilerOutput: No.7=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.38583374023438 info: ProfilerOutput: No.8=AssignNearbySegmentsToSameLandZone; TimesRun=15; Time=0.29238128662109 info: ProfilerOutput: No.9=ManageAllLandZones; TimesRun=711; Time=0.28631591796875 info: ProfilerOutput: No.10=ManageSpecificLandZone; TimesRun=5950; Time=0.26889038085938 37 Optimisation – calculating pathing distance once instead of twice The above is still too long, but I may be able to optimise slightly – currently this is achieved by looping through every land zone in a plateau as the starting land zone, and then looping through every land zone in that same plateau as the target land zone, and calculating the difference. This means e.g. land zone 1 will calculate the travel path to land zone 2, and then land zone 2 will calculate the travel path to land zone 1. I should be able to instead have land zone 2 realise it has already calculated the travel distance and obtain those results instead of recalculating it. I also move some logic that checks for the furthest adjacent land zone each time such a check is done and instead do this at the end which should reduce the number of times it’s called. After making these changes, the results are: info: ProfilerOutput: No.1=SetupMap; TimesRun=2; Time=115.82766723633 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=104.29391479492 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=58.265022277832 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=40.830474853516 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=5550; Time=40.816192626953 info: ProfilerOutput: No.6=AssignSegmentsNearMexesToLandZones; TimesRun=1; Time=4.7161407470703 info: ProfilerOutput: No.7=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.4591064453125 So the time required has almost halved (which is a bit better than I was hoping, as I had to add extra logic/checks in the single cycle for it to cover both directions). Although 2 minutes is a long time, this is on an 80km map and the AI isn’t really intended for such maps. 20km timing check Testing on a 20km map, Setons, gives the following results: info: ProfilerOutput: No.1=SetupMap; TimesRun=2; Time=55.516708374023 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=54.269756317139 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=26.1360206604 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=18.954334259033 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=4160; Time=18.944271087646 info: ProfilerOutput: No.6=AssignSegmentsNearMexesToLandZones; TimesRun=1; Time=6.154712677002 info: ProfilerOutput: No.7=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=2.9932746887207 38 info: ProfilerOutput: No.8=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=767; Time=1.7424964904785 info: ProfilerOutput: No.9=AssignNearbySegmentsToSameLandZone; TimesRun=19; Time=1.2180976867676 info: ProfilerOutput: No.10=ManageAllLandZones; TimesRun=1468; Time=0.59584045410156 This is under a minute, and of this calculating the distances and travel paths between every land zone is taking 19s, so I think this is a price worth paying. Consequential MAA changes and misc ● Now that I can consider every land zone when considering MAA support, I’ll change the logic to only send MAA to a LZ that will result in it having enough threat, and then move onto the next nearest land zone. ● MAA should also try to help a zone with any non-scout non-MAA units in it, or non-scout units if we have MAA already in it and they have an air to ground threat in it ● T3 MAA are more likely to be built if the enemy has alive strats (as I found in live games that the strats just wouldn’t die despite a massive number of T2 MAA, despite getting a different result in sandbox). ● After these and bugfixes, M28 would kill the M27 Czar (but would still die to T3 arti, since it had no shielding logic). In another replay it managed a lucky win when M27 ventured its ACU out of its firebase briefly. ● Another change was to introduce a second mass storage builder for times where we end up with a T3 mex but still have mexes in the land zone wanting mass storage. ● Land factory builders wont ignore queued orders if we have less than 100 mass per second. 2.17) Mobile shields 2.17.1) Shield assignment: ● ● ● ● ● Cycling through LZs from the nearest first, record the first LZ for each of the following, where the LZ wants more mobile shields, in order of priority: o ACU LZ – I’ll look to add this in later once my ACU logic is in place o Zones with an enemy combat threat or air to ground threat o Zones with enemy units or adjacent enemies o Closest LZ o If no land zones can be found, then the closest LZ that has combat units in it and wants more combat units will be chosen. Assign available mobile shields to the highest priority of the above, until that LZ no longer wants more mobile shields or we run out of mobile shields to assign. When assigning a mobile shield, assign it to a particular unit When evaluating whether a mobile shield is available: o If shield is <=50% then the mobile shield isn’t available and should retreat o If the shield is >50%, if the assigned unit is no longer valid then make the mobile shield available When assigning shields to units in a land zone, to keep things simple for now Ill just cycle through the list of units recorded as wanting shields (rather than trying to sort by distance or value). 39 2.17.2) Shield production and management Shield production ● If we have any land zones in the plateau that are flagged as wanting mobile shields, and we have at least 10 net energy income (15 for T3 factories) then build mobile shields, as a fairly high priority. Shield orders ● Calculate the angle from the target unit to the nearest enemy base (of the LZ the target unit is in), and aim to be a distance that is max(50% of the shield radius – shield speed – unit speed), 3) behind this. 2.17.3) Misc changes made ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● Adjusted the distances for grouping mexes together slightly, increasing htem for larger maps, and decreasing the distance based on how many loops have been done for the same land zone. Adjusted the threshold for building a high priority land factory early on to make it slightly more likely. Fixed bugs with the energy and mass stall logic that caused everything to be paused, and adjusted some of the thresholds and amounts to pause or unpause. If we are upgrading more mexes than we have players on our team, then when having a mass or energy stall the ones with the lowest progress (until we would be left with 1 per player) are paused. Increased mass threshold for MAA to be assisted by mobile shields to 400 if enemy air to ground threat is less than 1k Adjusted the threshold for higher priority indirect fire units to be built based on factory tech level Limited the number of indirect fire and MAA units that are built for certain builders based on the number already being built in the same land zone. Land zones can no longer control adjacent land zone units if the adjacent land zone contains enemy direct fire units. The highest power generator should no longer be built if we have low mass Capped number of mobile shields per player to 35 or if lower Various bug fixes If we have 5+ engineers of our current tech level and fewer tanks than engineers then more tanks should be built as a high priority. Building MAA – if the enemy has no air to ground threat in the current or adjacent LZ, and their overall air to ground threat is low, then the number of factories building MAA in the LZ should be capped at the lower of 2 and half the number of land factories in the LZ, rounded down. Engineers should stop running if there are no longer any enemy units nearby or we have significantly more friendly force. Added backup logic for assigning a unit to a land zone where if it is an M28 unit and it has no orders and isnt on a land zone it will move to the nearest land zone and be added to the list of units for that land zone. T3 mobile artillery will be built in priority to the normal suggested unit when defending the main base or adjacent land zones if we are at T3 and have a high direct fire threat already 40 ● ● ● ● ● ● (i.e. if we’re Aeon or Seraphim with lots of sniper bots, then some T3 mobile arti may be good in case the sniperbots’ shots are blocked or they face lots of lower level tank spam, or enemy sniper bots). Added a limit on MAA if we have the equivalent of 5 T3 MAA and enemy has no/minimal air to ground threat. Increased the ratio of indirect fire to direct fire once we reach a high unit count of direct fire units, and also make the indirect fire builder activate even if we have low mass if we have lots of T3 direct fire units and too few indirect fire units. Adjusted MAA reinforcement logic to prioritise locations with enemy air to ground threats. After RNG bombers wrecked havoc on M28’s units (which are much more vulnerable due to the attack-move approach for their attacks) I decided to copy over M27’s bomb dodging logic. For now it’ll work in a similar way to M27, where both bombs and shots are considered for dodging. Omni sensor will be built with less energy income requirement than normal if we have built a large number of T3 tanks If we have radar coverage of a land zone then units regorded against that land zone will have their actual position updated 9so e.g. if an enemy has retreated out of the land zone and we can tell they aren’t there due to radar coverage, units will no longer avoid advancing due to incorrectly thinking the unit is still there). Performance check vs DilliDalli on forbidden pass: ● UEF Mirror – M28 won in 52m17 ● Aeon Mirror – M28 Won in 1 hour 28m – a very close game where M28 came back from a more than 4:1 mass deficit (was under 100 mass to DD’s more than 400 mass at one point). ● Cybran Mirror – DD won in 23m52 initially, after various changes made from other replays (noted above) M28 won in a close battle in about 53m ● Seraphim mirror: M28 won in 46m29 Although post-changes M28 won 4/4 games, they were all close with M28 behind at various points in the map and a fair bit of back and forth. Vs RNG on forbidden pass ● UEF Mirror – Win in 19m07 (fairly even battle but RNG was using its ACU in combat and it got overwhelmed by a swarm of M28 gattling bots) ● Aeon Mirror – Loss in 42m57 – M28 had the upper hand until RNG sneaked a GC through the water into M28’s base ● Cybran mirror – Win in 46m14 ● Seraphim mirror – Loss in 41m39 – M28 lost to an RNG Ythotha For reference, v41 of M27 had a 75%-100% win rate vs RNG and a 66% win range vs DilliDalli – i.e. M28 is almost at a similar level, despite making no use of its ACU, and not having any PD or air logic. Vs M27 v66 on forbidden pass ● UEF mirror: Loss in 41m32 – M28 was behind the entire game, although still managed some successful raids against M27. ● Aeon mirror: Loss in 33m36 – M28 was struggling to keep up with M27, and then M27’s strat arrived and wiped out most of M28’s eco. 2.18) ACU – after initial build order 2.18.1) ACU Upgrades 41 ● ● ● ● ● If not in initial build order mode, if have resources to get an initial gun upgrade then retreat until no enemies in any adjacent zone or are within 1 zone of a core base, and then get upgrade if we have the eco to support an upgrade. For now the upgrades will be the standard guncom sequence that M27 initially favoured, but without the late game upgrade options (since m27 could almost never get these to work effectively and they were only left in for fun). When deciding if we have the resources to get an upgrade, the number of active team upgrades will be taken into account (so e.g. a team with 500 energy combined should try to get 1 of the ACUs upgrading, wheras for M27 it may have waited until a single player had 500 energy on its own). To avoid calculating the upgrades wanted each time, I’ll calculate the upgrade path at the start of the game and then whenever an upgrade is completed. Added better support for unexpected upgrade options/mods – similarly to M27 the normal upgrade options are hardcoded in, but if they aren’t recognised, or the faction is different, then M28 should instead pick the cheapest upgrade that changes its weapon damage or range. 2.18.2) Nearby enemy logic In the case of M27 it couldn’t win battles with its land alone so relied on an aggressive ACU to help win it an advantage early on. My hope with M28 is that as its land logic is slightly better it can afford to be a bit more cautious with the use of its ACU. For now I’ll take the approach of having it run if it thinks it might lose a fight or is injured, or the enemy is in range of it. Overcharge ● First check if there are any enemies that can be overcharged. M27 handled overcharges by allowing it as a special additional action that would then have another action queued up after it. I want to try just having it as the only action, and then when the overcharge shot is fired a new action is obtained, to make the code a bit simpler. ● I’ll copy over the overcharge logic from M27 since it works fairly well, the only change being to add in tracking on a land zone basis of wall segments (so it is only checking for blocked paths from walls based on the number of walls in a land zone rather than globally) ● Logic to assess whether the ACU is currently running (when deciding whether to overcharge PD) is also replaced by checking if we have run in the last 30s. Deciding whether to run ● If the ACU doesn’t have more threat (taking into account only allied units in the same LZ as it, but considering enemies in all adjacent LZs) then it should try to retreat. It should also retreat if low on health. Attacking If the ACU doesn’t want to run and there are enemies nearby, then it should try and attack them; if its shot is blocked, it should advance to the enemy, otherwise it should attack-move until in range and then retreat. 2.18.3) Other actions when no enemies to attack Building mexes If the land zone has unclaimed mex points and there are no engineers assigned to build mexes, the ACU should build mexes. 42 Getting reclaim If there are any notable individual reclaim items, the ACU should reclaim these. Moving to other land zones If the ACU has no action for the land zone then it should find the land zone with the highest value that wants support within 175 of it, and if there is none then it should retreat. 2.18.4) Other ACU related logic ● ● ● ● ● ● Once the enemy has sniperbots or land experimental or T3+ air to ground unit, or we have 30+ T3 units, keep ACU at core base or 1 adjacent to core base – have a flag similar to the early game flag that indicates ACU should be kept near base. If the ACU cant find a LZ needing combat support nearby it should try going to an expansion with unclaimed mexes or lots of reclaim. ACU will consider if it is almost in range of an enemy or an enemy is almost in range of it before considering logic such as building on a mex or reclaiming. The ACUs should be tracked by land zone, with MAA factoring in if an ACU is present when deciding how much MAA to allocate. ACU is more aggressive if on our side of the map, near our base, and/or against the enemy ACU. Allied units should factor in a % of our ACU threat when deciding whether to attack. 2.18.5) Misc changes ● ● ● ● ● ● ● ● ● ● ● Non-skirmisher units when underwater will switch from attack-move orders to move orders (so they don’t get stuck underwater) Engineers should now finish building mexes where the original engineer was killed with the mex part-complete (thanks to Relent0r for highlighting) Early game (first 10m) M28 should be much less likely to upgrade a mex if the map is 10km or smaller and the enemy doesn’t have T2, instead preferring more factories. Adjusted land zone recording to increase the distance to search from mexes before resorting to creating mex-free land zones Improved initial build order so a second land factory shouldn’t be started until a base level of power has been built. Selen combat scouts should attack isolated enemy engineers. Added logic to track when a player dies, and copied over M27 logic for sharing resources on death. If one M28 has 2+ energy storage more than another (on building an energy storage) it should gift that energy storage to the teammate. If an enemy experimental is almost in range of direct fire units, then instead of running they should turn and attack (as e.g. in one case before this a Ythotha was able to kill 40 percies without taking any damage since the percies would try to run from it and die before they could fire a shot one at a time) Reduced the amount of power that gets built initially to try and avoid overbuilding it early game. Reduced the amount of engineers that get sent to a land zone to reclaim, particularly early-game. 43 ● Added a cap on the builder that gets DF units equal to the number of engineers, to be capped at 8 units (since this triggers before analysing what each zone individually needs). Grouping mexes near start points I want the start area to be larger than normal land zones, both to allow for nearby hydros to be included, and to give more building space. I’ll therefore include any mex within 70 of a start zone to that start zone, and have them assigned to the closest start point, while also assigning start points near each other to the same land zone. This means that on maps like theta passage (where previously one start position included the hydro and the other didn’t) both start positions now include the hydro. 2.19) Mobile stealth, enemy firebase, and misc 2.19.1) Mobile Stealth ● ● ● Added in mobile stealth, largely with a copy of the shield logic, but removing the ‘retreat when low health’ part of it It’ll also use higher mass thresholds, with a max of 1 mobile stealth every 3 lower mass units (so e.g. MMLs should get some stealth coverage, but not 1:1 stealth coverage, since stealth doesn’t double their effectiveness). If enemy has built omni or has map-wide omni, then don’t bother building deceivers. 2.19.2) T2 Arti avoidance/enemy firebase Planning ● If the enemy has 3+ T2 arti in a land zone, then I want to avoid that area unless I have an overwhelming force equivalent to an experimental. Prior to this I want to try and overwhelm the T2 arti with MMLs and T3 mobile arti though. ● I also want to adjust the threshold if the T2 arti get a high number of mass kills (to avoid e.g. a constant stream of MML being sent against a shielded T2 arti covered in TMD that ends up killing the MML without being in any danger of dying). ● However, I don’t want to apply this logic if the T2 arti is threatening a core base, since otherwise I lose the game. ● However, my normal land zone management logic wont work well, as T2 arti will likely outrange the land zone size, and I only consider adjacent land zone units when calculating threats (meaning my units wouldn’t see the T2 arti even if they were looking for it). ● I see two potential approaches here: o Whenver T2 arti is built (or destroyed) update every land zone in it’s range to record that T2 arti against the LZ, with this table then being considered for a land zone when deciding what to do and if it wants reinforcements. o Treat 3+ T2 arti as being a ‘firebase’, and record similarly to the above, meaning I would then apply logic to decide whether to try and assault the firebase or not (e.g. with an experimental). This could mean recording the LZ containing the firebase against each LZ in range of the T2 artillery. ● Thinking ahead, once M28 gets to the experimental stage of the game, it is likely to run into scenarios where the opponent has both an experimental and T2 arti in the same area; if I only record the T2 arti, then I risk thinking I can kill them by focusing only on the T2 arti, and then once the LZ the T2 arti are in becomes adjacent I realise there’s an experimental there 44 as well and retreat (meaning I end up constantly taking fire from the T2 arti while doing nothing). The second approach would probably be easier to deal with this situation since I could factor in the threat of the land zone containing the T2 arti into any decision on whether to attack or retreat. Identifying and tracking a firebase ● Track the number of enemy T2 arti against a land zone for a team (with a table separately to the enemy units table) ● When adding or removing a T2 arti to a land zone, check if there are 3+ T2 arti in the land zone, and if so record it as a firebase (or remove it if there are too few T2 arti) ● Whenever a T2 arti gets a kill, and has a mass kill value of at least 500, check the total mass kills of all T2 arti in the same team, and if it is >=2.5k or averages more than 1k per T2 arti, then record a firebase. ● When a firebase is recorded, add it to a global table of firebases, that for each firebase returns both the base land zone it is in, and then a table of all land zones in range of it. For each unit in the firebase assign it this reference number (so when a firebase is destroyed, all land zones can be updated) ● Get every adjacent land zone with a straight line distance of 35 above a T2 arti range; record against a table of enemy firebases for that land zone the land zone reference that is in range of it. Adjusting behaviour for a firebase Factory builders: ● ● If we are in range of a firebase: o If the firebase is in range of a core land zone, then request indirect fire units when considering what units the land zone wants. o Otherwise, request DF non-skirmisher units If there’s a firebase threatening a non-core LZ, then units should only be built to support other land zones if we have got every mex in the current land zone upgraded to T3. Land zone unit management: ● ● ● If the firebase is in range of a core land zone, then apply current logic (indirect fire units attack and ignore T2 arti) Otherwise, when deciding if there is enough threat to attack for a LZ in range of a firebase that isn’t in range of a core land zone, factor in the threat of any T2 arti and shields in the firebase, and require DF threat exceeding this value. After seeing how this works in-game, I tweaked to only factor in the firebase threat to decisions on what to do with units if athe unit closest to the firebase land zone is withi n140 of the firebase unit closest to the unit’s land zone. 2.19.3) Misc changes ● Have MAA backup logic go through each LZ and give it three times the MAA wanted before resorting to staying at rally point 2.19.4) Status check 45 I’ll now do a series of random faction matchups against DilliDalli and RNG on a variety of maps to see how it performs now that it has the ACU logic (meaning in theory M28 should have a reasonable chance on 5km maps). Some of the below results were before some of the above misc changes. vs DilliDalli (random faction matchups) ● Open Palms: Aeon vs DD Cybran – Win in 22m; UEF vs UEF ● Forbidden pass: Cybran vs DD Aeon - Win in 48m59 ● Astro craters: Aeon vs UEF - Win in 21m13 ● Theta Passage: Seraphim vs Cybran – Win in 16m23 Vs RNG (random faction matchups): ● Forbidden pass: Aeon vs UEF – Loss in 44m39 – M28 was ontop for most of the game until RNG managed to get a fatboy near M28’s ACU just before RNG’s base was overrun. o Doing another game, this time Cybran vs UEF, M28 won in 39m15 ● Theta Passage: Aeon vs UEF – Win in 32m55 ● Astro Craters: Cybran vs Cybran – Win in 27m14 ● Open Palms: Aeon vs Cybran – Win in 38m46 TeamGame scenarios ● Badlands: 4v4 vs DilliDalli: Win in 18m12 ● Badlands: 4v4 vs RNG: Win in c.40m (after fixing some bugs with M28’s use of overcharge – the first run of this M28 slowly pushed RNG back before RNG got a ythotha and wiped out all the M28 bases one at a time) ● Badlands: 4v4 vs M27: - M28 did manage to kill 1 M27 ACU, but M27’s combined gunship-land defence forces were too much for M28, along with M27 constantly taking out M28’s mexes with TML (since M28 cant build TMD yet). ● Open Palms: 3v3 vs M27: Loss in 37m – a resounding loss, with M28 losing at all stages of the game. Vs M27: ● Theta Passage UEF vs UEF – Win in 15m41 – M28’s first convincing win against M27 (i.e. where it hasn’t gotten lucky with killing an overextended M27 ACU). This was only after running a number of games on theta passage and fixing some bugs/slight issues with the ACU behaviour. o Trying again (this time Cybran vs UEF) M28 managed another win – it was losing initially, but M27 reduced the pressure allowing M28 to win back map control and even with M27’s TML constantly sniping M28’s T2 mexes (due to no TMD) M28 was still able to maintain a 2:1 eco lead throughout. ● Open Palms Aeon vs UEF – Loss in 34m44 – although M28 died to a nuke it was far behind for most of the game except the initial T1 stage. ● Forbidden pass UEF vs UEF – Loss in 39m44 - M28 stayed competitive with M27 (even having a slight eco edge for parts of the game) until the mid-T2 stage, but M27’s superior air and navy meant its defeat was inevitable after failing to get a decisive advantage in the early game. ● Astro Craters UEF vs UEF – Loss in 44m23 ● Williamson’s Bridge Cybran vs Cybran – Draw in 9m06 – M28 had the upper hand on eco until its ACU ended up sandwiched between M27’s base and M27’s ACU (with M28 having 24 mass to M27’s 14 when both ACUs died) 46 ● ● Cobalt Valley UEF vs Cybran – Loss in 7m16 – Unfortunately the ACUs get in combat too early on and M27 is better at hunting down an ACU than M28 is at defending an ACU in trouble. Desert Arena Seraphim vs UEF – Draw in 7m38 – M28 had the upper hand on eco but could only manage a draw when M27 pushed with its ACU to get the kill. 2.19.5) Further misc changes From the above, M28 has a reasonable (approximately 50%) win rate against M27 on many 5km maps, but is outclassed on 10km and larger maps. I want to see if I can improve it so that it is able to be competitive against M27 at least until the late T2 or early T3 stage on a map like open palms (M28 will suffer around this time due to no TMD logic or logic for sending transports to plateaus; however it cant even get to that point most of the time currently). ● ● Added a very high MAA builder for low levels of MAA if an enemy air unit is detected. ACU will now try and build a 3rd or 4th land factory if it is still in the core land zone and has some mass stored. 2.20) TMD, SMD and land experimentals 2.20.1) TMD Tracking units that want TMD coverage ● Oriignally I was thinking of having similar logic to M27, but recording units against land zones. ● In the end I went for a rewritten approach that while similar relies much more on callbacks. ● In summary, whenever a TML or TMD is detected or destroyed, then I’ll look for all units in range and update whether or not they want a TMD building to protect them. ● I’ll base the decision on whether they want a TMD on if they have as many TMD as there are TML in range of them. ● Where they want a TMD, then this gets recorded in a table for the land zone they’re in ● When the unit dies, it then gets removed from that land zone. ● This way, in theory I can just check for my engineer builder whether a land zone has units wanting TMD, without needing to do any rechecking of this table, so while the logic for identifying units wanting TMD is fairly heavy duty it should only be run at certain specific times. ● A TMD will only be considered as covering a unit if it covers it from all enemy TML in range of that unit. Building TMD The closest TML to the land zone should be selected, along with the closest unit wanting TMD to that TML. The starting point for the TMD to be built should then be a position 10 towards the closest TML from the closest unit wanting TMD (6 for Aeon TMD), with a build location near here being chosen. ● If the TMD ends up being built too far away from the unit, then a flag should be set that the unit no longer wants any more TMD (to reduce the risk we build infinite TMD in response to an enemy TML) 2.20.2) SMD ● Track enemy SML in a global table for the team, along with other significant enemy threats like land experimentals 47 ● ● ● Land zone valuation calculation – split into two parts, one which values the M28 buildings in the LZ, and the other which gives the value for everything else. If land zone value is >=12k (more for non-core LZs) then want an SMD for it If the land zone contains an SMD which isn’t loaded, then assist it o As part of this I copy over the M27 logic to pause SMD once it has 2 missiles loaded, and to only assist it for the first missile and then clear all engineers (although the latter is much easier to do now that I have order tracking in place, as I don’t need M27’s more complicated tracking of what engineers are doing what action to find the engineers to clear). 2.20.3) Land experimentals For now I want some basic logic for M28 to build land experimentals, mainly for if the enemy has a large firebase or an experimental of their own, and for now I’ll have the experimentals use the default logic (partly to highlight the flaws in the core logic, and partly because I’m feeling lazy): ● ● ● When a T3 direct or indirect fire unit is built, if the lifetime count is >=30 then flag that we should consider experimentals. Build an experimental if the flag for lots of T3 is true and we have no experimentals being built by our team or we have at least 8k mass stored +8k per no. of experimentals being built by our team, and our team mass income is at least 7 per tick. Also build if our team mass income is more than 16 + (30 * no. of experimentals being built by our team) When an experimental is being built, then don’t build units from a land factory for non-adjacent LZ threats if we have low mass. Tracking under construction experimentals ● The simplest approach would be to track when an experimental starts construction. However, this has the drawback that I could have 4 M28 AI each decide to start their own experimental at a similar time because none of the others has started. ● The alternative which is more complicated is to track the build power already assigned to build an experimental; this has the drawback if the engineers try to build somewhere that will take a long time to start construction (an issue M27 struggled with) but I’m hoping M28’s pre-identified build locations will reduce this risk to some extent. ● One approach to tracking could be: o When engineers are assigned an order to build an experimental or repair an experimental, record the engineer in the main team table, and flag that it is reecorded in such a table. o When an engineer has its orders cleared, if the flag is active then check for it in the team table and remove its entry. o When checking whether to build an experimental, check for: ▪ If we already have any engineers assigned to build it in the current land zone (apply lower thresholds if so); and ▪ The number of other land zones (rather than engineers) with orders to build an experimental. Other experimental related changes ● Units whose shield is as much as 80% of their health should retreat when their shield is low 2.20.4) Misc changes 48 ● ● ● ● T1 arti wont be built by lower tech land factories if we already have 60 When considering a firebase threat, it should be reduced by any friendly units between the current land zone and the firebase land zone. Increased the MAA allocation wanted if the enemy has air to ground threat and removed the requirement for there to be no enemy units. Increased the threshold for reclaiming T2 PGens to 600 energy per player After making the above changes, M28 was able to beat M27 on astro craters as Aeon (in 26m22), doubling the pool of maps where it has a reasonable chance (previously just Theta Passage). ● ● ● MAA, mobile shields and mobile stealth should be built even if trying to conserve mass for an experimental Increased the prioritisation of build locations by distance to reduce the risk that we pick a far away hydro location just because the nearby one has reclaim on it. Ignored the eco threshold for ACU to retreat if the enemy doesn’t have T3 2.21) Shielding from arti and novax and SAM creep 2.21.1) Shielding to defend from T3 arti and novax M27’s approach M27’s approach can be summarised as follows: ● ● When construction is started on a unit, if it is a high value unit it is flagged as wanting shielding by recording in a table against the aiBrain. Every time it considers what orders to give engineers, it refreshes this table, removing dead units and those that are now covered by a shield. I want to instead use a more callback and localised approach for M28 to hopefully improve performance: Tracking units wanting shielding ● Whenever construction is started on a unit, as per M27 decide if it is to be shielded based on its mass cost. ● Use a higher threshold if the enemy doesn’t have novax or T3 arti o As aprt of this, track if the enemy has T3 arti/novax/experimental arti as part of adding such units to the big threats table. ● If the unit does want shielding, then check if it is near a shield already and if so then record that shield as protecting it. ● When novax or T3 arti is first detected, then go through every unit and reassess if it should be flagged as wanting shielding. ● When deciding to shield a unit, store it in a table for that team’s land zone, and flag against the unit that it wants shielding. ● When a unit dies, if it was flagged as wanting shielding, then remove it from that team’s land zone table. ● When a shield starts construction, cycle through all units in the land zone flagged as wanting shielding and update to note they no longer want shielding. o Also update the shield to record the units that it is covering. ● When a fixed shield dies, cycle through all units recorded against it as being shielded, and if they are still valid then check if they have another shield that is covering them. If not, then include them in the table of units wanting shielding. ● (See below re tracking units where we cant find a valid location to build a shield) 49 Deciding whether to build a fixed shield ● If a LZ has units wanting shielding, then assign an action to build shields. ● Require T3 engineers if the enemy has T3 arti/novax, or the value is at least 14k mass. ● When processing the action to build a shield: o Cycle through each unit and look for somewhere nearby to build where the shield will provide coverage. o If there are no valid build locations close enough, then flag that the shield range for which the unit can’t be shielded (in case in the future I want to introduce logic to allow a teammate’s seraphim shields to be prioritised) 2.21.2) Shield assist logic This is largely a copy of the M27 logic with slight adjustments to work with the land zone approach: ● ● ● Every 10 seconds, the list of priority shields will be checked for the land zone by checking any fixed T3 shields in the land zone. Where there are any such shields, those covering a value of at least 25k (with this value made higher for SMD and nukes) will be treated as a priority shield (with an adjustment to reduce the risk that two shields covering the same unit both are considered priority units). Engineers then get assigned to the priority shield in the land zone with the least build power assisting it. Related changes ● Added a new engineer builder of higher priority than combat units for adjacent land zones, for where we are defending against T3 arti, or have some mass stored, and have multiple land factories, for which <25% are building engineers. 2.21.3) SAM creep ● ● ● If the enemy has an air to ground threat in the LZ, then SAMs/structure AA should be built up to the value of the enemy air to ground threat. AA should also be built pre-emptively based on the overall enemy air to ground threat. High value non-core zones should use similar logic, but only once we have T3 (compared to core LZs) 2.22) Island logic and engineer build location adjustments 2.22.1) Record islands ● ● ● Once all land zones have been recorded, cycle through each plateau and then each land zone; Check the island reference of the land zone based on the amphibious pathing reference for the land zone midpoint Record the following information for each island and land zone: o Against each land zone: ▪ The island number of that land zone ▪ The pathing information to each other island in the same plateau, similar to the details of pathing to other land zone, i.e. a table, ordered from the closest island to the furthest island, which records the nearest land zone in the island to the current land zone, along with the pathing of an amphibious 50 ● unit to get to the nearest land zone in the target island, and the travel distance o Against the plateau-island table: Each land zone in the island For performance reasons I’ll only record this information for islands with mexes in them, and also record the number of mexes per island in case I want the information in the future. 2.22.2) Initial logic for islands ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● Engineers – if have nearby (within 60% of the distance to the enemy base) islands that want engineers, and don’t have an enemy threat at that island, then send engineer there. Cap the number of engineers to send, to lower of amount wanted by the closest LZ, and BP of 20 – BP of all engineers traveling to the island If an island has at least 3 mexes, then build a land factory. Build a land factory for every 2 mexes above 3, to a max of 4 land factories, in an expansionbase. As part of the logic for getting the BP wanted to move to another land zone – if have flagged that we are using island pathing, then: o Check if the closest friendly base is on the same island o if it isn’t then cycle through every land zone on the current island, to see if any are flagged as a core base, and to get the total BP wanted, based on the individual LZ BP wanted, less any excess BP assigned to a land zone o when deciding the BP wanted for a LZ for the engineer logic, if have flagged to use island pathing then check this other variable to decide whether to send an engineer. To help with decision making, I’ll now have both a ‘core base’ flag for land zones, and a a ‘core expansion’ flag – the idea being the core expansion will use similar logic to the minor land zones, but will also build land factories, while those land factories will also have a slightly different to normal decision making for what to build. Land factories should no longer build skirmishers or DF combat units to keep up numbers/proportions if they cant path to the enemy base by land. Adjusted the MAA limit for land factores on a core expansion (so there’s still a limit but it’s slightly higher amount than for a core base land factory). Amphibious combat unit management – if no LZs (in the same island) that want DF support, check if any islands that want support and if so send amphibious and hover units there. Slightly reduced the amount of engineers to be built at a non-core base land zone. Factory builder (normal) – check for any islands with a travel distance within the same threshold as for combat units that have enemies on them, and if so then get amphibious combat units. When sending units to a nearby islan,d it should get flagged as a beachhead – units arriving there should then check for nearby units and lower the threat requirements to attack, to make it less likely they arrive then turn around and retreat immediately (due to no friendly land zone units). Land zones will no longer throw up an error at being unable to path to an ‘adjacent’ land zone if it’s on a different plateau. Rally points should be checked to see if they are on the same island, if there are none, then the current land zone should be treated as a rally point (i.e. units don’t retreat from an island). Core expansion land zones should be considered rally points. 51 ● When recording the midpoint of a land zone, I realised the flaw with my current approach was it could result in a midpoint that wasn’t pathable using the base ‘NavUtils’ functionality (i.e. I was relying on backup logic to adjust it), which would then cause issues when trying to decide if a nearby land zone was pathable on map creation. I’ll therefore move the midpoint of a land zone to somewhere that will return as pathable, in the same island, using NavUtils, which should produce more consistent results. This will be done first by starting with the midpoint and moving outwards up to 50 segments to find somewhere pathable, or trying the first pathable segment in the land zone (if this fails), or reverting to the previous default of the nearest mex otherwise. Other misc changes made ● ● Lowered the net mass requirement where we have at least 5k mass stored to be based on a percentage of the total mass stored if lower (as there were cases where M28 had 20k+ mass stored, and thought it didn’t have the eco to upgrade a mex as its income was -200 mass per second). Engineers shouldn’t try and move in range of construction if there’s a building blocking that location (but should just be given the construction order) 2.22.3) Build location blacklist I encountered an issue where my engineers wanted to build a T3 pgen, but the location they chose while valid was blocked by MAA who remained at that position (as there were no enemy air units), meaning the T3 pgen never got built. While I could change where the MAA move to (and intend to at some point), I first want to have logic to cope with this scenario as I expect there will be other scenarios in the future where a similar issue arises. For now I’ll just consider adding blacklisted locations for those near the midpoint of a land zone (given the midpoint is often used by units as a rally point), but at least if the functionality is in place I can expand this in the future. I’ll track blacklisted locations via a table attached to the land zone, listing each location and the radius, along with the ‘type’ of blacklist, as I also want to build in functionality to reserve a location to build on for potential future functionality (e.g. either for T3 arti, or just to have a location I can constantly build experimentals at). ● ● ● ● When an order is given to build at a location, and the engineer is the primary engineer, start a thread to monitor the location and the primary engineer assigned to it. Every 10s, check if the primary engineer is still trying to build at that location (i.e. its last order), and its unit state isnt building (otherwise abort); if so, then check how far away the engineer is, and wait until the engineer is within 30 of the build location After 45s of the engineer being within 30 of the build location, check if the build location is still valid, and the primary engineer is still trying to build the building at that location (i.e. its last order) without a unit state of building/repair. If the engineer fails this test, then check if there are any mobile units in the build area (either non-engineer mobile units, or engineer units that aren’t on our M28team or aren’t owned by M28AI); if there aren’t, then continue with this check every 15s for another 45s before going to the next step. If there are mobile units then move to the next step. 52 ● Need to factor in units being paused impacting things – e.g. if unit is flagged as having been paused, then wait 10s. Recording a blacklisted location ● Clear the engineer that is trying to build at a blacklisted location, and any assisting engineers. ● Add the blacklisted location to the table of locations for that land zone. ● Cycle through every recorded ‘valid’ location for the land zone and check their distance to the blacklisted location, and if they are too close then remove them as no longer being valid. Adjusting build locations for blacklisted locations ● When getting locations that are valid to be built on for a land zone, check for blacklisted locations (for any reason) and don’t include if would be building partially on them. 2.22.4) Expanding the core land zone Although it’s not yet been an issue except for when a bug prevented M28 from identifying further buildable locations, I need logic for when I have run out of places to build in a core land zone, to reduce the risk very late game that M28 stops building anything (other than units from factories). For now the idea is simple: ● ● ● When searching for valid locations to build a unit, if none can be found, and we are at a core land zone, then flag the closest adjacent land zone (if we have any on the same island) as being a core land zone via an override. Check for this override when setting somewhere as a core land zone. To test this, I temporarily disabled a bugfix that was preventing M28 from searching for more land zones, and it resulted in M28 building some units outside its land zone. 2.23) Water zones 2.23.1) Pond creation Similarly to M27 I want to divide water zones into ponds, and record key information about each pond such as the number of mexes that can be hit from the pond, as well as determining the preferred place to build the naval factory. This will mostly be a copy of M27’s approach with some minor tweaks – I want to do this ahead of water zone creation, as I want water zones to be based around naval factories in addition to dividing the map into squares. At the same time, I’ll record every segment that is in a water location, and will do this as part of the land zone final logic step (which would check if a segment was in a land zone) to avoid taxing performance too much. 2.23.2) Water zone creation Once I have recorded all of the ‘ponds’ on a map, which segments are part of a pond, and where I want any M28 brains to consider locating a naval factory, I want to divide the map into water zones. ● ● Water zones are recorded against the pond table (a bit like land zones are recorded against the plateau table). Water zones use a unique numerical value across all ponds (so that in the future land zones could record adjacent waterzones as a single variable allowing the water zone to be identified). Will want a table to return the pond of a waterzoneref to help with this. 53 ● ● ● ● ● ● ● At first I was intending to have naval factory build locations constitute a water zone, and setup the code in a slightly convolueted manner to achieve this, but when drafting I changed my mind and decided to just jump to dividing the map into grids, i.e.: o Cycle through every 200 x and z position on the map; if it is in a pond, then record it as a water zone. o If it’s not in a pond, then check +/- 25, 50 and 75 X and Z to see if any of these values are water, and if so record the first such value as a water zone instead. When recording somewhere as a water zone, ignore it if it is within 75 of an existing naval factory desired location. Also treat the location recorded as the midpoint of the waterzone. Once have done this/all water zones have been identified, cycle through all of them simultaneously and assign segments to that water zone, stopping once every segment in the pond being considered has been assigned. When dividing the map into water zones, for small maps (5km) I’ll use smaller water zones so there are e.g. 4 water zone on a map like sludge (almost entirely naval) instead of 1 water zone. Record the midpoint, min and max segment X and Z values of each waterzone. Also record the min and max segment X and Z values of each ladn zone. Once every watersegment has been recorded and assigned a waterzone, go through each waterzone and record adjacent land segments. o Option 1 – Calculate hover path from the water zone to each land zone, and determine if it goes through any other water zone or land zone, and if not then record as being adjacent. Main problems are it means land zones that are adjacent but with a cliff don’t get recorded, and it will take a long time to do the calculations. o Option 2 – Do a line in 8 (or even more) directions that keeps going until it comes across another water zone or land zone. Might be faster (not sure) than option 1, but will fail to pickup on land zones inbetween 2 of the lines. Potential solution is to do 32 lines, but this might be even slower o Option 3 – as per 2 above, but with 8 lines and then if a land zone is encountered then any adjacent land zones to it are checked; if any of these are also adjacent to the water zone then land zones adjacent to them are checked. o Option 4 – Look in a square around the water zone, with the size of the square based on the water zone square root of recorded segments. ▪ Look at square root + 10 for the radius, if are still in the starting water zone (if going north, east, south, or west) then increase to +30 ▪ Cycle through every segment on the perimeter of this square, if it’s a land zone that hasn’t already been considered then move towards the water zone and see if it comes to the water zone first or encounters another land or water zone. Record a table of LZs considered this way. o Option 5 – Only consider land zones whose min+max X and Z are within 20 / segment size (to max of 3 segments) of the water zone’s min and max X; do a line from the land zone midpoint to the water zone midpoint, and check if have any other valid land zone or water zone that we reach before the target. Then record adjacent water zones/pathing between water zones o Option 1 – only including adjacent water zones - Cycle through each water zone in the same pond, if the min and max Z values come within 1 of overlapping, then check the pathing between them (navy pathing), and add to a table in order of navy pathfinding distance between them. 54 o Option 2 – include all water zones (think will want this so can use similar logic approach to with land zones) – cycle through every water zone, and calculate the navy travel distance to each other water zone (midpoint to midpoint), and then record against each one in order of which is the closest. ▪ ● ● The approach land zones take to reinforcement of combat units is to cycle through each land zone in order of distance up to a certain threshold, so I need to be able to cycle through each water zone in order of distance to the base water zone, which this should allow. Increase the water zone size on 20km+ size maps – have part of it based on map size with the current size the desired level for a 10km map (but don’t increase in proportion to map size, so e.g. an 80km might only be twice the size of a 10km map). Also record data on mexes in range of a water zone by dist and dd/if type similar to m27 pond logic? [TBC if will do this – left open to revisit once got some unit management logic in place] The results of the above water zone creation on Pelagial is shown below: 55 ● Require 5 segments of another water zone before treating a water zone as not being adjacent, to make sure that corner positions still get included as adjacent to another. 2.23.3) Managing units in a water zone Overview I want units to be assigned to either a land zone or to a naval zone. To the extent this causes issues, I can then address on a case by case basis (e.g. I expect one issue is a land zone sends units to attack another island, and they enter the water zone and get different orders). M27 would differentiate between surface combat units (e.g. frigates, hover tanks), anti-air units (cruisers), submarines, and ‘support’ units (stealth boats and shield boats) for most of its logic, along with a ‘bombardment’ mode where if it thinks it has won naval control it switches to trying to take out enemy land based threats. For M28 I expect I will want a similar approach, but more localised. I’ll want an additional category though, to cover amphibious units that are good on land but not in water (e.g. Bricks and percivals). 56 M28 handles logic for each unit type separately, so I’ll try that approach for now, splitting between the following categories: ● ● ● ● ● Anti-air o This will need logic where if there are no air threats, and it is a UEF or seraphim cruiser, then this unit is given orders to attack enemy structures. Hover and surface naval combat – this will include ‘bombardment’ type logic Underwater combat (excluding amphibious units with a weak anti-naval attack) Support units (shields, stealth) Engineers General management For surface and underwater combat the approach will be similar to M27 – attack if we outrange the enemy, or (if we don’t outrange them) attack if we have notably more threat than them or are in a water zone containing a naval factory. Similarly to M28’s land zone logic, enemy threat should be based on ‘adjacent’ water zones, and handled on a team-wide basis, with a team subtable for each water zone recording relevant values: ● ● ● ● ● When assigning units to a land zone or pond, have them assigned to a water zone and then the water zone units refreshed the same way land zone units are. Cycle through every water zone every second – refer to the total number of water zones in the game, and come up with the number of water zones to assess each tick. Record enemy threat values similarly to land zones, but just in aggregate (don’t worry about threat by range), for just the land zone specifically. o Combine structure threat with mobile threat o Keep air threat tracking the same o For combat threat will have anti-surface threat, and range; anti-navy threat, and range; and submersible threat (some units getting included in multiple categories) Filter friendly units into the above 5 categories. Prepare subfunctions for each of the 5 categories above. Units moving between water and land zones Initially I want the water zone setup to work well for land units without building any naval units (and then check for naval units). Testing on maps, currently the issue is that e.g. on four-corners as UEF M27 will build percivals, send them to the enemy island, and as soon as they step foot on the island they realise they have too little threat and retreat. I therefore need the percivals to group in the water until they reach critical mass and attack, rather than retreat all the way back to the base island. Land zone – summary of current logic approach Reviewing how my land zones handle this (i.e. getting units to retreat and then build up in strength): ● If the unit is to be managed by a land zone, the following are recorded: oUnit[refiCurrentAssignmentValue] = iCurLZValue oUnit[refiCurrentAssignmentPlateauAndLZ] = {iPlateau, iLandZone} oUnit[refiTimeOfLastAssignment] = GetGameTimeSeconds() 57 ● ● ● The unit is only considered for assignment (and the above recorded) if the current land zone value is greater than it’s assigned value, or it was previously assigned to this land zone, or it has been 5s since it was last assigned. Combat units in adjacent land zones are also considered if that land zone’s value is less than the current land zone’s value, and has a negligible enemy threat in it If the enemy has units in the current LZ or an adjacent LZ, then a check of enemy ranges and threat is done; if we are outranged and the enemy has a greater threat, then units should retreat. o When retreating units, only units from the current land zone will be retreated; i.e. adjacent land zone units (to have been used if we weren’t retreating) shouldn’t be told to retreat. Linking with water zone logic ● Ideally, I want a similar approach to my water zones. The difficulty is a water zone doesn’t have much value since it’s unlikely to have mexes or bases to defend, so wouldn’t be expected to override the order from a land zone unit. ● I can think of a couple of options that might resolve this: o 1) If a unit is to retreat due to lack of threat, set a flag on it indicating it is retreating, and/or record the plateau and land zone that it is retreating to, and/or the plateau and land zone that gave the retreat order. This way water zones can take control of any retreating units from another land zone and give them new orders based on if they want to consolidate, or retreat. ▪ o This has the downside of remembering to always record if a unit is retreating, which is prone to error (as well as needing to update every unit every time an order is given, to indicate if it is retreating or not). 2) If the unit has been given a move order, and was last given orders by a plateau-land zone, get the island reference of the move order, and compare to the island reference of the plateau and land zone giving the order. Where they are in a different island, then this suggests the unit is either advancing or retreating. Either way, the unit could become assigned to the water zone’s logic, which can then better decide what to do with the unit. ▪ Although not perfect, this feels a better approach since I only need to be considering it when a unit is in a water zone (reducing the CPU impact), and I don’t need to record extra data for each unit. The main flaw is if I was to try and issue orders other than move orders for a unit to travel somewhere, but then it could always be expanded to cover these (e.g. an attack-move order could be factored in to the logic if needed). I’ll therefore look to do the following for my water zone logic when cycling through each unit: ● In addition to the check based on water zone value vs current assigned value, if the unit has a last order that is a move order, the unit has an assigned plateau and land zone, then check the island of its assigned plateau+land zone, and see if it is different to the island of the unit’s move order destination. If it is different, then treat the unit as available to the water zone. o Consider sending the following units to a land zone from a water zone as part of the main water zone combat unit manager: 58 ▪ Amphibious units (I don’t want fatboys or even wagners trying to fight as anti-sub units) ▪ Hover combat units where the enemy has no combat units in the current or adjacent water zone ▪ o Only consider units above where they are in the current water zone (not an adjacent water zone) Once a table is generated of all such units, look for the nearest land zone with enemy units in it that is in the same island, and consider sending the units there To generate the list of nearest land zone needing support: ● ● ● ● ● ● One option is to pre-record the land zone distances like what do with land zones where each water zone records each land zone in the same plateau based on hover pathing distance (rather than land pathing distance), so can then cycle through from closest to furthest. However, this could take ages on an 80km map with lots of water and land zones. Another is to calculate ‘on the fly’ – e.g. have a list of land zones wanting support, and see which is closest, but could end up with lots of LZs wanting support. A third is to cycle through water zones in order of distance (which his already calculated/recorded), and check if they have any adjacent land zones that need support. Then, as a backup, if there are no land zones needing support, units should get sent to the land zone adjacent to a water zone that is on the same island as the closest enemy base to the original water zone. o This requires recording the closest enemy base, similar to what is done for land zones. Land zones do this by checking the closest friendly brain start position to a position, and getting the primary enemy base for that brain. The land zone logic uses the function RecordClosestAllyAndEnemyBaseForEachLandZone to do this, which is called as part of team initialisation for now; it turns out I’d already copied this over though: RecordClosestAllyAndEnemyBaseForEachWaterZone o Ill therefore do this third approach both since it requires far less work, and Im worried M28 already takes far too long to start a game and this could drastically increase that time (while it should be relatively rare that land units are traveling through water – i.e. it should hopefully only affect a handful of zones at any point in time). Once the land zone target is decided on: o If the land zone is a core base, adjacent to a core base, or has friendly structures, then send our units to help. o If we have hover units that outrange the enemy forces at that island, then send our units to the island. o For all other units, only send them if they have x% more threat (based on the land zone retreat %), i.e. based on below: (iOurCombatThreat > iEnemyCombatThreat * 1.4 or (iOurCombatThreat > iEnemyCombatThreat and ((iFirebaseThreatAdjust > 0 and bHaveSignificantCombatCloserToFirebase) or tLZTeamData[M28Map.subrefLZTValue] > iOurCombatThreat * 0.5)) or (tLZTeamData[M28Map.subrefLZbCoreBase] and iOurCombatThreat > iEnemyCombatThreat * 0.8)) 59 I’ll use a custom function for this for the land zone, so I can make use of same function for this check (so if I change it, it will affect both places) ● If we don’t have enough threat, then choose whether to consolidate the units at the waterzone midpoint, or to retreat: o If we have an amphibious unit, then consolidate at waterzone midpoint o If we have any hover units, then: ▪ Get the nearest enemy unit in the target land zone ▪ Get the best enemy range in the target land zone ▪ Comapre the distance between the enemy unit and the waterzone midpoint (straightline) ▪ ● If the distance is more than 20 over that unit’s range, then consolidate at the waterzone midpoint. ● If we don’t want to consolidate at the waterzone midpoint, then retreat the unit to the water zone rally point. When a unit is given a land zone order, clear any water zone assignment – use similar approach to water zone function RecordUnitAsReceivingWaterZoneAssignment Engineer assignment from water zones to other water zones and land zones ● Add logic for water zones to send engineers in a water zone to an adjacent land zone: o Cycle through each water zone o If wZ needs engineers, and has no enemies in it, send here o If the WZ is adjacent to a LZ that wants BP, send to the WZ (where it should then be told to go to the LZ if that LZ still needs the engineers) Have land units kite naval units ● A new flag will be set to indicate if a land zone has adjacent water zones with enemy combat units in them (so it can consider if any of them need to be avoided/kited). ● Updated various logic which makes use of the flag for if a land zone has enemies in the land zone or an adjacent land zone, to also consider checking the adjacent water zone. ● When looking for enemies to decide whwat to do at a land zone, enemy direct fire units in adjacent water zones should be taken into account as the ‘nearest enemy’ (which impacts where units try to move to or run from). Other changes ● When looking for a rally point for a water zone, if there is no ‘core’ water zone, then search through water zones that are adjacent to land zones and pick the one closest to a land zone rally point for the same plateau. ● When looking for a land zone override, if no land zone can be found but the unit is amphibious/hover and the location is pathable by amphibious/hover, then no override should be recorded. ● Land zone unit management will now consider the nearest amphibious rally point in addition to the nearest land baesd rally point. Amphibious/hover units will then retreat to the amphibious rally point if no land based rally points are available (i.e. this means hover tanks that reach an enemy island and decide they want to retreat should now retreat from the island instead of running to the middle of the land zone on that island). 60 ● ● ● ● ● ● ● ● ● A land zoneshould have its ‘expansion’ flag cleared if there are no longer any units there (so e.g. if engineers try building a land factory and are killed, units wont rally to the midpoint of the island). If the ACU has no land zones to go to (on the same island) it should consider nearby islands with enemies or unclaimed mexes. Limit number of factories to be built if we are <T3 and the nearest enemy base is on a different island – I’ll now massively increase the mass per factory ratios where the island is different and less than 35% mass is stored (to help ensure enough mass for ecoing). If enemy has a sub that is detected, then disable the move to other island logic, and also have the ACU retreat if it is in a differnet island to the nearest base or is underwater. o I later add an exception to this so if the ACU has 3 upgrades (so likely a shield/cloak/nano) then it will still consider going to places closer to its base than the enemy base. If a unit has no antinavy attack, consider attacking the nearest surface enemy unit if there is one; if there isn’t, then consider assigning the unit to a different water zone (the same as if there is no enemy). If a unit has no DF attack but has an antinavy attack, consider attacking the nearest non-hover enemy unit. If there isn’t one, then consider assigning the unit to a different water zone (the same as if there is no enemy). When looking for a land zone to support from a water zone, a check is done if the units contain amphibious units, to make sure they can path there, given amphibious units have more restrictive pathing than hover units. ACU should now get the amphibious rally point when looking to kite, so it doesn’t e.g. charge into enemy T1 PD on an island. When considering the nearest enemy naval unit to focus on, units with no antinavy attack should only consider units that aren’t underwater. Land scouts ● Patrol zones for water zones use largely the same logic/approach as land zones, but slightly increased range/distance. ● Water zone midpoints should be moved further into the water zone if the initial midpoint isn’t on land (so it’s not on the beach/shore). ● Land zones: o After checking if adjacent land zones need scouts, adjacent waterzones should be checked o If a scout is assigned to a water zone, and is being considered by a land zone, it should be sent to the WZ it is traveling to. MAA Since land zones only record adjacent water zones, I want any land zone with an initial surplus of MAA to check if any of them are hover MAA, and if so consider assigning the hover MAA to an adjacent water zone. Rather than use a separate function I’ll adapt the existing land zone logic to handle water zones, although after rewriting it it ended up largely being a completely separate function (so probably would have been easier to just do via a copy). 2.23.4) Mexes 61 Similar to land zones, I want each water zone to have recorded any (underwater) mexes in it, along with if these are available, so I can decide whether to send engineers to claim them. The first step is adding mexes to water zone – since I’m not using mex locations for water zone midpoint logic/positioning or assigning segments to water zones (in contrast to land zones) this is a bit simpler so I’ll just loop through every mex already assigned to a pond (from the copy of M27 logic for ponds), and assign each mex to a water zone, and use a similar approach to the land logic for deciding if a mex is available to build on. I also adjust the logic for deciding if a mex is safe to upgrade to factor in if it is underwater and there are enemies in the current or adjacent water zone. Mex events (death and construction) Previously logic tracking if a mex was built or destroyed assumed the mexes would be on land, so the code needed adjusting to also handle if the mex was on water. Engineer orders ● =-Water zones should request engineers if they have mexes on them that are unbuilt. ● Engineers should be treated as available for a water zone if they are moving to that water zone and are now in the water zone, or they were running away but their current water zone has enough allied threat to deal with enemy units (or has no enemy naval threat). ● I also want engineers to actively try and reclaim enemy underwater mexes (since not many units can easily target mexes) where the enemy doesn’t have a combat threat in the water zone. ● Similarly to land zones, I also make sure part-built mees are tracked so they should continue construction if they are abandoned part-way through. 2.23.5) Unrelated changes ● ● While testing the water zone changes, I noticed MML fighting for an island wouldn’t fire at a scouted enemy PD, and was able to reproduce this error as a human (i.e. if the MML was moving or attack-moving it wouldn’t fire, despite the PD being revealed and in-range, until it got really close). o I’ve therefore adjusted the indirect fire land attack logic so if the closest enemy structure to the midpoint is within range of the unit then it will issue an attack on it. o Note this relates to a bug with FAF that Jip will be fixing in a later update. In one game an ACU started an upgrade in range of an enemy ravage, so I added very simplistic ‘cancel upgrade’ logic as a placeholder (I’ll likely incorporate M27’s logic at a later point), which compares the ACU’s health and upgrade progress to decide whether to cancel. 2.24) Air management 2.24.1) Planning/general approach ● ● M27 takes an aiBrain focused approach to air which works much better than I’d have expected. However, I want to have M28 factor in information from land and water zones in order to choose whether to attack somewhere with air or to hold off and let land forces attack, something which M27 can’t do very well. I also want the AirAA logic to better factor in if it is safe to support an area by targeting air units – for example, M27 will sometimes send anti-air units to attack enemy units by the enemy base, and/or will fly fighters over enemy MAA or cruisers that have dropped out of radar range, suffering heavy losses. 62 ● ● ● I also want to primarily use air defensively, since after watching M27 it’s most effective use of air, outside of the first T1 or first T3 bomber, is overwhelming an attacking enemy experimental or ground force with large numbers. The idea will be for M28 to have logic specific to the following scenarios: o T1 bomber engi hunter (similar to M27) – for the first 1-3 T1 bombers (potential future todo action) o T3 strat mex hunter (similar to M27) – only intended for the first 2 strats, with strats not built after this (potential future todo action). o Gunship groups as the primary air to ground solution, which are also used offensively where there’s sufficient AA support (whether by ground or by air) to target land or water zones with insufficient AA defence. o T2 bombers (plus any other T1-T3 bombers) used defensively where enemy has a large AA threat, in suicide missions (as a last resort) – i.e. this is M27’s main focus, whereas I want it to be much less of a focus for M28 with the main focus being gunships (potential future todo action). o T4 bomber – Custom logic specific to the bomber to target enemy units, and to make use of SAM creep to support it where lacking AA support (potential future todo action). A key issue with all of this will be how to manage air units/split them into groups: o For AirAA units, these should ideally be kept together to avoid a smaller enemy air force being able to pick them apart one by one. o However, on some maps if the M28 players are far apart the air force could risk being caught in the middle by enemy ground AA (e.g. I saw one game with M27 where the enemy had cruisers inbetween 2 M27 base, and the air force would respond to threats for both bases and get wiped out). o Therefore I’ll want to manage AirAA units on an ‘Air subteam’ basis (where at the start of the map M28 players are grouped together based on proximity, and air is handled as though it belongs to a separate team for each subteam). o For air to ground units, bombers for the T1 and T3 engi/mex logic can be used on a ‘per team’ rather than subteam basis, since I’m only planning on building a couple of them. o For other bombers, these are best managed on an air subteam basis, so all of the M28 players nearby can assist in an emergency defence with bombers. o For gunships, I probably want these managed on an air-wide basis to avoid 2 gunship groups targeting the same location. Instead, gunships will be managed by size, so once a gunship group reaches say >20 units, a new group is formed to manage the spare ones This means I’ll need to be able to determine air rally points on both a team and subteam basis, so some units (gunships, T3 bombers) can go to the nearest team-wide air rally point, while others (e.g. ASFs) can go to the nearest subteam rally point. Targeting enemy units ● M27 makes use of strike damage for air to ground forces, and mass value for ASFs/airaa which works fairly well. ● Meanwhile gunships wouldn’t work on strike damage but instead would just target vulnerable enemy locations. 63 ● ● ● Air experimentals should consider attacking ground forces based on zone assessment, and naval forces based on distance to any air subteam’s naval fac (i.e. could be on the same air subteam but different naval subteam) It’s possible I could make the AirAA logic work based on strike damage as well, but I’m not sure whether or not it would be better, and it would require some sandbox testing, so for now I’ll just go with mass values. However, I’m hopeful that I can improve the AirAA logic so that a greater mass value is assigned where there aren’t other AirAA targets, so that the air force moves as a ‘ball’ rather than a ‘stream’ of units, with the ball then adjusting on the fly. Ideally want to come up with a system where airAA units are managed on a per tick basis and spread out over each tick, to spread the load, but not sure this will be possible. Also a question over whether want to go with the M27 appraoch of assigning a target and then not changing that target, or always reassessing which fighter should target which unit. A hybrid option would be to only assess air units that are ‘surplus’ to targeting requirements – e.g. default is to sign 3xmass value of airaa against a target; could then go up to 10x if have idle air units, and reassign the 4th-10thx value if new targets become visible? o A variation could be to separate logic for the different types into different ticks, so AirAA has 1 tick, air to ground has 1, torpedo bombers has 1, transports has 1, or even to split airaa into 2 ticks, 1 for attack logic, 1 for ‘move to rally point’ logic, but I doubt this would make much difference since the main issue will be a large air to air fight. o Another alternative could be to spread the reissuing of orders to asf over a second, i.e. the target gets assigned in the initial tick, and then the move order gets refreshed throughout the tick. However this risks a unit having its orders cleared and restated 1 tick, and then 1 tick later having the order given again, with this potentially reducing the amount that the air units fire. o A third alternative is to do things like target reassessment on a tick by tick basis, which would spread the load for some parts of the calculation – I think this approach would be best. Sandbox testing of air fight ● ● ● Trying to micro an asf to ‘slow down’ so it can fire more often produced very poor results in a 1v1 scenario, with the micro’d asf ending up hardly firing at all while it was killed by the other asf, therefore I’m not sure spending a long time on this approach would be worthwhile (although the results would probably be better against large air groups). However, one issue with the ‘attack order’ approach is that asfs don’t fire at other units they pass near when on their way to the attack order target, so move orders instead of attack orders would be better, except they would have the downside of needing refreshing constantly which would create a greater CPU load. To properly determine which method is best, I’d probably want to do a 30 M28 asf vs 30 M27 asf battle a number of times to see which works, and even that wouldn’t be reliable since some approaches work best against specific other approaches, and human players will be using a ‘move ball’ approach rather than M27’s spread attack type approach. 2.24.2) AirAA logic in more detail Idle airAA units ● Manage AirAA on an air subteam basis 64 ● Have airforce wait at either the nearest rally point, or (if have high priority targets to protect) the priority target nearest the enemy base that is nearest the air subteam rally point, when idle. o When escorting a high priority target, get the nearest air rally point to that land target, and then travel in a straight line from that air rally point to the target, until reach a land zone or water zone that has significant enemy ground to air threat, and pick the previous land or water zone as the staging point. Targeting enemy units and treating air units as available ● If an airAA unit has no targets: o If it is low health or fuel, send to nearest air staging (or to the air rally point otherwise) o Otherwise, make available for targeting, and send any remaining units without targets to the air rally point ● If an airAA unit has a target: o Check if still want it as a target, if not then abort – unlike M27, I want to experiment with doing this regardless of how close the unit is (my concern with M27 was this would allow human players to bait its air force, but the downside is M27 often proceeds with air fights that it would lose, so I want to see how well or badly it works if the air units flee when they’ve lost) ▪ Means need some way of tracking if a unit is a current target or not. One option is to record the time that it was last a target, and where this is more than 2s to treat it as not being a target. ▪ May also want to use a distance based measure, e.g. if prioritising targets based on distance to a location, allow to remain targeting a unit that gets up to say 20 further from this distance (to avoid considering a large group of enemy asf, targeting one of them that then moves further into the ball, leading us to think it’s not a target as the logic tries targeting the asfs on the outer edge of the ball) ▪ o threat, but do the reassessment on a tick by tick basis to spread the load. Test sending a move order to the target (and refreshing this) vs sending an attack order to the target ▪ ● Alternatively could just manually assess each target for if it has significant air In the future could consider whether could do microing to make air units fire for a greater % of the chance? E.g. once in range of the enemy and facing it, calculate based on our facing direction, enemy facing direction, and our and enemy speed, whether we want to slow down in order to fire more. Would only want to do if handling <75 airAA units in a single cycle – see above sandbox notes where I’m not sure this would work. Ultimately the approach I want to try and take with target selection is that each asf ends up targeting the nearest enemy air unit to it, until a certain threshold is reached, at which point the next nearest enemy air unit gets targeted, etc., with the possibility of a tierd threshold system with say x3 mass value assigned to every enemy air unit, and then spare air units go for the nearest units again up to x6 mass value. 65 Target selection ● I need to decide how targets will be selected/prioritised. The best approach is probably going to be a distance based metric, but this raises the question on what I use as the base point for the distance – the nearest air rally point (more accurate, but risks strange results as and when the air rally point changes); or an ‘average start point’ for the air subteam which has the benefit of not moving, but the downside of treating 2 air units that are far apart from each other on opposite sides of the map as similar priority if they’re similar distance to this average start point. A third option is to base it on the ‘air support location’ (which will sometimes be the rally point, and sometimes be near to a unit that we are trying to protect. ● A fourth option is to order all land and water zones based on proximity to a friendly base, and then cycle through these in that order, meaning the recording only needs to be done once. ● A variation of all of these would be to first check priority targets to defend and units near to the support point or the air rally point, and then only consider other targets after dealing with these. ● I think the 3rd or 4th option would be best – the 3rd option gives the best likelihood of my air force remaining concentrated, while the 4th option is much easier to achieve (as it avoids needing to reorder the land and water zones every second) and should also therefore provide a slightly more stable targeting result. The 4th option would be combined with the variation for looking at priority targets. ● For performance reasons I want to avoid searching too far out for targets if I don’t have the AirAA units to consider the targets. One option would be to have a distance threshold for land and water zone midpoints from the midpoint of the support point land/water zone, based on the higher of the following: o Furthest M28 airaa unit from the support point + 110 o If we had idle airAA units last cycle, then 110 + the previous distance threshold o 110 + Furthest target for AirAA that has assigned units to it ● An alternative would be to instead assign AirAA to enemy targets as and when they are encountered, and stop the cycle once all AirAA units have been assigned. o This alternative requires some logic that will for any given support location work out the land and air zones near it, based on a straight line distance. o One option for this is to prepare a table of such logic ‘on the fly’, since it will mean using straight line distances for potentially hundreds of land zones on large maps which would be time consuming to record at the start of the game for every possible land and water zone. ▪ E.g. the start of the game could just record this for each start position, so there’s a startpoing recorded point. ▪ Then, if the support position changes, the calculations could be done over the next second (i.e. spread out each land zone and water zone over 10 ticks), and once the calculations have been completed, this new location could be used as the new support location; however this wouldn’t work when escorting a fast unit like a strategic bomber which might move land/water zones by the time the calcualtions are done. 66 ▪ However it might still be possible to fit the calculations inside 1 tick, with the advantage that performance should improve as the game goes on and more locations have the support logic calculated. ▪ As part of these calculations I want to record the angle of a location to the support point, so that I can potentially factor in angle and distance when determining if a land/water zone’s AA should be taken into account for determining a safe path to a target. AirAA logic summary from above: ● Each cycle determine the air rally point: o Go through start positions on the air subteam, and factor in friendly ground AA and enemy ground AA to pick the ‘best’ location ● Each cycle, get the ‘support location’: o If have any priority units, then get the closest priority unit to an enemy base (by getting the land/water zone of each priority unit, and checking the distance to the nearest enemy base from this midpoint) ▪ o determine the nearest land or water zone to the particular position, and record this in a table (similar to the plateau and land zone override) Starting from the closest friendly base, and then going through each land/water zone on a straight line basis, check if there is an adjacent enemy groundAA threat, and keep going until reach a land/water zone with an adjacent threat, at which point will move ‘back’ one. ▪ ● ● ● If the unit to support isn’t on a land or water zone, then run logic to If the base that start from has an adjacent enemy groundAA threat, then just use the air rally point. Get the AirAA units that are available (i.e. not attached/already refueling, and not going for refuelling) for the air subteam. o Bombers near a target they are attacking, and airaa units near a target that has enemy air in it, should not be treated as available for refuelling. First check for any enemy air to ground threats around a priority unit (i.e. in the current or adjacent land/water zones) Once done this, if still have available AirAA units, cycle through each land and water zone recorded in order of distance per the above, and check if there are any enemy air units recorded against the land/water zone. o If there are, then assess if the air units should be targeted based on the enemy ground to air threat from there to the support location, along with the nearby enemy airaa threat (based on how far behind we are on air control and if we have friendly ground AA in the location) o Assign available AirAA units to these targets based on the closest airAA unit, with the AirAA unit being given a move order to the target While writing the above initially I held off doing any pre-recording of air paths to understand for sure the use case. I’ve included notes on the thought process for targeting enemies, determining ‘air paths’, and if an enemy is safe to target below. 2.24.3) Enemy targeting and air path threats 67 The following section contain rough notes I made when trying to figure out how to have AirAA units target enemy air without venturing near enemy SAMs/flak, and also having a small AirAA force not suicide into a large air force. Choice of enemy units to target – only include if: ● ● Is in the zone itself that are trying to protect; or Has no groundAA o i.e. have a flag for whether to check for groundAA when considering somewhere o will need to reconsider the true flags used for if we have considered somewhere, might need extra series of flags, i.e. ‘consideredifnoAA’ and ‘consideredregardlessofAA’ However, first need to add in logic that works out every land and water zone including adjacent ones that will pass by if going from the support zone point to the target, so can then quickly reference this when calculating if somewhere is safe? That way can do these calculations in a different tick to help spread the load. ● Considering potential memory requirements, if there are say up to 1k land and water zones combined, with an average path of 10 entries to get to the support zone, this would mean storing 10k data entries; assuming 10 pieces of information are stored for each entry, this would mean 100k data every time. Realistically would then struggle recording if the support zone moved around a lot in large team games. o One solution to this could be to limit the range on any support path calculation? And/or to ignore plateaus or land zones with a small number of entries? ▪ o o o 6 in size? An alternative solution is to only store information to the next nearest land or water zone to get to the support zone, and then use that information – that means information only gets stored once, and saves a lot on the calculations. i.e. each land or water zone would store a single table containing the plateau, land zone and water zone (with land being nil or water being nil depending on which it is) of the land/water zone that it will pass through on the way to the support zone. Would then need to calculate ‘on the fly’ the total list of land and water zones that will pass by (including adjacency) if going along that route – so less calculation overall, but a bit more of it happening in the airaa tick. However also a lot less data is stored. ▪ ● For example, ignore any plateau whose min and max XZ values are less than Could also probably refine further so we store the enemy AirAA and groundAA cumulative values along the path to the support rally point. One option – round the start x and z, and end x and z, which are based on the land/water zone midpoint of the support point and the location the target is in, and have a table with these 4 as keys, which returns a table of intermediary entries (i.e. excluding start and end) for the plateau, land zone, and water zone references along with a flag each time if it’s a water zone or land zone, for both the path, and any adjacent references, with this only including each location once (not multiple times)? That way get around the issue of land zones and water zones needing separate referencing. 68 Could have table for each land and water zone of the adjacent land/water zone to reach a particular land/water zone; would sort by having x = (1 = land zone 0 = water zone); y = plateau, z = land or water zone red of the support location or rally point Then cycle through every land amd water zone and if ot doesnt have the adjacent value set, record it Then think of a way to record cumulative value of enemy ground aa; and enemy non-ground AA; -if do as part of land and water update issue is it is calculating for everything and isnt in order of distance from support/rally -if do as part of airaa logic then have to redo for gunship/bomber and harder to do cumulatively; although gunship logic will probably want to be done based on front gunship position ● ● Have temporary table that reset each cycle which records the ground AA; and separately one for AirAA (reduced for friendly groundAA) along a path from zone start point to zone end point When recording the zones that come across in a line from start zone to end zone, only record adjacent zones if we would be in that zone if traveling towards the midpoint of that zone by 70 from the line that we draw from start zone to end zone, to avoid including too much of the water – could even just test vs the min and max X and Z values of the zone to see if we might enter into the min/max (i.e. if do a square around the zone, if we will enter into that square, which would presumably be even quicker to calculate, and would avoid the issue of landing on a cliff that isnt in the zone, although would also be less accurate) If take this new approach, then not sure can do the ‘only record adjacent zones on thew ay to target, and then use their recorded adjacent zones’ approach, unless such information is recorded for a given start and end zone. I was going to (based on the above) have a temporary table of air ground threat, done for each airaa subteam, which works similar to the above in that you input the start zone and end zone, and it returns the enemy groundAA; and a separate temporary table for air air threat. When deciding whether a zone has too much AA to target, this value will be calculated. ● ● AirAA threat should be reduced by 2 x any friendly groundAA threat Would then apply a factor to enemy AirAA threat vs our AirAA threat when deciding whether to engage or not, with the factor depending on if we are far behind on air. However, I’m not sure how much efficiency I’ll actually gain from such a temporary variable (since my AirAA will assume every air unit is traveling from the support zone) so for now I’ll just calculate on the fly and revisit when I come to adding in bomber logic if I think it would be more efficient to record the AA result. Summary of approach to use ● Global table of air pathing, which has variables for the start zone, and the end zone, and returns a table of all of the zones that will path through to get there, along with any zones that will get within 65 of the edge of the zone; this is calculated as and when it is needed ● Enemy air units will only be considered if they have no groundAA threat in them or in a path to them from the support zone 2.24.4) Refuel units 69 ● ● ● ● ● ● Per the above I should have a table of units that I want to send for refuelling, which will include units that already have been given a refuel order, and units that haven’t. With M28’s approach to orders, I want to create a new tracked Refuel order, so I can avoid telling a unit to refuel if it has already been given the order. o If a unit’s order is cleared, and the last order was to refuel, then need to make sure it isn’t registered as refuelling? Or could handle as part of checking for available airstaging platforms o Adjust logic so strat bomber takes up 4 space? M27 logic doesn’t work so well as if air staging has 2 units in it, it will treat a strat bomber as being able to make use of it I think I also want to take a similar approach to M27 regarding calculating available air staging platforms to send units to refuel at, but fixing some of the issues M27’s simplifications caused, in particular: o Create a list of all air staging platforms owned by the air subteam o Calculate for each of them how much spare capacity they have o Cycle through each unit wanting refuelling, and based on its size find the closest air staging platform with enough space to fit it o Send any remaining untis (for whom there are no available air staging platforms) to the air rally point. Have idle air units refuel if their health is <85% or their fuel is <55% If an air staging has units in it that have full health and fuel then all such units should be released. If a unit’s last order was to refuel but the target is dead then it is treated as available. Meanwhile if a unit was recorded as being told to refuel but it is dead or its air staging target is different to the air staging unit being considered, then it is removed from that air staging’s list of units trying to refuel (so the air staging is treated as being available). 2.24.5) Attacking with land vs air – gunship logic Whereas M27 relied heavily on bombers for defence and gunships were also a defensive tool that would try and avoid going onto the enemy side of the map, for M28 I want to experiment more with focusing more on gunships in preference to bombers, and using gunships aggressively where the enemy lacks anti-air. My initial thoughts on logic to use are as follows: ● ● ● ● ● ● Get a list of available gunships (vs those wanting refuelling etc.) similar to AirAA units. Send gunships for refuelling similarly to for AirAA units. Check for any enemy units in a core base, and consider attacking units if we have available gunships (i.e. as a ‘last resort’), regardless of AA threat o To help with adding enemy units, I want to expand the previous function created for airaa units to add in a threshold for groundAA If still have no enemy targets, then get the gunship nearest to an enemy base, and use this front gunhip’s nearest land/water zone as the start point. Check if any enemy airaa threat in current or adjacent land or water zones, and if so then return to rally point If still have no enemy targets, then check the current and adjacent land zones to the front gunship – for each one, consider if any enemy units, and (if so) calculate the enemy groundAA threat and AirAA threat. 70 o ● ● If any airaa threat, then retreat to rally point (i.e. in a zone adjacent to an adjacent zone) Then start from the front gunship point and move outwards across land and air zones by order of distance. o Will want to consider cumulative enemy ground threat and airaa threat from the gunships to the current target. o If any AirAA threat, then ignore the target. o Otherwise, decide if the enemy MAA threat is insufficient to defend against the gunships: ▪ Want an 8:1 threat ratio ▪ I may want to refine this in the future, e.g. one option is that if the enemy has 3200+ groundAA threat, then I want it to have a 6:1 land to ground AA threat ratio (e.g. experimental supported by MAA). However for now I’ll see how it performs without this restriction as it may be in large numbers gunships can still overwhelm SAMs/T3 MAA with the AI’s gunship spreading logic. Gunship positioning – This is mostly an exact copy of M27’s logic, except for the final section for ordering gunships which makes use of the new M28 orders logic to do a similar thing. 2.24.6) Torpedo bombers ● ● ● Only to be used defensively (as will be relying on navy to beat the enemy more generally) At the start of the game, create a table of water zones that want to consider for torpedo bombing for each air subteam – Get the naval factory build location for each pond, and then consider this and any adjacent water zones. Each cycle order the water zones by distance to the air rally point. Cycle through these one by one. o Consider if there is any enemy airaa in a path from the water zone to our rally point; if there is, then don’t attack. o Otherwise, attack provided either have 125% as much torpedo bomber threat as the enemy groundAA threat, or we have at least 80% as much threat and have torpedo bombers in the water zone (to avoid sending bombers in and then aborting as they’re about toget in range). If we have at least 8k torpedo bomber threat then attack anyway. ▪ Prioritise enemy units containing the antiair category and shield boats in a group of enemies ▪ Then frigates ▪ Then other units o ● Assign torp bombers based on strike damage (using a copy of M27 logic for determining strike damage for all units, but with additions for torpedo bombers based on theblueprints to be more accurate – i.e. M27 would work based on threat and manual adjustments, whereas now I will work based on actual strike damage); in the case of cruisers and carriers assign 50% more in strike damage than is expected to be needed. Factor in unavailable torp bomber threat in decisions 71 ● ● ● Treat torp bomber as unavailable if it is within 90 of its target and its target is valid and on water; similarly (for future use) treat bombers as unavailable if their target is on land On death – remove assigned strike damage When targeting torpedo bombers, the closest enemy units in a water zone (of the priority category) should be targeted first (by the closest torpedo bombers). 2.24.7) Air scouts Recording when have visual of a location ● Record omni coverage similar to how radar coverage is recorded ● If a land or water zone has omni coverage of at least 30 (40 for water zone) then treat as having visual as part of the land/water zone cycling ● Cycle through every air scout and record its current land/water zone as having visual o Similarly, if have land scouts for a land zone, or naval non-sub combat units for a water zone, then treat as if have visual of that land/water zone. Air scout management ● Scouting – although done by subteam, will largely reference team varaibles (main reason for doing on subteam basis is so can ensure the logic takes place in a different tick to other air unit management) ● At start of game record each enemy base start position as a high priority, zones with mexes with medium priority, and other zones as low priority. o want to scout high priority (i.e. enemy base) every 60s if have t3 air and at least 12 mass per tick, 120s otherwise o locations with a mex: Every 120s if have T3 air/high mass, 200s otherwise o any other location 3 times the ‘with a mex’ location value ● Increase value by the cube of the number of failed scout attempts (i.e. 1s for 1 failed attempt, 8s for 2, 27s for 3, etc.) ● If have radar coverage of a location then x4 the time until want to scout it ● Create a shortlist of locations that are overdue being scouted ● If have available scouts: o cycle through each air scout one by one, by order of distance to the scout owner’s air subteam’s rally point o find the nearest ‘overdue for scouting’ location to the air scout, and send it here o record the target land/water zone against the scout; clear this value if scout is sent to rally point ● On scout death - if it had a target land/water zone, then record against tram data of that land/water zone the failed scout attempts, as +1, and reduce by 1 after 5m, and clear the assigned land/water zone (so dont increase by more than 1) 2.24.8) Transports The main differences to M27’s approach for transports are that I want to do on an island basis (instead of plateau basis), incorporate land zone logic information (so less likely to drop dangerous plateaus/islands), and make use of M28’s order tracking approach to hopefully end up with simpler logic (although I suspect I may run into similar issues that M27 did with transports and have to add complexities). In contrast to other air logic, I also want to do have transports rely on air team wide information rather than air subteam information, since ultimately I’ll be considering orders for each transport 72 individually (getting the nearest location) and they’ll consider dropping anywhere on the map, so I want to avoid air subteams doubling up on transports. However I’ll still include it as part of my air subteam logic so it’s easier to see at a glance what air logic is running in each tick. Main dids are doing on island instead of plateau basis, incorporating land zone logic, and order tracking approach: Generate shortlist of locations that want to try to drop to: Exclude islands with any of the following: ● ● ● ● ● enemy start position in it Enemy combat threat of at least 175 in a land zone (indicating an enemy acu or a number of tanks in the island) Engineers already travelling there Have had a failed transport attempt in the last 5 minutes (i.e. where a transport has died while travelling there) dont consider islands in the same plateau as the nearest friendly base that are within 190 travel distance of the nearest friendly base Calc available and in use transports (in use if special micro active) For available transports, cycle through each one and get preferred island to drop to – I’ll first sort the transports by distance to the rally point, to try and reduce the extent to which the order transports are considered changes causing their targets to change (with this resulting in a constant loop where they end up never reaching a destination). I also want logic to get the closest plateau and land zone/water zone to a unit position, and to revise the previous approach taken to air units with no zone so they will instead be assigned to the nearest zone. ● ● ● ● ● If no plateau at the position (factoring in override), then get the segmentX+Z of the current position If not in override table of nearest valid segment, then start moving in a circle around this until find a segmentX+Z that has a valid plateau and land or water zone. Record this segment X/Z in an override table based on the base segment (i.e. this way we avoid a really massive table size) Then return the plateau and land/water zone of this override segment (return 0 for water zone) Previously had logic for enemy air units with no zone – this should become redundant after updating for this If no islands to drop to, then go to nearest rally point For each transport: ● ● ● ● If have engineers attached then get preferred island to drop to; then decide if want to wait for more engineers or if have enough to drop Preferred island to drop to – go through each island on the shortlist, and calculate the closest land zone to the transport that has a safe path (i.e. no enemy airAA or groundAA) If have enough engis for preferred island, then give order to drop (so are doing this every cycle) if have enough engis, clearing any engis who have orders to load into the transport If want more engis then move to the closest friendly base if we aren’t in a core land zone 73 ● If are in a core land zone, then record against that land zone that the transport is waiting for engineers. Then for engi logic if have any transports wanting engis, load as a high priority unless have enough already assigned (will need to load one at a time with max of 5bp to assign) ● ● Engi logic will need to refresh the table each time to check for dead units or transports that no longer have this as their closest plateau/LZ As part of this I have a new order for loading onto transport (really this is the same as refuelling a unit but in case I want to apply different tracking later I want them separated out) When transport is told to unload, record its island target, otherwise clear this; then when a transport dies record against the team data for this island to indicate it has made a failed transport attempt If transport has no target plateaus and has engis attached then unload. If a target island has engineeres or factories on it then don’t target it for a drop. 2.24.9) Factory production and upgrades Building an air factory Have a function that will decide what type of factory we want to build for a land zone, which takes into account the following: ● ● If in core base LZ, or in same island as nearest allied base, then: o If cant path to enemy base by land or are on a 20km size map, then min tech 1, min land factories 1, energy wanted 22 per tick o If have less than 80% energy stored, then build a land factory o Otherwise calculate the number of land and air factories based on the distance to the nearest enemy base (closer distance = more land factories). Otherwise, only want land factories (i.e. land facs to secure a plateau dropped by engineers) Building units from an air factory ● If low power then only consider building engineers, and then only if have lots of mass ● Emergency builder – if enemy non-air scout air unit in current land zone, or air to ground threat in adjacent land zone, then build AirAA. ● Otherwise, if enemy ground in current or adjacent land zone, then build gunship ● Otherwise, try to maintain the following in order of priority: o AirAA until have at least 3 units o Torpedo bombers if enemy has nearby naval threat to target (limit of 150% of the nearby enemy naval threat) o Gunship ifhave fewer than 3 o Air scout if don’t have any o If have a need for torp bombers (i.e. for further away targets): o o ▪ If not far behind on air, build torp bombers ▪ If far behind on air, then only build torp bombers if our Torp bomber threat is less than our AirAA threat. If far behind on air, then want 3 times the mass in AirAA as gunship air to ground If not far behind, but don’t have air control, then want 2:1 ratio 74 o o Otherwise, want 0.75 mass in AirAA vs gunship threat Get more gunships if have enough AirAA based on the above ratios and either don’t have low mass, or have fewer than 5 gunships, subject to a cap of 22 gunships. Upgrading air factory I wanted the following to be done as a high priority: ● ● Enemy has nearby naval threat and we have no T2 air Enemy has T3 air and we don’t However, it looks like I’d already drafted code for this when I did my normal upgrade logic so I only needed a minor tweak to link in with the new variable flag for if I have naval targets but no torpedo bombers for anyone on the air subteam. 2.24.10) ● ● ● ● ● ● ● Will need to update the varaibles refbFarBehindOnAir and refbHaveAirControl based on AirAA threat – for now, if I have <75% of the enemy AirAA threat and it is more than a certain level, then it should flag as being far behind on air control. If I have at least 20% more AirAA threat than the enemy then it should flag as having air control. Air staging – if there are units needing refuelling and no air staging, then air staging should be built (to a max of 3 per core zone). Added the front gunship as a priority unit for AirAA to protect and for the support air zone logic. Gunships should prioritise cruisers over other anti-air Reduced the threat ratio required for gunships to attack when the enemy is closer (to reduce the risk of them advancing, getting hit by AA, and retreating, without doing anything). Gunships should ignore enemy AirAA if we have air control and the enemy AirAA threat isn’t that high a proportion of the gunship threat, depending on how close the gunships are to the support rally point. When getting the air support location if we have air control enemy air should be ignored. 2.24.11) ● Other air logic related points Other misc changes Added further redundancy for the default navigational pathing failures on larger maps, so segments with no land or water zone will search for nearby valid pathing locations (in a 3x3 distance of the segment midpoint) based on if the position is land or water. 2.25) Naval logic 2.25.1) Engineer adjustments My engineer logic was setup focused solely on land zones, and when I first added water zones I only included basic logic required in order to build on underwater mexes and get reclaim in water zones. I therefore need to replicate similar functionality for water zones for identifying locations to build. As part of this I create a separate list of template blueprints for each building size that can be built on water, and adjust the existing functions relating to this to handle water zones as well (rather than doing copies of the functions). As part of this I then reworked various parts of the engineer logic to in theory work with water zones as well as land zones (e.g. tracking of queued buildings). 75 I also add in logic to track hydro locations by water zone, to help for logner term logic where I try and get M28 functioning when it is given a water start point. Naval factory assistance ● Have any idle engineers assist the naval factory ● If don’t have low mass, have more engineers assist the naval factory (+5 BP each time/cycle over what is already assigned) ● Ensure a base level of BP assigned to assist the naval factory based on team’s mass income. 2.25.2) Factory build logic Choice of blueprint to build: ● Cycle through each water zone, and decide what to build based on each zone: o If have units wanting shielding, build shield boat o If have units wanting stealthing, build stealth boat o If enemy antinavy threat, build antinavy unit o If enemy surface combat threat, build surface combat (frigate/destroyer/battleship) o If need AA, build AA o If go through all WZs and have no units that want to build, then get a bombardment unit o If have low mass or low power then cap number of bombardment units to get ● Have a naval factory upgrade if don’t have low mass and we have at least 70 average mass income on the team (T1 to T2) or 140 (T2 to T3), separate to the centralised logic, and providing there are no active upgrades in the waterzone, and only if there are no units to build to attack an enemy WZ. 2.25.3) Naval unit management – bombardment mode Although I’d setup water zones with details of adjacent land zones with this in mind (as an alternative means of checking for nearby enemy units), in the end I was losing motivation to try and do something fancy here so just copyed the M27 logic for bombardments. 2.25.4) Other naval changes ● ● ● ● ● If a naval unit is thought to be in a land zone, and has no orders, then it should be told to move to the nearest water zone, or move randomly otherwise. Reduced the distance to stay away when shielding or stelathing a unit to 66% of the previous distance for larger shields, to hopefully help make shield boats more likely to keep their target under shield – most of the time they manage it now, although there are some cases where the unit can outpace the shield. Limited shield boat production to factor in power levels (both if have low power and gross levels), and also added a cap on the number of shield boats (and stealth boats) to be owned by a particular AI. Made naval factories more likely to upgrade with very high mass income. Added ground firing for units with no anti-naval attack but a good aoe attack, where there are no surface targets, and the enemy unit is less than 1.3 underwater or is a submarine (i.e. most battleships should ground-fire submarines). 76 ● ● ● ● ● ● If units with an antinavy attack can’t see the nearest enemy unit and that unit is submerged, they should try to get closer. Amphibious units that are underwater should have 35% of their mass cost treated as their base threat when calculating the submersible threat of enemy units. Shield boats shouldn’t be built if we have run out of high value targets for them Adjusted logic for amphibious pathing in water to check they can path amphibiously from the unit’s actual position (previously it used the water zone midpoint, which caused issues for water zones where the midpoint couldn’t be reached by amphibious units). Increased the priority on assisting the naval factory water zone to be equivalent to that of a water zone with unclaimed mexes. Adjusted the early game build order on naval maps to build fewer factories, and make it a higher priority for engineers to expand to islands, as well as adding an eco condition to building the initial naval factory. Sonar ● Added logic to track sonar coverage of water zones, similar to how radar coverage of land and water zones is tracked. ● Build sonar to increase sonar coverage: if no low mass or power o If average team mass income is 6 per tick, we have at least 125 E per tick, our highest tech level is T2, and there is no enemy threat in the core WZ or adjacent to it, then build T2 sonar in the core WZ o If we have 12 per tick average mass, and at least 250 E per tick, then for each non-core water zone, check if it is ‘safe’ (no enemies in WZ or adjacent), and if so if its sonar coverage is less than 115 build T2 sonar o Don’t build if AiX intel o Added logic to build t1 sonar where there are enemies in an adjacent WZ and we don’t have really high mass income. Frigate scouting: ● If have T3 navy fac, T3 naval units, mass income of at least 25 per tick, and no enemies adjacent to a core WZ, then set a flag that frigates are to be treated as mobile land scouts instead of combat units, and use them accordingly ● If this flag is set, then have factory build frigates if we have flagged as needing scouts in a location. ● When implementing this I realised there was a flaw in my land based scout logic (and hence frigate based logic) – it was tracking scouts assigned to travel to a location, but wasn’t updating these lists if the unit died, meaning some locations would never be scouted. 2.25.5) Other non-naval related changes ● ● ● If we have spare engineers for a land or water zone and are upgrading a unit in that zone, then all the spare engineers should assist the upgrade. Added new high priority engineer builder for air factories so we have a minimum number of engineers before getting other units There was a bug in the logic for calculating air travel paths, due to a bug with recording the min and max segment ranges for a land zone – the variables for the max segment X and Z used the same definition, causing strange behaviour where ASFs would suicide into enemy SAMs (thinking they weren’t nearby). 77 ● ● ● ● ● ● I also change the AirAA logic to assign 3x the threat to AirAA targets, and if there are any spare AirAA units to intercept then I increase this to 6x the threat. There was an issue with air logic where if an enemy intie came into a land zone (e.g. the enemy flies an intie over M28’s base) and the unit survives, then M28 would spend the whole game thinking there was an air unit there, messing up it’s logic. I’ve therefore tried to approximate the ability of a human to assess where the air is, by updating the positions of air units in a zone every 30s, or more often if allied units are in that zone. The difference this made was dramatic – I was prompted to do this by an M27 vs M28 replay on an island based map where M28 was behind the entire game initially about 2:1 and increasing to 3:1 until M28 lost navy and its main base. After the change M28 was able to take the lead in eco for a bit via use of its gunships, and able to repel M27’s initial naval attack with its torp bombers and gunships. However, M27’s navy production was superior to M28’s, and a large amount of shield boats coupled with cruisers was able to repel large amounts of torpedo bombers without loss. Air units should move near an air staging followed by a queued order to dock at the air staging if far away due to an issue I came across once where gunships were given a refuel order and it was somehow cancelled leading to them remaining idle far from base. This way if the issue happens (and there is no air staging available) the gunships should at least be in a safer location. Increased resources wanted to start on an ACU upgrade in certain scenarios including where we can’t path to the enemy by land, and where we already have ACU upgrades. Reduced the number of land factories to get on non-core islands and the likelihood of upgrading the land factories. Where the enemy cant be pathed to by land then engineers should be built in greater numbers initially. 2.26) Novax, Nukes, and TML Before M28 releases I want it to have slightly more variety than its current late game approach of spamming land experimentals, especially for UEF since fatboy is really bad on naval maps even if it makes it to the enemy land base. Since the SML logic and TML logic in M27 shares some parts, I’ll also add in TML logic at the same time. 2.26.1) Novax Production ● UEF – if cant path to enemy base by land, then check if enemy has significant land combat threat (a least 2k + 15k for each fatboy we already have) in total on our current island; if not, then only build fatboys up to the number of enemy land experimentals, with a max of 2, otherwise build a novax. ● If can path to enemy with land, then order of fatboys wanted: o 1 Fatboy o 1 Novax o 1 Fatboy + 1 per every enemy land experimental, to a max of 2 fatboys + 1 per active M28 team member, up to 4. o Remaining experimentals: Novax, unless have >=50% mass stored and >=90 team mass income per tick, in which case build mavor (for now I’ll build a novax though as I don’t have the logic in place to manage a mavor 78 To facilitate this, I’ll generate a table of the engineers by factions to pass to the function that picks the experimental category ot build, so I know more reliably if I have a UEF engineer (M27 would assume the faction based on the aiBrain in question, but M28’s decentralised approach means this could go wrong, and at some point in the future I want to try and have a system for one faction requesting the engineer from another faction). For the novax usage I want to copy thet part of the logic that considers targeting vulnerable enemy shields and ACUs, and then make use of the land zone logic to search for other targets: ● ● ● ● ● ● ● Generate a list of novax on the air subteam. Hook on killed so if novax kills unit it immediately gets a new target Copy M27 code with the following adjustments: o When searching for nearby enemy units, search in the current and adjacent land and water zones, so we can make use of ‘memory’ of a unit to consider targets. o If the novax is in a zone, refresh the position of all enemy units in that zone given the novax provides intel. Search current and adjacent land and water zones for all non underwater enemy units, and calculate the damage that could deal factoring in distance and if unit is shielded, with increased value for mexes and volatile units Weight the values by unit category similar to M27 (e.g. mexes are treated as being worth more than their mass cost, similarly for volatile units) Check if units are shielded by creating a list of mobile and fixed shields in these zones and seeing if are within range of any of these units. o However after initially drafting this I realised there’d be a flaw with this approach –if a unit was on the edge of an adjacent land zone, and was covered by a shield in a further away land zone (i.e. not adjacent), that shield wouldn’t be picked up initially, the novax would think the unit was unshielded and move ot target it, then realise it’s mistake and change targets once it got into the same land zone, leading to a potential infinite loop where it did nothing. o I’ll therefore need to create a shortlist of shields in zones adjacent to adjacent zones, and make sure I only include each shield once, and also only include the shield if it is close enough to the edge of its zone that the shield will go over. However after testing before this change (see later comment) I ended up scrapping the approach of cycling through adjacent zones due to it’s unreliable nature. I only want to include such targets if they meet a base value threshold – i.e. I don’t want my novax wasting time targeting high health low mass units. I’ll do this by treating the novax as already having ‘found’ a target with a certain value (iBestTargetValue), so future entries will only be considered if their value exceeds this. o In terms of what this value should be, the novax DPS I think is about 243 (ignoring that it’s much higher while firing and then 0 while reloading). It costs 36k mass, while in comparison getting a T3 mass fab and some power costs about 5k mass for 16 income per second. o Therefore, the opportunity cost of a novax is approximately 115 mass per second. ▪ I therefore ideally don’t want to go much below this when picking a target. ▪ Practically, I would expect the novax targeting a monkeylord to be ok, but targeting a ythotha to be inefficient 79 ▪ Checking a few units (mainly using UEF values since they typically have higher health), targeting a frigate or pillar constantly would deal 32 mass/s, 68 for a destroyer, 88 for T3 MAA, 96 for a Ythotha, 108 for a monkeylord, 194 for a cruiser. I’ll therefore use a value of 105. ▪ If I have at least 4 T3 gunship equivalent of air to ground threat on my air subteam and aren’t far behind on air then I want to increase the value of focusing down AA by 50% (so T3 MAA gets included) to give gunships more of a chance to attack, otherwise to leave it at default. ▪ Engineers only provide a value of 79 (T2 engineer) to 95 (T3 engineer). However, killing them potentially denies my opponent valuable reclaim and the ability to build shields, so I want to still consider targeting them. I’ll therefore increase the value of an engineer by 35% so they should also be targeted. ▪ If there are no suitable long range targets, then I want to instead use the best value target near the novax subject to half the cap as before. However after testing I realised this approach was too inconsistent, due to the differences in sizes of land and water zones, so I switched to using getunitsaroundpoint. 2.26.2) Nuke launcher Initially I wondered if I could make use of M28’s zone logic to keep track of blocking SMD, e.g.: ● ● ● ● ● ● Record against each land and water zone any potentially blocking SMD for each M28 owned nuke, so can then decide whether or not to target it Whenever an SMD is built or killed, this table would be updated. Would also want to be based on land zones, so could make good decisions about whether to build a nuke in the first place Check approach re TML and TMD as may be something similar wanted. Then for targeting would consider the value of a land zone coupled with combat and AA threat when deciding whether to target it (for WZ would just be combat and AA threat) And then would do a more precise calculation at both the midpoint of the zone and any T3 units in the zone to estimate the best target for that zone. An alternative approach to this could have been: ● ● ● ● tTeamData: Generate table of core bases, whenever core base is set to true, and it is a land zone, add to this table Whenever an SMD is sent to the pond/zone function for recording, add to table of enemySMD (may already do this), and run a function that cycles through every core base and then cycles through every land and water zone and considers if the SMD can block it; have it as a function that is sent the SMD unit in question (as will want to use same function below when a new core base is added and smd already exist) Whenever add a zone to this table for a team, check the team-wide table of enemy SMD; if it’s not empty, cycle through each entry, and then cycle through every land and water zone For every land and water zone, check if a missile fired from the midpoint of the core zone to the midpoint of the land/water zone in question would be blocked by the SMD. If it is, then 80 ● ● ● ● record the SMD in the core base’s land zone of blocking SMD for that zone (i.e. order things by plateau (0 for WZ) and zone ref; and then return a table of any blocking SMD units Whenever recording the blocking SMD in this way, against the SMD record in a similar table (i.e. plateau or 0; and WZ/LZ ref as the initial keys) the plateau or zero and core wz/lz ref that the SMD likely blocks a nuke from Whenever an SMD is destroyed, go through any zones where it was recorded as a blocking SMD, and remove it When a nuke is built by an M28AI, then redo the zone check (unless there’s already a nuke in the zone), but instead of using the zone midpoint will be using the nuke launcher position. Will also record against the teamdata of that zone the nuke that the nuke check is based on. When a nuke is destroyed, and it was owned by an M28AI, then re-do the zone check based on the midpoint (unless there’s another still living nuke in the zone in which case revert to that nuke’s position), and remove the nuke from the nukes in the zone. However, after sketching out the work involved for this, I decided I’d just copy M27’s approach, as the main benefit of the above is just when it comes to the decision of what nuke to build, and in practice I don’t think it would be as good as restricting targets based on if the midpoint of the zone they’re in can be hit will lead to a less accurate nuke. Some of the most entertaining parts of M27 replays have been when it manages to edge-nuke a human, which the zone based approach would significantly reduce the likelihood of (even if it would be far quicker to run). I’ll therefore consider doing something along the following lines: ● ● Keep a table of enemy SMD (so if they fire we know where they are even if they’re not revealed to avoid repeatedly nuking somewhere covered by SMD); when nuke is loaded then cycle through enemy units, considering 50 units each tick, and fire on the best target after considering 500 units, or finding a really good target, or running out of units to consider i.e. probably just a copy of M27’s logic. However, the main differences to M27’s approach will be: o Not cancelling construction of SML or reclaiming it o Checking for new targets every 10s if it failed to find a previous target o Increasing the threshold for firing a nuke to 14k (from 12k) SML construction I want to track on a team basis for each core land zone the other land zones it could hit with a nuke, and update this list whenever an enemy SMD is built or destroyed, a bit like what is done with TML but for zones instead of TML units, so I can build a nuke if there are any high value enemy zones considered vulnerable to a nuke. ● ● ● ● When deciding on the experimental category to build, engieners should call a function that gets the highest land zone value that they are expected to be able to nuke from there If I haven’t calculated this before, or an smd has been built or died since last calculated, then I’ll do a refresh of this logic for the core lz teamdata that are dealing with, with a flag for if smd have been added or died; if smd have died or have no entries then I’ll do a full refresh, otherwise I’ll only consider removing existing entries Ensure enemy smd is tracked when added to the pond/zone assignment function for the first time When cycling through enemy land and water zones record enemy structure mass value (ignoring health) 81 ● ● ● ● ● ● Cycle through every other land and water zone and for each midpoint check if it is in range of any of the smds known about for that team; if it isnt then record as an unprotected zone Once this function has run: in the bp function cycle through each recorded entry and get rhe highest value calcd as 100% of enemy structure mass value + 25% of enemy ground threat value If highest entry exceeds 20k then build a nuke launcher However a land experimental will be built as a higher priority if we have none and can path to the enemy base with land. Only one nuke launcher should be built per zone. Seraphim – added logic to build yolona – e.g. any map where cant path to enemy base by land or already have 3 land experiemntals, and have at least 80 mass income per tick. 2.26.3) TML TML targeting and usage ● I expanded the previous tracking approach so I can use it to identify targets as well – i.e. I’ll use the same trackers that highlight units that need TMD (for purposes of building TMD) in order to select targets for the TML where M28 owns the TML. ● I also copied the M27 logic for finding TML targets with minimal changes. However, I ran into issues getting this to work and reviewing the code realised there were flaws with it due to the complexity of scenarios it would need to capture to reliably track potential targets. After a number of aborted rework attempts, I decided to take a shortcut for my sanity and have all AI use a single shared tracking system, meaning M28 TML may get a slight unfair advantage re target selection but it should hopefully avoid performance concerns with recalculating everything on the fly whenever deciding to fire a missile, and makes things easier to follow. In summary, the code should do the following: ● Whenever a TML, TMD, or Category that is vulnerable to a TML is built, check for all nearby TML/TMD/Vulnerable category units, and update the TML related tracking variables on all of them, to record the following: o Units the TMD is protecting from enemy TML o Units in range of TML that have no TMD protection o Units in range of TML that have TMD protection These are tracked against individual units. When a TML or TMD dies, then the tracking is updated. However, I wont update when a ‘vulnerable category’ unit dies, and instead just have a check for if units are valid as part of the logic. Decision on when to build TML Ideally I want the engineer builders to have a low CPU way of accurately identifying potential TML targets if they were to build a TML in the land zone. However after the pain of getting the MTL logic to work (which I was expecting to not be that difficult) I’ll go with a simpler to code approach. The approach I’ll use is as follows: ● For now, only consider building TML in core LZs, although in theory it should be possible to expand to other zones if I decide to later on. 82 ● ● ● Only activate if we are at T2+, the enemy has at least T2 units, and we have no TML in the land zone Whenever a ‘vulnerable to TML’ category unit is sent to be recorded for a team, and it is an enemy to the team, and the team has M28AI in it, record it in a table for that land zone if it is a structure against the M28AI team data o Similarly record whenever a TMD is built and recorded against a LZ o Refresh both of these lists when updating the engineer logic (rather than whenever a unit dies) to remove dead units Cycle through every land and water zone, and consider any with vulnerable to TML enemy units recorded, but stop as soon as reach a zone that contains TMD (i.e. won’t bother considering direction, will just stop searching for all targets once reach a zone with TMD). 2.27) T2 PD, Ahwassa and T3 arti The following reflects relatively ‘core’ features I want M28 to be capable of before it releases. Although I originally planned to not release with T3 arti logic, on reflection Aeon and Cybran need something they can build for maps where land units cant reach the enemy base so they are capable of winning a late-game map (in theory). 2.27.1) Emergency PD to stop enemy Guncom ● ● ● For now I’ll hold off on M27’s complex logic on PD placement and firebases, and instead focus on just getting T2 land/air and T2 PD if the enemy’s ACU gets near. Core bases will call a function that cycles through a list of identified enemy ACUs, and totals up the threat of all ACUs who are close to the zone. Based on this threat, either a priority upgrade should be called (if the zone lacks T2), or point defence should be built. 2.27.2) Ahwassa Usage For now I’ll use a very simplified approach that I expect will need improving later on ● ● ● ● If lack air control then run from enemy AirAA threat of more than 400, otherwise only run from AirAA threat of more than 4k Determine pathing to all other zones from the zone the Ahwassa is in (similar to what is done for gunships Treat as unavailable if current target is within 100 of its position or special micro is active. Cycle through each other zone from the ahwassa position, and consider enemy structure and combat threat, considering any zones where the threat is at least 1.5k o Consider each T2+ unit in the zone plus T1 navy, and calculate the total mass value of enemy surface units. o Target the closest unit to the bomber o Calculate the best AOE target for targeting this unit if it is a structure o I’ll copy over M27 logic relating ot hover-bombing, but instead of hover-bombing I’ll have the Ahwassa fire a shot and then immediately hover-turn and retreat, before turning back again – this reduces its damage output, but hopefully increases its survivability (e.g. if the enemy attacks it with asfs it's more l’kely to be retreating to a friendly location). 83 o ● I also decide after testing to target the unit where a shot deals the most damage, instead of the unti closest to the bomber (improving its damage output at the cost of survivability). Make sure available bomber logic factors in ground attack orders similar to unit attack orders. Construction If have air control, or have as many land experimentals as the enemy and aren’t far behind on air, or cant path to the enemy base by amphibious, then build an ahwassa. 2.27.3) T3 and experimental arti I wasn’t originally planning on having T3 arti for the release version of m28 but on reflection it felt too big a gap to have UEF having a late game option (novax), Sera getting the experimental bomber, but Aeon and Cybran stuck with land only. Usage For now I’ll go with the following simplified approach to calculating T3 arti targets: ● ● ● ● ● Calculate pathing from the zone using the function used for air pathing If the arti doesn’t have potential zone targets recorded against it, then cycle through the zone pathing options, excluding any zones whose distance is inside the arti’s minimum range, or outside the maximum range. Then cycle through each of these zones, and identify the zone with the most ‘value’ to attack, and the second best zone (as when go through the detail the best zone may not actually be the best) Adjust the zone value based on a ‘T3 arti likely failure count’ value – whenever a unit dies in the zone that is a fixed shield whose fractioncomplete is 1, or a structure unit with a mass cost of at least 1k factoring in % complete, then reset this count for the zone. Whenever a shot is fired then get the zone of the target and increase the count by 1. o The value of a zone is 100% if the shot count is less than 10, and then changes to be reduced by 20% + 2% for every failed shot, to a maximum of a 96% reduction. Select the zone with the greatest threat value applying the following calculation: o Shot value % (per above) * (structure mass cost + mobile unit cost * 0.2) ▪ Add a further +80% of mobile unit cost if the groundAA is at least 4k, and the zone is within 300 straight line of the nearest friendly base, and the enemy has at least as many land expermentals as our team ▪ Alternatively, apply a further +80% of mobile unit cost if the enemy mobile threat with a range of 80+ exceeds 4k and the zone is within 300 straight line of the nearest friendly base. ▪ Apply a +100% uplift to the structure mass cost if it is within 200 of a friendly base and includes indirect fire units with a range exceeding 100 and a threat exceeding 6k (i.e. T2 arti) ▪ ● The value will be reduced slightly if the target is in a far away angle (up to 40 degrees if it’s in the opposite direction to the direction the Arti is facing) In the end I decided to select the best 2 zones (since the calculation used above isnt that precise), and then select the best target within these zones (focusing just on T3+ units if 84 there are any), before then getting the best point on the ground to attack out of these targets. Construction ● Build if we can’t path to the enemy base (or for UEF if we would build a novax but already have 3 novax and have more than 1 more novax than T3 arti (i.e. want 1 T3 arti with 3 novax, 2 T3 arti with 4 novax, etc.). o If team mass income exceeds 80 per tick then instead build a mavor or scathis or rapid fire arti o Also build these experimental arti if the nearest enemy base is more than 740 from the zone. 2.27.4) Late game eco and other adjustments Engineer reassignment ● When identifying available engineers, if none are available of the required tech level, check all assigned engineers with a different action to see if they are available, and if so then free up the engineer with the highest numerical priority (i.e. the lowest priority action, since 1=most urgent). ● When an engineer is given an action, record its priority (so the above can be checked). ● Ignore engineers who are actively reclaiming or have a priority 1 action. ● Engineers who have nearby enemies should be treated as having a priority 1 action. Other misc changes ● Added a relatively high priority second power builder to help with late game high mass situations. As part of this I’ll record when an air factory didn’t build an air unit due to lack of power, to ensure that more than this power is produced. ● Also added a similarly high priority 3rd power builder for very high energy and mass scenarios. ● Core land zones should consider a pre-emptive SMD once the total value of units in the LZ reaches 20k (or 30k if have low mass) ● Improved the emergency AA engineer builder to increase the amount of AA built ● T3 pgens shouldn’t be built adjacent to T1 air factories ● Added logic to ctrl-K T1 air factories and T1-2 land factories when low on mass and at T3. ● Capped number of land factories to 2 if we cant path to the enemy with amphibious units. ● Added a spare engineer action to reclaim in the area if there’s almost any mass. ● Engineers shouldn’t try reclaiming another wreck on completing their current reclaim order if the AI has lots of mass stored. ● If we reach 90% mass stored, then all reclaiming area and friendly unit engineers should have their actions cleared (with this check being spread out with 30 engineers considered per tick to avoid a significant performance issue) ● Cybran ASF (and other stealth units) should default to having stealth enabled. ● Improved TML targeting so if multiple TMLs are considering the same target and it dies to 1 missile, they should choose different targets; similarly a TML shouldn’t firem ore than once every 20s at a target that can be 1-shot. ● The mass and energy stall logic should no longer unpause missile launchers with 2+ missiles loaded. 85 ● ● ● ● Fixed an issue with units being paused when not complete which would lead to them being permanently paused when construction completed. T2+ Engineers dropped on a plateau should build a T1 land factory instead of a T2/T3 factory as their first factory. The first units built by a land factory on a plateau should be a combat unit and then a land scout, before the normal logic resumes. Transports with <25% fuel and no engineers should be ctrl-K’d. 2.28) Compatibility changes and performance check 2.28.1) Performance comparison to M27 All core logic other than compatibility type logic (for more niche game and map settings) are now in place, so I want to revisit how M28 performs on Africa compared to M27. The detailed profiling (which lists out every function) gave the following results for tick 6001: info: ProfilerOutput: Total time taken to get to 6001= 67.482643127441; Total time of any freezes = 0.39152234792709; Longest tick time=0.24288177490234; tick ref = 3921 to 3922 By contrast, M27’s results (from v67) were: info: ProfilerOutput: Total time taken to get to 6001= 167.24580383301; Total time of any freezes = 20.756183624268; Longest tick time=0.45658874511719; tick ref = 4690 to 4691 Overall this is far beyond what I was hoping for – not only is M28 about 2.5 times faster than M27, but more importantly it hardly ever freezes with a total time of freezes of just 0.39s to M27’s 20.8 (and I’m not sure the extent to which freezes could be caused by the logging I’ve added). 2.28.2) Unit cap This was a rare case where I was able to copy the M27 logic with minimal changes needed for it to work to some extent. The main refinements I then made to refine M27’s approach were: ● ● ● ● ● ● ● Recording the categories destroyed to get below the unit cap, and not building more units of this category Adding an exception to prevent building of T2 units so T2 engineers could be built if there was a bit of leeway in the unit cap and there were too few T3 engineers Only calling the function to update when a unit is created or constructed, and only when that unit’s creation means we may be close to the unit cap. Having more units be destroyed at low unit caps to give a margin of error Engineers shouldn’t build anything if their current action is a low tech unit and we are about to run out of units. After running, the same function should be run again in 30s Don’t build more factories if we already have 2 and are close to reaching the unit cap. Testing on Setons in the rear slot with a 125 unit cap, this resulted in the AI mostly having T3 mexes, T3 pgens, and building a couple of GC. It struggled to have the GC survive against enemy T2 bombers, but since it’s an unrealistic scenario anyway I’m happy with its general approach. 2.28.3) Maps with smaller playable areas To check M28 works ok, I tried running games on Adaptive Moon and DualGap Adaptive, as well as winter dual, to confirm there were no issues. 86 One issue that playing on dual gap highlighted is that the FAF navmesh generator will include areas outside the playable area when determining pathability – I’ve flagged to Jip in case this can be resolved, but it’d be too much effort to fix for M28 for what I expect to be a niche scenario (in short, if playing dual gap with M28 on only the top island, not the bottom, then it wont send transports to try and claim the bottom island and also wont send engineers to try and claim it amphibiously as a high priority. A fix if it’s not possible for Jip to change the way the navmesh generates paths would be for the transport drop logic to check the path generated to get from A to B and see if it passes outside the playable area, but this would only be fixing one symptom of a wider problem, and I expect most times dual gap is played there will be players in both the top and bottom start areas on the same team. 2.28.4) Water starts – Dreadnought Chasm (all water) This is a map (possibly the only one) that is entirely water. As far as I know no AI supports such maps, so I want to make M28 support it since that should make it more effective on maps where it starts in a ‘navy’ slot (even if there is nearby land). The aim isn’t for the AI to be good (e.g. long term there doesn’t seem to be any answer to nuke subs beyond killing the sub before it gets into range), but to at least provide a basic level of challenge (that would be greater with higher AiX modifiers). Initial plan ● Fix any error messages that arise when running the map ● If the start position is in water and there are no adjacent land zones, then set the start position as the core base, and set the flag that we have a naval start. ● Prioritise building any unbuilt hydro if we have low power ● Prioritise building mexes ● Include a (basic) anti-air engineer builder if the enemy has an air to ground threat in the WZ o I expand this to work for other (non-water start based) positions, including a lower priority AA builder if we mass available and are at T3 – i.e. effectively a SAM creep logic for water zones ● Update the naval factory builder to build engineers if it is in a core base naval zone, with a high priority builder (if we have fewer than 3 engineers of the factory brain’s highest tech level), and also a high priority builder if we have high mass and aren’t power stalling and want more BP for the water zone. ● When doing this I realised the ACU logic all assumed the ACU was always on land, so I updated it to make it easier to give water orders in the future (if e.g. I decide to go with cybran torpedo upgrade combat logic). ● Get Cybran ACU to get torpedo upgrade if its current WZ is an underwater start position One issue this highlighted was that the water zone creation approach (which was deliberately simple) doesn’t work if it results in the starting mexes and hydros being treated as being in a different water zone to the ACU (which his what happened on this map). My solution is to first create water zones for any start positions that are underwater, and treat a large area around these as being part of the same water zone. I also make some improvements to the underlying logic – using a ‘hollow box’ approach to assigning segments to a water zone in increasing box sizes (previously I was using filled boxes, meaning there was a lot of duplication of logic being run for the ‘filled’ part of the box), and fixing a bug where I was using non-rounded segment references. 87 Another highlighted issue is that the naval factory build location isn’t taking into account if we have a water zone start point, resulting in the ACU walking ages before it can build a naval factory. For this I’ll just use the start position as the naval factory desired build location, and then have the logic for generating build locations run loads of times for ‘core base’ water zones at the start of the game, to increase the likelihood there is a build location identified near the ACU when it tries to build. After fixing another bug highlighted (where mexes were having a land zone assigned even when underwater) this revealed an unexpected infinite loop where the logic for valuing land zones was only waiting between individual land zones, but if no land zones existed it would never wait, meaning the while loop would freeze the game. Further adjustments made include: ● Lower priority hydro builder ● Building more engineers initially before building navy. ● Build more naval factories ● Increased gross power requirement to build shield boats if in an underwater start position ● Adjusted the water zone creation so instead of setting the area around individual start positions to a water zone, all individual water start positions will be cycled through simultaneously with the area around them set (i.e. meaning 2 adjacent start positions should be similar in size) ● Include RAS upgrade for ACU ● Lowered power eco threshold for getting RAS upgrade on ACU if ACU is in an underwater start position WZ ● Allowed multiple naval factories to upgrade simultaneously ● A strange issue this highlighted was a flaw in my approach of predefined buildable locations – somewhere can show as buildable for a UEF naval factory, but not be buildable for a seraphim naval factory of the same size. I suspect the reasin is the SkirtOffset values in the blueprints are different. As a basic workaround for just this case I’ll have a table of blueprints for a size where I need to consider other blueprints of the same size, but a better solution might be to figure out if the offsetXZ values mean the build location should be adjusted to get a more generic location that is buildable. To help reduce the likelihood of this issue occurring for other blueprints, I’ll also add an extra check when picking a preferred location to exclude those which aren’t buildable ● Another issue highlighted was that my upgrade logic for ACUs needed to factor in upgrades that the ACU has which have pre-requisites so it doesn’t try and move from the better version to the earlier version (e.g. advanced RAS to RAS). 2.28.5) Water starts – Italy Italy provides a more common alternative to the extreme ‘water only’ scenario of Dreadnought Chasm, where some start positions have water, and some have land. My plan for now is to have water start positions work the same as on Dreadnought Chasm, but non-water zone start positions to act the same as on a conventional map. Only one change was required for this map, which was fixing a bug caused by the FAF navmesh not being 100% accurate, where somewhere could be pathable by land but not by hover/amphibious – now if the amphibious/hover pathing isn’t valid it should try a backup option to reduce the risk of this occurring. 2.28.6) Survival maps and unit restrictions 88 In theory M28’s approach should make it work on survival maps but there’s a high likelihood some logic won’t work as expected since it was all written on the assumption of a nearby enemy. Therefore the main aim will be for it to function to a basic extent on survival type maps. Fortunately both cases of error messages that arose I’d already included some basic redundancy/backup logic – in the case of there being no enemy brain, it would use the furthest away alive brain regardless of if it was an enemy or not, and in the case of unit restrictions it would just give a warning to alert me that it couldn’t build an air factory (which it looks like the map auto-enables as a unit restriction) and then try and proceed with other engineer logic. The downside of this is that land factories wouldn’t get built in as large numbers since it will be trying to build air factories. I figured it’d be a good time to add some basic logic for unit restrictions at this time. Since disabling air might be a moderately common unit restriction, I want to add a basic check so that land factories still get built: ● ● ● At the start of the game, flag if unit restrictions are present If unit restrictions are present and we haven’t specified if air factories can be built, then set against each team a flag for if air factories are buildable. If air factories aren’t buildable, then in the function to flag if an air factory should be built instead of a land factory, always return false. Trying on a Thermopylae survival map with all random M28 AiX 1.5 ACUs, they lasted until 14m30 before changing the land factory approach. For comparison, M27 AiX 1.5 lasted until 16m30. However, M28 had fewer error messages than M27 which was something. AI Wave survival mod The following changes were made to improve compatibility with this mod: ● ● ● ● Adding placeholder logic for bombers so they will attack the nearest enemy Adding placeholder logic for mercies so they will attack the nearest T2+ building or ACU Having Czar be treated the same as a gunship (so it will at least be used, even if poorly) in case the mod spawns czars at some point Fixed an issue where if there were dangerous enemy units at the start of the game the ACU would stop building the land factory and be stuck ‘running’ to the rally point. 2.28.7) Niche mods – flying engineers, infantry factories These are based on examples I recall where M27 failed: ● ● Flying engineers – for this I copied M27’s solution (change the category of units treated as engineers), which mostly works although I also decided to hide one of the error messages that appears if air units are sent to the land zone unit manager where the unit is an engineer. Infantry factories – this was a mod which allowed the construction of factories that couldn’t build engineers. M27’s solution which I planned to copy was to require the first factory built by an ACU to be capable of building engineers. However, the mod no longer works so without a way of easily testing this I’ve left it for now and can patch it in later if anyone raises a similar issue. 2.28.8) NoRush The main things I want M28 to do with no-rush are: 89 ● ● ● ● ● ● ● Early build order – recognise if the hydro it wants to build is outside the norush radius, and (if so) build normal PGens instead (M27 for a while suffered an issue where it wouldn’t build either) Factory production – ignore production of any non-factory or non-upgrade unit if no-rush has more than 30s remaining on the timer Upgrading – treat any location as safe for upgrading if there is at least 60s remaining on the timer Land and water zones – if the midpoint is outside the norush radius and it isn’t a core base, don’t flag as needing any engineers if there is more than 30s remaining on the timer. If in norush mode then only want 1 land fac before air fac, and don’t want more than 1 of each Priority mex upgrades should be sought if norush mode is active ACU should only build 1 land factory and then build 1 air (instead of building 2 land) 2.28.9) Crazy rush This is a special map where every time a mex is build, every adjacent slot becomes capable of supporting a mex. Including some logs it looks like the SimInit function CreateResourceDeposit triggers when this is done, which means in theory I can have my AI recognise these new points. However there will be some complications given it records mex locations at the start of the game and wasn’t intended to update these during the game. Fortunately with the way M28 was setup I didn’t need to make a huge amount of changes for recording land zones and it seems to work (although clearly suboptimally since most logic aims to cap T1 mexes as soon as possible leading to constantly being short on power). I also make the following changes to help it in this scenario since I figure they may also be of use more generally: ● ● Cap the BP assigned to build mexes if we are overflowing mass and have low power If team has at least 8 gross mass/tick and 50 gross E per tick and is at T1 then prioritise T2 land factory upgrade even if have low power 2.28.10) ● ● ● Accidently running the game with M28 enabled I want to make sure that M28 doesn’t run any code if it’s enabled by mistake. Most of the code won’t run due to being triggered by the creation of an M28AI. However, there were some error messages relating to events/callbacks that M28 was triggering which weren’t checking if any M28AI were in the game first. Adding in these checks to the remaining callbacks means these error messages no longer appear if M28 mod is active with no M28AI present in the game. 2.28.11) Unit mods and other popular mods– Nomads, Blackops, BrewLAN In theory M28 should work with unit mods, but to make sure I want to run games with M28 vs M28 on a map featuring land air and water to check for error messages. Nomads I’d hoped to get successful games working with Nomads, but the game crash. At first I thought it was an issue with M28 but Hdt80bro highlighted the debug.traceback() function which allowed me to 90 confirm it was the nomads projectiles that were causing the crash, and I was able to replicate the issue as a player with no AI mods (i.e. ground-firing certain Nomads units causes the game to crash as it creates projectils on a constant loop). Fortunately it turns out the issue was fixed by the maintainer and I was just using an older version though. While there are still errors relating to projectiles with the new version, they appear unrelated to the AI. Also of encouragement was that in the test UEF vs Nomads game (at AiX 2.0 to speed things up) nomads was able to get a significant eco lead on UEF (whereas for M27 generally it plays worse as nomads than as other factions). Mods that change ACU upgrades Testing with a blacktops ACU mod which rewrites all the upgrade options, both UEF and Cybran ACUs got a gun upgrade as expected. BrewLAN Testing a game with this I could see some of the new units (e.g. experimental point defence, other faction T3 mobile shield generators), and no error messages occurred (that related to the AI). 2.28.12) Playing as a human with M28 as a teammate Adding in logic for civilians (see below) highlighted an issue where M28 will take control of all allied units not just its own. I therefore made sure that if I had M28 as a teammate and build land, air and naval units, that none of htem would be taen control of (after putting through the fix to stop civilian units receiving orders). 2.29) Misc changes Revealing and capturing civilians ● Checking if an engineer of ACU is ‘available’ – I’ve expanded logic to cover if the unit state is capturing based on similar changes made to M27 (e.g. in case I add in capturing logic to M28 at some point). ● I then decided to copy over M27 logic for temporarily highlighting at the start of the game civilian structures (to give the AI similar ‘memory’ to a human player). ● Although I started copying over the logic for identifying targets to capture from M27 I decided I wanted to redo this, to make use of the land zone logic, so will park as a future todo option since it’s such a niche improvement and took a lot of time to get working for M27 (although that was largely due to the civilian ‘temporary reveal’ issues). With thanks to Balthazar for clarifying how to give a unit temporary vision: https://github.com/The-Balthazar/BrewLAN/blob/master/mods/BrewLAN_RNG/CrateDrop/hook/lua /sim/ScenarioUtilities.lua#L215 I used this approach as there were issues with the reliability of the approach used by M27/RNG 2.30) Competitiveness My plan to get M28 to a basic level of competitiveness is to pick a selection of maps that at least one of RNG or DilliDalli performs well on, along with maps that M27 typically tests itself on, and for each one have a random faction matchup against both RNG and DilliDalli. If M28 loses then I keep making changes until it either wins the replay or survives to the end of it in a winnable position, at which point I do a new replay with random factions and repeat the process until M28 wins. 91 i.e. it’s not about making sure M28 can win a majority of the time on every one of the maps, but just that it is at least capable of winning a game, with the hope that if it is capable of winning on every map it means that on the majority of maps it will have well above 50% win rate, and it will only be some of the harder maps that it is below 50%. 2.30.1) VS RNG on maps suited to RNG Crash site - performance I chose this map as I know it’s one RNG has been tested on a lot so should prove a fair test for M28. M28 has also lost vs RNG on this map relatively recently when I did a quick test (which is good since it’s easier to learn from a loss than a win). ● ● ● UEF mirror -The first game was a UEF mirror and despite very different styles and focus there was little to separate the two AI, and the game could’ve gone either way. It ended up lasting 44m with multiple experimentals built, but M28 just edged it (in no small part due to its fatboy surviving in a 1on1 fatboy dual with a sliver of health). What was interesting was that despite M28 maintaining double RNG’s mass kill values in the early-mid game, and having similar eco, it wasn’t able to increase its eco lead (and actually fell behind slightly) – e.g. it would end up sacrificing its mexes to protect its mongeese. I don’t think this is wrong, but it highlights the impact of different playstyles. Seraphim Mirror: M28 frequently lost during testing, although did sometimes manage wins; after making all the below changes I did one full game and M28 won a very hard fought battle after 1 hour 2m; however fixing a minor bug that caused the replay to desync resulted in an RNG win. Crash site - Changes made (these were issues I spotted with M28 while watching replays relating to the above): 1. Increased likelihood ACU will reclaim wrecks that are within its build range. 2. ACU should build on mexes inside its build area even if it’s still on its initial build order. 3. Improved initial build order and fixed bugs with tree reclaim so engineers will now try and reclaim trees to prevent power-stalling while constructing a hydro. 4. Fixed AirAA run logic so it will now run from groundAA (previously there were bugs with this) 5. Gunships should ignore land scouts (which bypasses the issue of them trying to target a selen that became cloaked after M28 became aware of it). 6. Added logic to assist air factories once T2 air has been reached. 7. When placing initial factory, if is a hydro in the same zone, then build the factory as close to the hydro as possible while retaining mex adjacency and being in build area and not being on reclaim. 8. Added similar approach to M27’s initial logic (before complexities were added) for deciding on the location of T2 PD. 9. Made sure engineers are only built if the factory’s land zone is requesting more engineers (as they were getting massively overbuilt if for a split second it looked like we had lots of mass, but early-game mass storage %s can fluctuate quickly) 10. Most buildings should try to build close to the midpoint of a zone 11. Fixed shields should have a maximum search range based on the highest radius of the shields available to the building engineer. 12. Increased the initial tanks to be built as a high priority once a certain number of engineers have been built. 92 13. Made sniperbots (particularly seraphim bots) much more cautious when they outrange the enemy so they’re less likely to die when kiting an enemy land experimental (although they still can since theyre slower). Overall I’d say M28 probably has a c.50% win chance against RNG on this map which is good enough for an initial release. Inquisition - performance ● Initially in an Aeon vs Aeon mirror M28 narrowly lost (it was at a 1:3 eco disadvantage for the entire game but managed to get amazing value from its units, only dying because the enemy built a GC that it only whittled down to half health before it reached M28’s ACU). ● Trying with random factions (Sera M28 vs Cybran RNG), throughout the below changes M28 managed to win a couple of times but lost 90% of the time. ● However, changing factions to random again (this time UEF mirror) M28 got a fairly convincing win – it was ahead early, fell back slightly mid-game, then slowly obtained a dominant position. ● More generally as with other replays it highlights the difference in design philosophy – M28 was able to have a 2:1 to 4:1 kill ratio to RNG consistently while not being far off RNG on eco, yet couldn’t translate that into an eco lead as RNG’s aggression and M28’s conservativism with its units would lead to RNG having map control and threatening m28’s mexes. Inquisition - Changes made: 1. Fixed gunship spacing to be more of a square than an x 2. Increased priority of T2 air fac upgrade 3. Added in a new PD builder for when non-ACU ground threats are close to base. 4. Added a high priority engineer builder for air factories when high on mass even if ground enemies are close (now that engineers can help by building PD) 5. On non-5km maps M28 should aim to only have 4 factories until it reaches T3, and should try and be upgrading a mex almost at all times. 6. If enemy has T3 air and we lack T3 SAM in a core base then build as a higher priority than power unless we have air control 7. MAA should no longer be built if the enemy is still at T1 and has no air to ground air threat. 8. Added a build cap on the number of active T1-T2 gunships of 80, and added backup logic to build strats if we are about to overflow mass (with lots of mass). 9. AirAA units should ignore enemy groundAA when deciding whether to protect a friendly experimental or ACU if the enemy has an air to ground threat nearby. 10. Engineers that are the primary builders can’t be reprioritised. 11. If an engineer is assisting an under construction building and there are no existing engineers assisting it, that engineer should be treated as the primary builder. 12. If the ACU is told to retreat to base, but has no nearby enemy experimental, it should consider attacking very nearby units and/or getting upgrades. If there is a nearby experimental then the ACU should run to the nearest fixed shield. Osiris This map is one of the few I’ve come across where RNG can beat M27 at 1.0 a significant proportion of the time, so I want to test M28 on it to see how it performs. 1. I came across an issue where 2 battleships stopped firing when near the naval factory and just sat (with move orders that weren’t followed) until they were killed. My hope is that having them try a specific unit attack order where this happens (and their shot isnt blocked) 93 may help mitigate this to some extent. I.e. battleships that haven’t fired for a while and are near the rallypoint should try an attack order on the nearest enemy unit. 2. Fixed a bug where frigates were being used as scouts far too early. 3. Changed destroyer target prioritisation so they prioritise shield units M28 won as UEF vs RNG’s Aeon on this map (prior to changes being made other than the bugfix for frigates). Retrying with the factions reversed, M28 won even more convincingly. 2.30.2) High AIX modifier games Island Zero For a long time I was very confident that M27 could crush the default and Sorian AI on any map with any settings (absent settings that completely broke the AI/caused it to not function). Then I saw a video with an AiX 10.0 mod where M27 was nomads and died to Sorian AiX 10.0 AI. While this is an extreme scenario and essentially means ‘bad’ decisions (like trying to build 4 experimentals at once, ignoring reclaim, using the ACU aggressively early on) could end up being good, I suspect it should also reward effective mass management and spending at high eco levels (and so simulate scenarios on large maps with lots of mexes). I’d hoped to test vs DilliDalli or Sorian rush on the map where M27 failed, but both had errors so I’ll do M28 vs M27. Initially M28 lost to M27 (M28 UEF vs M27 Cybran), but after making the below changes it was able to win (and had a stronger position throughout, with better eco and land forces). Changes made: 1. One valuable thing this highlighted was that I’d forgotten to go back and add AiX modifiers when calculating the ‘income excluding reclaim’ values that M28 uses for most of its logic (leading to it thinking it was power stalling despite massively overflowing in energy). 2. Once engineers finish constructing something all engineers building that should be cleared (to avoid an issue on high AiX modifiers where engineers far away don’t reach the building before construction completes). 3. Allowed second power builder to trigger for T1 and T2 at very high gross mass levels 4. Second experimental builder if have at least 1.2k gross mass income, at least 5k stored mass, net mass of at least 8 per tick, and mass stored % of at least 50% (provided don’t have low power). Normally these will be built separately to the main experimental but will assist an existing construction if they end up trying to build T3 arti or game-enders. 5. When construction is started, any queued engineers with a different action whose construction will be blocked should have their orders cleared. 6. T3 and experimental arti and SMLs should be built adjacent to T3 pgens. 7. If we have at least 40 T3 engineers in a land zone then start ctrl-king T1 engineers in that land zone that aren’t primary builders to reduce pathfinding issues – To consider this, I want the aiBrain to have at least 100 engineers in total, and more than 10 T1/T2 engineers in a zone, and it will then consider ctrl-King 3 engineers each time a T3 engineer is built in that zone. 8. Units trying to retreat when in the core land zone should run away from the nearest enemy unit. 9. There’s an issue with FAF where a unit htat is partially underwater (e.g. a megalith) but still able to fire at surface units wont be fired at by units on move and attackmove orders. However, they will if given a direct attack order. Therefore, if I have units that outrange the 94 enemy, they should use a direct attack order if the nearest enemy is underwater. This helps in the scenario (which I saw in this replay) where a fatboy is faced with an enemy megalith that is partially underwater. o Testing in sandbox it looks like the fatboy is capable of hitting T1 subs (I didn’t bother testing for others but from memory they all travel along the same layer), but I held off implementing logic to ground fire these due to the risk it ends up ground firing subs that it no longer has intel on (which would feel unfair for a human player on the receiving end). 2.30.3) M27 pre release maps I want to check how well M28 does against RNG and DilliDalli playing on maps that I normally test M27 on prior to a release as a basic check of its competitiveness. Polar Depression ● Vs RNG (M28 UEF vs RNG Seraphim) – a surprisingly close game, I thought M28 was set for a comfortable win when it got to the early-mid stage with marginally more eco than RNG, but RNG managed to scale up its eco with M28 falling behind, to a more than 2:1 eco lead to RNG towards the late game. M28 then managed to slowly wear RNG down and maintain a greater than 2:1 kill ratio. After more than an hour, with numerous experimentals built on both sides, M28 won. ● Vs DilliDalli (M28 Sera vs DD Aeon) – Initially DD crushed M28. After many changes it looked like M28 likely would have won the replay (but it ended). Re-running resulted in an M28 UEF vs DD Aeon that DD won, but again after a change M28 looked like it would win. M28 finally won with the next replay (with no changes needed), being M28UEF vs DD Sera. Essentially if M28 survies against DD until it has T3 air and gains air control (which basically requires 2 Asfs since DD will send its intie swap over M28’s base to die to flak/sams) then M28 is favoured to win as DD has no answer to the ever growing gunship ball. Changes made: 1. I realised (after seeing M28 build a crazy number of TMD) I’d not got any code preventing TMD being overbuilt or even trying to ensure TMD gets built near a unit needing TMD coverage, so added this in (i.e. adding a cap of 10 TMD per zone, having TMD get built near the unit closest to the enemy base that wants TMD coverage, and not building TMD if it will be further away from the unit than the TMD range). 2. When a building completes construction, don’t keep repairing it. 3. Improved the PD build logic to make sure the PD gets built in the same land zone, avoiding issues where it would get overbuilt (due to being built in a nearby zone and not registering in the zone that wants the PD) 4. If have at least 5 land scouts, then cap the number of land scouts at an amount equal to the number of engineers we have 5. When looking for zones to send engineers to, those with unbuilt mex locations should be prioritised. 6. Increased the thresholds for the ACU to get reclaim not in its build radius, particularly early-game. 7. Increased the thresholds for starting upgrades, as at one point we ended up getting 4 T3 mexes at once at the core base (which only has 4 mexes). 8. Also adjusted the order of backup upgrades to be more likely to upgrade support factories instead of HQs. 95 9. Changed air factory so instead of being idle it is more likely to build engineers when there aren’t many engineers in the current zone (if it has the highest tech level). 10. Added new AA builder for if we have T2+ air factory and no T2+ fixed AA in base (even if the enemy has no air to ground threat). 11. Non-engineer units just built from a land factory should be told to move away from the factory for a second to reduce the likelihood they block the factory from building more units. 12. Given the ACU a 30s memory of zones it has run from, and zones it was trying to move to when it decided to run, so it avoids those locations for 30s (reducing the risk the ACU appears to constantly move towards somewhere then run a second later) Pelagial ● Vs RNG – An interesting and closely fought game as M28 Aeon vs RNG UEF, RNG won the island closest to M28 but M28 contested RNG’s island for some time before losing it. However M28 gained naval control and air control despite worse eco, and was able to use restorers to wipe out one of the islands. However RNG fortified the other with shielded flak (that eventually took a nuke to dislodge it) and rebuilt navy at the rear of its base (leading to a trap for any M28 navla units trying to assault it), managing to hold out with comparable eco for a surprising length of time despite M28 navy being on its doorstep. ● Vs DilliDalli (M28 UEF vs DilliDalli UEF) – A much easier battle for M28, winning both islands and then killing DilliDalli with T2 gunships. To be expected given DilliDalli doesn’t build navy or T2+ air. Twin Rivers (2vs2) ● Vs RNG – Although close at times (when M28 started upgrading in its base and RNG was able to push and kill one of the ACUs) for most of the game M28 was on top. However after fixing a bug M28 died to RNG Guncoms leading to a change to make them more scared if they are outgunned by the enemy ACU. ● Vs DilliDalli – A very close game – forst almost the entire game DilliDalli was in one of M28’s bases (for the first half the game the bottom-right player’s, with most core mexes dead, then the other M28 ACU died and had its main base mostly destroyed). It wasn’t until M28 got a handful of T3 gunships that it was likely to win. Changes made (despite winning): 1. Relaxed the MAA builder so even if the enemy has no air to ground threat MAA should still be considered once factories are at T2+. 2. ACUs should flee to base if they see that the enemy is getting an upgrade or has an upgrade, and we aren’t in the core base. 3. Adjusted gunship formation to remove the corners of the last part of the square to reduce the risk gunships on the edge cant fire at the target. 4. Units on a plateau or island should now move more randomly in the zone they end up in if there are no enemies and they cant reach the enemy base. 5. UEF and Seraphim Cruiser weapon firing priorities should prioritise enemy TMD and shields ahead of other units 6. Seraphim destroyers should surface if they start the game underwater Eye of the Storm ● Vs RNG (UEF vs Aeon) – comfortable win, with M28 winning land and navy (with neither player winning air). 96 ● Vs DilliDalli (UEF vs Aeon) – I missed most of the replay but it looked like a fairly comfortable M28 win for the part I saw (to my surprise as DilliDalli gave M27 grief for a long time on this map). Changes made: 1. Naval combat units should retreat if no friendly AA and enemy has nearby torps. 2. Anti-air submarines should surface or submerge based on nearby enemy threat. 3. Battleships should prioritise enemy structures and high value naval targets. Forbidden Pass ● Vs DD – DD proved a tough opponent winning numerous times initially – the base starts are just far enough away that M28 thinks it is safe to eco/tech, and then DD sends a stream of T1 tank spam into M28’s base before M28 has time to build enough T2 units. However this did expose some fatal flaws in M28’s logic where it would get multiple T3 upgrades despite having no T1 or T2 presence. Even after improvements, with M28 gaining air control and a gunship ball it looked like it could fail, as DilliDalli’s relentless stream of units from two sides meant the gunships at some points couldn’t keep up and tanks would seep into M28’s core base. M28 eventually won as Aeon vs DD Sera. ● Vs RNG (M28 UEF RNG Sera): RNG maintained a 2:1 eco lead for much of the game, but M28 managed an impressive 8:1 mass kill lead that increased to more than 10:1. When M28 eventually reached eco parity the game was effectively over. Changes made: 1. 2. 3. 4. Added high priority early game T1 air fac upgrade logic Tweaked low power flag so we are less likely to overbuild T1 PGens initially Made M28 more likely to eco early on 10km maps Added a minimum number of units for T2 land and air facs to have built before being considered for upgrading. 5. Fixed an issue causing M28 to think it had more factories than it actually had when a factory upgraded. 6. Increased energy requirements to get a 2nd HQ upgrade to reduce the risk that we think we have enough energy due to the 1st upgrade not yet having been started (e.g. if a land factory queues up an upgrade, while building a unit, then M28 will think it has more energy spare to start an air fac upgrade than it actually has). 7. Slightly increased requirements to build a naval factory. Floralis ● Vs RNG – It took a long time to get M28 to the position where it would win in a Cybran mirror replay – it basically required abandoning the ‘Eco and rush to T2’ plan in favour of a ‘build land factories and tanks for ages’ plan, coupled with making the ACU semi-suicidal. Even then the game went to the T3 stage. ● Vs DilliDalli – After how hard the battle against RNG was, and how long it took M27 to win against DD I was expecting a tough battle but M28 won on the first attempt (Aeon vs Sera) Changes made: 1. Toned down the emergency T2 upgrade for T2 PD in response to an ACU is the ACU doesn’t have any upgrades and our mass income is poor. 97 2. On small maps more land factories should be built, and built more aggressively, while slightly less power should be built. 3. Decreased threat thresholds for units to attack on small maps and if the ACU is in the current zone. 4. Reduced the amount of fixed AA to be built in the core base at lower tech levels. 5. Significantly increased ACU aggression on small maps. 6. Limited the number of engineers built on smaller maps to be based on the number of combat units. Open Palms ● Vs DilliDalli – A couple of very close games where DD won (one was due to a bug that caused M28 to stop building units at its land factory) before M28 won as Cybran vs Seraphim. ● Vs RNG (UEF vs Aeon) – At first I thought M28 had a comfortable win, but RNG got a GC to bring M28’s shielded ACU that was under a shield within a second of death before M28’s gunships took it down. Changes made: 1. Adjusted the logic for upgrading from T2 air to T3 air slightly more to require T2 air units to have been built (not just T2 units) before upgrading to T3 air, but to only have this check if the enemy doesn’t already have T3 air. 2. Allowed more emergency PD to be built against non-ACU threats if we have some mass stored and/or positive mass income Astro Craters ● Vs RNG (Cybran vs Cybran) – Comfortable win with M28 ahead on eco the entire game. ● Vs DD (UEF vs Aeon) – Comfortable win (as expected given M27 has managed to beat 2.0 DD on this map – i.e. it’s one of DD’s weakest maps) Changes made: 1. Fixed an oversight that meant the first land experirmental built by a Cybran wasn’t a monkeylord White_Fire ● Vs DD – Comfortable win ● Vs RNG – Comfortable win Setons Clutch (4v4) M28 won both games but they were much closer than expected: ● ● Vs RNG – A closer game than I was expecting, with M28 building a yolona in the rear air slot but RNG getting a GC and ythotha up to it and killing the nearby M28 ACU. Fortunatly M28 managed to kill the experimentals shortly after and its yolona proceeded to wipe out RNG. Vs DD – Also a close game – DD took out 3 of M28’s 4 bases (although only 1 of the ACUs), and M28 didn’t get its usual gunship deathball due to spending its mass on an experimental. I didn’t actually see the original replay through to the end as M28 was making incredibly slow progress with a megalith deathball inching slightly closer to DilliDalli’s rock and beach bases (M28 had control of both seas, navy, and far outmatched DD’s ground forces, along with a 3:1 eco advantage so it was only a matter of time before DD died). Changes made: 98 1. Fixed a few different bugs 2. Realised I’d not completed drafting logic for specifying a particular faction to build a unit (relevant at the moment for experimentals) so added in 3. Similarly realised I didn’t have any code drafted for allocating stealth boats so added this in. 4. When building antinavy units from a naval factory, ‘Plan B’ missile subs shouldn’t be considered. 5. Made it more likely for game-enders to be built at high counts of experimentals. 6. Experimental construction should be paused slightly sooner if there are nearby enemies (to allow other units to be built instead) 7. Added logic for the Engineer part of M28 to get mex upgrades, mainly intended for cases where we have a T3 mex or as a team have significant mass income, to make sure core base mexes are upgraded constantly if there are no nearby enemies, to help with faster eco scaling. 8. ACU orders – if no enemies in LZ, are in core base, and no land factories, then build a land factory 9. Don’t build more nukes if we already have 2 (or 1 on 10km and smaller maps) 10. Scathis should now be treated like a T3 arti instead of a mobile land unit that tries to move to the enemy 11. Scathis should now have a delay before being given a target to fire at to reduce the likelihood it firs a single shot and then aborts. Burial Mounds (1v1) ● Vs DilliDalli – DD suicided their ACU into the civilian PD ● Vs RNG – M28 won – I had this running in the background so didn’t see the game but it looked fairly close in that M28 had gunships at RNG’s base while RNG had a GC approaching M28’s (with M28 having nothing in response). Badlands (4v4) ● Vs RNG – M28 lost after a close battle (it got a T3 gunship deathball but couldn’t get a response to RNG’s T2 arti firebases that were able to reach its main base). However, this was in part due to some of the logic it had working fine for 1v1 but terribly for 4v4, for example with it seeking to get gun, nano then shield on a UEC ACU, along with upgrading T2 land to T3 while still having T1 mexes in base (because it was considering the total team’s mass income). After fixing this, M28 was able to win. ● Vs DD – I was expecting M28 to lose this but it had a comfortable victory, being equal or ahead on eco at the T2 stage and crushing DD as soon as it got sufficient T2 units (the only moment of concern being prior to this when DD took the fight up to M28’s bases). Changes made: ● ● ● New very high first T2 builder Updated priority factory upgrade logic to factor in the number of M28 players on the team for team resource thresholds (so factory upgrades aren’t started too early) Increased some of the ACU upgrade eco thresholds to factor in the number of teammates, and increased the thresholds generally for ACUs with 2 upgrades and multiple teammates. Africa (4v4) ● Vs DilliDalli – Another comfortable victory 99 ● Vs RNG – A closer battle, RNG killed one of M28’s ACUs and had roughly a 3:2 eco advantage for a long time, but M28 maintained a strong kill:loss ratio. RNG then surprised one of the M28 with an underwater Ythotha (claiming its second kill) AiX further test - vs Adaptive, Sorian adaptive, and Uveso Overwhelm ● Vs Uveso Overwhelm on Island Zero – M28 and Uveso were equal for much of the game; M28 had air and navy control, but Uveso flooded the pond with percies which soaked up M28’s navy’s attention, while M28’s massive (>100) restorer deathball couldn’t crak Uveso’s core base. M28 was undone initially by a bug with its SMD that caused it to stop reloading after 2 missiles. After fixing this and some other changes to make it spend its mass sooner when overflowing (including building gameenders and tempests) M28 was able to claim a comfortable win. ● Vs Adaptive and Sorian Adaptive on Finns Revenge – M28 had comfortable wins against both default AiXs. What was concerning was against Adaptive there was a massive slowdown every second or so. Enabling detailed logging didn’t reveal any culprit so I’m unsure if it was down to M28 or the adaptive AI (but am hoping the latter) Changes made 1. Missile firing buildings (SMD, SML, TML) should be unpaused whenever they fire a missile. 2. Added new builders for tempest, atlantis, and an independent game ender builder (so in very high mass scenarios in theory 4 experimentals could be built at once, even if most of the time 1-2 will be built). 3. Increased the number of naval factories in very high mass scenarios. 4. Updated strat placeholder logic to target T2 or T3 structure and make use of the torpedo bomber logic to factor in strike damage 2.30.4) Pre-release further tweaks 1. Changed the colour of the eyes from M27 so there’s a slight difference in the mod icon 2. Added some initial greeting messages and some on death messages, including a reference to M27 being better 3. Made mobile shields and stealth a lower priority than other units wanted for a land zone 4. Made MML much higher priority if the enemy has a nearby ACU and T2+ structures 5. Fixed a bug causing massive T1 PD overbuild if the enemy ACU got close before we had T2. 6. Fixed a bug where TML that were paused wouldn’t fire the extra built missiles. 7. Reduced PD wanted in response to enemy Guncom to 1.75 of the threat (so e.g. against a nano-gun UEF ACU we should get 4 T2 PD instead of 7) 8. ACU more likely to run from enemy guncom. 9. TML shouldn’t be paused if they have no missile loaded 10. More shields should be built if the enemy has a significant air to ground threat. 11. Delayed initial greeting slightly 12. 1 tick delay added for factories if a factory in the same zone has built something in the last tick (to avoid issue where we have 4 air facs, don’t build anything due to lack of power, then build asf on all 4 at once once get power, and think each time we have enough power because the power requirements of those started in the same tick aren’t factored in) 13. T2 arti in response to high range enemy units (>=65), amount based on their threat, and our threat – e.g. moving outwards for each zone 14. T1/T2 radar should be ctrl-k’d when it becomes obsolete 15. Slightly relaxed the thresholds for not building any more MAA 100 16. Lowered the limit on bombardment units to be built, and added a high priority cruiser builder if we have 3+ destroyers and no cruisers. 17. Naval factories should no longer be built in low value ponds. 18. Gunships should engage enemy experimentals approaching a core base as a relatively high priority, even if the experimental is protected by AA. 19. Increased the max enemy AirAA required to make restorers flee. 20. On 10km and smaller maps even if the enemy base takes a long time to travel to M28 won’t go into full ‘eco/mass engi production’ mode at the start and neglect tanks entirely. 21. M28 should exit energy stall mode early-game if it has built more power from when it last stalled; it should also be less likely to go into energy stall in the first 2 minutes, requiring 0.1% energy storage instead of 5%. 22. At least 1 gunship should be built even if we have low power if enemies are near to the air factory. 23. If we have available gunships and no AirAA threat then the gunships should be restricted to only fighting by ground to air or adjacent to a core base, in case the enemy has an AirAA threat. 2.31) Pathing optimisation Polar depression load time improvement – initial setup FAF servers were down for longer than expected so I figured I’d have another look at the pathfinding to see if there were any improvements that wouldn’t impact too much on accuracy given how long some maps like polar depression take to calculate. Performance with current process: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=133.69367980957 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=132.0138092041 info: ProfilerOutput: No.3=AssignSegmentsNearMexesToLandZones; TimesRun=1; Time=102.55484008789 info: ProfilerOutput: No.4=AssignMexesALandZone; TimesRun=1; Time=11.381332397461 info: ProfilerOutput: No.5=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=9.1100463867188 info: ProfilerOutput: No.6=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=278; Time=9.0962219238281 info: ProfilerOutput: No.7=RecordPathingBetweenZones; TimesRun=1; Time=8.9162902832031 info: ProfilerOutput: No.8=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=2450; Time=8.909912109375 So clearly the area for improvement is assigning segments around mexes to land zones. It also highlights that I do need to do something about this – taking more than 2 minutes on a very fast CPU to load means worse cpus presumably could take 4+ minutes on a 10km map 1v1. 101 M28’s current pathing approach (summarised) ● Divides the map into 'segments', which are small squares based on map size (e.g. 10km I think is either 1x1 or 2x2 in size) ● Groups the map by plateaus (i.e. amphibious/hover pathable areas) that contain mexes ● Assigns each mex to a 'zone' - nearby mexes are grouped into the same 'zone' ● Cycles through each mex in the plateau being considered ● For each mex, it then cycles through each of the segments around that mex (up to a particular search distance, e.g. a distance of 85) and checks how long it takes to path to the mex by land, vs how long it takes by air ● If the land pathing is within 15 of the search distance (e.g. 100) then it records that mex's zone as a potential zone of interest, and records how long it would take to travel to the mex by land ● Once it's finished doing this for every mex, it goes through the values it recorded for land travel distance by mex for each segment, and assigns each segment to the closest (by land travel distance) mex Faster alternative approach Jip helpfully suggested a far quicker alternative approach to this that avoided the need to calculate travel distance at all: ● ● ● ● Start at each mex position Consider the 4 adjacent ‘segments’ to this, and if they are pathable, simultaneously with all other mexes, and (if pathable) assign them to the same zone Then move on to each adjacent segment to each of the preceding pathable segments and repeat the process Jip drafted some code to achieve this but I wasn’t able to get it to work for my use case (either I was using it wrong or it was complicated by how I was handling references to segments) so I rewrote in a probably slower but easier for me to follow way. The result is instead of taking 102.5s to assign segments near mexes, it took just 0.12 seconds! There were a few complications in getting the approach to work though: ● ● My segment sizes on a 10km were 4x4 compared to the 1x1 of the Navmesh. Therefore it was possible that two 4x4 squares would both be in the same land pathing label, but they might be either side of a cliff that is missed because it is less than 4x4 in size. I therefore added logic to check the level eveyr single point in a straight line between the two 4x4 squares. FAF’s navmesh would return a land pathing label for locations that weren’t pathable (in case it was a unit that was close to a cliff). Jip kindly agreed to add a new function that would just return the expected land pathing label for the position (and not try and search for the nearest valid pathing label). To avoid needing to delay M28’s release for this, I’ll do a copy of the code in the meantime and can patch M28 to refer to the FAF definition at a later point. This is what was generated prior to the new label: 102 i.e. you can see zones in most cases are being created ignoring cliffs (which isn’t wanted). This is the result after the new label: 103 i.e. the zones are now reflecting cliffs that break the pathing. Initial performance results Log after putting in an alternative calculation (‘ThirdAltAssignSegmentsNearMexesToLandZones in the below log, which replaces the previous ‘AssignSegmentsNearMexesToLandZones’ function): info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=25.735855102539 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=24.262310028076 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=9.7822494506836 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=7.9220657348633 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=2352; Time=7.917064666748 info: ProfilerOutput: No.6=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=6.417652130127 104 info: ProfilerOutput: No.7=RecordTemporaryTravelDistanceForBaseSegment; TimesRun=3291; Time=6.3633232116699 info: ProfilerOutput: No.8=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.12160491943359 Applying similar approach to the rest of the land zone creation logic Given these massive performance improvements, I want to try the following: ● Use a similar approach for ‘AssignRemainingSegmentsToLandZones’ (i.e. this currently takes 6.4s per the above) o When doing this, to avoid tiny zones I’ll copy the zone of a nearby segment that already has a zone for up to half the segment search distance (so effectively extending existing land zones by half the search distance, or creating new zones at the full segment search distance). After reflecting this, the results for polar depression are: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=18.589544296265 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=17.096019744873 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=10.234748840332 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=6.6568431854248 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=5174; Time=6.6492786407471 info: ProfilerOutput: No.6=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.17839050292969 info: ProfilerOutput: No.7=GetMapWaterHeight; TimesRun=1; Time=0.042026519775391 info: ProfilerOutput: No.8=GetCombatThreatRating; TimesRun=8890; Time=0.041606903076172 info: ProfilerOutput: No.9=GetAirThreatLevel; TimesRun=16510; Time=0.026054382324219 info: ProfilerOutput: No.10=AltAssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.016372680664063 I.e. ‘AltAssignRemainingSegmentsToLandZone was used instead of AssignRemainingSegmentsToLandZone, with the new function taking 0.016s vs the old function taking 6.417s. Water zones Previously my water zones used a simple approach of requiring the segment to be pathable, but not worrying about how long it would take to travel there. If I was to use a similar approach to the land zones then it should allow blocking terrain to be taken into account. Currently Pelagial loads very quickly, with the following results: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=6.1898040771484 info: ProfilerOutput: No.2=RecordIslands; TimesRun=1; Time=3.330696105957 105 info: ProfilerOutput: No.3=RecordClosestAllyAndEnemyBaseForEachWaterZone; TimesRun=2; Time=2.3944473266602 info: ProfilerOutput: No.4=SetupWaterZones; TimesRun=2; Time=1.1941375732422 info: ProfilerOutput: No.5=RecordWaterZonePathingToOtherWaterZones; TimesRun=1; Time=1.1399459838867 info: ProfilerOutput: No.6=SetupLandZones; TimesRun=3; Time=0.21800231933594 info: ProfilerOutput: No.7=AltAssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.11338043212891 info: ProfilerOutput: No.8=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.061996459960938 I replace it with the following logic: ● ● ● As before, create water zones for any underwater start positions, and assign the nearby segments to this water zone Then divide the map up into intervals, finding the nearest water position to every interval. The main difference, is instead of assigning any nearby entry that is in the same pond to the water zone, I’ll instead check the NavUtils water result when considering all starting interval points simultaneously (i.e. considering the 1st adjacent segments; then 2nd adjacent segments, etc.) The log after these changes is: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=6.8587608337402 info: ProfilerOutput: No.2=RecordIslands; TimesRun=1; Time=3.5790138244629 info: ProfilerOutput: No.3=RecordClosestAllyAndEnemyBaseForEachWaterZone; TimesRun=2; Time=3.1335601806641 info: ProfilerOutput: No.4=SetupWaterZones; TimesRun=2; Time=1.5646324157715 info: ProfilerOutput: No.5=RecordWaterZonePathingToOtherWaterZones; TimesRun=1; Time=1.1829566955566 info: ProfilerOutput: No.6=CreateWaterZones; TimesRun=1; Time=0.37642288208008 info: ProfilerOutput: No.7=SetupLandZones; TimesRun=3; Time=0.22396850585938 info: ProfilerOutput: No.8=AltAssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.11511611938477 info: ProfilerOutput: No.9=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.066295623779297 I.e. the time to setup water zones has increased slightly, but not massively, so I think the benefits to accuracy warrant this change. 106 Increased resolution The next change I want to consider given the time savings is increasing the segment ‘resolution’ size – currently each segment is a 4x4 box on a 10km map, and ideally I’d like it to be 2x2. On a 10km this would mean 65.5k entries, vs 16k from 4x4. Testing with 2x2 size: Testing on polar depression gives the following results with this change: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=18.795766830444 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=17.228979110718 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=10.103311538696 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=6.5982322692871 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=4302; Time=6.5912971496582 info: ProfilerOutput: No.6=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.47310447692871 info: ProfilerOutput: No.7=GetMapWaterHeight; TimesRun=1; Time=0.042203903198242 info: ProfilerOutput: No.8=GetCombatThreatRating; TimesRun=8890; Time=0.041923522949219 info: ProfilerOutput: No.9=AltAssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.040422439575195 i.e. before it took 18.6 to setup the map, now it takes 18.8, so there’s been barely any change. Trying again this time with a cap of 120k entries (almost 5 times the current 25k entries), i.e. 1x1 on a 10km, or 3x3 on a 20km: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=18.685972213745 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=17.150274276733 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=10.107316970825 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=6.5250091552734 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=4302; Time=6.5181579589844 info: ProfilerOutput: No.6=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.46537780761719 info: ProfilerOutput: No.7=GetMapWaterHeight; TimesRun=1; Time=0.041728973388672 info: ProfilerOutput: No.8=GetCombatThreatRating; TimesRun=8904; Time=0.041591644287109 info: ProfilerOutput: No.9=AltAssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.039133071899414 So again barely any increase (although there is a margin for error with these estimates – it took 20s on 2x2 sizing on a separate replay on the same map, polar depression). I’ll therefore stick with this size (i.e. 1x1 for 5km and 10km, 3x3 for 20km, 12x12 for 80km 107 Setons Clutch – time taken Testing with these settings on Setons Clutch gives the following results: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=16.968250274658 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=14.395324707031 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=10.605827331543 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=2.8388862609863 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=8126; Time=2.8275909423828 info: ProfilerOutput: No.6=RecordClosestAllyAndEnemyBaseForEachWaterZone; TimesRun=2; Time=1.8834114074707 info: ProfilerOutput: No.7=SetupWaterZones; TimesRun=2; Time=0.93829345703125 info: ProfilerOutput: No.8=CreateWaterZones; TimesRun=1; Time=0.86266326904297 info: ProfilerOutput: No.9=AltAssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.55030059814453 info: ProfilerOutput: No.10=ThirdAltAssignSegmentsNearMexesToLandZones; TimesRun=1; Time=0.37235832214355 I.e. it’s within the acceptable time limit for generation. 2.31.1) Check of performance on other maps As a final sense check of how M28 compares to RNG and DD, I wanted to pick a selection of maps in the current ladder pool and see what it’s win rate is (i.e. this is in contrast to before where I would re-run a replay again and again until M28 got a win in some cases). Unfortunately with FAF down at the time of doing this I couldn’t use the latest map pool; however when testing M27 for v41 I’d noted its performance against RNG and DD on a selection of maps which I think were mostly in the pool at the time, so I’ll do the same for M28, although in the end I got bored and just did M28 vs RNG matchups. The maps I ended up doing were: M28 won 15 of the matches, RNG won 4, with a mix of 5km 10km and 20km maps although the majority were 5km. The maps where RNG managed a win were Loki, Serenity Desert Small, Saltrock Colony, and Forbidden Pass (although M28 also managed wins on all of these except Saltrock Colony where I only did the one match). As a general rule, M28 had comfortable wins on larger (20km) maps and maps with navy. On small maps RNG would usually win the T1 stage and end up with a 2:1+ eco advantage. M28 then would usually claw back that advantage slowly with gunships and T2+ units, or RNG would have such an advantage that it would overwhelm. Sometimes RNG would win just as M28 looked to have equalised on eco, by getting a land experimental or early strat before M28 was able to finish recovering and build up enough gunships or AA to deal with the treat. The full results are as follows: 108 Row Labels 2v2 - Serenity Desert Small – FAF version Adaptive Hardshield Oasis Auburn Canyon Crossfire Canal - FAF version Forbidden Pass Loki - FAF version Paradise 2v2 Point of Reach Saltrock Colony Theta Passage M28 won 2 3 2 1 1 1 1 1 RN G wo n 1 1 1 1 3 2.32) V2-v3 - M28 in the FAF Campaign 2.32.1) V2 Hotfix Thanks to Relent0r who mentioned M28 wasn’t building tanks unless it had intel of the enemy – there was a bug where it thought it had built 0 of every unit leading to it always building engineers. 2.32.2) V3 - Misc changes and bugfixes ● ● ● ● ● Fixed a bug with PD placement logic – previously it would start near the base and move towards the enemy when looking for a valid location; now it will start near the base and move closer to the base. I.e. this means engineers should no longer try and build PD miles away from the existing land zone. M28 wouldn’t work with AiX modifiers in some cases where the AiX modifier was nil, e.g. on a campaign game. Strategic bombers should have an increased search range on very large maps or in large numbers, and idle bombers should return to the rally point. ACU should only get a build location once – previously it would get every cycle, and then not process if the order was for the same location. However, it would also exclude queued buildings when picking a location, leading to it alternating between building in one location then another location on repeat (if the location wasn’t in its build range). If the ACU can’t find a location that it can build immediately for a land factory (with mex adjacency) it should try and find a location without any adjacency. 2.32.3) Black Day Identifying if a map is campaign Doing logging of the ScenarioInfo.Options table on a campaign map it provides the following values which looked like they might work as proxies for figuring out if it is a campaign map (this was with myself in the first slot and M28 in the second slot on the first FAF campaign map) : Difficulty: 1 info: iEntry=save; vValue="/maps/x1ca_coop_001.v0028/X1CA_Coop_001_save.lua" 109 ScenarioFile: /maps/x1ca_coop_001.v0028/x1ca_coop_001_scenario.lua Other values of potential use: info: iEntry=HumanPlayers; vValue={ table: 2EE1B870 Player1=1, Player2=6 } info: iEntry=size; vValue={ table: 2E6D5D98 1024, 1024 } By contrast, on a non-scenario map the same values were: info: iEntry=save; vValue="/maps/astro_crater_battles/astro_crater_battles_save.lua" debug: - Difficulty: 1 [I think this is a value for one of the various mods I’ve got downloaded] info: - ScenarioFile: /maps/astro_crater_battles/astro_crater_battles_scenario.lua There was no value for HumanPlayers info: iEntry=size; vValue={ table: 1C1C0BB8 512, 512 } However Hdt80bro helpfully provided a more reliable method – checking the ScenarioInfo.type value, which is “skirmish” for skirmish maps (including matchmaker), and "campaign_coop" for campaign maps done via co-op. I also added in a 0.5s delay at the start of the game before running M28 logic since Hdt80bro highlighted how the brain creation happens before some of the campaign/map information is loaded. ● However, this caused an issue as M28 would call the default brain create logic if a non-M28 brain was created, and the delay meant the flag for if a non-M28 brain was created wasn’t being set, leading to both M28 and non-M28 logic running. Changes made ● Refined how M28 views civilians so on a campaign map it will only treat brains with “civilian” or “Civilian” in their name or nickname as civilians (in addition to the other checks M28 does). ● Changed the initial player greeting to reflect it’s a campaign, and delayed it until M28 has an ACU ● M28 wouldn’t appear to ‘see’ enemies when the playable area expands – i.e. it is based on the original playable area. I therefore need an approach that will be compatible with changes in the playable area size. o Searching the FAF database I’m assuming the following function (which changes the playable area) will be called by campaign maps when the map expands: o fa/lua/ScenarioFramework.lua function SetPlayableArea(rect, voFlag) o I therefore want to hook this function so after it has run I can update M28’s record of the playable area (which, at a basic level, should at least allow it to send units to the enlarged playable area). o For now I’ll try with the approach of having M28 start off generating land zones as though the entire map is playable, and then switch to only allow units to move 110 ● between the currently playable area; when the playable area changes I’ll then update the recorded playable area. At the start of the first mission the first player gets given all of the remnants of the base, including T3 PGens and T3 mexes. A human player is forced to be in the first slot, and the ability to gift units to a teammate is disabled. Therefore M28 is prevented from gaining resources to build up (beyond reclaim and what it builds itself), causing its progress to be heavily stalled. I therefore want to allocate units to M28 at the start of the game using the following approach: o When an ACU is identified, if it’s a campaign map start a forked scrip to check for friendly buildings. o Every tick, check for allied units within 250 of the ACU position. And abort the code after 5 seconds o If units are found, start a new script to divide up friendly units: ▪ Calculate the number of human players, and M28AI players, and work out the nth unit to give to M28AI (e.g. if 50% of players are M28, n will be 2; if 75% of players are M28 n will be 4) ▪ Group all units by blueprint in a table, only grouping those non-ACU units owned by a human brain ▪ ● ● ● Cycle through each blueprint table entry. If there is more than 1 entry in the table, then cycle through each entry, and allocate the nth entry to M28AI ● If there’s more than one M28AI, allocate it to a random M28AI. During testing one issue that arose was enemy brains that had a start position outside of the playable area. M28 would try and get the plateauland zone of that location and come across an error. This highlighted a flaw with M28’s logic, as it divides the map into ‘segments’, but it bases these segments on the playable area rather than the overall map size. I therefore want to review all use of my PlayableArea logic and have a separate variable for the potentialplayablearea – on campaign maps this will be the entire map size, on other maps it will be the main playable area. One issue this exposed on non-campaign maps is that delaying when some of the m28 initial code runs until later means it thinks M28 AI aren’t in the game Campaign doesn’t allow use of AiX modifiers, meaning if an AiX AI is selected it causes an error as M28 tries to interpret a nil value. I therefore added a lobby option for AiX up to 1.0 for the ally, along with backup logic where if it’s nil then it will manually set the buff to 1.5. Given the bugs encountered during this (the main one being an error in certain water map zone creation which could break the entire AI) I’ll release with only these changes for now rather than improve its campaign performance to a decent level. 2.33) V4 – Further campaign improvements 2.33.1) Bug fixes 1. Added in some redundancies to code to check for when there are no longer any active M28 brains. 2. Updated some of the team handling logic to make sure it is only running for teams containing an M28 brain. 111 3. Fixed an error in the code that could have sometimes occurred when trying to build shields 4. If the enemy base was in water then a T2 land factory trying to build something when a T3 factory existed could cause an error. 5. Expanded the check on unit restrictions being present to reference a separate setting (as campaigns don’t make use of the scenario.options setting for unit restrictions, which was what I was checking previously). 6. There’s an issue where a separate AI is giving my factories assist orders causing them to not build anything. As a partial preventative measure, my factories will be treated as idle if their unit state is guarding (more for redundancy). 7. In addition, I’ve added various hooks to try and prevent base AI taking control, requiring 3 different sets of code to cover the current FAF, FAF develop, and then soon to be released FAF develop changes all of which impact on where the code running base AI logic appears. 8. M28 brains should update the primary enemy brain base location when a player dies if the nearest enemy base brain is dead. 9. When there were no enemy units in the pond the navy was meant to try and move elsewhere to support but there was a bug cuasing it to do nothing. 10. Fixed a bug where a flag for whether to avoid groundAA when protecting ACUs and experimentals wouldn’t reset (which in theory could have caused an issue with multiple experimentals in different scenarios). 11. When searching for buildable locations in a water zone, one of the lines failed to flag it was a water zone (resulting in errors). 12. One of the unit cap checks that would reset it was inverted, meaning it would immediately reset the flag that M28 was close to the unit cap limit (instead of requiring a bit of headroom before changing the flag). 13. Mass and energy stalls should now factor in the highest build rate cheat modifier on the M28 team if the brain has cheats enabled (i.e. its an AiX brain) – previously build rate modifiers were ignored. 14. It looks like if engineers are told to assist a T2 factory, and that factory upgrades to T3, the engineers will stay assisting it. This causes an issue for my tracking, as I track what units are assisting a factory against the factory itself, but if a factory upgrades, the T2 factory unit is destroyed and replaced with a T3 factory unit (that doesn’t contain this information). I’ll therefore have M28 treat engineers as available if their last order was to guard a unit that no longer exists. 15. Power and mass stall managers were failing to calculate the mass/power saving achieved on upgrading mexes. 16. Power and mass stall managers should no longer incorrectly calculate the mass/power savings as being 10% of the actual saving for certain units (engineers and upgrading units) 17. Anti-air submaraines (e.g. seraphim submarines) should more reliably surface when faced with enemy torpedo threats. 18. If there are submarines in a zone but no non-submarine units, the submarines should still get orders. 19. Seraphim submarines and atlantis should no longer be treated as AA units but instead as submersible combat units. 20. There was an error in one of the eco tests if an experimental factory was built (e.g. as a result of mods). 21. Yolona Oss should no longer be paused even if it has no targets. 22. Water zone generation logic contained an error that conflated segments with positions. 112 23. When air rally points were considering locations underwater they used the wrong reference for water zones which could lead to no valid rally point being identified and various resulting errors. 24. Fixed several tracking errors that resulted in my profiler providing incorrect results for how long a function was taking. 2.33.2) Misc changes 1. Retreat low health shielded units (titans, obsidians, etc.) – previously only units like fatboy would be retreated. However such combat units will retreat when their shield is much closer to being depleted compared with a fatboy. 2. Added a higher priority AA builder for minor zones that contain T2+ mexes that are under enemy air attack. 3. Added a cap to the number of experimental naval units to be built. 4. If unit restrictions are present and we failed to build an experimental level unit, then a random experimental level unit should be built instead if we have at least 35% mass stored. 5. Further factories shouldn’t be built if we have recently failed to find anything to build from the factory. 6. Add builder to build land experimentals in water if we have very high mass and income, and already have at least 4 T3 navy/experimental units. 7. If we tried building an experimental and failed, and unit restrictions are present, then a random experimental should be built. 8. Added in Quantum gateway builder if we are AiX 1.2+ or in campaign, and all mexes in the zone are T3, and we don’t have low mass and have no quantum gateway in the zone. 9. Added simple logic for RAS SACUs, so they help with fighting if units are in the same zone as them, otherwise they assist a unit (e.g. the quantum gateway; an air factory; shields; or an active upgrade) 10. Adjusted AirAA thresholds to be more likely to engage when there are low levels of enemy ground AA threats. 11. AI Teammates on campaign maps would often have start positions that weren’t pathable or were outside the initial playable area (e.g. the Order on mission 2). I’ll therefore only include such locations in the ‘nearest friendly base’ that is recorded at the start of the game if it is pathable, and is inside the playable area. 12. Sometimes land zones could be close enough for AA in them to hit a zone that wasn’t adjacent to it, so I’ve added a backup to look for a single point at 90 degree angles when searching along a path for zones that could be in range of air travel paths. 13. Increased the enemy AA threshold required to make gunships run if their last order was to attack. 14. Adjusted the flag that means no MAA get built to be based on MAA threat rather than total ground threat to see if it resolves issues where M28 would fail to get MAA to support experimentals. 15. Some unit cap mods change the army unit cap rather than the scenario.options unit cap, so I’ll check the unit cap for a particular army rather than the scenario settings to work out the unit cap for an M28AI. 16. Engineers should now try and build the same building at the same location instead of assisting the building engineer so the building sometimes gets started on slightly sooner. 17. Factories with nothing to build should have any assisting engineers clear their orders. 18. Fixed a mod compatibility issue where the indirect fire range on units with no range category wouldn’t be recognised. 113 19. Increased SMD pause threshold based on total enemy nuke launchers – i.e. 2 + 1 for each enemy nuke launcher Optimisations Fearghal provided a replay where M28 would suffer major slowdowns late game. I therefore made the following optimisations in an attempt to reduce this: ● ● ● ● ● ● ● Blacklist build locations are only done for a specific location rather than an area. Theyre also recorded by location, so instead of needing to check every blacklist location I only need to check for 1 particular entry in the table. I’ll also no longer track the type of blacklist (i.e. if I want to ‘reserve’ a location then I’ll have to come up with other logic/tracking table, e.g. having it return a value to indicate the type of reservation – currently it just returns true) Engineers with the same order – I removed the distance check done as part of this and will rely on the ‘queue reference’ that is used. Slight reduction in the number of checks idle factories will do (I highly doubt this will have a noticeable impact but thought there little harm) Engineer logic should be significantly curtailed once there are no more locations to build. Added spare engi logic to account for scenarios where the first engineer builds on the last available build space leading to no further engineers being assigned – if not got low power or mass then assign every engineer to the nearest under construction building. Queued buildings – In addition to current tracking, I’ll now track the queued location using tables for each location against the relevant land zone, to hopefully provide a faster lookup option than doing a distance check when there are multiple queued buildings in a zone. A very rough (and somewhat unreliable) comparison with the replay I was dealing with at the time suggested this may have reduced the time required by 19% overall for this function (although this will be somewhat offset by a slightly increased time on the tracking functions). Reduced the extent to which building locations get refreshed. When checking the (now deynced) replay I noticed a massive pause at one point, and for once the function count was really high: info: ProfilerOutput: iTick=20307: No.1=GetCurrentAndMaximumShield; TimesRun=38022; Total Time=38022 info: ProfilerOutput: iTick=20307: No.2=IsTargetUnderShield; TimesRun=5396; Total Time=5396 info: ProfilerOutput: iTick=20307: No.3=GetDamageFromBomb; TimesRun=25; Total Time=25 i.e. despite only trying to get the damage from 25 bombs, we were checking the shielding on 38k units! Trying to debug every instance would be impractical so I decided to log where every 100th call to GetCurrentAndMaximumShield was taking place, and only once the count in a tick exceeded many thousands of entries. Summarising this in Excel resulted in the following line counts: mods\m28ai\lua\ai\m28building.lua(1375): in function <...er forged alliance\mods\m28ai\lua\ai\m28bui mods\m28ai\lua\ai\m28logic.lua(508): in function `GetDamageFromBomb' mods\m28ai\lua\ai\m28unitinfo.lua(979): in function `GetCurrentAndMaximumShield' 114 mods\m28ai\lua\ai\m28utilities.lua(54): in function `ErrorHandler' mods\m28ai\lua\ai\m28logic.lua(291): in function `IsTargetUnderShield' mods\m28ai\lua\ai\m28logic.lua(505): in function `GetDamageFromBomb' An example audit trail is: warning: ...r forged alliance\mods\m28ai\lua\ai\m28utilities.lua(54): in function `ErrorHandler' warning: ...er forged alliance\mods\m28ai\lua\ai\m28unitinfo.lua(979): in function `GetCurrentAndMaximumShield' warning: ...ander forged alliance\mods\m28ai\lua\ai\m28logic.lua(291): in function `IsTargetUnderShield' warning: ...ander forged alliance\mods\m28ai\lua\ai\m28logic.lua(505): in function `GetDamageFromBomb' warning: ...er forged alliance\mods\m28ai\lua\ai\m28building.lua(1375): in function <...er forged alliance\mods\m28ai\lua\ai\m28building.lua:1088> i.e. this is part of the ‘ConsiderLaunchingMissile’ logic. This logic was one of the few parts taken from M27, so it looks like I need to come up with a more efficient way of calculating things even if it is less precise. In particular, the advantage of the current approach used for nukes is that it is far more likely to find locations that aren’t protected by an SMD and target them. The main downside is that as unit countrs scale it results in an exponential number of targets. E.g. if there are 100 units bunched together of a particular category of interest, then the nuke considers firing at the location of each one, and factors in the damage dealt (which means considering the other 100 nearby units), i.e. it ends up doing 10k calculations. Now if there are 1k units (in the slowdown replay it was on astro craters so it was possible to have very large quantities of units in one location) it ends up doing 1 million calculations. This is despite having a 1 tick delay every 25 units being considered (so presumably the sheer number of units in the aoe was causing the slowdown). I therefore thought of introducint the following changes: ● ● At the start of the game setup ‘alternative nuke points’ for land zones: o If the min/max position in a land zone is more than 40 from the midpoint, then divide the zone up into 30x30 points, i.e. each point is 30 from the midpoint/other points. Cycle through every zone and sort through them by likely value (based on 100% of enemy building value and 25% of ground combat threat). Consider launching a nuke at the zone midpoint and any alternative nuke points and getting its value. However after thinking some more, the following approach should provide a similar result but requires less change to the code base: 115 ● ● ● ● ● ● When deciding whether to consider a target for a nuke, check if we have already considered somewhere within 15 of this: o After considering a target, record the location divided by 15 (and rounded) in a table for the X and Z values o Only consider new locations whose value for this isnt already in the table. Consider a max of 10 targets per tick (previously 25) After more than 2s of calculations, reduce the threshold required to stop searching by 5% each tick. After 10s of calculations, reduce further, and after 15s abort. Don’t recalculate the best aoe target if we havent changed the target from the start position (where we already do this upfront). Another issue this highlights is that I’m checking units’ shielding despite a nuke dealing so much damage that I don’t need to worry about shielding. I therefore want to avoid checking for shields at all when the base damage is at least 25k. Have a flag as part of the unit cap logic, this time for all units – if the number of units in the game reaches 1k+, then have nuke launchers use refined targeting logic where they ignore T1 units (all kinds) and ignore T2 mobile land. o High value aoe (such as nuke) will also now ignore T1 mobile land anyway. I’m still not sure that this has solved the problem, but as a basic check after all these changes I compared how long M28 would take on a 4v4 on astro rich (the replay that had the major slowdown) with v3 M28, and v4 M28 (post these changes). The results are below for 30m into the game (some of the ‘time= values are incorrect due to errors) With changes UEF 4v4: info: ProfilerOutput: No.1=SearchForBuildableLocationsForLandOrWaterZone; TimesRun=141614; Time=7773.6118164063 info: ProfilerOutput: No.2=DecideAndBuildUnitForFactory; TimesRun=62436; Time=6075.38671875 info: ProfilerOutput: No.3=CanBuildAtLocation; TimesRun=1196651; Time=97.941482543945 info: ProfilerOutput: No.4=ManageAllLandZones; TimesRun=27662; Time=92.679611206055 info: ProfilerOutput: No.5=ManageSpecificLandZone; TimesRun=43090; Time=75.623260498047 info: ProfilerOutput: No.6=OnConstructed; TimesRun=3627; Time=63.012977600098 info: ProfilerOutput: No.7=UpdateGrossIncomeForUnit; TimesRun=17366; Time=62.493110656738 info: ProfilerOutput: No.8=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100634; Time=39.733673095703 info: ProfilerOutput: No.9=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=14365; Time=35.5087890625 info: ProfilerOutput: No.10=FilterToAvailableEngineersByTech; TimesRun=100634; Time=29.474563598633 info: ProfilerOutput: Total time taken to get to 18001= 572.85369873047; Total time of any freezes = 49.67162322998; Longest tick time=0.38421630859375; tick ref = 15882 to 15883 116 Aeon 4v4 info: ProfilerOutput: No.1=SearchForBuildableLocationsForLandOrWaterZone; TimesRun=180185; Time=1152122.75 info: ProfilerOutput: No.2=CanBuildAtLocation; TimesRun=1267780; Time=13714.370117188 info: ProfilerOutput: No.3=DecideAndBuildUnitForFactory; TimesRun=63457; Time=8481.966796875 info: ProfilerOutput: No.4=ManageAllLandZones; TimesRun=27304; Time=188.31784057617 info: ProfilerOutput: No.5=ManageSpecificLandZone; TimesRun=43090; Time=167.60601806641 info: ProfilerOutput: No.6=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100633; Time=114.56607055664 info: ProfilerOutput: No.7=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=14365; Time=109.92969512939 info: ProfilerOutput: No.8=OnConstructed; TimesRun=4257; Time=106.64226531982 info: ProfilerOutput: No.9=UpdateGrossIncomeForUnit; TimesRun=17687; Time=106.05750274658 info: ProfilerOutput: No.10=FilterToAvailableEngineersByTech; TimesRun=100633; Time=101.03744506836 info: ProfilerOutput: Total time taken to get to 18001= 849.73559570313; Total time of any freezes = 126.95933532715; Longest tick time=0.79705810546875; tick ref = 12341 to 12342 info: ProfilerOutput: No.18=SearchForBuildableLocationsForLandOrWaterZone; TimesRun=51735; Time=3.0337448120117 Without changes UEF 4v4 info: ProfilerOutput: No.1=MonitorEngineerForBlacklistLocation; TimesRun=9270; Time=46497.78515625 info: ProfilerOutput: No.2=DecideAndBuildUnitForFactory; TimesRun=53011; Time=10219.234375 info: ProfilerOutput: No.3=CanBuildAtLocation; TimesRun=939375; Time=5361.7529296875 info: ProfilerOutput: No.4=OnConstructed; TimesRun=3686; Time=425.10430908203 info: ProfilerOutput: No.5=UpdateGrossIncomeForUnit; TimesRun=18650; Time=398.64923095703 info: ProfilerOutput: No.6=ConsiderReclaimingPower; TimesRun=116; Time=397.72705078125 info: ProfilerOutput: No.7=ManageAllLandZones; TimesRun=27275; Time=105.44129943848 info: ProfilerOutput: No.8=ManageSpecificLandZone; TimesRun=43090; Time=86.590408325195 info: ProfilerOutput: No.9=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100634; Time=50.129913330078 info: ProfilerOutput: No.10=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=14365; Time=46.643600463867 117 info: ProfilerOutput: Total time taken to get to 18001= 609.38195800781; Total time of any freezes = 33.399173736572; Longest tick time=0.4432373046875; tick ref = 17671 to 17672 Aeon 4v4 info: ProfilerOutput: No.1=MonitorEngineerForBlacklistLocation; TimesRun=7235; Time=22651.900390625 info: ProfilerOutput: No.2=CanBuildAtLocation; TimesRun=932320; Time=4223.7084960938 info: ProfilerOutput: No.3=DecideAndBuildUnitForFactory; TimesRun=34536; Time=2551.9614257813 info: ProfilerOutput: No.4=OnConstructed; TimesRun=2979; Time=477.38296508789 info: ProfilerOutput: No.5=UpdateGrossIncomeForUnit; TimesRun=18157; Time=440.66409301758 info: ProfilerOutput: No.6=ConsiderReclaimingPower; TimesRun=67; Time=197.17919921875 info: ProfilerOutput: No.7=ManageAllLandZones; TimesRun=27076; Time=49.765731811523 info: ProfilerOutput: No.8=ManageSpecificLandZone; TimesRun=43092; Time=40.011734008789 info: ProfilerOutput: No.9=CheckIfBuildableLocationsNearPositionStillValid; TimesRun=2979; Time=32.785472869873 info: ProfilerOutput: No.10=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100636; Time=22.65845489502 info: ProfilerOutput: Total time taken to get to 18001= 433.2658996582; Total time of any freezes = 23.438877105713; Longest tick time=0.32365417480469; tick ref = 9619 to 9620 So overall the changes are far from conclusive. That said, there was a bugfix in one of the functions for searching for buildable locations so Im assuming fixing this resulted in the large increase in times this was called. From a rough skim of function calls by tick though the calls are spread out over each tick (e.g. it might be called 8-12 times a tick), which is good since while the times it is called in the game is massive, the load from this should be spread out. I therefore do a check of Africa 4v4 UEF to compare to the v1 results. V4 gives: info: ProfilerOutput: Total time taken to get to 6001= 52.16051864624; Total time of any freezes = 0.81795173883438; Longest tick time=0.13208770751953; tick ref = 5040 to 5041 In contrast, v1 was 67.5s, which suggests (although again the measure is unreliable) that these changes may have helped improve performance. 2.33.3) Completing capture and repair objectives Looking through a couple of the FAF campaign scripts, it looks like objectives to give an order are stored in a local variable AssignedObjectives However, they also appear to follow a consistent naming convention when stored in ScenarioInfo, e.g.: ScenarioInfo.M1P1 118 For the first primary objective for the first map size ScenarioInfo.M2P1 for the second map size’s first primary objective Etc. This records a table containing information on the objective. For example, a capture objective for M2 (to capture the prison) is: ScenarioInfo.M2P1 = Objectives.Capture( 'primary', -- type 'incomplete', -- status OpStrings.X02_M02_OBJ_010_010, -- title OpStrings.X02_M02_OBJ_010_020, -- description { FlashVisible = true, NumRequired = 1, Units = {ScenarioInfo.Prison}, } ) I therefore want to check for this information rather than hardcoding map names (which might change), which hopefully means that if other maps are setup in a similar way (they probably wont be) then my AI would automatically help with capture missions. The idea is that I will check for such objectives periodically (every 60s) on a campaign map, since I don’t think Im able to do a callback for this and the overhead should be minimal. The log for the first objective of the 2nd FAF campaign map’s 2nd mission (i.e. 2nd map expansion) to capture a prison is: info: - Active: true info: - AddAreaTarget: function: 5C424F50 info: - AddProgressCallback: function: 5DBD39BC info: - AddResultCallback: function: 5D2B6B28 info: - AddUnitTarget: function: 5C4248C0 info: - Complete: false info: - Decal: false info: - Decals: table: 5D355D98 info: - Description: <LOC X02_M02_OBJ_010_020>Capture the holding facility to free the Loyalist captives. info: - Fail: function: 2F426508 info: - IconOverrides: table: 57949960 info: - 1: table: 573C87D0 (Unit of type: xac1101, with entity id: 1048773) info: - ManualResult: function: 273EC780 info: - NextTargetTag: 1 119 info: - OnProgress: function: 5C4A09F4 info: - OnResult: function: 2F3415E8 info: - OnUnitCaptured: function: 5DE912D0 info: - OnUnitGiven: function: 5C72B168 info: - OnUnitKilled: function: 5DE91AB0 info: - PositionUpdateThreads: table: 57949348 info: - 1: thread: 572EEC30 info: - ProgressCallbacks: table: 57949BE0 info: - ResultCallbacks: table: 57949910 info: - 1: function: 5D355398 info: - SimStartTime: 2584.1000976563 info: - Tag: Objective3 info: - Title: <LOC X02_M02_OBJ_010_010>Rescue the Loyalist POWs info: - UnitMarkers: table: 5D355DC0 info: - VizMarkers: table: 57949550 I can see a table containing the unit xac1101 but it looks like this might be linked to iconoverrides so I’m concerned it isn’t reliable. The code that recordes the objective is based in: import('/lua/ScenarioFramework.lua').Objectives which in turn takes it from: import("/lua/simobjectives.lua") This actually highlights that I could have done a callback for the objective instead of my 60s cycle approach, so I’ll look to implement callbacks instead since it feels a bit neater. The above code file includes the function: function Capture(Type, Complete, Title, Description, Target) This makes use of the line: AddObjective(Type, Complete, Title, Description, image, Target) Where Target will be a table of units to be captured Going through the code some more, it looks like it records Target.captured = 0 for a capture mission, so I’ll use this to decide whether to record a capture target. 120 I’ll then update the minor land zone logic to capture any buildings in that table, so it should request engineers to undertake the capture, but to only do this if there are no dangerous enemies in the zone. Civilian capture logic Since I’m implementing capture logic it feels like a good time to similarly have M28 try and capture civilian combat units of interest (e.g. titans on a map like big bang dry). 2.33.4) M28 vs RNG performance check at AiX 10.0 Supreme Battles 2020 mentioned RNG beat M28 15 out of 16 games (presumably at 10.0 AiX). I therefore want to figure out why M28 is performing worse than expected (since M28 typically beats M27 at this level). In the games played M28 did fairly well, often being ahead much of the game and if it died it was usually due to failing to fully shield its base before RNG’s t3 arti started firing. However the following changes have been made to try and make M28 play better generally as it was still frequently overflowing lots of mass. 1. Added in logic for minor land zones to build land factories (up to 2 per zone) when about to overflow mass and at high mass income levels. 2. If there are already 2 land factories then they’ll build an experimental level unit (e.g. a land factory). 3. Added several new high priority engineer builders for high mass scenarios. 4. Reduced BP assigned for high multipliers to reduce the scenarios where 40 engineers all try and build something that would built faster with 20 due to less time spent for the engineers to move out of the way. 5. Land factories shouldn’t be paused in a power stall if we have a base level of energy and significant mass stored. 6. If the enemy base isn’t revealed yet then T3 arti should fire at the enemy start position. 7. Added in a ‘second shield’ builder if we have unshielded T3 arti or game-enders, that will focus just on trying to shield those units. 8. Increased the accuracy of experimental builder for minor zones so they will check if the zone itself can path to the enemy base instead of relying on if an aiBrain can. 9. ACU should now factor in AiX build rate multiplier into its decisions on whether it can afford to get an upgrade. 10. Playing a game on Finns revenge highlighted a major flaw with my ACU initial build order, as many of the conditions were based on gross energy/mass income, e.g. it assumed that it would gain 2 mass per sec for each mex and not build more mexes with the ACU once this was reached. At 10 AiX this meant it failed to build mexes, and also failed to build power, resulting in a major power stall. 11. The upgrade logic would only consider upgrading after 2.5 minutes – I’ve reduced this to the higher of 1m and 2.5 minutes / the AiX modifier, along with a further check where if our team mass is at least 60/tick then the time threshold will be ignored entirely. 12. One hilarious to see but unintended consequence of some logic M28 has was to see M28 spend a while building an assault transport, only to ctrl-K it the moment it was built. I presume this was logic it has to ctrl-K transports that aren’t of use to get the reclaim value. Therefore, the backup ‘build any experimental if the initial experimental choice can’t be built’ logic won’t consider building experimental transports, while experimental transports 121 will be treated the same as gunships instead of transports (to avoid the ctrl-K logic triggering). 13. There’s a bug with FAF where RAS SACUs don’t benefit from AiX resource modifiers, so I’ve added a basic fix in M28’s logic (for all AIs when there’s an M28AI in the game) 14. More than 1 quantum gateway should be built at high (AiX 1.5+ modifiers). Running a few games vs RNG on different maps after all the above changes: Finns revenge ● Sera mirror – M28 won, but very close ● Aeon Mirror – M28 won, another close game, M28 almost won early on with a nuke but RNG compelted the SMD missile just as the nuke was about to land, before M28 slowly won with navy despite slightly worse eco throughout ● Cybran mirror – M28 lost (although I suspect this was in part due to a bug where RAS SACUs don’t benefit from the AiX resource boost, as M28 built a lot of them but they had little impact on its eco). High Noon ● UEF mirror – M28 loss – fairly close game for much of it, but late-game RNG’s T3 arti proved superior to M28’s land experimental+novax mix. ● Aeon mirror – M28 win ● Cybran mirror – M28 win ● Seraphim mirror – M28 win (just – RNG’s Ythotha was about to kill M28’s ACU as M28’s yolona broke through RNG’s SMD) Setons Clutch ● UEF mirror – M28 win Badlands ● M28 Seraphim vs RNG Cybran – M28 win 2.33.5) Another reworking of build locations While testing the above I noticed M28 was failing to identify places as being buildable. I therefore want to revisit the idea of tracking build locations by location so I can update properly when a unit is built or dies rather than the current approach of just cycling through a certain number of segments in the zone to refresh build locations (which may be having performance implications). Currently M28 will for each zone record a list of all buildable locations by building size. I still want to be able to easily refer to something like this so I can just specify the size of building and instantly have a shortlist of buildable locations, but I also want to have a separate table which tracks which locations are buildable in the first place. One option is to have a new table, with keys that are segment X and Z values, and for each of these I can specify for each segment the maximum building size that it permits (and not record anything if the location isn’t buildable, to try and slightly reduce the memory). Then when a unit construction is started (or the unit is created and hasn’t had an on construction event run) or the unit is or destroyed, I can search 50% of the maximum build distance (which will be that of a Czar) + the unit’s size radius, and update every segment to see if it is still buildable for the largest size – when a unit is built, I only need to consider the segment properly if its largest size 122 brings it into conflict with the unit just built. When a unit is destroyed, then I need to consider the all segments, and check from the size above from the previously recorded highest value onwards. To then have this link into the table of buildable locations by size, I could change the buildable locations by size to also use [x] and [z] segment keys, and then update this based on if locations have been added/removed for a particular size. I therefore rewrite (as a separate branch in case it ends up not working or far worse) to do this, involving a compelte rewrite of some of the functions to make use of the new referencing system, and a lot of time debugging to figure out why parts of the logic wouldn’t work. As part of this, I needed to add a table recording destroyed buildings, since I’m unable to do a forked thread from the onunitdeath event without it causing an error. Therefore when a unit dies I’ll record the blueprint and time, and every tick I check the table and update for any entries more than 3.9s old (since I need to wait until the building destruction animation has completed). Experimentals under construction The testing also highlighted another issue – the built in function CanBuildStructureAt doesn’t take into account mobile experimentals under construction – e.g. it still thinks a PGen can be built in the location a GC is being constructed. I therefore see the following as a potential solution: ● ● ● ● ● ● When a mobile experimental construction is started for the first time, Cycle through every segment covered by the experimental footprint, and if it doesn’t have a blacklist location recorded for it, record the blacklist Record the temporary blacklist entry against the mobile experimental whose construction was started. Once the blacklist is recorded, run the normal check for if the nearby buildable locations are still valid, including the blacklist (only include blacklist if it’s a mobile experimental). When an experimental dies or construction completes, check if it has this entry, and if so remove from the blacklist and the experimental. As a backup, whenever recording a blacklist entry for an experimental, clear the entry after 4 minutes if the experimental no longer exists. Normal blacklist entries should also be cleared after 8 minutes in case it was due to a temporary issue that has now resolved. Profiling new construction logic Checking how long it takes to run on the 4v4 Astro scenario (see earlier for the times with the old method): 4v4 UEF with changes: info: ProfilerOutput: No.1=CanBuildAtLocation; TimesRun=10222327; Time=[invalid – error in code] info: ProfilerOutput: No.2=DecideAndBuildUnitForFactory; TimesRun=88892; Time=4865.056640625 info: ProfilerOutput: No.3=ManageAllLandZones; TimesRun=26943; Time=208.82913208008 info: ProfilerOutput: No.4=ManageSpecificLandZone; TimesRun=43090; Time=184.24096679688 info: ProfilerOutput: No.5=OnConstructed; TimesRun=3760; Time=160.69473266602 info: ProfilerOutput: No.6=UpdateGrossIncomeForUnit; TimesRun=17338; Time=160.17340087891 123 info: ProfilerOutput: No.7=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100634; Time=117.87591552734 info: ProfilerOutput: No.8=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=14365; Time=111.26459503174 info: ProfilerOutput: No.9=FilterToAvailableEngineersByTech; TimesRun=100634; Time=97.935234069824 info: ProfilerOutput: No.10=CheckIfBuildableLocationsNearPositionStillValid; TimesRun=1540; Time=26.161964416504 info: ProfilerOutput: Total time taken to get to 18001= 1279.2435302734; Total time of any freezes = 263.53198242188; Longest tick time=0.95118713378906; tick ref = 9 to 10 Unfortunately instead of showing an improvement to the time taken this shows a massive worsening of the time. The main reason is the amount of times a location is checked to see if its buildable – previously this was 1.2m times in 30m. After these changes (which do at least have the benefit of being more accurate) this check is being done 10.2m times. Time spent managing land zones has also increased dramatically from 97s to 208s. The time taken for an engineer’s assignment has also increased dramatically, from 40s to 111s, which accounts for a significant part of this increase. I suspect that one factor at play here is that there are more options to choose from when picking the best build location, which is increasing the calculation time. One potential option to mitigate this might be to localise engineer build logic/decisions on where to build a unit, by searching outwards from a centrepoint and including all buildable locations. However, there’s no guaranatee this would reduce times since late game all places close to the centre of the land zone would have been built on meaning it would take much longer to reach buildable locations. Another option would be to stop after getting 50 valid build locations. This runs the risk though of building far away from the centre of the land zone if all build locations are grouped in one place, limiting the effectiveness of the logic of choosing the best location. Yet another option could be to reduce segment size and limit the buildable options that way. Another variant could be to get the first 30 build locations, and to then randomly pick a further 20 locations (ignoring any duplicate random numbers), so most of the time there is a reasonable variety in the build location options. However due to the way Im now tracking build locations I don’t think this random option would be that easy to do as I’d have to cycle through and discard lots of invalid zones. A variation that I think is more feasible is to work out the number of available entries, and if its more than 50 then only include the nth valid entry in the potential locations. For now I’ll try restricting the options to choose from to the first 40 by taking the nth entry. 124 Unfortunately this doesn’t have much of an impact – e.g. for the time taken to get to tick 13821 (I couldn’t be bothered with waiting to the end) it decreased from to 751s to 736s, with the detailed log being: info: ProfilerOutput: No.1=CanBuildAtLocation; TimesRun=8002101; Time=[N/A – Bug] info: ProfilerOutput: No.2=DecideAndBuildUnitForFactory; TimesRun=73448; Time=[N/A – bug] info: ProfilerOutput: No.3=OnConstructed; TimesRun=3044; Time=160.5387878418 info: ProfilerOutput: No.4=UpdateGrossIncomeForUnit; TimesRun=13217; Time=160.16943359375 info: ProfilerOutput: No.5=ManageAllLandZones; TimesRun=20736; Time=123.68119049072 info: ProfilerOutput: No.6=ManageSpecificLandZone; TimesRun=33059; Time=110.50128936768 info: ProfilerOutput: No.7=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=77227; Time=68.629089355469 info: ProfilerOutput: No.8=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=11022; Time=63.691535949707 info: ProfilerOutput: No.9=FilterToAvailableEngineersByTech; TimesRun=77227; Time=55.483390808105 info: ProfilerOutput: No.10=CheckIfBuildableLocationsNearPositionStillValid; TimesRun=1156; Time=20.372230529785 One potential way I could reduce the time required is to not reconsider every size for every segment, but only those sizes I expect may have changed. For example, suppose a 2x2 PGen gets destroyed. It’s now possible that a 3x3 area centred on that pgen can support another pgen (so should be reconsidered). Meanwhile it’s possible that any of the locations in a 25x25 area centred around that pgen location could now support building a czar where previously they couldn’t. In addition, if the max size of the pgen (when refreshed) is only say an 8x8 building but not a 10x10 building, then that means only locations in a hollow box with the outer being a 25x25 area and the inner box being a 10x10 area might be able to support a czar. However, due to how the logic works trying to add this sort of exclusion approach is non-trivial. I could also just limit the search to cover 8x8 buildings (e.g. T3 pgens and smaller) instead of czar sized buildings, and rely on the separate functionality for checking which segments are buildable over time (and when there are no more build locations) to cover this. For example previously if a land factory died, it would search an area 4 (land fac radius) + 12 (Czar radius) = 16x16 = 256 If I changed to cover 8x8 buildings, then it would only search an area 8x8 = 64, i.e. 25% as many entries. Changing the segment size to be 2x2 on 10km and larger maps as a minimum would apply another 25% reduction. 125 Another change was not running the logic to check for buildable locations when a mex or hydro is built or dies. These still don’t have the desired effect. However after fixing a couple of bugs my profiling logs are a bit more meaningful, with the following being the position after these changes (at an earlier tick): info: ProfilerOutput: No.1=ManageAllLandZones; TimesRun=17629; Time=77.556365966797 info: ProfilerOutput: No.2=ManageSpecificLandZone; TimesRun=27851; Time=67.93505859375 info: ProfilerOutput: No.3=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=65075; Time=36.946632385254 info: ProfilerOutput: No.4=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=9285; Time=33.541702270508 info: ProfilerOutput: No.5=FilterToAvailableEngineersByTech; TimesRun=65075; Time=30.062580108643 info: ProfilerOutput: No.6=RecordGroundThreatForLandZone; TimesRun=27851; Time=11.213144302368 info: ProfilerOutput: No.7=ManageCombatUnitsInLandZone; TimesRun=9644; Time=10.174573898315 info: ProfilerOutput: No.8=GetCombatThreatRating; TimesRun=1034721; Time=10.168375015259 info: ProfilerOutput: No.9=CheckIfBuildableLocationsNearPositionStillValid; TimesRun=497; Time=6.7498073577881 info: ProfilerOutput: No.10=CheckIfSegmentsStillBuildable; TimesRun=497; Time=6.6457366943359 info: ProfilerOutput: Total time taken to get to 11651= 544.40576171875; Total time of any freezes = 69.678382873535; Longest tick time=0.95945167541504; tick ref = 9 to 10 This is including the initial map start time. This highlights that by far the biggest contribution towards slowdown is the FilterToAvailableEngineersByTech function, since this is run as part of all of functions 1-4 that are taking the longest time, accounting for 30/33 of the core land zone engineer assignment logic. I suspect this could be due to large land zones on the map in question (astro craters rich) resulting in a large group of enemy units being considered. Each friendly engineer will check how far away it is from each enemy unit when deciding if an enemy unit is range. One simplification I can make is to check how close the engineer is to the zone midpoint, and how close the closest enemy unit is to the midpoint. If the distance between these two is more than the threshold for the engineer acting based on nearby enemies, then it can ignore it. A second potential simplification is to switch methods to a ‘getunitsaroundpoint’ approach where there are at least 10 enemies, since I suspect this approach may be quicker as it tells me if there are enemies within the distance without needing to distance check each of them. 126 Testing the second first (since it’s much easier to do) results in a dramtic improvement in time taken early game for this function, so I wont bother with the first option. I also notice that my emergency PD logic gets the nearest enemy unit twice (once for each builder) so I add an optimisation to not get it the second time if I’ve already got it the first time. Running a new 4v4 UEF mirror on astro rich gives the following results: info: ProfilerOutput: No.1=ManageAllLandZones; TimesRun=27046; Time=89.451591491699 info: ProfilerOutput: No.2=ManageSpecificLandZone; TimesRun=43091; Time=70.2021484375 info: ProfilerOutput: No.3=RecordGroundThreatForLandZone; TimesRun=43091; Time=20.336393356323 info: ProfilerOutput: No.4=GetCombatThreatRating; TimesRun=1405422; Time=17.022764205933 info: ProfilerOutput: No.5=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100635; Time=17.020629882813 info: ProfilerOutput: No.6=ManageCombatUnitsInLandZone; TimesRun=14144; Time=15.054508209229 info: ProfilerOutput: No.7=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=14365; Time=13.736473083496 info: ProfilerOutput: No.8=CheckIfBuildableLocationsNearPositionStillValid; TimesRun=813; Time=10.491506576538 info: ProfilerOutput: No.9=CheckIfSegmentsStillBuildable; TimesRun=813; Time=10.340942382813 info: ProfilerOutput: No.10=CanBuildAtLocation; TimesRun=3879070; Time=9.3387413024902 info: ProfilerOutput: Total time taken to get to 18001= 783.64086914063; Total time of any freezes = 41.950523376465; Longest tick time=1.0018310546875; tick ref = 9 to 10 The Aeon 4v4 results are: info: ProfilerOutput: No.1=ManageAllLandZones; TimesRun=26959; Time=107.51538848877 info: ProfilerOutput: No.2=ManageSpecificLandZone; TimesRun=43090; Time=85.687393188477 info: ProfilerOutput: No.3=RecordGroundThreatForLandZone; TimesRun=43090; Time=23.963935852051 info: ProfilerOutput: No.4=GetCombatThreatRating; TimesRun=1644976; Time=19.987089157104 info: ProfilerOutput: No.5=ManageCombatUnitsInLandZone; TimesRun=14362; Time=18.299633026123 info: ProfilerOutput: No.6=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=100634; Time=17.607286453247 info: ProfilerOutput: No.7=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=14365; Time=14.353818893433 127 info: ProfilerOutput: No.8=CheckIfBuildableLocationsNearPositionStillValid; TimesRun=825; Time=10.983692169189 info: ProfilerOutput: No.9=CheckIfSegmentsStillBuildable; TimesRun=825; Time=10.845937728882 info: ProfilerOutput: No.10=CanBuildAtLocation; TimesRun=4071099; Time=9.4974784851074 info: ProfilerOutput: Total time taken to get to 18001= 927.14483642578; Total time of any freezes = 103.59169006348; Longest tick time=0.92333221435547; tick ref = 9 to 10 So unfortunately after lots of work optimising I’m still at a worse off position than before. However the appeal of more accurate build location logic and the potential for this to help late-game performance even if early game performance is worse means I’ll stick with this approach rather than revert back. However, later on during testing I realised there was an error with the ‘Getunitsaroundpoint’ approach I used where it would never actually trigger (hence why it was so much faster). After fixing this, checking part-way through the replay, at tick 11301, gave the following results for the function relating to this. Before: info: ProfilerOutput: No.18=FilterToAvailableEngineersByTech; TimesRun=63115; Time=1.8183212280273 After: info: ProfilerOutput: No.13=FilterToAvailableEngineersByTech; TimesRun=63116; Time=2.9245834350586 So while the time has increased significantly, it looks like it is significantly faster than before, as the log for the same time previously was: info: ProfilerOutput: No.9=FilterToAvailableEngineersByTech; TimesRun=63116; Time=32.177177429199 Note that some variance is expected with the results since these are different games/replays, but it still gives a rough idea as to how long the function is taking. Running on Africa 4v4, by 10m: Including initial setup: info: ProfilerOutput: Total time taken to get to 6001= 76.245834350586; Total time of any freezes = 10.55298614502; Longest tick time=4.8122062683105; tick ref = 9 to 10 I forgot to disable profiling for the map setup (previous logs had excluded map setup time). However the time to setup the map with the core function was 10.3s, i.e. the approximate total time would have been less than 66s with 0.2s of freezes. 2.33.6) Acknowledgements ● ● Hdt80bro – helping me find a better way to confirm if a map is a campaign map, and clarifying how to hook orders such as IssueGuard Grandpa Sawyer – helping me debug an issue with the base AI taking control of my units (including the IssueFactoryAssist() order being the one I needed to hook) 128 ● ● ● Jip – Helping with the same bug as the above, highlighting I was hooking a file that only existed on FAF develop (hence why it wasn’t doing anything for non-FAF develop) Fearghal – replay highlighting major late game slowdown for M28 on Astro Craters Rich Wingflier - replay showing M28 losing at 1.5 AiX 2.34) V5 Changes 2.34.1) Bugfixes 1. There were some issues on campaign maps due to the difference between the map area and the playable area. I’ve therefore refined the logic for getting a location within map bounds so for each usage of this function I have specified whether it should use the playable area currently, or the map playable area if expanded. I.e. for initial recording of zones and pathability I want to do the latter, for deciding where to send a unit right now I want to do the former. 2. I’ll also ignore air units targeting zones whose midpoint is outside the current playable area. 3. There was an issue with the new building logic that could result in M28 thinking there was nowhere to build when there was. 4. If an air factory HQ is destroyed and the team has no HQ left, T1 air factory should be built as a top priority. Similarly for land factories. 5. Reworded a couple of variable references that used M27 as a prefix instead of M28 6. The playable area wasn’t always being identified on a map expansion. I therefore will use the string rect (which sends a mission code) as an override for the playable area. 7. There was a bug where some of the air logic used the wrong reference for a zone leading to the zone never being considered. 8. M28 was meant to only build more power if its net energy income was below a certain threshold, but a bug meant it would always want more power. 9. When deciding whether a unit is in a land or water zone for assignment, if the unit can path in water then it will first check if the segment is assigned to a water zone, and if not will check if it is in a land zone. In addition, only mobile land units will be treated as being expected to have a pathable nearby land zone (previously all units would, leading to error messages appearing if a submarine wasn’t in a land zone). 10. When calculating the damage done by an aoe effect (e.g. T3 arti), there was a bug relating to how under construction units were taken into account (meaning e.g. experimental air units being constructed wouldn’t be factored in properly). 11. RAS upgrades weren’t being taken into account by M28 when calculating how much mass and energy it was generating (affecting various thresholds for builders). 12. RAS SACUs aren’t treated as having an upgrade the moment they are built meaning M28 was failing to calculate its income properly. However, the blurprint lists put the upgrades they are set to receive, so I was able to refrence this to fix the issue. 13. RAS SACUs were meant to assist under construction experimentals at high mass values but instead assisted each other. 14. RAS SACU orders should only be cleared (when they are to be idle) if they are repairing/building/guarding, to avoid scenarios where they are cleared before exiting the gateway. 15. M28’s calculation of its gross mass income should now include a very rough approximation for mass storage’s adjacency bonus. 2.34.2) Misc changes 129 1. Added a low priority air staging builder for minor zones with no nearby enemies if we have a shortage of air staging facilities and the zone has no nearby enemies and has radar coverage. 2. Increased the cap on low priority gunship builder for campaign and high mass non-campaign scenarios. 3. Added ‘T2 radar creep’ logic for 20km+ maps 4. Air staging should no longer be ctrl-kd when close to the unit cap (due to the risk of ending up with low fuel units that do nothing) 5. Unit cap thresholds for resetting being close to the unit cap are much higher at the ‘worse’/closer to threshold results. 6. Low fuel units should be ctrl-kd if we are close to the unit cap and the unit is close to the rally point, and lacks an air staging to go to. 7. If there are no land zones adjacent to water that need support, then a land zone that is closer to the enemy base than the current zone should be picked. 8. The ‘factory is idle’ warning message should not show if the M28 owner is close to the unit cap. 9. Reduced the AA threshold at which gunships will consider attacking for campaign maps since they can probably operate more safely further away from base compared to if fighting a human player. 10. Made it less likely to want more power in high net energy scenarios where we are close to the unit cap. 11. Added a cap of 50 on the number of RAS SACUs to be built. 2.34.3) Campaign - Repair damaged building objective After checking logs for the FAF mission 1 objective to repair the shield there’s little information I can get other than that there is an objective involving a unit. I’ll therefore assume there is a repair objective if there is a table which only contains injured allied units. I also add in logic to both minor land zones and core zones (previously capture logic was only in minor land zones), since in this case the shield is part of the initial base starting position. 2.34.4) Protect civilian objectives ● ● If there is a ‘protect’ objective, then include such units in a table of priority units to protect. Have this table included when looking for priority targets for gunships to protect. As a reference, the following were logs for some of the objectives on FAF mission 1, e.g. the objective to protect civilians: info: Have a mission, Title=<LOC X01_M02_OBJ_010_010>Defend the Civilians at Seabring; Description=<LOC X01_M02_OBJ_010_020>At least 50% of the civilian structures must survive.; Target.captured=nil; reprs of Target= info: - Image: /textures/ui/common/faction_icon-lg/uef_ico.dds info: - NumRequired: 12 info: - PercentProgress: true info: - ShowFaction: UEF 130 info: - Units: table: 65F0A550 info: - 10: table: 51AD4B40 (Unit of type: uec1101, with entity id: 4194313) info: - 11: table: 651F3D48 (Unit of type: uec1501, with entity id: 4194314) info: - 12: table: 538D0D20 (Unit of type: uec1201, with entity id: 4194315) info: - 13: table: 5DB7FD20 (Unit of type: uec1101, with entity id: 4194316) info: - 14: table: 6593A848 (Unit of type: uec1301, with entity id: 4194317) info: - 15: table: 57AC2BE0 (Unit of type: uec1501, with entity id: 4194318) info: - 16: table: 54194780 (Unit of type: uec1101, with entity id: 4194319) info: - 17: table: 52930168 (Unit of type: uec1101, with entity id: 4194320) info: - 18: table: 2F932578 (Unit of type: uec1101, with entity id: 4194321) info: - 19: table: 5BEEC870 (Unit of type: uec1401, with entity id: 4194322) info: - 1: table: 65F0AC30 (Unit of type: uec1401, with entity id: 4194304) info: - 20: table: 674DD2D0 (Unit of type: uec1101, with entity id: 4194323) info: - 21: table: 2F8132F8 (Unit of type: uec1501, with entity id: 4194324) info: - 22: table: 62E18ED8 (Unit of type: uec1101, with entity id: 4194325) info: - 23: table: 62E18320 (Unit of type: uec1101, with entity id: 4194326) info: - 2: table: 576EA168 (Unit of type: uec1101, with entity id: 4194305) info: - 3: table: 576EA5F0 (Unit of type: uec1101, with entity id: 4194306) info: - 4: table: 5D969E60 (Unit of type: uec1501, with entity id: 4194307) info: - 5: table: 5CBA0E88 (Unit of type: uec1101, with entity id: 4194308) info: - 6: table: 53F68460 (Unit of type: uec1401, with entity id: 4194309) info: - 7: table: 53F68230 (Unit of type: uec1101, with entity id: 4194310) info: - 8: table: 65ADF4D8 (Unit of type: uec1201, with entity id: 4194311) info: - 9: table: 5BE0FE88 (Unit of type: uec1101, with entity id: 4194312) IsAlly shows as true for the unit brain owner. Log for later protect civilians objective: info: Have a mission, Title=<LOC X01_M02_OBJ_020_010>Save the Civilian Outpost; Description=<LOC X01_M02_OBJ_020_020>Protect at least 50% of the civilian structures in the outpost to the east.; Target.captured=nil; reprs of Target= info: - Image: /textures/ui/common/faction_icon-lg/uef_ico.dds info: - NumRequired: 21 info: - PercentProgress: true 131 info: - ShowFaction: UEF 2.34.5) Campaign – Units to destroy E.g. mission 3 adds Seraphim bombers to destroy that the player can’t see. In case this means that the bombers won’t be known by M28 to be there, if a unit is included as part of an objective. This also highlighted an issue with my T3 arti targeting logic – M28 built a mavor, but it wouldn’t target where the experimental bombers were being built, despite knowing they were there, because the logic for determining the damage from the T3 arti would only take into account currently visible units. I’ve therefore adjusted so it will take into account other (unseen) units as well. 2.34.6) Campaign – naval build locations that are out of bounds On mission 3 I was puzzled why M28 wasn’t building a naval factory, and after a long time debugging to confirm engineers were being given the order to build a factory and not having that order cleared, I realised it was because the water zone chosen is mostly out of bounds at the start of the game: Meaning the midpoint of that zone would be invalid. I therefore want to adjust the water zone midpoint so that if a water zone midpoint is outside the playable area, but the min or max segments are in the playable area, then I want to adjust the midpoint to be in the playable area. Checking the zone (with the midpoint drawn in red this time) confirms it is now in a valid location: 132 2.34.7) Unit cap adjustments ● ● ● Don’t build a unit from a factory if we already have 50 of that unit (e.g. this is intended to cover asfs, gunships, SACUs, engineers) if the 2nd worst unit cap threshold has been reached. Don’t try and build T1 units with engineers if are near the unit cap (i.e. including energy and mass storage). If are in campaign and close to the unit cap, then try building a game-ender. After making these changes, M28 went from needing more than 2 hours to eke out a victory on FAF mission 3 (relying significantly on the Rhiza teammate) to 1 hour 22m. ● ● ● One thing games on the missions highlighted was the need for a higher AI unit cap – even with its logic to ctrl-K units, the 500 unit cap is just too low to handle. I therefore want to do something similar to the AiX logic where unit caps can be specified (since it looks like in campaign the option is hidden). However, from playing the original SC campaign on FAF with an uncapped unit mod enabled, and still suffering from lower unit caps, I’m assuming that there is logic to reset this unit cap (e.g. original SupCom will change the unit cap by mission). I‘ll therefore refresh the unit cap every time the map size changes and every time a new objective is added. Acknowledgements: ● Azraeelian Angel – Replay where there was a desync 2.35) V6 - Replay adjustments This version was mostly a case of making imrpovements for issues I saw watching some human vs M28AI replays Azraeelian Angel sent me, including replays 20058912 and 20049298. 1. If a T2+ unit or ACU gets within range of a skirmisher that would be doing an attack-move, the skirmisher should instead do an issueattack at that unit. 2. Indirect fire units should still attack the enemy if they outrange the enemy direct fire units and have significantly more threat than the enemy indirect fire units. 133 3. MMLs should now give off a small threat level for combat purposes and so be more likely to attack if they outrange the enemy. 4. When deciding whether to attack with outranged units, greater consideration should be given to nearby enemy zone threats. 5. If we have a unit with an indirect fire aoe attack and the enemy is in range of it but we have temporarily lost vision of it, and the unit hasn’t fired recently, then a ground fire attack should be used (assuming the unit isn’t moving). 6. Azraeelian Angel highlighted a number of games desyncing where the common factor was M27 and M28 were both on the same team. I’ve therefore added a warning message if there are 2+ players in the game with both M27 and M28 AI. 7. If M28’s ACU is hit by a TML while upgrading, it should cancel the upgrade and move away from the enemy TML. 8. T2 mexes and ACUs shouldn’t be treated as safe to upgrade if the enemy has TML in range of them and they don’t have TMD coverage. 9. Cloaked enemy ACU – If the enemy has a cloaked ACU or SACU, and we have a gunship threat of at least 1.5k, then the gunship should request a priority air scout be assigned to it (so the air scout can reveal the omni). 10. If have at least 100 mass per tick or if lower 40 per M28 brain, SACUs should switch from assisting the quantum gateway to assisting the other units (previously the threshold was 80 per M28 brain) 11. Increased the amount of AA to be built for core land zones generally, and if far behind on air. 12. Increased the amount of AA to be built for minor zones based on the number of mexes in that zone. 13. Switched most of the logic for working out if we don’t want any more MAA to be based of MAA threat (previously it was based of all groundAA threat, i.e. including SAMs) 14. Factored in the number of M28 brains to the decision on whether to build a gameender 15. If there is a gameender underconstruction then engineers shouldn’t be assigned to build another gameender. 16. Mexes should be treated as safe to upgrade if they have survived at least 5 minutes and there are no enemies in the zone. 17. Island factories should try and get a basic level of threat even if the enemy isn’t on the island yet. 18. ACU should be less likely to upgrade if at core base unless it is close to the midpoint, if it is low health. 19. Slightly more AirAA should be built when we already have a base gunship threat of approximately 3 T3 gunships. 2.35.1) Bug fixes ● ● Fixed a bug that prevented size 1 buildings (and hence T2 PD since T2 PD would want 1 T1 pd built first) being built Fixed a bug where Air experimentals wouldn’t be assisted properly when under construction. 2.35.2) Having sniperbots avoid fatboys While doing a sandbox testing of one of the changes (where I cheated in a couple of fatboys to stop M28 overruning me as a human) I noticed M28 would suicide sniperbots into the fatboy. Investigating further, the reason was the land zones are so small that the fatboy in a non-adjacent 134 zone can hit a zone (i.e. 2 zones away) – in the below example, the sniperbot was in the pink area, the fatboy in the darkblue main spawn area: My planned solution to this is: ● ● ● ● ● Have an enemy fatboy monitor thread Whenever an enemy unit with a DF range exceeding 80 is detected, it is added to the fatboy monitor thread Against each unit, it records the last zone that it was in Whenever this zone changes, all zones adjacent to adjacent land zones get the unit recorded in a table for that zone of ‘nearby enemy fatboy threats’ When calculating the enemy combat threat for a zone, the threat of the ‘nearby fatboy’ table is added, and we aren’t treated as outranging the enemy unless our best range exceeds 100 (i.e. we have a fatboy of our own). 2.35.3) Pre-release checks: 135 ● ● ● ● ● Forbidden pass vs RNG (UEF vs Aeon) – Win in 56m10 - RNG almost managed to kill M28’s ACU with a GC when it looked like the game was over (in M28’s favour) by sneaking it up through the water; after that it was M28’s game. Setons 4v4 vs RNG – I stopped before the replay ended to make some minor improvements but it looked a likely M28 win (M28 had 2.5:1 eco and had beaten 2 of RNG’s bases) Twin Rivers 2v2 vs RNG – RNG Win (M28 couldn’t handle RNG’s early Aeon guncoms due to a bug preventing T2 PD from building) Burial Mounds 1v1 vs RNG – RNG Win (there was a bug with air experimentals being built which led M28 to have an air experimental part-complete blocking build locations and not being assisted further, crippling its eco – I’ve fixed one of the two issues this highlighted, and will see if the second (power generators trying to be built ontop of the air experimental) recurs or was fixed as a consequence). Africa 4v4 Time taken (excl first 2 secs): info: ProfilerOutput: Total time taken to get to 6001= 59.426670074463; Total time of any freezes = 0.86589473485947; Longest tick time=0.17135620117188; tick ref = 5520 to 5521 2.35.4) Acknowledgements ● ● Azraeelian Angel – Multiple player vs M28 replays Relent0r – highlighting M28’s ACU could be killed by a single TML firing multiple missiles, and a replay where M28’s ACU would upgrade while taking damage and almost dead. 2.36) V7 – Replay and campaign issues 2.36.1) Bug fixes 1. If M28 got enough eco to justify building a game ender there was a bug which would break both its engineer logic and land unit management for the majority of land units. 2. ASFs should no longer try and ‘protect’ a novax satellite from enemy air units. 3. Resolved an issue with identifying the nearest plateau/land zone to a location to record overrides for locations where the segment position’s ‘plateau’ from navutils is different to the recorded plateau (which would then cause an error when trying to identify the plateau/zone details). 4. Corrected typo with the ‘disable M27 mod’ that referred to M28 instead of M27. 2.36.2) Misc changes 1. When deciding whether to get more factories, the average number of factories per M28 player should be considered (previously the total number of factories for all M28 brains would be considered) 2. Made core zone localised mex upgrade logic more likely to trigger sooner 3. Don’t get omni unless have at least 2 T3 mexes in the zone (or 1 T3 mex and no T2 or T1) 4. Similarly don’t get preemptive SMD unless have 2 T3 mexes (or 1 T3 mex and no T2 or T1) 5. SMD shouldn’t be built for minor zones unless the enemy has a nuke launcher or the value is very high. 6. AirAA should be less likely to attack enemy air units in a zone adjacent to a priority unit to defend where there is significant groundAA in that zone. 7. ACU should be more likely to run if the enemy has T2+ PD is nearby. 8. Changed monkeylord to be treated as having a range of 30 instead of 64 if it’s owned by an M28AI. 136 9. Added higher priority MML builder that takes priority over the ‘initial couple of tanks’ if an adjacent zone needs indirect support and we don’t have many MML. 2.36.3) Basic pre-release check Africa vs RNG (4v4): Win in 47m 2.36.4) Acknowledgements ● ● ● QAI300 – Replay highlighting bug with land units not moving (caused by the logic that triggers when engineers are to build a game ender). Radde – 4 human v 4 M28AI replay highlighting mass overflow issues at the T2-T3 stage Azraeelian Angel – More human vs AI replays 2.37) V8 More replay and campaign improvements 2.37.1) Changes based on replay 20105758 1. ACU should no longer try to ‘expand’/move to a land zone that is a core base (e.g. on teamgames it could sometimes travel to an allied M28 base to claim mexes, wasting valuable time) 2. Core base engineers should prioritise unbuilt mex zones that aren’t core base zones (previously they could end up traveling to an adjacent core zone owned by an M28 teammate instead of getting mexes early on). 3. If the ACU is near a T2 PD it should treat the location as safe to get an upgrade even if there are enemy threats. 4. Changed the initial high priority tank builder to be a team based test (since with more teammates there should be more ACUs to cover potential initial attacks). 5. Reduced the number of high priority units to be built when a factory reaches T2, to be reduced by the number of active M28 brains (i.e. so not as many are built as a high priority in large teamgames). 6. Slightly increased the amount of indirect fire units built as normal 7. Lowered thresholds for T2 arti to be built in response to enemy sniperbots. 8. T2 arti should be built in response to an enemy firebase that is threatening a core base. 2.37.2) Changes based on replay 20106323 9. When considering if enemy threats should be included from adjacent zones, only those that are 95%+ complete should be included 10. When we have far more threat than the enemy in a zone, and a very high threat (e.g. equivalent to 5+ percies), units should move instead of attack-moving – in the hope that e.g. a monkeylord won’t attack-move enemy engineers and land scouts. 11. When deciding to retreat units from a zone, M28 would only retreat units actually in that zone. However, this would lead to an issue where that zone was taking control of units in adjacent zones (due to being a higher priority), causing those units to not receive any orders until they entered the current zone (which in some cases might not happen), resulting in units suiciding into the enemy. I’ll now try it where in the retreat scenario the units have their priority cleared so the next highest adjacent zone takes control of them. 12. Where multiple engineers are assigned to build a mex in a zone, they should each try and build a different mex location. 137 13. Adjusted the start land zone mex assignment to reduce the search radius for further away mexes where a significant number of mexes are already assigned – the issue is illustrated by how zones were assigned on this map originally: The initial land zone assignment for start positions is shown in black below, with blue being the enlarged range after assigning nearby mexes: 138 This would lead to strange behaviour as the grey ACU 2nd from the top-left would treat a massive area as it’s ‘core’ zone, despite some of that being almost in the middle of the map. After tweaking the values (to reduce the search distance for additional mexes after the initial assignments to be based on the total number of mexes above 2 in the core zone), it gives: 139 Which is much closer to what I want. To check this doesn’t lead to wildly different results on other maps, I check theta passage (where it’s important the hydro is seen as part of the same zone), and this still appears consistent: 140 2.37.3) Changes based on replay 20106849 14. Fixed a bug with the resource sharing logic that meant resources wouldn’t get shared properly which in turn meant M28 would think it was mass stalling if any one of the AI had 0 mass. 15. Added redundancies to the mass stall manager so if at least 2k mass is stored then it will start unpausing, even if it thinks it has low mass. 2.37.4) Changes from testing on M5 and M6 of the FA campaign 16. Reclaim attempts should no longer be made on reclaim with a different terrain pathing result if it is outside the engineer’s build range and the engineer’s build range and size is less than the reclaim segment size, to reduce the risk of engineers stuck trying to reclaim something just outside their range. 17. (Note for FA Campaign mission 5 I decided not to try and have the AI move Brackman and leave it to the player, due to the risk of the AI suiciding the megalith) 141 18. Mission 5 highlighted an issue with invulnerable buildings such as the QAI mainframe and cybran network nodes being treated as enemies, leaving to M28 sending its gunships and armies to attack these locations (and do nothing). I’ll therefore ignore tracking units that are flagged as not being able to do damage or be killed by the campaign script. o However, this caused an issue as it turns out a lot of units are flagged as not being able to be killed when initially created, so I’ll only exclude units that are flagged as not being able to take damage; not being able to be killed; and are a civilian structure, and then only if it is a campaign map. 19. Mission 6 highlighted how you can start off with no ACU, and M28 would just move its SACU around not building anything. I therefore want to search for SACUs if after a while of searching I have no ACU, and to then increase to consider engineers if there are no SACUs, with the first such unit then being treated as an ACU. 20. Amphibious units should only move (as a rally point) to the water zone midpoint if we have more antinavy threat than the enemy in that water zone, otherwise they should move back to the nearest friendly base. 21. When deciding whether to attack or retreat from a water zone, amphibious units should also take into account nearby units (resolving an issue I saw on mission 6 where 4 GCs set off to the enemy island base, but as soon as 2 of them passed from 1 water zone to the adjacent one, it thought there weren’t enough GCs to take the island as it only had 2 damaged GCs, and ended up retreating all 4 GCs). 2.37.5) 20131411 22. Added high priority land factory HQ upgrade at high gross mass incomes (but with a lower threshold than before for large teamgames), in the hope that with good eco M28 will get to T3 and hence experimentals sooner than before. 23. The separate ‘build a game ender’ logic for very high resource values should switch to building land experimentals if we have fewer than 5 land experimentals per game-ender. 24. Adjusted the decision making on what experimental to build so if we have a game-ender we want a greater number of fatboys (for UEF). 25. Fixed a bug where certain engineer experimental construction actions weren’t being tracked. 26. Orders to engineers to construct an experimental should be aborted if we have one under construction in a nearby zone already and don’t expect to complete it in the next 45s 27. If an engineer starts constructing an experimental and there are nearby experimentals under construction and we don’t have huge amounts of mass then the construction should be aborted and the unit reclaimed. 28. Added higher priority air scout builder for if the factory hasn’t built an air scout before. 2.37.6) Other changes 29. Allied radar should now be taken into account when deciding whether to build radar. 30. Improved accuracy of mass storage income calculation – track when storage is built or destroyed, or mex is build or destroyed, and update the mass storage income each time for the adjacency bonus 31. Early upgrades should be more likely with very high mass (to avoid unusual scenarios early game where the AI might overflow resources – more of a preemptive potential logic, as it only happened when I cheated in a T2 mex and T2 pgen for the AI to help with testing, but in theory a campaign might gift such resources to the player) 142 32. When choosing the location for mass storage, the adjacency bonus should be factored in (meaning T3 mexes get prioritised over T2, and on maps like astro craters places that benefit 2 T2 mexes get prioritised over other T2 mexes) 2.37.7) PreRelease basic check Africa 4 M28 AiX 1.5 vs 4 RNG AiX 1.5 M28 win in 36.5m - A close game until the late stage, M28 and RNG had similar income until early experimental stage where M28 fell behind, but M28 maintained a good kill:death ratio, and soon obtained an unassailable lead thanks to its air control and gunships. M28 generally seemed to do a good job of spending its mass with almost no mass in storage throughout the game. Acknowledgements Radde, Azraeelian Angel – Both provided a number of human vs AI teamgame replays which formed the basis of most of the changes this update. 2.38) V9 – Ahwassa and misc 2.38.1) Experimental bomber targeting rework ● ● ● ● ● ● Improve approach to experimental bomber targeting – currently, M28 just looks for the first zone with enemies and then gets the best target for the bomb out of those enemies, prioritising zones near the base first then zones near the bomber in order of distance. I want to make the following changes: o Once get to the ‘cycle through zones by distance for targets’, if we have a land zone that has targets, then consider the next 6 zones and include any that are within 100 of the zone chosen before going on to pick the best target. Also do this if there are targets in the zone the bomber is in. o Get the closest >80% complete enemy T3 MAA/T2+ Naval AA or SAM, and the closest ‘high value category’ >80% (or 25% if experimental level) unit (T2+ building+navy, T3 land), and target this (or if a significantly better value AA target is nearby, target this – i.e. this is a test based both on the distance of the target to the bomber, and the value of the bomb, but subject to limits in both cases. ▪ Factor in the o If there is no AA, then go with current approach of targeting the highest value target. o Increase the value of a target by 10% if it is within 15% of the bomber’s facing direction. Significantly increased the threshold of enemy AirAA required for an experimental strat bomber to retreat from, both generally, and to increase both based on nearby groundAA and on the total number of experimental bombers owned. Fixed a bug where experimental bombers would run from groundAA instead of AirAA. Once an experimental bomber has turned around after firing its bomb, it should keep moving towards the rally point for a few seconds (where it is relatively far away) before getting new orders, to reduce the risk it turns around (trying to target the new target) and ends up flying over enemy AA. When making changes I realised there was a major bug with the Ahwassa targeting logic where if it wanted to target a structure it would get the best location to fire a bomb, but never actually fire the bomb there! When getting the damage dealt by a bomb for units who wont be killed outright, the value % of the unit’s mass cost should be limited to the % of its max health that will be dealt. This 143 ● ● ● means the ahwassa should be more likely to target a T3 army accompanying a GC compared with targeting the GC. Fixed a bug where units with 0 enemy combat threat and 0 friendly combat threat but which contained enemy units would be ignored (e.g. a zone with only enemy mexes, pgens etc. would be ignored) Expanded the factors taken into account with whether to ignore a zone, so zones with an AA threat but no combat threat should still be considered even if they have a friendly combat threat, to strike a balance between e.g. a couple of T1/T2 tanks meaning the ahwassa won’t bother Adjusted the experimental builder to be more likely to build an ahwassa even if lacking in air control - instead of being based only on the number of Yolonas that the team owns, it’ll be based on the number of game enders (e.g. if the team has 1 mavor/scathis/rapid fire artillery, then it will want at least 3 Ahwassas before trying to get Seraphim to build a Yolona). Also made it more likely to be built when we have high numbers of land experimentals or T3 arti. 2.38.2) Replay 20137011v7 M28 1. Fixed a bug with determining if the enemy has AA threat in an adjacent zone (which would use the current zone instead of the adjacent zone). I suspect this may make gunships far more timid than before so may require future refinement, but it was also potentially the cause of scenarios where gunships would fail to attack poorly defended enemies. 2.38.3) Replay 20141289 v8 M28: 1. Increased ACU aggression so it now factors in allied threat in adjacent zones when deciding if it needs to run. 2. Restricted calculation of the enemy best range to units that are almost constructed to avoid units running from e.g. under construction experimentals. 3. Increased the amount of build power to be assigned to T2 arti production when faced with a very large long range enemy threat. 4. Engineers assisting a shield shouldn’t be reassigned as part of the logic to reassign engineers with lower priority actions. 5. GCs should no longer be treated as having an indirect fire weapon (in addition to a direct fire weapon). Also adjusted the logic for managing land units so if they have the same range as the enemy (but are in the part of the logic that is based on outranging the enemy or having equal range with far greater threat), units with the same range should consider attacking. 6. Experimentals that have enemy experimentals near them should move towards them instead of attack-moving towards them in some cases (broadly where they would normally retreat but the enemy has experimentals that are too near them so they will attack to do some damage rather than dying doing nothing). 2.38.4) Replay 20142350 v8 M28: 1. There was a bug where units that weren’t completed would be sent for land zone orders (resulting in an error message when this was attempted with an ahwassa) – this should no longer happen. 20142613 144 1. If MML are firing and their missiles are being stopped by TMD, the zone should flag it wants indirect support and be slightly more likely to build MML. 2. RAS SACUs should assist shields that cover T3 arti or gameenders as a top priority if the enemy has its own arti. They should also assist if the shield is under construction. 2.38.5) Other (non-replay based) changes 1. Quantum gateways (and hence RAS SACUs) should be built on 20km maps even without a resource modifier if the AI has some spare mass and all T3 mexes in the zone 2. Units such as the megalith with a direct fire range of 64+ should now attack-move even if they have significantly more threat than the enemy (given they cant retreat easily and their range means it is better to adopt a gradual approach of attacking the enemy). 2.38.6) FAF develop upcoming release – compatibility The upcoming FAF develop changes (expected late June 2023) change how AI brains work in FAF, with custom AI each having their own brain class to use. Jip helpfully talked through how to update M28AI to reflect this new approach: https://youtu.be/bpdHM2-QXQk Copying the code Jip DM’s me re this with minor tweaks (to reflect the location where I’m keeping M28’s brain class, which is a new file M28Brain.lua) and it appears to be working although I’ll want to test some more when the changes come out to make sure. 2.38.7) Basic pre-release check 3v3 on TwinRivers vs RNG as AiX 2.0 – A fairly close game – RNG killed 1 M28 with an early experimental along with the majority of its base and maintained an eco lead, but M28 was still able to handle the experimental attacks (just). However I came across a bug so didn’t let the replay play out fully. The main reason for the game was to check M28 still seemed to be achieving similar results, and it managed a health 4:1 kill:loss ratio for much of the game so without analysing in detail it hopefully is ok. I also did a part-game of 2 M28 AiX 4.0 against each other on Africa to check for any very obvious bugs. 2.38.8) Acknowledgements: ● ● Jip – video call and code for the new AI brain class in the upcoming FAF develop release Radde and Azraeelian Angel – replays 2.39) V10 – Building a game ender under T3 arti fire 2.39.1) Special shielding logic - Planning I’ve seen a few replays now where M28 (with a resource boost) out ecos the enemy team but the enemy gets T3 arti and gradually blasts M28 into submission. Back when I was still planning on updates to M27 I did some sandboxing on possible shield defence against an enemy mavor. Shield cycling was only really viable for UEF and Seraphim T3 shields as an option, but a potentially easier approach to defending would be to aim to have 3 T3 shields covering a high value target (mavor/T3 arti), 2 of which are constructed and 1 which is near-complete. 1 of the constructed shields is marked for assistance, and the other gets ctrlk’d when depleted (so it can 145 be rebuilt). That then means I need 1 T3 shield to be able to survive long enough for the shield to be ctrlk’d , the destruction animation to cease, and a new shield to be constructed. The problem with this is that Cybran shields suck, so I really need to try and build non-Cybran shields to protect somewhere (e.g. it might be worth allowing any shield to be built as the first shield, but the 2nd+3rd should be seraphim if that’s an option, or if not then UEF or Aeon). For example, a UEF T3 shield has 17k health, and a Seraphim T3 arti does 5k damage a shot. This means that I could in theory survive 4 T3 arti shots a cycle with the above approach. The T3 arti shots fire every 6 seconds, with Aeon and UEF T3 shields needing 4k/5k build time (Sera requires 5.8k but can absorb an extra T3 arti shot). I’d noted the destruction animation speeds as being (in order from fastest to slowest) Aeon, Cybran ED4, UEF, Seraphim. Testing again, with a UEF T3 shield, even with lots of RAS and building on the old wreck (something that would be even harder for AI to achieve) I wasn’t able to maintain shielding against 4 T3 arti. I therefore need to eliminate/reduce the build death animation as a factor, so want to have all 3 shields in a cycle of being destroyed and rebuilt. I.e. the idea would be: ● ● ● ● ● Identify 3 shields that cover the game ender/T3 arti, and ideally cover each other and (even better) are adjacent to each other so engineers can reach all 3. Keep engineers in a location where they are in build range of all 3 shields. ‘Idle’ state – have 2 shields at 99% construction, and 1 shield complete. When a shield drops to 0 shield health, then complete 1 of the 99% complete shields and ctrl-K the shield that has gone to 0 health (don’t ctrlK if we have no under construction shields though) Start rebuilding the shield in the wreck location of the old shield (so it starts 50% complete). o This will require checking every tick for if the location can be built on. Given how much work this will be, I only want to attempt it to build a game-ender (rather than T3 arti), and only if my AI has a large gross mass income (at least 100 per tick mass). I also want to consider trying the shield cycling approach if there is enough build space, since it has the advantage of not requiring mass to maintain. However, this depends on how easy it is to manage the shield cycling. In particular, I want to know whether shields will recharge when disabled (if not depleted fully), in which case it becomes much easier to do shield cycling. However it looks like they don’t recharge at all when disabled, in addition to having quite a while before they will become enabled again. A UEF T3 shield will become active somewhere between 5-6 seconds from being enabled. This means that shield cycling logic would need to have multiple shields active at different levels. I was able to fit 5 T3 UEF shields and 1 T3 arti with 3 T3 PGens in an area (with all shields covering each other). When active the shields heal 131 hp/s, and when down they effectively heal 708 hp/s. Therefore, with perfect timing (which I expect to be effectively impossible) 5 shields would provide 3540 hp/s healing. 146 However, I would need to reliably estimate the point 6s away that a shield would fail, in order to enable a new shield. In addition, aoe damage would cause multiple shields to take damage at the same time, in addition to FAF’s shield overflow logic. Therefore while it would probably be well suited to defending against a single mavor attack, it would be weak against multiple T3 arti due to the less predictable nature of shots. UEF Shield SACUs provide another option, but they’re not well suited to prolonged/attritional games, as while they have a large health pool (52k) they regen at only 150hp/s normally and 241 hp/s when depleted. So while they’d be able to reduce the risk of a shield not being active, and would also fit into a smaller area, I’d need far more of them. The small size of the shield means they’d be unable to protect all the T3 power around a mavor, only the mavor itself (and up to 2 T3 power adjacent to it) Testing in sandbox, against 4 power assisted T3 arti, I would need to enable the UEF SACU shield preset around the 35%-40% level (broadly, the point at which the shield would fail if it took 7 T3 arti hits, being 4 + (4-1), since the new shield wouldn’t activate in time from when the previous T3 arti volley hit, meaning it needs to survive 1 fully volley plus any remaining shots of the current volley (which could be anywhere between 0-3 arti shots). Doing some rough sandbox testing, with 6 SACU shield presets active/recharging, the first one that was failed was on 42% when the 6th one’s shield failed against 4 power assisted T3 seraphim arti (and that was with imperfect cycling where I activated some shields too late – so in reality it would be below 42% if done ‘correctly’). Assuming it would be 40%, then that implies I would need 15 UEF Shield SACUs to continuously protect 1 mavor/game ender from 4 T3 arti. Obviously that many shield SACUs would require a lot of T3 pgens that couldn’t be protected (each shield SACU costs 1k energy to maintain). The mass cost alone is 7600 to build 1 SACU, meaning a total mass cost of 114k. So while it is less than the 4 T3 arti (70k each, so 280k total), if factoring in the game ender cost it ends up much more. E.g. a Mavor and 15 Shield SACUs would cost 339k. This despite how the T3 arti would be wrecking havoc on M28’s eco and buildings outside the shield SACU range. Compared with a RAS SACU, it costs 6.6k and yields 11 mass per second, so the mass equivalent income of this setup of 114k shield SACUs (ignoring power, which has a big impact) would be at least 190 mass per second. That mass would allow a UEF T3 shield to be built over the wreck of an old T3 shield every 8.7s. However, 4 T3 arti would be firing c.20k damage (enough to overwhelm a T3 shield) every 6s. So overall it doesn’t seem like a massive difference between the two approaches: ● ● Shield SACUs vs T3 shield building: Pros: o Less build space required o Easier to code the logic Cons: o Less resource efficient (incur the cost of the shield SACUs regardless of whether they’re used) o Smaller area protected o Requires large power grid 147 o o Requires UEF tech Potentially subject to change (although this has been rumoured for 2+ years and not yet happened) Revisiting the idea of having Seraphim T2 shields be built, I’d originally discounted this because the shield was too weak to withstand a single mavor shell (meaning the aoe from a mavor could sometimes damage the building being covered by the T2 shield, even if the shield was on full health). However, it could be an option to defend against mass T3 arti, given the individual damage from each shell is much less. A Seraphim T2 shield costs just 700 mass, or 350 if being built from 50% (a T3 UEF shield is 1.65k from 50% health. So, if the aim was to protect a single high value building (game-ender) from T3 arti I could in theory get away with just building T2 shields. I’d also need less build power, needing only 1.25k build power to fully build a T2 searphim shield vs 5k for a T3 UEF shield. Regardless of which approach I use, I need logic to send an engineer from one faction to another zone, so I can get the best shields needed (especially if I have a cybran on the team given how poor their shields are). 2.39.2) Special shielding logic - M28 planned approach – game ender and shield coverage idea (strikethrough text denotes originally planned changes which I decided would be too much effort for now as it took much longer than hoped to get the shield assist logic working). For now I’ll try a simplified approach that makes use of M28’s existing systems where possible: ● ● When determining the best location to build for a game-ender or T3 arti, adjust the building size as follows: o Yolona Oss and Scathis (size 8) – look for an experimental bomber (size 16) build location o T3 arti, Mavor and Rapid Fire Artillery (size 8) – look for a Czar (size 24) build location When construction is started on a game ender (and isn’t to be aborted), or a 100% complete game ender is created for which construction start hasn’t been run, and it’s owned by M28AI, change the normal logic for updating whether a location is buildable as follows: o First look for 3 shield build locations that can be built close to each other and the game-ender/T3 arti, and record these locations against the gameender o At the same time record the best engineer shield tech available – use the team table to track what factions we have T3 land factories for, and then cycle through core zones to identify the nearest zone with that faction. Prioritise engineers as follows: ▪ Seraphim ▪ Aeon ▪ UEF ▪ (Other – no faction requirement) o Record the closest such factory to the gameender position against the gameender, and record against the factory the unit(s) that it is recorded as being the nearest source of engineers for. Also record against the zone the factory is in, in a table of factories with priority engineers. o If the factory dies, update this recording for the game-ender. If the game-ender dies, update for the factory. 148 o ● ● ● Factory builder - if it has any game-enders assigned as needing its engineers, and check if there are at least 3 T3 engineers of its faction traveling to the same zone as the game-ender. If not, then build an engineer as a near-top priority. ▪ Determine this by having a flag for if we need engineers of a particular faction as part of the ‘want BP’ approach for engineers for the zone in question, so the factory builder can just check for this flag status. o When attempting to build a unit, if a particular faction is required (e.g. for this logic or for any other logic I might introduce), then a flag should be set that the zone wants engineers of that faction. o Then look for if there are any T3 power adjacency locations (if dealing with T3 arti, mavor or rapid fire artillery) and record these locations against the game ender o Also record the game ender against the land zone o When the game-ender dies, update the land zone to no longer have it recorded Treat any such recorded shield build locations and power build locations as being ‘blacklisted’ for normal construction. Have a high priority action for both core and minor land zones – if the zone has any factory that is a key faction engineer builder (see above), check if the zone of the game-ender it is getting engineers for has at least 3 T3 engineers of the desired faction. If not, then send an engineer of that faction to that zone (subject to how many engineers of that zone are already traveling there). o Need to factor in the optional variable to the ‘send engineer’ existing action and/or add a new action since will want to send it both the zone to travel to and the faction wanted. Have a high priority ‘refActionSpecialShieldDefence’ action for engineers if the zone has a gameender: o Focus on the game ender in the zone with the most invested mass o Track the engineers assigned as such against the game-ender unit they are trying to protect, and if the game-ender has no active engineer shield thread, start a new thread to protect it, that runs as long as the game-ender is alive. Active shielding thread: ● ● ● ● ● Check if we have build shields in all of the preassigned locations. o If we have any M28AI owned structures in the location that aren’t shields, then ctrl-K these to create space. o Track the actual shield units against the game-ender being shielded, along with the number of the valid locations, so can easily compare the size of the shield units table against If not already started construction, then limit to the faction of the shield that we want (see above re recording the best faction available). Build T2 seraphim shield if enemy has no mavor, otherwise build T3 shield. When a shield construction is started, if it is by an engineer with the relevant active shielding action, then the shield should get recorded against the game-ender assigned to that engineer. When deciding how many shields are available and under construction: o We want 1 shield that is both fully constructed, and has an active shield (ignoring power stall). o If there are no shields that are constructed with > 0 shield health, then construct another shield. 149 o ● ● ● If we have 3 shield units, and at least 2 are constructed, and at least 1 has 0 health, then ctrl-K the shield with the lowest health (also do this if all 3 are constructed even if none have 0 health). Want 500 build power assigned (enough to build a T3 UEF shield every 5 seconds) if are defending against arti, otherwise just want 100 build power assigned. Adjust any power builders so if there is a gameender with power adjacency locations and no assigned power, then will build the power in that location. When deciding on the build location for a gameender, prioritise the location furthest from the enemy base (assuming multiple options). o Have a high priority engineer builder to build the game ender in that zone o Determine the faction(s) of engineers wanted for that zone and get them sent over as high priority actions. Other changes made while testing for this: ● Increased the threshold for a team to be considered to always not have low mass to 400 per tick from 200. ● M28 took 30m with a paragon and being cheated lots of engineers and still failed to have a game-ender completed, with mass overflowing and engineers sitting idle. This was because it thought it had low power. Now if it has a gross level of power similar to that of a paragon it should proceed as if it doesn’t have low power. ● When searching for a part-complete building to assist, it should be ignored if that unit has been assigned for special shielding (so e.g. a unit trying to build a shield as part of the normal shielding logic doesn’t complete a near-compelte shield that has been prepared as part of the special shielding logic. ● I noticed a likely bug where if reclaiming an enemy unit the tracking was being done in the wrong order so the the unit would track the action then have that tracking cleared. ● During testing I came across strange results where engineers would stop assisting a shield construction 2 ticks ahead of the shield being completed, but the shield would still be completed, and this would happen before it showed as completed on screen/in game. I therefore will stop construction once a shield hits 99%, or it is estimated to be 2.5 ticks from completion. ● Another issue that came up during testing was that when getting units in a rectangle, it would get units outside that rectangle – e.g. in the below screenshots, both mexes build location was outside the rectangle (drawn in blue), but getunitsinrect would still return them, resulting in the mexes being killed despite not being a blocking unit: 150 This also highlighted a number of other issues: ● ● ● ● ● Killing mexes and hydros wont make any difference to freeing up build locations (so I want to ignore these when searching for buildings to destroy) The ‘kill’ logic was triggering when construction was started of a part complete building. Investigating further, there can be a fraction of a second between when the shield monitor thread checks for if a location is buildable, and when the event for construction being started triggers, meaning it thinks it can’t build somewhere, and that there is no shield in that location, but actually there is a shield that has just started construction in that location. This is because the thread is forked when it triggers to avoid the risk that something in M28 that goes wrong causes the core FAF game to go wrong. To try and get around this: o A delay is required before constructing a shield, to require construction to be wanted for at least 1 tick before, so I’ll track the ‘previous action’ of engineers doing this active shielding, and not do anything when they want to construct a shield for the first time (as well as clearing their actions if previously they were assisting a shield, in case the shield is one that is almost constructed). If there is a shield blocking a build location, then that shield should be incorporated into the special shielding logic. Engineers shouldn’t be treated as available (with the general approach) if they are assigned to special shield defence. Added in a similar builder for minor land zones that have gameenders (for niche cases on large mass games). 2.39.3) Adaptive dark card and map zone adjustments 151 Adaptive dark card’s land zones had an issue where the central area would get included with one of the start zones: The initial creation from this looks ok: 152 The issue was with the assignment of areas without a zone. I made the following adjustments to the logic: ● ● ● When dividing up parts of a map with no zone, the points chosen should be symmetrical on a square map Reduced the distance for assigning segments to an existing zone on maps that are 512 or smaller in size. Small adjustments to the zone generation code relating to this which I hope might make it fractionally faster although the difference wouldn’t be noticeable (noted more so if I look back I know I made some changes to things including a potential bugfix that shouldn’t have had an impact). After these, the zone generation gave: 153 154 ● ● ● There were also error messages which would happen at the start of the game due to civilian controlled underwater mexes, as the code assumed that any mexes would be owned by a brain with enemies. I therefore added a delay to when this check is done, and if there are still no enemy brains then it should search for any non ally brains. Another issue was that some of the water zone team variables weren’t setup by the time the civilians were identified/revealed in the water, leading to other errors. Hidden warning message about mexes at the start of the game that would result from the initial map setup logic thinking the mexes weren’t valid/available (due to a building being on it), and then the logic for recognising the unit later triggering and thinking there was an inconsistency as a mex managed to be built somewhere that wasn’t considered available for construction. 155 ● When the zone was being extended and caused the PD to be included, it resulted in the Orange ACU in the above diagram trying to attack the PD instead of building the factory. I therefore want to have the ACU ignore enemy structure threats if it is still doing its initial build order, and also ignore threats that are far away from its current position if it’s doing its initial build order. 2.39.4) Profiling late-game with experimental bombers The following is a log of almost 6 minutes in the late-game where M28 had 3 active Ahwassas (as the game was slowing down occasionally), although I don’t know how reliable it is as I might have paused the game during part of this: info: ProfilerOutput: No.1=ManageExperimentalBomber; TimesRun=360; Time=54.929748535156 info: ProfilerOutput: No.2=GetDamageFromBomb; TimesRun=26309; Time=54.724731445313 info: ProfilerOutput: No.3=IsTargetUnderShield; TimesRun=941156; Time=38.741760253906 info: ProfilerOutput: No.4=ManageAllLandZones; TimesRun=3572; Time=18.12939453125 info: ProfilerOutput: No.5=ManageSpecificLandZone; TimesRun=16904; Time=14.75634765625 info: ProfilerOutput: No.6=GetBestAOETarget; TimesRun=116; Time=8.796875 info: ProfilerOutput: No.7=ConsiderLandOrWaterZoneEngineerAssignment; TimesRun=16904; Time=5.1810913085938 info: ProfilerOutput: No.8=GetCurrentAndMaximumShield; TimesRun=4583176; Time=5.1098022460938 info: ProfilerOutput: No.9=ConsiderCoreBaseLandZoneEngineerAssignment; TimesRun=1800; Time=3.38037109375 info: ProfilerOutput: No.10=RecordGroundThreatForLandZone; TimesRun=16904; Time=3.2745361328125 info: ProfilerOutput: No.11=ConsiderActionToAssign; TimesRun=35270; Time=2.1931762695313 info: ProfilerOutput: No.12=GetCombatThreatRating; TimesRun=85054; Time=2.1148071289063 info: ProfilerOutput: No.13=ManageAirAAUnits; TimesRun=360; Time=2.0195922851563 info: ProfilerOutput: No.14=ConsiderMinorLandZoneEngineerAssignment; TimesRun=15104; Time=1.6680908203125 info: ProfilerOutput: No.15=ManageRASSACUsInLandZone; TimesRun=1583; Time=1.6134643554688 info: ProfilerOutput: No.16=ManageGunships; TimesRun=359; Time=1.254150390625 info: ProfilerOutput: No.17=FilterToAvailableEngineersByTech; TimesRun=16904; Time=1.1463012695313 info: ProfilerOutput: No.18=OnEnhancementComplete; TimesRun=22; Time=1.0410766601563 info: ProfilerOutput: No.19=RecordClosestAdjacentEnemiesAndGetBestEnemyRange; TimesRun=16904; Time=0.9609375 156 info: ProfilerOutput: No.20=CanBuildAtLocation; TimesRun=366467; Time=0.8946533203125 The time managing these bombers is unsurprisingly very high (as given the significance of the unit they will do far more intensive calculations than others). However, it looks like the main cause of this is checking if a unit is under a shield or not at 38.7s. One possible way of shortening this might be to as part of the land zone and water zone management do a check on if there are shields in that zone, and to then only run this logic if there are. However, this runs the risk of inaccuracy (1s delay on mobile units, and shields being on the edge of a zone where they can provide cover to units not in that zone). I’m also not sure how much it would actually help as in this case the bases were heavily shielded so it’s likely most units being considered did have shields in them. Another option is to reduce the number of times the function is called in the first place, but this would require further filtering of the experimental gunship targeting logic. Looking at the function itself for potential optimisation, it is making use of GetUnitsAroundPoint as the way of identifying nearby shields. I could therefore have a time check of the time a unit was last checked for if it has a mobile shield, coupled with a true/false flag, and only refresh if the last check was more than 0.9s ago (menaing e.g. in the case of multiple experimental bombers the time taken isn’t increasing in proportion to the number of bombers, while for things like novax it should still be responsive to a target going under a shield). However, this would need to make use of a table approach given the different potential input parameters for the function. After this change the game didn’t desync (suggesting the decision made by the experimental bomber was unchanged) but the stats were much better, even if allowing for pausing the game potentially affecting things (i.e. the % of the time of getdamagefrombomb taken up by checking if a target is under a shield is lower): info: ProfilerOutput: No.4=GetDamageFromBomb; TimesRun=26309; Time=13.608703613281 info: ProfilerOutput: No.14=IsTargetUnderShield; TimesRun=941156; Time=1.3123779296875 The game still ran slowly, but not as slowly as it might otherwise have done. I’ll therefore spread out the logic for experimental bombers over a max of 3 ticks to help alleviate the issue. 2.39.5) SC Campaign – UEF Mission 1 ● ● This has the issue that only mexes can be built initially, whereas M28 assumes it can build a land factory. I therefore add some backup logic for campaigns where if the ACU doesn’t have an order it will try building a mex; then power; then a factory (land, then air, then navy). This then revealed another issue – if M28 builds the mexes (as player 2), the next part of the campaign doesn’t take place. Investigating further, the campaign script will only check ‘HumanPlayer’ armies. E.g. the objectives such as build 3 mex or build 3 PGens are limited to Armies = {'HumanPlayers'}, in the SCCA_Coop_E01_script.lua function StartMission1Part1(). This comes from ScenarioFramework which in turn comes from SimObjectives.lua, which has a function ArmyStatCompare which receives the ‘Target’ variable (which for this objective is a table containing Armies as one of the keys). 157 ● ● ● ● ● ● The list of brains to consider is based on the line local armyBrainsList = MakeListFromTarget(Target), so I did a destructive hook of this, copying the code with the change that an M28AI brain will count as a human. When overflowing mass (/at 99% stored) without low power, further factories should be built regardless of eco conditions and pathability. Increased the likelihood of MAA being built at T1 (and generally) – previously it wouldn’t be built at T1 in most cases on the assumption that we could get T2 (which is far better). Now it will still consider building it if the enemy has significantly better air to ground threat than our MAA (with this threshold decreasing after 10 minutes). Increased the travel distance that land factories will search for enemy targets to build units to counter when more than 50% mass is stored to 100% of the distance to the nearest enemy base, along with a minimum range of 250 (M28 works on the assumption for normal skirmish that if there are no enemies within 75% of the nearest enemy base then it is better to put the mass into ecoing and experimentals, which isn’t an option in campaign, resulting in land factories idling while overflowing mass). Fixed a bug that meant adjacent land zones weren’t being recorded. I don’t get how I have gone so long with M28AI with this bug as at first glance the bug should’ve meant no adjacent land zones would ever be recorded, yet they still seemed to have been so I’m guessing I wrote some sort of redundancy that usually but not always kicks in. Once we have at least 150 combat units in a land zone then they should attack even if the enemy appears to have more threat. 2.39.6) FA Campaign Mission 6 – Further changes/Capture the control centre One bug highlighted to me was that M28 would reclaim the control centre instead of capturing it where the enemy AI had captured it. To help potentially resolve this, I first need to be able to figure out when a unit has been captured (since the old unit gets destroyed and a new unit created in its place, meaning variables I assigned to the old unit such as that it should be captured will be lost). Doing a hook of the following achieves this, where tUnits is a table of the newly captured unit(s), and bCaptured is true if the unit is captured: import('/lua/SimUtils.lua').TransferUnitsOwnership(tUnits, iArmyIndex, bCaptured) I therefore want to check the following: ● ● ● ● ● ● When a unit is captured, if it is a campaign map, then check if the captured unit is on a different team now to the first M28AI in the game. If it is, then check if the land zone has any capture targets. If so, then cycle through each recorded capture target, and check if their unit ID is the same as the unit that has been captured. If so, then add the captured unit to the table of capture targets. Also add a flag to capture targets both at the time of the objective and on any recapture to note they shouldn’t be reclaimed but instead should be captured. Adjust the engineer ‘reclaim enemy’ special logic so instead of trying to reclaim the nearest enemy it should try to capture it if it is flagged as being capturable. 158 After doing all of this it still didn’t work so I investigated further and it turns out this objective doesn’t use the ‘AddObjective’ function that all the others until this point have. To fix this, I therefore add in some manual code whenever an objective is added or the map size changed to check for if the control centre exists and is capturable, and if so I add it as a capture target. Other Mission 6 changes ● Added some redundancies for when the enemy start position isn’t on a land zone, including searching slightly around the nearest enemy base for a land zone, and using a more precise terrain label check to see if the enemy base is in the same island as the factory. ● There was a bug with SACUs getting upgrades where M28 wouldn’t realise they already had an upgrade and would keep trying to get it. 2.39.7) MML synchronised shots I’d held off adding this logic to M28 for a while as for M27 it rarely got featured. However, M28 tends to build more MMLs than M27 so I figured I’d add in something basic to help give it a slight boost on those scenarios. If zone has mml that has been intercepted by tmd in the past 15s, and mml outrange enemy df and indirect fire, check if have only non-aeon tmd (ie both have non aeon tmd and no aeon tmd), and no loyalists, in either the current zone or an adjacent zone, and that we have an indirect threat in the current zone of at least 700. bConsiderSpecialMMLLogic If satisfy the above, then when cycling through units for scenario 1 and 2 add mml to a new table instead of giving orders. tMMLForSynchronisation Special logic for table of MMLs: First record a table of all enemy shields and tmd in cur and adjacent zones, and filter this down to those that we lack intel on which are at least 30% constructed —want to stay at least 5 out of range of any PD or mobile units (normally would be 10+) Find the closest TML+TMD Attack-move towards it if we are more than 5 out of range, otherwise issue a ground attack at this target’s location. Also record any such (within 5 range) MML in a table of attacking MML in the cur zone. Determine whether firing cycles of mml are far enough apart to warrant disabling weapons: ● ● ● ● Want at least 4 MML before considering synchronising want missiles fired within 1s of each other however if unit hasnt fired for a long time then dont want to disable if 75%+ of mmls in sync or 25%+ havent fired for a long time then dont disable When enabling the weapon, if mml is flagged as having a time the weapon was last disabled then set this to nil and clear from the team table(see below) 159 Otherwise disable the MML weapons: When disabling the mml weapons, record the time the mml weapon was disabled, and include in a table in teamdata. Team cycler – every second check for table of weapon disabled inits. If time last wanted the weapon disabled was more than 2.1s ago then enable the weapon When testing I noticed that my MML threat was being included based on the ‘direct’ threat value given (which is much lower) which may have led to some strange decisions. I’ve therefore updated so that indirect fire units have their indirect fire threat calculated if they have no direct fire weapon. Another issue is that some MMLs fire a salvo, meaning the estimate of the time between shots isn’t accurate. To help mitigate this (as the original logic meant the MML would all be paused because the code didn’t think they were ready to fire yet), I’ll also calculate the average time for the MML until they’re ready to fire, and enable firing if 80% of the MML are within 1s of the average, or if the difference between the longest to fire and shortest to fire is less than 1.5s. I also noticed when testing there was a bug with DF support units with trying to get the closest indirect fire unit to support, and that DF units were a bit too aggressive when the enemy was adjacent to the core zone (given the size of land zones means often this can be near the middle of the map), so I adjusted to make it less likely outranged units will attack from the core zone if the enemy is in an adjacent zone. 2.39.8) Ecoing adjustments ● ● ● ● ● Changed how priority mex upgrade logic works to try and spend a base level of mass upgrading mexes, and to focus on safe mexes where the team has some, rather htan trying to upgrade 1 mex per brain. Also adjusted the thresholds so even when mass stalling M28 will try to upgrade mexes. This resulted in further adjustments being required to when land factories upgrade (with a high priority upgrader added where there are lots of T3 mexes nearby). Emergency PD builders should factor in all PD along the path to the nearest enemy meaning if there is an allied base with PD in it then less PD should be built in the rear M28 player’s base. HQs should be less likely to be paused in a mass stall Idling air factory HQs should consider building engineers if there is at least 1k mass stored. 2.39.9) Other changes 1. If an engineer attempts to build a factory and fails (e.g. a T3 Seraphim engineer tries to build a T3 Air factory when the owner only has a T3 UEF air factory) then it should now try and build a factory of that type of any tech level instead of failing to build anything. 2. Fixed a bug where fatboys could be treated as being gameenders (due to being an experimental artillery unit based on categories). 3. Fixed a bug where no build locations would be identified for SMD (which in theory should’ve meant no SMD ever got built, but I’m guessing some redundancy logic meant SMD would very occasionally be built, hence why I didn’t notice it sooner – thanks to Fearghal for flagging the issue). 4. Fixed a bug that would cause M28 to break in rare cases on maps, e.g. such as on the map Abhor (thanks to Relent0r for flagging this map) – it happened where there was an inconsistency between the plateau based on the terrain label for a segment, and what was 160 actually recorded as the plateau for that segment’s assigned land zone. Also thanks to J_W_W who highlighted the same bug on Concord Lake 5. Gunships should try and avoid active friendly M28 nuke targets (to reduce cases where a massive gunship ball gets wiped out by a friendly nuke). 6. Fixed a bug with experimental bomber targeting where it would target all units when trying. 2.39.10) ● ● ● ● ● ● ● Acknowledgements: Fearghal (highlighting issue with SMDs not being built; also later confirmed by tyne141) Radde – several replays against a 1.5 resource mod M28 J_W_W and Relent0r – errors where M28 wouldn’t work on a couple of maps Pedro_Lima – highlighting FA Mission 6 issues with capturing the control centre Unknown – I made a note that someone had highlighted one of the custom campaigns where M28 attacks PD at the start, but can’t find the comment now (I recall it was an issue either with golden crystals or raid. Since golden crystals has PD near the start I’m assuming it was that map, and a bugfix made more generally looks like it’s solved that issue). Russtymango Naval replay (sorry if I missed anyone out – I had some rl issues so wasn’t able to look at a number of issues prior to then) 2.40) V11 – Transports, optimisation and M2 SC UEF 2.40.1) Optimising for naval maps - Selkie Isle Thanks to Radde who highlighted how long it takes for M28 to load at the start of the game on this map – running profiling it was taking Profiling: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=172.03498840332 info: ProfilerOutput: No.2=RecordIslands; TimesRun=1; Time=161.7625579834 info: ProfilerOutput: No.3=SetupLandZones; TimesRun=3; Time=5.7037582397461 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=3.5779571533203 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=11134; Time=3.5703010559082 info: ProfilerOutput: No.6=SetupWaterZones; TimesRun=2; Time=1.2650299072266 info: ProfilerOutput: No.7=AssignMexesALandZone; TimesRun=1; Time=0.98745727539063 info: ProfilerOutput: No.8=CreateWaterZones; TimesRun=1; Time=0.68331909179688 info: ProfilerOutput: No.9=RecordWaterZonePathingToOtherWaterZones; TimesRun=1; Time=0.52227783203125 info: ProfilerOutput: No.10=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.50600051879883 Splitting the RecordIslands function into 3 parts based on how the code is setup, it’s clear that the third part (calculating pathing) accounts for all of the time taken: info: ProfilerOutput: No.2=RecordIslands; TimesRun=1; Time=162.75033569336 161 info: ProfilerOutput: No.3=RecordIslands: Pathing; TimesRun=1; Time=162.7501373291 I already only consider pathing to islands with mexes in. One further possible optimisation would be to only consider generating pathing for zones with mexes in them. Checking where the pathing gets used currently, it affects the following: ● ● ● ● ● ● ● ACU that doesn’t have a land zone to move to Engineers moving to an island from a core base (shouldn’t be impacted by the change since a core base would be expected to have mexes in it) Engineers moving to an island from a minor zone – could be impacted, but not a big deal given core bases should be able to cover any engineer requirements Factories checking if a nearby island wants engineers or amphibious combat units – unlikely to be impacted given factories tend to be in core zones (exception would a factory built on an island as a forward base, but even then often the factory will be on a location with a mex, and even if it doesn’t end up building amphibious combat units this isn’t a big part of M28) Land units looking for somewhere to support where there’s no land zone (i.e. on the current island) to support – this is the main issue/use case where having no island could cause issues. However, this is only relevant for amphibious/hover units. They also have a redundancy to move towards the enemy base if they have nowhere to support, so hopefully this would help and it would only be relatively niche cases where there could be problems, e.g.: o Units try moving to an island to support it o They come across a land zone on the way that has no mexes o That land zone has a greater ‘value’ than the zone they came to, meaning units take their orders from it o Units get sent to the enemy base, and that is in a different direction o They go back to the original land zone and the cycle repeats. However, I’m hoping this should be rare given most of the time a zone with no mexes will be smaller than one with mexes, and all else equal will have a lower value, and often the zone needing support will be in the same direction as the enemy base. Another usage is checking if a path is safe; from memory this is only really used by engineers, so again shouldn’t be a major issue. Applying this restriction, the results are: info: ProfilerOutput: No.2=RecordIslands; TimesRun=1; Time=81.08757019043 info: ProfilerOutput: No.3=RecordIslands: Pathing; TimesRun=1; Time=81.087310791016 I.e. it’s roughly halved the time taken on this map, so I’ll definitely retain this change. The main factor in this time, splitting things out further, is logic that identifies the nearest land zone on an island by pathing, with this taking almost all of the 81s: info: ProfilerOutput: No.4=RecordIslands: Excl land path; TimesRun=312; Time=79.514221191406 Another possible change might be if there’s some way I can add a distance cap on larger maps (20km+) for the islands considered, for example switching to recording straight line distance after a certain point (with an approximate penalty). 162 Another possibility is to have a land zone copy the pathing of an adjacent land zone if it has the pathing recorded, although it’d need to figure out a way to avoid 1 zone being copied for the entire island. Switching to distance based results reduced the time taken to less than 1 second: info: ProfilerOutput: No.57=RecordIslands: Excl land path; TimesRun=312; Time=0.003082275390625 I’ll therefore try the following as a compromise since it looks like I have a bit of room to spare: ● ● ● ● ● On any 10km+ map, with at least 45 land zones (30 for a 20km+ map), enable the ‘straight line distance check’ logic. Get the straight line distance to identify the 3 closest land zones from an island. For each of these 3, calculate the actual travel distance. Use this to pick the closest of the three. i.e. this means doing the travel distance check only 3 times instead of for every land zone. After implementing the above, the time taken is: info: ProfilerOutput: No.4=RecordIslands: Excl land path; TimesRun=312; Time=8.0988731384277 i.e. this is almost 10% of what it was taken before. Re-running the profiling, the total time taken now is: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=20.780799865723 info: ProfilerOutput: No.2=RecordIslands; TimesRun=1; Time=10.612384796143 info: ProfilerOutput: No.3=RecordIslands: Pathing; TimesRun=1; Time=10.612213134766 info: ProfilerOutput: No.4=RecordIslands: Excl land path; TimesRun=312; Time=7.8371429443359 info: ProfilerOutput: No.5=SetupLandZones; TimesRun=3; Time=5.5336036682129 I.e. the total time has decreased from 172s originally to just 21s! 2.40.2) Dropping far away locations on the same island Currently M28 will consider dropping on plateaus, and far away islands. However on maps like strip mine there are far away locations on the same island that are best to drop by transport. I therefore want M28 to handle this. This should also hopefully provide the framework for transport dropping on UEF Campaign mission 2. ● ● ● ● Search for any land zones with at least 3 mexes that are within 55% of the distance between our base and the enemy base, and which are on the same island as a friendly M28 base. When looking for potential transport locations, if the transport doesn’t have a target under the normal plateau/island approach, check for the ‘same island far away’ zones and include any of them where relevant. Ignore zones that we have engineers or factories or significant structure value on, or that have dangerous enemy units. While testing this I realised there was a bug with the mod distance recorded for zones. However, it turns out I wasn’t actually using this for anything ( must have added it because M27 makes much more use of the information). 163 ● Any such locations that are successfully dropped should be flagged similarly to an island expansion point so a land factory is built. For this I’ll add in an override option so the logic that says if a zone is an expansion zone will check for the override; then when a transport tries to drop on a land zone it will set the override to true. 2.40.3) Strip mine – 2nd air fac build order ● ● ● ● On maps like strip mine, M28 should try and do a ‘1st land 2nd air’ build order with its ACU, meaning it can make use of the new logic to drop engineers at the far away locations. As part of this, it should try and get the equivalent of 10 T1 PGens It was also power-stalling from building 4 T1 mexes before the hydro, so if there are 5+ mexes in the zone it should only try and build 3 T1 mexes before having the ACU assist the hydro (since otherwise the 3rd engineer starts building a mex and causes the powerstall). Testing strip mine it also took a long time to load – the profiling results are below: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=80.346221923828 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=77.549865722656 info: ProfilerOutput: No.3=AssignMexesALandZone; TimesRun=1; Time=38.173263549805 info: ProfilerOutput: No.4=RecordPathingBetweenZones; TimesRun=1; Time=37.814758300781 info: ProfilerOutput: No.5=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=6162; Time=37.804725646973 info: ProfilerOutput: No.6=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.76557159423828 One of these functions is assigning mexes a land zone. I suspect this is so long because the time taken will increase exponentionally with the number of mexes on the map. Identifying mexes near the start position It potentially calculates the travel distance for each mex to every start position (it will check if the mex is closer on a straight line distance than the closest travel distance, and if so it calculates the travel distance). ● ● While the above figures were for a 1v1, on large teamgames this could be optimised by only considering the 3 closest start positions, on a straight line distance, sorting them from closest to furthest away, calculate the travel distance on the first one, and then keep going only as long as that travel distance is more than any remaining straight line distance. However I spot another easier simplification for now – they were calculating the travel distance to find the closest base, if the straight line distance was below the search threshold. Now that search threshold will be the lower of the closest base found so far, and the distance. Another optimisation similar to the above but slightly easier to code – I’ll find the closest start position on a straight line basis; calculate the travel distance, and then consider the travel distance of all other start positions whose straight line distance is less than that travel distance. Adding mexes near each other mex ● This currently only uses a travel distance calculation. However, I can first do a straight line distance check to see if the mex is close enough to even consider (since the travel distance will only be further than the rough distance). 164 Profiling after changes: info: ProfilerOutput: No.1=SetupMap; TimesRun=4; Time=41.668556213379 info: ProfilerOutput: No.2=SetupLandZones; TimesRun=3; Time=38.939647674561 info: ProfilerOutput: No.3=RecordPathingBetweenZones; TimesRun=1; Time=37.405723571777 info: ProfilerOutput: No.4=ConsiderAddingTargetLandZoneToDistanceFromBaseTable; TimesRun=5852; Time=37.395477294922 info: ProfilerOutput: No.5=AssignRemainingSegmentsToLandZones; TimesRun=1; Time=0.73818588256836 info: ProfilerOutput: No.21=AssignMexesALandZone; TimesRun=1; Time=0.0051860809326172 I.e. this has reduced the time for this function from almost 38s to a tiny fraction of a second, which is better than I’d hoped, and means the load time for the wider map is much more bearable. 2.40.4) UEF Campaign mission 2 I’ve not been looking forward to getting M28 to work on this mission because the objectives will likely require a lot of custom code - - the initial objective requires a building to be repaired. However, due to how M28 calculates pathing it thinks it can reach the objective by land (which it could if the map was expanded), and it doesn’t (yet) have logic to build a transport to carry engineers somewhere on the same island. Even if I get this logic working, the later objective involves building a certain composition of units and moving them to parts of the map, something that will definitely require some hard-coded logic to handle. Repairing the initial objective I’ve been wanting to add logic more generally for transports to carry engineers to far away zones, so I’ll do this first (on the strip mine map), and then return to the first objective here to see if I can tweak that logic (moved order of notes so this follows the implementation of the ‘drop engieners somewhere on the same island’ logic above – i.e. considering M2 was the factor that led to this). For M2, this can hopefully now work as follows: ● ● ● When an objective is added with a unit to be repaired, check if the unit to be repaired is in a core zone or adjacent to a core zone. If it isn’t, then add it as a location to be considered for transport drops. I.e. make sure the zone is in UpdateTransportShortlistForFarAwayLandZoneDrops. When deciding whether to drop a location, if it doesn’t require BP check whether that is because it has engineers traveling there which are far away, in which case still try and drop engineers there. Defending the initial objective After finally getting M28 to repair the objective, I ran into a new problem – it suffers attacks first by enemy air units then by enemy land units, and would have nothing but a couple of T1 engineers to defend with. As a human player this is relatively easy to defend – transport over some T2 engineers, and pre-emptively build some T2 PD and flak. 165 However, M28 doesn’t realise the attack is coming, so doesn’t try and get any defences until it’s too late, at which point it has T1 engineers so can’t do much anything. However, I also don’t want M28 building such defences pre-emptively normally (i.e. in a skirmish game). I see two potential solutions here: ● ● Have M28 improve how it uses gunships and inties to defend Have M28 recognise it’s a campaign map with an objective and build up land factories and a base level of direct fire and AA threat at the location, and hope this is enough to handle the enemy attack waves. For example, I could have M28 treat the location as a ‘core base’, meaning it then builds land factories and air factories, but I’m worried this could have unintended consequences on other maps (e.g. with M28 suiciding units to an objective). An alternative could be designating it as a ‘core expansion’ location, meaning M28 tries to build a land factory there, although I thought it was already doing that (I later realise there was an oversight where I’d only do this if there were a certain number of mexes in the zone). Another option is to allow such locations as air rally points, meaning interceptors are closer and so are more likely to intercept the transports. However, before that I want to understand why when it had 2 T2 gunships and some inties it didn’t try and attack the ground force that had no MAA in it. Investigating, it was because M28 was trying to attack a unit that was outside of the playable area, so for a campaign map M28 will only try and target a unit with gunships if it is in the playable area. However, even after M28 engages the first ground force with its gunships (it only has 2 by that stage) they take too long to arrive and deal damage too slowly to handle the threat, with the objective being destroyed. Other changes made in respect of issues spotted from the replay: 1. The location should be treated as a core expansion location with land factories built if there are units to repair in the LZ (previously it’d only treat a drop location as an expansion if it had 3+ mexes) 2. Units to repair should be removed as objectives if they are at full health 3. Engineers shouldn’t try to reclaim segments whose midpoint is outside the playable area 4. The build power of engineers to reclaim an area should be capped at 5 if engineers have failed to find something to reclaim in the last 3s. 5. Units should not be given any new orders for 1.5s after being built at a land factory (to reduce the risk that they are given an invalid order causing them to stay on the land factory and prevent it building more units). 6. Power should be built at any tech level if there are unit restrictions or a campaign map so t1 pgens still get built if we hit t2 and cant build t2 pgens. 7. Repair targetes should be added to the table of high priority targets to defend (however due to the location recorded for the enemy base this doesn’t help with making AirAA units stay closer to the facility, and I don’t want to change this logic due to the negative impact it could have more generally). 166 8. One other possibility is to see if the transports are created off-map such that my inties can move to their destination at this point, and hopefully beat them to the destination. Cheating isn’t a concern here given a human player would know the drops are incoming and it’s a campaign map. o The transports are created slightly off map but not by much – while my inties attempt to target them off-map, this fails due to the transport being off-map. Therefore I could speed up the intie response slightly if I was to target their destination instead of the transport where the unit is off-map. o I’ll therefore add a check for interceptors to try and intercept the air unit later on if it is outside the playable area (on a campaign map). o This replaces previous logic I had to ignore air units if in a zone that is outside the playable area. o On one replay, the transport was first detected at time 1077.59. The OnCreate event was triggered at the same time. However, in the replay you can see the transport order a few seconds before this, so I’m guessing that the campaign uses a different OnCreate event that isn't being triggered. o The transports themselves are created with: ● ScenarioUtils.CreateArmyGroupAsPlatoon('Aeon', 'M15_Transports', 'ChevronFormation') Which is the lua\sim\ScenarioUtilities.lua file The function will return the platoon with the units in it I’m therefore able to hook this and trigger the OnCreate event which happens 3s earlier than before. I combine this with having M28 send ‘OnCreate’ units for assignment to a zone for all M28Brain teams if it is a campaign map (on the basis a human would have knowledge of where any units originate from) – I don’t want to do this on all games since it’d be an unfair advantage if M28 had knowledge of units the moment they were created anywhere on the map (e.g. making sneak nukes almost impossible). Unfortunately after testing it seems that the navigator target can be completely different to the actual target, so I’ll just ignore the navigator and target the enemy air unit instead. Killing the final base The above testing was all done on hard since I had a hope I might be able to get M28 to complete it on hard. Changing the difficulty to easy, and having myself complete the ‘bulid x units and send here’ objective, I ran into the issue where even with a 1k unit cap M28 would get too close to the cap and stop building, and ended up with almost 150 T1 MAA but only 5 MMLs, unable to break the final base (instead stuck in a pattern of killing the enemy attacks, then sending its 5 MML to fire a few shorts, before retreating when the next attack appeared). The following changes were therefore made to try and reduce the likelihood of this: 1. When near the unit cap, land and air factories below the highest tech level available should try to upgrade if not at low mass, and otherwise should only build if under immediate threat. 2. Air factories that are below the highest tech level and have built at least 25 T1 units should try and upgrade. 3. Made it slightly more likely land factories should upgrade in high mass scenarios – i.e. only requiring we have T2 tech (not T3) for one of the builders before upgrading T1 factories when high on mass, and including a ‘factory lifetime build count’ as part of the condition. 167 4. When near the unit cap, previously no T2 land units would be built. Now though this should only be the case if the factory isn’t at the highest tech level or we have had to destroy T2 land units to free up unit cap space. 5. Certain land units shouldn’t be destroyed as early as before if the highest land factory tech level is less than 3 and it is a campaign map or unit restrictions are present (to reduce the risk of ctrl-king units when they’re the best tech units available). 6. Added a cap on T1 MAA of 80 if are dealing with a T1 land factory (with the cap reducing if we have T2 land) 7. If we have air control gunships should stay by the air support point instead of the air rally point. ACU available upgrades The following code is run which prevents the ACU accessing certain upgrades – this causes a problem as until now it hasn’t needed to check if an upgrade is restricted (instead it only checks if the upgrade is available via the blueprint): ScenarioFramework.RestrictEnhancements({'AdvancedEngineering', 'T3Engineering', 'HeavyAntiMatterCannon', 'RightPod Right', 'ShieldGeneratorField', 'TacticalMissile', 'TacticalNukeMissile', 'Teleporter',}) I therefore want it to maintain a blacklist of restricted enhancements via a hook of this function, and to check this blacklist when deciding what upgrade to get. This function calls the below: SimUIVars.SaveEnhancementRestriction(restrict) import("/lua/enhancementcommon.lua").RestrictList(restrict) Reviewing the code for this shows a function in the file /lua/enhancementcommon.lua: GetRestricted() So hopefully this can just be used and I don’t need to use a hook. Another issue was air units either staying at the original start (taking ages to intercept a threat), or suiciding into the enemy base. The following changes were made to try and get the right balance for this: 1. Changed the approach (added just above) of gunships moving to the air support location as the air support location could be based on the gunship position, resulting in circular logic. Instead gunships will use the rally point again. 2. However, the rally point will be moved towards the support location as long as it is safe to do so (and we have air control). 3. In addition, the support location will be moved towards the enemy base as long as it is safe to do so (and we have air control). 168 4. Meanwhile the closest safe base will be used (if there is one) if the closest friendly base is dangerous – to help with cases in campaign maps where an allied ‘base’ is actually in the enemy base. 5. Fixed several bugs with getting the gunship threat at a location (when deciding whether to support with AirAA units) which would stop the AirAA logic from working. 6. AirAA units should only consider adjacent zones to a gunship or unit to support if the zone edge is relatively close to the gunship or unit position. 7. Once gunships have found a target, they should continue considering up to 4 zones to see if any of those aren’t too far away (compared to the first one where targets were found) but have mexes or high value structures to protect. 8. For MMLs, in addition to considering whether they are in range of the enemy structure closest to the midpoint, they should also check if the nearest enemy unit to them is a structure and (if so) if they are in range of it in roder to attack it (due to issues with attack-move not working properly for MMLs). 9. T1 power shouldn’t be ctrl-kd when near the unit cap if we have no T2+ power. 10. More gunships should be built at T2 if we have no T3 air fac and have air control (before there was a lower unit cap at T2 air, on the assumption that T3 air could be obtained) 11. Gunships should engage a greater ground AA threat if they are in a zone with a significant structure value or with T2+ mexes. 12. When we outrange the enemy (e.g. we have MMLs and they don’t) then units should get slightly closer to enemy structures before doing a kiting retreat. 13. One issue was the enemy base land zone and some of the nearby land zones are massive (due to very few mexes), resulting in gunships running too early from enemy threats. When gunships are deciding if there is too much AA threat, I’ve added a range limitation on the adjacent zones that get considered, so if the gunship is too far from the zone edge then it should be ignored (i.e. similar to the logic added for AirAA targets above). 14. Slightly adjusted the lower power threshold to be less likely to think we have low power based on the current energy compared with the energy when we last stalled. 15. Removed the 80 gunship unit limit for campaign. 16. T2 engineers should no longer be ctrl-k’d if we have no access to T3 factories. After all of these changes M28 was able to slowly grind down the aeon base. 2.40.5) Other changes ● ● Toned down the mex upgrade logic to try and reduce instances where lots of mexes would be upgraded at once despite a mass stall. Added support for Cybran to get the upcoming Nano upgrade in the expected 15 July FAF beta release (although I’ve not been able to test it to confirm). 2.41) V12 – M3-M4 UEF campaign 2.41.1) Misc improvements and bugfixes identified from playing mission 3 1. Added support for reclaim objectives (for M3 UEF SC) 2. If there are units in a zone to be reclaimed, then more BP should be requested if any of those units are reclaim objectives (i.e. the previous logic for M28 wouldn’t request additional engineers just to undertake reclaim). 3. Increased the distance threshold for engineers to go to other islands that have requested engineers by 50% on campaign maps 169 4. Added a lower priority action for 1 T1 engineer to travel to far away islands (up to 400 distance away) as a backup incase there are scenarios where there is an island far away that we still want to send an engineer to. 5. Added a cap on gunships to stop crazy numbers (500+) being built – now up to 200 will be built. 6. After the above, M28 was finally able to reclaim arnold’s wreck, and proceeded to wipe out the (easy) campaign AI. However, this highlighted a flaw in the campaign objective that makes it impossible for an AI to complete the game. 7. Torp bombers should now ignore small amounts of enemy AirAA threat when deciding targets if we have air control. 8. A fourth air staging facility should be built when there are high numbers of air units and a lack of air staging facilities. 9. Lowered the eco requirements to build sonar on campaign missions by 70%. 10. Fixed a bug/oversight where the damage assigned to a unit by bombers or torp bombers wouldn’t get reset when the bomber’s targets changed. 11. Mass storage gifted at the start – instead of following the normal ‘give half of the units to M28’ approach, mass storage should be linked to mexes and only transferred if the mex ownership is transferred. 12. Units built from a naval factory should be treated as unavailable for 1.5s to make it less likely they sit doing nothing (and hence block the naval factory from building) 13. When choosing a ‘bombardment’ target for naval units, a location inside the playable area should be sought. 14. The playable area should now use the smaller of the scenario info playable area, and the playable area set by campaign map size adjustments (to help address an issue where locations inside the campaign ‘playable area’ would actually be just outside the actual playable area and result in units not moving there) 15. When using the function to move ina direction and keep it inside the playable area, the distance adjust of -0.1 should use the correct factor to keep units just inside the playable area (sometimes they could end up being given a location just outside the playable area). 2.41.2) UEF Mission 3 objective flaw The UEF mission 3 only triggers the logic about the princess having fled the island once Player 1 approaches, and only adds the objective to kill the aeon commander once this happens, meaning if M28 kills the aeon commander then the mission never ends. I’ll therefore see if I can pick up when the objective to kill the princess is added, and create my own check on the Aeon commander, and as soon as it is detected by M28, treat the first objective as complete. o As part of the objective, it uses the following: ● ScenarioFramework.CreateAreaTrigger(M4IslandApproach, ScenarioUtils.AreaToRect('Aeon_Island_Area'), categories.ALLUNITS, true, false, ArmyBrains[Player1], 1, false) ● ScenarioInfo.M4P1 = Objectives.Basic( 'primary', 'incomplete', OpStrings.M4P1Title, OpStrings.M4P1Description, Objectives.GetActionIcon('kill') ) o It also sets the actual objective with: CreateAreaTrigger is: 170 local TriggerFile = import("/lua/scenariotriggers.lua") CreateAreaTrigger = TriggerFile.CreateAreaTrigger This in turn is: ---@see CreateMutlipleAreaTrigger() to pass in multiple areas ---@param callback NamedAreaTriggerCallback | AreaTriggerCallback ---@param area Area | Rectangle ---@param category EntityCategory ---@param onceOnly? boolean ---@param lessThan? boolean ---@param aiBrain? AIBrain ---@param unitCount? number defaults to any (or none with `lessThan` set) ---@param requireBuilt? boolean ---@param name? string ---@return thread function CreateAreaTrigger(callback, area, category, onceOnly, lessThan, aiBrain, unitCount, requireBuilt, name) return ForkThread(AreaTriggerThread, callback, {area}, category, onceOnly, lessThan, aiBrain, unitCount, requireBuilt, name) end Meanwhile the later objective (for Eris being killed) makes use of: ScenarioFramework.CreateUnitDeathTrigger(ErisKilled, ScenarioInfo.AeonCDR) I was wondering about creating a second areatrigger thread and copying the first via a hook, but that would probably duplicate the objective and could cause other issues, so I’ll leave it (especially as if the map ever gets fixed it could cause problems). Instead, I’ll just call the ‘ErisKilled’ function that ends the game: ● When an objective is added, check if ScenarioInfo.M4P1 is empty ● Also check that the objective is active, via: ScenarioInfo.M4P1.Active ● ● If not, check if the objective has no units If it has no units, check if there is a ScenarioInfo.AeonCDR unit Where such an objective is identified, I’ll then create a custom ‘end game’ trigger for Eris: o o o Use the ‘CreateUnitDeathTrigger’ function as per the above. However, has a custom EnemyACUKilled function When this function runs, it checks if M4P1 is still active, and if it is, then it calls the ‘ErisKilled’ function. 2.41.3) UEF SC Mission 4 1. When considering combat orders for naval units, enemy units that are outside the playable area should be ignored when getting the nearest enemy to the midpoint. 2. Fixed a bug with capture target objectives being recorded. 3. When looking for a mex to bombard, only mexes in the playable area should be considered. 4. When looking for a water zone to support, only water zones whose midpoint is in the playable area should be considered (note even after this there’s an issue with this map as there is a small bit of water north of the starting island that is in the playable area, leading to 171 M28 trying to send units there since it is pathable if the map was expanded – unfortunately there’s no easy solution to this). 5. Engineers should no longer be built at a factory if the tech level that would be built is lower than the lowest tech level that zone wants (i.e. the issue was that you can build a T3 air factory but no T3 engineers; so M28 would want to get more T3 engineers, and keep building engineers at the air factory, which would only be able to build T2 engineers, leading to a massive overproduction of T2 engineers). 6. Added an extra campaign intro message and fixed a bug that meant 2 of the options wouldn’t appear. 7. Added logic to try and build T2 factories instead of T3 if we have no T3 engineers and there are unit restrictions, to try and avoid the scenario where T3 support factories try to be built to deal with mass overflow but there are no T3 engineers to build them due to unit restrictions. 8. M28 would massively overbuild inties once it reached T3 air, due to wanting to have at least a couple of ASFs (but due to unit restrictions could never get them). 9. Reduced the threat given by T1 fixed AA to 150% instead of the normal 200% for structures. 10. Made it slightly less likely that land factories will get built where we are on a different island to the nearest enemy base, and fixed a bug with the decision on whether to get a land or air factory. 11. Fixed a bug with the decision on whether to upgrade a T2 support air factory to T3, which would only consider it if there were active upgrades in the zone (that weren’t an air factory), rather than also considering if there were no active upgrades at all. 12. Fixed a bug for island factories that meant they wouldn’t take into account the friendly threat in adjacent zones but instead would only consider their current zone when deciding what to build. 13. More factories shouldn’t be built if a land factor in the zone hasn’t built anything recently and either the same is the case for an air factory or we wouldn’t be building another air factory. 14. Increased the proportion of air factories to get vs land factories for campaign games to compensate for an issue on this map where the nearest enemy base shows up as being on the same island as our start position (when it isnt). 15. Increased the cap on air staging to 8 (where we have at least 50 air units per existing air staging and have units wanting refuelling with no available air staging). 16. Added a cap on the number of inties (and airaa units generally) to be built when building in proportion to our gunship threat, to avoid huge numberies of inties (500+) being built. 17. Increased the value of ponds in campaign, to account for how sometimes the enemy base will appear to be on the same island as us (despite not actually being). 18. Engineers should consider expanding to an island where the enemy threat at that island is less than 10 (previously they would only consider expanding if there were no enemy units at all). 19. Added some redundancies to water zones for scenarios where they might not have a hover label but do have a non-hover label (although these are very unlikely): o Made sure that any midpoint has a hover pathing label o Made sure that adjacent land zones are only added if they have a valid plateau 20. Fixed a bug that meant water zones wouldn’t reinforce adjacent land zones requesting engineers. 172 21. Increased the distance to consider sending an engineer to another island to a minimum of 125 to account for cases where the enemy base is closer (i.e. campaign maps with poorly placed enemy base positions). 22. Adjusted the threshold for units in water zones to attack the enemy when lacking a range advantage – now the enemy threat in adjacent zones should be taken into account, but the threshold is reduced from being 50% more than the enemy to being 30% more than the enemy. 23. Also changed the logic for engaging from a core zome from an automatic attack to only an attack if we have more threat than the enemy. 24. When checking for islands to support from the core zone, a check should be done for if the island land zone is in the playable area. 25. Core zones should now consider sending engineers to other islands that are in the playable area, and which have an enemy threat of less than 10 in adjacent zones (previously any enemy units would cause engineers to not be sent). 26. Updated the types of units to be protected by TMD to include all T2 buildings other than factories, and all T3 buildings other than factories. 2.41.4) Other changes (unrelated to M3-M4 of the campaign) Changes made from running an M28 vs RNG game on white fires ● Fixed a bug with the logic for working out what faction’s factories are available to produce engineers to shield a game-ender. ● Fixed a bug with getting engineers to move from a water zone to a land zone, and another bug where if the engineers would be sent back to a land zone they could end up never being treated as available. ● Made M28 more likely to want to build more power even when it thinks it isn’t low on power, including factoring in higher AiX modifiers, and high amounts of mass stored. ● Capped the amount of build power to be sent to a water zone from a land zone. ● Increased the range to consider sending land experimentals to other islands if the enemy has T3 arti/similar threats and fewer land experimentals. Other changes ● Added pre-emptive change for FAF beta balance which will change energy storage capacity – M28 had been using some hardcoded values, so I’m hoping I’ve picked up all of these (as they now use a value htat is based on the blueprints at the start of the game). Pre-release basic check Another 3v3 against RNG on twin rivers, for a change M28 won comfortably, managing to stay just behind RNG to the mid-game then quickly racing ahead on eco at the T3 stage. 2.41.5) V13 Hotfix I forgot to disable M28 logic for AiX being 10x, resulting in a hotfix. 2.42) V14 M5-M6 UEF and M1-2 Cybran Campaign 2.42.1) Mission 5 1. Fixed a bug with gifting mass storages. 173 2. The switch from titans to percies and loyalists to bricks should only happen if the factory can build bricks/percies. Nukes, TML and SMD should keep building missiles if we are close to overflowing resources. 3. Hard-coded logic to have M28’s ACUs move to the gateway at the end of the mission so that it can complete. SML overwhelm logic One thing I noticed was that M28 would build loads of nukes, due to wanting to build experimentals, not being able to, so having a fallback of building any available experimental level unit (including nukes), with nukes being the only one enabled. However, it would also not fire those nukes if the enemy had SMD coverage. I therefore want to support the extreme/niche scenario where M28 has say 6+ nukes, and the enemy only has 1-2 SMD, such that M28 could just overwhelm the SMD with nukes: ● ● ● Nukes, TML and SMD should keep building missiles if we are close to overflowing resources. Once M28 has more than 1.5 + 1 times the number of nukes as the enemy has SMD, at at least 4 nukes, it should try and overwhelm the SMD with Nukes. When trying to overwhelm SMD, in addition to ignoring if a target is covered by SMD (similar to the experimental nuke), the launcher should ignore if a nuke was fired at the target recently (to avoid spreading out the nukes over every enemy SMD one at a time). Land zone adjustment The Zone creation is too big for the central zone: 174 Since both enemy nuke bases are assigned to the starting zone. Based on mexes the position looks reasonable: 175 I’ll therefore reduce the distance threshold for a zone to be merged into an adjacent zone threshold on campaign maps. I will also reduce the size of the starting zones for campaign maps. I also change it so that once a nearby zone is found, only segments up to the copy zone distance will be assigned to that zone (instead of the entire square). After these changes the result is: Core assignment: 176 Final assignment: 177 Overall this looks much better, and should avoid the issues if units suiciding into the nuke base (particularly an issue on harder difficulty). 2.42.2) UEF Mission 6 changes For once the campaign mission completed with no changes needed. However, I noticed a few issues where improvements could be made, mostly relating to naval type logic: 1. Fixed an issue with battleships not ground-firing a submerged tempest - on investigation I realised it’s because the tempest blueprint Y size is more than the amount by which the tempest is underwater. Fixing this means that tempests should now be ground fired. 2. Fixed a bug with determining the enemy’s best combat range, which would lead to naval units suiciding themselves. 3. Fixed a bug with determining the enemy’s best antinavy range, which would only consider enemy units in the current water zone not adjacent water zones (leading to subs suiciding against enemy destroyers). 4. Fixed a bug where naval units were getting the nearest enemy unit even if it was in a non-adjacent water zone. 5. Changed naval engagement logic to be based on allied threat in current and adjacent zones vs enemy threat in current and adjacent zones (previously adjacent zones were ignored), 178 and updated submarines so their decision on whether to engage for a core zone is similar to that of surface units. 6. Fixed a bug with identifying water zones for torpedo bombers to target when there are no specified torpedo defence zones (this logic was a redundancy so in theory shouldn’t matter). 7. Fixed a bug with recording adjacent water zones to defend, where it would check if the original zone had already been recorded instead of the adjacent water zone, and a bug that wasn’t recording this check (meaning the same zone might get included multiple times) 8. Adjusted torpedo defence logic so they will consider further away areas the better our air control is. 9. Made it slightly quicker for a quantum gateway to be built in campaign than it already was. 10. RAS SACUs should assist quantum gateways for longer in campaign. 11. Torp bombers should still be built at the highest unit cap threshold 12. Torpedo bombers should now check if the target is inside the playable area before trying to attack it. 2.42.3) Cybran M1 changes 1. Added in a low priority bomber builder for when we are overflowing mass. 2. Added in a low priority air factory builder for when we are almost overflowing mass. 3. Added a low priority AirAA builder for any tech level where we lack air control and have a decent amount of mass. 4. Low fuel air units should consider self destructing if there are insufficient air staging facilities available. 5. Expanded bomber targeting logic so lower tech units near the rally point should be targeted. 6. Also added logic for bombers to target further away enemy units where there is air control. 2.42.4) Cybran M2 changes 1. Added a low priority bomber builder even if we have low mass for cases where we have no gunships (i.e. so we can get some bombers for defence). 2. Added higher priority bomber builder for when there are adjacent enemy naval units. 3. Bombers should now consider adjacent water zones for targeting 4. One issue this mission highlighted was that the Aeon labs that need to be destroyed don’t show as enemies, and have to be manually attacked. I therefore want very specific hardcoded logic for this, due to the risk of having M28 attack targets it isn’t meant to. However, I’m also unable to reclaim the temples which would’ve been the easiest way (for my code) to handle this. I therefore add custom logic to have bombers ground-fire special targets, and record these targets when an objective is added and the scenario contains a table of these temples (since examining the campaign script it records the temples against the ScenarioInfo data). ● This then caused an issue because M28 bombers would continue attacking ground fire targets due to being treated as ‘busy’ (as their target would be close by), so I’ve updated the tracking to allow ground fire orders to be linked to a unit so when that unit dies, the bomber is treated as available. 5. Made it more likely that energy storage should be built, particularly on campaign maps, at lower mass levels. 6. Made it more likely the ACU will get its first upgrade on campaign maps after a while when at low eco levels, even more-so as significant amount of time passes. 7. ACU should try and get RAS upgardes if it only has 1 available upgrade 179 8. ACU should consider engaging nearby enemy naval units. 9. Bombers should try and focus down enemy AA units ahead of non-AA units. 10. Adjusted the range on the ACU’s overcharge – previously it would only conider units 1 inside the ACU range, now it will consider units inside the range, provided the direction of the ACU towards the unit isn’t far from the ACU’s facing angle. 11. When ACU is trying to run and is also trying to dodge a shot, regardless of what its last move location was it should assume it is trying to move to the nearest base, to reduce cases where it may try attacking the enemy while dodging due to not receiving new orders while dodging (so going off the old orders that were to attack). 12. Bombers should only consider higher tech nearby units first when we have strat bombers. 13. Increased the proportion of air factories to build relative to land factories for campaign maps further. 14. One issue with the map setup is that the water near the start position wasn’t showing as being adjacent to the start position land zone, since it would cross briefly into another land zone when traveling between the two points. My solution is to allow a certain number of ‘strikes’ before no longer treating a water zone as adjacent to a land zone, based on how far apart the midpoints of the two zones are. 15. Fixed a bug where the RAS upgrade on an ACU wasn’t factored into M28’s calculation of its gross mass and energy generated. 16. Increased the search range of bombers further where we have high numbers of them. 17. Added a limit on the number of frigates to be built. 18. Added a higher priority upgrader for land factories where we don’t have low mass 19. Added a higher priority upgrader for land factories based on the number of units the factory ahs built (with the number required to upgrade being adjusted based on various factories including mass levels, how close enemies are, and how many other upgrades are active). 20. Minor optimisation to logic for determining how many units a factory has built. 21. ACU should sometimes consider rebuilding a base in its current zone where it loses its core base. 22. Land units should now try engaging enemy AA units in water (not just enemy direct fire units), meaning the early shards that get attacked can often be killed by land units (instead of having to suicide bombers into them) 23. More than 1 naval factory should be built with high amounts of mass stored. 24. For campaign maps the gross mass income threshold to build a naval factory is lower. 25. Changed the order/priority of the water zone logic for sending engineers to an adjacent water or land zone – the previous priority orders will only apply if the zone has no factory or engineers in it. Then 2 new lower priority reinforcements are added which will apply regardless of if there are engineers/factories, but these are now lower priority than logic to assist the naval factory. As part of this I’ve also expanded the logic to only send engineers if we have sufficient tech level (previously it just checked if the zone wanted more build power, so could send a T1 engineer when the zone only wanted a T2 engineer). 26. Added a higher priority torp bomber/gunship/bomber builder for when the enemy is in an adjacent water zone with a combat threat. 27. Land factories in ‘expansion’ locations should no longer try and maintain a minimum level of threat in adjacent zones if the factory itself has a large number of units it has built in its lifetime, and no adjacent enemies, due to the risk of it being in a location with zones adjacent to the adjacent zones, unless it has built nothing for the past 10s and doesn’t have low mass. 180 28. The mission still requires input from the player though as the final objective requires player 1’s ACU to enter the gateway. Strictly speaking I suppose the user could setup the game lobby with the AI as player 1 though, so I’ll add code to have the ACU move the quantum gate once the objective is added regardless of what player it is. Fortunately because I had to do the same thing for M5 of the UEF campaign it’s far easier to implement this (taking a couple of lines of code and not needing to be rerun numerous times to get working). 2.42.5) Misc 1. Fixed a bug added in v12 with certain naval unit management. 2. ACU is less aggressive for campaign missions (based on feedback I had from Pedro_Lima on Golden Crystals suiciding) 3. Made it less likely that SMD, TML and Nukes will be unpaused for more missiles at low gross mass values, even with lots of mass stored (i.e. they’ll now check that M28 doesn’t have low power, and will require 99% mass stored instead of 80% at lower gross mass levels). 4. Fixed a bug with determining locations where naval units can hit a mex, where the pre-recorded locations wouldn’t check if the location was in the same pond (only if it was in water) – now it will check if it’s in the same pond, to avoid units from one pond being given orders to try and move to another pond. 5. Units should be more aggressive if they are at a core base or expansion point and the enemy is almost in range of that location’s midpoint. 6. Adjusted the decision on whether to request indirect fire reinforcements, so that if we have more mobile DF threat in a zone than the enemy, and more than we have indirect fire threat, then adjacent zone threats should be taken into account and if the enemy has structure threat in an adjacent zone, then indirect units should be requested. 7. Added a workaround for a really strange error where an engineer would be given a move order yet not move (but show in the FAF engine as being moving) – engineers will now record their position when moving and if they haven’t moved more than 0.01 in 10 seconds will be cleared. 8. Added code provided by Sprouto to reduce the risk of errors relating to too many orders being given at once. Basic pre-release test – Another 3v3 against RNG on Twin Rivers, M28 looked in trouble early on when all 3 RNGs rushed M28 with 3 monkeylords at the same time, but M28 was able to recover with the loss of only 1 of its ACUs and quickly got into an unassailable position. 2.42.6) Acknowledgements: Sprouto – code to try and mitigate issues where orders weren’t being processed – it didn’t fix the issue, but I’ve left the code in incase it’s of help for a potential future issue. Pedro_Lima – Mentioning that M28’s ACU was being a bit too aggressive and dying on one of the campaign maps. 2.43) V15 M3-6 Cybran 2.43.1) Cybran mission 3 Starting this on hard it was clear that M28 isn’t going to be able to compete (without spending lots of time on mission specific logic) – M28 takes what would normally be the correct approach of getting a factory and power with its ACU, while sending its amphibious tanks to attack an undefended enemy base. However, this leaves civilian buildings exposed to the enemy attack, and since M28 only has 181 half of the starting units it also takes a while to defeat the northern air base. Instead I’ll assume the human player will send their units to defend the town while M28 attacks the air base. Having the human playerpatrol their starting 4 amphibious tanks to the west of the town though meant the town survived and M28 then proceeded to win the game. However, M28 failed to scale up its build power fast enough and was overflowing mass for much of the game despite constantly building new air factories. I therefore made the following changes: 1. Core expansion – Increased the number of land factories to build at high mass storage levels. 2. Air factory – Added logic to build a second air factory at the same time as the first for high mass stored values. 3. When getting units to build, land factories should only consider other zones that are in the playable area (to avoid it constantly producing say MMLs due to an enemy building just outside the playable area). 4. When deciding what to do with land combat units, a check should be done that the nearest enemy unit is in the playable area. 5. When deciding whether to attack from an ‘island beachhead’, units would attack if they outnumbered the enemy threat in that zone itself. Now they will only do this if there are enemies in the zone (to reduce the tendancy M28 had of suiciding units into the western base, provided the attacking patrols are dealt with). 2.43.2) Cybran Mission 4 – General changes 1. Increased the value of large ponds, and ponds on campaign maps, in order that the pond near the start position is considered worth building in. 2. Added some more caps to the number of inties to be built to try and avoid going much over 400. 3. Added a low priority air staging builder for core expansions. 4. If the bombardment location is outside the playable area (or is targeting the enemy base) then a search should be done for the nearest enemy unit in a land zone to try and attack (which results in the destroyers storming the initial southern base instead of trying to attack an off-map location in the north-west). 5. Added a hook whenever a trigger is created for the capture of a unit, so that the unit is added as a capture target if it is not an ally (as the previous approach of identifying a capture objective wouldn’t pick up every case – such as the final objective to capture nodes which used a different approach). As part of this I also fixed a bug with the previous code which could happen when checking if a capture target had already been added. 2.43.3) Mission 4 - Not attacking an enemy on purpose This mission has a strange scenario for an AI where attacking the main enemy base causes you to lose the game. My plan for a potential solution is to just have the AI play defensively and rely on the human player to complete the objective. I.e. I’ll have a global ‘Pacifist’ flag – if they are not in a core base or adjacent to a core base, or in a core expansion, then the following will no longer be managed, i.e.: ● ● ● ● LandCombat (based on zone flags) Naval combat (based on zone flags) Bombers (not torpedo bombers) – only use defensively (i.e. limit the adjacent search range) Gunships – only use defensively (i.e. limit the adjacent search range) 182 Meanwhile the following would still be used: ● ● ● Engineers (e.g. reclaiming) – since I figure they’d die before getting near Torpedo bombers (as the base isnt on water) AirAA (as they’d only kill enemy air units which hopefully won’t trigger a mission failure). However, checking how the script works, it appears to record the triggers and units at the start of the game. I therefore want a more localised blacklist logic: ● ● When an objective is added, check if we haven’t triggered the EMP and we have the data on the units, and havent yet recorded the blacklisted locations. If so, then: o Create a table of all the land zones that form part of ScenarioInfo.M3_Base (expected to just be 1 zone) o Cycle through all adjacent land and water zones, and blacklist them. o Disable the land combat and naval zone management for blacklisted zones (so they shouldn’t request reinforcements or engineers), after setting flags for wanting reinforcements and BP to false o Manually disable considering targets in blacklisted zones for Bombers and Gunships. o If a gunship is in a blacklisted zone, disable its weapon (otherwise enable it). I later disable airaa logic in blacklisted zones as well, since the crash damage triggers the mission failure. 2.43.4) Misc changes ● ● ● Removed code added in the previous update to try and increase the memory allocated to certain tasks as I suspect it may have been the cause of an issue where all replays would desync from the start. Fixed a bug with torp bombers not working when the enemy has nearby naval units. Land factories shouldn’t be paused in a mass stall if they have built fewer than 5 units, to try and reduce cases where engineers would start building on an island or plateau and the factory would be paused and take ages to complete. 2.43.5) Billy Nuke defence ● ● Defending against a billy nuke: My original plan was: o I want this logic to work for any mobile TML unit, and also units like cruisers, missile ships and nuke subs, so that M28 is capable of depending against them. o Record enemy ACUs that have TML or billy nukes in a special table of threats for the team. o Have core and minor zones check if that table is empty, and if not, check if we are within 50 of being in range of the manual missile. o If so, make sure we have at least 4 non-Aeon or 1 Aeon TMD in that direction. o Also set the flag to defend against arti, so that we try and get heavy shielding up. However, after drafting the first half of this, I realised there was an easier and more performant approach/one less at risk of massively slowing down the game: o Monitor the position on a team-wide basis of all enemy mobile TML units o Where the unit moves more than 10 from its last previously recorded position, use the existing TML/TMD logic to identify targets and threats. 183 o ● ● ● I’ll also only consider 1 enemy unit per tick where I am calculating all of the targets and whether theyre covered by TMD – so if e.g. I was to expand this to cover MMLs and the enemy built 100 MMLs, it shouldn’t risk slowing the game down to a crawl. In theory, this means I may also be able to make use of this logic for if I get the TML upgrade on an ACU. When putting through these changes, I make the following adjustments to the TML/TMD logic: o Aeon TMD are treated as being worth 2 normal TMD o UEF Billy Nuke is treated as being worth 4 TML (when working out how many TMD to get) o Aeon missile ships are treated as being worth 3 TML o The AOE of the TML is taken into account (instead of a hardcarded value of 2) o Mobile TML are treated as having 10 more range than a fixed TML (to allow for them moving slightly) In theory I could use the same logic to build up TMD against enemy MML, but for now I’ll hold off as M28 doesn’t try and build firebases outside its core land zone, and should be building air and land to attack MMLs attacking its core zone (which on average are likely to be a better mass investment). 2.43.6) Cybran Mission 5 ● ● ● Changed bomber targeting logic to consider water zones as well as land zones at high available bomber levels. Added an override cap on the number of T1 and T2 MAA to be built. Part-complete buildings should be assisted if there are available engineers in the zone (to cover cases where we start building a unit then stop). 2.43.7) Cybran Mission 6 – Objective 1 (destroy the Czar) Even on easy this proves a difficult mission – M28 is attacked by strats and battleships early on, so can’t just eco to a strong position, and while it gets asfs it doesn’t build enough to come close to handling a Czar. It correctly (for a normal game) builds lots of SAMs and aircraft carriers to protect itself from the Czar but this doesn’t help for when the Czar attacks the control centre. Trying with M28 as a 1.5 AiX, on Easy, it suffered a similar problem. Even increasing to AiX 2.0 still didn’t resolve things. I therefore made the following changes to try and improve performance and the number of asfs built by the time the Czar attacks: 1. ACU should try and claim any unclaimed mexes in the starting land zone at the start of the game even if its gross mass income is relatively high 2. T1 mex upgrades shouldn’t be paused in campaign maps in a mass stall (since generally the risk of them being taken out is lower than a normal game due to the greater focus on ecoing). 3. Fixed shields shouldn’t be built in campaign early on if we are low on mass, and should only be built between 10-20m if the arti is at least 60% done (if we have low mass). 4. Once we have a ground AA threat equivalent to roughly 4 SAMs, more should only built if we don’t hae low mass if the enemy has no air units in the zone and we don’t have a high level of gross mass. 5. Engineers given to the player at the start of the game should now be shared with M28AI. 184 6. If trying to build a random experimental due to the desired one not being available, if we decide to build a game-ender it should be cancelled if we don’t have a high level of gross mass income. 7. Game enders should only be built once we have built at least 3 experimental level units. 8. Air factories should be more likely to be built on campaign maps after the 2nd land factory (given issues with enemy bases often being nearby when they’re not), provided we have access to T2+ air factory tech. 9. If there is an experimental air objective that is owned by an enemy unit, then AirAA units should be much more likely to engage it than normal targets, disregarding significant amounts of ground and air AA threat, provided M28 has the equivalent of 20+ asfs. 10. Added delayed logic when the map expands to check for specific objectives (since mission 6 doesn’t use the normal approach to adding an objective for a unit target), which will manually check for if the table of czars to kill exists in the scenarioinfo (it gets added to here when the czar finishes construction). 11. Attached air units (e.g. air units inside a czar) should no longer be attempted to be targeted. 12. Added logic to try and get more air factories, with up to 10 total factories (air and land) if the enemy has a significant air to ground threat. 13. T3 naval factory shouldn’t be started early game on campaign maps if we are low on mass (and more generally if low on mass they shouldn’t be started if the T2 factory hasn’t built many units). 14. Allied radar and sonar that is created (e.g. spawned at the start of the mission) should be taken into account when deciding if we need radar/sonar. 15. Add a high priority action for airaa – if campaign map, and have czar and control centre as valid units, and enemy has air to ground threat of at least 10k, and czar is within 120 of the control centre, then attack it with everything. 16. Added a chat message when the ‘suicide into Czar’ logic triggers 17. Made it more likely more factories should be built even where the gross mass income isn’t that great, if the enemy has a large air to ground threat. 18. After seeing 60 asfs die to the Czar without taking out its shield, which I’m assuming is due to the aoe abilities on the Czar, I then changed the air attack logic so against the Czar it will use an attack order (whereas previously it would use a move order once it got near it). 19. ASF production - If the enemy has at least 10k air to ground threat, we already have a base level of torp bombers (or don’t need them) and gunships, and have asf threat less than the lower of 20k and 50% of the enemy air to ground threat, then build asfs as a high priority. 20. Reduced the amount of ground AA to be built at very high threat levels, as well as when only T2 AA is available. 21. Further reduced the amount of AA to be built in campaign maps early on (since on this map the Aeon player starts with a huge air force that could easily wipe out the base if it attacked, leading to M28 overbuilding SAMs and flak when it could be ecoing). Prior to these changes, M28 couldn’t get past the first objective even at AiX 2.0 on easy difficulty. After these changes, it’s able to manage AiX 1.0 on hard! (that said, there’s no significant difference in difficulty between easy and hard for this objective). Changes from the rest of the mission: 1. Final objective – if M28 captures black sun, then M28 should ‘fire’ it (i.e. it should end the game after a slight delay) – I’ll check this whenever M28 captures a unit (since the objective to fire black sun triggers when black sun is owned by the UEF). 185 2. Experimental gunships should use an attack order instead of a move order (i.e. they should ignore the normal gunship logic) 3. Adjacent enemy structure threats should only have 20% of the threat value included where we have at least 10k threat in the zone. 2.43.8) Other changes ● ● Land factories should be less likely to start upgrading an HQ at the same time as another HQ (previously they would try and upgrade once reaching a certain number of units built – this threshold is increased significantly where there is already an active HQ upgrade). Part-complete fixed shields should be ignored when considering units to assist (where there are part complete buildings in the zone). 2.43.9) Acknowledgements: ● FenixThorn – replay highlighting issues with M28 upgrading multiple HQs at once 2.44) V16 M1 Aeon 2.44.1) General changes 1. Added some redundancies in the map generation to try and cope with Seraphim mission 2, before discovering the reason for the errors was that the navigational mesh wasn’t working at all. Adding a full redundancy for this would be a lot of work and slow down the M28 code generally so I’ll probably wait to see if it’s possible for it to be fixed. 2. Hopefully fixed a compatibility issue with the StoneAge mod that would cause the game to crash. I’m not sure on the cause, but after checking for the specific way StoneAge adds unit restrictions (which is different to if a player adds them) pre-emptively I was able to avoid 3 games crashing (playing for 20+m) compared to the game I ran without the mod that crashed after about 15m. 3. Fixed a bug with determining how many engineers to build early-game 4. Fixed a bug in the logic for deciding if more factories are wanted that would result in lots of errors. 5. M28 should try and go second air if it has friendly teammates closer to each enemy than it is. 6. Air HQs building a transport shouldn’t be paused during a mass stall. 7. Air HQs building their first unit shouldn’t be paused during a mass stall. 8. Removed the logic for flagging a unit as a capture target when a capture trigger is added unless it’s a campaign map and the unit is mobile (to stop e.g. M28 trying to capture RNG engineers). 9. Fixed an issue where FAF prevents engineers reclaiming an actively constructed building or experimental – now engineers will try and target other units. 10. Engineers should try and reclaim the closest dangerous enemy unit in its build range if it has one (in priority to non-dangerous units) – i.e. any unit with a combat range (direct or indirect) or a unit that can reclaim. 11. Units shouldn’t try and go to an air staging unit that hasn’t finished being constructed. 12. Land factories on islands or plateaus should no longer be paused in a mass stall if they have built fewer than 10 units. 186 2.44.2) Aeon Mission 1 Naval factory production I wanted to add some logic where if M28 failed to build a land or air factory, it would move to the nearest water zone inside the playable area and build one there. The problem is that the water zone midpoints of all water zones were outside the playable area, with the closest one shown below: This then caused another problem – the ACU would head to the water to try and build the factory before it had completed the mex and power objectives. I therefore adjust so the logic only triggers if the ACU is capable of building a naval factory. Other changes for mission 1 1. Added a low priority builder for subs, surface combat, and AA units from a naval factory up to 30 of each, when overflowing mass. 187 2. Added a low priority bomber builder when almost overflowing mass and not at the highest tech level. 3. Added a unit cap on t1 AA boats for most build conditions 4. Added a redundancy for engineers to not get new capture orders if they are already capturing a unit, to avoid cases where they would keep switching between different perceived capture objectives ending up not completing any of them. 5. ACU should try and build an air factory if we have none in the zone and are unable to build a land factory. 6. Added a builder for bombers, torp bombers, gunships and airaa units based on if the enemy has units in a zone when considering nearby zones in a straight line distance. 7. ACU should try and build power if high on mass and below 500 energy per sec 8. More naval factories should be built if we have 1 and are high on mass. 9. Naval units that don’t appear to be in a water zone should be reassessed periodically (rather than forgotten about and effectively becoming invisible to M28). 10. Fixed an issue where a water zone could flag that it had dangerous enemies in an adjacent zone, but no enemies in an adjacent zone (i.e. if it couldn’t find enemies in an adjacent zone it would override the flag for if there were enemies, but wasn’t also overriding the similar flag for if there were dangerous enemies). 11. Fixed a bug where to determine if there were enemies in an adjacent water zone, every water zone was being considered (so it would always return true, leading to strange behaviour). 12. Torpedo launchers should now be included in the units to be assigned to a water zone, as previously they weren’t showing up in checks of nearby enemies (leading to units suiciding into them). 13. Submarines should now record if their last shot is blocked, with this logic working for underwater shots (previously it was only intended for above ground direct fire shots). 14. Submarines that get too close to the enemy should attack-move to it instead of moving even if their shot appears to be blocked, due to an issue where subs don’t fire at an enemy unit if ontop of it 15. Retreating/supporting water zone units should only be treated as having received an assignment if they belong to the water zone giving the orders (similar to the approach taken for land units). 16. When entering a new water zone units should have their assignment value set to 0 17. When choosing the best build location only those in the playable area should be considered. 18. When searching for potential build locations, the ‘cycle size’ (i.e. the n for every nth entry that gets considered) is reduced if it is more than 30, to 50% (for water) or 75% (for land), due to issues where every build location (5k+) was mapped for the water zone in M1 near the starting base, but none of the 79 locations chosen for consideration via the nth cycle approach was in the playable area. 19. The ACU when trying to build a land factory should search for buildable locations (to mean we reach the max mapped buildable locations much sooner). o Massively increased the number of locations/segments to search when the ACU is trying to build a naval factory in campaign, since even with these changes it wasn’t working through enough fo the water zone segments to locate those inside the playable area. 20. Added factory rally points, to try and further avoid issues where a unit gets built from a factory and blocks future units at that factory. 188 21. Naval factories no longer require a water start to build engineers with a higher priority when not low on mass. 22. If an ACU was recently given a build order but doesn’t have a valid order (e.g. due to unit restrictions) engineer tracking should be cleared so engineers don’t try to assist it when it is doing nothing. 23. MAA ships should factor in enemy anti navy range when deciding whether to retreat. 24. Fixed a bug with air factories for deciding whether to build bombers if they have no gunship threat and minimal bomber threat. 25. Engineers should no longer be treated as available if their unit state shows them as capturing or reclaiming. 26. Added redundancy to end the game at the end after c.40s due to the game not seeming to end normally (it might have been because it was a desynced replay, and I don’t really want to re-run it again to try and clarify further). Water zone creation adjustment I was still having an issue after these changes of units suiciding into the enemy torp launchers. After further investigation, the issue was with the water zones being too small in some places: 189 i.e. units in water zone 4 would try to move to water zone 8, and end up passing in range of the torpedo launchers in zone 9. Those torpedo launchers would effectively be invisible, as M28 would only check adjacent water zones (i.e. zones 8 and 10) when considering what to do with units in zone 4. I made the following adjustments to try and resolve: 1. Adjusted the water zone creation logic so if zones are created based on underwater start positions they will be slightly smaller but nearby other zones will check they aren’t within roughly 15 segments of this. 2. Reduced the distance by which the initial start point for a water zone will search for nearby water from 50% of the search interval to 35%, to try and reduce cases where tiny water zones get created. 3. When assigning water segments that have no zone assigned, before creating a new zone they should check if the location to the right and bottom-right are also unassigned (and if not then look to add the zone to the nearest zone). 190 4. When deciding to assign to the nearby zone, it should look for adjacent segments in the opposite direction to the loop, since otherwise it would almost always end up picking the previous segment’s zone leading to very thin potential paths. After these adjustments, the result is: So while not perfect, the tendency for a very small water zone that keeps 2 other water zones apart is reduced. Naval attack logic – current approach After all the above changes I still ahd the problem of units suiciding into the enemy T2 torps, meaning M28 could never build up a strong enough force to assault them (and I don’t want to change its core logic of ‘kill enemy navy first before trying to bombard shoreline structures, despite this map clearly being intended that you kill the shoreline structures first). Where naval units are outranged by the enemy, the threat currently works on the following basis: ‘calculate all our threat in this and adjacent zones, compare to enemy threat in adjacent zones, and attack if we have significantly more’, with a few adjustments such as excluding most of the enemy 191 structure threat in adjacent zone (to try and avoid M28 thinking the 20+ T2 torp longers far away are a threat when it is trying to attack somewhere much closer). This results in a single file line of frigates that charges towards the T2 torp launchers, then retreats as soon as they enter the zone with the torp launchers (since they now have less allied threat as they’re considering differnet allied adjacent zones) and greater enemy threat (since all the torp launchers are now in the same zone not an adjacent zone). I therefore plan to completely rework how this decision is done (again): Naval attack logic – new approach (when don’t outrange the enemy) ● For each unit record its highest indirect/DF/Antinavy range (for optimisation so I can then just refer to this range once) ● When recording threats, record threats with a range of at least 50 in a separate table ● Include 100% of the long range threat that is almost in range, and only 20% of any other threat. o i.e. include 20% of all threat, then +80% of the almost in range threat o Decide whether a unit is almost in range based on its best range, and if it is within that of getting inside the water zone min/max X and Z box (with the range adjusted down for structures) ● When deciding whether to attack if outranged, if the enemy unit is in another zone, the test should be done based on that other zone (not this one), so we are less likely to attack and then immediately retreat. ● In addition, a slightly higher threshold is required to attack an adjacent zone with no combat units in it than it is to attack a zone that already has combat units (to reduce the risk that we attack, then 1 unit takes damage and we immediately retreat). ● Meanwhile when retreating, units should stay in the current zone if there is enough available threat to beat the enemy when factoring in available units. In addition, they should flag as needing reinforcements. After all this I finally got M28 into the position where it could attack and kill the torp launchers, only to be foiled by an indestructible T2 PD (which wouldn’t die even when on 0 health) – checking the map script this looks intentional. However, after a while like this M28s engieners were able to capture/reclaim the AA defences and the czar attacked. That said, I’ll try and avoid this scenario by having units treat their shots as being blocked if they’re targeting an unkillable unit, meaning they move closer (which in this case should hopefully resolve things as they were trying to attack-move to the torpedo defences). 2.44.3) Acknowledgements: ● ● Sladow – flagging the incompatibility with the stone age mod Saver – replay with error/crash 3) Future possible todo points by area Non-M28 related - Consider logarithmic score screen – see Jip DM with link to code FenixThorn replay in DM (Setons) – cant get it to run goblinsly2 replays for M27 M27 upcoming FAF beta acu enhancement change 192 Human-AI interface: ● ● ● Relent0r mentioned about AIHandlePing sorian function Sprouto mentioned LOUD can interpret chat for orders. Ideas of possible inputs: o Specific text prompts for gl/hf/similar type messages at start o Get AI to adjust land threat at a location (i.e. increase/decrease [threat type] at position by [x] o Get AI to fortify a chokepoint/setup a firebase 3.1.1) SC Campaign – complete on easy 3.1.2) Spread out SAMs Spread out SAM/GroundAA construction to provide greater area control: ● ● First SAM/Fixed AA of the cur tech built as normal 2nd+ - If no enemy air to ground threat in the current zone, apply spread out logic; the first one gets built as far towards the enemy base as possible in the current zone o Start by 3.1.3) New navmesh Test out Jip’s new navmesh to see if it works as expected on both campaign and skirmish 3.2) ● ● 3.3) ● ● ● ● ● Non-M28 related (so don’t forget) [Unrelated point – look into hitboxes and stinger? But see if balance team responds first so not wasting time?] [Unrelated point – SpawnACU – test on SC orig campaign as review says it doesn’t work] Misc changes Relent0r suggestion – on 20km+ maps add a distance cap for engineer sharing between bases When reserving locations for an experimental, if the active monitoring code actually triggers, then before the main while loop if we only have 2 build locations for the shields, consider if we have t1 buildings blocking the expected 3rd location and there are no other buildings there, and if so consider ctrl-king those units if they are T1 non-mex non-hybro buildings (i.e. lower value) See v10 changes made, strikethrough text re changes to blacklist T3 power build locations for T3 arti gameenders. Don’t build PD at base if have a friendly base inbetween our base and enemy threat – e.g. twin rivers ended up having one base build lots of T2 PD when in the rear position (3v3 vs RNG AiX 2.0) If detect enemy has experimental, or are UEF in teamgame with team mass of at least 250, want to build a fatboy as a high priority – i.e. even if have low mass (and also want to start it sooner if don’t have low mass) – consider having a new ‘buildfatboy’ action? And then if are deciding on experimental to build will check for queued fatboy construction in the zone? o Could more generally have logic to rush the first land experimental, where will devote 50% of team’s income to the land experimental production, and pause all non-essential production if mass is low while building this. 193 ● ● ● Coordinate ahwassas to attack shielded positions if have multiple? If ahwassa is 5s from firing its bomb then don’t retreat when enemy AirAA appears Similar logic to M27 re cancelling upgrade if ACU taken significant damage recently; also want ACU to be closer to main base to do an upgrade (in core base) - i–e. atm just have a check if <50% health, think need to improve further so if ACU is in core base will wait until it is 20 from the start of the core base or is near T2 PD 3.3.1) Campaign notes Omni in a forward base with low intel coverage (to help give us intel of parts of map further away) Make forward base core base if it’s the closest forward base to 3.3.2) General misc 1. V8 – Cybran t2 destroyers were getting too near enemy and getting into T2 PD range (when pond was won) – e.g. Africa right hand pond – review bombardment logic 2. Should land experimentals move away from an enemy nuke target similar to a yolona? Might be a bit too powerful so alternative to approximate human behaviour would be to move either close to base or towards enemy base based on nuke target? 3. [When next FAF develop releases as at May 2023] – Remove hook of navutils for the precise getlabel alternative code 4. Very high gunship threats – consider targeting enemy ACU? Would mean changing weapon prioritisation as well as the unit to target. 5. Enemy has significant air to ground threat and ACU is flagged as needing to retreat to core base – if ACU is at core base then build a T3 shield, and then have ACU shelter under it. 6. When upgradeable building is created – add to pond if itsenemy and we had vis of its predecessor? – eg eenemy upgrades t2 air to t3- want to kow they havet3 7. Add in logic for defensive nukes, especially if have yolona – Testing in sandbox, a UEF missile launcher firing directly at the position of a GC (that is moving towards it) that is approx. 125 away ends up missing entirely – i.e. even at short distances it requires predicting where the enemy will be; given complications with friendly bases being nuked, would be risky. 8. Factory HQs shouldn’t be upgraded from T2 to T3 if there are T1 mexes in the same zone as the factory unless there are both active upgrades in the zone, at least 50% mass stored, 2k mass stored, or the enemy has T3 air 9. Need to treat mexes as safe if they’re inbetween friendly bases and no enemies in adjacent LZ 10. Arent escorting land experimentals with MAA - see if can reproduce in a shorter timeframe to test 11. Need to get better at escorting battleships with cruisers if far behind on air, and keeping cruisers out of harm’s way 12. First units from a land factory on an island tend to be MAA; however if we are on an island rather than plateau then a tank would be better if there’s no air to ground threat nearby. 13. Gunships returning to rally point/support point to refuel –stay in formation so they’re not clumped together when moving out again? 14. Cruisers are staying within enemy T2 arti range – need to review bombardment and more general logic for them. 194 15. Have non-primary engineers released if have a higher priority action 16. Only build the first land factory adjacent to a mex, not others (so don’t have to worry about losing storage adjacency) 17. High mass scenarios – consider building land experimentals at non-core bases that have land factories in them (but only land experimentals) – e.g. if we have >40 mass income, and >=50% mass stored (or 20k if lower), then trigger the builder. 18. Engi reclaim logic (test via sandbox) – consider switching reclaim targets if are reclaiming a building and have enemy reclaimable mobile unit get within 2 of our build range (so we don’t e.g. keep reclaiming a factory while an enemy engineer comes to reclaim us) 19. Consider better pathing logic for distance between nearby water zones – e.g. dual Italy 20. Mobile shield assignment – will need to have them only assist surface units if their shield is small 21. Similarly for mobile stealth 22. Also don’t want naval shield boat to shield amphibious or hover units since they could move back onto land while the shield boat couldnt 23. Usage of subs may need revisiting once have naval production logic in place – wont have been properly tested yet 24. Capturing units – have zone based logic so each zone records civilian units that can be captured and engineers will try to capture if they are of value 3.4) ● Experimental type units Czar and soulripper – for now they use gunship logic 3.4.1) T3 arti wars logic Various things that started considering for M27 or new logic that could look to implement: ● ● ● ● 3.5) ● ● ● Use of Shield SACU to provide shielding? Probably too slow a refresh rate to be worth it though, except if building game-ender, where it could provide a valuable backup option for when shields fail Syncrhonised T3 arti firing to break through shields Prioritising faction with highest T3 arti to be built (i.e. Aeon) – can potentially do this now although not sure that logic (that is in place for shielding game-enders) works properly so would need to test Reserving build locations for power, and/or picking a location where can fit T3 power adjacency and shielding – have got for shielding now, could try and add for power Air logic T1 bomber engi hunter (similar to M27) – for the first 1-3 T1 bombers (potential future todo action) T3 strat mex hunter (similar to M27) – only intended for the first 2 strats, with strats not built after this (potential future todo action). T2 bombers (plus any other T1-T3 bombers) used defensively where enemy has a large AA threat, in suicide missions (as a last resort) – i.e. this is M27’s main focus, whereas I want it to be much less of a focus for M28 with the main focus being gunships (potential future todo action). 195 3.6) ● ● 3.7) Land zone reinforcements When deciding whether to build indirect fire units for a LZ that wants indirect fire - Will want indirect fire units with a range greater than enemy DF (so T3+ only if enemy structure range is >=58), and with a threat equal to enemy DF and IF threat. When units are traveling to a land zone, record that they are traveling there; when deciding on whether to produce for a land zone, factor in the threat already assigned to travel there, and only build more to satisfy that LZ if it doesn’t already have enough threat. Mobile stealth I may have already implemented the below? Deciding if a LZ wants mobile stealth ● If a land zone contains T2+ skirmisher or T2+ indirect fire units, flag that it wants a mobile stealth generator. Stealth assignment ● Assign to the closest LZ that wants a mobile stealth generator and doesn’t have one assigned. Deciding if mobile stealth is available for assignment ● If it has an assigned LZ, and that LZ doesn’t want mobile stealth, then make the stealth available ● Also make available if it doesn’t have an assigned LZ. Mobile stealth orders ● If we aren’t in the target land zone, move to the target LZ midpoint o If we are in the assigned land zone, find the friendly unit closest to the enemy base, and aim to be max(50% of the shield radius – shield speed – unit speed), 3) in the opposite direction 3.8) Economy management 3.8.1) Factoring enemy TMLs and long range units into upgrade decision For now the below function just consideres if enemies are in the current or adjacent LZ: SafeToUpgradeUnit M27 had logic factoring in if there were TML in range – once have TML and TMD code implemented review this. 3.8.2) Power stall enhancements Active powerstall logic if ACU in combat and <80% health and is able to use overcharge but cant, and we have at least 50 gross E per tick 3.9) ACU logic 3.9.1) ACU upgrades - alternatives mirror M27 approach re getting T2, RAS etc. if enemy base is far away 3.9.2) Underwater actions – consider what happens/if need any extra code Ignore logic for attacking nearest enemy if the ACU is underwater. 196 3.10) Engineer logic 3.10.1) Reserved build areas ● Whether should try and setup reserved building location idea – in particular for T3 arti and shields. o E.g. one option is to just have certain parts of the map that remain unbuilt on except for emergency defences so that we can build a T3 arti there if we don’t face much early game pressure – so t3 arti we would try and build behind the base if there’s a large enough space; at start of game we’d try and find a location for a shield that at T3 would cover the most mexes without denying adjacency, etc. o Could also e.g. have a ‘reserved for building size x’ location, so if we fail to find somewhere to build randomly, we would make use of this, and once used we would then get a new ‘reserved for building size x’ location 3.10.2) TMD defence – factoring in unit upgrades Search for below – M27 had logic but will want land zone based approach so likely redoing TMD defence logic --T1 mexes - if start upgrading, then flag for TML protection --TODO in a future version 3.11) Quick reference land zones This is to help me when debugging. 3.11.1) Theta passage 22 Jan 23 version: 197 V10 land zones: 198 199 3.11.2) Four-Corners (23/03/2023): 200