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 #include "sky/compact.h"
24 #include "sky/disk.h"
25 #include "sky/grid.h"
26 #include "sky/logic.h"
27 #include "sky/compact.h"
28 
29 namespace Sky {
30 
31 #define	GRID_FILE_START	60000
32 
33 int8 Grid::_gridConvertTable[] = {
34 	0,	//0
35 	1,	//1
36 	2,	//2
37 	3,	//3
38 	4,	//4
39 	5,	//5
40 	6,	//6
41 	7,	//7
42 	8,	//8
43 	9,	//9
44 	10,	//10
45 	11,	//11
46 	12,	//12
47 	13,	//13
48 	14,	//14
49 	15,	//15
50 	16,	//16
51 	17,	//17
52 	18,	//18
53 	19,	//19
54 	20,	//20
55 	21,	//21
56 	22,	//22
57 	23,	//23
58 	24,	//24
59 	25,	//25
60 	26,	//26
61 	27,	//27
62 	28,	//28
63 	29,	//29
64 	30,	//30
65 	31,	//31
66 	32,	//32
67 	33,	//33
68 	34,	//34
69 	-1,	//35
70 	35,	//36
71 	36,	//37
72 	37,	//38
73 	38,	//39
74 	39,	//40
75 	40,	//41
76 	41,	//42
77 	-1,	//43
78 	42,	//44
79 	43,	//45
80 	44,	//46
81 	45,	//47
82 	46,	//48
83 	-1,	//49
84 	-1,	//50
85 	-1,	//51
86 	-1,	//52
87 	-1,	//53
88 	-1,	//54
89 	-1,	//55
90 	-1,	//56
91 	-1,	//57
92 	-1,	//58
93 	-1,	//59
94 	-1,	//60
95 	-1,	//61
96 	-1,	//62
97 	-1,	//63
98 	-1,	//64
99 	47,	//65
100 	TOT_NO_GRIDS,	//66
101 	48,	//67
102 	49,	//68
103 	50,	//69
104 	51,	//70
105 	52,	//71
106 	53,	//72
107 	54,	//73
108 	55,	//74
109 	56,	//75
110 	57,	//76
111 	58,	//77
112 	59,	//78
113 	60,	//79
114 	-1,	//80
115 	61,	//81
116 	62,	//82
117 	-1,	//83
118 	-1,	//84
119 	-1,	//85
120 	-1,	//86
121 	-1,	//87
122 	-1,	//88
123 	TOT_NO_GRIDS,	//89
124 	63,	//90
125 	64,	//91
126 	65,	//92
127 	66,	//93
128 	67,	//94
129 	68,	//95
130 	69,	//96
131 };
132 
Grid(Disk * pDisk,SkyCompact * skyCompact)133 Grid::Grid(Disk *pDisk, SkyCompact *skyCompact) {
134 	for (int cnt = 0; cnt < TOT_NO_GRIDS; cnt++)
135 		_gameGrids[cnt] = NULL;
136 	_skyDisk = pDisk;
137 	_skyCompact = skyCompact;
138 }
139 
~Grid()140 Grid::~Grid() {
141 	for (uint8 cnt = 0; cnt < TOT_NO_GRIDS; cnt++)
142 		if (_gameGrids[cnt])
143 			free(_gameGrids[cnt]);
144 }
145 
loadGrids()146 void Grid::loadGrids() {
147 	// no endian conversion necessary as I'm using uint8* instead of uint32*
148 	for (uint8 cnt = 0; cnt < TOT_NO_GRIDS; cnt++) {
149 		if (_gameGrids[cnt])
150 			free(_gameGrids[cnt]);
151 		_gameGrids[cnt] = _skyDisk->loadFile(GRID_FILE_START + cnt);
152 	}
153 	if (!SkyEngine::isDemo()) { // single disk demos never get that far
154 		// Reloading the grids can sometimes cause problems eg when reichs door is
155 		// open the door grid bit gets replaced so you can't get back in (or out)
156 		if (Logic::_scriptVariables[REICH_DOOR_FLAG])
157 			removeGrid(256, 280, 1, _skyCompact->fetchCpt(CPT_REICH_DOOR_20));
158 			//removeGrid(256, 280, 1, &SkyCompact::reich_door_20);
159 	}
160 }
161 
getGridValues(Compact * cpt,uint8 * resGrid,uint32 * resBitNum,uint32 * resWidth)162 bool Grid::getGridValues(Compact *cpt, uint8 *resGrid, uint32 *resBitNum, uint32 *resWidth) {
163 	uint16 width = SkyCompact::getMegaSet(cpt)->gridWidth;
164 	return getGridValues(cpt->xcood, cpt->ycood, width, cpt, resGrid, resBitNum, resWidth);
165 }
166 
getGridValues(uint32 x,uint32 y,uint32 width,Compact * cpt,uint8 * resGrid,uint32 * resBitNum,uint32 * resWidth)167 bool Grid::getGridValues(uint32 x, uint32 y, uint32 width, Compact *cpt, uint8 *resGrid, uint32 *resBitNum, uint32 *resWidth) {
168 	uint32 bitPos;
169 	if (y < TOP_LEFT_Y)
170 		return false; // off screen
171 	y -= TOP_LEFT_Y;
172 	y >>= 3; // convert to blocks
173 	if (y >= GAME_SCREEN_HEIGHT >> 3)
174 		return false; // off screen
175 	bitPos = y * 40;
176 	width++;
177 	x >>= 3; // convert to blocks
178 
179 	if (x < (TOP_LEFT_X >> 3)) { // at least partially off screen
180 		if (x + width < (TOP_LEFT_X >> 3))
181 			return false; // completely off screen
182 		else {
183 			width -= (TOP_LEFT_X >> 3) - x;
184 			x = 0;
185 		}
186 	} else
187 		x -= TOP_LEFT_X >> 3;
188 
189 	if ((GAME_SCREEN_WIDTH >> 3) <= x)
190 		return false; // off screen
191 	if ((GAME_SCREEN_WIDTH >> 3) < x + width) // partially off screen
192 		width = (GAME_SCREEN_WIDTH >> 3) - x;
193 
194 	bitPos += x;
195 	assert((_gridConvertTable[cpt->screen] >= 0) && (_gridConvertTable[cpt->screen] < TOT_NO_GRIDS));
196 	*resGrid = (uint8)_gridConvertTable[cpt->screen];
197 
198 	uint32 tmpBits = 0x1F - (bitPos&0x1F);
199 	bitPos &= ~0x1F; // divide into dword address and bit number
200 	bitPos += tmpBits;
201 	*resBitNum = bitPos;
202 	*resWidth = width;
203 	return true;
204 }
205 
removeObjectFromWalk(Compact * cpt)206 void Grid::removeObjectFromWalk(Compact *cpt) {
207 	uint32 bitNum, width;
208 	uint8 gridIdx;
209 	if (getGridValues(cpt, &gridIdx, &bitNum, &width))
210 		removeObjectFromWalk(gridIdx, bitNum, width);
211 }
212 
removeObjectFromWalk(uint8 gridIdx,uint32 bitNum,uint32 width)213 void Grid::removeObjectFromWalk(uint8 gridIdx, uint32 bitNum, uint32 width) {
214 	for (uint32 cnt = 0; cnt < width; cnt++) {
215 		_gameGrids[gridIdx][bitNum >> 3] &= ~(1 << (bitNum & 0x7));
216 		if ((bitNum & 0x1F) == 0)
217 			bitNum += 0x3F;
218 		else
219 			bitNum--;
220 	}
221 }
222 
objectToWalk(Compact * cpt)223 void Grid::objectToWalk(Compact *cpt) {
224 	uint32 bitNum, width;
225 	uint8 gridIdx;
226 	if (getGridValues(cpt, &gridIdx, &bitNum, &width))
227 		objectToWalk(gridIdx, bitNum, width);
228 }
229 
objectToWalk(uint8 gridIdx,uint32 bitNum,uint32 width)230 void Grid::objectToWalk(uint8 gridIdx, uint32 bitNum, uint32 width) {
231 	for (uint32 cnt = 0; cnt < width; cnt++) {
232 		_gameGrids[gridIdx][bitNum >> 3] |= (1 << (bitNum & 0x7));
233 		if ((bitNum & 0x1F) == 0)
234 			bitNum += 0x3F;
235 		else
236 			bitNum--;
237 	}
238 }
239 
plotGrid(uint32 x,uint32 y,uint32 width,Compact * cpt)240 void Grid::plotGrid(uint32 x, uint32 y, uint32 width, Compact *cpt) {
241 	uint32 resBitPos, resWidth;
242 	uint8 resGridIdx;
243 	if (getGridValues(x, y, width-1, cpt, &resGridIdx, &resBitPos, &resWidth))
244 		objectToWalk(resGridIdx, resBitPos, resWidth);
245 }
246 
removeGrid(uint32 x,uint32 y,uint32 width,Compact * cpt)247 void Grid::removeGrid(uint32 x, uint32 y, uint32 width, Compact *cpt) {
248 	uint32 resBitPos, resWidth;
249 	uint8 resGridIdx;
250 	if (getGridValues(x, y, width, cpt, &resGridIdx, &resBitPos, &resWidth))
251 		removeObjectFromWalk(resGridIdx, resBitPos, resWidth);
252 }
253 
giveGrid(uint32 pScreen)254 uint8 *Grid::giveGrid(uint32 pScreen) {
255 	if ((_gridConvertTable[pScreen] >= 0) && (_gridConvertTable[pScreen] < TOT_NO_GRIDS)) {
256 		return _gameGrids[_gridConvertTable[pScreen]];
257 	}
258 	return 0;
259 }
260 
261 } // End of namespace Sky
262