warzone2100/src/aiexperience.c

1082 lines
30 KiB
C

/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2007 Warzone Resurrection Project
Warzone 2100 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Warzone 2100 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
//aiexperience.c
#include <physfs.h>
#include <string.h>
#include "objmem.h"
#include "objectdef.h"
#include "map.h"
#include "lib/framework/frame.h"
#include "lib/script/interp.h"
#include "lib/script/stack.h"
#include "lib/script/codeprint.h"
#include "lib/script/script.h"
#include "multiplay.h"
#include "console.h" //for RIGHT_JUSTIFY
#include "geometry.h"
#include "aiexperience.h"
static PHYSFS_file* aiSaveFile[8];
SDWORD baseLocation[MAX_PLAYERS][MAX_PLAYERS][2]; //each player's visible enemy base x,y coords for each player (hence 3d)
static SDWORD oilLocation[MAX_PLAYERS][MAX_OIL_LOCATIONS][2]; //remembered oil locations
SDWORD baseDefendLocation[MAX_PLAYERS][MAX_BASE_DEFEND_LOCATIONS][2];
SDWORD baseDefendLocPrior[MAX_PLAYERS][MAX_BASE_DEFEND_LOCATIONS]; //Priority
SDWORD oilDefendLocation[MAX_PLAYERS][MAX_OIL_DEFEND_LOCATIONS][2];
SDWORD oilDefendLocPrior[MAX_PLAYERS][MAX_OIL_DEFEND_LOCATIONS];
void InitializeAIExperience(void)
{
SDWORD i,j;
for(i=0;i<MAX_PLAYERS;i++)
{
for(j=0;j<MAX_PLAYERS;j++)
{
baseLocation[i][j][0] = -1;
baseLocation[i][j][1] = -1;
}
for(j=0; j < MAX_BASE_DEFEND_LOCATIONS; j++)
{
baseDefendLocation[i][j][0] = -1;
baseDefendLocation[i][j][1] = -1;
baseDefendLocPrior[i][j] = -1;
}
for(j=0; j < MAX_OIL_DEFEND_LOCATIONS; j++)
{
oilDefendLocation[i][j][0] = -1;
oilDefendLocation[i][j][1] = -1;
oilDefendLocPrior[i][j] = -1;
}
//oil locations
for(j=0; j < MAX_OIL_LOCATIONS; j++)
{
oilLocation[i][j][0] = -1;
oilLocation[i][j][1] = -1;
}
}
}
void LoadAIExperience(BOOL bNotify)
{
SDWORD player,status;
for(player=0; player<game.maxPlayers; player++)
{
status = LoadPlayerAIExperience(player);
//notify if needed
if(bNotify)
{
if(status == EXPERIENCE_LOAD_NOSAVE)
{
console("No saved experience found for player %d", player);
}
else if(status == EXPERIENCE_LOAD_OK)
{
console("Successfully loaded experience for player %d", player);
}
else //any error
{
console("Error while loading experience for player %d", player);
}
}
}
}
BOOL SaveAIExperience(BOOL bNotify)
{
SDWORD i;
for(i=0;i<game.maxPlayers;i++)
{
(void)SavePlayerAIExperience(i, bNotify);
}
return true;
}
SDWORD LoadPlayerAIExperience(SDWORD nPlayer)
{
if((nPlayer > -1) && (nPlayer < MAX_PLAYERS))
{
return ReadAISaveData(nPlayer);
}
return EXPERIENCE_LOAD_ERROR;
}
BOOL SavePlayerAIExperience(SDWORD nPlayer, BOOL bNotify)
{
if((nPlayer > -1) && (nPlayer < MAX_PLAYERS))
{
if(!WriteAISaveData(nPlayer))
{
debug(LOG_ERROR,"SavePlayerAIExperience - failed to save exper");
//addConsoleMessage("Failed to save experience.",RIGHT_JUSTIFY,SYSTEM_MESSAGE);
console("Failed to save experience for player %d.", nPlayer);
return false;
}
}
if(bNotify)
{
console("Experience for player %d saved successfully.", nPlayer);
}
return true;
}
BOOL SetUpOutputFile(SDWORD nPlayer)
{
char sPlayer[255] = "";
char SaveDir[PATH_MAX] = "multiplay/learndata/";
char FileName[255] = "";
//debug(LOG_ERROR,"SetUpOutputFile");
/* Assemble dir string */
sprintf(sPlayer,"%d",nPlayer);
sstrcat(SaveDir, "player");
sstrcat(SaveDir, sPlayer);
/* Create dir on disk */
if ( !PHYSFS_mkdir(SaveDir))
{
debug( LOG_ERROR, "SetUpOutputFile: Error creating directory \"%s\": %s", SaveDir, PHYSFS_getLastError() );
return false;
}
sstrcat(SaveDir, "/");
/* Create filename */
sstrcpy(FileName, SaveDir);
sstrcat(FileName, game.map); // Map name
sstrcat(FileName, ".lrn"); // Like "multiplay/learndata/player0/Rush.lrn"
/* Open file */
aiSaveFile[nPlayer] = NULL;
aiSaveFile[nPlayer] = PHYSFS_openWrite(FileName);
if (!aiSaveFile[nPlayer])
{
debug(LOG_ERROR,"SetUpOutputFile(): Couldn't open debugging output file: '%s' for player %d", FileName,nPlayer);
return false;
}
return true;
}
BOOL SetUpInputFile(SDWORD nPlayer)
{
char FileName[255] = "";
char sPlayer[255] = "";
char SaveDir[PATH_MAX] = "multiplay/learndata/"; // "multiplay/learndata/";
/* Assemble dir */
snprintf(sPlayer, sizeof(sPlayer), "%d", nPlayer);
sstrcat(SaveDir, "player");
sstrcat(SaveDir, sPlayer);
sstrcat(SaveDir, "/"); // like "multiplay\learndata\player0\"
/* Create filename */
sstrcpy(FileName, SaveDir);
sstrcat(FileName, game.map); // map name
sstrcat(FileName, ".lrn"); // Like "multiplay\learndata\player0\Rush.lrn"
aiSaveFile[nPlayer] = NULL;
aiSaveFile[nPlayer] = PHYSFS_openRead(FileName);
if (!aiSaveFile[nPlayer])
{
debug(LOG_ERROR,"SetUpInputFile(): Couldn't open input file: '%s' for player %d: %s", FileName, nPlayer, PHYSFS_getLastError());
return false;
}
return true;
}
BOOL ExperienceRecallOil(SDWORD nPlayer)
{
FEATURE *psFeature;
return true;
/* Make visible all oil derricks */
for(psFeature = apsFeatureLists[0]; psFeature != NULL; psFeature = psFeature->psNext)
{
if(psFeature->psStats->subType == FEAT_OIL_RESOURCE)
{
printf_console("Enabling feature at x: %d y: %d",psFeature->pos.x/128,psFeature->pos.y/128);
psFeature->visible[nPlayer] = true;
}
}
}
BOOL WriteAISaveData(SDWORD nPlayer)
{
FEATURE *psFeature;
STRUCTURE *psCurr;
SDWORD x=0,y=0;
SDWORD NumEntries=0; //How many derricks/oil resources will be saved
UDWORD PosXY[MAX_OIL_ENTRIES]; //Locations, 0=x,1=y,2=x etc
UDWORD i,j;
BOOL bTileVisible;
/* prepare experience file for the current map */
if(!SetUpOutputFile(nPlayer))
{
debug(LOG_ERROR,"Failed to prepare experience file for player %d",nPlayer);
return false;
}
if (aiSaveFile[nPlayer])
{
//debug(LOG_ERROR,"WriteAISaveData - aiSaveFile ok");
/* Version */
NumEntries = SAVE_FORMAT_VERSION; //Version
if(PHYSFS_write(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1) != 1)
{
debug(LOG_ERROR,"WriteAISaveData: failed to write version for player %d",nPlayer);
return false;
}
//fwrite(&NumEntries,sizeof(NumEntries),1,aiSaveFile[nPlayer]); //Version
//debug(LOG_ERROR,"WriteAISaveData - Version ok");
/************************/
/* Enemy bases */
/************************/
NumEntries = MAX_PLAYERS;
/* max num of players to store */
if(PHYSFS_write(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1) != 1) //num of players to store
{
debug(LOG_ERROR,"WriteAISaveData: failed to write MAX_PLAYERS for player %d",nPlayer);
return false;
}
//debug(LOG_ERROR,"WriteAISaveData - MAX_PLAYERS ok");
/* base locations of all players */
if(PHYSFS_write(aiSaveFile[nPlayer], baseLocation[nPlayer], sizeof(SDWORD), MAX_PLAYERS * 2) != (MAX_PLAYERS * 2)) //num of players to store
{
debug(LOG_ERROR,"WriteAISaveData: failed to write base locations for player %d",nPlayer);
return false;
}
//debug(LOG_ERROR,"WriteAISaveData - Enemy bases ok");
/************************************/
/* Base attack locations */
/************************************/
NumEntries = MAX_BASE_DEFEND_LOCATIONS;
/* write MAX_BASE_DEFEND_LOCATIONS */
if(PHYSFS_write(aiSaveFile[nPlayer], &NumEntries, sizeof(SDWORD), 1) < 1)
{
debug(LOG_ERROR,"WriteAISaveData: failed to write defence locations count for player %d",nPlayer);
return false;
}
/* base defence locations */
if(PHYSFS_write(aiSaveFile[nPlayer], baseDefendLocation[nPlayer], sizeof(SDWORD), MAX_BASE_DEFEND_LOCATIONS * 2) < (MAX_BASE_DEFEND_LOCATIONS * 2))
{
debug(LOG_ERROR,"WriteAISaveData: failed to write defence locations for player %d",nPlayer);
return false;
}
/* base defend priorities */
if(PHYSFS_write(aiSaveFile[nPlayer], baseDefendLocPrior[nPlayer], sizeof(SDWORD), MAX_BASE_DEFEND_LOCATIONS * 2) < (MAX_BASE_DEFEND_LOCATIONS * 2))
{
debug(LOG_ERROR,"WriteAISaveData: failed to write defence locations priority for player %d",nPlayer);
return false;
}
//debug(LOG_ERROR,"WriteAISaveData - Base attack locations ok");
/************************************/
/* Oil attack locations */
/************************************/
NumEntries = MAX_OIL_DEFEND_LOCATIONS;
/* MAX_OIL_DEFEND_LOCATIONS */
if(PHYSFS_write(aiSaveFile[nPlayer], &NumEntries, sizeof(SDWORD), 1) < 1)
{
debug(LOG_ERROR,"WriteAISaveData: failed to write oil defence locations count for player %d",nPlayer);
return false;
}
/* oil locations */
if(PHYSFS_write(aiSaveFile[nPlayer], oilDefendLocation[nPlayer], sizeof(SDWORD), MAX_OIL_DEFEND_LOCATIONS * 2) < (MAX_OIL_DEFEND_LOCATIONS * 2))
{
debug(LOG_ERROR,"WriteAISaveData: failed to write oil defence locations for player %d",nPlayer);
return false;
}
/* oil location priority */
if(PHYSFS_write(aiSaveFile[nPlayer], oilDefendLocPrior[nPlayer], sizeof(SDWORD), MAX_OIL_DEFEND_LOCATIONS * 2) < (MAX_OIL_DEFEND_LOCATIONS * 2))
{
debug(LOG_ERROR,"WriteAISaveData: failed to write oil defence locations priority for player %d",nPlayer);
return false;
}
//debug(LOG_ERROR,"WriteAISaveData - Oil attack locations ok");
/****************************/
/* Oil Resources */
/****************************/
NumEntries = MAX_OIL_LOCATIONS;
/* MAX_OIL_LOCATIONS */
if(PHYSFS_write(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1) < 1)
{
debug(LOG_ERROR,"WriteAISaveData: failed to write oil locations count for player %d",nPlayer);
return false;
}
NumEntries = 0; //Num of oil resources
/* first save everything what we recalled from last load */
for(i=0; i<MAX_OIL_LOCATIONS; i++)
{
if(oilLocation[nPlayer][i][0] <= 0 || oilLocation[nPlayer][i][1] <= 0)
continue; //skip to next one, since nothing stored
PosXY[NumEntries * 2] = oilLocation[nPlayer][i][0]; //x
PosXY[NumEntries * 2 + 1] = oilLocation[nPlayer][i][1]; //y
NumEntries++;
}
/* now remember new ones that are not in memory yet (discovered this time) */
for(psFeature = apsFeatureLists[0]; psFeature != NULL; psFeature = psFeature->psNext)
{
if(psFeature->psStats->subType == FEAT_OIL_RESOURCE)
{
if (psFeature->visible[nPlayer]) //|| godMode)
{
if(!canRecallOilAt(nPlayer, psFeature->pos.x, psFeature->pos.y)) //already stored?
{
/* Save X */
PosXY[NumEntries * 2] = psFeature->pos.x;
/* Save Y */
PosXY[NumEntries * 2 + 1] = psFeature->pos.y;
//printf_console("New oil visible x: %d y: %d. Storing.", PosXY[NumEntries * 2]/128,PosXY[NumEntries * 2 + 1]/128);
NumEntries++;
}
}
}
}
//Save Derricks as oil resources, since most of them will be unoccupied when experiance will be loaded
for(i=0;i<MAX_PLAYERS;i=i+1)
{
for (psCurr = apsStructLists[i]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_RESOURCE_EXTRACTOR)
{
if(psCurr->visible[nPlayer]) //if can see it
{
if(!canRecallOilAt(nPlayer, psCurr->pos.x, psCurr->pos.y)) //already stored?
{
//psResExtractor = (RES_EXTRACTOR *)psCurr->pFunctionality;
x = psCurr->pos.x;
y = psCurr->pos.y;
//printf_console("Found derrick at x: %d, y: %d,, width: %d",psCurr->pos.x/128,psCurr->pos.y/128,mapWidth);
// Save X //
PosXY[NumEntries * 2] = psCurr->pos.x;
// Save Y //
PosXY[NumEntries * 2 + 1] = psCurr->pos.y;
//printf_console("New derrick visible x: %d y: %d. Storing.", PosXY[NumEntries * 2]/128,PosXY[NumEntries * 2 + 1]/128);
NumEntries++;
}
}
}
}
}
/* Write number of Oil Resources */
if(PHYSFS_write(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1) < 1)
{
debug(LOG_ERROR,"WriteAISaveData: failed to write stored oil locations count for player %d",nPlayer);
return false;
}
//printf_console("Num Oil Resources: %d ****",NumEntries);
/* Write Oil Resources coords */
if(NumEntries > 0) //Anything to save
{
if(PHYSFS_write(aiSaveFile[nPlayer], PosXY, sizeof(UDWORD), NumEntries * 2) < (NumEntries * 2))
{
debug(LOG_ERROR,"WriteAISaveData: failed to write oil locations fir player %d",nPlayer);
return false;
}
}
/************************/
/* Fog of War */
/************************/
NumEntries = MAX_OIL_DEFEND_LOCATIONS;
for(i=0;i<mapWidth;i++)
{
for(j=0;j<mapHeight;j++)
{
/* Write tile visibility */
bTileVisible = TEST_TILE_VISIBLE(nPlayer, mapTile(i, j));
if(PHYSFS_write(aiSaveFile[nPlayer], &bTileVisible, sizeof(BOOL), 1) < 1)
{
debug(LOG_ERROR,"WriteAISaveData: failed to write fog of war at tile %d-%d for player %d", i, j, nPlayer);
return false;
}
}
}
}
else
{
debug(LOG_ERROR,"WriteAISaveData(): no output file for player %d",nPlayer);
return false;
}
//printf_console("AI settings file written for player %d",nPlayer);
return PHYSFS_close(aiSaveFile[nPlayer]);
}
BOOL canRecallOilAt(SDWORD nPlayer, SDWORD x, SDWORD y)
{
SDWORD i;
/* go through all remembered oil and check */
for(i=0; i<MAX_OIL_LOCATIONS; i++)
{
if(oilLocation[nPlayer][i][0] != x)
continue;
if(oilLocation[nPlayer][i][1] != y)
continue;
return true; //yep, both matched
}
return false; //no
}
SDWORD ReadAISaveData(SDWORD nPlayer)
{
FEATURE *psFeature;
SDWORD NumEntries=0; //How many derricks/oil resources will be saved
UDWORD PosXY[MAX_OIL_ENTRIES]; //Locations, 0=x,1=y,2=x etc
UDWORD i,j;
BOOL Found,bTileVisible;
UDWORD version;
if(!SetUpInputFile(nPlayer))
{
//debug(LOG_ERROR,"No experience data loaded for %d",nPlayer);
return EXPERIENCE_LOAD_NOSAVE;
}
else
{
/* Read data version */
if (PHYSFS_read(aiSaveFile[nPlayer], &version, sizeof(NumEntries), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to read version number for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
// Check version, assume backward compatibility
if(version > SAVE_FORMAT_VERSION)
{
debug(LOG_ERROR,"ReadAISaveData(): Incompatible version of the learn data (%d, expected %d) for player '%d'", version, SAVE_FORMAT_VERSION, nPlayer);
}
/************************/
/* Enemy bases */
/************************/
/* read max number of players (usually 8) */
if (PHYSFS_read(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to read number of players for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/* read base locations of all players */
if (PHYSFS_read(aiSaveFile[nPlayer], baseLocation[nPlayer], sizeof(SDWORD), NumEntries * 2 ) != (NumEntries * 2) )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load baseLocation for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/************************************/
/* Base attack locations */
/************************************/
/* read MAX_BASE_DEFEND_LOCATIONS */
if (PHYSFS_read(aiSaveFile[nPlayer], &NumEntries, sizeof(SDWORD), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to read MAX_BASE_DEFEND_LOCATIONS for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/* check it's the same as current MAX_BASE_DEFEND_LOCATIONS */
if(NumEntries > MAX_BASE_DEFEND_LOCATIONS)
{
debug(LOG_ERROR, "ReadAISaveData(): saved MAX_BASE_DEFEND_LOCATIONS and current one don't match (%d / %d)", NumEntries, MAX_BASE_DEFEND_LOCATIONS);
return EXPERIENCE_LOAD_ERROR;
}
//debug(LOG_ERROR,"num base attack loc: %d", NumEntries);
/* read base defence locations */
if (PHYSFS_read(aiSaveFile[nPlayer], baseDefendLocation[nPlayer], sizeof(SDWORD), NumEntries * 2 ) != (NumEntries * 2) )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load baseDefendLocation for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/* read base defend priorities */
if (PHYSFS_read(aiSaveFile[nPlayer], baseDefendLocPrior[nPlayer], sizeof(SDWORD), NumEntries * 2 ) != (NumEntries * 2) )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load baseDefendLocPrior for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/************************************/
/* Oil attack locations */
/************************************/
/* read MAX_OIL_DEFEND_LOCATIONS */
if (PHYSFS_read(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to read max number of oil attack locations for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/* check it's the same as current MAX_OIL_DEFEND_LOCATIONS */
if(NumEntries > MAX_OIL_DEFEND_LOCATIONS)
{
debug(LOG_ERROR, "ReadAISaveData(): saved MAX_OIL_DEFEND_LOCATIONS and current one don't match (%d / %d)", NumEntries, MAX_OIL_DEFEND_LOCATIONS);
return EXPERIENCE_LOAD_ERROR;
}
//debug(LOG_ERROR,"num oil attack loc: %d", NumEntries);
/* read oil locations */
if (PHYSFS_read(aiSaveFile[nPlayer], oilDefendLocation[nPlayer], sizeof(SDWORD), NumEntries * 2 ) != (NumEntries * 2) )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load oilDefendLocation for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/* read oil location priority */
if (PHYSFS_read(aiSaveFile[nPlayer], oilDefendLocPrior[nPlayer], sizeof(SDWORD), NumEntries * 2 ) != (NumEntries * 2) )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load oilDefendLocPrior for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/****************************/
/* Oil Resources */
/****************************/
/* read MAX_OIL_LOCATIONS */
if (PHYSFS_read(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load MAX_OIL_LOCATIONS for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
/* check it's the same as current MAX_OIL_LOCATIONS */
if(NumEntries > MAX_OIL_LOCATIONS)
{
debug(LOG_ERROR, "ReadAISaveData(): saved MAX_OIL_LOCATIONS and current one don't match (%d / %d)", NumEntries, MAX_OIL_LOCATIONS);
return EXPERIENCE_LOAD_ERROR;
}
/* Read number of Oil Resources */
if (PHYSFS_read(aiSaveFile[nPlayer], &NumEntries, sizeof(NumEntries), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to read Oil Resources count for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
//debug(LOG_ERROR,"Num oil: %d", NumEntries);
if(NumEntries > 0) //any oil resources were saved?
{
/* Read Oil Resources coordinates */
if (PHYSFS_read(aiSaveFile[nPlayer], PosXY, sizeof(UDWORD), NumEntries * 2 ) != (NumEntries * 2) )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to read Oil Resources coordinates for player '%d'",nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
for(i=0; i<NumEntries; i++)
{
Found = false;
//re-read into remory
if(i < MAX_OIL_LOCATIONS) //didn't max out?
{
oilLocation[nPlayer][i][0] = PosXY[i * 2]; //x
oilLocation[nPlayer][i][1] = PosXY[i * 2 + 1]; //y
}
/* Iterate through all Oil Resources and try to match coordinates */
for(psFeature = apsFeatureLists[0]; psFeature != NULL; psFeature = psFeature->psNext)
{
if(psFeature->psStats->subType == FEAT_OIL_RESOURCE) //Oil resource
{
if (!(psFeature->visible[nPlayer])) //Not visible yet
{
if((PosXY[i * 2] == psFeature->pos.x) && (PosXY[i * 2 + 1] == psFeature->pos.y)) /* Found it */
{
//printf_console("Matched oil resource at x: %d y: %d", PosXY[i * 2]/128,PosXY[i * 2 + 1]/128);
psFeature->visible[nPlayer] = true; //Make visible for AI
Found = true;
break;
}
}
}
}
//if(!Found) //Couldn't find oil resource with this coords on the map
// printf_console("!!Failed to match oil resource #%d at x: %d y: %d", i,PosXY[i * 2]/128,PosXY[i * 2 + 1]/128);
}
/************************/
/* Fog of War */
/************************/
if(version >= 2)
{
for(i=0;i<mapWidth;i++)
{
for(j=0;j<mapWidth;j++)
{
if (PHYSFS_read(aiSaveFile[nPlayer], &bTileVisible, sizeof(BOOL), 1 ) != 1 )
{
debug(LOG_ERROR,"ReadAISaveData(): Failed to load tile visibility at tile %d-%d for player '%d'", i, j, nPlayer);
return EXPERIENCE_LOAD_ERROR;
}
// Restore tile visibility
if(bTileVisible)
{
SET_TILE_VISIBLE(selectedPlayer,mapTile(i,j));
}
}
}
}
}
}
return PHYSFS_close(aiSaveFile[nPlayer]) ? EXPERIENCE_LOAD_OK : EXPERIENCE_LOAD_ERROR;
}
BOOL OilResourceAt(UDWORD OilX,UDWORD OilY, SDWORD VisibleToPlayer)
{
FEATURE *psFeature;
BOOL Found;
/* Iterate through all Oil Resources and try to match coordinates */
for(psFeature = apsFeatureLists[0]; psFeature != NULL; psFeature = psFeature->psNext)
{
if(psFeature->psStats->subType == FEAT_OIL_RESOURCE) //Oil resource
{
if ((VisibleToPlayer < 0) || (!(psFeature->visible[VisibleToPlayer]))) //Not visible yet
{
if((OilX == psFeature->pos.x) && (OilY == psFeature->pos.y)) /* Found it */
{
printf_console("Matched oil resource at x: %d y: %d", OilX/128,OilY/128);
psFeature->visible[VisibleToPlayer] = true; //Make visible for AI
Found = true;
break;
}
}
}
}
return true;
}
//x and y are passed by script, find out if this loc is close to
//an already stored loc, if yes then increase its priority
BOOL StoreBaseDefendLoc(SDWORD x, SDWORD y, SDWORD nPlayer)
{
SDWORD i, index;
BOOL found;
index = GetBaseDefendLocIndex(x, y, nPlayer);
if(index < 0) //this one is new
{
//find an empty element
found = false;
for(i=0; i < MAX_BASE_DEFEND_LOCATIONS; i++)
{
if(baseDefendLocation[nPlayer][i][0] < 0) //not initialized yet
{
//addConsoleMessage("Base defense location - NEW LOCATION.", RIGHT_JUSTIFY,SYSTEM_MESSAGE);
baseDefendLocation[nPlayer][i][0] = x;
baseDefendLocation[nPlayer][i][1] = y;
baseDefendLocPrior[nPlayer][i] = 1;
found = true;
return true;
}
}
addConsoleMessage("Base defense location - NO SPACE LEFT.",RIGHT_JUSTIFY,SYSTEM_MESSAGE);
return false; //not enough space to store
}
else //this one already stored
{
//addConsoleMessage("Base defense location - INCREASED PRIORITY.",SYSTEM_MESSAGE);
baseDefendLocPrior[nPlayer][index]++; //higher the priority
if(baseDefendLocPrior[nPlayer][index] == SDWORD_MAX)
baseDefendLocPrior[nPlayer][index] = 1; //start all over
SortBaseDefendLoc(nPlayer); //now sort everything
}
return true;
}
SDWORD GetBaseDefendLocIndex(SDWORD x, SDWORD y, SDWORD nPlayer)
{
UDWORD i,range;
range = world_coord(SAME_LOC_RANGE); //in world units
for(i=0; i < MAX_BASE_DEFEND_LOCATIONS; i++)
{
if((baseDefendLocation[nPlayer][i][0] > 0) && (baseDefendLocation[nPlayer][i][1] > 0)) //if this one initialized
{
//check if very close to an already stored location
if(dirtySqrt(x,y,baseDefendLocation[nPlayer][i][0],baseDefendLocation[nPlayer][i][1]) < range)
{
return i; //end here
}
}
}
return -1;
}
//sort the priorities, placing the higher ones at the top
BOOL SortBaseDefendLoc(SDWORD nPlayer)
{
SDWORD i, prior, temp,LowestPrior,LowestIndex,SortBound;
SortBound = MAX_BASE_DEFEND_LOCATIONS-1; //nothing sorted yet, point at last elem
while(SortBound >= 0) //while didn't reach the top
{
LowestPrior = (SDWORD_MAX - 1);
LowestIndex = -1;
//find lowest element
for(i=0; i <= SortBound; i++)
{
prior = baseDefendLocPrior[nPlayer][i];
if(prior < LowestPrior) //lower and isn't a flag meaning this one wasn't initialized with anything
{
LowestPrior = prior;
LowestIndex = i;
}
}
//huh, nothing found? (probably nothing set yet, no experience)
if(LowestIndex < 0)
{
//debug(LOG_ERROR,"sortBaseDefendLoc() - No lowest elem found");
return true;
}
//swap
if(LowestPrior < baseDefendLocPrior[nPlayer][SortBound]) //need to swap? (might be the same elem)
{
//priority
temp = baseDefendLocPrior[nPlayer][SortBound];
baseDefendLocPrior[nPlayer][SortBound] = baseDefendLocPrior[nPlayer][LowestIndex];
baseDefendLocPrior[nPlayer][LowestIndex] = temp;
//x
temp = baseDefendLocation[nPlayer][SortBound][0];
baseDefendLocation[nPlayer][SortBound][0] = baseDefendLocation[nPlayer][LowestIndex][0];
baseDefendLocation[nPlayer][LowestIndex][0] = temp;
//y
temp = baseDefendLocation[nPlayer][SortBound][1];
baseDefendLocation[nPlayer][SortBound][1] = baseDefendLocation[nPlayer][LowestIndex][1];
baseDefendLocation[nPlayer][LowestIndex][1] = temp;
}
SortBound--; //in any case lower the boundry, even if didn't swap
}
return true;
}
void BaseExperienceDebug(SDWORD nPlayer)
{
SDWORD i;
printf_console("-------------");
for(i=0; i< MAX_BASE_DEFEND_LOCATIONS; i++)
{
printf_console("%d) %d - %d (%d)", i, map_coord(baseDefendLocation[nPlayer][i][0]), map_coord(baseDefendLocation[nPlayer][i][1]), baseDefendLocPrior[nPlayer][i]);
}
printf_console("-------------");
}
void OilExperienceDebug(SDWORD nPlayer)
{
SDWORD i;
printf_console("-------------");
for(i=0; i< MAX_OIL_DEFEND_LOCATIONS; i++)
{
printf_console("%d) %d - %d (%d)", i, map_coord(oilDefendLocation[nPlayer][i][0]), map_coord(oilDefendLocation[nPlayer][i][1]), oilDefendLocPrior[nPlayer][i]);
}
printf_console("-------------");
}
//x and y are passed by script, find out if this loc is close to
//an already stored loc, if yes then increase its priority
BOOL StoreOilDefendLoc(SDWORD x, SDWORD y, SDWORD nPlayer)
{
SDWORD i, index;
BOOL found;
index = GetOilDefendLocIndex(x, y, nPlayer);
if(index < 0) //this one is new
{
//find an empty element
found = false;
for(i=0; i < MAX_OIL_DEFEND_LOCATIONS; i++)
{
if(oilDefendLocation[nPlayer][i][0] < 0) //not initialized yet
{
//addConsoleMessage("Oil defense location - NEW LOCATION.", SYSTEM_MESSAGE);
oilDefendLocation[nPlayer][i][0] = x;
oilDefendLocation[nPlayer][i][1] = y;
oilDefendLocPrior[nPlayer][i] = 1;
found = true;
return true;
}
}
addConsoleMessage("Oil defense location - NO SPACE LEFT.",RIGHT_JUSTIFY,SYSTEM_MESSAGE);
return false; //not enough space to store
}
else //this one already stored
{
//addConsoleMessage("Oil defense location - INCREASED PRIORITY.",SYSTEM_MESSAGE);
oilDefendLocPrior[nPlayer][index]++; //higher the priority
if(oilDefendLocPrior[nPlayer][index] == SDWORD_MAX)
oilDefendLocPrior[nPlayer][index] = 1; //start all over
SortOilDefendLoc(nPlayer); //now sort everything
}
return true;
}
SDWORD GetOilDefendLocIndex(SDWORD x, SDWORD y, SDWORD nPlayer)
{
UDWORD i,range;
range = world_coord(SAME_LOC_RANGE); //in world units
for(i=0; i < MAX_OIL_DEFEND_LOCATIONS; i++)
{
if((oilDefendLocation[nPlayer][i][0] > 0) && (oilDefendLocation[nPlayer][i][1] > 0)) //if this one initialized
{
//check if very close to an already stored location
if(dirtySqrt(x,y,oilDefendLocation[nPlayer][i][0],oilDefendLocation[nPlayer][i][1]) < range)
{
return i; //end here
}
}
}
return -1;
}
//sort the priorities, placing the higher ones at the top
BOOL SortOilDefendLoc(SDWORD nPlayer)
{
SDWORD i, prior, temp,LowestPrior,LowestIndex,SortBound;
SortBound = MAX_OIL_DEFEND_LOCATIONS-1; //nothing sorted yet, point at last elem
while(SortBound >= 0) //while didn't reach the top
{
LowestPrior = (SDWORD_MAX - 1);
LowestIndex = -1;
//find lowest element
for(i=0; i <= SortBound; i++)
{
prior = oilDefendLocPrior[nPlayer][i];
if(prior < LowestPrior) //lower and isn't a flag meaning this one wasn't initialized with anything
{
LowestPrior = prior;
LowestIndex = i;
}
}
//huh, nothing found? (probably nothing set yet, no experience)
if(LowestIndex < 0)
{
//debug(LOG_ERROR,"sortBaseDefendLoc() - No lowest elem found");
return true;
}
//swap
if(LowestPrior < oilDefendLocPrior[nPlayer][SortBound]) //need to swap? (might be the same elem)
{
//priority
temp = oilDefendLocPrior[nPlayer][SortBound];
oilDefendLocPrior[nPlayer][SortBound] = oilDefendLocPrior[nPlayer][LowestIndex];
oilDefendLocPrior[nPlayer][LowestIndex] = temp;
//x
temp = oilDefendLocation[nPlayer][SortBound][0];
oilDefendLocation[nPlayer][SortBound][0] = oilDefendLocation[nPlayer][LowestIndex][0];
oilDefendLocation[nPlayer][LowestIndex][0] = temp;
//y
temp = oilDefendLocation[nPlayer][SortBound][1];
oilDefendLocation[nPlayer][SortBound][1] = oilDefendLocation[nPlayer][LowestIndex][1];
oilDefendLocation[nPlayer][LowestIndex][1] = temp;
}
SortBound--; //in any case lower the boundry, even if didn't swap
}
return true;
}
BOOL CanRememberPlayerBaseLoc(SDWORD lookingPlayer, SDWORD enemyPlayer)
{
if(lookingPlayer < 0 || enemyPlayer < 0)
return false;
if(lookingPlayer >= MAX_PLAYERS || enemyPlayer >= MAX_PLAYERS)
return false;
if(baseLocation[lookingPlayer][enemyPlayer][0] <= 0)
return false;
if(baseLocation[lookingPlayer][enemyPlayer][1] <= 0)
return false;
return true;
}
BOOL CanRememberPlayerBaseDefenseLoc(SDWORD player, SDWORD index)
{
if(player < 0)
return false;
if(player >= MAX_PLAYERS)
return false;
if(index < 0 || index >= MAX_BASE_DEFEND_LOCATIONS)
return false;
if(baseDefendLocation[player][index][0] <= 0)
return false;
if(baseDefendLocation[player][index][1] <= 0)
return false;
return true;
}
BOOL CanRememberPlayerOilDefenseLoc(SDWORD player, SDWORD index)
{
if(player < 0)
return false;
if(player >= MAX_PLAYERS)
return false;
if(index < 0 || index >= MAX_BASE_DEFEND_LOCATIONS)
return false;
if(oilDefendLocation[player][index][0] <= 0)
return false;
if(oilDefendLocation[player][index][1] <= 0)
return false;
return true;
}