//rww - rewrite from C++ SP version. //This is here only to make porting from SP easier, it's really sort of nasty (being static //now). Basically it's slower and takes more memory. #include "g_local.h" //typedef map < string, int > timer_m; #define MAX_GTIMERS 16384 typedef struct gtimer_s { const char *name; int time; struct gtimer_s *next; // In either free list or current list } gtimer_t; gtimer_t g_timerPool[ MAX_GTIMERS ]; gtimer_t *g_timers[ MAX_GENTITIES ]; gtimer_t *g_timerFreeList; /* ------------------------- TIMER_Clear ------------------------- */ void TIMER_Clear( void ) { int i; for (i = 0; i < MAX_GENTITIES; i++) { g_timers[i] = NULL; } for (i = 0; i < MAX_GTIMERS - 1; i++) { g_timerPool[i].next = &g_timerPool[i+1]; } g_timerPool[MAX_GTIMERS-1].next = NULL; g_timerFreeList = &g_timerPool[0]; } /* ------------------------- TIMER_Clear ------------------------- */ void TIMER_Clear2( gentity_t *ent ) { // rudimentary safety checks, might be other things to check? if ( ent && ent->s.number > 0 && ent->s.number < MAX_GENTITIES ) { gtimer_t *p = g_timers[ent->s.number]; // No timers at all -> do nothing if (!p) { return; } // Find the end of this ents timer list while (p->next) { p = p->next; } // Splice the lists p->next = g_timerFreeList; g_timerFreeList = g_timers[ent->s.number]; g_timers[ent->s.number] = NULL; return; } } //New C "lookup" func. //Returns existing timer in array if gtimer_t *TIMER_GetNew(int num, const char *identifier) { gtimer_t *p = g_timers[num]; // Search for an existing timer with this name while (p) { if (!Q_stricmp(p->name, identifier)) { // Found it return p; } p = p->next; } // No existing timer with this name was found, so grab one from the free list if (!g_timerFreeList) return NULL; p = g_timerFreeList; g_timerFreeList = g_timerFreeList->next; p->next = g_timers[num]; g_timers[num] = p; return p; } //don't return the first free if it doesn't already exist, return null. gtimer_t *TIMER_GetExisting(int num, const char *identifier) { gtimer_t *p = g_timers[num]; while (p) { if (!Q_stricmp(p->name, identifier)) { // Found it return p; } p = p->next; } return NULL; } /* ------------------------- TIMER_Set ------------------------- */ void TIMER_Set( gentity_t *ent, const char *identifier, int duration ) { gtimer_t *timer = TIMER_GetNew(ent->s.number, identifier); if (!timer) { return; } timer->name = identifier; timer->time = level.time + duration; } /* ------------------------- TIMER_Get ------------------------- */ int TIMER_Get( gentity_t *ent, const char *identifier ) { gtimer_t *timer = TIMER_GetExisting(ent->s.number, identifier); if (!timer) { return -1; } return timer->time; } /* ------------------------- TIMER_Done ------------------------- */ qboolean TIMER_Done( gentity_t *ent, const char *identifier ) { gtimer_t *timer = TIMER_GetExisting(ent->s.number, identifier); if (!timer) { return qtrue; } return (timer->time < level.time); } /* ------------------------- TIMER_RemoveHelper Scans an entities timer list to remove a given timer from the list and put it on the free list Doesn't do much error checking, only called below ------------------------- */ void TIMER_RemoveHelper( int num, gtimer_t *timer ) { gtimer_t *p = g_timers[num]; // Special case: first timer in list if (p == timer) { g_timers[num] = g_timers[num]->next; p->next = g_timerFreeList; g_timerFreeList = p; return; } // Find the predecessor while (p->next != timer) { p = p->next; } // Rewire p->next = p->next->next; timer->next = g_timerFreeList; g_timerFreeList = timer; return; } /* ------------------------- TIMER_Done2 Returns false if timer has been started but is not done...or if timer was never started ------------------------- */ qboolean TIMER_Done2( gentity_t *ent, const char *identifier, qboolean remove ) { gtimer_t *timer = TIMER_GetExisting(ent->s.number, identifier); qboolean res; if (!timer) { return qfalse; } res = (timer->time < level.time); if (res && remove) { // Put it back on the free list TIMER_RemoveHelper(ent->s.number, timer); } return res; } /* ------------------------- TIMER_Exists ------------------------- */ qboolean TIMER_Exists( gentity_t *ent, const char *identifier ) { gtimer_t *timer = TIMER_GetExisting(ent->s.number, identifier); if (!timer) { return qfalse; } return qtrue; } /* ------------------------- TIMER_Remove Utility to get rid of any timer ------------------------- */ void TIMER_Remove( gentity_t *ent, const char *identifier ) { gtimer_t *timer = TIMER_GetExisting(ent->s.number, identifier); if (!timer) { return; } // Put it back on the free list TIMER_RemoveHelper(ent->s.number, timer); } /* ------------------------- TIMER_Start ------------------------- */ qboolean TIMER_Start( gentity_t *self, const char *identifier, int duration ) { if ( TIMER_Done( self, identifier ) ) { TIMER_Set( self, identifier, duration ); return qtrue; } return qfalse; }