Author Topic: Please Help Me Fix An Ai Problem  (Read 2811 times)

Offline elwood_s

  • Jr. Member
  • **
  • Posts: 74
Please Help Me Fix An Ai Problem
« on: June 28, 2010, 02:29:34 PM »
In PCW, the AI periodically sends attack waves against the player's base, starting with just a single Micro-Lynx. Below is the section of the code that's supposed to add more types of units to the attack waves as time passes, and the aiCount counter gets incremented.

Code: [Select]
    // Check the count and increase the AI strength as needed
    if (saveData.aiCount == 10 * saveData.diffMultiplier)
    {
        // Starflare time
        saveData.aiMassGrp.SetTargCount(curType, mapStarflare, 3 - (saveData.diffMultiplier * 1.5));
    }
    else if (saveData.aiCount == 20 * saveData.diffMultiplier)
    {
        // Stickyfoam time
        saveData.aiMassGrp.SetTargCount(curType, mapStickyfoam, 3 - (saveData.diffMultiplier * 1.5));
    }
    else if (saveData.aiCount == 30 * saveData.diffMultiplier)
    {
        // EMP time
        saveData.aiMassGrp.SetTargCount(curType, mapEMP, 3 - (saveData.diffMultiplier * 1.5));
    }
    else if (saveData.aiCount == 45 * saveData.diffMultiplier)
    {
        // RPG time
        saveData.aiMassGrp.SetTargCount(curType, mapRPG, 3 - (saveData.diffMultiplier * 1.5));
    }
    else if (saveData.aiCount == 70 * saveData.diffMultiplier)
    {
        // ESG time
        saveData.aiMassGrp.SetTargCount(curType, mapESG, 3 - (saveData.diffMultiplier * 1.5));
    }
    else if (saveData.aiCount == 75 * saveData.diffMultiplier)
    {
        // Nova time
        saveData.aiMassGrp.SetTargCount(curType, mapSupernova, 3 - (saveData.diffMultiplier * 1.5));
    }


aiCount is an integer variable that gets incremented by 1 every cycle.  In this section, diffMultiplier is used to make the changes happen faster on Hard than on Normal, and slower on Easy than on Normal.

On "Normal"difficulty level, it does just that, sending single Micro's up until ~mark 220 when it starts sending waves made up of one Micro and one Starflare.  At ~mark 280 it starts sending waves made up of a Micro, a Starflare and a Sticky, and so on as time passes until it's sending waves made up of all seven unit types.  

The problem is it only works on Normal.  On both "Hard" and "Easy" difficulty levels, it just continues to send single Micro-Lynx waves throughout the entire game. When I first noticed the problem I assumed that it was something that I'd accidentally screwed up. Then, after wasting more than a week trying to find my mistake, I decided to test the original "Plymouth Cold War" (the one that comes bundled with the OPU version of Outpost2). I was surprised to find that the AI in the original behaves exactly as it does in my modded version. After squinting at the code and wracking my brains for more than two weeks, I finally think I've found the root of the problem in the following section of code which sets up the value of diffMultiplier.

Code: [Select]
Player[0].GoEden();
    saveData.diffMultiplier = 0.7;
Player[0].MarkResearchComplete(techResearchTrainingPrograms);
Player[0].MarkResearchComplete(techOffspringEnhancement);
Player[0].MarkResearchComplete(techCyberneticTeleoperation);

    if (Player[0].Difficulty() < 2)
    {
        saveData.diffMultiplier = 1;
        Player[0].MarkResearchComplete(techLargeScaleOpticalResonators);
        Player[0].MarkResearchComplete(techHighTemperatureSuperconductivity);
        Player[0].MarkResearchComplete(techMobileWeaponsPlatform);
        Player[0].MarkResearchComplete(techMetallogeny);
        if (Player[0].Difficulty() < 1)
        {
            saveData.diffMultiplier = 1.3;
            Player[0].MarkResearchComplete(techExplosiveCharges);
            Player[0].MarkResearchComplete(techScoutClassDriveTrainRefit);
        }
    }


I think the problem is that there's no possible integer value multiplied times .7 that can ever exactly equal 10, 20, 30, etc...  Same problem when you multiply by 1.3.  Of course multiplying by 1.0 (the Normal level value for diffMultiplier) is no problem, so Normal level works as it should.

Does this sound right to you?
« Last Edit: June 28, 2010, 03:50:27 PM by elwood_s »

Offline Moley

  • Jr. Member
  • **
  • Posts: 95
Please Help Me Fix An Ai Problem
« Reply #1 on: June 28, 2010, 04:05:34 PM »
uhh... no... the .7 and 1.3 is multiplied by 10,20 etc...
thus you get
for .7
7,14,21 etc.
for 1.3
13,26,39 etc.
I HATE SPELLING!!!!!!
if i spell something or screw up grammer,
ignore it or tell me if you dont understand what i typed.

Offline elwood_s

  • Jr. Member
  • **
  • Posts: 74
Please Help Me Fix An Ai Problem
« Reply #2 on: June 28, 2010, 07:45:58 PM »
Quote
uhh... no... the .7 and 1.3 is multiplied by 10,20 etc...
thus you get
for .7
7,14,21 etc.
for 1.3
13,26,39 etc.
Thanks Moley, you're right! I was reading the condition backwards.  :oops:  
I guess that's what dyslexia, combined with a complete lack of C programming experience can do to a fellow. :wacko:

So now I've still got to figure out why it works on Normal level, but not easy or hard.  :(
« Last Edit: June 29, 2010, 01:38:53 PM by elwood_s »

Offline elwood_s

  • Jr. Member
  • **
  • Posts: 74
Please Help Me Fix An Ai Problem
« Reply #3 on: June 29, 2010, 03:21:10 PM »
Well, it looks like I was half right. <_<

I was still suspicious of the non-integer values used for diffMultiplier in the Easy and Hard level games, even though I still couldn't figure out why would they would keep the AI from from adding more unit types to it's attack groups. So I finally decided to just change the Hard level value for diffMultiplier from .07 to 1 (line 2 in the section of code below) and then try a Hard level game to see if it makes any difference.

Code: [Select]
 Player[0].GoEden();
 saveData.diffMultiplier = 1;//changed from 0.7 to 1 for testing purposes only ***
Player[0].MarkResearchComplete(techResearchTrainingPrograms);
Player[0].MarkResearchComplete(techOffspringEnhancement);
Player[0].MarkResearchComplete(techCyberneticTeleoperation);

    if (Player[0].Difficulty() < 2)
    {
        saveData.diffMultiplier = 1;
        Player[0].MarkResearchComplete(techLargeScaleOpticalResonators);
        Player[0].MarkResearchComplete(techHighTemperatureSuperconductivity);
        Player[0].MarkResearchComplete(techMobileWeaponsPlatform);
        Player[0].MarkResearchComplete(techMetallogeny);

        if (Player[0].Difficulty() < 1)
        {
            saveData.diffMultiplier = 1.3;
            Player[0].MarkResearchComplete(techExplosiveCharges);
            Player[0].MarkResearchComplete(techScoutClassDriveTrainRefit);
        }
Player[0].SetWorkers(20 * saveData.diffMultiplier); // **upped workers from 15 to 20 on normal
Player[0].SetScientists(10 * saveData.diffMultiplier);// **upped scientists from 7 to 10 on normal
    }
else
{
  Player[0].SetWorkers((20 * saveData.diffMultiplier)+2); // ** 2 extra workers on hard only
  Player[0].SetScientists((10 * saveData.diffMultiplier)+2);// ** 2 scientist on hard only
}

Sure enough, I tried a Hard level game and the the AI started adding Starflares to it's attack groups around mark 130. This was the first time in the AI attacked with anything other than a single Micro-Lynx, in any of the PCW Hard level games I've tested, my mods or the original. So it very much appears that the non-integer values used for diffMultiplier in PCW Hard and Easy level games, are in fact what keeps the AI from escalating it's attacks in those games.

But I still can't figure out why a non-integer value for diffMultiplier for keeps the AI from escalating it's attacks?  I know it's not the issue I cited in the first post of this thread. Moley straightened me out on that point. Now I'm just stumped.

I've attached my source code to this post.  Would one of you guys with a better understanding of C and Op2 programming please take a look at it and help me find this bug.
« Last Edit: June 29, 2010, 03:25:25 PM by elwood_s »

Offline Hidiot

  • Hero Member
  • *****
  • Posts: 1018
Please Help Me Fix An Ai Problem
« Reply #4 on: June 30, 2010, 03:37:14 AM »
I'd suggest making the calculations in floats and casting the result into an integer, if an integer is absolutely necessary.
"Nothing from nowhere, I'm no one at all"

Offline elwood_s

  • Jr. Member
  • **
  • Posts: 74
Please Help Me Fix An Ai Problem
« Reply #5 on: June 30, 2010, 08:10:15 PM »
Quote
I'd suggest making the calculations in floats and casting the result into an integer, if an integer is absolutely necessary.
Thanks for the suggestion.  

diffMultiplier is set to one of three values when the game is initialized, depending on the difficulty level: 1.3 for Easy, 1.0 for Normal, and 0.7 for Hard and as near as I can tell the value is never changed after that.  It's the only float (actually a double) in the program.  It's a factor in the calculation of many different things, (starting resources, number of colonists, frequency and severity of disasters, how quickly the AI ramps up it's attacks, etc., etc...) Although I don't recognize the purpose of, or understand all the calculations it's used in, I've begun to doubt that the result of any of them actually requires floating point precision.
« Last Edit: June 30, 2010, 08:48:18 PM by elwood_s »

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Please Help Me Fix An Ai Problem
« Reply #6 on: July 01, 2010, 09:17:20 PM »
Have you tried the modified copy in put in SVN? I changed the diffMultiplier variable to be an integer, and scaled uses of it to try and match old behavior. I didn't really do much testing though, so I may have added bugs. I know for sure there was at least one section of code I forgot to convert in the first commit that someone else caught. That's been fixed now though.


Also, after a quick glance at the discussion above, the 0.7 and 1.3 multipliers seem like they should work for the *10 (and multiples there of) factors, but there are also the 45 and 75 cases.


At any rate, I generally avoid floating point like the plague. There are just too many things wrong with floating point, and generally no real reason to use them. I find it's far better to just stick with fixed point (scaled integers).
 

Offline elwood_s

  • Jr. Member
  • **
  • Posts: 74
Please Help Me Fix An Ai Problem
« Reply #7 on: July 02, 2010, 10:59:03 PM »
Quote
Have you tried the modified copy in put in SVN? I changed the diffMultiplier variable to be an integer, and scaled uses of it to try and match old behavior. I didn't really do much testing though, so I may have added bugs. I know for sure there was at least one section of code I forgot to convert in the first commit that someone else caught. That's been fixed now though.
.
Thanks Hooman.  :)

I tried it back when you first added it to the SVN.  I'm the one who noticed the unconverted section. Didn't know you'd fixed it, so I haven't tried it since.  I'll give it another go, as soon as I get a chance.

I tried changing the diffMultiplier variable to an int, with values of 1, 2, & 3 (Hard, Normal, & Easy) and have been tinkering around with this for the past few days. Making this one change fixes the problem of the AI not escalating it's attacks in Hard and Easy level games, though I'm still clueless as to why. :unsure: One question you can probably answer though: Since there are no longer any floats in the program, what do I have to do to get rid of the floating-point runtime library support? The compiled size didn't get any smaller, so it's apparently still being incorporated.
 
Quote
Also, after a quick glance at the discussion above, the 0.7 and 1.3 multipliers seem like they should work for the *10 (and multiples there of) factors,....
I agree that they should work.  Unfortunately they don't, while the 1 multiplier does.

Quote
There are just too many things wrong with floating point, and generally no real reason to use them. I find it's far better to just stick with fixed point (scaled integers).
This has surely made a believer out of me.
« Last Edit: July 02, 2010, 11:17:03 PM by elwood_s »

Offline Moley

  • Jr. Member
  • **
  • Posts: 95
Please Help Me Fix An Ai Problem
« Reply #8 on: July 03, 2010, 09:15:13 AM »
does the 1.3 work? because maybe it is converting the number to an integer BEFORE it multiplies?
I HATE SPELLING!!!!!!
if i spell something or screw up grammer,
ignore it or tell me if you dont understand what i typed.

Offline elwood_s

  • Jr. Member
  • **
  • Posts: 74
Please Help Me Fix An Ai Problem
« Reply #9 on: July 03, 2010, 03:16:41 PM »
Quote
does the 1.3 work? because maybe it is converting the number to an integer BEFORE it multiplies?
The 1.3 (Easy level) diffMultiplier value doesn't work either.

In Easy level games the AI never gets beyond using single Micro-Lynx Attack groups, same as in Hard Level (0.7 diffMultiplier value) games.  When the standard (Hard=0.7, Normal=1, Easy=1.3) diffMultiplier values are used, the AI only escalates it's attacks in the Normal level game. :(

BTW, thank you again for for pointing out the error in the way I was reading the conditions in the first post of this thread.  Kept me from wasting time trying to rewrite the conditions. :)
« Last Edit: July 03, 2010, 04:42:40 PM by elwood_s »

Offline Moley

  • Jr. Member
  • **
  • Posts: 95
Please Help Me Fix An Ai Problem
« Reply #10 on: July 04, 2010, 01:34:02 PM »
have you fixed it yet? if not, here is how i would solve it...
change the values to meet by a factor of 10, or so... and multiply the diffmultiplyers by 10...
ergo, target was 10 and multiplier .7
now target is 100 and multiplier is 7
I HATE SPELLING!!!!!!
if i spell something or screw up grammer,
ignore it or tell me if you dont understand what i typed.

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4955
Please Help Me Fix An Ai Problem
« Reply #11 on: July 04, 2010, 02:47:40 PM »
That's basically what I did when I modded the code. There were compile errors involving floating point, so I scaled everything and changed the floats to ints.

Offline Moley

  • Jr. Member
  • **
  • Posts: 95
Please Help Me Fix An Ai Problem
« Reply #12 on: July 05, 2010, 07:28:15 AM »
... sorry... yeah i didn't even read you code hooman :P
so i guess this means the problem is solved and i can sop trying to fix it?
I HATE SPELLING!!!!!!
if i spell something or screw up grammer,
ignore it or tell me if you dont understand what i typed.

Offline Flashy

  • Sr. Member
  • ****
  • Posts: 391
Please Help Me Fix An Ai Problem
« Reply #13 on: August 07, 2010, 01:51:27 PM »
Post 1)
I tested something similar but it worked for me.
Double test 0.7 and 1.3

count++
if(count == 10*test)
{
// Message
}

And the message got played. Im going to try to compile it with msvc. But i got an idea how to match the result of the 45 and 75 cases: By converting it into an int value.
if(savedata.aicount == (int)(45*savedata.diffmultiplier))
~~~~~~~~~
Post 2) Yes compiling works... i didn't want to solve the problems with the briefing, so i disabled it. the first thing i noticed was that my version saved the objectives correctly.
~~~~~~~~~
Post 3)
I added my fix and the briefing code. Strange, the briefing doesn't show up....
Praise the mighty light towers!!!