Author Topic: Psi AI Threat Priority Bug  (Read 782 times)

0 Members and 1 Guest are viewing this topic.

Offline scient

Psi AI Threat Priority Bug
« on: March 28, 2020, 07:35:16 PM »
So I started work on running some recently decompiled functions through my usual battery of regression tests and ran into an interesting issue when I got to enemy_capabilities(). Essentially, it's purpose is as follows:
Quote
Calculate specified faction's best available weapon and armor ratings as well as the fastest moving ground Veh chassis. Compare these capabilities to faction's best opponent capabilities based on current diplomacy.

I kept getting inconsistent results for output values each time I ran my code. The same would happen with the original function. Here is generally original function's code (I think original function used goto statement at end for diplomacy checks that I reworked/removed):
Quote
void __cdecl enemy_capabilities(int factionID) {
   BOOL hasWorms = veh_avail(BSC_MIND_WORMS, factionID, -1);
   PlayersData[factionID].bestPsiAtkVal = hasWorms ? weap_strat(WPN_PSI_ATTACK, factionID) : 0;
   PlayersData[factionID].bestWeaponVal = 1;
   for (int i = 0; i < MaxWeaponNum; i++) {
      if (has_tech(Weapon.preqTech, factionID) && Weapon.offenseRating < 99) {
         int weapVal = weap_strat(i, factionID);
         if (Weapon.offenseRating < 0 && weapVal > PlayersData[factionID].bestPsiAtkVal) {
            PlayersData[factionID].bestPsiAtkVal = weapVal;
         }
         if (weapVal > PlayersData[factionID].bestWeaponVal) {
            PlayersData[factionID].bestWeaponVal = weapVal;
         }
      }
   }
   PlayersData[factionID].bestPsiDefVal = hasWorms ? arm_strat(ARM_PSI_DEFENSE, factionID) : 0;
   PlayersData[factionID].bestArmorVal = 1;
   for (int i = 0; i < MaxArmorNum; i++) {
      if (has_tech(Armor.preqTech, factionID)) {
         int armVal = arm_strat(i, factionID);
         if (Armor.defenseRating < 0 && armVal > PlayersData[factionID].bestPsiDefVal) {
            PlayersData[factionID].bestPsiDefVal = armVal;
         }
         if (armVal > PlayersData[factionID].bestArmorVal) {
            PlayersData[factionID].bestArmorVal = armVal;
         }
      }
   }
   PlayersData[factionID].bestLandSpeed = 1;
   for (int i = 0; i < MaxChassisNum; i++) {
      if (has_tech(Chassis.preqTech, factionID) && Chassis.triad == TRIAD_LAND) {
         if (Chassis.speed > PlayersData[factionID].bestLandSpeed) {
            PlayersData[factionID].bestLandSpeed = Chassis.speed;
         }
      }
   }
   PlayersData[factionID].enemyBestWeaponVal = 0;
   PlayersData[factionID].enemyBestArmorVal = 0;
   PlayersData[factionID].enemyBestLandSpeed = 0;
   PlayersData[factionID].enemyBestPsiAtkVal = 0;
   PlayersData[factionID].enemyBestPsiDefVal = 0;
   for (int i = 0; i < 4 && !PlayersData[factionID].enemyBestWeaponVal; i++) {
      // 1st pass: vendetta, no treaty, has commlink
      // 2nd pass: no treaty, has commlink
      // 3rd pass: has commlink
      // 4th pass: any non-pact faction
      for (int j = 1, diploStat; j < MaxPlayerNum; j++) {
         if (j != factionID
            && (diploStat = PlayersData.diploStatus[j], !(diploStat & DSTATUS_PACT))
            && ((!i && diploStat & DSTATUS_VENDETTA && !(diploStat & DSTATUS_TREATY)
               && diploStat & DSTATUS_COMMLINK)
               || (i == 1 && !(diploStat & DSTATUS_TREATY) && diploStat & DSTATUS_COMMLINK)
               || (i == 2 && diploStat & DSTATUS_COMMLINK) || (i == 3))) {

            if (PlayersData[factionID].enemyBestWeaponVal < PlayersData[j].bestWeaponVal) {
               PlayersData[factionID].enemyBestWeaponVal = PlayersData[j].bestWeaponVal;
            }
            if (PlayersData[factionID].enemyBestArmorVal < PlayersData[j].bestArmorVal) {
               PlayersData[factionID].enemyBestArmorVal = PlayersData[j].bestArmorVal;
            }

            if (PlayersData[factionID].enemyBestLandSpeed < PlayersData[j].bestLandSpeed) {
               PlayersData[factionID].enemyBestLandSpeed = PlayersData[j].bestLandSpeed;
            }
            if (PlayersData[factionID].enemyBestPsiAtkVal < PlayersData[j].bestPsiAtkVal) {
               PlayersData[factionID].enemyBestPsiAtkVal = PlayersData[j].bestPsiAtkVal;
            }
            if (PlayersData[factionID].enemyBestPsiDefVal < PlayersData[j].bestPsiDefVal) {
               PlayersData[factionID].enemyBestPsiDefVal = PlayersData[j].bestPsiDefVal;
            }
         }
      }
   }
}

So pretty straightforward. It calculates both best defense and offense capabilities for faction (conventional / Psi) then goes on to compare these values to other factions based on certain diplomacy criteria. Well, the issue is with Psi calculations I've highlighted in red. If you dig into weap_strat and arm_strat you'll see unk_59/unk_60 values being used as part of combat ratio passed to psi_factor() and used to calculate Psi power. These are actually enemyBestArmorVal/enemyBestWeaponVal. So the issue is that when the strat functions are called, the best enemy faction's values haven't been fully calculated yet.  It seems after multiple consecutive runs in a row, they normalize. However, this is far too inconsistent a result and runs into same problem potentially as soon as a faction gains new military tech. So far the only real effect I can see this having is a faction prioritizing (or not) Empath Song or Hypnotic Trance. Possibility some stuff related to AI Social Engineering.

Anyway, I thought this was an interesting bug that I'd share. Still doing some more testing but it looks like you can easily break up enemy_capabilities to run conventional calculations first, then do the exact same thing for Psi. Not as efficient, but it prevents the buggy behavior.

Offline bvanevery

  • Emperor of the Tanks
  • Thinker
  • *
  • Posts: 6370
  • €659
  • View Inventory
  • Send /Gift
  • Allows access to AC2's quiz & chess sections for 144 hours from time of use.  You can't do without Leadship  Must. have. caffeine. -Ahhhhh; good.  Premium environmentally-responsible coffee, grown with love and care by Gaian experts.  
  • Planning for the next 20 years of SMACX.
  • AC2 Hall Of Fame AC Text modder Author of at least one AAR
    • View Profile
    • Awards
Re: Psi AI Threat Priority Bug
« Reply #1 on: March 28, 2020, 08:58:40 PM »
Can this explain the AI's completely useless fixation on designing many kinds of units with Empath Song?  There's generally no value in it.  A simple Scout will defeat a mindworm, at the cost of wounding itself some maybe.  If I were hitting the AI with 3 billion mindworms and they thought they were going to get to counterattack me, then maybe I could see the point.  That's not generally been my force mix and yet, so many anti-mindworm units.

Hypnotic Trance makes a lot more sense.  If it's mindworm combat, it's going to be a mindworm attacking, because that's how the game is designed.

Offline scient

Re: Psi AI Threat Priority Bug
« Reply #2 on: March 28, 2020, 09:07:46 PM »
One other thing. The way the original code works, bestWeaponVal/bestArmorVal could be set with Psi value if it's greater. This in turn would affect enemyBestArmorVal/enemyBestWeaponVal that in turn affects Psi factor. This makes my brain hurt.  ???

The fields for bestWeaponVal/bestArmorVal are used in a lot of instances related to diplomacy. I could see forcing this to be non-Psi only would negatively impact say Gaians or other factions that rely on Psi combat. The Psi fields aren't used in a lot of places.




Offline scient

Re: Psi AI Threat Priority Bug
« Reply #3 on: March 28, 2020, 09:12:49 PM »
Can this explain the AI's completely useless fixation on designing many kinds of units with Empath Song?  There's generally no value in it.  A simple Scout will defeat a mindworm, at the cost of wounding itself some maybe.  If I were hitting the AI with 3 billion mindworms and they thought they were going to get to counterattack me, then maybe I could see the point.  That's not generally been my force mix and yet, so many anti-mindworm units.

Hypnotic Trance makes a lot more sense.  If it's mindworm combat, it's going to be a mindworm attacking, because that's how the game is designed.

Pretty sure, yes. The consider_designs() function is used to promote/suggest building Veh prototypes. I quickly traced that var_18 value and it's related to check further up if faction has certain secret projects if Veh gain specific ability from SP.


Offline bvanevery

  • Emperor of the Tanks
  • Thinker
  • *
  • Posts: 6370
  • €659
  • View Inventory
  • Send /Gift
  • Allows access to AC2's quiz & chess sections for 144 hours from time of use.  You can't do without Leadship  Must. have. caffeine. -Ahhhhh; good.  Premium environmentally-responsible coffee, grown with love and care by Gaian experts.  
  • Planning for the next 20 years of SMACX.
  • AC2 Hall Of Fame AC Text modder Author of at least one AAR
    • View Profile
    • Awards
Re: Psi AI Threat Priority Bug
« Reply #4 on: March 28, 2020, 10:28:31 PM »
Well I have a partial workaround in my mod version 1.41.  My Explore tree is pretty pure nowadays.  Centauri Meditation doesn't give much in the way of benefits anymore, only Empath Song and Isle of the Deep.  No Xenoempathy Dome or Empaths, they've been put later in the game.  I decided the Dome is actually rather powerful, should cost more, should come later, and should be exclusive to Explore focused factions.  So this means non-Explore factions aren't nearly as likely to learn Empath Song nowadays.  And Explore factions are probably fielding mindworms, athough I should pay attention to Deirdre next time to see if she's producing all those Empath Song variant units or not.

A more severe workaround would be to move Empath Song much later in the tech tree.  I've done it for other things that I find overpowering, interfering, and chrome-like.  For instance, Dissociative Wave.  In 1.41 I also shoved the Dream Twister very far into the late game, up with Sentient Resonance.  Even the Neural Amplifier, I've put later.  Combat testing shows that mindworms having little defensive weakness, is a serious advantage.

 

* User

Welcome, Guest. Please login or register.
Did you miss your activation email?


Login with username, password and session length

Select language:

* Community poll

SMAC v.4 SMAX v.2 (or previous versions)
-=-
24 (7%)
XP Compatibility patch
-=-
9 (2%)
Gog version for Windows
-=-
103 (32%)
Scient (unofficial) patch
-=-
40 (12%)
Kyrub's latest patch
-=-
14 (4%)
Yitzi's latest patch
-=-
89 (28%)
AC for Mac
-=-
3 (0%)
AC for Linux
-=-
6 (1%)
Gog version for Mac
-=-
10 (3%)
No patch
-=-
16 (5%)
Total Members Voted: 314
AC2 Wiki Logo
-click pic for wik-

* Random quote

It will happen, and it will happen in our lifetimes. Fusion Power isn't just the future. Fusion Power is now.
~ T. M. Morgan-Reilly, Morgan Metagenics

* Select your theme

*
Templates: 5: index (default), PortaMx/Mainindex (default), PortaMx/Frames (default), Display (default), GenericControls (default).
Sub templates: 8: init, html_above, body_above, portamx_above, main, portamx_below, body_below, html_below.
Language files: 4: index+Modifications.english (default), TopicRating/.english (default), PortaMx/PortaMx.english (default), OharaYTEmbed.english (default).
Style sheets: 0: .
Files included: 45 - 1228KB. (show)
Queries used: 37.

[Show Queries]