Next step of AI, builds and collects something.

This commit is contained in:
johns 2001-04-26 23:16:20 +00:00
parent ef0564970b
commit d4b518e16b
6 changed files with 554 additions and 24 deletions

View file

@ -89,8 +89,8 @@ local void AiCheckUnits(void)
for( i=0; i<n; ++i ) {
counter[AiPlayer->UnitTypeBuilded[i].Type->Type]
+=AiPlayer->UnitTypeBuilded[i].Want;
DebugLevel0Fn("Already in build queue: %s %d\n",
AiPlayer->UnitTypeBuilded[i].Type->Ident,
DebugLevel0Fn("Already in build queue: %s %d\n" _C_
AiPlayer->UnitTypeBuilded[i].Type->Ident _C_
AiPlayer->UnitTypeBuilded[i].Want);
}
@ -102,7 +102,8 @@ local void AiCheckUnits(void)
t=AiPlayer->UnitTypeRequests[i].Table[0]->Type;
x=AiPlayer->UnitTypeRequests[i].Count;
if( x>AiPlayer->Player->UnitTypesCount[t]+counter[t] ) {
DebugLevel0Fn("Need %s\n",AiPlayer->UnitTypeRequests[i].Table[0]->Ident);
DebugLevel0Fn("Need %s\n" _C_
AiPlayer->UnitTypeRequests[i].Table[0]->Ident);
// Request it.
AiAddUnitTypeRequest(AiPlayer->UnitTypeRequests[i].Table[0],
x-AiPlayer->Player->UnitTypesCount[t]-counter[t]);
@ -123,6 +124,7 @@ local void AiCheckUnits(void)
global void AiInit(Player* player)
{
PlayerAi* pai;
AiType* ait;
DebugLevel0Fn("%d - %s\n" _C_ player->Player _C_ player->Name);
@ -132,8 +134,16 @@ global void AiInit(Player* player)
exit(0);
}
pai->Player=player;
pai->AiType=AiTypes;
pai->Script=AiTypes->Script;
ait=AiTypes;
//
// Search correct AI type.
//
while( ait->Race && strcmp(ait->Race,player->RaceName) ) {
ait=ait->Next;
DebugCheck( !ait );
}
pai->AiType=ait;
pai->Script=ait->Script;
player->Ai=pai;
}

View file

@ -45,7 +45,7 @@ enum _ai_script_command_ {
AiCmdBuild, /// build building
AiCmdTrain, /// train unit
AiCmdResearch, /// research upgrade
AiCmdForce, /// Set force.
AiCmdForce, /// Set force
};
/**
@ -78,9 +78,9 @@ enum _ai_priority_ {
*/
struct _ai_goal_ {
AiGoal* Next; /// double linked list of all goals
AiGoal* Down; /// dependend goals.
AiGoal* Down; /// dependend goals
AiGoal* Prev; /// double linked list of all goals
int Priority; /// Priority of this goal.
int Priority; /// Priority of this goal
};
// goals stuff
@ -108,15 +108,15 @@ typedef struct _ai_type_ AiType;
** Ai Type structure.
*/
struct _ai_type_ {
AiType* Next; /// Next ai type.
AiType* Next; /// Next ai type
char* Name; /// Name of this ai.
char* Race; /// for this race.
char* Class; /// class of this ai.
char* Name; /// Name of this ai
char* Race; /// for this race
char* Class; /// class of this ai
// nice flags
//unsigned char AllExplored : 1; /// Ai sees unexplored area.
//unsigned char AllVisibile : 1; /// Ai sees invisibile area.
//unsigned char AllExplored : 1; /// Ai sees unexplored area
//unsigned char AllVisibile : 1; /// Ai sees invisibile area
SCM Script; /// Main script
};
@ -157,6 +157,11 @@ typedef struct _player_ai_ {
// resource manager
int Reserve[MaxCosts]; /// Resources to keep in reserve
int Used[MaxCosts]; /// Used resources
int Needed[MaxCosts]; /// Needed resources
int NeededMask; /// Mask for needed resources
/// number of elements in UnitTypeRequests
int RequestsCount;
/// unit-types to build/train requested and priority list
@ -204,6 +209,12 @@ typedef struct _ai_helper_ {
*/
int ResearchCount;
AiUnitTypeTable** Research;
/**
** The index is the costs that should be collected, giving a table of all
** untis/buildings which could collect this resource.
*/
int CollectCount;
AiUnitTypeTable** Collect;
} AiHelper;
/*----------------------------------------------------------------------------

View file

@ -28,7 +28,10 @@
#include "freecraft.h"
#include "unit.h"
#include "map.h"
#include "pathfinder.h"
#include "ai_local.h"
#include "actions.h"
/*----------------------------------------------------------------------------
-- Variables
@ -38,6 +41,462 @@
-- Functions
----------------------------------------------------------------------------*/
/**
** Check if the costs are available for the AI.
**
** Take reserve and already used resources into account.
**
** @param costs Costs for something.
**
** @return A bit field of the missing costs.
*/
local int AiCheckCosts(const int* costs)
{
int i;
int err;
const int* resources;
const int* reserve;
const int* used;
err=0;
resources=AiPlayer->Player->Resources;
reserve=AiPlayer->Reserve;
used=AiPlayer->Used;
for( i=1; i<MaxCosts; ++i ) {
if( resources[i]<costs[i]-reserve[i]-used[i] ) {
err|=1<<i;
}
}
return err;
}
/**
** Check if the costs for an unit-type are available for the AI.
**
** Take reserve and already used resources into account.
**
** @param costs Costs for something.
**
** @return A bit field of the missing costs.
*/
local int AiCheckUnitTypeCosts(const UnitType* type)
{
return AiCheckCosts(type->Stats[AiPlayer->Player->Player].Costs);
}
/**
** Find free building place.
**
** @param worker Worker to build building.
** @param type Type of building.
** @param dx Pointer for X position returned.
** @param dy Pointer for Y position returned.
** @return True if place found, false if no found.
*/
global int AiFindBuildingPlace(const Unit * worker, const UnitType * type,
int *dx, int *dy)
{
int wx, wy, x, y, addx, addy;
int end, state;
wx = worker->X;
wy = worker->Y;
x = wx;
y = wy;
addx = 1;
addy = 1;
state = 0;
end = y + addy - 1;
for (;;) { // test rectangles arround the place
switch (state) {
case 0:
if (y++ == end) {
++state;
end = x + addx++;
}
break;
case 1:
if (x++ == end) {
++state;
end = y - addy++;
}
break;
case 2:
if (y-- == end) {
++state;
end = x - addx++;
}
break;
case 3:
if (x-- == end) {
state = 0;
end = y + addy++;
}
break;
}
// FIXME: this check outside the map could be speeded up.
if (y < 0 || x < 0 || y >= TheMap.Height || x >= TheMap.Width) {
continue;
}
if (CanBuildUnitType(worker, type, x, y)
&& PlaceReachable(worker, x, y, 1)) {
*dx=x;
*dy=y;
return 1;
}
}
return 0;
}
/**
** Check if we can build the building.
**
** @param type Unit that can build the building.
** @param building Building to be build.
** @return True if made, false if can't be made.
*/
local int AiBuildBuilding(const UnitType* type,UnitType* building)
{
Unit* table[UnitMax];
Unit* unit;
int nunits;
int i;
int num;
int x;
int y;
DebugLevel0Fn("%s can made %s\n" _C_ type->Ident _C_ building->Ident);
IfDebug( unit=NoUnitP; );
//
// Remove all workers on the way building something
//
nunits = FindPlayerUnitsByType(AiPlayer->Player,type,table);
for (num = i = 0; i < nunits; i++) {
unit = table[i];
if (unit->Orders[0].Action != UnitActionBuild
&& (unit->OrderCount==1
|| unit->Orders[1].Action != UnitActionBuild) ) {
table[num++] = unit;
}
}
if( !num ) { // No available unit.
return 0;
}
DebugLevel0Fn("Have an unit to build :)\n");
//
// Find place on that could be build.
//
if ( !AiFindBuildingPlace(unit,building,&x,&y) ) {
return 0;
}
DebugLevel0Fn("Have a building place :)\n");
CommandBuildBuilding(unit, x, y, building,FlushCommands);
return 1;
}
/**
** Check if we can make an unit-type.
**
** @param type Unit-type that must be made.
** @return True if made, false if can't be made.
*/
local int AiMakeUnit(UnitType* type)
{
int i;
int n;
const int* unit_count;
AiUnitTypeTable* const* tablep;
const AiUnitTypeTable* table;
//
// Check if we have a place for building or an unit to build.
//
if( type->Building ) {
n=AiHelpers.BuildCount;
tablep=AiHelpers.Build;
} else {
n=AiHelpers.TrainCount;
tablep=AiHelpers.Train;
}
if( type->Type>n ) { // Oops not known.
DebugLevel0Fn("Nothing known about `%s'\n" _C_ type->Ident);
return 0;
}
table=tablep[type->Type];
if( !table ) { // Oops not known.
DebugLevel0Fn("Nothing known about `%s'\n" _C_ type->Ident);
return 0;
}
i=0;
n=table->Count;
unit_count=AiPlayer->Player->UnitTypesCount;
for( i=0; i<n; ++i ) {
//
// The type is available
//
if( unit_count[table->Table[i]->Type] ) {
if( AiBuildBuilding(table->Table[i],type) ) {
return 1;
}
}
}
return 0;
}
/**
** Check what must be builded / trained.
*/
local void AiCheckingWork(void)
{
int i;
int n;
int c;
UnitType* type;
n=AiPlayer->BuildedCount;
for( i=0; i<n; ++i ) {
if( AiPlayer->UnitTypeBuilded[i].Want
>AiPlayer->UnitTypeBuilded[i].Made ) {
type=AiPlayer->UnitTypeBuilded[i].Type;
DebugLevel0Fn("Must build: %s " _C_ type->Ident);
//
// Check if resources available.
//
if( (c=AiCheckUnitTypeCosts(type)) ) {
DebugLevel0("- no resources\n");
AiPlayer->NeededMask=c;
return;
} else {
DebugLevel0("- enough resources\n");
if( AiMakeUnit(type) ) {
++AiPlayer->UnitTypeBuilded[i].Made;
}
}
}
}
}
/*----------------------------------------------------------------------------
-- WORKERS/RESOURCES
----------------------------------------------------------------------------*/
/**
** Assign worker to mine gold.
**
** IDEA: If no way to goldmine, we must dig the way.
** IDEA: If goldmine is on an other island, we must transport the workers.
*/
local void AiMineGold(Unit * unit)
{
Unit *dest;
DebugLevel3Fn("%d\n", UnitNumber(unit));
dest = FindGoldMine(unit, unit->X, unit->Y);
if (!dest) {
DebugLevel0Fn("goldmine not reachable\n");
return;
}
CommandMineGold(unit, dest,FlushCommands);
}
/**
** Assign worker to harvest.
*/
local int AiHarvest(Unit * unit)
{
int x, y, addx, addy, i, n, r, wx, wy, bestx, besty, cost;
Unit *dest;
DebugLevel3Fn("%d\n", UnitNumber(unit));
x = unit->X;
y = unit->Y;
addx = unit->Type->TileWidth;
addy = unit->Type->TileHeight;
r = TheMap.Width;
if (r < TheMap.Height) {
r = TheMap.Height;
}
// This is correct, but can this be written faster???
if ((dest = FindWoodDeposit(unit->Player, x, y))) {
NearestOfUnit(dest, x, y, &wx, &wy);
DebugLevel3("To %d,%d\n", wx, wy);
} else {
wx = unit->X;
wy = unit->Y;
}
cost = 99999;
IfDebug(bestx = besty = 0; ); // keep the compiler happy
// FIXME: if we reach the map borders we can go fast up, left, ...
--x;
while (addx <= r && addy <= r) {
for (i = addy; i--; y++) { // go down
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n", x, y, n);
if (n < cost && PlaceReachable(unit, x, y, 1)) {
cost = n;
bestx = x;
besty = y;
}
}
}
++addx;
for (i = addx; i--; x++) { // go right
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n", x, y, n);
if (n < cost && PlaceReachable(unit, x, y, 1)) {
cost = n;
bestx = x;
besty = y;
}
}
}
++addy;
for (i = addy; i--; y--) { // go up
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n", x, y, n);
if (n < cost && PlaceReachable(unit, x, y, 1)) {
cost = n;
bestx = x;
besty = y;
}
}
}
++addx;
for (i = addx; i--; x--) { // go left
if (CheckedForestOnMap(x, y)) {
n = max(abs(wx - x), abs(wy - y));
DebugLevel3("Distance %d,%d %d\n", x, y, n);
if (n < cost && PlaceReachable(unit, x, y, 1)) {
cost = n;
bestx = x;
besty = y;
}
}
}
if (cost != 99999) {
DebugLevel3Fn("wood on %d,%d\n", x, y);
CommandHarvest(unit, bestx, besty,FlushCommands);
return 1;
}
++addy;
}
DebugLevel0Fn("no wood reachable\n");
return 0;
}
/**
** Assign workers to collect resources.
*/
local void AiCollectResources(void)
{
int c;
int i;
int n;
UnitType** types;
Unit* table[UnitMax];
int nunits;
DebugLevel0Fn("%x\n",AiPlayer->NeededMask);
//
// Look through all costs, if needed.
//
for( c=0; c<OreCost; ++c ) {
if( c>=AiHelpers.CollectCount || !AiHelpers.Collect[c]
|| !(AiPlayer->NeededMask&(1<<c)) ) {
continue;
}
types=AiHelpers.Collect[c]->Table;
n=AiHelpers.Collect[c]->Count;
nunits=0;
for( i=0; i<n; ++i ) {
nunits += FindPlayerUnitsByType(AiPlayer->Player,
types[i],table+nunits);
}
DebugLevel0Fn("%s: units %d\n",DEFAULT_NAMES[c],nunits);
//
// Assign the worker
//
for( i=0; i<nunits; ++i ) {
// Unit is already *very* busy
if (table[i]->Orders[0].Action != UnitActionBuild
&& (table[i]->OrderCount==1
|| table[i]->Orders[1].Action != UnitActionBuild) ) {
switch( c ) {
case 1:
if (table[i]->Orders[0].Action != UnitActionMineGold ) {
AiMineGold(table[i]);
}
break;
case 2:
if (table[i]->Orders[0].Action != UnitActionHarvest ) {
AiHarvest(table[i]);
}
break;
default:
DebugCheck( 1 );
}
}
}
}
//
// Assign the remaining unit.
//
for( c=0; c<OreCost; ++c ) {
if( c>=AiHelpers.CollectCount || !AiHelpers.Collect[c] ) {
continue;
}
types=AiHelpers.Collect[c]->Table;
n=AiHelpers.Collect[c]->Count;
nunits=0;
for( i=0; i<n; ++i ) {
nunits += FindPlayerUnitsByType(AiPlayer->Player,
types[i],table+nunits);
}
DebugLevel0Fn("%s: units %d\n",DEFAULT_NAMES[c],nunits);
//
// Assign the worker
//
for( i=0; i<nunits; ++i ) {
// Unit is already busy
if (table[i]->Orders[0].Action != UnitActionStill
|| table[i]->OrderCount>1 ) {
continue;
}
switch( c ) {
case 1:
AiMineGold(table[i]);
break;
case 2:
AiHarvest(table[i]);
break;
default:
DebugCheck( 1 );
}
}
}
}
/**
** Add unit-type request to resource manager.
**
@ -48,7 +507,7 @@ global void AiAddUnitTypeRequest(UnitType* type,int count)
{
int n;
DebugLevel0Fn("%s %d\n",type->Ident,count);
DebugLevel0Fn("%s %d\n" _C_ type->Ident _C_ count);
if( AiPlayer->UnitTypeBuilded ) {
n=AiPlayer->BuildedCount;
AiPlayer->UnitTypeBuilded=realloc(AiPlayer->UnitTypeBuilded,
@ -68,6 +527,14 @@ global void AiAddUnitTypeRequest(UnitType* type,int count)
*/
global void AiResourceManager(void)
{
//
// Check if something needs to be build / trained.
//
AiCheckingWork();
//
// Collect resources.
//
AiCollectResources();
}
//@}

View file

@ -50,7 +50,7 @@
local void AiHelperSetupTable(int* count,AiUnitTypeTable*** table,int n)
{
int i;
++n;
if( n>(i=*count) ) {
if( *table ) {
@ -127,8 +127,9 @@ local SCM CclDefineAiHelper(SCM list)
UnitType* base;
UnitType* type;
Upgrade* upgrade;
int cost;
IfDebug( type=NULL; upgrade=NULL; ); // keep the compiler happy
IfDebug( type=NULL; upgrade=NULL; cost=0; );// keep the compiler happy
while( !gh_null_p(list) ) {
sub_list=gh_car(list);
list=gh_cdr(list);
@ -146,6 +147,8 @@ local SCM CclDefineAiHelper(SCM list)
what=2;
} else if( gh_eq_p(value,gh_symbol2scm("research")) ) {
what=3;
} else if( gh_eq_p(value,gh_symbol2scm("collect")) ) {
what=4;
} else {
fprintf(stderr,"unknown tag\n");
continue;
@ -163,7 +166,7 @@ local SCM CclDefineAiHelper(SCM list)
free(str);
continue;
}
DebugLevel0Fn("%s\n",base->Name);
DebugLevel0Fn("%s\n" _C_ base->Name);
free(str);
//
@ -180,7 +183,26 @@ local SCM CclDefineAiHelper(SCM list)
free(str);
continue;
}
DebugLevel0Fn("> %s\n",upgrade->Ident);
DebugLevel0Fn("> %s\n" _C_ upgrade->Ident);
} else if( what==4 ) {
if( !strcmp(DEFAULT_NAMES[1],str) ) {
cost=1;
} else if( !strcmp(DEFAULT_NAMES[2],str) ) {
cost=2;
} else if( !strcmp(DEFAULT_NAMES[3],str) ) {
cost=3;
} else if( !strcmp(DEFAULT_NAMES[4],str) ) {
cost=4;
} else if( !strcmp(DEFAULT_NAMES[5],str) ) {
cost=5;
} else if( !strcmp(DEFAULT_NAMES[6],str) ) {
cost=6;
} else {
fprintf(stderr,"unknown cost %s\n",str);
free(str);
continue;
}
DebugLevel0Fn("> %s\n" _C_ str);
} else {
type=UnitTypeByIdent(str);
if( !type ) {
@ -188,7 +210,7 @@ local SCM CclDefineAiHelper(SCM list)
free(str);
continue;
}
DebugLevel0Fn("> %s\n",type->Name);
DebugLevel0Fn("> %s\n" _C_ type->Name);
}
free(str);
@ -219,6 +241,11 @@ local SCM CclDefineAiHelper(SCM list)
AiHelperInsert(
AiHelpers.Research+(upgrade-Upgrades),base);
break;
case 4: // collect
AiHelperSetupTable(
&AiHelpers.CollectCount,&AiHelpers.Collect,cost);
AiHelperInsert( AiHelpers.Collect+cost,base);
break;
}
}
}
@ -245,7 +272,7 @@ local SCM CclDefineAi(SCM list)
value=gh_car(list);
list=gh_cdr(list);
str=gh_scm2newstr(value,NULL);
DebugLevel0Fn("%s\n",str);
DebugLevel0Fn("%s\n" _C_ str);
aitype->Name=str;
//
@ -254,7 +281,7 @@ local SCM CclDefineAi(SCM list)
value=gh_car(list);
list=gh_cdr(list);
str=gh_scm2newstr(value,NULL);
DebugLevel0Fn("%s\n",str);
DebugLevel0Fn("%s\n" _C_ str);
aitype->Race=str;
//
@ -263,7 +290,7 @@ local SCM CclDefineAi(SCM list)
value=gh_car(list);
list=gh_cdr(list);
str=gh_scm2newstr(value,NULL);
DebugLevel0Fn("%s\n",str);
DebugLevel0Fn("%s\n" _C_ str);
aitype->Class=str;
//
@ -424,7 +451,8 @@ local SCM CclAiWait(SCM value)
return SCM_BOOL_F;
}
// units available?
DebugLevel0Fn("%d,%d\n",AiPlayer->Player->UnitTypesCount[type->Type],autt->Count);
DebugLevel0Fn("%d,%d\n"
_C_ AiPlayer->Player->UnitTypesCount[type->Type] _C_ autt->Count);
if( AiPlayer->Player->UnitTypesCount[type->Type]>=autt->Count ) {
return SCM_BOOL_F;
}

View file

@ -65,6 +65,7 @@ struct _player_ {
char* Name; /// name of non computer
unsigned Type; /// type of player (human,computer,...)
char* RaceName; /// name of race.
unsigned Race; /// race of player (orc,human,...)
unsigned AiNum; /// AI for computer

View file

@ -159,6 +159,7 @@ global void CreatePlayer(char* name,int type)
player->Name=name;
player->Type=type;
player->Race=PlayerRaceHuman;
player->RaceName="human";
player->Team=team;
player->Enemy=0;
player->Allied=0;
@ -262,6 +263,18 @@ global void CreatePlayer(char* name,int type)
global void PlayerSetSide(Player* player,int side)
{
player->Race=side;
switch( side ) {
case PlayerRaceHuman:
player->RaceName="human";
break;
case PlayerRaceOrc:
player->RaceName="orc";
break;
default:
DebugLevel0Fn("Unsupported side %d\n",side);
player->RaceName="oops";
break;
}
}
/**