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  */
22 
23 
24 #include "queen/grid.h"
25 
26 #include "queen/display.h"
27 #include "queen/logic.h"
28 #include "queen/queen.h"
29 
30 #include "common/debug.h"
31 
32 namespace Queen {
33 
Grid(QueenEngine * vm)34 Grid::Grid(QueenEngine *vm)
35 	: _vm(vm) {
36 	memset(_zones, 0, sizeof(_zones));
37 }
38 
~Grid()39 Grid::~Grid() {
40 	delete[] _objMax;
41 	delete[] _areaMax;
42 	delete[] _area;
43 	delete[] _objectBox;
44 }
45 
readDataFrom(uint16 numObjects,uint16 numRooms,byte * & ptr)46 void Grid::readDataFrom(uint16 numObjects, uint16 numRooms, byte *&ptr) {
47 	uint16 i, j;
48 
49 	_numRoomAreas = numRooms;
50 
51 	_objMax  = new int16[_numRoomAreas + 1];
52 	_areaMax = new int16[_numRoomAreas + 1];
53 	_area    = new Area[_numRoomAreas + 1][MAX_AREAS_NUMBER];
54 
55 	_objMax[0] = 0;
56 	_areaMax[0] = 0;
57 	// _area[0][] cleared by default constructor
58 	for (i = 1; i <= _numRoomAreas; i++) {
59 		_objMax[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
60 		_areaMax[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
61 		// _area[i][0] cleared by default constructor
62 		for (j = 1; j <= _areaMax[i]; j++) {
63 			assert(j < MAX_AREAS_NUMBER);
64 			_area[i][j].readFromBE(ptr);
65 		}
66 	}
67 
68 	_objectBox = new Box[numObjects + 1];
69 	// _objectBox[0] cleared by default constructor
70 	for (i = 1; i <= numObjects; i++) {
71 		_objectBox[i].readFromBE(ptr);
72 	}
73 }
74 
setZone(GridScreen screen,uint16 zoneNum,uint16 x1,uint16 y1,uint16 x2,uint16 y2)75 void Grid::setZone(GridScreen screen, uint16 zoneNum, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
76 	debug(9, "Grid::setZone(%d, %d, (%d,%d), (%d,%d))", screen, zoneNum, x1, y1, x2, y2);
77 	assert(zoneNum < MAX_ZONES_NUMBER);
78 	ZoneSlot *pzs = &_zones[screen][zoneNum];
79 	pzs->valid = true;
80 	pzs->box.x1 = x1;
81 	pzs->box.y1 = y1;
82 	pzs->box.x2 = x2;
83 	pzs->box.y2 = y2;
84 }
85 
setZone(GridScreen screen,uint16 zoneNum,const Box & box)86 void Grid::setZone(GridScreen screen, uint16 zoneNum, const Box &box) {
87 	debug(9, "Grid::setZone(%d, %d, (%d,%d), (%d,%d))", screen, zoneNum, box.x1, box.y1, box.x2, box.y2);
88 	assert(zoneNum < MAX_ZONES_NUMBER);
89 	ZoneSlot *pzs = &_zones[screen][zoneNum];
90 	pzs->valid = true;
91 	pzs->box = box;
92 }
93 
findZoneForPos(GridScreen screen,uint16 x,uint16 y) const94 uint16 Grid::findZoneForPos(GridScreen screen, uint16 x, uint16 y) const {
95 	debug(9, "Logic::findZoneForPos(%d, (%d,%d))", screen, x, y);
96 	int i;
97 	if (screen == GS_PANEL) {
98 		y -= ROOM_ZONE_HEIGHT;
99 	}
100 	for (i = 1; i < MAX_ZONES_NUMBER; ++i) {
101 		const ZoneSlot *pzs = &_zones[screen][i];
102 		if (pzs->valid && pzs->box.contains(x, y)) {
103 			return i;
104 		}
105 	}
106 	return 0;
107 }
108 
findAreaForPos(GridScreen screen,uint16 x,uint16 y) const109 uint16 Grid::findAreaForPos(GridScreen screen, uint16 x, uint16 y) const {
110 	uint16 room = _vm->logic()->currentRoom();
111 	uint16 zoneNum = findZoneForPos(screen, x, y);
112 	if (zoneNum <= _objMax[room]) {
113 		zoneNum = 0;
114 	} else {
115 		zoneNum -= _objMax[room];
116 	}
117 	return zoneNum;
118 }
119 
clear(GridScreen screen)120 void Grid::clear(GridScreen screen) {
121 	debug(9, "Grid::clear(%d)", screen);
122 	for (int i = 1; i < MAX_ZONES_NUMBER; ++i) {
123 		_zones[screen][i].valid = false;
124 	}
125 }
126 
setupNewRoom(uint16 room,uint16 firstRoomObjNum)127 void Grid::setupNewRoom(uint16 room, uint16 firstRoomObjNum) {
128 	debug(9, "Grid::setupNewRoom()");
129 	clear(GS_ROOM);
130 
131 	uint16 i;
132 	uint16 zoneNum;
133 
134 	// setup objects zones
135 	uint16 maxObjRoom = _objMax[room];
136 	zoneNum = 1;
137 	for (i = firstRoomObjNum + 1; i <= firstRoomObjNum + maxObjRoom; ++i) {
138 		if (_vm->logic()->objectData(i)->name != 0) {
139 			if (room == 41 && i == 303) {
140 
141 				// WORKAROUND bug #1599009: In the room 41, the bounding box of the
142 				// stairs (object 303) doesn't match with the room picture. With the
143 				// original box dimensions, Joe could walk "above" the stairs, giving
144 				// the impression of floating in the air.
145 				// To fix this, the bounding box is set relative to the position of
146 				// the cabinet (object 295).
147 
148 				uint16 y1 = _objectBox[295].y2 + 1;
149 				setZone(GS_ROOM, zoneNum, _objectBox[i].x1, y1, _objectBox[i].x2, _objectBox[i].y2);
150 			} else {
151 				setZone(GS_ROOM, zoneNum, _objectBox[i]);
152 			}
153 		}
154 		++zoneNum;
155 	}
156 
157 	// setup room zones (areas)
158 	uint16 maxAreaRoom = _areaMax[room];
159 	for (zoneNum = 1; zoneNum <= maxAreaRoom; ++zoneNum) {
160 		setZone(GS_ROOM, maxObjRoom + zoneNum, _area[room][zoneNum].box);
161 	}
162 }
163 
setupPanel()164 void Grid::setupPanel() {
165 	for (int i = 0; i <= 7; ++i) {
166 		uint16 x = i * 20;
167 		setZone(GS_PANEL, i + 1, x, 10, x + 19, 49);
168 	}
169 
170 	// inventory scrolls
171 	setZone(GS_PANEL,  9, 160, 10, 179, 29);
172 	setZone(GS_PANEL, 10, 160, 30, 179, 49);
173 
174 	// inventory items
175 	setZone(GS_PANEL, 11, 180, 10, 213, 49);
176 	setZone(GS_PANEL, 12, 214, 10, 249, 49);
177 	setZone(GS_PANEL, 13, 250, 10, 284, 49);
178 	setZone(GS_PANEL, 14, 285, 10, 320, 49);
179 }
180 
drawZones()181 void Grid::drawZones() {
182 	for (int i = 1; i < MAX_ZONES_NUMBER; ++i) {
183 		const ZoneSlot *pzs = &_zones[GS_ROOM][i];
184 		if (pzs->valid) {
185 			const Box *b = &pzs->box;
186 			_vm->display()->drawBox(b->x1, b->y1, b->x2, b->y2, 3);
187 		}
188 	}
189 }
190 
zone(GridScreen screen,uint16 index) const191 const Box *Grid::zone(GridScreen screen, uint16 index) const {
192 	const ZoneSlot *zs = &_zones[screen][index];
193 	assert(zs->valid);
194 	return &zs->box;
195 }
196 
findVerbUnderCursor(int16 cursorx,int16 cursory) const197 Verb Grid::findVerbUnderCursor(int16 cursorx, int16 cursory) const {
198 	static const Verb pv[] = {
199 		VERB_NONE,
200 		VERB_OPEN,
201 		VERB_CLOSE,
202 		VERB_MOVE,
203 		VERB_GIVE,
204 		VERB_LOOK_AT,
205 		VERB_PICK_UP,
206 		VERB_TALK_TO,
207 		VERB_USE,
208 		VERB_SCROLL_UP,
209 		VERB_SCROLL_DOWN,
210 		VERB_INV_1,
211 		VERB_INV_2,
212 		VERB_INV_3,
213 		VERB_INV_4,
214 	};
215 	return pv[findZoneForPos(GS_PANEL, cursorx, cursory)];
216 }
217 
findObjectUnderCursor(int16 cursorx,int16 cursory) const218 uint16 Grid::findObjectUnderCursor(int16 cursorx, int16 cursory) const {
219 	uint16 roomObj = 0;
220 	if (cursory < ROOM_ZONE_HEIGHT) {
221 		int16 x = cursorx + _vm->display()->horizontalScroll();
222 		roomObj = findZoneForPos(GS_ROOM, x, cursory);
223 	}
224 	return roomObj;
225 }
226 
findObjectNumber(uint16 zoneNum) const227 uint16 Grid::findObjectNumber(uint16 zoneNum) const {
228 	// l.316-327 select.c
229 	uint16 room = _vm->logic()->currentRoom();
230 	uint16 obj = zoneNum;
231 	uint16 objectMax = _objMax[room];
232 	debug(9, "Grid::findObjectNumber(%X, %X)", zoneNum, objectMax);
233 	if (zoneNum > objectMax) {
234 		// this is an area box, check for associated object
235 		obj =  _area[room][zoneNum - objectMax].object;
236 		if (obj != 0) {
237 			// there is an object, get its number
238 			obj -= _vm->logic()->currentRoomData();
239 		}
240 	}
241 	return obj;
242 }
243 
findScale(uint16 x,uint16 y) const244 uint16 Grid::findScale(uint16 x, uint16 y) const {
245 	uint16 room = _vm->logic()->currentRoom();
246 	uint16 scale = 100;
247 	uint16 areaNum = findAreaForPos(GS_ROOM, x, y);
248 	if (areaNum != 0) {
249 		scale = _area[room][areaNum].calcScale(y);
250 	}
251 	return scale;
252 }
253 
saveState(byte * & ptr)254 void Grid::saveState(byte *&ptr) {
255 	uint16 i, j;
256 	for (i = 1; i <= _numRoomAreas; ++i) {
257 		for (j = 1; j <= _areaMax[i]; ++j) {
258 			_area[i][j].writeToBE(ptr);
259 		}
260 	}
261 }
262 
loadState(uint32 ver,byte * & ptr)263 void Grid::loadState(uint32 ver, byte *&ptr) {
264 	uint16 i, j;
265 	for (i = 1; i <= _numRoomAreas; ++i) {
266 		for (j = 1; j <= _areaMax[i]; ++j) {
267 			_area[i][j].readFromBE(ptr);
268 		}
269 	}
270 }
271 
272 } // End of namespace Queen
273