warzone2100/lib/gamelib/gtime.c

295 lines
5.8 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
*/
/*
* GTime.c
*
* Provide a game clock that runs only when the game runs.
*
*/
#include "SDL/SDL_timer.h"
#include <time.h>
//#define DEBUG_GROUP1
#include "lib/framework/frame.h"
#include "gtime.h"
#define TIME_FIX
//#define RATE_LIMIT
#define GTIME_MINFRAME (GAME_TICKS_PER_SEC/80)
/* The current time in the game world */
UDWORD gameTime;
/* The time for the last frame */
UDWORD frameTime;
/* The current time in the game world ( never stops )*/
UDWORD gameTime2;
/* The time for the last frame (never stops)*/
UDWORD frameTime2;
// the current clock modifier
static FRACT modifier;
// the amount of game time before the last time clock speed was set
static UDWORD timeOffset;
static UDWORD timeOffset2;
// the tick count the last time the clock speed was set
static UDWORD baseTime;
static UDWORD baseTime2;
/* When the game paused so that gameTime can be adjusted when the game restarts */
static SDWORD pauseStart;
/* Count how many times gameTimeStop has been called without a game time start */
static UDWORD stopCount;
/* Initialise the game clock */
BOOL gameTimeInit(void)
{
//gameTime = 0;
/*start the timer off at 2 so that when the scripts strip the map of objects
for multiPlayer they will be processed as if they died*/
gameTime = 2;
timeOffset = 0;
baseTime = SDL_GetTicks();
gameTime2 = 0;
timeOffset2 = 0;
baseTime2 = baseTime;
modifier = FRACTCONST(1,1);
stopCount = 0;
return TRUE;
}
UDWORD getTimeValueRange(UDWORD tickFrequency, UDWORD requiredRange)
{
UDWORD div1,div2;
div1 = gameTime2%tickFrequency;
div2 = tickFrequency/requiredRange;
return(div1/div2);
}
UDWORD getStaticTimeValueRange(UDWORD tickFrequency, UDWORD requiredRange)
{
UDWORD div1,div2;
div1 = gameTime%tickFrequency;
div2 = tickFrequency/requiredRange;
return(div1/div2);
}
/* Call this each loop to update the game timer */
void gameTimeUpdate(void)
{
UDWORD currTime, fpMod;
#ifdef TIME_FIX
Uint64 newTime;
Uint64 extraTime;
#else
unsigned long long newTime;
#endif
currTime = SDL_GetTicks();
if (currTime < baseTime)
{
#ifdef RATE_LIMIT
// Limit the frame time
#endif
// ooops the clock has wrapped round -
// someone actually managed to keep windows running for 50 days !!!!
// ........
}
//don't update the game time if gameTimeStop has been called
if (stopCount == 0)
{
// Calculate the new game time
newTime = currTime - baseTime;
// convert the modifier to fixed point cos we loose accuracy
fpMod = MAKEINT(FRACTmul(modifier, FRACTCONST(1000,1)));
newTime = newTime * fpMod / 1000;
newTime += timeOffset;
// Calculate the time for this frame
frameTime = (UDWORD)(newTime - gameTime);
// Limit the frame time
if (frameTime > GTIME_MAXFRAME)
{
#ifdef TIME_FIX
extraTime = frameTime - GTIME_MAXFRAME;
extraTime = extraTime * 1000 / fpMod;//adjust the addition to base time
baseTime += (UDWORD)extraTime;
#else
baseTime += frameTime - GTIME_MAXFRAME;
#endif
newTime = gameTime + GTIME_MAXFRAME;
frameTime = GTIME_MAXFRAME;
}
// Store the game time
gameTime = (UDWORD)newTime;
}
// now update gameTime2 which does not pause
newTime = currTime - baseTime2;
newTime += timeOffset;
// Calculate the time for this frame
frameTime2 = (UDWORD)newTime - gameTime2;
// Limit the frame time
if (frameTime2 > GTIME_MAXFRAME)
{
baseTime2 += frameTime2 - GTIME_MAXFRAME;
newTime = gameTime2 + GTIME_MAXFRAME;
frameTime2 = GTIME_MAXFRAME;
}
// Store the game time
gameTime2 = (UDWORD)newTime;
}
// reset the game time modifiers
void gameTimeResetMod(void)
{
timeOffset = gameTime;
timeOffset2 = gameTime2;
baseTime = SDL_GetTicks();
baseTime2 = SDL_GetTicks();
modifier = FRACTCONST(1,1);
}
// set the time modifier
void gameTimeSetMod(FRACT mod)
{
gameTimeResetMod();
modifier = mod;
}
// get the current time modifier
void gameTimeGetMod(FRACT *pMod)
{
*pMod = modifier;
}
BOOL gameTimeIsStopped(void)
{
return (stopCount != 0);
}
/* Call this to stop the game timer */
void gameTimeStop(void)
{
if (stopCount == 0)
{
pauseStart = SDL_GetTicks();
debug( LOG_NEVER, "Clock paused at %d\n", pauseStart);
}
stopCount += 1;
}
/* Call this to restart the game timer after a call to gameTimeStop */
void gameTimeStart(void)
{
if (stopCount == 1)
{
// shift the base time to now
timeOffset = gameTime;
baseTime = SDL_GetTicks();
}
if (stopCount > 0)
{
stopCount --;
}
}
/*Call this to reset the game timer*/
void gameTimeReset(UDWORD time)
{
// reset the game timers
gameTime = time;
timeOffset = time;
gameTime2 = time;
timeOffset2 = time;
baseTime = SDL_GetTicks();//used from save game only so GetTickCount is as valid as anything
baseTime2 = SDL_GetTicks();
modifier = FRACTCONST(1,1);
}
void getTimeComponents(UDWORD time, UDWORD *hours, UDWORD *minutes, UDWORD *seconds)
{
UDWORD h,m,s;
UDWORD tph,tpm;
/* Ticks in a minute */
tpm = GAME_TICKS_PER_SEC*60;
/* Ticks in an hour */
tph = tpm*60;
h = time/tph;
m = (time - (h*tph))/tpm;
s = (time - ((h*tph) + (m*tpm)))/GAME_TICKS_PER_SEC;
*hours = h;
*minutes = m;
*seconds = s;
}