GOOD NEWS EVERYBODYFuturama is back!
Errr, I mean I solved many AI shooting-related problems. I think... eh, what? Oooh, but I do have my jammies on. On related news the damage calculations have been fixed & the AI_HideNeeded was brought in line with the dodon patch (no more suicide, mkay?).
Kinda... I used proof-of-concept sampling of real shots via mock calls to G_ClientShoot, and, um, I broke my CPU (a turn takes 15 mins atm and crashes are frequent). I didn't check memory usage, but I expect that to skyrocket aswell.
Remember the fan-out term and tree size theorycrafting? Good, here's how it all ties into this post, along with the performance cost estimations & the necessary optimizations. We consider each function separately:
GAH, upon reviewing, my complexity calculations are WAY off. Too bothered to fix tm
AI_FighterCalcBestActionAll damage considerations for a given target are now moved to AI_GetDamagePotential. All notes on AI_GetDamagePotential are in reference to the code that existed i AI_FighterCalcBestAction
AI_GetDamagePotential now drops visibility checks against the target because:
* (fix) Visibility checks were counter-productive. G_VisTeam was used which incorrectly (yet efficiently) checks the vis flags. BUT, a few lines above we moved our critter to a new position which makes those flags obsolete (and G_Vis a terrible liar).
* (fix) We don't need to see someone if we yield an indirect-fire weapon like a grenade/grenadelauncher.
This removes the visibility cut-off and produces a possible fanout between 0(seeing all targets) to enemies+civilians(16?). So, worst case scenario is 16x more leafs.
Obvious performance optimizations are to re-introduce visibility checks for non-indirect weapons.
AI_GetDamagePotential now has all it's damage calculations replaced with the avg of 10 G_ClientShoot mock-up calls. This means that the damage expectation we have is the best there can be (even better from the UI estimations imho).
* (fix) Aliens properly pick shoot types and shooting spots. The difference in their dmg output is quite dramatic.
* (fix) Aliens no longer try and shoot through walls. LOF is properly calculated in G_ClientShoot.
* (fix) Aliens now know the destructive power of grenades & launchers. I did not test this, but it is most probable that they will strongly prefer crowded places for their splash weapons.
* (fix) Aliens properly evaluate friendly fire/self-harm chances (they currently subtract FF damage from damage to enemies in order to get to a final expected dmg).
The penalty we take on performance is quite significant. The fan-out may be only 10 (ontop of the previous one, for a total 160x number of leaves compared to 2.3 AI), but the tracing calculations needed here are a heavy factor.
Performance optimizations needed: An obvious proper bridge to the G_ClientShoot (no reason to try 10x, instead it can give us a base dmg+deviation), OR a complete copy of the damage calculations inside the AI code (bad, code replication&heavy maintenance). Best solution is a mathematical equation that can give us comparable results with minimal CPU.
For people wanting to try and extract the math equations, have a look at g_combat.c. Entry point is G_ClientShoot.
HELP APPRECIATED, I SUCK AT MATHAI_HideNeededThis function became an issue as soon as the dodon patch fixed a hiding issue which moved quite some weight onto this function. Right, over here we need to perform a basic morale check (if morale < brave, then we need to hide), but most of all we evaluate what kind of damage we can expect in the next round (given the tile we stand on). The old style was very simplistic and quite mistaken in the damage expectations. So, we change these with a call to our new AI_GetDamagePotential for every enemy soldier out there. Simple isn't it? That should fix:
* (fix) Aliens now exactly know how much damage they can take the next round (not taking enemies moving into consideration). This means that they will not wander in range of large guns for no reason (reason enough is ofc slamming a grenade in your cluster of soldiers
)
Now, this function is what cause the MAJOR fan-out disaster of doom. If you exclude the changes in this function, the AI is fast enough to play, but here we fan-out again, ontop of our 160x worst case scenario. For every of those leaves we check the damage possible for every enemy. Yes, that's another set of the same fan-outs we had up to this point (we just have num_enemies, not num_enemies+civilians). So that's a worst-case scenario of 8, bringing our fanout up to 8x10=80. Since this is in sequence with the damage calculations, this is multiplicative bringing the total amount of leaves to 160x80=12.800 for a worst case scenario. Yes, this is the point where the CPU just shrieks and tries to liftoff. And don't forget, the shooting calculations are a whole lot heavier than any other calculation we ever do.
Obviously, this would need to be another place were we need to improve quite a bit if we still intend to perform full-tree non-heuristic searches. Only checking only vs enemies that have a direct line of sight would be a first step (but that would make us oblivious to indirect-fire nades/launchers). Other than that, I can't see many ways to keep this functionality and still preserve a full-tree searching. The performance of this function is mainly influenced from the AI_GetDamagePotential function, so any performance gain (in fan-outs) there affects this function in a sqrt kinda of way (8x8 vs (8-Y)x(8-Y)).
So there it is, a nice step forward. Woah, the aliens in the background game are giving me a REALLY hard time :}
You may wanna test this out, if only for a turn or two to get a general idea of what's really changing. You may also want to skip the changes that happen in the AI_HideNeeded function if you only want to see the AI gains in the damage output department.
Oh and I did change the g_ai.h #def GUETE_CIV_FACTOR to 0.20 (from 0.25) because it seemed right (I liked 0.15, but babysteps...). I also created a "#def GUETE_DAMAGE_AVOID 0.5" which is the % of current HP that an alien considers 'acceptable losses' (if not, this tile does not get the GUETE_HIDE bonus). Obvious possible change to this is to flip it from a binary value (run | not_run) to a gradient of score penalty.
Here's the
svn diff vs the latest-ish trunk. (DO NOT GET COMMIT-HAPPY WITH THIS)
P.S: Sweet jesus, my squad got mauled in the last turn, and I did position them nicely...