Author Topic: For AI-"improvements", should I add a new option or use the existing "sneakyAI"?  (Read 13333 times)

Offline psavola

  • Commander
  • *****
  • Posts: 827
    • View Profile
I have played with sneaky AI a couple of times, but I must confess that I do not recall a huge difference in alien behavior. Of course this might be my playstyle as well. But I suppose the aliens could be even sneakier in always trying to use paths where they would much more frequently end their turns in a covered position (if possible: certain maps are very open).

This would very nicely blend in with a feature like you described, where alien "scouts" would more actively work as spotters and background aliens as snipers. In other words, even if the alien spotted you, they would not necessarily fire at you - if there is someone else to snipe from a longer distance and/or the alien would have enough TU left after shooting to run to cover. For aliens this could be a useful tactic with weapons that have no no-sight penalty or when the option is turned off (like vanilla).

Aliens setting up ambushes in precise spots don't necessarily work that well because the number of aliens and their potential deadliness usually far surpasses the X-COM soldiers (at least if you play with higher difficulties, where in a relateively small map you could have 10 or 20 aliens). 5 or 10 aliens cramped in a small space really call for X-COM to throw a grenade and deal with most of them that way. But I kind of agree that very sneaky aliens could possibly more often find better ambush locations and reserve TUs for reaction fire.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
Isn't this the way it's essentially supposed to work now? There is a difference of soldiers the aliens "know" and are "visible" to them. For example, based on turn 20+ cheating, the aliens cannot (AFAIK) shoot directly at the soldier, whose precise location is known (but not visible) to them, or even launch a blaster or throw a grenade (not sure of this), and maybe even not do PSI. For that, the aliens must have actually seen the soldier within a certain amount of turns (depending on the intelligence ie. "memory" or the alien). My understanding is, however, that this memory essentially only affects PSI (i.e. aliens can't still shoot a soldier they remember unless someone spots the soldier on their turn).
It seems like I've done a mistake here in my code due to not fully understanding how selectSpottedUnitForSniper works.
At first it didn't seem to work as I thought it would. But instead of understanding it, I basically just put my || Options::brutalAI there, saw that it now seems to work and moved on.
I have to investigate what exactly getTurnsLeftSpottedForSnipers does and whether I have to do something somewhere else.

So yeah, the issue of cheating with the sniping is likely not happening without brutalAI. So I have to delve a little deeper to make it work as I want. Always takes a while to get accustomed to different coding-styles. The coding-style in oxc is very different to the one in Remnants of the Precursors. The oxc-style has a lot of "methods manipulate members", which imho makes it a little harder to comprehend the flow of events.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
I have played with sneaky AI a couple of times, but I must confess that I do not recall a huge difference in alien behavior.
I also thought there would be some mentions of the Sneaky-option within the AI-code. But it's actually exclusively impacting their path-finding. The way it works is basically that it makes a path more "expensive" in their mind, when it goes through enemy-visible terrain. So they're willing to take a detour. If their path-leads them to an exposed position, then the path-finding doesn't help.

There may be some scenarios where it makes a difference but it's not a huge behavioural change as messing with the AI-code directly.

Another reason because of which it will barely play a role is that the AI doesn't really plan ahead where it wants to be several turns down the line.

Offline Vakrug

  • Colonel
  • ****
  • Posts: 320
    • View Profile
What I mean: Once a unit is spotted its position remains known to the AI for several turns.
I heard this statement several times and nobody bothered to explain what that actually means. Does that means that player's unit position is known to AI no matter where that unit goes or that for several turns AI think that a unit is where it was earlier spotted (and bomb that spot)?

A big reason for the tower-defense-exploit is that they are kinda hard-coded to be hiding until turn 20 and starting from turn 21 they get the idea that maybe they should start exploring.
Hiding until turn 20??? No, only officers are staying inside. Pretty much everyone else run outside from the turn 1.

Another idea: make aliens eager to sneak inside player's vehicle and blow their stockpile of weapons. Something similar do civilians on some maps, just without blowing.
« Last Edit: October 24, 2022, 06:13:10 pm by Vakrug »

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3349
    • View Profile
I would welcome some improvements to AI but not how current Pull Request did that, it do not look like BrutalAI but more like Brutal Force Attack :>

I would prefer multiple new mod options that could alter current AI, there are already one like: turn delay for explosive weapons.
Another thing is that checking full map is not good idea, especially if have map 100x100x20.

And for common knowledge, could be this only applied when both aliens see each other (distance affected by intelligence or psi)?
How one rat at one edge of map could know that other rat on other side know about our soldiers? He should not, but two Ethereals could.





Offline Finnik

  • Commander
  • *****
  • Posts: 508
  • Finnik#0257
    • View Profile
I heard this statement several times and nobody bothered to explain what that actually means. Does that means that player's unit position is known to AI no matter where that unit goes or that for several turns AI think that a unit is where it was earlier spotted (and bomb that spot)?
Hiding until turn 20??? No, only officers are staying inside. Pretty much everyone else run outside from the turn 1.

Another idea: make aliens eager to sneak inside player's vehicle and blow their stockpile of weapons. Something similar do civilians on some maps, just without blowing.

Sorta, for instance, because of that they can shoot through smoke in conditions when they absolutely can not see you. I mean, while debug you can see what current unit can see (using "player" rules, not cheaty AI rules), and smoke is breaking LoS. But the enemy still shoot precisely and likely hit, as it would actually see it.
Misterjopper pointed that feature to me and prepared a fix: https://github.com/723Studio/OpenXcom_FTA/pull/157
He also made own build with that fix, check it out, it has more detailed description: https://openxcom.old.mod.io/sniper-spotter-ai-nerf-for-open-xcom-engine-7517
For me personally, it fixed multiple balance issues with some of my missions.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
I heard this statement several times and nobody bothered to explain what that actually means. Does that means that player's unit position is known to AI no matter where that unit goes or that for several turns AI think that a unit is where it was earlier spotted (and bomb that spot)?
Yes. It means the position is known for several turns no matter where that unit goes. But the AI doesn't bomb that spot. It just takes it into consideration for their actions.

Hiding until turn 20??? No, only officers are staying inside. Pretty much everyone else run outside from the turn 1.
Not hiding as in actually hiding. It's more like "rocking back and forth between patrol-nodes". If these patrol-nodes are outside, they will rock back and forth outside, if they are inside the UFO, they will do it inside. Officers have a higher chance of spawning inside. That's why it's usually them in the UFO.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
I would welcome some improvements to AI but not how current Pull Request did that, it do not look like BrutalAI but more like Brutal Force Attack :>

I would prefer multiple new mod options that could alter current AI, there are already one like: turn delay for explosive weapons.
Another thing is that checking full map is not good idea, especially if have map 100x100x20.

And for common knowledge, could be this only applied when both aliens see each other (distance affected by intelligence or psi)?
How one rat at one edge of map could know that other rat on other side know about our soldiers? He should not, but two Ethereals could.
Didn't make too much progress yesterday. I fixed the sniping without being spotted and tried to get them to do a more defensive style. Then I played on another map and they just got stuck due to it all not working as intended. It definitely was too premature of a pull-request. I'm now also thinking of separating my code much more from the rest because dozens of if(Options::brutalAI)-checks spread all over the code makes it look very messy. I'd rather split off my decision-making right at the beginning from a clean slate. That will obviously take longer but I'll feel a lot more in control of what happens.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
Sorta, for instance, because of that they can shoot through smoke in conditions when they absolutely can not see you. I mean, while debug you can see what current unit can see (using "player" rules, not cheaty AI rules), and smoke is breaking LoS. But the enemy still shoot precisely and likely hit, as it would actually see it.
Misterjopper pointed that feature to me and prepared a fix: https://github.com/723Studio/OpenXcom_FTA/pull/157
He also made own build with that fix, check it out, it has more detailed description: https://openxcom.old.mod.io/sniper-spotter-ai-nerf-for-open-xcom-engine-7517
For me personally, it fixed multiple balance issues with some of my missions.
Yeah, when I investigated how the spotter-code is supposed to work, I also thought that this is what would happen. It seems to also just tag a unit as spotted and duration of that tag is dependent of the intelligence of the spotter.
No idea why it was written like that.
What I'm now using is a simple function that asks the alien's friends if any of them can actually currently see an enemy. Which I think is much more straightforward.

Offline Finnik

  • Commander
  • *****
  • Posts: 508
  • Finnik#0257
    • View Profile
Yeah, when I investigated how the spotter-code is supposed to work, I also thought that this is what would happen. It seems to also just tag a unit as spotted and duration of that tag is dependent of the intelligence of the spotter.
No idea why it was written like that.
What I'm now using is a simple function that asks the alien's friends if any of them can actually currently see an enemy. Which I think is much more straightforward.
Yeah, when I investigated how the spotter-code is supposed to work, I also thought that this is what would happen. It seems to also just tag a unit as spotted and duration of that tag is dependent of the intelligence of the spotter.
No idea why it was written like that.
What I'm now using is a simple function that asks the alien's friends if any of them can actually currently see an enemy. Which I think is much more straightforward.
Sounds very promising, looking forward to see what you can offer. We did not get any AI updates for a while :)

Didn't make too much progress yesterday. I fixed the sniping without being spotted and tried to get them to do a more defensive style. Then I played on another map and they just got stuck due to it all not working as intended. It definitely was too premature of a pull-request. I'm now also thinking of separating my code much more from the rest because dozens of if(Options::brutalAI)-checks spread all over the code makes it look very messy. I'd rather split off my decision-making right at the beginning from a clean slate. That will obviously take longer but I'll feel a lot more in control of what happens.
I also thought that way - some enemies are primitive monsters, that can't cooperate tactically over battlescape, some are just human soldiers, that actually can communicate via radio to cooperate. Some are even psionivally merged consciousness. I would really like to have an option to define units behavior to reflect their nature in that way.
For instance, I thought if I could make a feature for some swarm monsters - if one in the group is attacking or being attacked, it makes a cry to call all friends. This would take all patrolling units from the group and set their patriol distribution to their enemy. This would make an interesting fight with swarm of, say, zombie or chupacabras...

Offline bohemond

  • Sergeant
  • **
  • Posts: 44
    • View Profile
I'd rather split off my decision-making right at the beginning from a clean slate. That will obviously take longer but I'll feel a lot more in control of what happens.

I can confirm that splitting the code off completely is probably the best way to do it. What I've done is sidestep the game AI in BattlescapeGame.cpp like this:
In BattlescapeGame::think, instead of
Code: [Select]
if (!handlePanickingUnit(_save->getSelectedUnit()))
handleAI(_save->getSelectedUnit());
I have my AI module return a BattleAction and let that be handled by the Battlescape:
Code: [Select]
BattleAction unitAction = sideAI[_save->getSide()]->HandleTurn();
if (unitAction.type != BA_NONE)
{
handleUnitAction(unitAction);
}

That way, your AI can also handle order of selecting units, which is sometimes important.
Some other code is necessary to connect the modules together, but I've had best results with this kind of idea.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
I didn't think of putting the AI-code somewhere else completely.
What I've done yesterday was to call a "brutalThink()" method relatively early in "think()".
Writing it completely from scratch seemed a bit unreasonable.

Some of the existing methods already did almost exactly what I wanted. Like the Psi- and Blaser-usage code.

The already existing sniper-code is so good, honestly with just a small modification. It actually uses a sophisticated algorithm to decide which weapon and fire-mode to use and that makes the regular fire-mode/weapon-selection code pretty much obsolete.

The main-reason for making my own method is to have the code that decides where to move all in one place with one iteration over the possible targets and calculating a score based on various criteriae.
Besides of the obvious of placing them where they can shoot at X-Com, I think I really want to avoid having them charge at the X-Com-soldiers as that always will be exploitable.
I found that for each unit the currently visible tiles are stored. So I can evaluate the positions of all alien units in the beginning based on how many tiles they see and then tell the others to look for similarly neat spots near the unit that has the good spot.

So essentially an approach that is much closer to Vakrug's suggestion. I have a great save of a map with the UFO and 3 houses. It currently is much easier to deal with the aliens UFO than the ones in the three houses that fire through windows or from the rooftops.

I'm really looking forward to trying whether what I have in mind will end up working.

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
Made some good progress today. It kinda works like I wanted it to work.

I'm having a bit of a friendly-fire issue when they meet up with their friends. Need to find a way where they space out a little better and avoid shooting each other in the back.

The other issue is that Floaters and Ethereals take significantly longer for their turns due to the addition of the third dimension to their movement. I don't really see too much potential to further cut down on the performance without giving up playing-strength.

Edit:

I think _save->getTileEngine()->calculateLineTile(current->getPosition(), bestTargetableEnemy->getPosition(), positionsToAvoid); is my friend when it comes to back-shooting-avoidance :)
« Last Edit: October 27, 2022, 02:27:21 am by Xilmi »

Offline Xilmi

  • Moderator
  • Commander
  • ***
  • Posts: 642
    • View Profile
Here's some more detail on the way it works now. Please chime in with recommendations if you think there seems to be something wrong with it.

Alien does their usual check for psi-attack or blaster-launch.
Then it uses a modified version of the sniper-code that uses an actual visibility check of their friends and doesn't cheat like the last version. Not cheating obviously makes it weaker in that sense.
Another modification is that when there's several potential targets the closest is preferred instead of a random one.

After that everything is entirely new code.
The first part is what I'd call the line-of-fire-checking-part. It looks up all tiles in range with enough TU reserved to still do an attack from where it can get a line of fire to x-com-soldiers. There's a huge score-bonus if that soldier is currently visible to a friend. It also traces back from all x-com-soldiers to get a divisor for how often it would be in their line of fire. Civilians get drastically reduced score for that. (I shall also do that for the sniper, target-selection I just realized).
So tiles from which many x-com-soldiers could be shot at will be preferred.
If no LOF was found, path-finding to that tile will be skipped since path finding is way more expensive than LOF-checking and we don't want to do it unnecessarily.
The path-finding is used to determine a score-factor based on distance to the preferred tile and also to make sure we don't pass on an unreachable tile as this results in an endless-loop.

There's 3 possible scenarios. The simplest one is the one where the unit finds a tile with a higher score in it's range. Then it simply just goes there.
Scenario 2 is that it realized it's already standing on the best tile in range. Then a check is performed to find the x-com-unit that is in lof of the most aliens. If at least 2 aliens can see the most visible one, the alien closest to it will be ordered to walk towards it. It basically becomes a spotter for the others. Note that none of that happens when there's no Lof. So you can't lure the aliens in an alley to set up your own traps.
If less than 2 aliens have a lof the unit will just stay where it is and face in the direction of the closest enemy is has lof to. Note that BA_TURN was not implemented before so I had to do it. AI couldn't turn without moving before. It was basically 1 line of code that was simply missing.

Scenario 3 is when the alien didn't find any tile to get a lof from.

In this case there's a 2 step process for what it does instead. First it asks it's friend who has the best LoF. If none of the friends does have any lof either, it asks them who can see the most tiles. (I had to change the code for that too, as this was only tracked for x-com-units but not aliens. And then I had to make sure the aliens don't reveal the map for the player, as this was done in the same function that stores the visible tiles to the unit.)

Whichever it was, it then will carefully (saving enough TUs for aimed) walk towards their position. In all the determinations of where to go there will be a check to avoid standing directly in the line of fire of other aliens. They still tend to end up quite close together, which makes them a good target for AoE. If you can find them before they kill you, that is.

I've done two test-battles. One of them went way better than the other. Having a lot of cover, in this case no less than 4 buildings, helped tremendously. I got really close to a pack of 4 aliens while getting there unseen.

I think the whole "move towards friend"-idea is probably mistaken. It discards other good opportunities and leads to vulnerabilty against AoE. My initial idea was to calculate a generalized score for everything. But that was hard to handle. So I went to this "look at my friends"-idea instead.
Now I'm thinking instead of combining the scores, I calculate two separate ones. When the first one is above zero it always wins. But if not, then the other will be a fallback-score. And that one could actually be about hiding. It still could consider visibility, how good it is visible for enemies, proximity to friends and also enemies in some way.

So the idea would be: If the X-Com soldiers expose themselves, we get into position to snipe them, send a spotter and then fire at them from all angles. But if the X-Com soldiers hide themselves, we do the same and let them come to us.

I realize that this is vastly different from my initial idea of how the aliens should play and really close to what Vakrug said from the beginning.

Offline psavola

  • Commander
  • *****
  • Posts: 827
    • View Profile
There's 3 possible scenarios. The simplest one is the one where the unit finds a tile with a higher score in it's range. Then it simply just goes there.
Scenario 2 is that it realized it's already standing on the best tile in range. Then a check is performed to find the x-com-unit that is in lof of the most aliens. If at least 2 aliens can see the most visible one, the alien closest to it will be ordered to walk towards it. It basically becomes a spotter for the others. Note that none of that happens when there's no Lof. So you can't lure the aliens in an alley to set up your own traps.
If less than 2 aliens have a lof the unit will just stay where it is and face in the direction of the closest enemy is has lof to. Note that BA_TURN was not implemented before so I had to do it. AI couldn't turn without moving before. It was basically 1 line of code that was simply missing.

Not sure if I understand all of this, but finding a "best tile" where to move sounds maybe too simplistic. With vanilla options, would it make sense to fire from the tile that requires least amount of movement. The main issue with "best tile" comes up with with extended accuracy/no-LOS penalty options (not sure if you've tested those as well). There each tile might have a different accuracy to the target. Then it might become a difficult optimization problem which tile is "best" to move to - should you try to move to a tile, where the alien can itself see the enemy and remove the no-LOS penalty? Or which other tile (with increasing/decreasing accuracy) would be "best"? It might be arguable that the unit should settle with a tile that is "good enough" (and possibly leaves some TUs to spare), or at least that the unit does not unnecessarily move closer to the target and expose itself if doing so does not provide any real advantage.