New AI builds now forces.
This commit is contained in:
parent
da30d69f80
commit
09f7e5dc02
7 changed files with 716 additions and 172 deletions
|
@ -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
|
||||
|
|
188
src/ai/ai.cpp
188
src/ai/ai.cpp
|
@ -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
196
src/ai/ai_building.cpp
Normal 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
160
src/ai/ai_force.cpp
Normal 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
|
|
@ -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);
|
||||
|
||||
//@}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue