1 /*
2  * Holotz's Castle
3  * Copyright (C) 2004 Juan Carlos Seijo P�rez
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc., 59
17  * Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Juan Carlos Seijo P�rez
20  * jacob@mainreactor.net
21  */
22 
23 /** Map definition file for Holotz's Castle.
24  * @file    HCMap.cpp
25  * @author  Juan Carlos Seijo P�rez
26  * @date    29/04/2004
27  * @version 0.0.1 - 29/04/2004 - First version.
28  */
29 
30 #include <HCMap.h>
31 
HCMap()32 HCMap::HCMap()
33 {
34 	cells = 0;
35 	rows = cols = cellWidth = cellHeight = 0;
36 	width = height = 0;
37 	exitRow = exitCol = 0;
38 	linkCells = 0;
39 
40 	//gravity = 0.7f;
41 	gravity = 0.9f;
42 }
43 
Init(HCTheme & _theme)44 bool HCMap::Init(HCTheme &_theme)
45 {
46 	cells = 0;
47 	rows = cols = 0;
48 	width = height = 0;
49 	exitRow = exitCol = 0;
50 
51 	theme = &_theme;
52 
53 	// Inits common parameters
54 	cellWidth = theme->Floor(0).Width();
55 	cellHeight = theme->Floor(0).Height();
56 
57 	Pos(0, 0);
58 
59 	return true;
60 }
61 
Update()62 s32 HCMap::Update()
63 {
64 	HCMapCell *mc = linkCells;
65 
66 	while (mc)
67 	{
68 		mc->cell->Update();
69 		mc = mc->next;
70 	}
71 
72   return 1;
73 }
74 
Draw()75 void HCMap::Draw()
76 {
77 	HCMapCell *mc = linkCells;
78 
79 	while (mc)
80 	{
81 		mc->cell->Draw();
82 		mc = mc->next;
83 	}
84 }
85 
Pos(float xPos,float yPos)86 void HCMap::Pos(float xPos, float yPos)
87 {
88 	pos.x = xPos;
89 	pos.y = yPos;
90 
91 	for (s32 j = 0; j < rows; ++j)
92 	{
93 		for (s32 i = 0; i < cols; ++i)
94 		{
95 			cells[j][i]->Pos(xPos + (i * cellWidth), yPos + (j * cellHeight));
96 		}
97 	}
98 }
99 
ScreenToMap(s32 & xPos,s32 & yPos)100 void HCMap::ScreenToMap(s32 &xPos, s32 &yPos)
101 {
102 	xPos = ToCol(xPos);
103 	yPos = ToRow(yPos);
104 }
105 
MapToScreen(s32 & col,s32 & row)106 void HCMap::MapToScreen(s32 &col, s32 &row)
107 {
108 	col = ToX(col);
109 	row = ToY(row);
110 
111 	// Adds the map offset and the distance to the baseline's mid-point
112 	col += (s32)pos.x + cellWidth/2;
113 	row += (s32)Y() + cellHeight - 1;
114 }
115 
ToCol(s32 xx)116 s32 HCMap::ToCol(s32 xx)
117 {
118 	// Removes map offsets
119 	xx -= (s32)pos.x;
120 
121 	if (xx < 0)
122 	{
123 		return 0;
124 	}
125 
126 	xx /= cellWidth;
127 
128 	return (xx > cols-1 ? cols-1 : xx);
129 }
130 
ToRow(s32 yy)131 s32 HCMap::ToRow(s32 yy)
132 {
133 	// Removes map offsets
134 	yy -= (s32)pos.y;
135 
136 	if (yy < 0)
137 	{
138 		return 0;
139 	}
140 
141 	yy /= cellHeight;
142 
143 	return (yy > rows-1 ? rows-1 : yy);
144 }
145 
ToX(s32 col)146 s32 HCMap::ToX(s32 col)
147 {
148 	col *= cellWidth;
149 
150 	// Adds the map offset and the distance to the baseline's mid-point
151 	col += (s32)pos.x + cellWidth/2;
152 	return col;
153 }
154 
ToY(s32 row)155 s32 HCMap::ToY(s32 row)
156 {
157 	row *= cellHeight;
158 
159 	// Adds the map offset and the distance to the baseline's mid-point
160 	row += (s32)pos.y + cellHeight - 1;
161 	return row;
162 }
163 
Resize(s32 newRows,s32 newCols,bool growRight,bool growDown)164 void HCMap::Resize(s32 newRows, s32 newCols, bool growRight, bool growDown)
165 {
166 	if (newRows == 0 || newCols == 0)
167 	{
168 		// Only destroys the cells
169 		Destroy();
170 
171 		return;
172 	}
173 
174 	HCCell ***newCells;
175 
176 	// Creates the map cells
177 	newCells = new HCCell **[newRows];
178 
179 	for (s32 j = 0; j < newRows; ++j)
180 	{
181 		newCells[j] = new HCCell *[newCols];
182 		memset(newCells[j], 0, sizeof(HCCell*) * newCols);
183 	}
184 
185 	if (cells != 0)
186 	{
187 		s32 maxRows = rows > newRows ? newRows : rows;
188 		s32 maxCols = cols > newCols ? newCols : cols;
189 
190 		// Copies the existing cells, reducing, if necessary from the top right
191 		// corner. Defaults the rest of the cells, in case of enlargement, to blank
192 		for (s32 row = 0; row < newRows; ++row)
193 		{
194 			for (s32 col = 0; col < newCols; ++col)
195 			{
196 				if (row < maxRows && col < maxCols)
197 				{
198 					// while reducing
199 					if (growDown)
200 					{
201 						if (growRight)
202 						{
203 							newCells[row][col] = cells[row][col];
204 							cells[row][col] = 0;
205 						}
206 						else
207 						{
208 							newCells[row][newCols - 1 - col] = cells[row][cols - col - 1];
209 							cells[row][cols - col - 1] = 0;
210 						}
211 					}
212 					else
213 					{
214 						if (growRight)
215 						{
216 							newCells[newRows - 1 - row][col] = cells[rows - row - 1][col];
217 							cells[rows - row - 1][col] = 0;
218 						}
219 						else
220 						{
221 							newCells[newRows - 1 - row][newCols - 1 - col] = cells[rows - row - 1][cols - col - 1];
222 							cells[rows - row - 1][cols - col - 1] = 0;
223 						}
224 					}
225 				}
226 				else
227 				{
228 					// If enlarging
229 					if (growDown)
230 					{
231 						if (growRight)
232 						{
233 							newCells[row][col] = new HCCell;                                // Grows down-right
234 						}
235 						else
236 						{
237 							newCells[row][newCols - 1 - col] = new HCCell;                  // Grows down-left
238 						}
239 					}
240 					else
241 					{
242 						if (growRight)
243 						{
244 							newCells[newRows - 1 - row][col] = new HCCell;                  // Grows up-left
245 						}
246 						else
247 						{
248 							newCells[newRows - 1 - row][newCols - 1 - col] = new HCCell;    // Grows up-right
249 						}
250 					}
251 				}
252 			}
253 		}
254 
255 		// Destroy the rest of the original cells if reducing
256 		Destroy();
257 	}
258 	else
259 	{
260 		// Initializes the map to empty cells
261 		for (s32 row = 0; row < newRows; ++row)
262 		{
263 			for (s32 col = 0; col < newCols; ++col)
264 			{
265 				newCells[row][col] = new HCCell;
266 			}
267 		}
268 	}
269 
270 	cells = newCells;
271 	rows = newRows;
272 	cols = newCols;
273 	width = cellWidth * cols;
274 	height = cellHeight * rows;
275 
276 	Pos(pos.x, pos.y);
277 
278 	BuildCellLinkList();
279 }
280 
Destroy()281 void HCMap::Destroy()
282 {
283   if (0 != cells)
284   {
285     for (s32 row = 0; row < rows; ++row)
286     {
287       for (s32 col = 0; col < cols; ++col)
288       {
289         JDELETE(cells[row][col]);
290       }
291 
292       delete[] cells[row];
293       cells[row] = 0;
294     }
295 
296     delete[] cells;
297     cells = 0;
298   }
299 
300 	DestroyCellLinkList();
301 }
302 
BuildContFloorOnce(s32 row,s32 col)303 void HCMap::BuildContFloorOnce(s32 row, s32 col)
304 {
305 	if (cells[row][col]->Type() == HCCELLTYPE_CONTFLOOR)
306 	{
307 		((HCContFloor *)cells[row][col])->Build(theme->ContFloor(cells[row][col]->Subtype()),
308 																						cells[row-1][col-1]->Type() == HCCELLTYPE_CONTFLOOR,
309 																						cells[row-1][col]->Type() == HCCELLTYPE_CONTFLOOR,
310 																						cells[row-1][col+1]->Type() == HCCELLTYPE_CONTFLOOR,
311 																						cells[row][col-1]->Type() == HCCELLTYPE_CONTFLOOR,
312 																						cells[row][col+1]->Type() == HCCELLTYPE_CONTFLOOR,
313 																						cells[row+1][col-1]->Type() == HCCELLTYPE_CONTFLOOR,
314 																						cells[row+1][col]->Type() == HCCELLTYPE_CONTFLOOR,
315 																						cells[row+1][col+1]->Type() == HCCELLTYPE_CONTFLOOR);
316 	}
317 }
318 
BuildContFloor(s32 row,s32 col)319 void HCMap::BuildContFloor(s32 row, s32 col)
320 {
321 	BuildContFloorOnce(row - 1, col - 1);
322 	BuildContFloorOnce(row - 1, col);
323 	BuildContFloorOnce(row - 1, col + 1);
324 	BuildContFloorOnce(row, col - 1);
325 	BuildContFloorOnce(row, col);
326 	BuildContFloorOnce(row, col + 1);
327 	BuildContFloorOnce(row + 1, col - 1);
328 	BuildContFloorOnce(row + 1, col);
329 	BuildContFloorOnce(row + 1, col + 1);
330 }
331 
BuildCellLinkList()332 void HCMap::BuildCellLinkList()
333 {
334 	DestroyCellLinkList();
335 
336 	HCMapCell *mc = 0, *mcOld = 0;
337 
338 	for (s32 row = 0; row < rows; ++row)
339 	{
340 		for (s32 col = 0; col < cols; ++col)
341 		{
342 			if (cells[row][col]->Type() != HCCELLTYPE_BLANK)
343 			{
344 				mc = new HCMapCell;
345 				mc->cell = cells[row][col];
346 
347 				if (mcOld)
348 				{
349 					mcOld->next = mc;
350 				}
351 
352 				if (!linkCells)
353 				{
354 					linkCells = mc;
355 				}
356 
357         mcOld = mc;
358 			}
359 		}
360 	}
361 
362 	if (mc)
363 	{
364 		mc->next = 0;
365 	}
366 }
367 
DestroyCellLinkList()368 void HCMap::DestroyCellLinkList()
369 {
370 	if (0 != linkCells)
371 	{
372 		HCMapCell *mc = linkCells, *tmp;
373 
374 		while (mc)
375 		{
376 			tmp = mc->next;
377 			delete mc;
378 			mc = tmp;
379 		}
380 
381 		linkCells = 0;
382 	}
383 }
384 
Load(JRW & f)385 u32 HCMap::Load(JRW &f)
386 {
387 	Destroy();
388 
389 	// Loads the number of rows and cols, etc.
390 	if (0 == f.ReadLE32((u32 *)&gravity) ||
391 			0 == f.ReadLE32(&rows) ||
392 			0 == f.ReadLE32(&cols) ||
393 			0 == f.ReadLE32(&exitRow) ||
394 			0 == f.ReadLE32(&exitCol))
395 	{
396 		return 1;
397 	}
398 
399 	Resize(rows, cols);
400 
401 	// Loads the cells
402 	s32 ret = 1;
403 	s32 t, subt;
404 	HCBreak *prevBreak = 0;
405 
406 	for (s32 row = 0; ret != 0 && row < rows; ++row)
407 	{
408 		for (s32 col = 0; ret != 0 && col < cols; ++col)
409 		{
410 			ret = f.ReadLE32(&t);
411 			ret = f.ReadLE32(&subt);
412 
413 			if (t != HCCELLTYPE_BREAK)
414 			{
415 				prevBreak = 0;
416 			}
417 
418 			JDELETE(cells[row][col]);
419 
420 			switch (t)
421 			{
422 			case HCCELLTYPE_FLOOR:
423 				cells[row][col] = new HCFloorCell(&(theme->Floor(subt)));
424 				cells[row][col]->Subtype(subt);
425 				break;
426 
427 			case HCCELLTYPE_CONTFLOOR:
428 				cells[row][col] = new HCContFloor;
429 				cells[row][col]->Subtype(subt);
430 				break;
431 
432 			case HCCELLTYPE_BAR:
433 				cells[row][col] = new HCBarCell(&(theme->Bar(subt)));
434 				cells[row][col]->Subtype(subt);
435 				break;
436 
437 			case HCCELLTYPE_LADDER:
438 				cells[row][col] = new HCLadderCell(&(theme->Ladder(subt)));
439 				cells[row][col]->Subtype(subt);
440 				break;
441 
442 			case HCCELLTYPE_BREAK:
443 				cells[row][col] = prevBreak = new HCBreak(theme->Break(subt),	prevBreak);
444 				cells[row][col]->Subtype(subt);
445 				break;
446 
447 			case HCCELLTYPE_BLANK:
448 			default:
449 				cells[row][col] = new HCCell;
450 				cells[row][col]->Subtype(subt);
451 				break;
452 			}
453 
454 			t = cells[row][col]->Type();
455 		}
456 	}
457 
458 	for (s32 row = 1; ret != 0 && row < rows - 1; ++row)
459 	{
460 		for (s32 col = 1; ret != 0 && col < cols - 1; ++col)
461 		{
462 			if (cells[row][col]->Type() == HCCELLTYPE_CONTFLOOR)
463 				BuildContFloor(row, col);
464 		}
465 	}
466 
467 	BuildCellLinkList();
468 
469 	return 0;
470 }
471 
Save(JRW & f)472 u32 HCMap::Save(JRW &f)
473 {
474 	// Saves the number of rows and cols, etc.
475 	if (0 == f.WriteLE32((u32 *)&gravity) ||
476 			0 == f.WriteLE32(&rows) ||
477 			0 == f.WriteLE32(&cols) ||
478 			0 == f.WriteLE32(&exitRow) ||
479 			0 == f.WriteLE32(&exitCol))
480 	{
481 		return 1;
482 	}
483 
484 	// Saves the cells
485 	s32 ret = 1;
486 	s32 data, index;
487 
488 	for (s32 row = 0; ret != 0 && row < rows; ++row)
489 	{
490 		for (s32 col = 0; ret != 0 && col < cols; ++col)
491 		{
492 			data = cells[row][col]->Type();
493 			index = cells[row][col]->Subtype();
494 			ret = f.WriteLE32(&data);
495 			ret = f.WriteLE32(&index);
496 		}
497 	}
498 
499 	return 0;
500 }
501