Added initial support for game replay
This commit is contained in:
parent
61803751eb
commit
24a33f940d
5 changed files with 793 additions and 38 deletions
src
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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);
|
||||
|
|
447
src/ui/menus.cpp
447
src/ui/menus.cpp
|
@ -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
|
||||
----------------------------------------------------------------------------*/
|
||||
|
|
Loading…
Add table
Reference in a new issue