New AI builds now forces.

This commit is contained in:
johns 2001-04-29 17:51:53 +00:00
parent da30d69f80
commit 09f7e5dc02
7 changed files with 716 additions and 172 deletions

View file

@ -23,6 +23,7 @@ MODULE = ai
HDRS = ai_local.h
OBJS = ai.$(OE) new_ai.$(OE) ccl_ai.$(OE) ai_resource.$(OE)
OBJS = ai.$(OE) new_ai.$(OE) ccl_ai.$(OE) ai_resource.$(OE) \
ai_building.$(OE) ai_force.$(OE)
include $(TOPDIR)/Common.mk

View file

@ -76,7 +76,8 @@ local void AiExecuteScript(void)
local void AiCheckUnits(void)
{
int counter[UnitTypeMax];
AiBuildQueue* queue;
const AiBuildQueue* queue;
const int* unit_types_count;
int i;
int n;
int t;
@ -91,6 +92,7 @@ local void AiCheckUnits(void)
DebugLevel0Fn("Already in build queue: %s %d/%d\n" _C_
queue->Type->Ident _C_ queue->Made _C_ queue->Want);
}
unit_types_count=AiPlayer->Player->UnitTypesCount;
//
// Look if something is missing.
@ -99,14 +101,35 @@ local void AiCheckUnits(void)
for( i=0; i<n; ++i ) {
t=AiPlayer->UnitTypeRequests[i].Table[0]->Type;
x=AiPlayer->UnitTypeRequests[i].Count;
if( x>AiPlayer->Player->UnitTypesCount[t]+counter[t] ) {
DebugLevel0Fn("Need %s\n" _C_
AiPlayer->UnitTypeRequests[i].Table[0]->Ident);
// Request it.
if( x>unit_types_count[t]+counter[t] ) { // Request it.
DebugLevel0Fn("Need %s *%d\n" _C_
AiPlayer->UnitTypeRequests[i].Table[0]->Ident,x);
AiAddUnitTypeRequest(AiPlayer->UnitTypeRequests[i].Table[0],
x-AiPlayer->Player->UnitTypesCount[t]-counter[t]);
x-unit_types_count[t]-counter[t]);
counter[t]+=x-unit_types_count[t]-counter[t];
}
counter[t]-=x;
}
//
// Look through the forces what is missing.
//
for( i=0; i<AI_MAX_FORCES; ++i ) {
const AiUnitType* aiut;
for( aiut=AiPlayer->Force[i].UnitTypes; aiut; aiut=aiut->Next ) {
t=aiut->Type->Type;
x=aiut->Want;
if( x>unit_types_count[t]+counter[t] ) { // Request it.
DebugLevel0Fn("Force %d need %s * %d\n" _C_ i _C_
aiut->Type->Ident,x);
AiAddUnitTypeRequest(aiut->Type,
x-unit_types_count[t]-counter[t]);
counter[t]+=x-unit_types_count[t]-counter[t];
AiPlayer->Force[i].Completed=0;
}
counter[t]-=x;
}
counter[t]+=x;
}
}
@ -146,6 +169,60 @@ global void AiInit(Player* player)
player->Ai=pai;
}
/*----------------------------------------------------------------------------
-- Support functions
----------------------------------------------------------------------------*/
/**
** Remove unit-type from build list.
**
** @param pai Computer AI player.
** @param type Unit-type which is now available.
*/
local void AiRemoveFromBuilded(PlayerAi* pai,const UnitType* type)
{
AiBuildQueue** queue;
AiBuildQueue* next;
//
// Search the unit-type order.
//
for( queue=&pai->UnitTypeBuilded; (next=*queue); queue=&next->Next ) {
DebugCheck( !next->Want );
if( type==next->Type && next->Made ) {
if( !--next->Want ) {
*queue=next->Next;
free(next);
}
--next->Made;
return;
}
}
DebugCheck( 1 );
}
/**
** Reduce made unit-type from build list.
**
** @param pai Computer AI player.
** @param type Unit-type which is now available.
*/
local void AiReduceMadeInBuilded(const PlayerAi* pai,const UnitType* type)
{
AiBuildQueue* queue;
//
// Search the unit-type order.
//
for( queue=pai->UnitTypeBuilded; queue; queue=queue->Next ) {
if( type==queue->Type && queue->Made ) {
queue->Made--;
return;
}
}
DebugCheck( 1 );
}
/*----------------------------------------------------------------------------
-- Callback Functions
----------------------------------------------------------------------------*/
@ -154,11 +231,11 @@ global void AiInit(Player* player)
** Called if a Unit is Attacked
**
** @param unit Pointer to unit that is being attacked.
**
*/
global void AiHelpMe(Unit* unit)
{
DebugLevel0Fn("%d %d" _C_ unit->X _C_ unit->Y);
DebugLevel0Fn("%d(%s) attacked at %d,%d" _C_
UnitNumber(unit) _C_ unit->Type->Ident _C_ unit->X _C_ unit->Y);
}
/**
@ -169,30 +246,13 @@ global void AiHelpMe(Unit* unit)
*/
global void AiWorkComplete(Unit* unit,Unit* what)
{
AiBuildQueue** queue;
AiBuildQueue* next;
PlayerAi* pai;
DebugLevel1Fn("AiPlayer %d: %d build %s at %d,%d completed\n" _C_
unit->Player->Player _C_ UnitNumber(unit), what->Type->Ident _C_
unit->X _C_ unit->Y);
DebugLevel1Fn("AiPlayer %d: %d(%s) build %s at %d,%d completed\n" _C_
unit->Player->Player _C_ UnitNumber(unit) _C_ unit->Type->Ident _C_
what->Type->Ident _C_ unit->X _C_ unit->Y);
DebugCheck(unit->Player->Type == PlayerHuman);
//
// Search the unit-type order.
//
pai=unit->Player->Ai;
for( queue=&pai->UnitTypeBuilded; (next=*queue); queue=&next->Next ) {
if( what->Type==next->Type && next->Want && next->Made ) {
if( next->Want==next->Made ) {
*queue=next->Next;
free(next);
}
return;
}
}
DebugCheck( 1 );
AiRemoveFromBuilded(unit->Player->Ai,what->Type);
}
/**
@ -203,26 +263,13 @@ global void AiWorkComplete(Unit* unit,Unit* what)
*/
global void AiCanNotBuild(Unit* unit,const UnitType* what)
{
AiBuildQueue* queue;
const PlayerAi* pai;
DebugLevel1Fn("AiPlayer %d: %d Can't build %s at %d,%d\n" _C_
unit->Player->Player _C_ UnitNumber(unit), what->Ident _C_
unit->X _C_ unit->Y);
DebugCheck(unit->Player->Type == PlayerHuman);
//
// Search the unit-type order.
//
pai=unit->Player->Ai;
for( queue=pai->UnitTypeBuilded; queue; queue=queue->Next ) {
if( what==queue->Type && queue->Made ) {
queue->Made--;
return;
}
}
DebugCheck( 1 );
AiReduceMadeInBuilded(unit->Player->Ai,what);
}
/**
@ -233,60 +280,33 @@ global void AiCanNotBuild(Unit* unit,const UnitType* what)
*/
global void AiCanNotReach(Unit* unit,const UnitType* what)
{
AiBuildQueue* queue;
const PlayerAi* pai;
DebugLevel1Fn("AiPlayer %d: %d Can't reach %s at %d,%d\n" _C_
unit->Player->Player _C_ UnitNumber(unit), what->Ident _C_
unit->X _C_ unit->Y);
DebugLevel1Fn("AiPlayer %d: %d(%s) Can't reach %s at %d,%d\n" _C_
unit->Player->Player _C_ UnitNumber(unit) _C_ unit->Type->Ident _C_
what->Ident _C_ unit->X _C_ unit->Y);
DebugCheck(unit->Player->Type == PlayerHuman);
//
// Search the unit-type order.
//
pai=unit->Player->Ai;
for( queue=pai->UnitTypeBuilded; queue; queue=queue->Next ) {
if( what==queue->Type && queue->Made ) {
queue->Made--;
return;
}
}
DebugCheck( 1 );
AiReduceMadeInBuilded(unit->Player->Ai,what);
}
/**
** Called if training of an unit is completed.
**
** @param unit Pointer to unit.
** @param what Pointer to type.
** @param unit Pointer to unit making.
** @param what Pointer to new ready trained unit.
*/
global void AiTrainingComplete(Unit* unit,Unit* what)
{
AiBuildQueue** queue;
AiBuildQueue* next;
PlayerAi* pai;
DebugLevel1Fn("AiPlayer %d: %d training %s at %d,%d completed\n" _C_
unit->Player->Player _C_ UnitNumber(unit), what->Type->Ident _C_
unit->X _C_ unit->Y);
DebugLevel1Fn("AiPlayer %d: %d(%s) training %s at %d,%d completed\n" _C_
unit->Player->Player _C_ UnitNumber(unit) _C_ unit->Type->Ident _C_
what->Type->Ident _C_ unit->X _C_ unit->Y);
DebugCheck(unit->Player->Type == PlayerHuman);
//
// Search the unit-type order.
//
pai=unit->Player->Ai;
for( queue=&pai->UnitTypeBuilded; (next=*queue); queue=&next->Next ) {
if( what->Type==next->Type && next->Want && next->Made ) {
if( next->Want==next->Made ) {
*queue=next->Next;
free(next);
}
return;
}
}
DebugCheck( 1 );
AiRemoveFromBuilded(unit->Player->Ai,what->Type);
AiPlayer=unit->Player->Ai;
AiAssignToForce(what);
}
/**

196
src/ai/ai_building.cpp Normal file
View file

@ -0,0 +1,196 @@
// ___________ _________ _____ __
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
// \/ \/ \/ \/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// FreeCraft - A free fantasy real time strategy game engine
//
/**@name ai_building.c - AI building functions. */
//
// (c) Copyright 2001 by Lutz Sammer
//
// $Id$
#ifdef NEW_AI // {
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "freecraft.h"
#include "unit.h"
#include "map.h"
#include "pathfinder.h"
#include "ai_local.h"
/*----------------------------------------------------------------------------
-- Variables
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Check if the surrounding are free.
**
** @param type Type of building.
** @param x X map tile position for the building.
** @param y Y map tile position for the building.
**
** @return True if the surrounding is free, false otherwise.
**
** @note Can be faster written.
*/
local int AiCheckSurrounding(const UnitType * type,int x, int y)
{
int i;
int h;
int w;
int f;
h=type->TileWidth+2;
w=type->TileHeight+2;
--x;
--y;
f=0;
for( i=0; i<w; ++i ) { // Top row
if( x+i<0 || x+i>TheMap.Width ) { // FIXME: slow, worse,...
continue;
}
if( y>=0 && TheMap.Fields[x+i+y*TheMap.Width].Flags&(MapFieldUnpassable
|MapFieldWall|MapFieldRocks|MapFieldForest|MapFieldBuilding) ) {
return 0;
} // Bot row
if( (y+w)<TheMap.Height && TheMap.Fields[x+i+(y+w)*TheMap.Width].Flags&
(MapFieldUnpassable|MapFieldWall|MapFieldRocks
|MapFieldForest|MapFieldBuilding) ) {
return 0;
}
}
++y;
h-=2;
for( i=0; i<h; ++i ) { // Left row
if( y+i<0 || y+i>TheMap.Height ) { // FIXME: slow, worse,...
continue;
}
if( x>=0 && TheMap.Fields[x+(y+i)*TheMap.Width].Flags&
(MapFieldUnpassable|MapFieldWall|MapFieldRocks
|MapFieldForest|MapFieldBuilding) ) {
return 0;
} // Right row
if( (x+w)<TheMap.Width && TheMap.Fields[x+w+(y+i)*TheMap.Width].Flags&
(MapFieldUnpassable|MapFieldWall|MapFieldRocks
|MapFieldForest|MapFieldBuilding) ) {
return 0;
}
}
return 1;
}
/**
** 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.
** @param flag Flag if surrounding must be free.
** @return True if place found, false if no found.
**
** @note This can be done faster, use flood fill.
*/
local int AiFindBuildingPlace2(const Unit * worker, const UnitType * type,
int *dx, int *dy,int flag)
{
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++;
if( addx>=TheMap.Width && addy>=TheMap.Height ) {
return 0;
}
}
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)
&& (!flag || AiCheckSurrounding(type, x, y))
&& PlaceReachable(worker, x, y, 1) ) {
*dx=x;
*dy=y;
return 1;
}
}
return 0;
}
/**
** 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)
{
if( AiFindBuildingPlace2(worker,type,dx,dy,1) ) {
return 1;
}
return 0;
//return AiFindBuildingPlace2(worker,type,dx,dy,0);
}
//@}
#endif // } NEW_AI

160
src/ai/ai_force.cpp Normal file
View file

@ -0,0 +1,160 @@
// ___________ _________ _____ __
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
// \/ \/ \/ \/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// FreeCraft - A free fantasy real time strategy game engine
//
/**@name ai_force.c - AI force functions. */
//
// (c) Copyright 2001 by Lutz Sammer
//
// $Id$
#ifdef NEW_AI // {
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "freecraft.h"
#include "unit.h"
#include "ai_local.h"
/*----------------------------------------------------------------------------
-- Variables
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Ai clean units in a force.
**
** @param force Force number.
*/
local void AiCleanForce(int force)
{
AiUnit** prev;
AiUnit* aiunit;
//
// Release all killed units.
//
prev=&AiPlayer->Force[force].Units;
while( (aiunit=*prev) ) {
if( aiunit->Unit->Destroyed ) {
RefsDebugCheck( !aiunit->Unit->Refs );
if( !--aiunit->Unit->Refs ) {
ReleaseUnit(aiunit->Unit);
}
AiPlayer->Force[force].Completed=0;
*prev=aiunit->Next;
free(aiunit);
continue;
}
prev=&aiunit->Next;
}
}
/**
** Cleanup units in forces.
*/
local void AiCleanForces(void)
{
int force;
//
// Release all killed units.
//
for( force=0; force<AI_MAX_FORCES; ++force ) {
AiCleanForce(force);
}
}
/**
** Check if the units belongs to the force.
**
** @param force Force to be checked.
** @param type Type to check.
** @return Returns true if it fits, false otherwise.
*/
local int AiCheckBelongsToForce(int force,const UnitType* type)
{
AiUnit* aiunit;
AiUnitType* aitype;
int counter[UnitTypeMax];
int flag;
memset(counter,0,sizeof(counter));
//
// Count units in force.
//
aiunit=AiPlayer->Force[force].Units;
while( aiunit ) {
counter[aiunit->Unit->Type->Type]++;
aiunit=aiunit->Next;
}
//
// Look what should be in the force.
//
flag=0;
AiPlayer->Force[force].Completed=1;
aitype=AiPlayer->Force[force].UnitTypes;
while( aitype ) {
if( aitype->Want>counter[aitype->Type->Type] ) {
if( type==aitype->Type ) {
if( aitype->Want-1>counter[aitype->Type->Type] ) {
AiPlayer->Force[force].Completed=0;
}
flag=1;
} else {
AiPlayer->Force[force].Completed=0;
}
}
aitype=aitype->Next;
}
return flag;
}
/**
** Ai assign unit to force.
*/
global void AiAssignToForce(Unit* unit)
{
int force;
AiCleanForces();
//
// Check to which force it belongs
//
for( force=0; force<AI_MAX_FORCES; ++force ) {
if( AiCheckBelongsToForce(force,unit->Type) ) {
AiUnit* aiunit;
aiunit=malloc(sizeof(aiunit));
aiunit->Next=AiPlayer->Force[force].Units;
aiunit->Unit=unit;
RefsDebugCheck( unit->Destroyed || !unit->Refs );
++unit->Refs;
AiPlayer->Force[force].Units=aiunit;
break;
}
}
}
//@}
#endif // } NEW_AI

View file

@ -129,6 +129,33 @@ typedef struct _ai_unittype_table_ {
UnitType* Table[1]; /// the table
} AiUnitTypeTable;
/**
** Ai unit-type typedef.
*/
typedef struct _ai_unit_type_ AiUnitType;
/**
** Ai unit-type in a force.
*/
struct _ai_unit_type_ {
AiUnitType* Next; /// next unit-type
int Want; /// number of this unit-type wanted
UnitType* Type; /// unit-type self
};
/**
** Ai unit typedef.
*/
typedef struct _ai_unit_ AiUnit;
/**
** Ai unit in a force.
*/
struct _ai_unit_ {
AiUnit* Next; /// next unit
Unit* Unit; /// unit self
};
/**
** AI force typedef.
*/
@ -140,7 +167,10 @@ typedef struct _ai_force_ AiForce;
** A force is a group of units belonging together.
*/
struct _ai_force_ {
AiUnitTypeTable UnitTypeTable; /// Count and types of unit-type
int Completed; /// Flag saying force is complete build
int Attacking; /// Flag saying force is attacking
AiUnitType* UnitTypes; /// Count and types of unit-type
AiUnit* Units; /// Units in the force.
};
/**
@ -172,6 +202,10 @@ typedef struct _player_ai_ {
SCM Script; /// Script executed
int ScriptDebug; /// Flag script debuging on/off
// forces
#define AI_MAX_FORCES 10 /// How many forces are supported
AiForce Force[AI_MAX_FORCES]; /// Forces controlled by AI.
// resource manager
int Reserve[MaxCosts]; /// Resources to keep in reserve
@ -179,10 +213,20 @@ typedef struct _player_ai_ {
int Needed[MaxCosts]; /// Needed resources
int NeededMask; /// Mask for needed resources
int NeedFood; /// Flag need food
/// number of elements in UnitTypeRequests
int RequestsCount;
/// unit-types to build/train requested and priority list
AiUnitTypeTable* UnitTypeRequests;
/// number of elements in UpgradeRequests
int UpgradeToRequestsCount;
/// Upgrade to unit-type requested and priority list
UnitType** UpgradeToRequests;
/// number of elements in ResearchRequests
int ResearchRequestsCount;
/// Upgrades requested and priority list
Upgrade** ResearchRequests;
/// What the resource manager should build
AiBuildQueue* UnitTypeBuilded;
@ -262,6 +306,17 @@ extern void AiAddUnitTypeRequest(UnitType* type,int count);
/// Periodic called resource manager handler
extern void AiResourceManager(void);
//
// Buildings
//
/// Find nice building place
extern int AiFindBuildingPlace(const Unit*, const UnitType * , int *, int *);
//
// Forces
//
/// Assign a new unit to a force.
extern void AiAssignToForce(Unit* unit);
//@}

View file

@ -87,81 +87,14 @@ 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++;
if( addx>=TheMap.Width && addy>=TheMap.Height ) {
return 0;
}
}
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.
**
** @note We must check if the dependencies are fulfilled.
*/
local int AiBuildBuilding(const UnitType* type,UnitType* building)
{
@ -250,7 +183,6 @@ local void AiRequestFarms(void)
AiPlayer->NeededMask|=c;
return;
} else {
AiPlayer->NeededMask=0;
DebugLevel0("- enough resources\n");
if( AiMakeUnit(type) ) {
queue=malloc(sizeof(*AiPlayer->UnitTypeBuilded));
@ -268,8 +200,10 @@ local void AiRequestFarms(void)
** Check if we can train the unit.
**
** @param type Unit that can train the unit.
** @param what what to be trained.
** @param what What to be trained.
** @return True if made, false if can't be made.
**
** @note We must check if the dependencies are fulfilled.
*/
local int AiTrainUnit(const UnitType* type,UnitType* what)
{
@ -311,6 +245,8 @@ local int AiTrainUnit(const UnitType* type,UnitType* what)
**
** @param type Unit-type that must be made.
** @return True if made, false if can't be made.
**
** @note We must check if the dependencies are fulfilled.
*/
local int AiMakeUnit(UnitType* type)
{
@ -372,22 +308,33 @@ local void AiCheckingWork(void)
UnitType* type;
AiBuildQueue* queue;
DebugLevel0Fn("%d %d %d\n" _C_
DebugLevel3Fn("%d %d %d\n" _C_
AiPlayer->Player->Resources[1] _C_
AiPlayer->Player->Resources[2] _C_
AiPlayer->Player->Resources[3]);
AiPlayer->NeededMask=0;
if( AiPlayer->NeedFood ) { // Food has the highest priority
AiPlayer->NeedFood=0;
AiRequestFarms();
}
//
// Look to the build requests, what can be done.
//
for( queue=AiPlayer->UnitTypeBuilded; queue; queue=queue->Next ) {
if( queue->Want>queue->Made ) {
type=queue->Type;
DebugLevel0Fn("Must build: %s " _C_ type->Ident);
DebugLevel3Fn("Must build: %s " _C_ type->Ident);
//
// Check if we have enough food.
//
if( !type->Building && AiPlayer->Player->Food
<=AiPlayer->Player->NumFoodUnits ) {
DebugLevel0Fn("Need food\n");
DebugLevel3Fn("Need food\n");
AiPlayer->NeedFood=1;
AiRequestFarms();
return;
}
@ -396,12 +343,11 @@ local void AiCheckingWork(void)
// Check if resources available.
//
if( (c=AiCheckUnitTypeCosts(type)) ) {
DebugLevel0("- no resources\n");
AiPlayer->NeededMask=c;
DebugLevel3("- no resources\n");
AiPlayer->NeededMask|=c;
return;
} else {
AiPlayer->NeededMask=0;
DebugLevel0("- enough resources\n");
DebugLevel3("- enough resources\n");
if( AiMakeUnit(type) ) {
++queue->Made;
}
@ -420,7 +366,7 @@ local void AiCheckingWork(void)
** 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)
local int AiMineGold(Unit * unit)
{
Unit *dest;
@ -428,9 +374,12 @@ local void AiMineGold(Unit * unit)
dest = FindGoldMine(unit, unit->X, unit->Y);
if (!dest) {
DebugLevel0Fn("goldmine not reachable\n");
return;
return 0;
}
DebugCheck(unit->Type!=UnitTypeHumanWorker && unit->Type!=UnitTypeOrcWorker);
CommandMineGold(unit, dest,FlushCommands);
return 1;
}
/**
@ -514,6 +463,7 @@ local int AiHarvest(Unit * unit)
}
if (cost != 99999) {
DebugLevel3Fn("wood on %d,%d\n", x, y);
DebugCheck(unit->Type!=UnitTypeHumanWorker && unit->Type!=UnitTypeOrcWorker);
CommandHarvest(unit, bestx, besty,FlushCommands);
return 1;
}
@ -525,6 +475,9 @@ local int AiHarvest(Unit * unit)
/**
** Assign workers to collect resources.
**
** If we have a shortage of a resource, let many workers collecting this.
** If no shortage, split workers to all resources.
*/
local void AiCollectResources(void)
{
@ -535,7 +488,7 @@ local void AiCollectResources(void)
Unit* table[UnitMax];
int nunits;
DebugLevel0Fn("%x\n" _C_ AiPlayer->NeededMask);
DebugLevel3Fn("Needed resources %x\n" _C_ AiPlayer->NeededMask);
//
// Look through all costs, if needed.
@ -545,6 +498,10 @@ local void AiCollectResources(void)
|| !(AiPlayer->NeededMask&(1<<c)) ) {
continue;
}
//
// Get all workers that can collect this resource.
//
types=AiHelpers.Collect[c]->Table;
n=AiHelpers.Collect[c]->Count;
nunits=0;
@ -552,7 +509,7 @@ local void AiCollectResources(void)
nunits += FindPlayerUnitsByType(AiPlayer->Player,
types[i],table+nunits);
}
DebugLevel0Fn("%s: units %d\n" _C_ DEFAULT_NAMES[c] _C_ nunits);
DebugLevel3Fn("%s: units %d\n" _C_ DEFAULT_NAMES[c] _C_ nunits);
//
// Assign the worker
@ -560,8 +517,7 @@ local void AiCollectResources(void)
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) ) {
&& table[i]->OrderCount==1 ) {
switch( c ) {
case 1:
if (table[i]->Orders[0].Action != UnitActionMineGold ) {
@ -587,6 +543,10 @@ local void AiCollectResources(void)
if( c>=AiHelpers.CollectCount || !AiHelpers.Collect[c] ) {
continue;
}
//
// Get all workers that can collect this resource.
//
types=AiHelpers.Collect[c]->Table;
n=AiHelpers.Collect[c]->Count;
nunits=0;
@ -594,7 +554,7 @@ local void AiCollectResources(void)
nunits += FindPlayerUnitsByType(AiPlayer->Player,
types[i],table+nunits);
}
DebugLevel0Fn("%s: units %d\n" _C_ DEFAULT_NAMES[c] _C_ nunits);
DebugLevel3Fn("%s: units %d\n" _C_ DEFAULT_NAMES[c] _C_ nunits);
//
// Assign the worker
@ -633,7 +593,7 @@ local void AiCollectResources(void)
types[i],table+nunits);
}
}
DebugLevel0Fn("Return: units %d\n" _C_ nunits);
DebugLevel3Fn("Return: units %d\n" _C_ nunits);
//
// Assign the workers with goods

View file

@ -483,6 +483,152 @@ local SCM CclAiWait(SCM value)
return SCM_BOOL_T;
}
/**
** Define a force, a groups of units.
**
** @param list Pairs of unit-types and counts.
*/
local SCM CclAiForce(SCM list)
{
AiUnitType** prev;
AiUnitType* aiut;
UnitType* type;
int count;
int force;
printf("Force: ");
gh_display(list);
gh_newline();
force=gh_scm2int(gh_car(list));
if( force<0 || force>=AI_MAX_FORCES ) {
errl("Force out of range",gh_car(list));
}
list=gh_cdr(list);
while( !gh_null_p(list) ) {
type=CclGetUnitType(gh_car(list));
list=gh_cdr(list);
count=gh_scm2int(gh_car(list));
list=gh_cdr(list);
//
// Look if already in force.
//
for( prev=&AiPlayer->Force[force].UnitTypes; (aiut=*prev);
prev=&aiut->Next ) {
if( aiut->Type==type ) { // found
if( count ) {
aiut->Want=count;
} else {
*prev=aiut->Next;
free(aiut);
}
break;
}
}
//
// New type append it.
//
if( !aiut ) {
*prev=aiut=malloc(sizeof(*aiut));
aiut->Next=NULL;
aiut->Want=count;
aiut->Type=type;
}
}
return SCM_BOOL_F;
}
/**
** Wait for a force ready.
**
** @param value Force number.
*/
local SCM CclAiWaitForce(SCM value)
{
int force;
printf("Wait-Force: ");
gh_display(value);
gh_newline();
force=gh_scm2int(value);
if( force<0 || force>=AI_MAX_FORCES ) {
errl("Force out of range",value);
}
if( AiPlayer->Force[force].Completed ) {
return SCM_BOOL_F;
}
return SCM_BOOL_T;
}
/**
** Attack with force.
**
** @param value Force number.
*/
local SCM CclAiAttackWithForce(SCM value)
{
printf("Attack: ");
gh_display(value);
gh_newline();
// FIXME: more later!
return SCM_BOOL_F;
}
/**
** Sleep n frames.
**
** @param value Number of frames to delay.
*/
local SCM CclAiSleep(SCM value)
{
static int fc;
int i;
printf("Sleep: ");
gh_display(value);
printf(" %d %d",fc,FrameCounter);
gh_newline();
i=gh_scm2int(value);
if( fc ) {
if( fc<FrameCounter ) {
fc=0;
return SCM_BOOL_F;
}
} else {
fc=FrameCounter+i;
}
return SCM_BOOL_T;
}
/**
** Research an upgrade.
**
** @param value Upgrade as string/symbol/object.
*/
local SCM CclAiResearch(SCM value)
{
return SCM_BOOL_F;
}
/**
** Upgrade an unit to an new unit-type.
**
** @param value Unit-type as string/symbol/object.
*/
local SCM CclAiUpgradeTo(SCM value)
{
return SCM_BOOL_F;
}
#else
/**
@ -519,6 +665,12 @@ global void AiCclRegister(void)
gh_new_procedure1_0("ai:need",CclAiNeed);
gh_new_procedure2_0("ai:set",CclAiSet);
gh_new_procedure1_0("ai:wait",CclAiWait);
gh_new_procedureN("ai:force",CclAiForce);
gh_new_procedure1_0("ai:wait-force",CclAiWaitForce);
gh_new_procedure1_0("ai:attack-with-force",CclAiAttackWithForce);
gh_new_procedure1_0("ai:sleep",CclAiSleep);
gh_new_procedure1_0("ai:research",CclAiResearch);
gh_new_procedure1_0("ai:upgrade-to",CclAiUpgradeTo);
#endif
}