(*
* Hedgewars, a free turn based strategy game
* Copyright (c) 2004-2010 Andrey Korotaev <unC0Rr@gmail.com>
*
* This program 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; version 2 of the License
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*)
{$INCLUDE "options.inc"}
{$IFDEF WIN32}
{$R hwengine.rc}
{$ENDIF}
{$IFDEF HWLIBRARY}
unit hwengine;
interface
{$ELSE}
program hwengine;
{$ENDIF}
uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uKeys, uSound,
uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions, sysutils;
type arrayofpchar = array[0..9] of PChar;
var isTerminated: boolean = false;
alsoShutdownFrontend: boolean = false;
{$IFDEF HWLIBRARY}
procedure initEverything(complete:boolean);
procedure freeEverything(complete:boolean);
implementation
{$ELSE}
procedure OnDestroy; forward;
procedure initEverything(complete:boolean); forward;
procedure freeEverything(complete:boolean); forward;
{$ENDIF}
////////////////////////////////
procedure DoTimer(Lag: LongInt);
{$IFNDEF IPHONEOS}
var s: shortstring;
{$ENDIF}
begin
if not isPaused then inc(RealTicks, Lag);
case GameState of
gsLandGen: begin
GenMap;
GameState:= gsStart;
end;
gsStart: begin
if HasBorder then DisableSomeWeapons;
AddClouds;
AssignHHCoords;
AddMiscGears;
StoreLoad;
InitWorld;
ResetKbd;
SoundLoad;
if GameType = gmtSave then
begin
isSEBackup:= isSoundEnabled;
isSoundEnabled:= false
end;
FinishProgress;
PlayMusic;
SetScale(zoom);
ScriptCall('onGameStart');
GameState:= gsGame;
end;
gsConfirm,
gsGame: begin
DrawWorld(Lag); // never place between ProcessKbd and DoGameTick - bugs due to /put cmd and isCursorVisible
ProcessKbd;
if not isPaused then
begin
DoGameTick(Lag);
ProcessVisualGears(Lag);
end;
end;
gsChat: begin
DrawWorld(Lag);
if not isPaused then
begin
DoGameTick(Lag);
ProcessVisualGears(Lag);
end;
end;
gsExit: begin
isTerminated:= true;
end;
end;
{$IFDEF SDL13}
SDL_RenderPresent();
{$ELSE}
SDL_GL_SwapBuffers();
{$ENDIF}
{$IFNDEF IPHONEOS}
// not going to make captures on the iPhone
if flagMakeCapture then
begin
flagMakeCapture:= false;
s:= 'hw_' + FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks);
WriteLnToConsole('Saving ' + s + '...');
MakeScreenshot(s);
//SDL_SaveBMP_RW(SDLPrimSurface, SDL_RWFromFile(Str2PChar(s), 'wb'), 1)
end;
{$ENDIF}
end;
////////////////////
procedure OnDestroy;
begin
WriteLnToConsole('Freeing resources...');
FreeActionsList();
StoreRelease();
ControllerClose();
SendKB();
CloseIPC();
TTF_Quit();
{$IFDEF SDL13}
SDL_DestroyRenderer(SDLwindow);
SDL_DestroyWindow(SDLwindow);
{$ENDIF}
SDL_Quit();
isTerminated:= false;
end;
///////////////////
procedure MainLoop;
var PrevTime, CurrTime: Longword;
event: TSDL_Event;
begin
PrevTime:= SDL_GetTicks;
while isTerminated = false do
begin
while SDL_PollEvent(@event) <> 0 do
begin
case event.type_ of
SDL_KEYDOWN: if GameState = gsChat then KeyPressChat(event.key.keysym.unicode);
{$IFDEF SDL13}
SDL_WINDOWEVENT:
if event.wevent.event = SDL_WINDOWEVENT_SHOWN then
cHasFocus:= true;
{$ELSE}
SDL_ACTIVEEVENT:
if (event.active.state and SDL_APPINPUTFOCUS) <> 0 then
cHasFocus:= event.active.gain = 1;
{$ENDIF}
{$IFNDEF IPHONEOS}
SDL_MOUSEBUTTONDOWN: if event.button.button = SDL_BUTTON_WHEELDOWN then uKeys.wheelDown:= true;
SDL_MOUSEBUTTONUP: if event.button.button = SDL_BUTTON_WHEELUP then uKeys.wheelUp:= true;
{$ENDIF}
SDL_JOYAXISMOTION: ControllerAxisEvent(event.jaxis.which, event.jaxis.axis, event.jaxis.value);
SDL_JOYHATMOTION: ControllerHatEvent(event.jhat.which, event.jhat.hat, event.jhat.value);
SDL_JOYBUTTONDOWN: ControllerButtonEvent(event.jbutton.which, event.jbutton.button, true);
SDL_JOYBUTTONUP: ControllerButtonEvent(event.jbutton.which, event.jbutton.button, false);
SDL_QUITEV: isTerminated:= true
end; // end case event.type_
end; // end while SDL_PollEvent(@event) <> 0
if isTerminated = false then
begin
CurrTime:= SDL_GetTicks;
if PrevTime + cTimerInterval <= CurrTime then
begin
DoTimer(CurrTime - PrevTime);
PrevTime:= CurrTime
end
else SDL_Delay(1);
IPCCheckSock();
end;
end;
end;
/////////////////////////
procedure ShowMainWindow;
begin
if cFullScreen then ParseCommand('fullscr 1', true)
else ParseCommand('fullscr 0', true);
SDL_ShowCursor(0)
end;
///////////////
{$IFDEF HWLIBRARY}
procedure Game(gameArgs: arrayofpchar); cdecl; export;
var tmp_quality: LongInt;
{$ELSE}
procedure Game;
{$ENDIF}
var p: TPathType;
s: shortstring;
{$IFDEF DEBUGFILE}
i: LongInt;
{$ENDIF}
begin
{$IFDEF HWLIBRARY}
cBits:= 32;
cFullScreen:= false;
cVSyncInUse:= true;
cTimerInterval:= 8;
PathPrefix:= 'Data';
{$IFDEF DEBUGFILE}
cShowFPS:= true;
{$ELSE}
cShowFPS:= true; // update me at release time
{$ENDIF}
cInitVolume:= 100;
UserNick:= gameArgs[0];
val(gameArgs[1], ipcPort);
isSoundEnabled:= gameArgs[2] = '1';
isMusicEnabled:= gameArgs[3] = '1';
cLocaleFName:= gameArgs[4];
cAltDamage:= gameArgs[5] = '1';
val(gameArgs[6], cScreenHeight);
val(gameArgs[7], cScreenWidth);
recordFileName:= gameArgs[8];
val(gameArgs[9], tmp_quality);
case tmp_quality of
0: cReducedQuality:= rqNone;
1: cReducedQuality:= rqBlurryLand;
2: cReducedQuality:= rqBlurryLand or rqKillFlakes;
3: cReducedQuality:= rqBlurryLand or rqKillFlakes or rqLowRes;
end;
{$ENDIF}
initEverything(true);
WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
{$IFDEF DEBUGFILE}
AddFileLog('Prefix: "' + PathPrefix +'"');
for i:= 0 to ParamCount do
AddFileLog(inttostr(i) + ': ' + ParamStr(i));
{$ENDIF}
for p:= Succ(Low(TPathType)) to High(TPathType) do
if p <> ptMapCurrent then Pathz[p]:= PathPrefix + '/' + Pathz[p];
WriteToConsole('Init SDL... ');
SDLTry(SDL_Init(SDL_INIT_VIDEO) >= 0, true);
WriteLnToConsole(msgOK);
SDL_EnableUNICODE(1);
WriteToConsole('Init SDL_ttf... ');
SDLTry(TTF_Init() <> -1, true);
WriteLnToConsole(msgOK);
{$IFDEF WIN32}
s:= SDL_getenv('SDL_VIDEO_CENTERED');
SDL_putenv('SDL_VIDEO_CENTERED=1');
ShowMainWindow();
SDL_putenv(str2pchar('SDL_VIDEO_CENTERED=' + s));
{$ELSE}
ShowMainWindow();
{$ENDIF}
AddProgress();
ControllerInit(); // has to happen before InitKbdKeyTable to map keys
InitKbdKeyTable();
if recordFileName = '' then
InitIPC;
WriteLnToConsole(msgGettingConfig);
LoadLocale(Pathz[ptLocale] + '/en.txt'); // Do an initial load with english
if cLocaleFName <> 'en.txt' then
begin
// Try two letter locale first before trying specific locale overrides
if (Length(cLocaleFName) > 6) and (Copy(cLocaleFName,1,2)+'.txt' <> 'en.txt') then
LoadLocale(Pathz[ptLocale] + '/' + Copy(cLocaleFName,1,2)+'.txt');
LoadLocale(Pathz[ptLocale] + '/' + cLocaleFName);
end;
if recordFileName = '' then
SendIPCAndWaitReply('C') // ask for game config
else
LoadRecordFromFile(recordFileName);
ScriptOnGameInit;
s:= 'eproto ' + inttostr(cNetProtoVersion);
SendIPCRaw(@s[0], Length(s) + 1); // send proto version
InitTeams();
AssignStores();
if isSoundEnabled then
InitSound();
isDeveloperMode:= false;
TryDo(InitStepsFlags = cifAllInited, 'Some parameters not set (flags = ' + inttostr(InitStepsFlags) + ')', true);
ParseCommand('rotmask', true);
MainLoop();
// clean up SDL and GL context
OnDestroy();
// clean up all the other memory allocated
freeEverything(true);
if alsoShutdownFrontend then halt;
end;
procedure initEverything (complete:boolean);
begin
Randomize();
uConsts.initModule;
uMisc.initModule;
uConsole.initModule; // MUST happen after uMisc
uLand.initModule;
uIO.initModule;
if complete then
begin
uAI.initModule;
//uAIActions does not need initialization
//uAIAmmoTests does not need initialization
uAIMisc.initModule;
uAmmos.initModule;
uChat.initModule;
uCollisions.initModule;
//uFloat does not need initialization
//uGame does not need initialization
uGears.initModule;
uKeys.initModule;
//uLandGraphics does not need initialization
//uLandObjects does not need initialization
//uLandTemplates does not need initialization
uLandTexture.initModule;
//uLocale does not need initialization
uRandom.initModule;
uScript.initModule;
uSound.initModule;
uStats.initModule;
uStore.initModule;
uTeams.initModule;
uVisualGears.initModule;
uWorld.initModule;
end;
end;
procedure freeEverything (complete:boolean);
begin
if complete then
begin
uWorld.freeModule;
uVisualGears.freeModule;
uTeams.freeModule;
uStore.freeModule; //stub
uStats.freeModule; //stub
uSound.freeModule;
uScript.freeModule;
uRandom.freeModule; //stub
//uLocale does not need to be freed
//uLandTemplates does not need to be freed
uLandTexture.freeModule;
//uLandObjects does not need to be freed
//uLandGraphics does not need to be freed
uKeys.freeModule; //stub
uGears.freeModule;
//uGame does not need to be freed
//uFloat does not need to be freed
uCollisions.freeModule; //stub
uChat.freeModule; //stub
uAmmos.freeModule;
uAIMisc.freeModule; //stub
//uAIAmmoTests does not need to be freed
//uAIActions does not need to be freed
uAI.freeModule; //stub
end;
uIO.freeModule; //stub
uLand.freeModule;
uConsole.freeModule;
uMisc.freeModule; // uMisc closes the debug log.
uConsts.freeModule; //stub
end;
/////////////////////////
procedure GenLandPreview{$IFDEF HWLIBRARY}(port: LongInt); cdecl; export{$ENDIF};
var Preview: TPreview;
begin
initEverything(false);
{$IFDEF HWLIBRARY}
WriteLnToConsole('Preview connecting on port ' + inttostr(port));
ipcPort:= port;
{$ENDIF}
InitIPC;
IPCWaitPongEvent;
TryDo(InitStepsFlags = cifRandomize, 'Some parameters not set (flags = ' + inttostr(InitStepsFlags) + ')', true);
Preview:= GenPreview();
WriteLnToConsole('Sending preview...');
SendIPCRaw(@Preview, sizeof(Preview));
SendIPCRaw(@MaxHedgehogs, sizeof(byte));
WriteLnToConsole('Preview sent, disconnect');
CloseIPC();
freeEverything(false);
end;
{$IFNDEF HWLIBRARY}
/////////////////////
procedure DisplayUsage;
var i: LongInt;
begin
WriteLn('Wrong argument format: correct configurations is');
WriteLn();
WriteLn(' hwengine <path to data folder> <path to replay file> [option]');
WriteLn();
WriteLn('where [option] must be specified either as');
WriteLn(' --set-video [screen width] [screen height] [color dept]');
WriteLn(' --set-audio [volume] [enable music] [enable sounds]');
WriteLn(' --set-other [language file] [full screen] [show FPS]');
WriteLn(' --set-multimedia [screen height] [screen width] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
WriteLn(' --set-everything [screen height] [screen width] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]');
WriteLn();
WriteLn('Read documentation online at http://www.hedgewars.org/node/1465 for more information');
Write('parsed command: ');
for i:=0 to ParamCount do
Write(ParamStr(i) + ' ');
WriteLn();
end;
////////////////////
procedure GetParams;
begin
case ParamCount of
18: begin
val(ParamStr(2), cScreenWidth);
val(ParamStr(3), cScreenHeight);
cBitsStr:= ParamStr(4);
val(cBitsStr, cBits);
val(ParamStr(5), ipcPort);
cFullScreen:= ParamStr(6) = '1';
isSoundEnabled:= ParamStr(7) = '1';
cVSyncInUse:= ParamStr(8) = '1'; //unused
cWeaponTooltips:= ParamStr(9) = '1'; //should be merged with rqFlags
cLocaleFName:= ParamStr(10);
val(ParamStr(11), cInitVolume);
val(ParamStr(12), cTimerInterval);
PathPrefix:= ParamStr(13);
cShowFPS:= ParamStr(14) = '1';
cAltDamage:= ParamStr(15) = '1';
UserNick:= DecodeBase64(ParamStr(16));
isMusicEnabled:= ParamStr(17) = '1';
if (ParamStr(18) = '1') then //HACK
cReducedQuality:= $FFFFFFFF xor rqLowRes
else
val(ParamStr(18), cReducedQuality);
end;
3: begin
val(ParamStr(2), ipcPort);
GameType:= gmtLandPreview;
if ParamStr(3) <> 'landpreview' then
OutError(errmsgShouldntRun, true);
end;
2: begin
PathPrefix:= ParamStr(1);
recordFileName:= ParamStr(2);
end;
6: begin
PathPrefix:= ParamStr(1);
recordFileName:= ParamStr(2);
if ParamStr(3) = '--set-video' then
begin
val(ParamStr(4), cScreenWidth);
val(ParamStr(5), cScreenHeight);
cBitsStr:= ParamStr(6);
val(cBitsStr, cBits);
end
else
begin
if ParamStr(3) = '--set-audio' then
begin
val(ParamStr(4), cInitVolume);
isMusicEnabled:= ParamStr(5) = '1';
isSoundEnabled:= ParamStr(6) = '1';
end
else
begin
if ParamStr(3) = '--set-other' then
begin
cLocaleFName:= ParamStr(4);
cFullScreen:= ParamStr(5) = '1';
cShowFPS:= ParamStr(6) = '1';
end
else GameType:= gmtSyntax;
end
end;
end;
11: begin
PathPrefix:= ParamStr(1);
recordFileName:= ParamStr(2);
if ParamStr(3) = '--set-multimedia' then
begin
val(ParamStr(4), cScreenWidth);
val(ParamStr(5), cScreenHeight);
cBitsStr:= ParamStr(6);
val(cBitsStr, cBits);
val(ParamStr(7), cInitVolume);
isMusicEnabled:= ParamStr(8) = '1';
isSoundEnabled:= ParamStr(9) = '1';
cLocaleFName:= ParamStr(10);
cFullScreen:= ParamStr(11) = '1';
end
else GameType:= gmtSyntax;
end;
15: begin
PathPrefix:= ParamStr(1);
recordFileName:= ParamStr(2);
if ParamStr(3) = '--set-everything' then
begin
val(ParamStr(4), cScreenWidth);
val(ParamStr(5), cScreenHeight);
cBitsStr:= ParamStr(6);
val(cBitsStr, cBits);
val(ParamStr(7), cInitVolume);
isMusicEnabled:= ParamStr(8) = '1';
isSoundEnabled:= ParamStr(9) = '1';
cLocaleFName:= ParamStr(10);
cFullScreen:= ParamStr(11) = '1';
cAltDamage:= ParamStr(12) = '1';
cShowFPS:= ParamStr(13) = '1';
val(ParamStr(14), cTimerInterval);
if (ParamStr(15) = '1') then //HACK
cReducedQuality:= $FFFFFFFF xor rqLowRes
else
val(ParamStr(15), cReducedQuality);
end
else GameType:= gmtSyntax;
end;
else GameType:= gmtSyntax;
end;
end;
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// m a i n ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
begin
GetParams();
if GameType = gmtLandPreview then GenLandPreview()
else if GameType = gmtSyntax then DisplayUsage()
else Game();
if GameType = gmtSyntax then
ExitCode:= 1
else
ExitCode:= 0;
{$ENDIF}
end.