1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 */
21 
22 #include "headers.h"
23 
Map()24 Map::Map()
25 {
26 	clear();
27 
28 	for (int i = 0 ; i < 10 ; i++)
29 	{
30 		boss[i] = NULL;
31 	}
32 }
33 
34 
clear()35 void Map::clear()
36 {
37 	fightingGaldov = false;
38 	bossNextThink = 0;
39 
40 	foundItems = totalItems = 0;
41 	foundMIAs = totalMIAs = 0;
42 	requiredMIAs = 0;
43 
44 	limitLeft = limitUp = 0;
45 	limitRight = ((MAPWIDTH - 40) * BRICKSIZE);
46 	limitDown = ((MAPHEIGHT - 30) * BRICKSIZE);
47 
48 	name[0] = 0;
49 
50 	for (int x = 0 ; x < MAPWIDTH ; x++)
51 		for (int y = 0 ; y < MAPHEIGHT ; y++)
52 			data[x][y] = 0;
53 
54 	for (int i = 0 ; i < 10 ; i++)
55 		allowableEnemy[i] = NULL;
56 
57 	maxAllowableEnemies = 0;
58 
59 	trainList.clear();
60 	itemList.clear();
61 	bulletList.clear();
62 	enemyList.clear();
63 	miaList.clear();
64 	obstacleList.clear();
65 	particleList.clear();
66 	switchList.clear();
67 	spawnList.clear();
68 	effectList.clear();
69 	objectiveList.clear();
70 	teleportList.clear();
71 	lineList.clear();
72 	trapList.clear();
73 
74 	remainingMinutes = 0;
75 	remainingSeconds = 0;
76 
77 	waterLevel = requiredWaterLevel = -1;
78 	isBossMission = false;
79 	isIceLevel = false;
80 	isBlizzardLevel = false;
81 	isCavesTileset = false;
82 	isGrasslandsTileset = false;
83 	bossNextThink = 0;
84 	mainBossPart = NULL;
85 	doBossLevelAction = NULL;
86 	bossEnergyMeterBit = 0;
87 
88 	for (int i = 0 ; i < 10 ; i++)
89 	{
90 		if (boss[i] != NULL)
91 		{
92 			delete boss[i];
93 		}
94 		boss[i] = NULL;
95 	}
96 
97 	windPower = windChangeTime = 0;
98 }
99 
destroy()100 void Map::destroy()
101 {
102 	clear();
103 
104 	persistantList.clear();
105 }
106 
isPracticeMission()107 bool Map::isPracticeMission()
108 {
109 	if (strstr(name, "Practice"))
110 		return true;
111 
112 	return false;
113 }
114 
isValid(int x,int y)115 bool Map::isValid(int x, int y)
116 {
117 	if (x >= 0 && y >= 0 && x < MAPWIDTH && y < MAPHEIGHT)
118 		return true;
119 
120 	return false;
121 }
122 
isSolid(int x,int y)123 bool Map::isSolid(int x, int y)
124 {
125 	if (!isValid(x, y))
126 		return false;
127 
128 	if ((data[x][y] >= MAP_BREAKABLE) && (data[x][y] < MAP_DECORATION))
129 	{
130 		return true;
131 	}
132 
133 	return false;
134 }
135 
isBreakable(int x,int y)136 bool Map::isBreakable(int x, int y)
137 {
138 	if (!isValid(x, y))
139 		return false;
140 
141 	if ((data[x][y] >= MAP_BREAKABLE) && (data[x][y] <= MAP_BREAKABLE2))
142 	{
143 		return true;
144 	}
145 
146 	return false;
147 }
148 
isNoReset(int x,int y)149 bool Map::isNoReset(int x, int y)
150 {
151 	if (!isValid(x, y))
152 		return false;
153 
154 	if ((data[x][y] >= MAP_NORESET) && (data[x][y] < MAP_DECORATION))
155 	{
156 		return true;
157 	}
158 
159 	return false;
160 }
161 
isLiquid(int x,int y)162 bool Map::isLiquid(int x, int y)
163 {
164 	if (!isValid(x, y))
165 		return false;
166 
167 	if (data[x][y] == 0)
168 	{
169 		return false;
170 	}
171 	else if ((data[x][y] >= MAP_WATER) && (data[x][y] <= MAP_LAVA))
172 	{
173 		return true;
174 	}
175 	else if ((data[x][y] >= MAP_WATERANIM) && (data[x][y] <= MAP_LAVAANIM))
176 	{
177 		return true;
178 	}
179 
180 	return false;
181 }
182 
isTopLayer(int x,int y)183 bool Map::isTopLayer(int x, int y)
184 {
185 	if (!isValid(x, y))
186 		return false;
187 
188 	if (data[x][y] >= MAP_TOPLAYER)
189 	{
190 		return true;
191 	}
192 
193 	return false;
194 }
195 
getPersistant(const char * name)196 Persistant *Map::getPersistant(const char *name)
197 {
198 	Persistant *p = (Persistant*)persistantList.getHead();
199 
200 	while (p->next != NULL)
201 	{
202 		p = (Persistant*)p->next;
203 
204 		if (strcmp(p->stageName, name) == 0)
205 		{
206 			return p;
207 		}
208 	}
209 
210 	return NULL;
211 }
212 
createPersistant(const char * name)213 Persistant *Map::createPersistant(const char *name)
214 {
215 	Persistant *p = (Persistant*)persistantList.getHead();
216 
217 	while (p->next != NULL)
218 	{
219 		p = (Persistant*)p->next;
220 
221 		if (strcmp(p->stageName, name) == 0)
222 		{
223 			return p;
224 		}
225 	}
226 
227 	debug(("Creating %s in persistance list...\n", name));
228 
229 	p = new Persistant();
230 	p->setName(name);
231 
232 	persistantList.add(p);
233 
234 	return p;
235 }
236 
destroyPersistant(const char * name)237 void Map::destroyPersistant(const char *name)
238 {
239 	Persistant *p = (Persistant*)persistantList.getHead();
240 
241 	while (p->next != NULL)
242 	{
243 		p = (Persistant*)p->next;
244 
245 		if (strcmp(p->stageName, name) == 0)
246 		{
247 			strlcpy(p->stageName, "@none@", sizeof p->stageName);
248 			p->clear();
249 			return;
250 		}
251 	}
252 }
253 
setName(const char * name)254 void Map::setName(const char *name)
255 {
256 	strlcpy(this->name, name, sizeof this->name);
257 
258 	if (strstr(name, "BioMech"))
259 	{
260 		isBossMission = true;
261 	}
262 
263 	if (strcmp(name, "Galdov") == 0)
264 	{
265 		isBossMission = true;
266 	}
267 
268 	if (strcmp(name, "Final Battle") == 0)
269 	{
270 		isBossMission = true;
271 	}
272 
273 	if (strstr(name, "Ice"))
274 	{
275 		isIceLevel = true;
276 	}
277 
278 	if (strstr(name, "Arctic"))
279 	{
280 		isIceLevel = true;
281 		isBlizzardLevel = true;
282 	}
283 }
284 
setClipping(int limitLeft,int limitRight,int limitUp,int limitDown)285 void Map::setClipping(int limitLeft, int limitRight, int limitUp, int limitDown)
286 {
287 	if (limitLeft != -1) this->limitLeft = limitLeft;
288 	if (limitRight != -1) this->limitRight = limitRight;
289 	if (limitUp != -1) this->limitUp = limitUp;
290 	if (limitDown != -1) this->limitDown = limitDown;
291 }
292 
addTrain(const char * name,int startX,int startY,int endX,int endY,int pause,bool atStart,bool active)293 void Map::addTrain(const char *name, int startX, int startY, int endX, int endY, int pause, bool atStart, bool active)
294 {
295 	Train *train = new Train();
296 	train->setName(name);
297 	train->type = TR_TRAIN;
298 	train->set(startX, startY, endX, endY, pause, atStart);
299 	train->active = active;
300 
301 	train->width = 64;
302 	train->height = 16;
303 
304 	if (pause == 0)
305 	{
306 		debug(("WARNING: TRAIN WITH 0 WAIT TIME ADDED '%s' (%d:%d)\n", name, startX, startY));
307 	}
308 
309 	trainList.add(train);
310 }
311 
addDoor(const char * name,int type,int startX,int startY,int endX,int endY,bool active)312 void Map::addDoor(const char *name, int type, int startX, int startY, int endX, int endY, bool active)
313 {
314 	Train *train = new Train();
315 	train->setName(name);
316 
317 	train->type = type;
318 
319 	train->set(startX, startY, endX, endY, 0, false);
320 	train->active = active;
321 
322 	if (type < TR_SLIDEDOOR)
323 	{
324 		train->width = 16;
325 		train->height = 64;
326 	}
327 	else
328 	{
329 		train->width = 64;
330 		train->height = 16;
331 	}
332 
333 	trainList.add(train);
334 }
335 
addSwitch(const char * name,const char * linkName,const char * requiredObjectName,const char * activateMessage,int type,int x,int y,bool activated)336 void Map::addSwitch(const char *name, const char *linkName, const char *requiredObjectName, const char *activateMessage, int type, int x, int y, bool activated)
337 {
338 	Switch *swt = new Switch();
339 	swt->set(name, linkName, requiredObjectName, activateMessage, type, x, y, activated);
340 
341 	switchList.add(swt);
342 }
343 
addItem(Entity * item)344 void Map::addItem(Entity *item)
345 {
346 	itemList.add(item);
347 }
348 
addBullet(Entity * bullet)349 void Map::addBullet(Entity *bullet)
350 {
351 	bulletList.add(bullet);
352 }
353 
addParticle(float x,float y,float dx,float dy,int health,int color,Sprite * sprite,int flags)354 void Map::addParticle(float x, float y, float dx, float dy, int health, int color, Sprite *sprite, int flags)
355 {
356 	Particle *particle = new Particle();
357 	particle->set(x, y, dx, dy, color, health, flags);
358 	particle->setSprite(sprite);
359 
360 	particleList.add(particle);
361 }
362 
addEnemy(Entity * enemy)363 void Map::addEnemy(Entity *enemy)
364 {
365 	enemyList.add(enemy);
366 }
367 
addMIA(Entity * mia)368 void Map::addMIA(Entity *mia)
369 {
370 	miaList.add(mia);
371 }
372 
addObstacle(Entity * obstacle)373 void Map::addObstacle(Entity *obstacle)
374 {
375 	obstacleList.add(obstacle);
376 }
377 
addSpawnPoint(const char * name,int x,int y,int type,int subtype,int min,int max,bool active)378 void Map::addSpawnPoint(const char *name, int x, int y, int type, int subtype, int min, int max, bool active)
379 {
380 	SpawnPoint *spawnPoint = new SpawnPoint();
381 	spawnPoint->create(name, x, y, type, subtype, min, max, active);
382 
383 	spawnList.add(spawnPoint);
384 }
385 
addEffect(Effect * effect)386 void Map::addEffect(Effect *effect)
387 {
388 	effectList.add(effect);
389 }
390 
addObjective(const char * description,const char * target,int targetValue,bool required)391 void Map::addObjective(const char *description, const char *target, int targetValue, bool required)
392 {
393 	Objective *objective = new Objective(description, target, targetValue, required);
394 
395 	objectiveList.add(objective);
396 }
397 
addTeleporter(Teleporter * teleporter)398 void Map::addTeleporter(Teleporter *teleporter)
399 {
400 	teleportList.add(teleporter);
401 }
402 
addLineDef(LineDef * lineDef)403 void Map::addLineDef(LineDef *lineDef)
404 {
405 	lineList.add(lineDef);
406 }
407 
addTrap(Trap * trap)408 void Map::addTrap(Trap *trap)
409 {
410 	trapList.add(trap);
411 }
412 
evalTileset(const char * baseDir)413 void Map::evalTileset(const char *baseDir)
414 {
415 	if (strstr(baseDir, "caves"))
416 	{
417 		isCavesTileset = true;
418 	}
419 	else if (strstr(baseDir, "grasslands"))
420 	{
421 		isGrasslandsTileset = true;
422 	}
423 }
424 
killAllEnemies()425 void Map::killAllEnemies()
426 {
427 	Entity *enemy = (Entity*)enemyList.getHead()->next;
428 
429 	while (enemy != NULL)
430 	{
431 		enemy->health = -1;
432 
433 		enemy = (Entity*)enemy->next;
434 	}
435 }
436 
setAllowableEnemy(Entity * enemy)437 void Map::setAllowableEnemy(Entity *enemy)
438 {
439 	for (int i = 0 ; i < 10 ; i++)
440 	{
441 		if (allowableEnemy[i] == NULL)
442 		{
443 			allowableEnemy[i] = enemy;
444 			maxAllowableEnemies = i + 1;
445 			return;
446 		}
447 	}
448 
449 	debug(("WARNING: Can't add anymore spawnable enemies to list!!!\n"));
450 }
451 
getSpawnableEnemy(int i)452 char *Map::getSpawnableEnemy(int i)
453 {
454 	if (allowableEnemy[i] == NULL)
455 		return NULL;
456 
457 	return allowableEnemy[i]->name;
458 }
459 
getSpawnableEnemy()460 char *Map::getSpawnableEnemy()
461 {
462 	if (maxAllowableEnemies == 0)
463 	{
464 		printf("ERROR: No enemy spawn list defined for map '%s'!! Please report this Error!\n", name);
465 		exit(1);
466 	}
467 
468 	return allowableEnemy[Math::prand() % maxAllowableEnemies]->name;
469 }
470 
getRandomEntityPosition(int * x,int * y)471 void Map::getRandomEntityPosition(int *x, int *y)
472 {
473 	Entity *ent = (Entity*)miaList.getHead();
474 
475 	while (ent->next != NULL)
476 	{
477 		ent = (Entity*)ent->next;
478 
479 		if ((Math::prand() % 5) == 0)
480 		{
481 			*x = (int)ent->x;
482 			*y = (int)ent->y;
483 			return;
484 		}
485 	}
486 
487 	ent = (Entity*)enemyList.getHead();
488 
489 	while (ent->next != NULL)
490 	{
491 		ent = (Entity*)ent->next;
492 
493 		if ((Math::prand() % 5) == 0)
494 		{
495 			*x = (int)ent->x;
496 			*y = (int)ent->y;
497 			return;
498 		}
499 	}
500 
501 	ent = (Entity*)itemList.getHead();
502 
503 	while (ent->next != NULL)
504 	{
505 		ent = (Entity*)ent->next;
506 
507 		if ((Math::prand() % 5) == 0)
508 		{
509 			*x = (int)ent->x;
510 			*y = (int)ent->y;
511 			return;
512 		}
513 	}
514 }
515 
setMainBossPart(Boss * boss)516 void Map::setMainBossPart(Boss *boss)
517 {
518 	mainBossPart = boss;
519 
520 	if (mainBossPart != NULL)
521 	{
522 		bossEnergyMeterBit = 200;
523 		bossEnergyMeterBit /= boss->maxHealth;
524 	}
525 }
526