1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * Handles timers.
22  *
23  * Note: As part of the transition to ScummVM, the ticks field of a timer has been changed
24  * to a millisecond value, rather than ticks at 24Hz. Most places should be able to use
25  * the timers without change, since the ONE_SECOND constant has been set to be in MILLISECONDS
26  */
27 
28 #include "tinsel/timers.h"
29 #include "tinsel/dw.h"
30 #include "common/serializer.h"
31 #include "common/textconsole.h"
32 #include "common/system.h"
33 
34 namespace Tinsel {
35 
36 //----------------- LOCAL DEFINES --------------------
37 
38 #define MAX_TIMERS 16
39 
40 struct TIMER {
41 	int	tno;		/**< Timer number */
42 	int		ticks;		/**< Tick count */
43 	int		secs;		/**< Second count */
44 	int		delta;		/**< Increment/decrement value */
45 	bool	frame;		/**< If set, in ticks, otherwise in seconds */
46 };
47 
48 
49 
50 //----------------- LOCAL GLOBAL DATA --------------------
51 
52 static TIMER g_timers[MAX_TIMERS];	// FIXME: Avoid non-const global vars
53 
54 
55 //--------------------------------------------------------
56 
57 /**
58  * Gets the current time in number of ticks.
59  *
60  * DOS timer ticks is the number of 54.9254ms since midnight. Converting the
61  * millisecond count won't give the exact same 'since midnight' count, but I
62  * figure that as long as the timing interval is more or less accurate, it
63  * shouldn't be a problem.
64  */
65 
DwGetCurrentTime()66 uint32 DwGetCurrentTime() {
67 	return g_system->getMillis() * 55 / 1000;
68 }
69 
70 /**
71  * Resets all of the timer slots
72  */
73 
RebootTimers()74 void RebootTimers() {
75 	memset(g_timers, 0, sizeof(g_timers));
76 }
77 
78 /**
79  * (Un)serialize the timer data for save/restore game.
80  */
syncTimerInfo(Common::Serializer & s)81 void syncTimerInfo(Common::Serializer &s) {
82 	for (int i = 0; i < MAX_TIMERS; i++) {
83 		s.syncAsSint32LE(g_timers[i].tno);
84 		s.syncAsSint32LE(g_timers[i].ticks);
85 		s.syncAsSint32LE(g_timers[i].secs);
86 		s.syncAsSint32LE(g_timers[i].delta);
87 		s.syncAsSint32LE(g_timers[i].frame);
88 	}
89 }
90 
91 /**
92  * Find the timer numbered thus, if one is thus numbered.
93  * @param num	number of the timer
94  * @return the timer with the specified number, or NULL if there is none
95  */
findTimer(int num)96 static TIMER *findTimer(int num) {
97 	for (int i = 0; i < MAX_TIMERS; i++) {
98 		if (g_timers[i].tno == num)
99 			return &g_timers[i];
100 	}
101 	return NULL;
102 }
103 
104 /**
105  * Find an empty timer slot.
106  */
allocateTimer(int num)107 static TIMER *allocateTimer(int num) {
108 	assert(num); // zero is not allowed as a timer number
109 	assert(!findTimer(num)); // Allocating already existent timer
110 
111 	for (int i = 0; i < MAX_TIMERS; i++) {
112 		if (!g_timers[i].tno) {
113 			g_timers[i].tno = num;
114 			return &g_timers[i];
115 		}
116 	}
117 
118 	error("Too many timers");
119 }
120 
121 /**
122  * Update all timers, as appropriate.
123  */
FettleTimers()124 void FettleTimers() {
125 	for (int i = 0; i < MAX_TIMERS; i++) {
126 		if (!g_timers[i].tno)
127 			continue;
128 
129 		g_timers[i].ticks += g_timers[i].delta;	// Update tick value
130 
131 		if (g_timers[i].frame) {
132 			if (g_timers[i].ticks < 0)
133 				g_timers[i].ticks = 0;	// Have reached zero
134 		} else {
135 			if (g_timers[i].ticks < 0) {
136 				g_timers[i].ticks = ONE_SECOND;
137 				g_timers[i].secs--;
138 				if (g_timers[i].secs < 0)
139 					g_timers[i].secs = 0;	// Have reached zero
140 			} else if (g_timers[i].ticks == ONE_SECOND) {
141 				g_timers[i].ticks = 0;
142 				g_timers[i].secs++;		// Another second has passed
143 			}
144 		}
145 	}
146 }
147 
148 /**
149  * Start a timer up.
150  */
StartTimer(int num,int sval,bool up,bool frame)151 void StartTimer(int num, int sval, bool up, bool frame) {
152 	TIMER *pt;
153 
154 	assert(num); // zero is not allowed as a timer number
155 
156 	pt = findTimer(num);
157 	if (pt == NULL)
158 		pt = allocateTimer(num);
159 
160 	pt->delta = up ? 1 : -1;	// Increment/decrement value
161 	pt->frame = frame;
162 
163 	if (frame) {
164 		pt->secs = 0;
165 		pt->ticks = sval;
166 	} else {
167 		pt->secs = sval;
168 		pt->ticks = 0;
169 	}
170 }
171 
172 /**
173  * Return the current count of a timer.
174  */
Timer(int num)175 int Timer(int num) {
176 	TIMER *pt;
177 
178 	pt = findTimer(num);
179 
180 	if (pt == NULL)
181 		return -1;
182 
183 	if (pt->frame)
184 		return pt->ticks;
185 	else
186 		return pt->secs;
187 }
188 
189 } // End of namespace Tinsel
190