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