• Hello and welcome to MSFC. We are a small and close knitted community who specialises in modding the game Star Trek Armada 2 and the Fleet Operations modification, however we have an open field for discussing a number of topics including movies, real life events and everything in-between.

    Being such a close community, we do have some restrictions, including all users required to be registered before being able to post as well as all members requiring to have participated in the community for sometime before being able to download our modding files to name the main ones. This is done for both the protection of our members and to encourage new members to get involved with the community. We also require all new registrations to first be authorised by an Administrator and to also have an active and confirmed email account.

    We have a policy of fairness and a non harassment environment, with the staff quick to act on the rare occasion of when this policy is breached. Feel free to register and join our community.

A2 AI Modding

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
I got this bit of code from Civ 3 I believe and wanted to know if anyone here knows how to read it? Is this LUA? What does the -> between words mean like ai->m_planner->the_AIP.max_misc_bid_bonus? Is it just saying reference the ai file and inside that is the m_planner file and inside that is.....?

double high_movement_weight = .75;
double low_defense_weight = .25;
double bonuses = 0.0;
sint32 best_defense;
sint32 my_defense = army_agent->GetBestDefense(ai);
if (ai->m_science_agent->GetBestLandDefense(best_defense))
bonuses += (1.0 - (my_defense / best_defense))
* ai->m_planner->the_AIP.max_misc_bid_bonus
* low_defense_weight;
else
;
sint32 best_move;
double my_move = army_agent->GetBestMove(ai);
if (ai->m_science_agent->GetBestLandMove(best_move))
bonuses += (my_move / best_move)
* ai->m_planner->the_AIP.max_misc_bid_bonus
* high_movement_weight;
else
;
double time_term;
MapPointData dest_pos;
army_agent->GetPos(ai, dest_pos);
double tile_count = ai->m_map->WrappedDistance(*m_pos, dest_pos);
time_term = ( rounds * rounds
* ai->m_planner->the_AIP.distance_from_unit_priority_modifier )
- tile_count;
return bonuses + time_term + Compute_Raw_Priority(ai);
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
I managed to find a link to LUA website and their guide to read LUA from scrolling through the Civ forums.

This is a link to what seems to be a dumping ground Lua information from one of the Civ games.

I'm not sure how much of help these can be as I gave up trying to understand Lua, but they might be able to point you to the right direction.
 

CABAL

<< ■ II ▶ >>
Staff member
Administrator
Star Navigator
Rogue AI technocrat
Joined
15 Aug 2009
Messages
3,511
Age
33
Found some information! It looks like -> is an operator unique to the C family, so here's a C++ example, since I think Civ3 may use C++:

Code:
#include <iostream>
using namespace std;

class SomeClass
{
public:
       int mydata;
       bool someTruth;

       SomeClass()
       {
              mydata = 0;
              someTruth = false;
       }
};

int main()
{
        SomeClass mySomeClass;  // Not a pointer...
        SomeClass *pSomeClass;  // we defined the pointer.
        pSomeClass = new SomeClass; // we allocate the pointer.

        // accessing the stuff beyond the pointer.
        pSomeClass->mydata = 10; // we assigned mydata, the object's member, to 10.
        pSomeClass->someTruth = true;  // now we made someTruth, the object's member, to true
        // the previous too lines are basically similar to
        mySomeClass.mydata = 10;
        mySomeClass.someTruth = true;

        // agian accessing the member of the pointer of SomeClass
        if(pSomeClass->someTruth == true)
        {
               cout << "pSomeClass->someTruth was True" << endl;
        }

        // clean up the pointer
        delete pSomeClass;
    
        return 0;
}

So they defined a custom object class called SomeClass. Objects of SomeClass have two properties, mydata and someTruth. They create an object of SomeClass, conveniently called mySomeClass, define a pointer, and use the pointer to modify the properties of mySomeClass.

I think a similar thing is going on with that Civ code. Most of it looks like they could have just used (to use the above example again) something like mySomeClass.mydata, so I'm not sure why they're going with such a convoluted approach, though they could just be used to doing it that way or there's some advantage I'm not aware of.

So, from the Civ code, this line:

sint32 my_defense = army_agent->GetBestDefense(ai);

means they're creating a 32 bit integer named my_defense and assigning it a value equivalent to a property of army_agent. I think. I'm more familiar with C# and this is a weird implementation to me. There seems to be a function involved, which is throwing me off. Though I suppose they maybe could have used a function as a property of army_agent, for some reason.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Thank you both. I'm not trying to understand LUA per say Admiral*Alex, but that code or more precisely some snippets of those codes appear in Battlezone, Dark Reigh, Civ 3, Star Trek Armada and Armada II which are evolution's of the same game engine so I'm digging for info on how to understand some of the AI settings in the personality files of A2.

For instance the following appear in each game in some form or another: int attack_region_priority =1000; double max_matching_force_ratio = 1.5; double min_matching_force_ratio = 0.95
int human_target_raw_bonus = 0; int max_misc_bid_bonus = 600;

I think I'm slowly understanding some of them and still testing, but others elude me and I can't for the life of me grasp yet. Some I've figured out, but for instance 'int human_target_raw_bonus = xx' may mean the AI gets a bonus against the player or the player gets a bonus against the human making the human player a juicer target than another AI on the map. I can make it 0 or 1000, but can't discern in testing what the benefit is? I'm going through a bunch of info from Dark Reign and Civ 3 for clues and appreciate any tips you all provide.

Here's another:
int max_danger_raw_bonus = 0;
int max_threat_raw_bonus = 0;

For years I always wondered what a bonus to danger and threat could possibly mean. From what I'm finding and I could be way off base is that the AI gives weight in it's decision to attack if something is more dangerous than something else and projects more threat. It's only a guess, but like I said testing, testing, testing. This seems off though as found decades ago in Armada 2 the AI attacks ships with lower health first which seems counter productive. If you have a scout and a battleship the scout always gets attacked first if within the same range.
 

Terra_Inc

MSFC's Cheshire Cat
Staff member
Site Manager
Necromancer/Troll hunter
Kitten Commander
Joined
16 Dec 2009
Messages
3,137
Age
34
I got this bit of code from Civ 3 I believe and wanted to know if anyone here knows how to read it? Is this LUA? What does the -> between words mean like ai->m_planner->the_AIP.max_misc_bid_bonus? Is it just saying reference the ai file and inside that is the m_planner file and inside that is.....?

I can make limited sense of it, yes. It looks like a function. I can see a return statement, but no signature. If you could get a larger or more complete snippet of the code, I might be able to understand it better. As to the language, it looks like C++ to me. Definitely not Lua.

It's hard to say what the code does without knowing the implementation of the classes being used here, and there are no comments either. Even with the complete code there's no guarantee I'd actually be able to understand what it's supposed to do -- as you're finding out yourself, other people's code can be very hard to understand. What I can do is explain to you how to read this kind of code.

So, let's get technical. The ->, as CABAL pointed out, is an arrow operator. It's used to access members of an object or structure. The dot operator, which is used here too, does much the same. If you're not familiar with the idea of an object, it's basically just a grouping of data with associated functions that operate on said data. They do not correspond to actual files in your file system. Objects are an instance of a class, which dictates what kind of data and which functions an object of that class should contain. So, as a rough example, two ships in a game like A2 are different objects of the same class, whereas a ship and a station would probably be two objects of different classes.

Let's take a look at the term ai->m_planner->the_AIP.max_misc_bid_bonus. Without knowing anything about the objects and classes involved, we can see that there's a pointer to an object called ai, which contains a pointer to another object called m_planner. This m_planner holds an object called the_AIP, and we're accessing a variable called max_misc_bid_bonus -- this is clearly an actual numeral variable -- inside the_AIP.

(Note that there is a difference between a pointer to a thing and the thing itself. Hence why they use different access operators.)

So, from the Civ code, this line:

sint32 my_defense = army_agent->GetBestDefense(ai);

means they're creating a 32 bit integer named my_defense and assigning it a value equivalent to a property of army_agent. I think. I'm more familiar with C# and this is a weird implementation to me. There seems to be a function involved, which is throwing me off. Though I suppose they maybe could have used a function as a property of army_agent, for some reason.

Specifically, they declare what appears to be a signed 32-bit integer variable called my_defense. We have pointers to two objects, army_agent and ai, being used here. They're calling the GetBestDefense() function that belongs to the army_agent object, and passing the pointer to ai as a parameter to said function. The return value of the function -- that is usually the result of whatever it's computing -- is then stored in my_defense. The function may also make changes to the data inside the both objects, it's impossible to know without the code of the function.

I hope this is not too much! :sweat: Please do not hesitate to message me if you need help with code.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
That's helps a lot I think and I'll try not to butcher it as I continue. :) Here's the full text:
#include "c3.h"
#include "IC3UnitDB.h"
#include "DynArr.h"
#include "CivArchive.h"
#include "IMapPointData.h"
#include "IC3GameState.h"
#include "IC3World.h"
#include "AiMain.h"
#include "AiMap.h"
#include "airndcnt.h"
#include "dr_debug.h"
#include "matrix.h"
#include "Grassfire.h"
#include "Strategic_Map.h"
#include "FzOut.h"
#include "BSet.h"
#include "ArmyAgent.h"
#include "CityAgent.h"
#include "ForeignAgent.h"
#include "Foreigner.h"
#include "ScienceAgent.h"
#include "GoalExpel.h"
#include "AILOG.h"
BOOL GoalExpel::pretestConstruct(
AiMain *ai,
ForeignAgent * agent
)
{
sint32 unit_type = agent->GetTopUnitType();
if (!ai->m_foreigner[agent->GetPlayerIndex()])
return FALSE;
if (ai->m_foreigner[agent->GetPlayerIndex()]->IsAtColdWar())
{
BOOL can_be_expelled = ai->m_unitDB->IsCanBeExpelled(unit_type);
BOOL can_be_sued = ai->m_unitDB->IsCanBeSued(unit_type);
return (can_be_expelled || can_be_sued);
}
else
return FALSE;
}
GoalExpel::GoalExpel()
{
the_class = MILITARY_GOAL_CLASS;
m_foreign_player = -1;
what_goal = GOAL_TYPE_EXPEL;
the_class = MILITARY_GOAL_CLASS;
}
GoalExpel::GoalExpel
(
AiMain *init_ai,
ForeignAgent *the_target,
MapPointData pos
)
: ArmyGoal(init_ai, 1000000, pos)
{
the_class = MILITARY_GOAL_CLASS;
raw_priority = BAD_UTILITY;
what_goal = GOAL_TYPE_EXPEL;
the_class = MILITARY_GOAL_CLASS;
removal_time = REMOVE_WHEN_SORTED;
m_target_id = BSetID(the_target->GetID().GetVal());
m_foreign_player = the_target->GetPlayerIndex();
the_target->GetXYPos(*m_XYpos);
m_ai = init_ai;
}
GoalExpel::GoalExpel(AiMain *ai, CivArchive &archive)
{
the_class = MILITARY_GOAL_CLASS;
what_goal = GOAL_TYPE_EXPEL;
the_class = MILITARY_GOAL_CLASS;
m_foreign_player=-1;
raw_priority = BAD_UTILITY;
m_ai = ai;
Serialize(ai, archive);
}
GoalExpel::~GoalExpel()
{
}
void GoalExpel::confused:erialize(AiMain *ai,CivArchive &archive)
{
CHECKSERIALIZE
ArmyGoal::confused:erialize(ai, archive);
uint32 v;
if (archive.IsStoring()) {
archive << m_foreign_player;
archive.PutSINT32(m_target_id.GetVal());
} else {
archive >> m_foreign_player;
v = archive.GetSINT32();
m_target_id = BSetID(v);
}
}
BOOL GoalExpel::Validate(AiMain *ai)
{
return ArmyGoal::Validate(ai);
}
void GoalExpel::HookUp(AiMain *ai)
{
Assert(0 <= m_foreign_player);
Assert(m_foreign_player < k_MAX_PLAYERS);
Assert(ai->m_foreigner[m_foreign_player]);
BSet<ForeignAgent> *vc = ai->m_foreigner[m_foreign_player]->GetVisibleUnits();
BSetID h_id;
ForeignAgent *him=NULL;
for (him = vc->First(h_id); vc->Last(); him = vc->Next(h_id)) {
if (him->GetID() == m_target_id) {
return;
}
}
{
BOOL COULD_NOT_FIND_EXPEL_GOAL_TARGET=0;
Assert(COULD_NOT_FIND_EXPEL_GOAL_TARGET);
}
}
GOAL_TYPE GoalExpel::GetType () const
{
return what_goal;
}
void GoalExpel::Display_Goal_Type(AiMain *ai)
{
#ifdef DBGAILOG
if (ai->AI_VERBOSITY >= LOG_MEDIUM)
AILOG(( wstr, "GOAL_TYPE_EXPEL"));
#endif DBGAILOG
}
void GoalExpel::Compute_Needed_Troop_Flow(AiMain *ai)
{
return;
}
double GoalExpel::Compute_Matching_Value
(
AiMain *ai,
squad_ptr the_squad
)
{
double utility;
double summed_utility = 0.0;
double avg_utility;
int unit_count;
ArmyAgent *tmpAgent;
BOOL same_squad_goal_combo;
unit_count = the_squad->GetUnitCount();
if (unit_count <= 0)
return BAD_UTILITY;
sint32 found_agents = 0;
for (int i = 0; i< unit_count; i++)
{
tmpAgent = (ArmyAgent *) the_squad->GetUnitByNumber(i);
utility = Action_Bid(ai, tmpAgent);
if (utility > BAD_UTILITY + 0.5)
{
summed_utility += utility;
found_agents++;
}
}
if (found_agents > 0)
{
avg_utility = summed_utility / found_agents;
}
else
avg_utility = BAD_UTILITY;
same_squad_goal_combo = (the_squad->last_goal_type is what_goal);
if (same_squad_goal_combo)
{
avg_utility += ai->m_planner->the_AIP.persistence_modifier;
}
return (avg_utility);
}
int GoalExpel::Is_Unit_Appropriate
(
AiMain *ai,
Agent * unit_in_question
)
{
AGENT_STATE agent_state;
AGENT_TYPE agent_type;
ArmyAgent * the_army;
CityAgent * the_city;
if (!ArmyGoal::Is_Unit_Appropriate(ai, unit_in_question))
return FALSE;
agent_type = unit_in_question->GetType();
switch (agent_type)
{
case AGENT_TYPE_ARMY:
{
the_army = (ArmyAgent *) unit_in_question;
if (!PretestBid(ai, the_army))
return false;
agent_state = the_army->GetState();
switch (agent_state)
{
case AGENT_STATE_MARKED_SETTLE:
case AGENT_STATE_MARKED_DEAD:
case AGENT_STATE_MARKED_GARRISON:
case AGENT_STATE_AT_GOAL:
return false;
default:
return true;
}
break;
}
break;
case AGENT_TYPE_CITY:
{
the_city = (CityAgent *) unit_in_question;
if (the_city->GetQueueLen() < 1)
return true;
else
return false;
break;
}
default:
return false;
}
}
BOOL GoalExpel::WithinRange
(
AiMain *ai,
Agent *agent,
const SUB_TASK_TYPE & sub_task
)
{
ArmyAgent *army_agent = (ArmyAgent *) agent;
switch (agent->GetType())
{
case AGENT_TYPE_ARMY:
BOOL close_enough;
if (sub_task == SUB_TASK_CARGO_TO_BOARD ||
sub_task == SUB_TASK_TRANSPORT_TO_BOARD)
return army_agent->AtEndOfPath(ai);
close_enough = (army_agent->GetRemainingPathPoints(ai) <= 1);
return close_enough;
break;
case AGENT_TYPE_CITY:
break;
case AGENT_TYPE_UNKNOWN:
default:
INSANE(DISTANCE_TO_SQUAD_GOAL_UNKNOWN);
break;
}
return false;
}
void GoalExpel::ArrivedAtTask(AiMain *ai, ArmyAgent *the_army,
ArmyAgent *the_transport, SUB_TASK_TYPE sub_task)
{
BOOL succeeded;
if (SUB_TASK_CARGO_TO_BOARD == sub_task)
{
the_army->TryToBoardTransport(ai, the_transport);
return;
}
if (sub_task == SUB_TASK_GOAL)
{
succeeded = the_army->ActionTryToExpel(ai, *m_pos);
if (the_army->GetState() != AGENT_STATE_MARKED_DEAD)
{
the_army->SetState(AGENT_STATE_LOOKING_FOR_WORK);
}
Set_Totally_Complete(succeeded);
}
}
BOOL GoalExpel::pretestBid(AiMain *ai, ArmyAgent *actor)
{
if (actor->PretestBid(ai, GetType(), *m_pos) <= BAD_UTILITY)
return FALSE;
sint32 unit_type;
BOOL can_doit = FALSE;
ForeignAgent *target = GetTarget(ai);
BOOL can_be_expelled = FALSE;
BOOL can_be_sued = FALSE;
if (target != NULL)
{
unit_type = target->GetTopUnitType();
can_be_expelled = ai->m_unitDB->IsCanBeExpelled(unit_type);
can_be_sued = ai->m_unitDB->IsCanBeSued(unit_type);
}
else
{
BOOL NO_TARGET_FOUND_FOR_EXPEL_SUE_GOAL = FALSE;
Assert(NO_TARGET_FOUND_FOR_EXPEL_SUE_GOAL);
return FALSE;
}
Assert(can_be_expelled || can_be_sued);
if (!can_be_expelled && !can_be_sued)
return FALSE;
for (int i=0; i < actor->GetUnitCount(); i++)
{
unit_type = actor->GetUnitTypeByNumber(i);
if (ai->m_unitDB->IsNuclearAttack(unit_type))
return false;
if (ai->m_unitDB->IsSettler(unit_type))
return false;
can_doit = (can_doit ||
(can_be_expelled &&
ai->m_unitDB->GetAttack(unit_type) > 0) ||
(can_be_sued &&
ai->m_unitDB->CanSue(unit_type)));
}
if (actor->GotCargo()) {
return false;
}
return can_doit;
}
double GoalExpel::Action_Bid(AiMain *ai, Agent *agent)
{
ArmyAgent *army_agent = (ArmyAgent *)agent;
CityAgent *city_agent = (CityAgent *)agent;
if (agent->GetType() == AGENT_TYPE_CITY)
return city_agent->FindBestBuildUtility(ai,this,army_agent);
if (!PretestBid(ai, army_agent))
return BAD_UTILITY;
if (army_agent->GetState() == AGENT_STATE_UNBUILT)
{
if (army_agent->GetHomeCityAgent()->GetQueueLen() > 0)
return BAD_UTILITY;
}
double move_point_cost;
sint32 rounds;
double build_time;
if (army_agent->BidDistance(ai, FALSE, *m_pos, move_point_cost, rounds, build_time) < 0.0) {
return BAD_UTILITY;
}
if (ai->m_my_player_id == PLAYER_INDEX_VANDALS &&
rounds > ai->m_planner->the_AIP.wander_rounds_from_target)
return BAD_UTILITY;
double high_movement_weight = .75;
double low_defense_weight = .25;
double bonuses = 0.0;
sint32 best_defense;
sint32 my_defense = army_agent->GetBestDefense(ai);
if (ai->m_science_agent->GetBestLandDefense(best_defense))
bonuses += (1.0 - (my_defense / best_defense))
* ai->m_planner->the_AIP.max_misc_bid_bonus
* low_defense_weight;
else
;
sint32 best_move;
double my_move = army_agent->GetBestMove(ai);
if (ai->m_science_agent->GetBestLandMove(best_move))
bonuses += (my_move / best_move)
* ai->m_planner->the_AIP.max_misc_bid_bonus
* high_movement_weight;
else
;
double time_term;
MapPointData dest_pos;
army_agent->GetPos(ai, dest_pos);
double tile_count = ai->m_map->WrappedDistance(*m_pos, dest_pos);
time_term = ( rounds * rounds
* ai->m_planner->the_AIP.distance_from_unit_priority_modifier )
- tile_count;
return bonuses + time_term + Compute_Raw_Priority(ai);
}
void GoalExpel::confused:et_Invalid()
{
invalid_goal = true;
ForeignAgent *target = GetTarget(m_ai);
if (target != NULL)
{
target->RemoveExpelGoal(m_ai, this->GetID());
target = NULL;
}
Goal::confused:et_Invalid();
}
double GoalExpel::Compute_Raw_Priority(AiMain *ai)
{
#ifdef _DEBUG
MapPointData *size;
size = ai->m_map->GetSize();
Assert(m_pos);
Assert(m_XYpos);
Assert(0 <= m_XYpos->x);
Assert(m_XYpos->x < size->x*2);
Assert(0 <= m_XYpos->y);
Assert(m_XYpos->y < size->y);
Assert(0 <= m_XYpos->z);
Assert(m_XYpos->z < size->z);
Assert(0 <= m_pos->x);
Assert(m_pos->x < size->x);
Assert(0 <= m_pos->y);
Assert(m_pos->y < size->y);
Assert(0 <= m_pos->z);
Assert(m_pos->z < size->z);
#endif
raw_priority = ai->m_planner->the_AIP.expel_priority;
raw_priority += ArmyGoal::Compute_Raw_Priority(ai,
-1,
-1,
1,
1,
-1,
1,
1);
return raw_priority;
}
Goal_Result GoalExpel::BuildTaskSolution(AiMain *ai, CityAgent *the_city,
Plan *the_plan)
{
ArmyAgent *unbuilt_army;
the_city->FindBestBuildUtility(ai, this, unbuilt_army);
double utility = the_plan->GetMatchingValue();
if (unbuilt_army) {
sint32 unit_idx = unbuilt_army->GetUnbuiltType();
if (the_city->PretestContructUnit(ai, unit_idx))
{
the_city->EnqueueArmy(ai, unit_idx, utility);
the_city->current_goal_type = what_goal;
return GOAL_IN_PROGRESS;
}
return GOAL_INAPPROPRIATE;
} else {
return GOAL_INAPPROPRIATE;
}
}
ForeignAgent *GoalExpel::GetTarget(AiMain *ai)
{
if (m_target_id.GetVal()) {
if (!ai->m_foreigner) return NULL;
if (!ai->m_foreigner[m_foreign_player]) return NULL;
BSet<ForeignAgent> *vua = ai->m_foreigner[m_foreign_player]->GetVisibleUnits();
BSetID h_id;
ForeignAgent *his_agent=NULL;
for (his_agent = vua->First(h_id); vua->Last(); his_agent = vua->Next(h_id)) {
if (his_agent->GetID().GetVal() == m_target_id.GetVal()) {
return his_agent;
}
}
}
return NULL;
}

I'm guessing this is the Expel AIP or what the AI uses to expel/kill those enemies in it's lands. Army agent I'm guessing your troops like infantry, artillery, paratroopers, etc..

I'm thinking the max_misc_bid_bonus is a value the AI uses to determine if to attack. Like let's say the value is 500 then whatever sum it comes up with using the other parameters if that is below the bid bonus is won't attack and if it's over it will attack or something like that? Hope I'm not too illiterate with that?

I've found similar files for Goal Sally and Goal Retreat as well. Not sure if Sally is attack or rally the troops? If I can understand even on a basic level how it's using max_misc_bid_bonus and the threat modifiers and bonuses it'll give me insight how the AI plays and what is uses those for.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Still been doing testing and the AI is so frustrating. Some games are really good and some not so much. I think the maps themselves contribute to how the AI plays as well. I use the same 6 player stock map for all my testing and depending on the start location at AI will do good, but in another location they don't perform well.

8472 almost always goes into it's defensive AIP and build list within a minute or two of game start and I can't figure out why? Then after it builds up it's forces (that may not be the trigger) it goes into its aggressive AIP like the other races. I'm not sure what is triggering it with that race? Some races sit their scout in the base for the first 15 minutes of the game and some search the entire map right off the bat. Anybody know Dr. Ian Davis personally? :lol2:
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
It might not apply, but in Command and Conquer: Generals: Zero Hour expansion's maps, faction's general attack strategy could be altered (where to attack, amount of units/force composition). While it wasn't much, a combination of the map and faction might be the issue. Try opening the map in the game's map editor to find out (assuming that is viewable in the map editor). If it, it should be easy to spot.


Again, that might not apply, but a place to start.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
If I'm understanding you correctly in C&C some of the game play is actually set up inside the map? Is that correct? In A2 the map is just the map at least in the Instant Action game mode. So all the AI settings and what each race builds are kept in files which is what I'm altering and testing.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
I wanted to report a very promising finding that I feel may be the key to a better AI. I've had two really good games with one ending in three AI's rushing me at once and killing me. In the RTS_cfg file in the root directory of A2 there is this line "AI-Grid-Size=400" I knew it was tied to the strategic parameters, but didn't get around to changing it yet.

The scheduling program as posted in the AI file of Star Trek Armada:
Parameter Interactions

In one of the rare occasions of thorough commenting, Dr. Ian (who developed Armada II's AI) provided an in depth explanation of how the parameters interact and are used by the AI scheduler to assign Craft to goals.

The steps in a scheduling phase are first described followed by details of how the computations at selected steps are made.

Scheduler 12 step program:
  1. A strategic map is created by dividing the map into grid squares
  2. Each grid square has one of each goal type associated with it.
  3. Compute the raw priority of each goal at each grid square.
  4. Compute the match utility between every squad and goal.
  5. Sort matches highest to lowest.
  6. Examine highest match that contains a squad with uncommitted units.
  7. Commit units from squad in match to associated goal.
  8. If the goal has enough unit strength committed to it, command those committed units to move to the grid cell of the goal.
  9. When all units on the team have been committed to goals, go to step 11.
  10. Otherwise examine next match and go to step 7.
  11. Rollback committed units from goals that still do not have enough troop strength and mark those units invalid for the goal.
  12. Go to step 6.
Step 1: The Strategic Map
Parameters are specified in the strategic_AI_config.txt file.
Parameters that are important to the strategic AI are:
// number of map units per grid cell (i.e. 400x400 units per AI strategic grid cell)
#define goal_map_resolution 400
// Fraction of bleedover during threat relax
double relaxation_coefficient = 0.8;
// Number of threat relax cycles. This becomes how far away a threat is felt.
int relaxation_cycles = 2;

*****CK-5/2/18-Full stragetic_AI_cfg.txt file (For Reference)*****
The strategic_ai_cfg.txt file in the AI folder contains all the strategic parameters as follows:
// How many tiles per threat mapgrid?
#define threat_map_resolution 800

// How many tiles per death mapgrid?
#define death_map_resolution 800

// How many tiles per our empire mapgrid?
#define empire_map_resolution 800

// How many tiles per enemy empire mapgrid?
#define enemy_empire_map_resolution 800

// How many tiles per exploration cell?
#define exploration_map_resolution 800

// How many tiles per goal cell?
#define goal_map_resolution 800

// Iteration for relaxing grid borders
// NOTE: DO NOT CHANGE
int relaxation_cycles = 1;

// Relaxation bleedover
// NOTE: DO NOT CHANGE
double relaxation_coefficient = 0.5;
**************************************************************
Step 2: goals are assigned to grid squares
Escort goals are the exception to this rule. One escort goal is created for every unit on your team that is of the Freighter Class. The four goals that are created for each map grid cell are the: Attack Base Goal, Attack Goal, Defend Goal and Explore Goal.
Step 3: compute the raw priority of each goal
The raw priority is computed for each goal type in this way:
Attack Goal:
If the grid cell has enemy stations or contains no enemy threat, the goal is invalid. Otherwise, the value is the SUM of these factors:
  1. Distance To Our Empire
    • * AIP->distance_from_home_priority_modifier
  2. Distance To Enemy Empire
    • * AIP->distance_from_enemy_priority_modifier
  3. Threat in Map Cell
    • * AIP->attack_troops_priority
  4. AIP->perimeter_priority (if a Perimeter Map Cell)
Defend Goal:
If the grid cell contains no friendly stations, the goal is invalid. Otherwise, the value is the SUM of these factors:
  1. Distance To Our Empire
    • * AIP->distance_from_home_priority_modifier
  2. Distance To Enemy Empire
    • * AIP->distance_from_enemy_priority_modifier
  3. Threat in Map Cell
    • * AIP->attack_troops_priority
  4. AIP->perimeter_priority (if a Perimeter Map Cell)
  5. Number of Our Stations in Cell
    • * AIP->defend_buildings_priority
Attack Base Goal:
If the grid cell contains no enemy stations, the goal is invalid. Otherwise, the value is the SUM of these factors:
  1. Distance To Our Empire
    • * AIP->distance_from_home_priority_modifier
  2. Distance To Enemy Empire
    • * AIP->distance_from_enemy_priority_modifier
  3. Threat in Map Cell
    • * AIP->attack_troops_priority
  4. AIP->perimeter_priority (if a Perimeter Map Cell)
  5. Number of Enemy Stations in Cell
    • * AIP->attack_enemy_base_priority
Explore Goal:
If the grid cell as already been explored, the goal is invalid. Otherwise, the value is the SUM of these factors:
  1. Distance To Our Empire
    • * AIP->distance_from_home_priority_modifier
  2. Distance To Enemy Empire
    • * AIP->distance_from_enemy_priority_modifier
  3. AIP->perimeter_priority (if a Perimeter Map Cell)
  4. AIP->exploration_priority
Escort Goal:
If the craft this escort goal is attached to is destroyed, the goal is invalid. Otherwise, the value is the SUM of these factors:
  1. Distance To Our Empire
    • * AIP->distance_from_home_priority_modifier
  2. Distance To Enemy Empire
    • * AIP->distance_from_enemy_priority_modifier
  3. AIP->perimeter_priority (if a Perimeter Map Cell)
  4. AIP->escort_priority
Step 4: compute the match utility between a squad and goal
The squad match value is computed from the average matching value for the units in a squad. The match utility of a unit equals the SUM of these factors:
  1. Distance from unit to goal
    • * AIP->distance_from_goal_match_modifier
  2. Raw Priority of goal.
Step 7: commit units from squad in match to associated goal
Units in a squad are committed based on their match utility; i.e. closest units are committed before further ones.

Step 8: check if the goal has enough unit strength committed to it
The Attack Goal, Defend Goal and Attack Base Goals, currently only require that the total shield strength of enemy units at the target is less than the total shields of the committed units.
Note: Force matching values are not currently used.

The Escort Goal is satisfied when units with shields that exceed 1000 * the Build Time of the ship have been committed. This obviously needs a more logical measure.

The Explore Goal is satisfied when at least one ship has been committed to it.

The map gets divided into grid squares for the strategic map. The value in A2 was set at 400 which is what was used in the first Armada game and all the "_map_resulution" values in the strategic_AI_cfg.txt file were 400 in the first Armada, but changed to 800 in A2.

I feel that changing the AI_grid_size to 800 or even more (needs testing) helps the AI better plan strategically because it's taking more area of the map into account. It can't plan properly if it's only taking 400 or a 4x4 grid into account. If it accounts for more of the map strategically it then gets a better picture of what's around a starbase, etc. A starbase itself takes up a 2x2 or 3x3 grid in some cases.

So far I'm seeing (repeatable behavior) like enemy AI that doesn't go into it's defensive AIP that often any more if it looses 1 or 2 stations. It just rebuilds and moves on. It truly has to be beaten back into it's starting area (most if not all stations destroyed) to go into it's defensive AIP. I'm seeing enemy ships seemingly avoid danger better. There was a group of about 12 Galaxies and a couple Akiras sitting in an area and a cube flew directly to them, but instead turned around. I saw this behavior in several other cases as well.

Don't misunderstand, I'm not saying the AI has been figured out as I still need a lot more play testing, but I'm seeing repeatable behavior so far that appears to me more logical and not just a dumb AI. In some instances a couple ships steer clear of the starbase and attack nearby research stations and yards, but sometimes the AI still flies ships right to the base and sits there getting shot to pieces so some things still need figured out.

So in recap I think the AI_grid_size in the RTS_cfg file needs increased in value to give the AI a better strategic view of the map. If you try it out let us know your findings. It might even make the original Armada game play better by increasing the value in its file.
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
If I'm understanding you correctly in C&C some of the game play is actually set up inside the map? Is that correct? In A2 the map is just the map at least in the Instant Action game mode. So all the AI settings and what each race builds are kept in files which is what I'm altering and testing.

Very, very crudely. Without a map script, AI will never attack you from that position. Say you have three ways to get to your base, left center and right. (It's an RTS so same rough ideas can transfer from A2 to C&C). Forget to add a map script to one of those three ways, say the left, then the AI will never launch an attack from the left. While aircraft are excluded, the AI can still attack you if you approach from the left (so it can still defend itself).

*(Aircraft (and ground units too) pick their targets based on priority. I swore it was based on literal numbers, but I was told that years ago. I can't find it (it may have been years, but I remember the INI files very well) I do for a fact that scripts tell the AI where to attack.)*

I brought up C&C as one way some modders/map makers make maps harder is by adding more possibilities of attack, you get overwhelmed/stretch yourself too far. However, that won't work for obvious reasons.
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
So in recap I think the AI_grid_size in the RTS_cfg file needs increased in value to give the AI a better strategic view of the map. If you try it out let us know your findings. It might even make the original Armada game play better by increasing the value in its file.

I found the file/line. I'm defiantly going to be tinkering around with it.

I'm also thinking that messing around with these lines
Code:
#define EASY_AI "AI_Easy_Script.dsl"
#define MEDIUM_AI "AI_Medium_Script.dsl"
#define HARD_AI "AI_Hard_Script.dsl"
should spice things up. I just read through everything you have here and I say you didn't touch them yet.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
I'm also thinking that messing around with these lines
Code:
#define EASY_AI "AI_Easy_Script.dsl"
#define MEDIUM_AI "AI_Medium_Script.dsl"
#define HARD_AI "AI_Hard_Script.dsl"
should spice things up. I just read through everything you have here and I say you didn't touch them yet.

In regards to that section I don't see any .dsl files called AI_Easy, Medium and Hard_Script that could possibly be edited. I think they are left over code from before the first Armada game. In Star Trek Armada there are .dsl files for Borg, Federation, Klingon, and Romulan_Medium_Script, but nothing there for Easy, Medium or Hard unless those script files is buried somewhere we can't see them?

The key files that need edits/testing are the strategic_AI_cfg in the AI/AIPs folder, and aggressive, defensive, exploration, and very_aggressive files or hard_aggressive, hard_defensive and hard_exploration if you play with hard settings. They all work in conjunction to tell the AI how to play on a tactical and strategic level.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Had another good game last nite that culminated in the Borg and the Feds ganging up and killing me. I do all my testing on the stock map Wide Open with 5 AI and me. I play Romulan and don't let anyone build Tachyon Detection so I can place cloaked scouts all around to see what the AI is doing and using the debugger to watch behind the scenes.

Still seeing some promising game play, but still some dumb stuff. Having changed the AI_grid_size from 400 to 800 for the strategic map has made the AI not go into it's exploration AIP hardly at all now. It does occasionally, but not totally sure what triggers it?

8472 goes in/out of its defensive AIP a lot and I think it's because it's mother has is_starbase = 0. So it's not being calculated as a starbase which may mess all sorts of things up.

Some races send their scout out right at the beginning of the game and others don't. The scout is supposed to be used for scouting in Instant Action according to the way it's programmed, but some use them in attack fleets over and over. As we know the scout is the first ship attacked so dies quickly and pointlessly.

I saw twice where a scout flew at a starbase and then turned around and another where one flew towards a group of Galaxies then turned around. Other times scouts fly leisurely at a starbase only to be killed. It's sense of self-preservation is skewed.

Some of the code for danger and threat are:
double danger_diminishment = 1;
int avoid_danger_priority_modifier = 500;
double threatModifier = 0;
int max_danger_raw_bonus = 0;
int max_threat_raw_bonus = 0;
int threat_proximity_modifier = 0;

I'm still trying to understand what they mean and how they are used. If danger_diminishment reduces danger why would you want to?

The threatModifier line only appears in the hard_aggressive, hard_defensive, hard_expolration, and very_aggressive AIPs whereas the max_danger_raw_bonus, max_threat_raw_bonus and threat_proximity_modifier codes only appear on the easy AIP's (the ones without the 'hard' in front of them)

I have to believe the original programmers had a reason, but still trying to figure it out. I've had low values and high values for avoid_danger_priority_modifier, but that seems to make no difference so not sure it's even an active command?
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
Have you tried removing the weapons on the scout? Having weapons might make the AI think their combat ships instead of non-combats (due to extremely low health and more support function).



I haven't had a chance to try out your AI changes, but on Hard with complete vision the AI (Borg and Klingon I think) but up and overrun me with ships and rarely if ever do they send in scouts. I'll have to double check it.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
I hadn't thought of removing the weapons on the scout. They come in handy sometimes for combat so not sure about that though?

The craft.odf has this: can_explore = 1 so all craft can explore whether it's a scout or not and scoutBase.odf has these: combat = 1, alert = 1, can_sandd = 1

Those mean it can perform combat, change its alert status and perform search and destroy actions. Those are probably what you'd want to change instead of removing the weapons perhaps?

I'm certainly no great player, I just like modding the game and the AI can beat you without any changes whatsoever. I just want to try and make it better. I'm still learning what 'better' is too. :) In my testing I only build a few ships to ward off smaller attacks. But in 2 of 3 games so far the AI has simply crushed me with swarms of battleships. I usually hide a few constructors away from my base to rebuild in such cases, but I usually quit before one AI has truly beat everyone.

I'm wondering now if 800 is even too small for the AI_grid_size for the strategic map? I wish it scaled to the size of each map, but there's no way to do that. If the AI used the entire map as 1 strategic grid maybe it would play better still? Who knows? I really need to try and determine if the AI who turns a ship around to avoid destruction is truly showing self preservation or just happened to turn around for some other reason. If the AI could really avoid danger then that would be a huge step.
 

MrVulcan

Crewman 2nd Class
Joined
17 Aug 2011
Messages
142
I don't have access to game files at the moment, but if memory serves, there is a parameter for recompute interval for AI maps. It is possible that too long of a wait between recompute is causing the odd behaviour. For example, a group of enemy ships arrives in a strategic map square, but AI didn't recompute the threat map. But another time, the recompute happened earlier and threat map is updated.

Also there is a parameter for decay rate of old threats. I think it would be related to "growth" rate of new threats. If you want the AI to respond quicker, tweaking the decay rate might help too
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
I don't have access to game files at the moment, but if memory serves, there is a parameter for recompute interval for AI maps. It is possible that too long of a wait between recompute is causing the odd behaviour. For example, a group of enemy ships arrives in a strategic map square, but AI didn't recompute the threat map. But another time, the recompute happened earlier and threat map is updated.

Also there is a parameter for decay rate of old threats. I think it would be related to "growth" rate of new threats. If you want the AI to respond quicker, tweaking the decay rate might help too
I have been messing with those as well to try and understand how they work. Not at home, but I think the first one is recompute_strategy_period. From the scheduler notes in the first armada it states the AI adds threats to its threat map every 400 cycles and it processes 60 cycles per second so it would seem it rethinks its strategy every 6.6 seconds.
The danger_diminishment line I think is part of it, but also the threat_relaxation line too. They are all intertwined somehow
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
Just spitballing, but I think danger_diminishment I think is how quickly threat is lost (the decay rate). While threat_relaxation is about how quickly the AI will stand down/redeploy after the threat is gone or eliminated.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
You're right about the danger_diminishment line. Here's the relevant lines from the default.aip file with some added notes by me:

// I. Threat Map

// This sets how many neighboring strategic grids to spill any threat into
// Strategic grid size set by AI_grid_size = xx in RTS_cfg file (Stock is 400)
// Threat value set by '#define threat_map_resolution 900' in strategic_ai_cfg
// file. 900 being a 9x9 grid size or 900 units
int relaxation_cycles = 1;

// This sets how much of threat to spill over into next strategic grid.
// 0 is none, .5 is 50% and 1.0 is 100%
double relaxation_coefficient = 0.5;

// How much to reduce danger recorded in grid cell each cycle
// I think 1 is 100% and .15 is 15%
double danger_diminishment = 0.15;

the relaxation-cycles and relaxation-coefficient I understand and can prove what they do in the debugger, but it's the diminishment that can't be seen. It says right on the line it reduces the danger recorded each cycle, but I question why? Why reduce the danger at all? A starbase or a ship are always dangerous so I wonder why that's even there and what purpose it serves?
 

CABAL

<< ■ II ▶ >>
Staff member
Administrator
Star Navigator
Rogue AI technocrat
Joined
15 Aug 2009
Messages
3,511
Age
33
Why reduce the danger at all? A starbase or a ship are always dangerous so I wonder why that's even there and what purpose it serves?
Something I noticed in Armada 1 is that if the AI loses enough ships in an area, such as the entrance to your base, they'll stop moving ships there entirely. The AI could be made to never leave its base at all if you locked down the resource points for long enough. My guess is that this bit is so that the AI will eventually do something in such a scenario.
 

Admiral*Alex

Petty Officer 2nd Class
Joined
4 Apr 2018
Messages
212
Age
26
Something I noticed in Armada 1 is that if the AI loses enough ships in an area, such as the entrance to your base, they'll stop moving ships there entirely. The AI could be made to never leave its base at all if you locked down the resource points for long enough. My guess is that this bit is so that the AI will eventually do something in such a scenario.


Possibility (don't have A1) and/or if someone stations a large force in front of my base and I know I don't have the firepower to destroy it, I'd avoid it too till I either admitted defeat or got enough forces to counter it.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Something I noticed in Armada 1 is that if the AI loses enough ships in an area, such as the entrance to your base, they'll stop moving ships there entirely. The AI could be made to never leave its base at all if you locked down the resource points for long enough. My guess is that this bit is so that the AI will eventually do something in such a scenario.

That is interesting as the AI in A2 seems to be the opposite and always put it's ships right in range of the starbase, but not seem to care that they get shot to pieces. Fleet after fleet.

'avoid_danger_priority' is a line in each of the AIP's that I feel may not be activated or something however, I've only had values no higher than 2000 in there. I wonder if the value is changed to 20000 or 50000 or maybe 99999 if the AI would then show some sense of self preservation?

Anyone, even the AI is going to build their shipyards and research stations within the weapons arc of the starbase so it's going to be hard for anyone to skirt around those defenses to kill a station, but I've started seeing at least a little intelligence with the strategic grid changes I made in that the AI parks its fleet just outside the starbase range and then kill a station here/there that is just out of the weapons range of the starbase so that's promising.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
I wanted to post a sample AIP file with notes for reference for anyone interested. Some notes are original and self explanatory and on some I've added my own.
// Load up the basic structures...
#include "aipdef.h"

/////////////////////////////////////////////////////////////////////
// I. Threat Map

// This sets how many neighboring strategic grids to spill any threat into
// Strategic grid size set by AI_grid_size = xx in RTS_cfg file (Stock is 400)
// Threat value set by '#define threat_map_resolution 900' in strategic_ai_cfg
// file. 900 being a 9x9 grid size or 900 units. So a threat projection of 900
// plus 1 neighboring strategic grid of 400 = 1300 or a 13 x 13 grid of total
// threat projection. *Every ship/station with "attackpower=XX" in its odf projects
// a threat 900 units out (or whatever value is set in threat_map_resolution*
int relaxation_cycles = 1;

// This sets how much of any threat to spill over into next strategic grid.
// 0 is none, .5 is 50% and 1.0 is 100%
double relaxation_coefficient = 0.5;

// How much to reduce danger recorded in grid cell each cycle. Why reduce the
// danger? Not sure of the purpose of this.
double danger_diminishment = 0.15;

/////////////////////////////////////////////////////////////////////
// II. Strategy Upkeep

// Game engine supposedly processes 60 cycles per second and it takes 400 cycles
// before AI adds info to it's strategic map. Do we recompute the strategy every
// 200 cycles then execute it at every 400 cycles or do we wait 200 cycles after
// the initial 400 to recompute it?
int recompute_strategy_period = 200;

/////////////////////////////////////////////////////////////////////
// III. Evaluated/execute goal counts

// Used to specify how many of each goal type to evaluate and how many to execute. Small
// counts increase performance, but decrease intelligence.
// NOTE: The MAX_EXEC numbers have positive values that should not exceed 1000;
// NOTE: You can 'turn off' goals by specifying a MAX_EXEC count of 0 or limit the goals
// executed by specifying a smaller number.
int MAX_EVAL_ATTACK_BASE = 1000;
int MAX_EVAL_ATTACK = 1000;
int MAX_EVAL_DEFEND = 1000;
int MAX_EVAL_ESCORT = 1000;
int MAX_EVAL_EXPLORE = 1000;
int MAX_EVAL_RESOURCE = 1000;

int MAX_EXEC_ATTACK_BASE = 1000;
int MAX_EXEC_ATTACK = 1000;
int MAX_EXEC_DEFEND = 1000;
int MAX_EXEC_ESCORT = 0;
int MAX_EXEC_EXPLORE = 2;
int MAX_EXEC_RESOURCE = 1000;

/////////////////////////////////////////////////////////////////////
// IV. Raw Priority parameters

// NOTE: Positive for emphasis away from home, negative for emphasis near home
int distance_from_home_priority_modifier = 2;

// NOTE: Positive for emphasis away from enemy, negative for emphasis near enemy
int distance_from_enemy_priority_modifier = -2;

// NOTE: Positive for emphasis in region between home and enemy
int perimeter_priority = 500;

// The notes state this is not computed in Armada. Needs more testing with much
// higher values possibly?
int avoid_danger_priority_modifier = 500;

// This priority is multiplied by each enemy craft in a grid cell for
// ATTACK and DEFEND goals; for ATTACK_BASE goals this number is multiplied
// by -1 * the number of enemy craft.
// NOTE: Increase positive values to make the AI more likely to attack and defend
// places with many enemy ships (and undefended bases).
// NOTE: Decrease negative values to make the AI less likely to attack and defend
// places with many enemy ships (or more likely to attack defended bases)
int attack_troops_priority = 1000;

// Added for each friendly base in a grid cell for DEFEND goals.
// NOTE: Increase this value to make the AI more likely to defend bases, or decrease
// to make the AI less likely to defend bases. (valid values: -99999 to 99999)
int defend_priority = 750;

// Added for each enemy base in a grid cell for ATTACK_BASE goals.
// NOTE: Increase this value to make the AI more likely to attack enemy bases,
// or decrease to make the AI less likely to defend bases.
// (valid values: -99999 to 99999)
int attack_enemy_base_priority = 3000;

// Added for each unit of intrinsic value in a grid cell for ATTACK
// and ATTACK_BASE goals.
// NOTE: Increase this value to make the AI more likely to attack
// valuable targets, or decrease to make the AI less likely to attack
// valuable targets. (valid values: 0 to 99999)
int intrinsic_value_bonus = 500;

// Added to unexplored grid cell for EXPLORE goals.
// NOTE: Increase this value to make the AI more likely to explore unexplored
// grid cells, or decrease to make the AI less likely to explore unexplored
// grid cells. (valid values: -99999 to 99999)
int exploration_priority = 750;

// No original notes.
// Not sure what this does? Some kind of penalty for not reaching an exploration cell?
int explorationFailurePenalty = 50000;

// Added for each escorted ship in a grid cell for ESCORT goals.
// NOTE: Increase this value to make the AI more likely to escort escortable
// ships, or decrease to make the AI less likely to escort escortable ships.
// (valid values: -99999 to 99999)
int escort_priority = 0;

// Added for each moon in a grid cell for RESOURCE goals.
// NOTE: Increase this value to make the AI more likely to defend moons, or
// decrease to make the AI less likely to defend moons.
// (valid values: -99999 to 99999)
int resource_priority = 500;

/////////////////////////////////////////////////////////////////////
// V. Match Priority parameters

// The distance from the craft to the goal is multiplied by this term
// for every legal goal and craft match.
// NOTE: The more negative the term, the more likely craft will be assigned to
// nearby goals before goals that are far away.
double distance_from_goal_match_modifier = -0.01;

// The minimum # of ships used for each type of goal.
int min_escort_force = 1;
int min_defense_force = 2;
int min_exploration_force = 1;
int min_attack_force = 8;
int min_resource_force = 1;
int min_perimeter_force = 2;

// These 4 entries for 'tendency' seem superfluous as the AI only builds what
// you tell it too. Needs testing to see if they'll still build if set to 0
// The hard AIP's don't even have these entries. Only the easy AIP's do!
double resource_dilithium_tendency = 1.0;
double resource_latinum_tendency = 0.0;
double resource_metal_tendency = 1.0;
double resource_biomatter_tendency = 1.0;

// how likely are we to build resource bases far from our main base. ACTUALLY, this
// is how IMPORTANT it is that a base be close to our main base. This gets
// multiplied by the inverse of the distance... (*The higher the number the further
// from home the AI will build mining bases to get resources*)
double resource_distance_multiplier = 10000.0;

// how likely are we to prefer resources with more health
// Since this looks at the actual value of how many units of resource something has,
// we need to scale this down. A planet having 32000 resources vs. a planet with 8000
double resource_health_multiplier = 0.0001;

// How likely are we to build bases we don't already have
// Again, seems superfluous too as the AI builds only what you tell it to.
// Will it still build orbital and mining stations if set to 0? Does this actually
// affect the freighters going to get the resources instead? Like when it runs low on
// latinum and has to research it diverts freighters to gather latinum?
double resource_lack_multiplier = 2.0;

// What is the penalty for building near an enemy resource
// *I think now that this may mean the AI will leave a 1x1 grid or 100 units
// between it and another AI station when it builds near an enemy? Needs testing*
double resource_enemy_penalty = 100.0;

/////////////////////////////////////////////////////////////////////
// VI. NOT USED currently

// The max # of ships used for each goal. *Original notes state not used, but I
// show it is. I have my attack_force at 16 and fleets of 16 ships do get formed if
// it can produce that many*
int max_escort_force = 1;
int max_defense_force = 8;
int max_exploration_force = 1;
int max_attack_force = 20;
int max_resource_force = 2;
int max_perimeter_force = 2;

// How much emphasis to pay to high threat regions.
// From testing any concentration of ships/stations with weapons that pose a threat
// will affect this. *Shown by yellow to red coloring on the debugger map
// depending on amount of threat projected - more ships = more threat*
int attack_region_priority = 1000;

// Original notes state these are currently not computed. I think the min_matching
// values at least are used
double max_matching_force_ratio = 1.5;
double min_matching_force_ratio = 0.9;

// No original notes
// This seems to make the AI group it's forces so they attack together.
// 1.0 is 100% of the time I believe. AI seems to stop sending in small groups
// or individual ships when this is set at 1.0 and sends the fleet together.
// .4 is the stock setting.
double fleetAIRatio = 1.0;

// Global value for scripted p's (Original note)
// May be a scripted value assigned to each goal by the designers? Does a higher
// value guarantee it'll attack something more? From Dr. Ian Davis' Designer's
// Diary: "On top of that is The Expert System for choosing personality for the
// computer. We have a system of rules and scripts for setting up the highest
// level of AI behavior." *Is this more used in the missions or for Instant
// Action games too?*
int scripted_priority = 10;

// RAW BID MODIFIERS
// Not sure what these bonuses/modifiers are for? Why modify or give a bonus
// to the threat? Just let the threat be the threat! Are these next 4
// modifiers/bonuses to add weight to more dangerous/threatening ships so it
// knows where/when to attack/attack better?? Of note, the 'threatModifier' is only
// used in the hard AIP's and the danger_raw_bonus, threat_raw_bonus and
// threat_proximity_modifier are only used in the easy AIP's! Why??
double threatModifier = 0;
int max_danger_raw_bonus = 0;
int max_threat_raw_bonus = 0;
int threat_proximity_modifier = 0;

// Does this give the player a bonus over the AI or the bonus to the AI over
// the player? Is it a bonus per say or more weight (incentive) for the AI
// to attack the player?
int human_target_raw_bonus = 200;

// No original notes. Not sure what this does? Give weight to more important or
// higher priority goals?
int max_misc_bid_bonus = 600;

// No original notes.
// I think this has something to do with when a squad gets assigned to a goal
// this is used to keep the same squad going back to the same goal when possible?
int persistence_modifier = 200;

// No original notes.
// I think this might mean the AI will patrol 1 out of every 6 goals.
// Maybe it's tied with the perimeter priority/force?
int patrol_one_in_n = 6;

// No original notes
// This may tell the AI when to scout randomly vs specifically scouting every
// specified goal? A low value means the AI rarely goes about scouting on its
// own randomly? If set to 1 will the AI always scout randomly? Am not certain
// if the AI has programming to do this randomly??
double scoutRandomlyRatio = 0;

// Bonus threat for enemy held planets ***This is not calcualated per the AI
// debugger*** The value in the debugging menu is always 0 so not implemented?
// int planetThreatBonus = 300000;
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
So, now that I can play A2 again thanks to GOG I am getting back to working with the AI and thought I'd ask if anyone had been doing any work with it in the year and a half I couldn't play? Find anything that really makes the AI play better or more intelligently? I'll start testing and reporting back as I go but welcome any thoughts. Also, welcome anyone willing to drop some AI personality files into their game to test.
 

Terra_Inc

MSFC's Cheshire Cat
Staff member
Site Manager
Necromancer/Troll hunter
Kitten Commander
Joined
16 Dec 2009
Messages
3,137
Age
34
So, now that I can play A2 again thanks to GOG I am getting back to working with the AI and thought I'd ask if anyone had been doing any work with it in the year and a half I couldn't play? Find anything that really makes the AI play better or more intelligently? I'll start testing and reporting back as I go but welcome any thoughts. Also, welcome anyone willing to drop some AI personality files into their game to test.
I'm still actively modding here and there, so if you want me to test some AI mods, I'm sure I can find the time.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Thanks Terra. May take you up on that. Got my files all modded and starting to test however, realize I cannot pull up the debugging menu. I thought you had to have the map editor installed to access it so dropped those files in my directory, but no go. Anyone have ideas why the GOG version won't let me access the debug menu? Normally hit Ctrl-Alt-A I believe.
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Hi all. This may have been asked before so forgive me however, there is refernece to Easy_AI, Medium_AI and Hard_AI with "AI_Easy_Script.dsl" referenced for each in the RTS_CFG file in A2. Does anyone know where these .dsl files may be if they exist? Are they buried in the code somewhere?
 

Rifraf

I know just enough to be a danger to myself
Joined
25 Aug 2013
Messages
1,236
Age
51
Since my question goes along with my AI modifications I figured I'd keep it here. Stock A2 can have 14 buildItems in a ship yard correct? So buildItem 0-13 right for 14 ships total?
 
Top