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  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 
26 #include "common/rect.h"
27 
28 #include "sword2/sword2.h"
29 #include "sword2/defs.h"
30 #include "sword2/header.h"
31 #include "sword2/console.h"
32 #include "sword2/logic.h"
33 #include "sword2/maketext.h"
34 #include "sword2/memory.h"
35 #include "sword2/mouse.h"
36 #include "sword2/resman.h"
37 #include "sword2/router.h"
38 #include "sword2/screen.h"
39 
40 namespace Sword2 {
41 
clearDebugTextBlocks()42 void Debugger::clearDebugTextBlocks() {
43 	uint8 blockNo = 0;
44 
45 	while (blockNo < MAX_DEBUG_TEXTS && _debugTextBlocks[blockNo] > 0) {
46 		// kill the system text block
47 		_vm->_fontRenderer->killTextBloc(_debugTextBlocks[blockNo]);
48 
49 		// clear this element of our array of block numbers
50 		_debugTextBlocks[blockNo] = 0;
51 
52 		blockNo++;
53 	}
54 }
55 
makeDebugTextBlock(char * text,int16 x,int16 y)56 void Debugger::makeDebugTextBlock(char *text, int16 x, int16 y) {
57 	uint8 blockNo = 0;
58 
59 	while (blockNo < MAX_DEBUG_TEXTS && _debugTextBlocks[blockNo] > 0)
60 		blockNo++;
61 
62 	assert(blockNo < MAX_DEBUG_TEXTS);
63 
64 	_debugTextBlocks[blockNo] = _vm->_fontRenderer->buildNewBloc((byte *)text, x, y, 640 - x, 0, RDSPR_DISPLAYALIGN, CONSOLE_FONT_ID, NO_JUSTIFICATION);
65 }
66 
buildDebugText()67 void Debugger::buildDebugText() {
68 	char buf[128];
69 
70 	int32 showVarNo;		// for variable watching
71 	int32 showVarPos;
72 	int32 varNo;
73 
74 	ScreenInfo *screenInfo = _vm->_screen->getScreenInfo();
75 
76 	// clear the array of text block numbers for the debug text
77 	clearDebugTextBlocks();
78 
79 	// mouse coords
80 	// print mouse coords beside mouse-marker, if it's being displayed
81 	if (_displayMouseMarker) {
82 		int mouseX, mouseY;
83 
84 		_vm->_mouse->getPos(mouseX, mouseY);
85 
86 		sprintf(buf, "%d,%d", mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y);
87 		if (mouseX > 560)
88 			makeDebugTextBlock(buf, mouseX - 50, mouseY - 15);
89 		else
90 			makeDebugTextBlock(buf, mouseX + 5, mouseY - 15);
91 	}
92 
93 	// mouse area coords
94 
95 	// defining a mouse area the easy way, by creating a box on-screen
96 	if (_draggingRectangle || _vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) {
97 		// so we can see what's behind the lines
98 		_rectFlicker = !_rectFlicker;
99 
100 		sprintf(buf, "x1=%d", _rectX1);
101 		makeDebugTextBlock(buf, 0, 120);
102 
103 		sprintf(buf, "y1=%d", _rectY1);
104 		makeDebugTextBlock(buf, 0, 135);
105 
106 		sprintf(buf, "x2=%d", _rectX2);
107 		makeDebugTextBlock(buf, 0, 150);
108 
109 		sprintf(buf, "y2=%d", _rectY2);
110 		makeDebugTextBlock(buf, 0, 165);
111 	}
112 
113 	// testingSnR indicator
114 
115 	if (_testingSnR) {		// see fnAddHuman()
116 		sprintf(buf, "TESTING LOGIC STABILITY!");
117 		makeDebugTextBlock(buf, 0, 105);
118 	}
119 
120 	// debug info at top of screen - enabled/disabled as one complete unit
121 
122 	if (_displayTime) {
123 		int32 time = _vm->getMillis();
124 
125 		if ((time - _startTime) / 1000 >= 10000)
126 			_startTime = time;
127 
128 		time -= _startTime;
129 		sprintf(buf, "Time %.2d:%.2d:%.2d.%.3d", (time / 3600000) % 60, (time / 60000) % 60, (time / 1000) % 60, time % 1000);
130 		makeDebugTextBlock(buf, 500, 360);
131 		sprintf(buf, "Game %d", _vm->_gameCycle);
132 		makeDebugTextBlock(buf, 500, 380);
133 	}
134 
135 	// current text number & speech-sample resource id
136 
137 	if (_displayTextNumbers) {
138 		if (_textNumber) {
139 			if (_vm->_logic->readVar(SYSTEM_TESTING_TEXT)) {
140 				if (_vm->_logic->readVar(SYSTEM_WANT_PREVIOUS_LINE))
141 					sprintf(buf, "backwards");
142 				else
143 					sprintf(buf, "forwards");
144 
145 				makeDebugTextBlock(buf, 0, 340);
146 			}
147 
148 			sprintf(buf, "res: %d", _textNumber / SIZE);
149 			makeDebugTextBlock(buf, 0, 355);
150 
151 			sprintf(buf, "pos: %d", _textNumber & 0xffff);
152 			makeDebugTextBlock(buf, 0, 370);
153 
154 			sprintf(buf, "TEXT: %d", _vm->_logic->_officialTextNumber);
155 			makeDebugTextBlock(buf, 0, 385);
156 		}
157 	}
158 
159 	// resource number currently being checking for animation
160 
161 	if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) {
162 		sprintf(buf, "trying resource %d", _vm->_logic->readVar(SYSTEM_TESTING_ANIMS));
163 		makeDebugTextBlock(buf, 0, 90);
164 	}
165 
166 	// general debug info
167 
168 	if (_displayDebugText) {
169 /*
170 		// CD in use
171 		sprintf(buf, "CD-%d", currentCD);
172 		makeDebugTextBlock(buf, 0, 0);
173 */
174 
175 		// mouse coords & object pointed to
176 
177 		if (_vm->_logic->readVar(CLICKED_ID))
178 			sprintf(buf, "last click at %d,%d (id %d: %s)",
179 				_vm->_logic->readVar(MOUSE_X),
180 				_vm->_logic->readVar(MOUSE_Y),
181 				_vm->_logic->readVar(CLICKED_ID),
182 				_vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID)));
183 		else
184 			sprintf(buf, "last click at %d,%d (---)",
185 				_vm->_logic->readVar(MOUSE_X),
186 				_vm->_logic->readVar(MOUSE_Y));
187 
188 		makeDebugTextBlock(buf, 0, 15);
189 
190 		uint32 mouseTouching = _vm->_mouse->getMouseTouching();
191 
192 		int mouseX, mouseY;
193 
194 		_vm->_mouse->getPos(mouseX, mouseY);
195 
196 		if (mouseTouching)
197 			sprintf(buf, "mouse %d,%d (id %d: %s)",
198 				mouseX + screenInfo->scroll_offset_x,
199 				mouseY + screenInfo->scroll_offset_y,
200 				mouseTouching,
201 				_vm->_resman->fetchName(mouseTouching));
202 		else
203 			sprintf(buf, "mouse %d,%d (not touching)",
204 				mouseX + screenInfo->scroll_offset_x,
205 				mouseY + screenInfo->scroll_offset_y);
206 
207 		makeDebugTextBlock(buf, 0, 30);
208 
209 		// player coords & graphic info
210 		// if player objct has a graphic
211 
212 		if (_graphAnimRes)
213 			sprintf(buf, "player %d,%d %s (%d) #%d/%d",
214 				screenInfo->player_feet_x,
215 				screenInfo->player_feet_y,
216 				_vm->_resman->fetchName(_graphAnimRes),
217 				_graphAnimRes,
218 				_graphAnimPc,
219 				_graphNoFrames);
220 		else
221 			sprintf(buf, "player %d,%d --- %d",
222 				screenInfo->player_feet_x,
223 				screenInfo->player_feet_y,
224 				_graphAnimPc);
225 
226 		makeDebugTextBlock(buf, 0, 45);
227 
228 		// frames-per-second counter
229 
230 		sprintf(buf, "fps %d", _vm->_screen->getFps());
231 		makeDebugTextBlock(buf, 440, 0);
232 
233 		// location number
234 
235 		sprintf(buf, "location=%d", _vm->_logic->readVar(LOCATION));
236 		makeDebugTextBlock(buf, 440, 15);
237 
238 		// "result" variable
239 
240 		sprintf(buf, "result=%d", _vm->_logic->readVar(RESULT));
241 		makeDebugTextBlock(buf, 440, 30);
242 
243 		// no. of events in event list
244 
245 		sprintf(buf, "events=%d", _vm->_logic->countEvents());
246 		makeDebugTextBlock(buf, 440, 45);
247 
248 		// sprite list usage
249 
250 		sprintf(buf, "bgp0: %d/%d", _vm->_screen->getCurBgp0(), MAX_bgp0_sprites);
251 		makeDebugTextBlock(buf, 560, 0);
252 
253 		sprintf(buf, "bgp1: %d/%d", _vm->_screen->getCurBgp1(), MAX_bgp1_sprites);
254 		makeDebugTextBlock(buf, 560, 15);
255 
256 		sprintf(buf, "back: %d/%d", _vm->_screen->getCurBack(), MAX_back_sprites);
257 		makeDebugTextBlock(buf, 560, 30);
258 
259 		sprintf(buf, "sort: %d/%d", _vm->_screen->getCurSort(), MAX_sort_sprites);
260 		makeDebugTextBlock(buf, 560, 45);
261 
262 		sprintf(buf, "fore: %d/%d", _vm->_screen->getCurFore(), MAX_fore_sprites);
263 		makeDebugTextBlock(buf, 560, 60);
264 
265 		sprintf(buf, "fgp0: %d/%d", _vm->_screen->getCurFgp0(), MAX_fgp0_sprites);
266 		makeDebugTextBlock(buf, 560, 75);
267 
268 		sprintf(buf, "fgp1: %d/%d", _vm->_screen->getCurFgp1(), MAX_fgp1_sprites);
269 		makeDebugTextBlock(buf, 560, 90);
270 
271 		// largest layer & sprite
272 
273 		// NB. Strings already constructed in Build_display.cpp
274 		makeDebugTextBlock(_vm->_screen->getLargestLayerInfo(), 0, 60);
275 		makeDebugTextBlock(_vm->_screen->getLargestSpriteInfo(), 0, 75);
276 
277 		// "waiting for person" indicator - set form fnTheyDo and
278 		// fnTheyDoWeWait
279 
280 		if (_speechScriptWaiting) {
281 			sprintf(buf, "script waiting for %s (%d)",
282 				_vm->_resman->fetchName(_speechScriptWaiting),
283 				_speechScriptWaiting);
284 			makeDebugTextBlock(buf, 0, 90);
285 		}
286 
287 		// variable watch display
288 
289 		showVarPos = 115;	// y-coord for first showVar
290 
291 		for (showVarNo = 0; showVarNo < MAX_SHOWVARS; showVarNo++) {
292 			varNo = _showVar[showVarNo];	// get variable number
293 
294 			// if non-zero ie. cannot watch 'id' but not needed
295 			// anyway because it changes throughout the logic loop
296 
297 			if (varNo) {
298 				sprintf(buf, "var(%d) = %d", varNo, _vm->_logic->readVar(varNo));
299 				makeDebugTextBlock(buf, 530, showVarPos);
300 				showVarPos += 15;	// next line down
301 			}
302 		}
303 
304 		// memory indicator - this should come last, to show all the
305 		// sprite blocks above!
306 
307 		uint32 totAlloc = _vm->_memory->getTotAlloc();
308 		int16 numBlocks = _vm->_memory->getNumBlocks();
309 
310 		if (totAlloc < 1024)
311 			sprintf(buf, "%u bytes in %d memory blocks", totAlloc, numBlocks);
312 		else if (totAlloc < 1024 * 1024)
313 			sprintf(buf, "%uK in %d memory blocks", totAlloc / 1024, numBlocks);
314 		else
315 			sprintf(buf, "%.02fM in %d memory blocks", totAlloc / 1048576., numBlocks);
316 
317 		makeDebugTextBlock(buf, 0, 0);
318 	}
319 }
320 
drawDebugGraphics()321 void Debugger::drawDebugGraphics() {
322 	ScreenInfo *screenInfo = _vm->_screen->getScreenInfo();
323 	// walk-grid
324 
325 	if (_displayWalkGrid)
326 		_vm->_logic->_router->plotWalkGrid();
327 
328 	// player feet coord marker
329 
330 	if (_displayPlayerMarker)
331 		plotCrossHair(screenInfo->player_feet_x, screenInfo->player_feet_y, 215);
332 
333 	// mouse marker & coords
334 
335 	if (_displayMouseMarker) {
336 		int mouseX, mouseY;
337 
338 		_vm->_mouse->getPos(mouseX, mouseY);
339 
340 		plotCrossHair(mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y, 215);
341 	}
342 
343 	// mouse area rectangle / sprite box rectangle when testing anims
344 
345 	if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) {
346 		// draw box around current frame
347 		drawRect(_rectX1, _rectY1, _rectX2, _rectY2, 184);
348 	} else if (_draggingRectangle) {
349 		// defining a mouse area the easy way, by creating a box
350 		// on-screen
351 		if (_rectFlicker)
352 			drawRect(_rectX1, _rectY1, _rectX2, _rectY2, 184);
353 	}
354 }
355 
plotCrossHair(int16 x,int16 y,uint8 pen)356 void Debugger::plotCrossHair(int16 x, int16 y, uint8 pen) {
357 	_vm->_screen->plotPoint(x, y, pen);
358 
359 	_vm->_screen->drawLine(x - 2, y, x - 5, y, pen);
360 	_vm->_screen->drawLine(x + 2, y, x + 5, y, pen);
361 
362 	_vm->_screen->drawLine(x, y - 2, x, y - 5, pen);
363 	_vm->_screen->drawLine(x, y + 2, x, y + 5, pen);
364 }
365 
drawRect(int16 x1,int16 y1,int16 x2,int16 y2,uint8 pen)366 void Debugger::drawRect(int16 x1, int16 y1, int16 x2, int16 y2, uint8 pen) {
367 	_vm->_screen->drawLine(x1, y1, x2, y1, pen);	// top edge
368 	_vm->_screen->drawLine(x1, y2, x2, y2, pen);	// bottom edge
369 	_vm->_screen->drawLine(x1, y1, x1, y2, pen);	// left edge
370 	_vm->_screen->drawLine(x2, y1, x2, y2, pen);	// right edge
371 }
372 
373 } // End of namespace Sword2
374