Added initial support for game replay

This commit is contained in:
jsalmon3 2002-08-01 16:22:02 +00:00
parent 61803751eb
commit 24a33f940d
5 changed files with 793 additions and 38 deletions

View file

@ -32,12 +32,19 @@
-- Variables
----------------------------------------------------------------------------*/
extern int CommandLogEnabled; /// True, if command log is on
extern int CommandLogDisabled; /// True, if command log is off
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/// Replay user commands from log each cycle
extern void ReplayEachCycle(void);
/// Load replay
extern int LoadReplay(char* name);
/// End logging
extern void EndReplayLog(void);
/*
** The send command functions sends a command, if needed over the
** Network, this is only for user commands. Automatic reactions which

View file

@ -44,6 +44,10 @@
#include "network.h"
#include "netconnect.h"
#include "campaign.h" // for CurrentMapPath
#include "ccl.h"
#include "commands.h"
#include "interface.h"
#include "iocompat.h"
//----------------------------------------------------------------------------
// Declaration
@ -53,7 +57,12 @@
// Variables
//----------------------------------------------------------------------------
global int CommandLogEnabled; /// True if command log is on
global int CommandLogDisabled; /// True if command log is off
local int DisabledLog; /// Disabled log for replay
local SCM ReplayLog; /// Replay log
local FILE* LogFile; /// Replay log file
local int NextLogCycle; /// Next log cycle number
//----------------------------------------------------------------------------
// Log commands
@ -79,9 +88,7 @@ global int CommandLogEnabled; /// True if command log is on
local void CommandLog(const char* name,const Unit* unit,int flag,
unsigned x,unsigned y,const Unit* dest,const char* value,int num)
{
static FILE* logf;
if( !CommandLogEnabled ) { // No log wanted
if( CommandLogDisabled ) { // No log wanted
return;
}
@ -89,15 +96,25 @@ local void CommandLog(const char* name,const Unit* unit,int flag,
// Create and write header of log file. The player number is added
// to the save file name, to test more than one player on one computer.
//
if( !logf ) {
if( !LogFile ) {
time_t now;
char buf[256];
char buf[PATH_MAX];
char* s;
char* s1;
sprintf(buf,"log_of_freecraft_%d.log",ThisPlayer->Player);
logf=fopen(buf,"wb");
if( !logf ) {
#ifdef USE_WIN32
strcpy(buf,"logs");
mkdir(buf);
#else
sprintf(buf,"%s/%s",getenv("HOME"),FREECRAFT_HOME_PATH);
mkdir(buf,0777);
strcat(buf,"/logs");
mkdir(buf,0777);
#endif
sprintf(buf,"%s/log_of_freecraft_%d.log",buf,ThisPlayer->Player);
LogFile=fopen(buf,"wb");
if( !LogFile ) {
return;
}
@ -109,34 +126,35 @@ local void CommandLog(const char* name,const Unit* unit,int flag,
//
// Parseable header
// TODO: add custom start options (eg high resources, game type, etc)
//
fprintf(logf,";;;(replay-log\n");
fprintf(logf,";;; 'comment\t\"Generated by FreeCraft Version " VERSION "\"\n");
fprintf(logf,";;; 'comment\t\"Visit http://FreeCraft.Org for more informations\"\n");
fprintf(logf,";;; 'comment\t\"$Id$\"\n");
fprintf(logf,";;; 'type\t\"%s\"\n","single-player");
fprintf(logf,";;; 'date\t\"%s\"\n",s);
fprintf(logf,";;; 'map\t\"%s\"\n",TheMap.Description);
fprintf(logf,";;; 'map-id\t%u\n",TheMap.Info->MapUID);
fprintf(logf,";;; 'map-path\t\"%s\"\n",CurrentMapPath);
fprintf(logf,";;; 'engine\t'(%d %d %d)\n",
fprintf(LogFile,"(replay-log\n");
fprintf(LogFile," 'comment\t\"Generated by FreeCraft Version " VERSION "\"\n");
fprintf(LogFile," 'comment\t\"Visit http://FreeCraft.Org for more informations\"\n");
fprintf(LogFile," 'comment\t\"$Id$\"\n");
fprintf(LogFile," 'type\t\"%s\"\n","single-player");
fprintf(LogFile," 'date\t\"%s\"\n",s);
fprintf(LogFile," 'map\t\"%s\"\n",TheMap.Description);
fprintf(LogFile," 'map-id\t%u\n",TheMap.Info->MapUID);
fprintf(LogFile," 'map-path\t\"%s\"\n",CurrentMapPath);
fprintf(LogFile," 'engine\t'(%d %d %d)\n",
FreeCraftMajorVersion,FreeCraftMinorVersion,FreeCraftPatchLevel);
fprintf(logf,";;; 'network\t'(%d %d %d)\n",
fprintf(LogFile," 'network\t'(%d %d %d)\n",
NetworkProtocolMajorVersion,
NetworkProtocolMinorVersion,
NetworkProtocolPatchLevel);
fprintf(logf,";;; )\n");
fprintf(LogFile," )\n");
}
//
// Frame, unit, (type-ident only to be better readable).
//
if( unit ) {
fprintf(logf,"(log %lu 'U%d '%s '%s '%s",
fprintf(LogFile,"(log %lu 'unit %d 'ident '%s 'name '%s 'flag '%s",
GameCycle,UnitNumber(unit),unit->Type->Ident,name,
flag ? "flush" : "append");
} else {
fprintf(logf,"(log %lu '%s '%s",
fprintf(LogFile,"(log %lu 'name '%s 'flag '%s",
GameCycle,name, flag ? "flush" : "append");
}
@ -144,35 +162,325 @@ local void CommandLog(const char* name,const Unit* unit,int flag,
// Coordinates given.
//
if( x!=-1 || y!=-1 ) {
fprintf(logf," '(%d %d)",x,y);
fprintf(LogFile," 'pos '(%d %d)",x,y);
}
//
// Destination given.
//
if( dest ) {
fprintf(logf," 'U%d",UnitNumber(dest));
fprintf(LogFile," 'dest '%d",UnitNumber(dest));
}
//
// Value given.
//
if( value ) {
fprintf(logf," '%s",value);
fprintf(LogFile," 'value '%s",value);
}
//
// Number given.
//
if( num!=-1 ) {
fprintf(logf," %d",num);
fprintf(LogFile," 'num %d",num);
}
if( unit ) {
fprintf(logf,") ;%d:%d %X",unit->Player->Player,unit->Refs,
fprintf(LogFile,") ;%d:%d %X",unit->Player->Player,unit->Refs,
SyncRandSeed);
} else {
fprintf(logf,") ;-:- %X",SyncRandSeed);
fprintf(LogFile,") ;-:- %X",SyncRandSeed);
}
fprintf(logf,"\n");
fflush(logf);
fprintf(LogFile,"\n");
fflush(LogFile);
}
/**
**
*/
local SCM CclLog(SCM list)
{
SCM var;
var=gh_symbol2scm("*replay_log*");
if( gh_null_p(symbol_value(var,NIL)) ) {
setvar(var,cons(list,NIL),NIL);
} else {
SCM tmp;
tmp=symbol_value(var,NIL);
while( !gh_null_p(gh_cdr(tmp)) ) {
tmp=gh_cdr(tmp);
}
setcdr(tmp,cons(list,NIL));
}
return SCM_UNSPECIFIED;
}
/**
**
*/
local SCM CclReplayLog(SCM list)
{
SCM value;
SCM sublist;
const char* comment;
const char* logtype;
const char* logdate;
const char* map;
unsigned int mapid;
const char* mappath;
int ever1;
int ever2;
int ever3;
int nver1;
int nver2;
int nver3;
while( !gh_null_p(list) ) {
value=gh_car(list);
list=gh_cdr(list);
if( gh_eq_p(value,gh_symbol2scm("comment")) ) {
comment=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("type")) ) {
logtype=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("date")) ) {
logdate=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("map")) ) {
map=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("map-id")) ) {
mapid=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("map-path")) ) {
mappath=get_c_string(gh_car(list));
strcpy(CurrentMapPath,mappath);
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("engine")) ) {
sublist=gh_car(list);
ever1=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
ever2=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
ever3=gh_scm2int(gh_car(sublist));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("network")) ) {
sublist=gh_car(list);
nver1=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
nver2=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
nver3=gh_scm2int(gh_car(sublist));
list=gh_cdr(list);
}
}
return SCM_UNSPECIFIED;
}
/**
** Load a log file to replay a game
**
** @param name name of file to load.
*/
global int LoadReplay(char* name)
{
gh_new_procedureN("log",CclLog);
gh_new_procedureN("replay-log",CclReplayLog);
gh_define("*replay_log*",NIL);
vload(name,0,1);
ReplayLog=symbol_value(gh_symbol2scm("*replay_log*"),NIL);
NextLogCycle=-1;
if( !CommandLogDisabled ) {
CommandLogDisabled=1;
DisabledLog=1;
}
return 0;
}
/**
** End logging
*/
global void EndReplayLog(void)
{
if( LogFile ) {
fclose(LogFile);
LogFile=NULL;
}
if( DisabledLog ) {
CommandLogDisabled=0;
DisabledLog=0;
}
}
/**
** Do next replay
*/
local void DoNextReplay(void)
{
SCM value;
SCM list;
int unit;
const char* ident;
const char* name;
const char* flag;
int flags;
int posx;
int posy;
int dest;
const char* val;
int num;
list=gh_car(ReplayLog);
NextLogCycle=gh_scm2int(gh_car(list));
list=gh_cdr(list);
if( NextLogCycle!=GameCycle ) {
return;
}
NextLogCycle=-1;
unit=-1;
name=NULL;
flags=0;
posx=-1;
posy=-1;
dest=-1;
val=NULL;
num=-1;
while( !gh_null_p(list) ) {
value=gh_car(list);
list=gh_cdr(list);
if( gh_eq_p(value,gh_symbol2scm("unit")) ) {
unit=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("ident")) ) {
ident=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("name")) ) {
name=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("flag")) ) {
flag=get_c_string(gh_car(list));
if( !strcmp(flag,"flush") ) {
flags=1;
}
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("pos")) ) {
SCM sublist;
sublist=gh_car(list);
posx=gh_scm2int(gh_car(sublist));
sublist=gh_cdr(sublist);
posy=gh_scm2int(gh_car(sublist));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("dest")) ) {
dest=gh_scm2int(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("value")) ) {
val=get_c_string(gh_car(list));
list=gh_cdr(list);
} else if( gh_eq_p(value,gh_symbol2scm("num")) ) {
num=gh_scm2int(gh_car(list));
list=gh_cdr(list);
}
}
if( !strcmp(name,"stop") ) {
SendCommandStopUnit(Units[unit]);
} else if( !strcmp(name,"stand-ground") ) {
SendCommandStandGround(Units[unit],flags);
} else if( !strcmp(name,"follow") ) {
SendCommandFollow(Units[unit],Units[dest],flags);
} else if( !strcmp(name,"move") ) {
SendCommandMove(Units[unit],posx,posy,flags);
} else if( !strcmp(name,"repair") ) {
SendCommandRepair(Units[unit],posx,posy,Units[dest],flags);
} else if( !strcmp(name,"attack") ) {
SendCommandAttack(Units[unit],posx,posy,Units[dest],flags);
} else if( !strcmp(name,"attack-ground") ) {
SendCommandAttackGround(Units[unit],posx,posy,flags);
} else if( !strcmp(name,"patrol") ) {
SendCommandPatrol(Units[unit],posx,posy,flags);
} else if( !strcmp(name,"board") ) {
SendCommandBoard(Units[unit],posx,posy,Units[dest],flags);
} else if( !strcmp(name,"unload") ) {
SendCommandUnload(Units[unit],posx,posy,dest!=-1?Units[dest]:NoUnitP,flags);
} else if( !strcmp(name,"build") ) {
SendCommandBuildBuilding(Units[unit],posx,posy,UnitTypeByIdent(val),flags);
} else if( !strcmp(name,"cancel-build") ) {
SendCommandCancelBuilding(Units[unit],Units[dest]);
} else if( !strcmp(name,"harvest") ) {
SendCommandHarvest(Units[unit],posx,posy,flags);
} else if( !strcmp(name,"mine") ) {
SendCommandMineGold(Units[unit],Units[dest],flags);
} else if( !strcmp(name,"haul") ) {
SendCommandHaulOil(Units[unit],Units[dest],flags);
} else if( !strcmp(name,"return") ) {
SendCommandReturnGoods(Units[unit],Units[dest],flags);
} else if( !strcmp(name,"train") ) {
SendCommandTrainUnit(Units[unit],UnitTypeByIdent(val),flags);
} else if( !strcmp(name,"cancel-train") ) {
SendCommandCancelTraining(Units[unit],num,UnitTypeByIdent(val));
} else if( !strcmp(name,"upgrade-to") ) {
SendCommandUpgradeTo(Units[unit],UnitTypeByIdent(val),flags);
} else if( !strcmp(name,"cancel-upgrade-to") ) {
SendCommandCancelUpgradeTo(Units[unit]);
} else if( !strcmp(name,"research") ) {
SendCommandResearch(Units[unit],UpgradeByIdent(val),flags);
} else if( !strcmp(name,"cancel-research") ) {
SendCommandCancelResearch(Units[unit]);
} else if( !strcmp(name,"demolish") ) {
SendCommandDemolish(Units[unit],posx,posy,Units[dest],flags);
} else if( !strcmp(name,"spell-cast") ) {
SendCommandSpellCast(Units[unit],posx,posy,Units[dest],num,flags);
} else if( !strcmp(name,"diplomacy") ) {
int state;
if( !strcmp(val,"neutral") ) {
state=DiplomacyNeutral;
} else if( !strcmp(val,"allied") ) {
state=DiplomacyAllied;
} else if( !strcmp(val,"enemy") ) {
state=DiplomacyEnemy;
} else if( !strcmp(val,"crazy") ) {
state=DiplomacyCrazy;
} else {
DebugLevel0Fn("Invalid diplomacy command: %s" _C_ val);
state=-1;
}
SendCommandDiplomacy(posx,state,posy);
} else {
DebugLevel0Fn("Invalid name: %s" _C_ name);
}
ReplayLog=gh_cdr(ReplayLog);
}
/**
** Replay user commands from log each cycle
*/
global void ReplayEachCycle(void)
{
if( gh_null_p(ReplayLog) ) {
return;
}
if( NextLogCycle!=-1 && NextLogCycle!=GameCycle ) {
return;
}
do {
DoNextReplay();
} while( !gh_null_p(ReplayLog) && (NextLogCycle==-1 || NextLogCycle==GameCycle) );
if( gh_null_p(ReplayLog) ) {
SetMessage("End of replay");
}
}
//@}

View file

@ -58,6 +58,7 @@
#include "campaign.h"
#include "sound_server.h"
#include "settings.h"
#include "commands.h"
#if defined(USE_SDLCD) || defined(USE_LIBCDA)
#include "sound_server.h"
@ -740,6 +741,7 @@ global void GameMainLoop(void)
fprintf(stderr,"FIXME: *** round robin ***\n");
fprintf(stderr,"FIXME: *** round robin ***\n");
}
ReplayEachCycle();
NetworkCommands(); // Get network commands
UnitActions(); // handle units
MissileActions(); // handle missiles
@ -865,6 +867,7 @@ global void GameMainLoop(void)
// Game over
//
NetworkQuit();
EndReplayLog();
if( GameResult==GameDefeat ) {
fprintf(stderr,"You have lost!\n");
SetStatusLine("You have lost!");

View file

@ -1339,7 +1339,7 @@ global int main(int argc,char** argv)
AiCostFactor=atoi(optarg);
continue;
case 'l':
CommandLogEnabled=1;
CommandLogDisabled=1;
continue;
case 'P':
NetworkPort=atoi(optarg);

View file

@ -62,6 +62,7 @@
#include "sound.h"
#include "ccl.h"
#include "editor.h"
#include "commands.h"
#if defined(USE_SDLCD) || defined(USE_SDLA)
#include "SDL.h"
@ -279,6 +280,18 @@ local void EditorSaveConfirmOk(void);
local void EditorSaveConfirmCancel(void);
local void EditorQuitMenu(void);
local void ReplayGameMenu(void);
local void ReplayGameInit(Menuitem *mi);
local void ReplayGameLBInit(Menuitem *mi);
local void ReplayGameLBExit(Menuitem *mi);
local int ReplayGameRDFilter(char *pathbuf, FileList *fl);
local void ReplayGameLBAction(Menuitem *mi, int i);
local unsigned char *ReplayGameLBRetrieve(Menuitem *mi, int i);
local void ReplayGameVSAction(Menuitem *mi, int i);
local void ReplayGameFolder(void);
local void ReplayGameOk(void);
local void ReplayGameCancel(void);
/*----------------------------------------------------------------------------
-- Variables
----------------------------------------------------------------------------*/
@ -580,6 +593,18 @@ global void InitMenuFuncHash(void) {
HASHADD(EditorSaveConfirmInit,"editor-save-confirm-init");
HASHADD(EditorSaveConfirmOk,"editor-save-confirm-ok");
HASHADD(EditorSaveConfirmCancel,"editor-save-confirm-cancel");
// Replay game
HASHADD(ReplayGameMenu,"replay-game-menu");
HASHADD(ReplayGameInit,"replay-game-init");
HASHADD(ReplayGameLBInit,"replay-game-lb-init");
HASHADD(ReplayGameLBExit,"replay-game-lb-exit");
HASHADD(ReplayGameLBAction,"replay-game-lb-action");
HASHADD(ReplayGameLBRetrieve,"replay-game-lb-retrieve");
HASHADD(ReplayGameVSAction,"replay-game-vs-action");
HASHADD(ReplayGameFolder,"replay-game-folder");
HASHADD(ReplayGameOk,"replay-game-ok");
HASHADD(ReplayGameCancel,"replay-game-cancel");
}
/*----------------------------------------------------------------------------
@ -905,7 +930,8 @@ local void SaveVSAction(Menuitem *mi, int i)
}
DebugCheck(mi->d.listbox.startline < 0);
DebugCheck(mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
DebugCheck(mi->d.listbox.noptions > 0 &&
mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
SaveLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
MustRedraw |= RedrawMenu;
@ -1178,7 +1204,8 @@ local void LoadVSAction(Menuitem *mi, int i)
}
DebugCheck(mi->d.listbox.startline < 0);
DebugCheck(mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
DebugCheck(mi->d.listbox.noptions > 0 &&
mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
LoadLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
MustRedraw |= RedrawMenu;
@ -2842,7 +2869,8 @@ local void ScenSelectVSAction(Menuitem *mi, int i)
}
DebugCheck(mi->d.listbox.startline < 0);
DebugCheck(mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
DebugCheck(mi->d.listbox.noptions > 0 &&
mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
ScenSelectLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
MustRedraw |= RedrawMenu;
@ -4668,7 +4696,8 @@ local void EditorMainLoadVSAction(Menuitem *mi, int i)
}
DebugCheck(mi->d.listbox.startline < 0);
DebugCheck(mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
DebugCheck(mi->d.listbox.noptions > 0 &&
mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
EditorMainLoadLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
MustRedraw |= RedrawMenu;
@ -5344,7 +5373,8 @@ local void EditorSaveVSAction(Menuitem *mi, int i)
}
DebugCheck(mi->d.listbox.startline < 0);
DebugCheck(mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
DebugCheck(mi->d.listbox.noptions > 0 &&
mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
EditorSaveLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
MustRedraw |= RedrawMenu;
@ -5416,6 +5446,413 @@ local void EditorEndMenu(void)
MustRedraw = RedrawMenu;
}
/**
** Replay game menu
*/
local void ReplayGameMenu(void)
{
char buf[PATH_MAX];
#ifdef USE_WIN32
strcpy(buf,"logs");
mkdir(buf);
sprintf(ScenSelectPath, "logs/");
#else
sprintf(buf,"%s/%s",getenv("HOME"),FREECRAFT_HOME_PATH);
mkdir(buf,0777);
strcat(buf,"/logs");
mkdir(buf,0777);
sprintf(ScenSelectPath,"%s/%s/logs/", getenv("HOME"), FREECRAFT_HOME_PATH);
#endif
*ScenSelectDisplayPath = '\0';
VideoLockScreen();
VideoClearScreen();
MenusSetBackground();
VideoUnlockScreen();
Invalidate();
GuiGameStarted = 0;
ProcessMenu("menu-replay-game",1);
if (GuiGameStarted) {
GameMenuReturn();
}
}
/**
** Replay game menu init callback
*/
local void ReplayGameInit(Menuitem *mi)
{
DebugCheck(!*ScenSelectPath);
mi->menu->items[5].flags =
*ScenSelectDisplayPath ? 0 : MenuButtonDisabled;
mi->menu->items[5].d.button.text = ScenSelectDisplayPath;
DebugLevel0Fn("Start path: %s\n" _C_ ScenSelectPath);
}
/**
** Replay game listbox init callback
*/
local void ReplayGameLBInit(Menuitem *mi)
{
int i;
ReplayGameLBExit(mi);
i = mi->d.listbox.noptions = ReadDataDirectory(ScenSelectPath, ReplayGameRDFilter,
(FileList **)&(mi->d.listbox.options));
if (i == 0) {
mi->menu->items[3].d.button.text = "OK";
mi->menu->items[3].flags |= MenuButtonDisabled;
} else {
ReplayGameLBAction(mi, 0);
mi->menu->items[3].flags &= ~MenuButtonDisabled;
if (i > 5) {
mi[1].flags &= ~MenuButtonDisabled;
}
}
}
/**
** Replay game listbox exit callback
*/
local void ReplayGameLBExit(Menuitem *mi)
{
FileList *fl;
if (mi->d.listbox.noptions) {
fl = mi->d.listbox.options;
free(fl);
mi->d.listbox.options = NULL;
mi->d.listbox.noptions = 0;
mi[1].flags |= MenuButtonDisabled;
}
}
/**
** Replay game read directory filter
*/
local int ReplayGameRDFilter(char *pathbuf, FileList *fl)
{
char *suf;
char *np;
char *cp;
char *lcp;
#ifdef USE_ZZIPLIB
int sz;
ZZIP_FILE *zzf;
#endif
suf = ".log";
np = strrchr(pathbuf, '/');
if (np) {
np++;
} else {
np = pathbuf;
}
cp = np;
cp--;
fl->type = -1;
#ifdef USE_ZZIPLIB
if ((zzf = zzip_open(pathbuf, O_RDONLY|O_BINARY))) {
sz = zzip_file_real(zzf);
zzip_close(zzf);
if (!sz) {
goto usezzf;
}
}
#endif
do {
lcp = cp++;
cp = strcasestr(cp, suf);
} while (cp != NULL);
if (lcp >= np) {
cp = lcp + strlen(suf);
#ifdef USE_ZLIB
if (strcmp(cp, ".gz") == 0) {
*cp = 0;
}
#endif
#ifdef USE_BZ2LIB
if (strcmp(cp, ".bz2") == 0) {
*cp = 0;
}
#endif
if (*cp == 0) {
#ifdef USE_ZZIPLIB
usezzf:
#endif
if (strcasestr(pathbuf, ".log")) {
fl->type = 1;
fl->name = strdup(np);
return 1;
}
}
}
return 0;
}
/**
** Replay game listbox action
*/
local void ReplayGameLBAction(Menuitem *mi, int i)
{
FileList *fl;
DebugCheck(i<0);
if (i < mi->d.listbox.noptions) {
fl = mi->d.listbox.options;
if (fl[i].type) {
mi->menu->items[3].d.button.text = "OK";
} else {
mi->menu->items[3].d.button.text = "Open";
}
if (mi->d.listbox.noptions > 5) {
mi[1].d.vslider.percent = (i * 100) / (mi->d.listbox.noptions - 1);
mi[1].d.hslider.percent = (i * 100) / (mi->d.listbox.noptions - 1);
}
}
}
/**
** Replay game listbox retrieve
*/
local unsigned char *ReplayGameLBRetrieve(Menuitem *mi, int i)
{
FileList *fl;
static char buffer[1024];
if (i < mi->d.listbox.noptions) {
fl = mi->d.listbox.options;
if (fl[i].type) {
strcpy(buffer, " ");
} else {
strcpy(buffer, "\260 ");
}
strcat(buffer, fl[i].name);
return buffer;
}
return NULL;
}
/**
** Replay game vertical scroll action
*/
local void ReplayGameVSAction(Menuitem *mi, int i)
{
int op;
int d1;
int d2;
mi--;
switch (i) {
case 0: // click - down
case 2: // key - down
if (mi[1].d.vslider.cflags&MI_CFLAGS_DOWN) {
if (mi->d.listbox.curopt+mi->d.listbox.startline+1 < mi->d.listbox.noptions) {
mi->d.listbox.curopt++;
if (mi->d.listbox.curopt >= mi->d.listbox.nlines) {
mi->d.listbox.curopt--;
mi->d.listbox.startline++;
}
MustRedraw |= RedrawMenu;
}
} else if (mi[1].d.vslider.cflags&MI_CFLAGS_UP) {
if (mi->d.listbox.curopt+mi->d.listbox.startline > 0) {
mi->d.listbox.curopt--;
if (mi->d.listbox.curopt < 0) {
mi->d.listbox.curopt++;
mi->d.listbox.startline--;
}
MustRedraw |= RedrawMenu;
}
}
ReplayGameLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
if (i == 2) {
mi[1].d.vslider.cflags &= ~(MI_CFLAGS_DOWN|MI_CFLAGS_UP);
}
break;
case 1: // mouse - move
if (mi[1].d.vslider.cflags&MI_CFLAGS_KNOB && (mi[1].flags&MenuButtonClicked)) {
if (mi[1].d.vslider.curper > mi[1].d.vslider.percent) {
if (mi->d.listbox.curopt+mi->d.listbox.startline+1 < mi->d.listbox.noptions) {
for (;;) {
op = ((mi->d.listbox.curopt + mi->d.listbox.startline + 1) * 100) /
(mi->d.listbox.noptions - 1);
d1 = mi[1].d.vslider.curper - mi[1].d.vslider.percent;
d2 = op - mi[1].d.vslider.curper;
if (d2 >= d1)
break;
mi->d.listbox.curopt++;
if (mi->d.listbox.curopt >= mi->d.listbox.nlines) {
mi->d.listbox.curopt--;
mi->d.listbox.startline++;
}
if (mi->d.listbox.curopt+mi->d.listbox.startline+1 == mi->d.listbox.noptions)
break;
}
}
} else if (mi[1].d.vslider.curper < mi[1].d.vslider.percent) {
if (mi->d.listbox.curopt+mi->d.listbox.startline > 0) {
for (;;) {
op = ((mi->d.listbox.curopt + mi->d.listbox.startline - 1) * 100) /
(mi->d.listbox.noptions - 1);
d1 = mi[1].d.vslider.percent - mi[1].d.vslider.curper;
d2 = mi[1].d.vslider.curper - op;
if (d2 >= d1)
break;
mi->d.listbox.curopt--;
if (mi->d.listbox.curopt < 0) {
mi->d.listbox.curopt++;
mi->d.listbox.startline--;
}
if (mi->d.listbox.curopt+mi->d.listbox.startline == 0)
break;
}
}
}
DebugCheck(mi->d.listbox.startline < 0);
DebugCheck(mi->d.listbox.noptions > 0 &&
mi->d.listbox.startline+mi->d.listbox.curopt >= mi->d.listbox.noptions);
ReplayGameLBAction(mi, mi->d.listbox.curopt + mi->d.listbox.startline);
MustRedraw |= RedrawMenu;
}
break;
default:
break;
}
}
/**
** Replay game folder button callback
*/
local void ReplayGameFolder(void)
{
Menu *menu;
Menuitem *mi;
char *cp;
menu = FindMenu("menu-replay-game");
mi = &menu->items[1];
if (ScenSelectDisplayPath[0]) {
cp = strrchr(ScenSelectDisplayPath, '/');
if (cp) {
*cp = 0;
} else {
ScenSelectDisplayPath[0] = 0;
menu->items[5].flags |= MenuButtonDisabled;
menu->items[5].d.button.text = NULL;
}
cp = strrchr(ScenSelectPath, '/');
if (cp) {
*cp = 0;
ReplayGameLBInit(mi);
mi->d.listbox.cursel = -1;
mi->d.listbox.startline = 0;
mi->d.listbox.curopt = 0;
mi[1].d.vslider.percent = 0;
mi[1].d.hslider.percent = 0;
MustRedraw |= RedrawMenu;
}
}
}
/**
** Replay game ok button callback
*/
local void ReplayGameOk(void)
{
Menu *menu;
Menuitem *mi;
FileList *fl;
int i;
menu = FindMenu("menu-replay-game");
mi = &menu->items[1];
i = mi->d.listbox.curopt + mi->d.listbox.startline;
if (i < mi->d.listbox.noptions) {
fl = mi->d.listbox.options;
if (fl[i].type == 0) {
strcat(ScenSelectPath, "/");
strcat(ScenSelectPath, fl[i].name);
if (menu->items[5].flags&MenuButtonDisabled) {
menu->items[5].flags &= ~MenuButtonDisabled;
menu->items[5].d.button.text = ScenSelectDisplayPath;
} else {
strcat(ScenSelectDisplayPath, "/");
}
strcat(ScenSelectDisplayPath, fl[i].name);
ReplayGameLBInit(mi);
mi->d.listbox.cursel = -1;
mi->d.listbox.startline = 0;
mi->d.listbox.curopt = 0;
mi[1].d.vslider.percent = 0;
mi[1].d.hslider.percent = 0;
MustRedraw |= RedrawMenu;
} else {
strcpy(ScenSelectFileName, fl[i].name); // Final map name
if (ScenSelectPath[0]) {
strcat(ScenSelectPath, "/");
strcat(ScenSelectPath, ScenSelectFileName);
} else {
strcpy(ScenSelectPath, ScenSelectFileName);
}
LoadReplay(ScenSelectPath);
for (i = 0; i < MAX_OBJECTIVES; i++) {
if (GameIntro.Objectives[i]) {
free(GameIntro.Objectives[i]);
GameIntro.Objectives[i] = NULL;
}
}
GameIntro.Objectives[0] = strdup(DefaultObjective);
GuiGameStarted = 1;
EndMenu();
}
}
}
/**
** Replay game cancel button callback
*/
local void ReplayGameCancel(void)
{
char* s;
//
// Use last selected map.
//
DebugLevel0Fn("Map path: %s\n" _C_ CurrentMapPath);
strcpy(ScenSelectPath, FreeCraftLibPath);
if (*ScenSelectPath) {
strcat(ScenSelectPath, "/");
}
strcat(ScenSelectPath, CurrentMapPath);
if ((s = strrchr(ScenSelectPath, '/'))) {
strcpy(ScenSelectFileName, s + 1);
*s = '\0';
}
strcpy(ScenSelectDisplayPath, CurrentMapPath);
if ((s = strrchr(ScenSelectDisplayPath, '/'))) {
*s = '\0';
} else {
*ScenSelectDisplayPath = '\0';
}
DebugLevel0Fn("Start path: %s\n" _C_ ScenSelectPath);
EndMenu();
}
/*----------------------------------------------------------------------------
-- Init functions
----------------------------------------------------------------------------*/