<-- -->

Free Web Hosting : Free Hosting : Troubled Teens : Report Abuse

Code Examples

Last update: Civ-Evo 0.6.5

Forum | Index

Saving data

Basic saving implementation:

//data types
const
  dRndSeed=0;	//random number generator seed
  dOldMoney=1;	//income from previous turn so can calculate change.
//size is in dwords (multiple of 4 bytes).
function TStdAI.SaveData(dtype,size:integer; var data):integer;    //result=ok
begin
  result:=eInvalid;
  if not(loading) then      //probably ok to set loading:=false here
  begin
    if size>15 then exit;
    if dtype>=(65536-CClientEx) shr 4 then exit;
    result:=Server(CClientEx+(dtype shl 4)+size,me,0,data);
  end;
end;

The save command accepts data like this:

Command:0-2047, (size=0-15 must match data size), data 0-15 words (0-60 bytes).

In the example implementation, the Command part is used to store the type of the save data - this is convenient for loading if you need to save more than one type of data.

To load data you need to handle CClientEx messages in your Client() function,

case Command of
  ...
  else
    if command>=CClientEx then         //possibly saved data
      if AI[Player]<>nil then
        AI[PLayer].LoadData(command-CClientEx,data);

You will also receive CClientEx messages every time you save data (the saved message will be echoed back). To know which messages are real and which are echoes you need to know if the game is loading data.

If you use a flag to detect when the game is loading you can set it to true when you get the message cLoadGame and clear it on cTurn (before executing any AI players). cGetReady is not suitable because it is sent before data is loaded.

Here is an example of a loading routine.

procedure TStdAI.LoadData(command:integer; var data);
var
  datasize,datatype:integer;
begin
  if loading then  //will be echo called when savedata() is called.
  begin
    datasize:=command mod 16;    //0...15 dwords
    datatype:=command shr 4;     //0...(65535-CClientEx)shr 4
    //do stuff with saved data
    case datatype of
      dRndSeed:
        RndSeed:=integer(data);	 //cast to the appropriate type.
      dOldMoney:
        OldMoney:=integer(data);
    end;
  end;
end;

Spherical Distance Calculation

The map wraps over at the East and West "edges". To find the minimum spherical distance between two points (and the vector) you test if the vector magnitude is greater than the maximum spherical magnitude and if so (ie if there is a shorter spherical vector) transform the vector to the shorter spherical vector.

This implementation is correct for most cases:

implementation
  uses Linear, Protocol, AIClasses;	//Linear is from AILib
//returns the distance squared. (Linear spherical vector calculated in dx,dy)
function Distance(FromLoc, ToLoc: CLocation): integer;
var
  dx,dy: integer;
begin
  dx:=rLoc(Toloc.loc).x-rLoc(FromLoc.loc).x;
  dy:=rLoc(Toloc.loc).y-rLoc(FromLoc.loc).y;
  //spherical overflow can occur in the direction (1,1) and (-1,-1)
  //if the distance>lx div 2 in those directions, spherical overflow occured
  if (dx>0) and (dy>0) then
  begin
    if dx>dy then        //dy,dy main
    begin
      if dy>g.lx div 2 then begin dy:=g.lx-dy; dx:=g.lx-dx; end;
    end else //dx,dx main
      if dx>g.lx div 2 then begin dy:=g.lx-dy; dx:=g.lx-dx; end;
  end;
  if (dx<0) and (dy<0) then
  begin
    if dx<dy then        //dy,dy main
    begin
      if dy<(-g.lx div 2) then begin dy:=g.lx+dy; dx:=g.lx+dx; end;
    end else //dx,dx main
      if dx<(-g.lx div 2) then begin dy:=g.lx+dy; dx:=g.lx+dx; end;
  end;
  result:=dx*dx+dy*dy;
end;


Top