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