1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: maps.cpp
5 	Desc: level generator code
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include "main.hpp"
13 #include "game.hpp"
14 #include "stat.hpp"
15 #include "entity.hpp"
16 #include "files.hpp"
17 #include "items.hpp"
18 #include "prng.hpp"
19 #include "monster.hpp"
20 #include "magic/magic.hpp"
21 #include "interface/interface.hpp"
22 #include "book.hpp"
23 #include "net.hpp"
24 #include "paths.hpp"
25 #include "collision.hpp"
26 #include "player.hpp"
27 #include "scores.hpp"
28 #include "mod_tools.hpp"
29 #include "menu.hpp"
30 
31 int startfloor = 0;
32 
33 /*-------------------------------------------------------------------------------
34 
35 	monsterCurve
36 
37 	selects a monster randomly, taking into account the region the monster
38 	is being spawned in
39 
40 -------------------------------------------------------------------------------*/
41 
monsterCurve(int level)42 int monsterCurve(int level)
43 {
44 	if ( !strncmp(map.name, "The Mines", 9) )   // the mines
45 	{
46 		switch ( rand() % 10 )
47 		{
48 			case 0:
49 			case 1:
50 			case 2:
51 			case 3:
52 				return RAT;
53 			case 4:
54 			case 5:
55 			case 6:
56 			case 7:
57 				return SKELETON;
58 			case 8:
59 				if ( level >= 2 )
60 				{
61 					return SPIDER;
62 				}
63 				else
64 				{
65 					return SKELETON;
66 				}
67 			case 9:
68 				if ( level >= 2 )
69 				{
70 					return TROLL;
71 				}
72 				else
73 				{
74 					return SKELETON;
75 				}
76 				break;
77 		}
78 	}
79 	else if ( !strncmp(map.name, "The Swamp", 9) )     // the swamp
80 	{
81 		switch ( rand() % 10 )
82 		{
83 			case 0:
84 			case 1:
85 				return SPIDER;
86 			case 2:
87 			case 3:
88 			case 4:
89 				return GOBLIN;
90 			case 5:
91 			case 6:
92 			case 7:
93 				return SLIME;
94 			case 8:
95 			case 9:
96 				return GHOUL;
97 		}
98 	}
99 	else if ( !strncmp(map.name, "The Labyrinth", 13) )     // sand labyrinth
100 	{
101 		switch ( rand() % 20 )
102 		{
103 			case 0:
104 			case 1:
105 			case 2:
106 			case 3:
107 				return GOBLIN;
108 			case 4:
109 			case 5:
110 			case 6:
111 			case 7:
112 			case 8:
113 				return SCORPION;
114 			case 9:
115 			case 10:
116 			case 11:
117 			case 12:
118 				return TROLL;
119 			case 13:
120 			case 14:
121 			case 15:
122 			case 16:
123 				return SCARAB;
124 			case 17:
125 			case 18:
126 			case 19:
127 				return INSECTOID;
128 		}
129 	}
130 	else if ( !strncmp(map.name, "The Ruins", 9) )     // blue ruins
131 	{
132 		switch ( rand() % 10 )
133 		{
134 			case 0:
135 				return GOBLIN;
136 			case 1:
137 			case 2:
138 			case 3:
139 				return GNOME;
140 			case 4:
141 			case 5:
142 			case 6:
143 			case 7:
144 				return TROLL;
145 			case 8:
146 				if ( rand() % 10 > 0 )
147 				{
148 					return TROLL;
149 				}
150 				else
151 				{
152 					return VAMPIRE;
153 				}
154 			case 9:
155 				return DEMON;
156 		}
157 	}
158 	else if ( !strncmp(map.name, "Underworld", 10) )     // underworld
159 	{
160 		switch ( rand() % 10 )
161 		{
162 			case 0:
163 				return SLIME;
164 			case 1:
165 				return SHADOW;
166 			case 2:
167 			case 3:
168 			case 4:
169 				return CREATURE_IMP;
170 			case 5:
171 			case 6:
172 			case 7:
173 				return GHOUL;
174 			case 8:
175 			case 9:
176 				return SKELETON;
177 		}
178 	}
179 	else if ( !strncmp(map.name, "Hell", 4) )     // hell
180 	{
181 		switch ( rand() % 20 )
182 		{
183 			case 0:
184 			case 1:
185 				return SUCCUBUS;
186 			case 2:
187 			case 3:
188 				return INCUBUS;
189 			case 4:
190 			case 5:
191 			case 6:
192 			case 7:
193 			case 8:
194 				if ( strstr(map.name, "Boss") )
195 				{
196 					return DEMON;    // we would otherwise lag bomb on the boss level
197 				}
198 				else
199 				{
200 					return CREATURE_IMP;
201 				}
202 			case 9:
203 			case 10:
204 			case 11:
205 			case 12:
206 			case 13:
207 			case 14:
208 				return DEMON;
209 			case 15:
210 			case 16:
211 			case 17:
212 			case 18:
213 				return GOATMAN;
214 			case 19:
215 				return SHADOW;
216 		}
217 	}
218 	else if ( !strncmp(map.name, "Caves", 5) )
219 	{
220 		if ( currentlevel <= 26 )
221 		{
222 			switch ( rand() % 15 )
223 			{
224 				case 0:
225 				case 1:
226 				case 2:
227 				case 3:
228 				case 4:
229 					return KOBOLD;
230 				case 5:
231 				case 6:
232 					return SCARAB;
233 				case 7:
234 					return AUTOMATON;
235 				case 8:
236 				case 9:
237 				case 10:
238 				case 11:
239 					return INSECTOID;
240 				case 12:
241 				case 13:
242 					if ( rand() % 2 == 0 )
243 					{
244 						return INCUBUS;
245 					}
246 					else
247 					{
248 						return INSECTOID;
249 					}
250 				case 14:
251 					if ( rand() % 2 == 0 )
252 					{
253 						return CRYSTALGOLEM;
254 					}
255 					else
256 					{
257 						return COCKATRICE;
258 					}
259 			}
260 		}
261 		else
262 		{
263 			switch ( rand() % 15 )
264 			{
265 				case 0:
266 				case 1:
267 				case 2:
268 				case 3:
269 					return KOBOLD;
270 				case 4:
271 					return SCARAB;
272 				case 5:
273 					return AUTOMATON;
274 				case 6:
275 				case 7:
276 				case 8:
277 				case 9:
278 					return INSECTOID;
279 				case 10:
280 				case 11:
281 				case 12:
282 					return CRYSTALGOLEM;
283 				case 13:
284 					return INCUBUS;
285 				case 14:
286 					return COCKATRICE;
287 			}
288 		}
289 	}
290 	else if ( !strncmp(map.name, "Citadel", 7) )
291 	{
292 		switch ( rand() % 15 )
293 		{
294 			case 0:
295 				return KOBOLD;
296 			case 1:
297 				return SCARAB;
298 			case 2:
299 			case 3:
300 			case 4:
301 			case 5:
302 				return GOATMAN;
303 			case 6:
304 			case 7:
305 				return CRYSTALGOLEM;
306 			case 8:
307 			case 9:
308 				return VAMPIRE;
309 			case 10:
310 				return SHADOW;
311 			case 11:
312 				return INCUBUS;
313 			case 12:
314 				return AUTOMATON;
315 			case 13:
316 			case 14:
317 				return COCKATRICE;
318 		}
319 	}
320 	return SKELETON; // basic monster
321 }
322 
323 /*-------------------------------------------------------------------------------
324 
325 	generateDungeon
326 
327 	generates a level by drawing data from numerous files and connecting
328 	their rooms together with tunnels.
329 
330 -------------------------------------------------------------------------------*/
331 
generateDungeon(char * levelset,Uint32 seed,std::tuple<int,int,int,int> mapParameters)332 int generateDungeon(char* levelset, Uint32 seed, std::tuple<int, int, int, int> mapParameters)
333 {
334 	char* sublevelname, *subRoomName;
335 	char sublevelnum[3];
336 	map_t* tempMap, *subRoomMap;
337 	list_t mapList, *newList, *subRoomList, subRoomMapList;
338 	node_t* node, *node2, *node3, *nextnode, *subRoomNode;
339 	Sint32 c, i, j;
340 	Sint32 numlevels, levelnum, levelnum2, subRoomNumLevels;
341 	Sint32 x, y, z;
342 	Sint32 x0, y0, x1, y1;
343 	door_t* door, *newDoor;
344 	bool* possiblelocations, *possiblelocations2, *possiblerooms;
345 	bool* firstroomtile;
346 	Sint32 numpossiblelocations, pickedlocation, subroomPickRoom;
347 	Entity* entity, *entity2, *childEntity;
348 	Uint32 levellimit;
349 	list_t doorList;
350 	node_t* doorNode, *subRoomDoorNode;
351 	bool shoplevel = false;
352 	map_t shopmap;
353 	map_t secretlevelmap;
354 	int secretlevelexit = 0;
355 	bool *trapexcludelocations;
356 	bool *monsterexcludelocations;
357 	bool *lootexcludelocations;
358 
359 	if ( std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) == -1
360 		&& std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) == -1
361 		&& std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) == -1
362 		&& std::get<LEVELPARAM_DISABLE_NORMAL_EXIT>(mapParameters) == 0 )
363 	{
364 		printlog("generating a dungeon from level set '%s' (seed %d)...\n", levelset, seed);
365 	}
366 	else
367 	{
368 		char generationLog[256] = "generating a dungeon from level set '%s'";
369 		char tmpBuffer[32];
370 		if ( std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) != -1 )
371 		{
372 			snprintf(tmpBuffer, 31, ", secret chance %d%%%%", std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters));
373 			strcat(generationLog, tmpBuffer);
374 		}
375 		if ( std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) != -1 )
376 		{
377 			snprintf(tmpBuffer, 31, ", darkmap chance %d%%%%", std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters));
378 			strcat(generationLog, tmpBuffer);
379 		}
380 		if ( std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) != -1 )
381 		{
382 			snprintf(tmpBuffer, 31, ", minotaur chance %d%%%%", std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters));
383 			strcat(generationLog, tmpBuffer);
384 		}
385 		if ( std::get<LEVELPARAM_DISABLE_NORMAL_EXIT>(mapParameters) != 0 )
386 		{
387 			snprintf(tmpBuffer, 31, ", disabled normal exit", std::get<LEVELPARAM_DISABLE_NORMAL_EXIT>(mapParameters));
388 			strcat(generationLog, tmpBuffer);
389 		}
390 		strcat(generationLog, ", (seed %d)...\n");
391 		printlog(generationLog, levelset, seed);
392 
393 		conductGameChallenges[CONDUCT_MODDED] = 1;
394 	}
395 
396 	std::string fullMapPath;
397 	fullMapPath = physfsFormatMapName(levelset);
398 
399 	int checkMapHash = -1;
400 	if ( fullMapPath.empty() || loadMap(fullMapPath.c_str(), &map, map.entities, map.creatures, &checkMapHash) == -1 )
401 	{
402 		printlog("error: no level of set '%s' could be found.\n", levelset);
403 		return -1;
404 	}
405 	if ( checkMapHash == 0 )
406 	{
407 		conductGameChallenges[CONDUCT_MODDED] = 1;
408 	}
409 
410 	// store this map's seed
411 	mapseed = seed;
412 	prng_seed_bytes(&mapseed, sizeof(mapseed));
413 
414 	// generate a custom monster curve if file exists
415 	monsterCurveCustomManager.readFromFile();
416 
417 	// determine whether shop level or not
418 	if ( gameplayCustomManager.processedShopFloor(currentlevel, secretlevel, map.name, shoplevel) )
419 	{
420 		// function sets shop level for us.
421 	}
422 	else if ( prng_get_uint() % 2 && currentlevel > 1 && strncmp(map.name, "Underworld", 10) && strncmp(map.name, "Hell", 4) )
423 	{
424 		shoplevel = true;
425 	}
426 
427 	// determine whether minotaur level or not
428 	if ( (svFlags & SV_FLAG_MINOTAURS) && gameplayCustomManager.processedMinotaurSpawn(currentlevel, secretlevel, map.name) )
429 	{
430 		// function sets mino level for us.
431 	}
432 	else if ( std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) != -1 )
433 	{
434 		if ( prng_get_uint() % 100 < std::get<LEVELPARAM_CHANCE_MINOTAUR>(mapParameters) && (svFlags & SV_FLAG_MINOTAURS) )
435 		{
436 			minotaurlevel = 1;
437 		}
438 	}
439 	else if ( (currentlevel < 25 && (currentlevel % LENGTH_OF_LEVEL_REGION == 2 || currentlevel % LENGTH_OF_LEVEL_REGION == 3))
440 		|| (currentlevel > 25 && (currentlevel % LENGTH_OF_LEVEL_REGION == 2 || currentlevel % LENGTH_OF_LEVEL_REGION == 4)) )
441 	{
442 		if ( prng_get_uint() % 2 && (svFlags & SV_FLAG_MINOTAURS) )
443 		{
444 			minotaurlevel = 1;
445 		}
446 	}
447 
448 	// dark level
449 	if ( gameplayCustomManager.processedDarkFloor(currentlevel, secretlevel, map.name) )
450 	{
451 		// function sets dark level for us.
452 		if ( darkmap )
453 		{
454 			messagePlayer(clientnum, language[1108]);
455 		}
456 	}
457 	else if ( !secretlevel )
458 	{
459 		if ( std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) != -1 )
460 		{
461 			if ( prng_get_uint() % 100 < std::get<LEVELPARAM_CHANCE_DARKNESS>(mapParameters) )
462 			{
463 				darkmap = true;
464 				messagePlayer(clientnum, language[1108]);
465 			}
466 			else
467 			{
468 				darkmap = false;
469 			}
470 		}
471 		else if ( currentlevel % LENGTH_OF_LEVEL_REGION >= 2 )
472 		{
473 			if ( prng_get_uint() % 4 == 0 )
474 			{
475 				darkmap = true;
476 				messagePlayer(clientnum, language[1108]);
477 			}
478 		}
479 	}
480 
481 	// secret stuff
482 	if ( !secretlevel )
483 	{
484 		if ( std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) != -1 )
485 		{
486 			if ( prng_get_uint() % 100 < std::get<LEVELPARAM_CHANCE_SECRET>(mapParameters) )
487 			{
488 				secretlevelexit = 7;
489 			}
490 			else
491 			{
492 				secretlevelexit = 0;
493 			}
494 		}
495 		else if ( (currentlevel == 3 && prng_get_uint() % 2) || currentlevel == 2 )
496 		{
497 			secretlevelexit = 1;
498 		}
499 		else if ( currentlevel == 7 || currentlevel == 8 )
500 		{
501 			secretlevelexit = 2;
502 		}
503 		else if ( currentlevel == 11 || currentlevel == 13 )
504 		{
505 			secretlevelexit = 3;
506 		}
507 		else if ( currentlevel == 16 || currentlevel == 18 )
508 		{
509 			secretlevelexit = 4;
510 		}
511 		else if ( currentlevel == 28 )
512 		{
513 			secretlevelexit = 5;
514 		}
515 		else if ( currentlevel == 33 )
516 		{
517 			secretlevelexit = 6;
518 		}
519 	}
520 
521 	mapList.first = nullptr;
522 	mapList.last = nullptr;
523 	doorList.first = nullptr;
524 	doorList.last = nullptr;
525 
526 	// load shop room
527 	if ( shoplevel )
528 	{
529 		sublevelname = (char*) malloc(sizeof(char) * 128);
530 		for ( numlevels = 0; numlevels < 100; numlevels++ )
531 		{
532 			strcpy(sublevelname, "shop");
533 			snprintf(sublevelnum, 3, "%02d", numlevels);
534 			strcat(sublevelname, sublevelnum);
535 
536 			fullMapPath = physfsFormatMapName(sublevelname);
537 
538 			if ( fullMapPath.empty() )
539 			{
540 				break;    // no more levels to load
541 			}
542 		}
543 		if ( numlevels )
544 		{
545 			int shopleveltouse = prng_get_uint() % numlevels;
546 			if ( !strncmp(map.name, "Citadel", 7) )
547 			{
548 				strcpy(sublevelname, "shopcitadel");
549 			}
550 			else
551 			{
552 				strcpy(sublevelname, "shop");
553 				snprintf(sublevelnum, 3, "%02d", shopleveltouse);
554 				strcat(sublevelname, sublevelnum);
555 			}
556 
557 			fullMapPath = physfsFormatMapName(sublevelname);
558 
559 			shopmap.tiles = nullptr;
560 			shopmap.entities = (list_t*) malloc(sizeof(list_t));
561 			shopmap.entities->first = nullptr;
562 			shopmap.entities->last = nullptr;
563 			shopmap.creatures = new list_t;
564 			shopmap.creatures->first = nullptr;
565 			shopmap.creatures->last = nullptr;
566 			if ( fullMapPath.empty() || loadMap(fullMapPath.c_str(), &shopmap, shopmap.entities, shopmap.creatures, &checkMapHash) == -1 )
567 			{
568 				list_FreeAll(shopmap.entities);
569 				free(shopmap.entities);
570 				list_FreeAll(shopmap.creatures);
571 				delete shopmap.creatures;
572 				if ( shopmap.tiles )
573 				{
574 					free(shopmap.tiles);
575 				}
576 			}
577 			if ( checkMapHash == 0 )
578 			{
579 				conductGameChallenges[CONDUCT_MODDED] = 1;
580 			}
581 		}
582 		else
583 		{
584 			shoplevel = false;
585 		}
586 		free( sublevelname );
587 	}
588 
589 	sublevelname = (char*)malloc(sizeof(char) * 128);
590 
591 	// a maximum of 100 (0-99 inclusive) sublevels can be added to the pool
592 	for ( numlevels = 0; numlevels < 100; ++numlevels )
593 	{
594 		strcpy(sublevelname, levelset);
595 		snprintf(sublevelnum, 3, "%02d", numlevels);
596 		strcat(sublevelname, sublevelnum);
597 
598 		fullMapPath = physfsFormatMapName(sublevelname);
599 		if ( fullMapPath.empty() )
600 		{
601 			break;    // no more levels to load
602 		}
603 
604 		// allocate memory for the next sublevel and attempt to load it
605 		tempMap = (map_t*) malloc(sizeof(map_t));
606 		tempMap->tiles = nullptr;
607 		tempMap->entities = (list_t*) malloc(sizeof(list_t));
608 		tempMap->entities->first = nullptr;
609 		tempMap->entities->last = nullptr;
610 		tempMap->creatures = new list_t;
611 		tempMap->creatures->first = nullptr;
612 		tempMap->creatures->last = nullptr;
613 		if ( fullMapPath.empty() || loadMap(fullMapPath.c_str(), tempMap, tempMap->entities, tempMap->creatures, &checkMapHash) == -1 )
614 		{
615 			mapDeconstructor((void*)tempMap);
616 			continue; // failed to load level
617 		}
618 		if ( checkMapHash == 0 )
619 		{
620 			conductGameChallenges[CONDUCT_MODDED] = 1;
621 		}
622 
623 		// level is successfully loaded, add it to the pool
624 		newList = (list_t*) malloc(sizeof(list_t));
625 		newList->first = nullptr;
626 		newList->last = nullptr;
627 		node = list_AddNodeLast(&mapList);
628 		node->element = newList;
629 		node->deconstructor = &listDeconstructor;
630 
631 		node = list_AddNodeLast(newList);
632 		node->element = tempMap;
633 		node->deconstructor = &mapDeconstructor;
634 
635 		// more nodes are created to record the exit points on the sublevel
636 		for ( y = 0; y < tempMap->height; y++ )
637 		{
638 			for ( x = 0; x < tempMap->width; x++ )
639 			{
640 				if ( x == 0 || y == 0 || x == tempMap->width - 1 || y == tempMap->height - 1 )
641 				{
642 					if ( !tempMap->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * tempMap->height] )
643 					{
644 						door = (door_t*) malloc(sizeof(door_t));
645 						door->x = x;
646 						door->y = y;
647 						if ( x == tempMap->width - 1 )
648 						{
649 							door->dir = 0;
650 						}
651 						else if ( y == tempMap->height - 1 )
652 						{
653 							door->dir = 1;
654 						}
655 						else if ( x == 0 )
656 						{
657 							door->dir = 2;
658 						}
659 						else if ( y == 0 )
660 						{
661 							door->dir = 3;
662 						}
663 						node2 = list_AddNodeLast(newList);
664 						node2->element = door;
665 						node2->deconstructor = &defaultDeconstructor;
666 					}
667 				}
668 			}
669 		}
670 	}
671 
672 	subRoomName = (char*)malloc(sizeof(char) * 128);
673 	subRoomMapList.first = nullptr;
674 	subRoomMapList.last = nullptr;
675 	char letterString[2];
676 	letterString[1] = '\0';
677 	int subroomCount[100] = {0};
678 
679 	// a maximum of 100 (0-99 inclusive) sublevels can be added to the pool
680 	for ( subRoomNumLevels = 0; subRoomNumLevels <= numlevels; subRoomNumLevels++ )
681 	{
682 		for ( char letter = 'a'; letter <= 'z'; letter++ )
683 		{
684 			// look for mapnames ending in a letter a to z
685 			strcpy(subRoomName, levelset);
686 			snprintf(sublevelnum, 3, "%02d", subRoomNumLevels);
687 			letterString[0] = letter;
688 			strcat(subRoomName, sublevelnum);
689 			strcat(subRoomName, letterString);
690 
691 			fullMapPath = physfsFormatMapName(subRoomName);
692 
693 			if ( fullMapPath.empty() )
694 			{
695 				break;    // no more levels to load
696 			}
697 
698 			// check if there is another subroom to load
699 			//if ( !dataPathExists(fullMapPath.c_str()) )
700 			//{
701 			//	break;    // no more levels to load
702 			//}
703 
704 			printlog("[SUBMAP GENERATOR] Found map lv %s, count: %d", subRoomName, subroomCount[subRoomNumLevels]);
705 			++subroomCount[subRoomNumLevels];
706 
707 			// allocate memory for the next subroom and attempt to load it
708 			subRoomMap = (map_t*)malloc(sizeof(map_t));
709 			subRoomMap->tiles = nullptr;
710 			subRoomMap->entities = (list_t*)malloc(sizeof(list_t));
711 			subRoomMap->entities->first = nullptr;
712 			subRoomMap->entities->last = nullptr;
713 			subRoomMap->creatures = new list_t;
714 			subRoomMap->creatures->first = nullptr;
715 			subRoomMap->creatures->last = nullptr;
716 			if ( fullMapPath.empty() || loadMap(fullMapPath.c_str(), subRoomMap, subRoomMap->entities, subRoomMap->creatures, &checkMapHash) == -1 )
717 			{
718 				mapDeconstructor((void*)subRoomMap);
719 				continue; // failed to load level
720 			}
721 			if ( checkMapHash == 0 )
722 			{
723 				conductGameChallenges[CONDUCT_MODDED] = 1;
724 			}
725 
726 			// level is successfully loaded, add it to the pool
727 			subRoomList = (list_t*)malloc(sizeof(list_t));
728 			subRoomList->first = nullptr;
729 			subRoomList->last = nullptr;
730 			node = list_AddNodeLast(&subRoomMapList);
731 			node->element = subRoomList;
732 			node->deconstructor = &listDeconstructor;
733 
734 			node = list_AddNodeLast(subRoomList);
735 			node->element = subRoomMap;
736 			node->deconstructor = &mapDeconstructor;
737 
738 			// more nodes are created to record the exit points on the sublevel
739 			/*for ( y = 0; y < subRoomMap->height; y++ )
740 			{
741 				for ( x = 0; x < subRoomMap->width; x++ )
742 				{
743 					if ( x == 0 || y == 0 || x == subRoomMap->width - 1 || y == subRoomMap->height - 1 )
744 					{
745 						if ( !subRoomMap->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * subRoomMap->height] )
746 						{
747 							door = (door_t*)malloc(sizeof(door_t));
748 							door->x = x;
749 							door->y = y;
750 							if ( x == subRoomMap->width - 1 )
751 							{
752 								door->dir = 0;
753 							}
754 							else if ( y == subRoomMap->height - 1 )
755 							{
756 								door->dir = 1;
757 							}
758 							else if ( x == 0 )
759 							{
760 								door->dir = 2;
761 							}
762 							else if ( y == 0 )
763 							{
764 								door->dir = 3;
765 							}
766 							node2 = list_AddNodeLast(subRoomList);
767 							node2->element = door;
768 							node2->deconstructor = &defaultDeconstructor;
769 						}
770 					}
771 				}
772 			}*/
773 		}
774 	}
775 
776 	// generate dungeon level...
777 	int roomcount = 0;
778 	if ( numlevels > 1 )
779 	{
780 		possiblelocations = (bool*) malloc(sizeof(bool) * map.width * map.height);
781 		trapexcludelocations = (bool*)malloc(sizeof(bool) * map.width * map.height);
782 		monsterexcludelocations = (bool*)malloc(sizeof(bool) * map.width * map.height);
783 		lootexcludelocations = (bool*)malloc(sizeof(bool) * map.width * map.height);
784 		for ( y = 0; y < map.height; y++ )
785 		{
786 			for ( x = 0; x < map.width; x++ )
787 			{
788 				if ( x < 2 || y < 2 || x > map.width - 3 || y > map.height - 3 )
789 				{
790 					possiblelocations[x + y * map.width] = false;
791 				}
792 				else
793 				{
794 					possiblelocations[x + y * map.width] = true;
795 				}
796 				trapexcludelocations[x + y * map.width] = false;
797 				if ( map.flags[MAP_FLAG_DISABLEMONSTERS] == true )
798 				{
799 					// the base map excludes all monsters
800 					monsterexcludelocations[x + y * map.width] = true;
801 				}
802 				else
803 				{
804 					monsterexcludelocations[x + y * map.width] = false;
805 				}
806 				if ( map.flags[MAP_FLAG_DISABLELOOT] == true )
807 				{
808 					// the base map excludes all monsters
809 					lootexcludelocations[x + y * map.width] = true;
810 				}
811 				else
812 				{
813 					lootexcludelocations[x + y * map.width] = false;
814 				}
815 			}
816 		}
817 		possiblelocations2 = (bool*) malloc(sizeof(bool) * map.width * map.height);
818 		firstroomtile = (bool*) malloc(sizeof(bool) * map.width * map.height);
819 		possiblerooms = (bool*) malloc(sizeof(bool) * numlevels);
820 		for ( c = 0; c < numlevels; c++ )
821 		{
822 			possiblerooms[c] = true;
823 		}
824 		levellimit = (map.width * map.height);
825 		for ( c = 0; c < levellimit; c++ )
826 		{
827 			// reset array of possible locations for the current room
828 			for ( y = 0; y < map.height; y++ )
829 				for ( x = 0; x < map.width; x++ )
830 				{
831 					possiblelocations2[x + y * map.width] = true;
832 				}
833 
834 			// pick the room to be used
835 			if ( c == 0 )
836 			{
837 				levelnum = 0; // the first room *must* be an entrance hall
838 				levelnum2 = 0;
839 				numlevels--;
840 				possiblerooms[0] = false;
841 				node = mapList.first;
842 				node = ((list_t*)node->element)->first;
843 				doorNode = node->next;
844 				tempMap = (map_t*)node->element;
845 			}
846 			else if ( c == 1 && secretlevelexit )
847 			{
848 				secretlevelmap.tiles = nullptr;
849 				secretlevelmap.entities = (list_t*) malloc(sizeof(list_t));
850 				secretlevelmap.entities->first = nullptr;
851 				secretlevelmap.entities->last = nullptr;
852 				secretlevelmap.creatures = new list_t;
853 				secretlevelmap.creatures->first = nullptr;
854 				secretlevelmap.creatures->last = nullptr;
855 				char secretmapname[128];
856 				switch ( secretlevelexit )
857 				{
858 					case 1:
859 						strcpy(secretmapname, "minesecret");
860 						break;
861 					case 2:
862 						strcpy(secretmapname, "swampsecret");
863 						break;
864 					case 3:
865 						strcpy(secretmapname, "labyrinthsecret");
866 						break;
867 					case 4:
868 						strcpy(secretmapname, "ruinssecret");
869 						break;
870 					case 5:
871 						strcpy(secretmapname, "cavessecret");
872 						break;
873 					case 6:
874 						strcpy(secretmapname, "citadelsecret");
875 						break;
876 					case 7:
877 						strcpy(secretmapname, levelset);
878 						strcat(secretmapname, "secret");
879 						break;
880 					default:
881 						break;
882 				}
883 				fullMapPath = physfsFormatMapName(secretmapname);
884 				if ( fullMapPath.empty() || loadMap(fullMapPath.c_str(), &secretlevelmap, secretlevelmap.entities, secretlevelmap.creatures, &checkMapHash) == -1 )
885 				{
886 					list_FreeAll(secretlevelmap.entities);
887 					free(secretlevelmap.entities);
888 					list_FreeAll(secretlevelmap.creatures);
889 					delete secretlevelmap.creatures;
890 					if ( secretlevelmap.tiles )
891 					{
892 						free(secretlevelmap.tiles);
893 					}
894 				}
895 				if ( checkMapHash == 0 )
896 				{
897 					conductGameChallenges[CONDUCT_MODDED] = 1;
898 				}
899 
900 				levelnum = 0;
901 				levelnum2 = -1;
902 				tempMap = &secretlevelmap;
903 			}
904 			else if ( c == 2 && shoplevel )
905 			{
906 				// generate a shop
907 				levelnum = 0;
908 				levelnum2 = -1;
909 				tempMap = &shopmap;
910 			}
911 			else
912 			{
913 				if ( !numlevels )
914 				{
915 					break;
916 				}
917 				levelnum = prng_get_uint() % (numlevels); // draw randomly from the pool
918 
919 				// traverse the map list to the picked level
920 				node = mapList.first;
921 				i = 0;
922 				j = -1;
923 				while (1)
924 				{
925 					if (possiblerooms[i])
926 					{
927 						++j;
928 						if (j == levelnum)
929 						{
930 							break;
931 						}
932 					}
933 					node = node->next;
934 					++i;
935 				}
936 				levelnum2 = i;
937 				node = ((list_t*)node->element)->first;
938 				doorNode = node->next;
939 				tempMap = (map_t*)node->element;
940 			}
941 
942 			// find locations where the selected room can be added to the level
943 			numpossiblelocations = map.width * map.height;
944 
945 			bool hellGenerationFix = !strncmp(map.name, "Hell", 4);
946 
947 			for ( y0 = 0; y0 < map.height; y0++ )
948 			{
949 				for ( x0 = 0; x0 < map.width; x0++ )
950 				{
951 					for ( y1 = y0; y1 < std::min(y0 + tempMap->height, map.height); y1++ )
952 					{
953 						// don't generate start room in hell along the rightmost wall, causes pathing to fail. Check 2 tiles to the right extra
954 						// to try fit start room.
955 						for ( x1 = x0; x1 < std::min(x0 + tempMap->width + ((hellGenerationFix && c == 0) ? 2 : 0), map.width); x1++ )
956 						{
957 							if ( possiblelocations[x1 + y1 * map.width] == false && possiblelocations2[x0 + y0 * map.width] == true )
958 							{
959 								possiblelocations2[x0 + y0 * map.width] = false;
960 								numpossiblelocations--;
961 							}
962 						}
963 					}
964 				}
965 			}
966 
967 			// in case no locations are available, remove this room from the selection
968 			if ( numpossiblelocations <= 0 )
969 			{
970 				if ( levelnum2 >= 0 && levelnum2 < numlevels )
971 				{
972 					possiblerooms[levelnum2] = false;
973 				}
974 				--numlevels;
975 				if ( levelnum2 == 0 )
976 				{
977 					// if we couldn't even fit the entrance hall into the dungeon, we have a problem
978 					free(possiblerooms);
979 					free(possiblelocations);
980 					free(possiblelocations2);
981 					free(trapexcludelocations);
982 					free(monsterexcludelocations);
983 					free(lootexcludelocations);
984 					free(firstroomtile);
985 					free(sublevelname);
986 					free(subRoomName);
987 					list_FreeAll(&subRoomMapList);
988 					list_FreeAll(&mapList);
989 					if ( shoplevel && c == 2 )
990 					{
991 						list_FreeAll(shopmap.entities);
992 						free(shopmap.entities);
993 						list_FreeAll(shopmap.creatures);
994 						delete shopmap.creatures;
995 						if ( shopmap.tiles )
996 						{
997 							free(shopmap.tiles);
998 						}
999 					}
1000 					if ( secretlevelexit && c == 1 )
1001 					{
1002 						list_FreeAll(secretlevelmap.entities);
1003 						free(secretlevelmap.entities);
1004 						list_FreeAll(secretlevelmap.creatures);
1005 						delete secretlevelmap.creatures;
1006 						if ( secretlevelmap.tiles )
1007 						{
1008 							free(secretlevelmap.tiles);
1009 						}
1010 					}
1011 					printlog("error: entrance room must fit into dungeon!\n");
1012 					return -1;
1013 				}
1014 				else if ( numlevels < 1 )
1015 				{
1016 					// if we've run out of rooms to build the dungeon with, skip to the next step of generation
1017 					break;
1018 				}
1019 				continue;
1020 			}
1021 
1022 			// otherwise, choose a location from those available (to be stored in x/y)
1023 			if ( MFLAG_GENADJACENTROOMS )
1024 			{
1025 				pickedlocation = 0;
1026 				i = -1;
1027 				x = 0;
1028 				y = 0;
1029 
1030 				if ( !strncmp(map.name, "Citadel", 7) )
1031 				{
1032 					if ( c == 0 )
1033 					{
1034 						// 7x7, pick random location across all map.
1035 						x = 2 + (prng_get_uint() % 7) * 7;
1036 						y = 2 + (prng_get_uint() % 7) * 7;
1037 					}
1038 					else if ( secretlevelexit && c == 1 )
1039 					{
1040 						// 14x14, pick random location minus 1 from both edges.
1041 						x = 2 + (prng_get_uint() % 6) * 7;
1042 						y = 2 + (prng_get_uint() % 6) * 7;
1043 					}
1044 					else if ( c == 2 && shoplevel )
1045 					{
1046 						// 7x7, pick random location across all map.
1047 						x = 2 + (prng_get_uint() % 7) * 7;
1048 						y = 2 + (prng_get_uint() % 7) * 7;
1049 					}
1050 				}
1051 				else
1052 				{
1053 					if ( c == 0 )
1054 					{
1055 						// pick random location across all map.
1056 						x = 2 + (prng_get_uint() % tempMap->width) * tempMap->width;
1057 						y = 2 + (prng_get_uint() % tempMap->height) * tempMap->height;
1058 					}
1059 					else if ( secretlevelexit && c == 1 )
1060 					{
1061 						x = 2 + (prng_get_uint() % tempMap->width) * tempMap->width;
1062 						y = 2 + (prng_get_uint() % tempMap->height) * tempMap->height;
1063 						while ( x + tempMap->width >= map.width )
1064 						{
1065 							x = 2 + (prng_get_uint() % tempMap->width) * tempMap->width;
1066 						}
1067 						while ( y + tempMap->height >= map.height )
1068 						{
1069 							y = 2 + (prng_get_uint() % tempMap->height) * tempMap->height;
1070 						}
1071 					}
1072 					else if ( c == 2 && shoplevel )
1073 					{
1074 						// pick random location across all map.
1075 						x = 2 + (prng_get_uint() % tempMap->width) * tempMap->width;
1076 						y = 2 + (prng_get_uint() % tempMap->height) * tempMap->height;
1077 					}
1078 				}
1079 
1080 				while ( 1 )
1081 				{
1082 					if ( possiblelocations2[x + y * map.width] == true )
1083 					{
1084 						++i;
1085 						if ( i == pickedlocation )
1086 						{
1087 							break;
1088 						}
1089 					}
1090 					++x;
1091 					if ( x >= map.width )
1092 					{
1093 						x = 0;
1094 						++y;
1095 						if ( y >= map.height )
1096 						{
1097 							y = 0;
1098 							++pickedlocation;
1099 						}
1100 					}
1101 				}
1102 			}
1103 			else
1104 			{
1105 				pickedlocation = prng_get_uint() % numpossiblelocations;
1106 				i = -1;
1107 				x = 0;
1108 				y = 0;
1109 				while ( 1 )
1110 				{
1111 					if ( possiblelocations2[x + y * map.width] == true )
1112 					{
1113 						++i;
1114 						if ( i == pickedlocation )
1115 						{
1116 							break;
1117 						}
1118 					}
1119 					++x;
1120 					if ( x >= map.width )
1121 					{
1122 						x = 0;
1123 						++y;
1124 						if ( y >= map.height )
1125 						{
1126 							y = 0;
1127 						}
1128 					}
1129 				}
1130 			}
1131 
1132 			// now copy all the geometry from the sublevel to the chosen location
1133 			if ( c == 0 )
1134 			{
1135 				for ( z = 0; z < map.width * map.height; ++z )
1136 				{
1137 					firstroomtile[z] = false;
1138 				}
1139 			}
1140 			x1 = x + tempMap->width;
1141 			y1 = y + tempMap->height;
1142 
1143 
1144 			//**********pick subroom if available
1145 			int pickSubRoom = 0;
1146 			int k = 0;
1147 			int subRoom_tilex = 0;
1148 			int subRoom_tiley = 0;
1149 			int subRoom_tileStartx = -1;
1150 			int subRoom_tileStarty = -1;
1151 			int foundSubRoom = 0;
1152 			if ( ((levelnum2 - levelnum) > 1) && (c > 0) && (subroomCount[levelnum2] > 0) )
1153 			{
1154 				// levelnum is the start of map search, levelnum2 is jumps required to get to a suitable map.
1155 				// normal operation is levelnum2 - levelnum == 1. if a levelnum map is unavailable,
1156 				// then levelnum2 will advance search by 1 (higher than normal).
1157 				// levelnum2 will keep incrementing until a suitable map is found.
1158 				printlog("[SUBMAP GENERATOR] Skipped map when searching for levelnum %d, setting to %d", levelnum, levelnum2 - 1);
1159 				levelnum = levelnum2 - 1;
1160 			}
1161 			//printlog("(%d | %d), possible: (%d, %d) x: %d y: %d", levelnum, levelnum2, possiblerooms[1], possiblerooms[2], x, y);
1162 			if ( subroomCount[levelnum + 1] > 0 )
1163 			{
1164 				int jumps = 0;
1165 				pickSubRoom = prng_get_uint() % subroomCount[levelnum + 1];
1166 				// traverse the map list to the picked level
1167 				subRoomNode = subRoomMapList.first;
1168 				for ( int cycleRooms = 0; (cycleRooms < levelnum + 1) && (subRoomNode != nullptr); ++cycleRooms )
1169 				{
1170 					for ( int cycleRoomSubMaps = subroomCount[cycleRooms]; cycleRoomSubMaps > 0; --cycleRoomSubMaps )
1171 					{
1172 						// advance the subroom map list by the previous entries.
1173 						// e.g 2 subrooms, 3 maps each should advance pointer 3 maps when loading second room.
1174 						subRoomNode = subRoomNode->next;
1175 						jumps++; // just to keep track of how many jumps we made.
1176 					}
1177 				}
1178 				k = 0;
1179 
1180 				while ( 1 )
1181 				{
1182 					if ( k == pickSubRoom )
1183 					{
1184 						break;
1185 					}
1186 					subRoomNode = subRoomNode->next;
1187 					k++;
1188 				}
1189 				//messagePlayer(0, "%d + %d jumps!", jumps, k + 1);
1190 				subRoomNode = ((list_t*)subRoomNode->element)->first;
1191 				subRoomMap = (map_t*)subRoomNode->element;
1192 				subRoomDoorNode = subRoomNode->next;
1193 			}
1194 
1195 			for ( z = 0; z < MAPLAYERS; z++ )
1196 			{
1197 				for ( y0 = y; y0 < y1; y0++ )
1198 				{
1199 					for ( x0 = x; x0 < x1; x0++ )
1200 					{
1201 						if ( subroomCount[levelnum + 1] > 0 && tempMap->tiles[z + (y0 - y) * MAPLAYERS + (x0 - x) * MAPLAYERS * tempMap->height] == 201 )
1202 						{
1203 							if ( !foundSubRoom )
1204 							{
1205 								subRoom_tileStartx = x0;
1206 								subRoom_tileStarty = y0;
1207 								foundSubRoom = 1;
1208 								printlog("Picked level: %d from %d possible rooms in submap %d at x:%d y:%d", pickSubRoom + 1, subroomCount[levelnum + 1], levelnum + 1, x, y);
1209 							}
1210 
1211 							map.tiles[z + y0 * MAPLAYERS + x0 * MAPLAYERS * map.height] = subRoomMap->tiles[z + (subRoom_tiley)* MAPLAYERS + (subRoom_tilex)* MAPLAYERS * subRoomMap->height];
1212 
1213 							++subRoom_tilex;
1214 							if ( subRoom_tilex >= subRoomMap->width )
1215 							{
1216 								subRoom_tilex = 0;
1217 								++subRoom_tiley;
1218 								if ( subRoom_tiley >= subRoomMap->height )
1219 								{
1220 									subRoom_tiley = 0;
1221 								}
1222 							}
1223 						}
1224 						else
1225 						{
1226 							map.tiles[z + y0 * MAPLAYERS + x0 * MAPLAYERS * map.height] = tempMap->tiles[z + (y0 - y) * MAPLAYERS + (x0 - x) * MAPLAYERS * tempMap->height];
1227 						}
1228 
1229 						if ( z == 0 )
1230 						{
1231 							possiblelocations[x0 + y0 * map.width] = false;
1232 							if ( tempMap->flags[MAP_FLAG_DISABLETRAPS] == 1 )
1233 							{
1234 								trapexcludelocations[x0 + y0 * map.width] = true;
1235 								//map.tiles[z + y0 * MAPLAYERS + x0 * MAPLAYERS * map.height] = 83;
1236 							}
1237 							if ( tempMap->flags[MAP_FLAG_DISABLEMONSTERS] == 1 )
1238 							{
1239 								monsterexcludelocations[x0 + y0 * map.width] = true;
1240 							}
1241 							if ( tempMap->flags[MAP_FLAG_DISABLELOOT] == 1 )
1242 							{
1243 								lootexcludelocations[x0 + y0 * map.width] = true;
1244 							}
1245 							if ( c == 0 )
1246 							{
1247 								firstroomtile[y0 + x0 * map.height] = true;
1248 							}
1249 							else if ( c == 2 && shoplevel )
1250 							{
1251 								firstroomtile[y0 + x0 * map.height] = true;
1252 								if ( x0 - x > 0 && y0 - y > 0 && x0 - x < tempMap->width - 1 && y0 - y < tempMap->height - 1 )
1253 								{
1254 									shoparea[y0 + x0 * map.height] = true;
1255 								}
1256 							}
1257 						}
1258 
1259 						// remove any existing entities in this region too
1260 						for ( node = map.entities->first; node != nullptr; node = nextnode )
1261 						{
1262 							nextnode = node->next;
1263 							Entity* entity = (Entity*)node->element;
1264 							if ( (int)entity->x == x0 << 4 && (int)entity->y == y0 << 4 )
1265 							{
1266 								list_RemoveNode(entity->mynode);
1267 							}
1268 						}
1269 					}
1270 				}
1271 			}
1272 
1273 			// copy the entities as well from the tempMap.
1274 			for ( node = tempMap->entities->first; node != nullptr; node = node->next )
1275 			{
1276 				entity = (Entity*)node->element;
1277 				childEntity = newEntity(entity->sprite, 1, map.entities, nullptr);
1278 
1279 				// entity will return nullptr on getStats called in setSpriteAttributes as behaviour &actmonster is not set.
1280 				// check if the monster sprite is correct and set the behaviour manually for getStats.
1281 				if ( checkSpriteType(entity->sprite) == 1 && multiplayer != CLIENT )
1282 				{
1283 					entity->behavior = &actMonster;
1284 				}
1285 
1286 				setSpriteAttributes(childEntity, entity, entity);
1287 				childEntity->x = entity->x + x * 16;
1288 				childEntity->y = entity->y + y * 16;
1289 				//printlog("1 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
1290 
1291 				if ( entity->behavior == actMonster || entity->behavior == actPlayer )
1292 				{
1293 					entity->addToCreatureList(map.creatures);
1294 				}
1295 			}
1296 
1297 			if ( foundSubRoom )
1298 			{
1299 				// copy the entities from subroom
1300 				for ( subRoomNode = subRoomMap->entities->first; subRoomNode != nullptr; subRoomNode = subRoomNode->next )
1301 				{
1302 					entity = (Entity*)subRoomNode->element;
1303 					childEntity = newEntity(entity->sprite, 1, map.entities, nullptr);
1304 
1305 					// entity will return nullptr on getStats called in setSpriteAttributes as behaviour &actmonster is not set.
1306 					// check if the monster sprite is correct and set the behaviour manually for getStats.
1307 					if ( checkSpriteType(entity->sprite) == 1 && multiplayer != CLIENT )
1308 					{
1309 						entity->behavior = &actMonster;
1310 					}
1311 
1312 					setSpriteAttributes(childEntity, entity, entity);
1313 					childEntity->x = entity->x + subRoom_tileStartx * 16;
1314 					childEntity->y = entity->y + subRoom_tileStarty * 16;
1315 
1316 					if ( entity->behavior == actMonster || entity->behavior == actPlayer )
1317 					{
1318 						entity->addToCreatureList(map.creatures);
1319 					}
1320 
1321 					//messagePlayer(0, "1 Generated entity. Sprite: %d X: %.2f Y: %.2f", childEntity->sprite, childEntity->x / 16, childEntity->y / 16);
1322 				}
1323 			}
1324 
1325 			// finally, copy the doors into a single doors list
1326 			while ( doorNode != nullptr )
1327 			{
1328 				door = (door_t*)doorNode->element;
1329 				newDoor = (door_t*) malloc(sizeof(door_t));
1330 				newDoor->x = door->x + x;
1331 				newDoor->y = door->y + y;
1332 				newDoor->dir = door->dir;
1333 				node = list_AddNodeLast(&doorList);
1334 				node->element = newDoor;
1335 				node->deconstructor = &defaultDeconstructor;
1336 				doorNode = doorNode->next;
1337 			}
1338 
1339 			if ( foundSubRoom )
1340 			{
1341 				// copy subroom doors
1342 				while ( subRoomDoorNode != nullptr )
1343 				{
1344 					door = (door_t*)subRoomDoorNode->element;
1345 					newDoor = (door_t*)malloc(sizeof(door_t));
1346 					newDoor->x = door->x + subRoom_tileStartx;
1347 					newDoor->y = door->y + subRoom_tileStarty;
1348 					newDoor->dir = door->dir;
1349 					node = list_AddNodeLast(&doorList);
1350 					node->element = newDoor;
1351 					node->deconstructor = &defaultDeconstructor;
1352 					subRoomDoorNode = subRoomDoorNode->next;
1353 				}
1354 			}
1355 
1356 			// free shop map if used
1357 			if ( shoplevel && c == 2 )
1358 			{
1359 				list_FreeAll(shopmap.entities);
1360 				free(shopmap.entities);
1361 				list_FreeAll(shopmap.creatures);
1362 				delete shopmap.creatures;
1363 				if ( shopmap.tiles )
1364 				{
1365 					free(shopmap.tiles);
1366 				}
1367 			}
1368 			if ( secretlevelexit && c == 1 )
1369 			{
1370 				list_FreeAll(secretlevelmap.entities);
1371 				free(secretlevelmap.entities);
1372 				list_FreeAll(secretlevelmap.creatures);
1373 				delete secretlevelmap.creatures;
1374 				if ( secretlevelmap.tiles )
1375 				{
1376 					free(secretlevelmap.tiles);
1377 				}
1378 			}
1379 			++roomcount;
1380 		}
1381 		free(possiblerooms);
1382 		free(possiblelocations2);
1383 	}
1384 	else
1385 	{
1386 		free(subRoomName);
1387 		free(sublevelname);
1388 		list_FreeAll(&subRoomMapList);
1389 		list_FreeAll(&mapList);
1390 		list_FreeAll(&doorList);
1391 		printlog("error: not enough levels to begin generating dungeon.\n");
1392 		return -1;
1393 	}
1394 
1395 	// post-processing:
1396 
1397 	// doors
1398 	for ( node = doorList.first; node != nullptr; node = node->next )
1399 	{
1400 		door = (door_t*)node->element;
1401 		for (node2 = map.entities->first; node2 != nullptr; node2 = node2->next)
1402 		{
1403 			entity = (Entity*)node2->element;
1404 			if ( entity->x / 16 == door->x && entity->y / 16 == door->y && (entity->sprite == 2 || entity->sprite == 3) )
1405 			{
1406 				switch ( door->dir )
1407 				{
1408 					case 0: // east
1409 						map.tiles[OBSTACLELAYER + door->y * MAPLAYERS + (door->x + 1)*MAPLAYERS * map.height] = 0;
1410 						for ( node3 = map.entities->first; node3 != nullptr; node3 = nextnode )
1411 						{
1412 							entity = (Entity*)node3->element;
1413 							nextnode = node3->next;
1414 							if ( entity->sprite == 2 || entity->sprite == 3 )
1415 							{
1416 								if ( (int)(entity->x / 16) == door->x + 2 && (int)(entity->y / 16) == door->y )
1417 								{
1418 									list_RemoveNode(entity->mynode);
1419 									break;
1420 								}
1421 								else if ( (int)(entity->x / 16) == door->x + 1 && (int)(entity->y / 16) == door->y )
1422 								{
1423 									list_RemoveNode(entity->mynode);
1424 									break;
1425 								}
1426 								else if ( (int)(entity->x / 16) == door->x + 1 && (int)(entity->y / 16) == door->y + 1 )
1427 								{
1428 									list_RemoveNode(entity->mynode);
1429 									break;
1430 								}
1431 								else if ( (int)(entity->x / 16) == door->x + 1 && (int)(entity->y / 16) == door->y - 1 )
1432 								{
1433 									list_RemoveNode(entity->mynode);
1434 									break;
1435 								}
1436 							}
1437 						}
1438 						break;
1439 					case 1: // south
1440 						map.tiles[OBSTACLELAYER + (door->y + 1)*MAPLAYERS + door->x * MAPLAYERS * map.height] = 0;
1441 						for ( node3 = map.entities->first; node3 != nullptr; node3 = nextnode )
1442 						{
1443 							entity = (Entity*)node3->element;
1444 							nextnode = node3->next;
1445 							if ( entity->sprite == 2 || entity->sprite == 3 )
1446 							{
1447 								if ( (int)(entity->x / 16) == door->x && (int)(entity->y / 16) == door->y + 2 )
1448 								{
1449 									list_RemoveNode(entity->mynode);
1450 									break;
1451 								}
1452 								else if ( (int)(entity->x / 16) == door->x && (int)(entity->y / 16) == door->y + 1 )
1453 								{
1454 									list_RemoveNode(entity->mynode);
1455 									break;
1456 								}
1457 								else if ( (int)(entity->x / 16) == door->x + 1 && (int)(entity->y / 16) == door->y + 1 )
1458 								{
1459 									list_RemoveNode(entity->mynode);
1460 									break;
1461 								}
1462 								else if ( (int)(entity->x / 16) == door->x - 1 && (int)(entity->y / 16) == door->y + 1 )
1463 								{
1464 									list_RemoveNode(entity->mynode);
1465 									break;
1466 								}
1467 							}
1468 						}
1469 						break;
1470 					case 2: // west
1471 						map.tiles[OBSTACLELAYER + door->y * MAPLAYERS + (door->x - 1)*MAPLAYERS * map.height] = 0;
1472 						for ( node3 = map.entities->first; node3 != nullptr; node3 = nextnode )
1473 						{
1474 							entity = (Entity*)node3->element;
1475 							nextnode = node3->next;
1476 							if ( entity->sprite == 2 || entity->sprite == 3 )
1477 							{
1478 								if ( (int)(entity->x / 16) == door->x - 2 && (int)(entity->y / 16) == door->y )
1479 								{
1480 									list_RemoveNode(entity->mynode);
1481 									break;
1482 								}
1483 								else if ( (int)(entity->x / 16) == door->x - 1 && (int)(entity->y / 16) == door->y )
1484 								{
1485 									list_RemoveNode(entity->mynode);
1486 									break;
1487 								}
1488 								else if ( (int)(entity->x / 16) == door->x - 1 && (int)(entity->y / 16) == door->y + 1 )
1489 								{
1490 									list_RemoveNode(entity->mynode);
1491 									break;
1492 								}
1493 								else if ( (int)(entity->x / 16) == door->x - 1 && (int)(entity->y / 16) == door->y - 1 )
1494 								{
1495 									list_RemoveNode(entity->mynode);
1496 									break;
1497 								}
1498 							}
1499 						}
1500 						break;
1501 					case 3: // north
1502 						map.tiles[OBSTACLELAYER + (door->y - 1)*MAPLAYERS + door->x * MAPLAYERS * map.height] = 0;
1503 						for ( node3 = map.entities->first; node3 != nullptr; node3 = nextnode )
1504 						{
1505 							entity = (Entity*)node3->element;
1506 							nextnode = node3->next;
1507 							if ( entity->sprite == 2 || entity->sprite == 3 )
1508 							{
1509 								if ( (int)(entity->x / 16) == door->x && (int)(entity->y / 16) == door->y - 2 )
1510 								{
1511 									list_RemoveNode(entity->mynode);
1512 									break;
1513 								}
1514 								else if ( (int)(entity->x / 16) == door->x && (int)(entity->y / 16) == door->y - 1 )
1515 								{
1516 									list_RemoveNode(entity->mynode);
1517 									break;
1518 								}
1519 								else if ( (int)(entity->x / 16) == door->x + 1 && (int)(entity->y / 16) == door->y - 1 )
1520 								{
1521 									list_RemoveNode(entity->mynode);
1522 									break;
1523 								}
1524 								else if ( (int)(entity->x / 16) == door->x - 1 && (int)(entity->y / 16) == door->y - 1 )
1525 								{
1526 									list_RemoveNode(entity->mynode);
1527 									break;
1528 								}
1529 							}
1530 						}
1531 						break;
1532 				}
1533 			}
1534 		}
1535 	}
1536 	bool foundsubmaptile = false;
1537 	// if for whatever reason some submap 201 tiles didn't get filled in, let's get rid of those.
1538 	for ( z = 0; z < MAPLAYERS; ++z )
1539 	{
1540 		for ( y = 1; y < map.height; ++y )
1541 		{
1542 			for ( x = 1; x < map.height; ++x )
1543 			{
1544 				if ( map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] == 201 )
1545 				{
1546 					map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = 0;
1547 					foundsubmaptile = true;
1548 				}
1549 			}
1550 		}
1551 	}
1552 	if ( foundsubmaptile )
1553 	{
1554 		printlog("[SUBMAP GENERATOR] Found some junk tiles!");
1555 	}
1556 
1557 	for ( node = map.entities->first; node != nullptr; node = node->next )
1558 	{
1559 		// fix gate air-gap borders on citadel map next to perimeter gates.
1560 		if ( !strncmp(map.name, "Citadel", 7) )
1561 		{
1562 			Entity* gateEntity = (Entity*)node->element;
1563 			if ( gateEntity->sprite == 19 || gateEntity->sprite == 20 ) // N/S E/W gates take these sprite numbers in the editor.
1564 			{
1565 				int gatex = static_cast<int>(gateEntity->x) / 16;
1566 				int gatey = static_cast<int>(gateEntity->y) / 16;
1567 				for ( z = OBSTACLELAYER; z < MAPLAYERS; ++z )
1568 				{
1569 					if ( gateEntity->x / 16 == 1 ) // along leftmost edge
1570 					{
1571 						if ( !map.tiles[z + gatey * MAPLAYERS + (gatex + 1) * MAPLAYERS * map.height] )
1572 						{
1573 							map.tiles[z + gatey * MAPLAYERS + (gatex + 1) * MAPLAYERS * map.height] = 230;
1574 							//messagePlayer(0, "replaced at: %d, %d", gatex, gatey);
1575 						}
1576 					}
1577 					else if ( gateEntity->x / 16 == 51 ) // along rightmost edge
1578 					{
1579 						if ( !map.tiles[z + gatey * MAPLAYERS + (gatex - 1) * MAPLAYERS * map.height] )
1580 						{
1581 							map.tiles[z + gatey * MAPLAYERS + (gatex - 1) * MAPLAYERS * map.height] = 230;
1582 							//messagePlayer(0, "replaced at: %d, %d", gatex, gatey);
1583 						}
1584 					}
1585 					else if ( gateEntity->y / 16 == 1 ) // along top edge
1586 					{
1587 						if ( !map.tiles[z + (gatey + 1) * MAPLAYERS + gatex * MAPLAYERS * map.height] )
1588 						{
1589 							map.tiles[z + (gatey + 1) * MAPLAYERS + gatex * MAPLAYERS * map.height] = 230;
1590 							//messagePlayer(0, "replaced at: %d, %d", gatex, gatey);
1591 						}
1592 					}
1593 					else if ( gateEntity->y / 16 == 51 ) // along bottom edge
1594 					{
1595 						if ( !map.tiles[z + (gatey - 1) * MAPLAYERS + gatex * MAPLAYERS * map.height] )
1596 						{
1597 							map.tiles[z + (gatey - 1) * MAPLAYERS + gatex * MAPLAYERS * map.height] = 230;
1598 							//messagePlayer(0, "replaced at: %d, %d", gatex, gatey);
1599 						}
1600 					}
1601 				}
1602 			}
1603 		}
1604 	}
1605 
1606 	bool customTrapsForMapInUse = false;
1607 	struct CustomTraps
1608 	{
1609 		bool boulders = false;
1610 		bool arrows = false;
1611 		bool spikes = false;
1612 		bool verticalSpelltraps = false;
1613 	} customTraps;
1614 
1615 	if ( gameplayCustomManager.inUse() && gameplayCustomManager.mapGenerationExistsForMapName(map.name) )
1616 	{
1617 		auto m = gameplayCustomManager.getMapGenerationForMapName(map.name);
1618 		if ( m && m->usingTrapTypes )
1619 		{
1620 			customTrapsForMapInUse = true;
1621 			for ( auto& traps : m->trapTypes )
1622 			{
1623 				if ( traps.compare("boulders") == 0 )
1624 				{
1625 					customTraps.boulders = true;
1626 				}
1627 				else if ( traps.compare("arrows") == 0 )
1628 				{
1629 					customTraps.arrows = true;
1630 				}
1631 				else if ( traps.compare("spikes") == 0 )
1632 				{
1633 					customTraps.spikes = true;
1634 				}
1635 				else if ( traps.compare("spelltrap_vertical") == 0 )
1636 				{
1637 					customTraps.verticalSpelltraps = true;
1638 				}
1639 			}
1640 		}
1641 	}
1642 
1643 	// boulder and arrow traps
1644 	if ( (svFlags & SV_FLAG_TRAPS) && map.flags[MAP_FLAG_DISABLETRAPS] == 0
1645 		&& (!customTrapsForMapInUse || (customTrapsForMapInUse && (customTraps.boulders || customTraps.arrows)) )
1646 		)
1647 	{
1648 		numpossiblelocations = 0;
1649 		for ( c = 0; c < map.width * map.height; ++c )
1650 		{
1651 			possiblelocations[c] = false;
1652 		}
1653 		for ( y = 1; y < map.height - 1; ++y )
1654 		{
1655 			for ( x = 1; x < map.width - 1; ++x )
1656 			{
1657 				int sides = 0;
1658 				if ( firstroomtile[y + x * map.height] )
1659 				{
1660 					continue;
1661 				}
1662 				if ( !map.tiles[OBSTACLELAYER + y * MAPLAYERS + (x + 1)*MAPLAYERS * map.height] )
1663 				{
1664 					sides++;
1665 				}
1666 				if ( !map.tiles[OBSTACLELAYER + (y + 1)*MAPLAYERS + x * MAPLAYERS * map.height] )
1667 				{
1668 					sides++;
1669 				}
1670 				if ( !map.tiles[OBSTACLELAYER + y * MAPLAYERS + (x - 1)*MAPLAYERS * map.height] )
1671 				{
1672 					sides++;
1673 				}
1674 				if ( !map.tiles[OBSTACLELAYER + (y - 1)*MAPLAYERS + x * MAPLAYERS * map.height] )
1675 				{
1676 					sides++;
1677 				}
1678 				if ( sides == 1 && (trapexcludelocations[x + y * map.width] == false) )
1679 				{
1680 					possiblelocations[y + x * map.height] = true;
1681 					numpossiblelocations++;
1682 				}
1683 			}
1684 		}
1685 
1686 		// don't spawn traps in doors
1687 		node_t* doorNode;
1688 		for ( doorNode = doorList.first; doorNode != nullptr; doorNode = doorNode->next )
1689 		{
1690 			door_t* door = (door_t*)doorNode->element;
1691 			int x = std::min<unsigned int>(std::max(0, door->x), map.width); //TODO: Why are const int and unsigned int being compared?
1692 			int y = std::min<unsigned int>(std::max(0, door->y), map.height); //TODO: Why are const int and unsigned int being compared?
1693 			if ( possiblelocations[y + x * map.height] == true )
1694 			{
1695 				possiblelocations[y + x * map.height] = false;
1696 				--numpossiblelocations;
1697 			}
1698 		}
1699 
1700 		// do a second pass to look for internal doorways
1701 		for ( node = map.entities->first; node != nullptr; node = node->next )
1702 		{
1703 			entity = (Entity*)node->element;
1704 			int x = entity->x / 16;
1705 			int y = entity->y / 16;
1706 			if ( (entity->sprite == 2 || entity->sprite == 3)
1707 				&& (x >= 0 && x < map.width)
1708 				&& (y >= 0 && y < map.height) )
1709 			{
1710 				if ( possiblelocations[y + x * map.height] )
1711 				{
1712 					possiblelocations[y + x * map.height] = false;
1713 					--numpossiblelocations;
1714 				}
1715 			}
1716 		}
1717 
1718 		int whatever = prng_get_uint() % 5;
1719 		if ( strncmp(map.name, "Hell", 4) )
1720 			j = std::min(
1721 			        std::min(
1722 			            std::max(1, currentlevel),
1723 			            5
1724 			        )
1725 			        + whatever, numpossiblelocations
1726 			    )
1727 			    / ((strcmp(map.name, "The Mines") == 0) + 1);
1728 		else
1729 		{
1730 			j = std::min(15, numpossiblelocations);
1731 		}
1732 		//printlog("j: %d\n",j);
1733 		//printlog("numpossiblelocations: %d\n",numpossiblelocations);
1734 		for ( c = 0; c < j; ++c )
1735 		{
1736 			// choose a random location from those available
1737 			pickedlocation = prng_get_uint() % numpossiblelocations;
1738 			i = -1;
1739 			//printlog("pickedlocation: %d\n",pickedlocation);
1740 			//printlog("numpossiblelocations: %d\n",numpossiblelocations);
1741 			x = 0;
1742 			y = 0;
1743 			while ( 1 )
1744 			{
1745 				if ( possiblelocations[y + x * map.height] == true )
1746 				{
1747 					i++;
1748 					if ( i == pickedlocation )
1749 					{
1750 						break;
1751 					}
1752 				}
1753 				x++;
1754 				if ( x >= map.width )
1755 				{
1756 					x = 0;
1757 					y++;
1758 					if ( y >= map.height )
1759 					{
1760 						y = 0;
1761 					}
1762 				}
1763 			}
1764 			int side = 0;
1765 			if ( !map.tiles[OBSTACLELAYER + y * MAPLAYERS + (x + 1)*MAPLAYERS * map.height] )
1766 			{
1767 				side = 0;
1768 			}
1769 			else if ( !map.tiles[OBSTACLELAYER + (y + 1)*MAPLAYERS + x * MAPLAYERS * map.height] )
1770 			{
1771 				side = 1;
1772 			}
1773 			else if ( !map.tiles[OBSTACLELAYER + y * MAPLAYERS + (x - 1)*MAPLAYERS * map.height] )
1774 			{
1775 				side = 2;
1776 			}
1777 			else if ( !map.tiles[OBSTACLELAYER + (y - 1)*MAPLAYERS + x * MAPLAYERS * map.height] )
1778 			{
1779 				side = 3;
1780 			}
1781 			bool arrowtrap = false;
1782 			bool noceiling = false;
1783 			bool arrowtrapspawn = false;
1784 			if ( !strncmp(map.name, "Hell", 4) )
1785 			{
1786 				if ( side == 0 && !map.tiles[(MAPLAYERS - 1) + y * MAPLAYERS + (x + 1)*MAPLAYERS * map.height] )
1787 				{
1788 					noceiling = true;
1789 				}
1790 				if ( side == 1 && !map.tiles[(MAPLAYERS - 1) + (y + 1)*MAPLAYERS + x * MAPLAYERS * map.height] )
1791 				{
1792 					noceiling = true;
1793 				}
1794 				if ( side == 2 && !map.tiles[(MAPLAYERS - 1) + y * MAPLAYERS + (x - 1)*MAPLAYERS * map.height] )
1795 				{
1796 					noceiling = true;
1797 				}
1798 				if ( side == 3 && !map.tiles[(MAPLAYERS - 1) + (y - 1)*MAPLAYERS + x * MAPLAYERS * map.height] )
1799 				{
1800 					noceiling = true;
1801 				}
1802 				if ( noceiling )
1803 				{
1804 					arrowtrapspawn = true;
1805 				}
1806 			}
1807 			else
1808 			{
1809 				if ( prng_get_uint() % 2 && (currentlevel > 5 && currentlevel <= 25) )
1810 				{
1811 					arrowtrapspawn = true;
1812 				}
1813 			}
1814 
1815 			if ( customTrapsForMapInUse )
1816 			{
1817 				arrowtrapspawn = customTraps.arrows;
1818 				if ( customTraps.boulders && prng_get_uint() % 2 )
1819 				{
1820 					arrowtrapspawn = false;
1821 				}
1822 			}
1823 
1824 			if ( arrowtrapspawn || noceiling )
1825 			{
1826 				arrowtrap = true;
1827 				entity = newEntity(32, 1, map.entities, nullptr); // arrow trap
1828 				entity->behavior = &actArrowTrap;
1829 				map.tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map.height] = 53; // trap wall
1830 			}
1831 			else
1832 			{
1833 				//messagePlayer(0, "Included at x: %d, y: %d", x, y);
1834 				entity = newEntity(38, 1, map.entities, nullptr); // boulder trap
1835 				entity->behavior = &actBoulderTrap;
1836 			}
1837 			entity->x = x * 16;
1838 			entity->y = y * 16;
1839 			//printlog("2 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity->sprite,entity->getUID(),entity->x,entity->y);
1840 			entity = newEntity(18, 1, map.entities, nullptr); // electricity node
1841 			entity->x = x * 16 - (side == 3) * 16 + (side == 1) * 16;
1842 			entity->y = y * 16 - (side == 0) * 16 + (side == 2) * 16;
1843 			//printlog("4 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity->sprite,entity->getUID(),entity->x,entity->y);
1844 			// make torches
1845 			if ( arrowtrap )
1846 			{
1847 				entity = newEntity(4 + side, 1, map.entities, nullptr);
1848 				Entity* entity2 = newEntity(4 + side, 1, map.entities, nullptr);
1849 				switch ( side )
1850 				{
1851 					case 0:
1852 						entity->x = x * 16 + 16;
1853 						entity->y = y * 16 + 4;
1854 						entity2->x = x * 16 + 16;
1855 						entity2->y = y * 16 - 4;
1856 						break;
1857 					case 1:
1858 						entity->x = x * 16 + 4;
1859 						entity->y = y * 16 + 16;
1860 						entity2->x = x * 16 - 4;
1861 						entity2->y = y * 16 + 16;
1862 						break;
1863 					case 2:
1864 						entity->x = x * 16 - 16;
1865 						entity->y = y * 16 + 4;
1866 						entity2->x = x * 16 - 16;
1867 						entity2->y = y * 16 - 4;
1868 						break;
1869 					case 3:
1870 						entity->x = x * 16 + 4;
1871 						entity->y = y * 16 - 16;
1872 						entity2->x = x * 16 - 4;
1873 						entity2->y = y * 16 - 16;
1874 						break;
1875 				}
1876 				//printlog("5 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity->sprite,entity->getUID(),entity->x,entity->y);
1877 				//printlog("6 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity2->sprite,entity2->getUID(),entity2->x,entity2->y);
1878 			}
1879 			i = 0;
1880 			int testx = 0, testy = 0;
1881 			do
1882 			{
1883 				if ( i == 0 )
1884 				{
1885 					// get rid of extraneous torch
1886 					node_t* tempNode;
1887 					node_t* nextTempNode;
1888 					for ( tempNode = map.entities->first; tempNode != nullptr; tempNode = nextTempNode )
1889 					{
1890 						nextTempNode = tempNode->next;
1891 						Entity* tempEntity = (Entity*)tempNode->element;
1892 						if ( tempEntity->sprite >= 4 && tempEntity->sprite <= 7 )
1893 						{
1894 							if ( ((int)floor(tempEntity->x + 8)) / 16 == x && ((int)floor(tempEntity->y + 8)) / 16 == y )
1895 							{
1896 								list_RemoveNode(tempNode);
1897 							}
1898 						}
1899 					}
1900 				}
1901 				if ( arrowtrap )
1902 				{
1903 					entity = newEntity(33, 1, map.entities, nullptr); // pressure plate
1904 				}
1905 				else
1906 				{
1907 					entity = newEntity(34, 1, map.entities, nullptr); // pressure plate
1908 				}
1909 				entity->x = x * 16;
1910 				entity->y = y * 16;
1911 				//printlog("7 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity->sprite,entity->getUID(),entity->x,entity->y);
1912 				entity = newEntity(18, 1, map.entities, nullptr); // electricity node
1913 				entity->x = x * 16 - (side == 3) * 16 + (side == 1) * 16;
1914 				entity->y = y * 16 - (side == 0) * 16 + (side == 2) * 16;
1915 				//printlog("8 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity->sprite,entity->getUID(),entity->x,entity->y);
1916 				switch ( side )
1917 				{
1918 					case 0:
1919 						x++;
1920 						break;
1921 					case 1:
1922 						y++;
1923 						break;
1924 					case 2:
1925 						x--;
1926 						break;
1927 					case 3:
1928 						y--;
1929 						break;
1930 				}
1931 				i++;
1932 				testx = std::min(std::max<unsigned int>(0, x), map.width - 1); //TODO: Why are const int and unsigned int being compared?
1933 				testy = std::min(std::max<unsigned int>(0, y), map.height - 1); //TODO: Why are const int and unsigned int being compared?
1934 			}
1935 			while ( !map.tiles[OBSTACLELAYER + testy * MAPLAYERS + testx * MAPLAYERS * map.height] && i <= 10 );
1936 		}
1937 	}
1938 
1939 	// monsters, decorations, and items
1940 	numpossiblelocations = map.width * map.height;
1941 	for ( y = 0; y < map.height; y++ )
1942 	{
1943 		for ( x = 0; x < map.width; x++ )
1944 		{
1945 			if ( checkObstacle( x * 16 + 8, y * 16 + 8, NULL, NULL ) || firstroomtile[y + x * map.height] )
1946 			{
1947 				possiblelocations[y + x * map.height] = false;
1948 				numpossiblelocations--;
1949 			}
1950 			else if ( lavatiles[map.tiles[y * MAPLAYERS + x * MAPLAYERS * map.height]] )
1951 			{
1952 				possiblelocations[y + x * map.height] = false;
1953 				numpossiblelocations--;
1954 			}
1955 			else if ( swimmingtiles[map.tiles[y * MAPLAYERS + x * MAPLAYERS * map.height]] )
1956 			{
1957 				possiblelocations[y + x * map.height] = false;
1958 				numpossiblelocations--;
1959 			}
1960 			else
1961 			{
1962 				possiblelocations[y + x * map.height] = true;
1963 			}
1964 		}
1965 	}
1966 	for ( node = map.entities->first; node != nullptr; node = node->next )
1967 	{
1968 		entity = (Entity*)node->element;
1969 		x = entity->x / 16;
1970 		y = entity->y / 16;
1971 		if ( x >= 0 && x < map.width && y >= 0 && y < map.height )
1972 		{
1973 			if ( possiblelocations[y + x * map.height] )
1974 			{
1975 				possiblelocations[y + x * map.height] = false;
1976 				--numpossiblelocations;
1977 			}
1978 		}
1979 	}
1980 
1981 	// read some editor map data if available:
1982 	int genEntityMin = 0;
1983 	int genEntityMax = 0;
1984 	int genMonsterMin = 0;
1985 	int genMonsterMax = 0;
1986 	int genLootMin = 0;
1987 	int genLootMax = 0;
1988 	int genDecorationMin = 0;
1989 	int genDecorationMax = 0;
1990 
1991 	if ( map.flags[MAP_FLAG_GENBYTES1] != 0 || map.flags[MAP_FLAG_GENBYTES2] != 0 )
1992 	{
1993 		genEntityMin = (map.flags[MAP_FLAG_GENBYTES1] >> 24) & 0xFF; // first leftmost byte
1994 		genEntityMax = (map.flags[MAP_FLAG_GENBYTES1] >> 16) & 0xFF; // second leftmost byte
1995 
1996 		genMonsterMin = (map.flags[MAP_FLAG_GENBYTES1] >> 8) & 0xFF; // third leftmost byte
1997 		genMonsterMax = (map.flags[MAP_FLAG_GENBYTES1] >> 0) & 0xFF; // fourth leftmost byte
1998 
1999 		genLootMin = (map.flags[MAP_FLAG_GENBYTES2] >> 24) & 0xFF; // first leftmost byte
2000 		genLootMax = (map.flags[MAP_FLAG_GENBYTES2] >> 16) & 0xFF; // second leftmost byte
2001 
2002 		genDecorationMin = (map.flags[MAP_FLAG_GENBYTES2] >> 8) & 0xFF; // third leftmost byte
2003 		genDecorationMax = (map.flags[MAP_FLAG_GENBYTES2] >> 0) & 0xFF; // fourth leftmost byte
2004 	}
2005 
2006 	int entitiesToGenerate = 30;
2007 	int randomEntities = 10;
2008 
2009 	if ( genEntityMin > 0 || genEntityMax > 0 )
2010 	{
2011 		genEntityMin = std::max(genEntityMin, 2); // make sure there's room for a ladder.
2012 		entitiesToGenerate = genEntityMin;
2013 		randomEntities = std::max(genEntityMax - genEntityMin, 1); // difference between min and max is the extra chances.
2014 		//Needs to be 1 for prng_get_uint() % to not divide by 0.
2015 		j = std::min<Uint32>(entitiesToGenerate + prng_get_uint() % randomEntities, numpossiblelocations); //TODO: Why are Uint32 and Sin32 being compared?
2016 	}
2017 	else
2018 	{
2019 		// revert to old mechanics.
2020 		j = std::min<Uint32>(30 + prng_get_uint() % 10, numpossiblelocations); //TODO: Why are Uint32 and Sin32 being compared?
2021 	}
2022 	int forcedMonsterSpawns = 0;
2023 	int forcedLootSpawns = 0;
2024 	int forcedDecorationSpawns = 0;
2025 
2026 	if ( genMonsterMin > 0 || genMonsterMax > 0 )
2027 	{
2028 		forcedMonsterSpawns = genMonsterMin + prng_get_uint() % std::max(genMonsterMax - genMonsterMin, 1);
2029 	}
2030 	if ( genLootMin > 0 || genLootMax > 0 )
2031 	{
2032 		forcedLootSpawns = genLootMin + prng_get_uint() % std::max(genLootMax - genLootMin, 1);
2033 	}
2034 	if ( genDecorationMin > 0 || genDecorationMax > 0 )
2035 	{
2036 		forcedDecorationSpawns = genDecorationMin + prng_get_uint() % std::max(genDecorationMax - genDecorationMin, 1);
2037 	}
2038 
2039 	//messagePlayer(0, "Num locations: %d of %d possible, force monsters: %d, force loot: %d, force decorations: %d", j, numpossiblelocations, forcedMonsterSpawns, forcedLootSpawns, forcedDecorationSpawns);
2040 	printlog("Num locations: %d of %d possible, force monsters: %d, force loot: %d, force decorations: %d", j, numpossiblelocations, forcedMonsterSpawns, forcedLootSpawns, forcedDecorationSpawns);
2041 	int numGenItems = 0;
2042 	int numGenGold = 0;
2043 	int numGenDecorations = 0;
2044 
2045 	//printlog("j: %d\n",j);
2046 	//printlog("numpossiblelocations: %d\n",numpossiblelocations);
2047 	for ( c = 0; c < std::min(j, numpossiblelocations); ++c )
2048 	{
2049 		// choose a random location from those available
2050 		pickedlocation = prng_get_uint() % numpossiblelocations;
2051 		i = -1;
2052 		//printlog("pickedlocation: %d\n",pickedlocation);
2053 		//printlog("numpossiblelocations: %d\n",numpossiblelocations);
2054 		x = 0;
2055 		y = 0;
2056 		while ( 1 )
2057 		{
2058 			if ( possiblelocations[y + x * map.height] == true )
2059 			{
2060 				++i;
2061 				if ( i == pickedlocation )
2062 				{
2063 					break;
2064 				}
2065 			}
2066 			++x;
2067 			if ( x >= map.width )
2068 			{
2069 				x = 0;
2070 				++y;
2071 				if ( y >= map.height )
2072 				{
2073 					y = 0;
2074 				}
2075 			}
2076 		}
2077 
2078 		// create entity
2079 		entity = nullptr;
2080 		if ( (c == 0 || (minotaurlevel && c < 2)) && (!secretlevel || currentlevel != 7) && (!secretlevel || currentlevel != 20)
2081 			&& std::get<LEVELPARAM_DISABLE_NORMAL_EXIT>(mapParameters) == 0 )
2082 		{
2083 			if ( strcmp(map.name, "Hell") )
2084 			{
2085 				entity = newEntity(11, 1, map.entities, nullptr); // ladder
2086 				entity->behavior = &actLadder;
2087 			}
2088 			else
2089 			{
2090 				entity = newEntity(45, 1, map.entities, nullptr); // hell uses portals instead
2091 				entity->behavior = &actPortal;
2092 				entity->skill[3] = 1; // not secret portals though
2093 			}
2094 
2095 			// determine if the ladder generated in a viable location
2096 			if ( strncmp(map.name, "Underworld", 10) )
2097 			{
2098 				bool nopath = false;
2099 				bool hellLadderFix = !strncmp(map.name, "Hell", 4);
2100 				/*if ( !hellLadderFix )
2101 				{
2102 					hellLadderFix = !strncmp(map.name, "Caves", 4);
2103 				}*/
2104 				for ( node = map.entities->first; node != NULL; node = node->next )
2105 				{
2106 					entity2 = (Entity*)node->element;
2107 					if ( entity2->sprite == 1 )
2108 					{
2109 						list_t* path = generatePath(x, y, entity2->x / 16, entity2->y / 16, entity, entity2, hellLadderFix);
2110 						if ( path == NULL )
2111 						{
2112 							nopath = true;
2113 						}
2114 						else
2115 						{
2116 							list_FreeAll(path);
2117 							free(path);
2118 						}
2119 						break;
2120 					}
2121 				}
2122 				if ( nopath )
2123 				{
2124 					// try again
2125 					c--;
2126 					list_RemoveNode(entity->mynode);
2127 					entity = NULL;
2128 				}
2129 			}
2130 		}
2131 		else if ( c == 1 && secretlevel && currentlevel == 7 && !strncmp(map.name, "Underworld", 10) )
2132 		{
2133 			entity = newEntity(89, 1, map.entities, nullptr);
2134 			entity->monsterStoreType = 1;
2135 			entity->skill[5] = nummonsters;
2136 			++nummonsters;
2137 			//entity = newEntity(68, 1, map.entities, nullptr); // magic (artifact) bow
2138 		}
2139 		else
2140 		{
2141 			int x2, y2;
2142 			bool nodecoration = false;
2143 			int obstacles = 0;
2144 			for ( x2 = -1; x2 <= 1; x2++ )
2145 			{
2146 				for ( y2 = -1; y2 <= 1; y2++ )
2147 				{
2148 					if ( checkObstacle((x + x2) * 16, (y + y2) * 16, NULL, NULL) )
2149 					{
2150 						obstacles++;
2151 						if ( obstacles > 1 )
2152 						{
2153 							break;
2154 						}
2155 					}
2156 				}
2157 				if ( obstacles > 1 )
2158 				{
2159 					break;
2160 				}
2161 			}
2162 			if ( obstacles > 1 )
2163 			{
2164 				nodecoration = true;
2165 			}
2166 			if ( forcedMonsterSpawns > 0 || forcedLootSpawns > 0 || (forcedDecorationSpawns > 0 && !nodecoration) )
2167 			{
2168 				// force monsters, then loot, then decorations.
2169 				if ( forcedMonsterSpawns > 0 )
2170 				{
2171 					--forcedMonsterSpawns;
2172 					if ( monsterexcludelocations[x + y * map.width] == false )
2173 					{
2174 						bool doNPC = false;
2175 						if ( gameplayCustomManager.processedPropertyForFloor(currentlevel, secretlevel, map.name, GameplayCustomManager::PROPERTY_NPC, doNPC) )
2176 						{
2177 							// doNPC processed by function
2178 						}
2179 						else if ( prng_get_uint() % 10 == 0 && currentlevel > 1 )
2180 						{
2181 							doNPC = true;
2182 						}
2183 
2184 						if ( doNPC )
2185 						{
2186 							if ( currentlevel > 15 && prng_get_uint() % 4 > 0 )
2187 							{
2188 								entity = newEntity(93, 1, map.entities, map.creatures);  // automaton
2189 								if ( currentlevel < 25 )
2190 								{
2191 									entity->monsterStoreType = 1; // weaker version
2192 								}
2193 							}
2194 							else
2195 							{
2196 								entity = newEntity(27, 1, map.entities, map.creatures);  // human
2197 								if ( multiplayer != CLIENT && currentlevel > 5 )
2198 								{
2199 									entity->monsterStoreType = (currentlevel / 5) * 3 + (rand() % 4); // scale humans with depth.  3 LVL each 5 floors, + 0-3.
2200 								}
2201 							}
2202 						}
2203 						else
2204 						{
2205 							entity = newEntity(10, 1, map.entities, map.creatures);  // monster
2206 						}
2207 						entity->skill[5] = nummonsters;
2208 						++nummonsters;
2209 					}
2210 				}
2211 				else if ( forcedLootSpawns > 0 )
2212 				{
2213 					--forcedLootSpawns;
2214 					if ( lootexcludelocations[x + y * map.width] == false )
2215 					{
2216 						if ( prng_get_uint() % 10 == 0 )   // 10% chance
2217 						{
2218 							entity = newEntity(9, 1, map.entities, nullptr);  // gold
2219 							numGenGold++;
2220 						}
2221 						else
2222 						{
2223 							entity = newEntity(8, 1, map.entities, nullptr);  // item
2224 							setSpriteAttributes(entity, nullptr, nullptr);
2225 							numGenItems++;
2226 						}
2227 					}
2228 				}
2229 				else if ( forcedDecorationSpawns > 0 && !nodecoration )
2230 				{
2231 					--forcedDecorationSpawns;
2232 					// decorations
2233 					if ( (prng_get_uint() % 4 == 0 || currentlevel <= 10 && !customTrapsForMapInUse) && strcmp(map.name, "Hell") )
2234 					{
2235 						switch ( prng_get_uint() % 7 )
2236 						{
2237 							case 0:
2238 								entity = newEntity(12, 1, map.entities, nullptr); //Firecamp.
2239 								break; //Firecamp
2240 							case 1:
2241 								entity = newEntity(14, 1, map.entities, nullptr); //Fountain.
2242 								break; //Fountain
2243 							case 2:
2244 								entity = newEntity(15, 1, map.entities, nullptr); //Sink.
2245 								break; //Sink
2246 							case 3:
2247 								entity = newEntity(21, 1, map.entities, nullptr); //Chest.
2248 								setSpriteAttributes(entity, nullptr, nullptr);
2249 								entity->chestLocked = -1;
2250 								break; //Chest
2251 							case 4:
2252 								entity = newEntity(39, 1, map.entities, nullptr); //Tomb.
2253 								break; //Tomb
2254 							case 5:
2255 								entity = newEntity(59, 1, map.entities, nullptr); //Table.
2256 								setSpriteAttributes(entity, nullptr, nullptr);
2257 								break; //Table
2258 							case 6:
2259 								entity = newEntity(60, 1, map.entities, nullptr); //Chair.
2260 								setSpriteAttributes(entity, nullptr, nullptr);
2261 								break; //Chair
2262 						}
2263 					}
2264 					else
2265 					{
2266 						if ( customTrapsForMapInUse )
2267 						{
2268 							if ( !customTraps.spikes && !customTraps.verticalSpelltraps )
2269 							{
2270 								continue;
2271 							}
2272 							else if ( customTraps.verticalSpelltraps && prng_get_uint() % 2 == 0 )
2273 							{
2274 								entity = newEntity(120, 1, map.entities, nullptr); // vertical spell trap.
2275 								setSpriteAttributes(entity, nullptr, nullptr);
2276 							}
2277 							else if ( customTraps.spikes )
2278 							{
2279 								entity = newEntity(64, 1, map.entities, nullptr); // spear trap
2280 							}
2281 						}
2282 						else
2283 						{
2284 							if ( currentlevel <= 25 )
2285 							{
2286 								entity = newEntity(64, 1, map.entities, nullptr); // spear trap
2287 							}
2288 							else
2289 							{
2290 								if ( prng_get_uint() % 2 == 0 )
2291 								{
2292 									entity = newEntity(120, 1, map.entities, nullptr); // vertical spell trap.
2293 									setSpriteAttributes(entity, nullptr, nullptr);
2294 								}
2295 								else
2296 								{
2297 									entity = newEntity(64, 1, map.entities, nullptr); // spear trap
2298 								}
2299 							}
2300 						}
2301 						Entity* also = newEntity(33, 1, map.entities, nullptr);
2302 						also->x = x * 16;
2303 						also->y = y * 16;
2304 						//printlog("15 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",also->sprite,also->getUID(),also->x,also->y);
2305 					}
2306 					numGenDecorations++;
2307 				}
2308 			}
2309 			else
2310 			{
2311 				// return to normal generation
2312 				if ( prng_get_uint() % 2 || nodecoration )
2313 				{
2314 					// balance for total number of players
2315 					int balance = 0;
2316 					for ( i = 0; i < MAXPLAYERS; i++ )
2317 					{
2318 						if ( !client_disconnected[i] )
2319 						{
2320 							balance++;
2321 						}
2322 					}
2323 					switch ( balance )
2324 					{
2325 						case 1:
2326 							balance = 4;
2327 							break;
2328 						case 2:
2329 							balance = 3;
2330 							break;
2331 						case 3:
2332 							balance = 2;
2333 							break;
2334 						case 4:
2335 							balance = 2;
2336 							break;
2337 						default:
2338 							balance = 2;
2339 							break;
2340 					}
2341 
2342 					// monsters/items
2343 					if ( balance )
2344 					{
2345 						if ( prng_get_uint() % balance )
2346 						{
2347 							if ( lootexcludelocations[x + y * map.width] == false )
2348 							{
2349 								if ( prng_get_uint() % 10 == 0 )   // 10% chance
2350 								{
2351 									entity = newEntity(9, 1, map.entities, nullptr);  // gold
2352 									numGenGold++;
2353 								}
2354 								else
2355 								{
2356 									entity = newEntity(8, 1, map.entities, nullptr);  // item
2357 									setSpriteAttributes(entity, nullptr, nullptr);
2358 									numGenItems++;
2359 								}
2360 							}
2361 						}
2362 						else
2363 						{
2364 							if ( monsterexcludelocations[x + y * map.width] == false )
2365 							{
2366 								bool doNPC = false;
2367 								if ( gameplayCustomManager.processedPropertyForFloor(currentlevel, secretlevel, map.name, GameplayCustomManager::PROPERTY_NPC, doNPC) )
2368 								{
2369 									// doNPC processed by function
2370 								}
2371 								else if ( prng_get_uint() % 10 == 0 && currentlevel > 1 )
2372 								{
2373 									doNPC = true;
2374 								}
2375 
2376 								if ( doNPC )
2377 								{
2378 									if ( currentlevel > 15 && prng_get_uint() % 4 > 0 )
2379 									{
2380 										entity = newEntity(93, 1, map.entities, map.creatures);  // automaton
2381 										if ( currentlevel < 25 )
2382 										{
2383 											entity->monsterStoreType = 1; // weaker version
2384 										}
2385 									}
2386 									else
2387 									{
2388 										entity = newEntity(27, 1, map.entities, map.creatures);  // human
2389 										if ( multiplayer != CLIENT && currentlevel > 5 )
2390 										{
2391 											entity->monsterStoreType = (currentlevel / 5) * 3 + (rand() % 4); // scale humans with depth. 3 LVL each 5 floors, + 0-3.
2392 										}
2393 									}
2394 								}
2395 								else
2396 								{
2397 									entity = newEntity(10, 1, map.entities, map.creatures);  // monster
2398 								}
2399 								entity->skill[5] = nummonsters;
2400 								nummonsters++;
2401 							}
2402 						}
2403 					}
2404 				}
2405 				else
2406 				{
2407 					// decorations
2408 					if ( (prng_get_uint() % 4 == 0 || (currentlevel <= 10 && !customTrapsForMapInUse)) && strcmp(map.name, "Hell") )
2409 					{
2410 						switch ( prng_get_uint() % 7 )
2411 						{
2412 							case 0:
2413 								entity = newEntity(12, 1, map.entities, nullptr); //Firecamp entity.
2414 								break; //Firecamp
2415 							case 1:
2416 								entity = newEntity(14, 1, map.entities, nullptr); //Fountain entity.
2417 								break; //Fountain
2418 							case 2:
2419 								entity = newEntity(15, 1, map.entities, nullptr); //Sink entity.
2420 								break; //Sink
2421 							case 3:
2422 								entity = newEntity(21, 1, map.entities, nullptr); //Chest entity.
2423 								setSpriteAttributes(entity, nullptr, nullptr);
2424 								entity->chestLocked = -1;
2425 								break; //Chest
2426 							case 4:
2427 								entity = newEntity(39, 1, map.entities, nullptr); //Tomb entity.
2428 								break; //Tomb
2429 							case 5:
2430 								entity = newEntity(59, 1, map.entities, nullptr); //Table entity.
2431 								setSpriteAttributes(entity, nullptr, nullptr);
2432 								break; //Table
2433 							case 6:
2434 								entity = newEntity(60, 1, map.entities, nullptr); //Chair entity.
2435 								setSpriteAttributes(entity, nullptr, nullptr);
2436 								break; //Chair
2437 						}
2438 					}
2439 					else
2440 					{
2441 						if ( customTrapsForMapInUse )
2442 						{
2443 							if ( !customTraps.spikes && !customTraps.verticalSpelltraps )
2444 							{
2445 								continue;
2446 							}
2447 							else if ( customTraps.verticalSpelltraps && prng_get_uint() % 2 == 0 )
2448 							{
2449 								entity = newEntity(120, 1, map.entities, nullptr); // vertical spell trap.
2450 								setSpriteAttributes(entity, nullptr, nullptr);
2451 							}
2452 							else if ( customTraps.spikes )
2453 							{
2454 								entity = newEntity(64, 1, map.entities, nullptr); // spear trap
2455 							}
2456 						}
2457 						else
2458 						{
2459 							if ( currentlevel <= 25 )
2460 							{
2461 								entity = newEntity(64, 1, map.entities, nullptr); // spear trap
2462 							}
2463 							else
2464 							{
2465 								if ( prng_get_uint() % 2 == 0 )
2466 								{
2467 									entity = newEntity(120, 1, map.entities, nullptr); // vertical spell trap.
2468 									setSpriteAttributes(entity, nullptr, nullptr);
2469 								}
2470 								else
2471 								{
2472 									entity = newEntity(64, 1, map.entities, nullptr); // spear trap
2473 								}
2474 							}
2475 						}
2476 						Entity* also = newEntity(33, 1, map.entities, nullptr);
2477 						also->x = x * 16;
2478 						also->y = y * 16;
2479 						//printlog("15 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",also->sprite,also->getUID(),also->x,also->y);
2480 					}
2481 					numGenDecorations++;
2482 				}
2483 			}
2484 		}
2485 		if ( entity != nullptr )
2486 		{
2487 			entity->x = x * 16;
2488 			entity->y = y * 16;
2489 			//printlog("9 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",entity->sprite,entity->getUID(),entity->x,entity->y);
2490 		}
2491 		// mark this location as inelligible for reselection
2492 		possiblelocations[y + x * map.height] = false;
2493 		numpossiblelocations--;
2494 	}
2495 
2496 	// on hell levels, lava doesn't bubble. helps performance
2497 	/*if( !strcmp(map.name,"Hell") ) {
2498 		for( node=map.entities->first; node!=NULL; node=node->next ) {
2499 			Entity *entity = (Entity *)node->element;
2500 			if( entity->sprite == 41 ) { // lava.png
2501 				entity->skill[4] = 1; // LIQUID_LAVANOBUBBLE =
2502 			}
2503 		}
2504 	}*/
2505 
2506 	free(possiblelocations);
2507 	free(trapexcludelocations);
2508 	free(monsterexcludelocations);
2509 	free(lootexcludelocations);
2510 	free(firstroomtile);
2511 	free(subRoomName);
2512 	free(sublevelname);
2513 	list_FreeAll(&subRoomMapList);
2514 	list_FreeAll(&mapList);
2515 	list_FreeAll(&doorList);
2516 	printlog("successfully generated a dungeon with %d rooms, %d monsters, %d gold, %d items, %d decorations.\n", roomcount, nummonsters, numGenGold, numGenItems, numGenDecorations);
2517 	//messagePlayer(0, "successfully generated a dungeon with %d rooms, %d monsters, %d gold, %d items, %d decorations.", roomcount, nummonsters, numGenGold, numGenItems, numGenDecorations);
2518 	return secretlevelexit;
2519 }
2520 
2521 /*-------------------------------------------------------------------------------
2522 
2523 	assignActions
2524 
2525 	configures a map to be playable from a default state
2526 
2527 -------------------------------------------------------------------------------*/
2528 
assignActions(map_t * map)2529 void assignActions(map_t* map)
2530 {
2531 	Sint32 x, y, c;
2532 	//Sint32 z;
2533 	node_t* node, *nextnode;
2534 	Entity* entity, *childEntity;
2535 	Item* item;
2536 	bool itemsdonebefore = false;
2537 	Entity* vampireQuestChest = nullptr;
2538 
2539 	if ( map == nullptr )
2540 	{
2541 		return;
2542 	}
2543 
2544 	// add lava lights
2545 	for ( y = 0; y < map->height; ++y )
2546 	{
2547 		for ( x = 0; x < map->width; ++x )
2548 		{
2549 			if ( lavatiles[map->tiles[y * MAPLAYERS + x * MAPLAYERS * map->height]] )
2550 			{
2551 				lightSphereShadow(x, y, 2, 128);
2552 			}
2553 		}
2554 	}
2555 
2556 	// seed the random generator
2557 
2558 	prng_seed_bytes(&mapseed, sizeof(mapseed));
2559 
2560 	int balance = 0;
2561 	int i;
2562 	for ( i = 0; i < MAXPLAYERS; i++ )
2563 	{
2564 		if ( !client_disconnected[i] )
2565 		{
2566 			balance++;
2567 		}
2568 	}
2569 
2570 	bool customMonsterCurveExists = false;
2571 	if ( !monsterCurveCustomManager.inUse() )
2572 	{
2573 		monsterCurveCustomManager.readFromFile();
2574 	}
2575 	if ( monsterCurveCustomManager.curveExistsForCurrentMapName(map->name) )
2576 	{
2577 		customMonsterCurveExists = true;
2578 		conductGameChallenges[CONDUCT_MODDED] = 1;
2579 		gamemods_disableSteamAchievements = true;
2580 	}
2581 	if ( gameplayCustomManager.inUse() )
2582 	{
2583 		conductGameChallenges[CONDUCT_MODDED] = 1;
2584 		gamemods_disableSteamAchievements = true;
2585 	}
2586 
2587 	// assign entity behaviors
2588 	for ( node = map->entities->first; node != nullptr; node = nextnode )
2589 	{
2590 		entity = (Entity*)node->element;
2591 		nextnode = node->next;
2592 		switch ( entity->sprite )
2593 		{
2594 			// null:
2595 			case 0:
2596 			{
2597 				list_RemoveNode(entity->mynode);
2598 				entity = nullptr;
2599 				break;
2600 				// player:
2601 			}
2602 			case 1:
2603 			{
2604 				if ( numplayers >= 0 && numplayers < MAXPLAYERS )
2605 				{
2606 					if ( client_disconnected[numplayers] )
2607 					{
2608 						// don't spawn missing players
2609 						++numplayers;
2610 						list_RemoveNode(entity->mynode);
2611 						entity = nullptr;
2612 						break;
2613 					}
2614 					if ( multiplayer != CLIENT )
2615 					{
2616 						if ( stats[numplayers]->HP <= 0 )
2617 						{
2618 							messagePlayer(numplayers, language[1109]);
2619 							stats[numplayers]->HP = stats[numplayers]->MAXHP / 2;
2620 							stats[numplayers]->MP = stats[numplayers]->MAXMP / 2;
2621 							stats[numplayers]->HUNGER = 500;
2622 							for ( c = 0; c < NUMEFFECTS; ++c )
2623 							{
2624 								if ( !(c == EFF_VAMPIRICAURA && stats[numplayers]->EFFECTS_TIMERS[c] == -2)
2625 									&& c != EFF_WITHDRAWAL && c != EFF_SHAPESHIFT )
2626 								{
2627 									stats[numplayers]->EFFECTS[c] = false;
2628 									stats[numplayers]->EFFECTS_TIMERS[c] = 0;
2629 								}
2630 							}
2631 						}
2632 					}
2633 					entity->behavior = &actPlayer;
2634 					entity->addToCreatureList(map->creatures);
2635 					entity->x += 8;
2636 					entity->y += 8;
2637 					entity->z = -1;
2638 					entity->focalx = limbs[HUMAN][0][0]; // 0
2639 					entity->focaly = limbs[HUMAN][0][1]; // 0
2640 					entity->focalz = limbs[HUMAN][0][2]; // -1.5
2641 					entity->sprite = 113; // head model
2642 					entity->sizex = 4;
2643 					entity->sizey = 4;
2644 					entity->flags[GENIUS] = true;
2645 					if ( numplayers == clientnum && multiplayer == CLIENT )
2646 					{
2647 						entity->flags[UPDATENEEDED] = false;
2648 					}
2649 					else
2650 					{
2651 						entity->flags[UPDATENEEDED] = true;
2652 					}
2653 					entity->flags[BLOCKSIGHT] = true;
2654 					entity->skill[2] = numplayers; // skill[2] == PLAYER_NUM
2655 					players[numplayers]->entity = entity;
2656 					if ( entity->playerStartDir == -1 )
2657 					{
2658 						entity->yaw = (prng_get_uint() % 8) * 45 * (PI / 180.f);
2659 					}
2660 					else
2661 					{
2662 						entity->yaw = entity->playerStartDir * 45 * (PI / 180.f);
2663 					}
2664 					entity->playerStartDir = 0;
2665 					if ( multiplayer != CLIENT )
2666 					{
2667 						if ( numplayers == 0 && minotaurlevel )
2668 						{
2669 							createMinotaurTimer(entity, map);
2670 						}
2671 					}
2672 					++numplayers;
2673 				}
2674 				if ( balance > 4 )
2675 				{
2676 					// if MAXPLAYERS > 4, then add some new player markers
2677 					--balance;
2678 					Entity* extraPlayer = newEntity(1, 1, map->entities, nullptr);
2679 					extraPlayer->x = entity->x - 8;
2680 					extraPlayer->y = entity->y - 8;
2681 				}
2682 				if ( numplayers > MAXPLAYERS )
2683 				{
2684 					printlog("warning: too many player objects in level!\n");
2685 				}
2686 				break;
2687 			}
2688 			// east/west door:
2689 			case 2:
2690 			{
2691 				entity->x += 8;
2692 				entity->y += 8;
2693 				entity->sprite = 1;
2694 				entity->flags[PASSABLE] = true;
2695 				entity->behavior = &actDoorFrame;
2696 				childEntity = newEntity(2, 0, map->entities, nullptr); //Door frame entity.
2697 				childEntity->x = entity->x;
2698 				childEntity->y = entity->y;
2699 				TileEntityList.addEntity(*childEntity);
2700 				//printlog("16 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
2701 				childEntity->sizex = 1;
2702 				childEntity->sizey = 8;
2703 				childEntity->behavior = &actDoor;
2704 				childEntity->flags[BLOCKSIGHT] = true;
2705 				childEntity->skill[0] = 0; // signify behavior code of DOOR_DIR
2706 
2707 				// copy editor options from frame to door itself.
2708 				childEntity->doorDisableLockpicks = entity->doorDisableLockpicks;
2709 				childEntity->doorForceLockedUnlocked = entity->doorForceLockedUnlocked;
2710 				childEntity->doorDisableOpening = entity->doorDisableOpening;
2711 
2712 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door entity.
2713 				childEntity->flags[INVISIBLE] = true;
2714 				childEntity->flags[BLOCKSIGHT] = true;
2715 				childEntity->x = entity->x;
2716 				childEntity->y = entity->y - 7;
2717 				TileEntityList.addEntity(*childEntity);
2718 
2719 				//printlog("17 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
2720 				childEntity->sizex = 2;
2721 				childEntity->sizey = 2;
2722 				childEntity->behavior = &actDoorFrame;
2723 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door frame entity.
2724 				childEntity->flags[INVISIBLE] = true;
2725 				childEntity->flags[BLOCKSIGHT] = true;
2726 				childEntity->x = entity->x;
2727 				childEntity->y = entity->y + 7;
2728 				TileEntityList.addEntity(*childEntity);
2729 				//printlog("18 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
2730 				childEntity->sizex = 2;
2731 				childEntity->sizey = 2;
2732 				childEntity->behavior = &actDoorFrame;
2733 				break;
2734 			}
2735 			// north/south door:
2736 			case 3:
2737 			{
2738 				entity->x += 8;
2739 				entity->y += 8;
2740 				entity->yaw -= PI / 2.0;
2741 				entity->sprite = 1;
2742 				entity->flags[PASSABLE] = true;
2743 				entity->behavior = &actDoorFrame;
2744 				childEntity = newEntity(2, 0, map->entities, nullptr); //Door frame entity.
2745 				childEntity->x = entity->x;
2746 				childEntity->y = entity->y;
2747 				TileEntityList.addEntity(*childEntity);
2748 				//printlog("19 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
2749 				childEntity->sizex = 8;
2750 				childEntity->sizey = 1;
2751 				childEntity->yaw -= PI / 2.0;
2752 				childEntity->behavior = &actDoor;
2753 				childEntity->flags[BLOCKSIGHT] = true;
2754 				childEntity->skill[0] = 1; // signify behavior code of DOOR_DIR
2755 
2756 				// copy editor options from frame to door itself.
2757 				childEntity->doorDisableLockpicks = entity->doorDisableLockpicks;
2758 				childEntity->doorForceLockedUnlocked = entity->doorForceLockedUnlocked;
2759 				childEntity->doorDisableOpening = entity->doorDisableOpening;
2760 
2761 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door entity.
2762 				childEntity->flags[INVISIBLE] = true;
2763 				childEntity->flags[BLOCKSIGHT] = true;
2764 				childEntity->x = entity->x - 7;
2765 				childEntity->y = entity->y;
2766 
2767 				TileEntityList.addEntity(*childEntity);
2768 				//printlog("20 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
2769 				childEntity->sizex = 2;
2770 				childEntity->sizey = 2;
2771 				childEntity->behavior = &actDoorFrame;
2772 
2773 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door frame entity.
2774 				childEntity->flags[INVISIBLE] = true;
2775 				childEntity->flags[BLOCKSIGHT] = true;
2776 				childEntity->x = entity->x + 7;
2777 				childEntity->y = entity->y;
2778 				TileEntityList.addEntity(*childEntity);
2779 				//printlog("21 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
2780 				childEntity->sizex = 2;
2781 				childEntity->sizey = 2;
2782 				childEntity->behavior = &actDoorFrame;
2783 				break;
2784 			}
2785 			// east torch:
2786 			case 4:
2787 			{
2788 				if ( darkmap )
2789 				{
2790 					list_RemoveNode(entity->mynode);
2791 					entity = NULL;
2792 					break;
2793 				}
2794 				entity->behavior = &actTorch;
2795 				entity->x += 1;
2796 				entity->y += 8;
2797 				entity->z -= 1;
2798 				entity->sprite = 3;
2799 				entity->flags[PASSABLE] = true;
2800 				entity->flags[BRIGHT] = true;
2801 				break;
2802 				// south torch:
2803 			}
2804 			case 5:
2805 			{
2806 				if ( darkmap )
2807 				{
2808 					list_RemoveNode(entity->mynode);
2809 					entity = NULL;
2810 					break;
2811 				}
2812 				entity->behavior = &actTorch;
2813 				entity->x += 8;
2814 				entity->y += 1;
2815 				entity->z -= 1;
2816 				entity->yaw += PI / 2.0;
2817 				entity->sprite = 3;
2818 				entity->flags[PASSABLE] = true;
2819 				entity->flags[BRIGHT] = true;
2820 				break;
2821 			}
2822 			// west torch:
2823 			case 6:
2824 			{
2825 				if ( darkmap )
2826 				{
2827 					list_RemoveNode(entity->mynode);
2828 					entity = NULL;
2829 					break;
2830 				}
2831 				entity->behavior = &actTorch;
2832 				entity->x += 15;
2833 				entity->y += 8;
2834 				entity->z -= 1;
2835 				entity->yaw += PI;
2836 				entity->sprite = 3;
2837 				entity->flags[PASSABLE] = true;
2838 				entity->flags[BRIGHT] = true;
2839 				break;
2840 			}
2841 			// north torch:
2842 			case 7:
2843 			{
2844 				if ( darkmap )
2845 				{
2846 					list_RemoveNode(entity->mynode);
2847 					entity = NULL;
2848 					break;
2849 				}
2850 				entity->behavior = &actTorch;
2851 				entity->x += 8;
2852 				entity->y += 15;
2853 				entity->z -= 1;
2854 				entity->yaw += 3 * PI / 2.0;
2855 				entity->sprite = 3;
2856 				entity->flags[PASSABLE] = true;
2857 				entity->flags[BRIGHT] = true;
2858 				break;
2859 			}
2860 			// item:
2861 			case 68:
2862 			case 69:
2863 			case 8:
2864 			{
2865 				entity->sizex = 4;
2866 				entity->sizey = 4;
2867 				entity->x += 8;
2868 				entity->y += 8;
2869 				entity->roll = PI / 2.0;
2870 				entity->yaw = (prng_get_uint() % 360) * PI / 180.0;
2871 				entity->flags[PASSABLE] = true;
2872 				entity->behavior = &actItem;
2873 				if ( entity->sprite == 68 )   // magic_bow.png
2874 				{
2875 					entity->skill[10] = ARTIFACT_BOW;
2876 				}
2877 				else if ( entity->sprite == 69 )     // magic_spear.png
2878 				{
2879 					entity->skill[10] = ARTIFACT_SPEAR;
2880 					entity->x += 8;
2881 					entity->y += 8;
2882 				}
2883 				else if ( entity->skill[10] == 0 || entity->skill[10] == 1 )
2884 				{
2885 					if ( entity->skill[16] == 0 )
2886 					{
2887 						// random category default, either set by editor or spawn naturally.
2888 						if ( !itemsdonebefore && !strcmp(map->name, "Start Map") )
2889 						{
2890 							entity->skill[10] = READABLE_BOOK;
2891 						}
2892 						else
2893 						{
2894 							bool extrafood = false;
2895 							switch ( balance )
2896 							{
2897 								case 2:
2898 									if ( prng_get_uint() % 8 == 0 )
2899 									{
2900 										extrafood = true;
2901 									}
2902 									break;
2903 								case 3:
2904 									if ( prng_get_uint() % 6 == 0 )
2905 									{
2906 										extrafood = true;
2907 									}
2908 									break;
2909 								case 4:
2910 									if ( prng_get_uint() % 5 == 0 )
2911 									{
2912 										extrafood = true;
2913 									}
2914 									break;
2915 								default:
2916 									extrafood = false;
2917 									break;
2918 							}
2919 							if ( !extrafood )
2920 							{
2921 								if ( prng_get_uint() % 2 == 0 )
2922 								{
2923 									// possible magicstaff
2924 									int randType = prng_get_uint() % (NUMCATEGORIES - 1);
2925 									if ( randType == THROWN && prng_get_uint() % 3 ) // THROWN items 66% to be re-roll.
2926 									{
2927 										randType = prng_get_uint() % (NUMCATEGORIES - 1);
2928 									}
2929 									entity->skill[10] = itemLevelCurve(static_cast<Category>(randType), 0, currentlevel);
2930 								}
2931 								else
2932 								{
2933 									// impossible magicstaff
2934 									int randType = prng_get_uint() % (NUMCATEGORIES - 2);
2935 									if ( randType >= MAGICSTAFF )
2936 									{
2937 										randType++;
2938 									}
2939 									if ( randType == THROWN && prng_get_uint() % 3 ) // THROWN items 66% to be re-roll.
2940 									{
2941 										randType = prng_get_uint() % (NUMCATEGORIES - 2);
2942 										if ( randType >= MAGICSTAFF )
2943 										{
2944 											randType++;
2945 										}
2946 									}
2947 									entity->skill[10] = itemLevelCurve(static_cast<Category>(randType), 0, currentlevel);
2948 								}
2949 							}
2950 							else
2951 							{
2952 								entity->skill[10] = itemLevelCurve(FOOD, 0, currentlevel);
2953 							}
2954 						}
2955 					}
2956 					else
2957 					{
2958 						// editor set the random category of the item to be spawned.
2959 						if ( entity->skill[16] > 0 && entity->skill[16] <= 13 )
2960 						{
2961 							entity->skill[10] = itemLevelCurve(static_cast<Category>(entity->skill[16] - 1), 0, currentlevel);
2962 						}
2963 						else
2964 						{
2965 							int randType = 0;
2966 							if ( entity->skill[16] == 14 )
2967 							{
2968 								// equipment
2969 								randType = prng_get_uint() % 2;
2970 								if ( randType == 0 )
2971 								{
2972 									entity->skill[10] = itemLevelCurve(static_cast<Category>(WEAPON), 0, currentlevel);
2973 								}
2974 								else if ( randType == 1 )
2975 								{
2976 									entity->skill[10] = itemLevelCurve(static_cast<Category>(ARMOR), 0, currentlevel);
2977 								}
2978 							}
2979 							else if ( entity->skill[16] == 15 )
2980 							{
2981 								// jewelry
2982 								randType = prng_get_uint() % 2;
2983 								if ( randType == 0 )
2984 								{
2985 									entity->skill[10] = itemLevelCurve(static_cast<Category>(AMULET), 0, currentlevel);
2986 								}
2987 								else
2988 								{
2989 									entity->skill[10] = itemLevelCurve(static_cast<Category>(RING), 0, currentlevel);
2990 								}
2991 							}
2992 							else if ( entity->skill[16] == 16 )
2993 							{
2994 								// magical
2995 								randType = prng_get_uint() % 3;
2996 								if ( randType == 0 )
2997 								{
2998 									entity->skill[10] = itemLevelCurve(static_cast<Category>(SCROLL), 0, currentlevel);
2999 								}
3000 								else if ( randType == 1 )
3001 								{
3002 									entity->skill[10] = itemLevelCurve(static_cast<Category>(MAGICSTAFF), 0, currentlevel);
3003 								}
3004 								else
3005 								{
3006 									entity->skill[10] = itemLevelCurve(static_cast<Category>(SPELLBOOK), 0, currentlevel);
3007 								}
3008 							}
3009 						}
3010 					}
3011 				}
3012 				else if ( entity->skill[10] != 0 && entity->skill[10] != 1 ) //editor set the item type
3013 				{
3014 					entity->skill[10] = entity->skill[10] - 2; //reduce by 2 as the editor treats 1 as random, 0 is NULL
3015 				}
3016 
3017 				if ( entity->sprite == 8 )
3018 				{
3019 					if ( entity->skill[11] == 0 ) //random
3020 					{
3021 						entity->skill[11] = 1 + prng_get_uint() % 4; // status
3022 					}
3023 					else
3024 					{
3025 						entity->skill[11]--; //editor set number, sets this value to 0-5, with 1 being BROKEN, 5 being EXCELLENT
3026 					}
3027 				}
3028 				else
3029 				{
3030 					entity->skill[11] = DECREPIT + (currentlevel > 5) + (currentlevel > 15) + (currentlevel > 20);
3031 				}
3032 				if ( entity->sprite == 8 )
3033 				{
3034 					if ( entity->skill[12] == 10 ) //random, else the value of this variable is the curse/bless
3035 					{
3036 						if ( prng_get_uint() % 2 == 0 )   // 50% chance of curse/bless
3037 						{
3038 							entity->skill[12] = -2 + prng_get_uint() % 5;
3039 						}
3040 						else
3041 						{
3042 							entity->skill[12] = 0;
3043 						}
3044 					}
3045 				}
3046 				else
3047 				{
3048 					entity->skill[12] = 1;
3049 				}
3050 				if ( entity->sprite == 8 )
3051 				{
3052 					if ( entity->skill[13] == 0 )
3053 					{
3054 						entity->skill[13] = 1; // count set by maps.cpp, otherwise set by editor
3055 					}
3056 					else if ( entity->skill[13] == 1 )
3057 					{
3058 						if ( items[entity->skill[10]].category == FOOD )
3059 						{
3060 							switch ( balance )
3061 							{
3062 								case 2:
3063 									if ( prng_get_uint() % 3 == 0 )
3064 									{
3065 										entity->skill[13] += prng_get_uint() % 2;
3066 									}
3067 									break;
3068 								case 3:
3069 									if ( prng_get_uint() % 3 == 0 )
3070 									{
3071 										entity->skill[13] += prng_get_uint() % 3;
3072 									}
3073 									break;
3074 								case 4:
3075 									if ( prng_get_uint() % 2 == 0 )
3076 									{
3077 										entity->skill[13] += prng_get_uint() % 3;
3078 									}
3079 									break;
3080 								default:
3081 									break;
3082 							}
3083 						}
3084 					}
3085 				}
3086 
3087 				if ( !itemsdonebefore && !strcmp(map->name, "Start Map") )
3088 				{
3089 					entity->skill[14] = getBook("My Journal");
3090 				}
3091 				else
3092 				{
3093 					if ( items[entity->skill[10]].category == SCROLL || items[entity->skill[10]].variations > 1 )
3094 					{
3095 						entity->skill[14] = prng_get_uint();    // appearance
3096 					}
3097 					else
3098 					{
3099 						entity->skill[14] = 0;    // appearance
3100 					}
3101 				}
3102 				if ( entity->skill[15] == 1 ) // editor set as identified
3103 				{
3104 					entity->skill[15] = 1;
3105 				}
3106 				else if ( entity->skill[15] == 0 ) // unidentified (default)
3107 				{
3108 					entity->skill[15] = 0;
3109 				}
3110 				else  if ( entity->skill[15] == 2 ) // editor set as random
3111 				{
3112 					entity->skill[15] = prng_get_uint() % 2;
3113 				}
3114 				else
3115 				{
3116 					entity->skill[15] = 0; // unidentified.
3117 				}
3118 
3119 				if ( entity->skill[10] == ENCHANTED_FEATHER )
3120 				{
3121 					entity->skill[14] = 75 + 25 * (prng_get_uint() % 2);    // appearance
3122 				}
3123 				else if ( entity->skill[10] >= BRONZE_TOMAHAWK && entity->skill[10] <= CRYSTAL_SHURIKEN )
3124 				{
3125 					// thrown weapons always fixed status. (tomahawk = decrepit, shuriken = excellent)
3126 					entity->skill[11] = std::min(DECREPIT + (entity->skill[10] - BRONZE_TOMAHAWK), static_cast<int>(EXCELLENT));
3127 				}
3128 
3129 				item = newItemFromEntity(entity);
3130 				entity->sprite = itemModel(item);
3131 				if ( !entity->itemNotMoving )
3132 				{
3133 					// shurikens and chakrams need to lie flat on floor as their models are rotated.
3134 					if ( item->type == CRYSTAL_SHURIKEN || item->type == STEEL_CHAKRAM || item->type == BOOMERANG )
3135 					{
3136 						entity->roll = PI;
3137 						if ( item->type == CRYSTAL_SHURIKEN )
3138 						{
3139 							entity->z = 8.5 - models[entity->sprite]->sizey * .25;
3140 						}
3141 						else if ( item->type == BOOMERANG )
3142 						{
3143 							entity->z = 9.0 - models[entity->sprite]->sizey * .25;
3144 						}
3145 						else
3146 						{
3147 							entity->z = 8.75 - models[entity->sprite]->sizey * .25;
3148 						}
3149 					}
3150 					else if ( item->type == TOOL_BOMB || item->type == TOOL_FREEZE_BOMB
3151 						|| item->type == TOOL_SLEEP_BOMB || item->type == TOOL_TELEPORT_BOMB )
3152 					{
3153 						entity->roll = PI;
3154 						entity->z = 7 - models[entity->sprite]->sizey * .25;
3155 					}
3156 					else
3157 					{
3158 						entity->z = 7.5 - models[entity->sprite]->sizey * .25;
3159 					}
3160 				}
3161 				entity->itemNotMoving = 1; // so the item retains its position
3162 				entity->itemNotMovingClient = 1; // so the item retains its position for clients
3163 				itemsdonebefore = true;
3164 				if ( !strcmp(map->name, "Sokoban") && item->type == ARTIFACT_GLOVES ) // artifact gloves.
3165 				{
3166 					entity->flags[INVISIBLE] = true;
3167 					entity->itemSokobanReward = 1;
3168 				}
3169 				free(item);
3170 				break;
3171 			}
3172 			// gold:
3173 			case 9:
3174 				entity->sizex = 4;
3175 				entity->sizey = 4;
3176 				entity->x += 8;
3177 				entity->y += 8;
3178 				entity->z = 6.5;
3179 				entity->yaw = (prng_get_uint() % 360) * PI / 180.0;
3180 				entity->flags[PASSABLE] = true;
3181 				entity->behavior = &actGoldBag;
3182 				entity->skill[0] = 10 + rand() % 100 + (currentlevel); // amount
3183 				entity->sprite = 130; // gold bag model
3184 				if ( !strcmp(map->name, "Sokoban") )
3185 				{
3186 					entity->flags[INVISIBLE] = true;
3187 					entity->goldSokoban = 1;
3188 				}
3189 				break;
3190 			// monster:
3191 			case 71:
3192 			case 70:
3193 			case 62:
3194 			case 48:
3195 			case 36:
3196 			case 35:
3197 			case 30:
3198 			case 27:
3199 			case 10:
3200 			case 75:
3201 			case 76:
3202 			case 77:
3203 			case 78:
3204 			case 79:
3205 			case 80:
3206 			case 81:
3207 			case 82:
3208 			case 83:
3209 			case 84:
3210 			case 85:
3211 			case 86:
3212 			case 87:
3213 			case 88:
3214 			case 89:
3215 			case 90:
3216 			case 91:
3217 			case 92:
3218 			case 93:
3219 			case 94:
3220 			case 95:
3221 			case 163:
3222 			case 164:
3223 			case 165:
3224 			case 166:
3225 			{
3226 				entity->sizex = 4;
3227 				entity->sizey = 4;
3228 				entity->x += 8;
3229 				entity->y += 8;
3230 				entity->z = 6;
3231 				entity->yaw = (rand() % 360) * PI / 180.0;
3232 				entity->behavior = &actMonster;
3233 				entity->flags[UPDATENEEDED] = true;
3234 				entity->skill[5] = -1;
3235 				Stat* myStats = NULL;
3236 				if ( multiplayer != CLIENT )
3237 				{
3238 					myStats = entity->getStats();
3239 				}
3240 				//Assign entity creature list pointer.
3241 				entity->addToCreatureList(map->creatures);
3242 
3243 				Monster monsterType = SKELETON;
3244 				bool monsterIsFixedSprite = true;
3245 
3246 				if ( entity->sprite == 27 )   // human.png
3247 				{
3248 					monsterType = HUMAN;
3249 				}
3250 				else if ( entity->sprite == 30 )     // troll.png
3251 				{
3252 					monsterType = TROLL;
3253 				}
3254 				else if ( entity->sprite == 35 )     // shop.png
3255 				{
3256 					monsterType = SHOPKEEPER;
3257 				}
3258 				else if ( entity->sprite == 36 )     // goblin.png
3259 				{
3260 					monsterType = GOBLIN;
3261 				}
3262 				else if ( entity->sprite == 48 )     // spider.png
3263 				{
3264 					monsterType = SPIDER;
3265 				}
3266 				else if ( entity->sprite == 62 )     // herx.png
3267 				{
3268 					monsterType = LICH;
3269 				}
3270 				else if ( entity->sprite == 70 )     // gnome.png
3271 				{
3272 					monsterType = GNOME;
3273 				}
3274 				else if ( entity->sprite == 71 )     // devil.png
3275 				{
3276 					monsterType = DEVIL;
3277 				}
3278 				else if ( entity->sprite == 83 )     // devil.png
3279 				{
3280 					monsterType = SKELETON;
3281 				}
3282 				else if ( entity->sprite == 84 )     // devil.png
3283 				{
3284 					monsterType = KOBOLD;
3285 				}
3286 				else if ( entity->sprite == 85 )     // devil.png
3287 				{
3288 					monsterType = SCARAB;
3289 				}
3290 				else if ( entity->sprite == 86 )     // devil.png
3291 				{
3292 					monsterType = CRYSTALGOLEM;
3293 				}
3294 				else if ( entity->sprite == 87 )     // devil.png
3295 				{
3296 					monsterType = INCUBUS;
3297 				}
3298 				else if ( entity->sprite == 88 )     // devil.png
3299 				{
3300 					monsterType = VAMPIRE;
3301 				}
3302 				else if ( entity->sprite == 89 )     // devil.png
3303 				{
3304 					monsterType = SHADOW;
3305 				}
3306 				else if ( entity->sprite == 90 )     // devil.png
3307 				{
3308 					monsterType = COCKATRICE;
3309 				}
3310 				else if ( entity->sprite == 91 )     // devil.png
3311 				{
3312 					monsterType = INSECTOID;
3313 				}
3314 				else if ( entity->sprite == 92 )     // devil.png
3315 				{
3316 					monsterType = GOATMAN;
3317 				}
3318 				else if ( entity->sprite == 93 )     // devil.png
3319 				{
3320 					monsterType = AUTOMATON;
3321 				}
3322 				else if ( entity->sprite == 94 )     // devil.png
3323 				{
3324 					monsterType = LICH_ICE;
3325 				}
3326 				else if ( entity->sprite == 95 )     // devil.png
3327 				{
3328 					monsterType = LICH_FIRE;
3329 				}
3330 				else if ( entity->sprite == 81 )     // devil.png
3331 				{
3332 					monsterType = RAT;
3333 				}
3334 				else if ( entity->sprite == 75 )     // devil.png
3335 				{
3336 					monsterType = DEMON;
3337 				}
3338 				else if ( entity->sprite == 76 )     // devil.png
3339 				{
3340 					monsterType = CREATURE_IMP;
3341 				}
3342 				else if ( entity->sprite == 77 )     // devil.png
3343 				{
3344 					monsterType = MINOTAUR;
3345 				}
3346 				else if ( entity->sprite == 78 )     // devil.png
3347 				{
3348 					monsterType = SCORPION;
3349 				}
3350 				else if ( entity->sprite == 79 )     // devil.png
3351 				{
3352 					monsterType = SLIME;
3353 				}
3354 				else if ( entity->sprite == 80 )     // devil.png
3355 				{
3356 					monsterType = SUCCUBUS;
3357 				}
3358 				else if ( entity->sprite == 82 )     // devil.png
3359 				{
3360 					monsterType = GHOUL;
3361 				}
3362 				else if ( entity->sprite == 163 )
3363 				{
3364 					monsterType = SENTRYBOT;
3365 				}
3366 				else if ( entity->sprite == 164 )
3367 				{
3368 					monsterType = SPELLBOT;
3369 				}
3370 				else if ( entity->sprite == 165 )
3371 				{
3372 					monsterType = DUMMYBOT;
3373 				}
3374 				else if ( entity->sprite == 166 )
3375 				{
3376 					monsterType = GYROBOT;
3377 				}
3378 				else
3379 				{
3380 					monsterIsFixedSprite = false;
3381 					monsterType = static_cast<Monster>(monsterCurve(currentlevel));
3382 					if ( customMonsterCurveExists )
3383 					{
3384 						Monster customMonsterType = static_cast<Monster>(monsterCurveCustomManager.rollMonsterFromCurve(map->name));
3385 						if ( customMonsterType != NOTHING )
3386 						{
3387 							monsterType = customMonsterType;
3388 						}
3389 						else
3390 						{
3391 							customMonsterCurveExists = false;
3392 						}
3393 					}
3394 				}
3395 
3396 				if ( multiplayer != CLIENT )
3397 				{
3398 					if ( myStats == nullptr )
3399 					{
3400 						// need to give the entity its list stuff.
3401 						// create an empty first node for traversal purposes
3402 						node_t* node2 = list_AddNodeFirst(&entity->children);
3403 						node2->element = nullptr;
3404 						node2->deconstructor = &emptyDeconstructor;
3405 
3406 						if ( entity->sprite == 10 )
3407 						{
3408 							// if the sprite is 10, then choose from monsterCurve.
3409 							// Create the stat struct again for the new monster
3410 							myStats = new Stat(monsterType + 1000);
3411 						}
3412 						else
3413 						{
3414 							// if monster not random, then create the stat struct here
3415 							// should not occur (unless we hack it)
3416 							myStats = new Stat(entity->sprite);
3417 						}
3418 						node2 = list_AddNodeLast(&entity->children);
3419 						node2->element = myStats;
3420 						//					node2->deconstructor = &myStats->~Stat;
3421 						node2->size = sizeof(myStats);
3422 					}
3423 					else if ( entity->sprite == 10 )
3424 					{
3425 						// monster is random, but generated from editor
3426 						// stat struct is already created, need to set stats
3427 						setDefaultMonsterStats(myStats, monsterType + 1000);
3428 						setRandomMonsterStats(myStats);
3429 					}
3430 
3431 					std::string checkName = myStats->name;
3432 					if ( checkName.find(".json") != std::string::npos )
3433 					{
3434 						monsterCurveCustomManager.createMonsterFromFile(entity, myStats, checkName, monsterType);
3435 					}
3436 					else if ( customMonsterCurveExists )
3437 					{
3438 						std::string variantName = "default";
3439 						if ( monsterIsFixedSprite )
3440 						{
3441 							if ( isMonsterStatsDefault(*myStats) )
3442 							{
3443 								variantName = monsterCurveCustomManager.rollFixedMonsterVariant(map->name, monsterType);
3444 							}
3445 						}
3446 						else
3447 						{
3448 							variantName = monsterCurveCustomManager.rollMonsterVariant(map->name, monsterType);
3449 						}
3450 
3451 						if ( variantName.compare("default") != 0 )
3452 						{
3453 							// find a custom file name.
3454 							monsterCurveCustomManager.createMonsterFromFile(entity, myStats, variantName, monsterType);
3455 						}
3456 					}
3457 				}
3458 
3459 				switch ( monsterType )
3460 				{
3461 					case RAT:
3462 						entity->focalx = limbs[RAT][0][0]; // 0
3463 						entity->focaly = limbs[RAT][0][1]; // 0
3464 						entity->focalz = limbs[RAT][0][2]; // 0
3465 						break;
3466 					case SCORPION:
3467 						entity->focalx = limbs[SCORPION][0][0]; // 0
3468 						entity->focaly = limbs[SCORPION][0][1]; // 0
3469 						entity->focalz = limbs[SCORPION][0][2]; // 0
3470 						break;
3471 					case HUMAN:
3472 						entity->z = -1;
3473 						entity->focalx = limbs[HUMAN][0][0]; // 0
3474 						entity->focaly = limbs[HUMAN][0][1]; // 0
3475 						entity->focalz = limbs[HUMAN][0][2]; // -1.5
3476 						break;
3477 					case GOBLIN:
3478 						entity->z = 0;
3479 						entity->focalx = limbs[GOBLIN][0][0]; // 0
3480 						entity->focaly = limbs[GOBLIN][0][1]; // 0
3481 						entity->focalz = limbs[GOBLIN][0][2]; // -1.75
3482 						break;
3483 					case SLIME:
3484 						if ( multiplayer != CLIENT )
3485 						{
3486 							myStats->LVL = 7;
3487 						}
3488 						break;
3489 					case SUCCUBUS:
3490 						entity->z = -1;
3491 						entity->focalx = limbs[SUCCUBUS][0][0]; // 0
3492 						entity->focaly = limbs[SUCCUBUS][0][1]; // 0
3493 						entity->focalz = limbs[SUCCUBUS][0][2]; // -1.5
3494 						break;
3495 					case TROLL:
3496 						entity->z = -1.5;
3497 						entity->focalx = limbs[TROLL][0][0]; // 1
3498 						entity->focaly = limbs[TROLL][0][1]; // 0
3499 						entity->focalz = limbs[TROLL][0][2]; // -2
3500 						break;
3501 					case SHOPKEEPER:
3502 						entity->z = -1;
3503 						entity->focalx = limbs[SHOPKEEPER][0][0]; // 0
3504 						entity->focaly = limbs[SHOPKEEPER][0][1]; // 0
3505 						entity->focalz = limbs[SHOPKEEPER][0][2]; // -1.5
3506 						break;
3507 					case SKELETON:
3508 						entity->z = -.5;
3509 						entity->focalx = limbs[SKELETON][0][0]; // 0
3510 						entity->focaly = limbs[SKELETON][0][1]; // 0
3511 						entity->focalz = limbs[SKELETON][0][2]; // -1.5
3512 						break;
3513 					case MINOTAUR:
3514 						entity->z = -6;
3515 						entity->focalx = limbs[MINOTAUR][0][0]; // 0
3516 						entity->focaly = limbs[MINOTAUR][0][1]; // 0
3517 						entity->focalz = limbs[MINOTAUR][0][2]; // 0
3518 						break;
3519 					case GHOUL:
3520 						entity->z = -.25;
3521 						entity->focalx = limbs[GHOUL][0][0]; // 0
3522 						entity->focaly = limbs[GHOUL][0][1]; // 0
3523 						entity->focalz = limbs[GHOUL][0][2]; // -1.5
3524 						break;
3525 					case DEMON:
3526 						entity->z = -8.5;
3527 						entity->focalx = limbs[DEMON][0][0]; // -1
3528 						entity->focaly = limbs[DEMON][0][1]; // 0
3529 						entity->focalz = limbs[DEMON][0][2]; // -1.25
3530 						break;
3531 					case SPIDER:
3532 						entity->z = 4.5;
3533 						entity->focalx = limbs[SPIDER][0][0]; // -3
3534 						entity->focaly = limbs[SPIDER][0][1]; // 0
3535 						entity->focalz = limbs[SPIDER][0][2]; // -1
3536 						break;
3537 					case LICH:
3538 						entity->focalx = limbs[LICH][0][0]; // -0.75
3539 						entity->focaly = limbs[LICH][0][1]; // 0
3540 						entity->focalz = limbs[LICH][0][2]; // 0
3541 						entity->z = -2;
3542 						entity->yaw = PI;
3543 						entity->sprite = 274;
3544 						entity->skill[29] = 120;
3545 						break;
3546 					case CREATURE_IMP:
3547 						entity->z = -4.5;
3548 						entity->focalx = limbs[CREATURE_IMP][0][0]; // 0
3549 						entity->focaly = limbs[CREATURE_IMP][0][1]; // 0
3550 						entity->focalz = limbs[CREATURE_IMP][0][2]; // -1.75
3551 						break;
3552 					case GNOME:
3553 						entity->z = 2.25;
3554 						entity->focalx = limbs[GNOME][0][0]; // 0
3555 						entity->focaly = limbs[GNOME][0][1]; // 0
3556 						entity->focalz = limbs[GNOME][0][2]; // -2
3557 						break;
3558 					case DEVIL:
3559 						entity->focalx = limbs[DEVIL][0][0]; // 0
3560 						entity->focaly = limbs[DEVIL][0][1]; // 0
3561 						entity->focalz = limbs[DEVIL][0][2]; // 0
3562 						entity->z = -4;
3563 						entity->sizex = 20;
3564 						entity->sizey = 20;
3565 						entity->yaw = PI;
3566 						break;
3567 					case KOBOLD:
3568 						entity->z = 2.25;
3569 						entity->focalx = limbs[KOBOLD][0][0]; // 0
3570 						entity->focaly = limbs[KOBOLD][0][1]; // 0
3571 						entity->focalz = limbs[KOBOLD][0][2]; // -2
3572 						break;
3573 					case SCARAB:
3574 						entity->focalx = limbs[SCARAB][0][0]; // 0
3575 						entity->focaly = limbs[SCARAB][0][1]; // 0
3576 						entity->focalz = limbs[SCARAB][0][2]; // 0
3577 						if ( !strncmp(map->name, "The Labyrinth", 13) )
3578 						{
3579 							if ( myStats )
3580 							{
3581 								myStats->DEX -= 4;
3582 								myStats->LVL = 10;
3583 							}
3584 						}
3585 						break;
3586 					case CRYSTALGOLEM:
3587 						entity->z = -1.5;
3588 						entity->focalx = limbs[CRYSTALGOLEM][0][0]; // 1
3589 						entity->focaly = limbs[CRYSTALGOLEM][0][1]; // 0
3590 						entity->focalz = limbs[CRYSTALGOLEM][0][2]; // -2
3591 						break;
3592 					case INCUBUS:
3593 						entity->z = -1;
3594 						entity->focalx = limbs[INCUBUS][0][0]; // 0
3595 						entity->focaly = limbs[INCUBUS][0][1]; // 0
3596 						entity->focalz = limbs[INCUBUS][0][2]; // -1.5
3597 						break;
3598 					case VAMPIRE:
3599 						entity->z = -1;
3600 						entity->focalx = limbs[VAMPIRE][0][0]; // 0
3601 						entity->focaly = limbs[VAMPIRE][0][1]; // 0
3602 						entity->focalz = limbs[VAMPIRE][0][2]; // -1.5
3603 						if ( !strncmp(map->name, "The Ruins", 9) )
3604 						{
3605 							if ( myStats )
3606 							{
3607 								strcpy(myStats->name, "young vampire");
3608 							}
3609 						}
3610 						break;
3611 					case SHADOW:
3612 						entity->z = -1;
3613 						entity->focalx = limbs[SHADOW][0][0]; // 0
3614 						entity->focaly = limbs[SHADOW][0][1]; // 0
3615 						entity->focalz = limbs[SHADOW][0][2]; // -1.75
3616 						if ( !strncmp(map->name, "Underworld", 10) && currentlevel <= 7 && entity->monsterStoreType == 0 )
3617 						{
3618 							entity->monsterStoreType = 2;
3619 						}
3620 						break;
3621 					case COCKATRICE:
3622 						entity->z = -4.5;
3623 						entity->focalx = limbs[COCKATRICE][0][0]; // 0
3624 						entity->focaly = limbs[COCKATRICE][0][1]; // 0
3625 						entity->focalz = limbs[COCKATRICE][0][2]; // -1.75
3626 						break;
3627 					case INSECTOID:
3628 						entity->z = 0;
3629 						entity->focalx = limbs[INSECTOID][0][0]; // 0
3630 						entity->focaly = limbs[INSECTOID][0][1]; // 0
3631 						entity->focalz = limbs[INSECTOID][0][2]; // -1.75
3632 						if ( !strncmp(map->name, "The Labyrinth", 13) )
3633 						{
3634 							if ( myStats )
3635 							{
3636 								strcpy(myStats->name, "lesser insectoid");
3637 							}
3638 						}
3639 						break;
3640 					case GOATMAN:
3641 						entity->z = 0;
3642 						entity->focalx = limbs[GOATMAN][0][0]; // 0
3643 						entity->focaly = limbs[GOATMAN][0][1]; // 0
3644 						entity->focalz = limbs[GOATMAN][0][2]; // -1.75
3645 						if ( strstr(map->name, "Hell") )
3646 						{
3647 							if ( myStats )
3648 							{
3649 								strcpy(myStats->name, "lesser goatman");
3650 							}
3651 						}
3652 						break;
3653 					case AUTOMATON:
3654 						entity->z = -.5;
3655 						entity->focalx = limbs[AUTOMATON][0][0]; // 0
3656 						entity->focaly = limbs[AUTOMATON][0][1]; // 0
3657 						entity->focalz = limbs[AUTOMATON][0][2]; // -1.5
3658 						if ( entity->monsterStoreType == 1 )
3659 						{
3660 							if ( myStats )
3661 							{
3662 								strcpy(myStats->name, "damaged automaton");
3663 							}
3664 						}
3665 						break;
3666 					case LICH_ICE:
3667 						entity->focalx = limbs[LICH_ICE][0][0]; // -0.75
3668 						entity->focaly = limbs[LICH_ICE][0][1]; // 0
3669 						entity->focalz = limbs[LICH_ICE][0][2]; // 0
3670 						entity->z = -2;
3671 						entity->yaw = PI;
3672 						entity->sprite = 650;
3673 						entity->skill[29] = 120;
3674 						break;
3675 					case LICH_FIRE:
3676 						entity->focalx = limbs[LICH_FIRE][0][0]; // -0.75
3677 						entity->focaly = limbs[LICH_FIRE][0][1]; // 0
3678 						entity->focalz = limbs[LICH_FIRE][0][2]; // 0
3679 						entity->z = -1.2;
3680 						entity->yaw = PI;
3681 						entity->sprite = 646;
3682 						entity->skill[29] = 120;
3683 						break;
3684 					case SENTRYBOT:
3685 						entity->z = 0;
3686 						entity->focalx = limbs[SENTRYBOT][0][0]; // 0
3687 						entity->focaly = limbs[SENTRYBOT][0][1]; // 0
3688 						entity->focalz = limbs[SENTRYBOT][0][2]; // -1.75
3689 						break;
3690 					case SPELLBOT:
3691 						entity->z = 0;
3692 						entity->focalx = limbs[SENTRYBOT][0][0];
3693 						entity->focaly = limbs[SENTRYBOT][0][1];
3694 						entity->focalz = limbs[SENTRYBOT][0][2];
3695 						break;
3696 					case GYROBOT:
3697 						entity->z = 5;
3698 						entity->focalx = limbs[GYROBOT][0][0];
3699 						entity->focaly = limbs[GYROBOT][0][1];
3700 						entity->focalz = limbs[GYROBOT][0][2];
3701 						break;
3702 					case DUMMYBOT:
3703 						entity->z = 0;
3704 						entity->focalx = limbs[DUMMYBOT][0][0];
3705 						entity->focaly = limbs[DUMMYBOT][0][1];
3706 						entity->focalz = limbs[DUMMYBOT][0][2];
3707 						break;
3708 					default:
3709 						break;
3710 				}
3711 				if ( multiplayer != CLIENT )
3712 				{
3713 					myStats->type = monsterType;
3714 					if ( myStats->type == DEVIL )
3715 					{
3716 						childEntity = newEntity(72, 1, map->entities, nullptr);
3717 						//printlog("Generated devil spawner. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3718 						childEntity->x = entity->x - 8;
3719 						childEntity->y = entity->y - 8;
3720 						childEntity->setUID(-3);
3721 						entity_uids--;
3722 					}
3723 				}
3724 				break;
3725 			}
3726 			// ladder:
3727 			case 11:
3728 				entity->sizex = 4;
3729 				entity->sizey = 4;
3730 				entity->x += 8;
3731 				entity->y += 8;
3732 				entity->z = 5.45;
3733 				entity->flags[PASSABLE] = true;
3734 				entity->behavior = &actLadder;
3735 				entity->sprite = 161; // ladder
3736 				break;
3737 			// campfire:
3738 			case 12:
3739 				if ( darkmap )
3740 				{
3741 					list_RemoveNode(entity->mynode);
3742 					entity = NULL;
3743 					break;
3744 				}
3745 				entity->sizex = 3;
3746 				entity->sizey = 3;
3747 				entity->x += 8;
3748 				entity->y += 8;
3749 				entity->z = 6;
3750 				entity->flags[BRIGHT] = true;
3751 				entity->flags[PASSABLE] = true;
3752 				entity->behavior = &actCampfire;
3753 				entity->sprite = 162; // firepit
3754 				break;
3755 			//The Mystical Fountain of TODO:
3756 			case 14:
3757 			{
3758 				entity->sizex = 4;
3759 				entity->sizey = 4;
3760 				entity->x += 8;
3761 				entity->y += 8;
3762 				entity->z = 6.5;
3763 				entity->behavior = &actFountain;
3764 				entity->sprite = 163; //Fountain
3765 				entity->skill[0] = 1; //Fountain is full.
3766 				//Randomly determine effect.
3767 				int effect = rand() % 10; //3 possible effects.
3768 				entity->skill[28] = 1; //TODO: This is just for testing purposes.
3769 				switch (effect)
3770 				{
3771 					case 0:
3772 						//10% chance
3773 						entity->skill[1] = 3; //Will bless all equipment.
3774 						if ( (rand() % 4) != 0 )
3775 						{
3776 							entity->skill[1] = 4; //Will bless only one piece of equipment.
3777 						}
3778 						break;
3779 					case 1:
3780 					case 2:
3781 						//20% chance.
3782 						entity->skill[1] = 0; //Will spawn a succubus.
3783 						break;
3784 					case 3:
3785 					case 4:
3786 					case 5:
3787 						//30% chance.
3788 						entity->skill[1] = 1; //Will raise nutrients.
3789 						break;
3790 					case 6:
3791 					case 7:
3792 					case 8:
3793 					case 9:
3794 						//40% chance.
3795 						//Random potion effect.
3796 						entity->skill[1] = 2;
3797 						entity->skill[3] = rand() % 15; //Randomly choose from the number of potion effects there are.
3798 						break;
3799 					default:
3800 						break; //Should never happen.
3801 				}
3802 				break;
3803 			}
3804 			//Sink.
3805 			case 15:
3806 				entity->sizex = 4;
3807 				entity->sizey = 4;
3808 				entity->x += 8;
3809 				entity->y += 8;
3810 				entity->z = 5;
3811 				entity->behavior = &actSink;
3812 				entity->sprite = 164;
3813 				entity->skill[0] = 1 + rand() % 4; // number of uses
3814 				switch ( rand() % 10 )
3815 				{
3816 					case 0:
3817 						//10% chance.
3818 						entity->skill[3] = 0; //Player will find a ring.
3819 						break;
3820 					case 1:
3821 						//10% chance.
3822 						entity->skill[3] = 1; //Will spawn a slime.
3823 						break;
3824 					case 2:
3825 					case 3:
3826 					case 4:
3827 					case 5:
3828 					case 6:
3829 					case 7:
3830 						//60% chance.
3831 						entity->skill[3] = 2; //Will raise nutrition.
3832 						break;
3833 					case 8:
3834 					case 9:
3835 						//20% chance.
3836 						entity->skill[3] = 3; //Player will lose 1 HP.
3837 						break;
3838 					default:
3839 						break;
3840 				}
3841 				break;
3842 			//Switch.
3843 			case 17:
3844 				entity->sizex = 1;
3845 				entity->sizey = 1;
3846 				entity->x += 8;
3847 				entity->y += 8;
3848 				entity->z = 7;
3849 				entity->sprite = 184; // this is the switch base.
3850 				entity->flags[PASSABLE] = true;
3851 				childEntity = newEntity(186, 0, map->entities, nullptr); //Switch entity.
3852 				childEntity->x = entity->x;
3853 				childEntity->y = entity->y;
3854 				TileEntityList.addEntity(*childEntity);
3855 				//printlog("22 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3856 				childEntity->z = 8;
3857 				childEntity->focalz = -4.5;
3858 				childEntity->sizex = 1;
3859 				childEntity->sizey = 1;
3860 				childEntity->sprite = 185; // this is the switch handle.
3861 				childEntity->roll = PI / 4; // "off" position
3862 				childEntity->flags[PASSABLE] = true;
3863 				childEntity->behavior = &actSwitch;
3864 				entity->parent = childEntity->getUID();
3865 				break;
3866 			//Circuit.
3867 			case 18:
3868 				entity->sizex = 3;
3869 				entity->sizey = 3;
3870 				entity->x += 8;
3871 				entity->y += 8;
3872 				entity->z = 5;
3873 				entity->behavior = &actCircuit;
3874 				entity->flags[PASSABLE] = true;
3875 				entity->flags[INVISIBLE] = true;
3876 				entity->flags[NOUPDATE] = true;
3877 				//entity->sprite = 164; //No sprite.
3878 				entity->skill[28] = 1; //It's a depowered powerable.
3879 				break;
3880 			//North/South gate: //TODO: Adjust this. It's a copypaste of door.
3881 			case 19:
3882 				entity->x += 8;
3883 				entity->y += 8;
3884 				entity->yaw -= PI / 2.0;
3885 				entity->sprite = 1;
3886 				entity->flags[PASSABLE] = true;
3887 				entity->behavior = &actDoorFrame;
3888 
3889 				//entity->skill[28] = 1; //It's a mechanism.
3890 				childEntity = newEntity(186, 0, map->entities, nullptr); //Gate entity.
3891 				childEntity->x = entity->x;
3892 				childEntity->y = entity->y;
3893 				TileEntityList.addEntity(*childEntity);
3894 				//printlog("23 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3895 				childEntity->sizex = 8;
3896 				childEntity->sizey = 1;
3897 				childEntity->yaw -= PI / 2.0;
3898 				childEntity->gateInverted = 0; // non-inverted
3899 				childEntity->gateStatus = 0; // closed.
3900 				childEntity->skill[28] = 1; //It's a mechanism.
3901 				childEntity->behavior = &actGate;
3902 				childEntity->skill[0] = 1; // signify behavior code of DOOR_DIR
3903 
3904 				// copy editor options from frame to gate itself.
3905 				childEntity->gateDisableOpening = entity->gateDisableOpening;
3906 
3907 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door frame entity.
3908 				childEntity->flags[INVISIBLE] = true;
3909 				childEntity->flags[BLOCKSIGHT] = true;
3910 				childEntity->x = entity->x - 7;
3911 				childEntity->y = entity->y;
3912 				TileEntityList.addEntity(*childEntity);
3913 				//printlog("24 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3914 				childEntity->sizex = 2;
3915 				childEntity->sizey = 2;
3916 				childEntity->behavior = &actDoorFrame;
3917 
3918 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door frame entity.
3919 				childEntity->flags[INVISIBLE] = true;
3920 				childEntity->flags[BLOCKSIGHT] = true;
3921 				childEntity->x = entity->x + 7;
3922 				childEntity->y = entity->y;
3923 				TileEntityList.addEntity(*childEntity);
3924 				//printlog("25 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3925 				childEntity->sizex = 2;
3926 				childEntity->sizey = 2;
3927 				childEntity->behavior = &actDoorFrame;
3928 				break;
3929 			//East/west gate: //TODO: Adjust this. It's a copypaste of door.
3930 			case 20:
3931 				entity->x += 8;
3932 				entity->y += 8;
3933 				entity->sprite = 1;
3934 				entity->flags[PASSABLE] = true;
3935 				entity->behavior = &actDoorFrame;
3936 
3937 				childEntity = newEntity(186, 0, map->entities, nullptr); //Gate entity.
3938 				childEntity->x = entity->x;
3939 				childEntity->y = entity->y;
3940 				TileEntityList.addEntity(*childEntity);
3941 				//printlog("26 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3942 				childEntity->sizex = 1;
3943 				childEntity->sizey = 8;
3944 				childEntity->gateInverted = 0; // non-inverted
3945 				childEntity->gateStatus = 0; // closed.
3946 				childEntity->skill[28] = 1; //It's a mechanism.
3947 				childEntity->behavior = &actGate;
3948 				childEntity->skill[0] = 0; // signify behavior code of DOOR_DIR
3949 
3950 				// copy editor options from frame to gate itself.
3951 				childEntity->gateDisableOpening = entity->gateDisableOpening;
3952 
3953 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door frame entity.
3954 				childEntity->flags[INVISIBLE] = true;
3955 				childEntity->flags[BLOCKSIGHT] = true;
3956 				childEntity->x = entity->x;
3957 				childEntity->y = entity->y - 7;
3958 				TileEntityList.addEntity(*childEntity);
3959 				//printlog("27 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3960 				childEntity->sizex = 2;
3961 				childEntity->sizey = 2;
3962 				childEntity->behavior = &actDoorFrame;
3963 
3964 				childEntity = newEntity(1, 0, map->entities, nullptr); //Door frame entity.
3965 				childEntity->flags[INVISIBLE] = true;
3966 				childEntity->flags[BLOCKSIGHT] = true;
3967 				childEntity->x = entity->x;
3968 				childEntity->y = entity->y + 7;
3969 				TileEntityList.addEntity(*childEntity);
3970 				//printlog("28 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
3971 				childEntity->sizex = 2;
3972 				childEntity->sizey = 2;
3973 				childEntity->behavior = &actDoorFrame;
3974 				break;
3975 			//Chest.
3976 			case 21:
3977 			{
3978 				entity->sizex = 3;
3979 				entity->sizey = 2;
3980 				entity->x += 8;
3981 				entity->y += 8;
3982 				entity->z = 5.5;
3983 				entity->yaw = entity->yaw * (PI / 2); //set to 0 by default in editor, can be set 0-3
3984 				entity->behavior = &actChest;
3985 				entity->sprite = 188;
3986 				//entity->skill[9] = -1; //Set default chest as random category < 0
3987 
3988 				childEntity = newEntity(216, 0, map->entities, nullptr); //Chest lid entity.
3989 				childEntity->parent = entity->getUID();
3990 				entity->parent = childEntity->getUID();
3991 				if ( entity->yaw == 0 ) //EAST FACING
3992 				{
3993 					childEntity->x = entity->x - 3;
3994 					childEntity->y = entity->y;
3995 				}
3996 				else if ( entity->yaw == PI / 2 ) //SOUTH FACING
3997 				{
3998 					childEntity->x = entity->x;
3999 					childEntity->y = entity->y - 3;
4000 				}
4001 				else if ( entity->yaw == PI ) //WEST FACING
4002 				{
4003 					childEntity->x = entity->x + 3;
4004 					childEntity->y = entity->y;
4005 				}
4006 				else if (entity->yaw == 3 * PI/2 ) //NORTH FACING
4007 				{
4008 					childEntity->x = entity->x;
4009 					childEntity->y = entity->y + 3;
4010 				}
4011 				else
4012 				{
4013 					childEntity->x = entity->x;
4014 					childEntity->y = entity->y - 3;
4015 				}
4016 				TileEntityList.addEntity(*childEntity);
4017 				//printlog("29 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4018 				childEntity->z = entity->z - 2.75;
4019 				childEntity->focalx = 3;
4020 				childEntity->focalz = -.75;
4021 				childEntity->yaw = entity->yaw;
4022 				childEntity->sizex = 2;
4023 				childEntity->sizey = 2;
4024 				childEntity->behavior = &actChestLid;
4025 				childEntity->flags[PASSABLE] = true;
4026 
4027 				//Chest inventory.
4028 				node_t* tempNode = list_AddNodeFirst(&entity->children);
4029 				tempNode->element = NULL;
4030 				tempNode->deconstructor = &emptyDeconstructor;
4031 
4032 				if ( !strcmp(map->name, "The Mystic Library") && !vampireQuestChest )
4033 				{
4034 					vampireQuestChest = entity;
4035 				}
4036 				break;
4037 			}
4038 			// liquid marker
4039 			case 28:
4040 				entity->sizex = 8;
4041 				entity->sizey = 8;
4042 				entity->x += 8;
4043 				entity->y += 8;
4044 				entity->behavior = &actLiquid;
4045 				entity->flags[SPRITE] = true;
4046 				entity->flags[INVISIBLE] = true;
4047 				entity->skill[2] = -9; // so clients know it's a liquid
4048 				break;
4049 			// arrow trap
4050 			case 32:
4051 				entity->sizex = 2;
4052 				entity->sizey = 2;
4053 				entity->x += 8;
4054 				entity->y += 8;
4055 				entity->behavior = &actArrowTrap;
4056 				entity->flags[SPRITE] = true;
4057 				entity->flags[INVISIBLE] = true;
4058 				entity->flags[PASSABLE] = true;
4059 				entity->flags[NOUPDATE] = true;
4060 				entity->skill[28] = 1; // is a mechanism
4061 				entity->skill[1] = QUIVER_SILVER + rand() % 7; // random arrow type.
4062 				if ( currentlevel <= 15 )
4063 				{
4064 					while ( entity->skill[1] == QUIVER_CRYSTAL || entity->skill[1] == QUIVER_PIERCE )
4065 					{
4066 						entity->skill[1] = QUIVER_SILVER + rand() % 7; // random arrow type.
4067 					}
4068 				}
4069 				entity->skill[3] = 0; // refire type.
4070 				break;
4071 			// trap (pressure plate thingy)
4072 			case 33:
4073 				entity->sizex = 2;
4074 				entity->sizey = 2;
4075 				entity->x += 8;
4076 				entity->y += 8;
4077 				entity->behavior = &actTrap;
4078 				entity->flags[SPRITE] = true;
4079 				entity->flags[INVISIBLE] = true;
4080 				entity->flags[PASSABLE] = true;
4081 				entity->flags[NOUPDATE] = true;
4082 				break;
4083 			// trap permanent (pressure plate thingy) (remains on)
4084 			case 34:
4085 				entity->sizex = 2;
4086 				entity->sizey = 2;
4087 				entity->x += 8;
4088 				entity->y += 8;
4089 				entity->behavior = &actTrapPermanent;
4090 				entity->flags[SPRITE] = true;
4091 				entity->flags[INVISIBLE] = true;
4092 				entity->flags[PASSABLE] = true;
4093 				entity->flags[NOUPDATE] = true;
4094 				break;
4095 			// minotaur spawn trap
4096 			case 37:
4097 				entity->skill[28] = 1; // is a mechanism
4098 				entity->sizex = 2;
4099 				entity->sizey = 2;
4100 				entity->x += 8;
4101 				entity->y += 8;
4102 				entity->behavior = &actMinotaurTrap;
4103 				entity->flags[SPRITE] = true;
4104 				entity->flags[INVISIBLE] = true;
4105 				entity->flags[PASSABLE] = true;
4106 				entity->flags[NOUPDATE] = true;
4107 				break;
4108 			// summon monster trap
4109 			case 97:
4110 				entity->skill[28] = 1; // is a mechanism
4111 				if ( entity->skill[1] == 0 )
4112 				{
4113 					// not generated by editor, set monster qty to 1.
4114 					entity->skill[1] = 1;
4115 				}
4116 				if ( entity->skill[2] == 0 )
4117 				{
4118 					// not generated by editor, set time between spawns to 1.
4119 					entity->skill[2] = 1;
4120 				}
4121 				if ( entity->skill[3] == 0 )
4122 				{
4123 					// not generated by editor, amount spawns to 1.
4124 					entity->skill[3] = 1;
4125 				}
4126 				if ( entity->skill[4] > 1 )
4127 				{
4128 					// catch invalid input by editor, require power flag
4129 					entity->skill[4] = 0;
4130 				}
4131 				if ( entity->skill[5] > 100 )
4132 				{
4133 					// catch invalid input by editor, chance to fail set to 0
4134 					entity->skill[5] = 0;
4135 				}
4136 				entity->sizex = 2;
4137 				entity->sizey = 2;
4138 				entity->x += 8;
4139 				entity->y += 8;
4140 				entity->behavior = &actSummonTrap;
4141 				entity->flags[SPRITE] = true;
4142 				entity->flags[INVISIBLE] = true;
4143 				entity->flags[PASSABLE] = true;
4144 				entity->flags[NOUPDATE] = true;
4145 				break;
4146 			// boulder trap
4147 			case 38:
4148 			{
4149 				entity->sizex = 2;
4150 				entity->sizey = 2;
4151 				entity->x += 8;
4152 				entity->y += 8;
4153 				entity->behavior = &actBoulderTrap;
4154 				entity->flags[SPRITE] = true;
4155 				entity->flags[INVISIBLE] = true;
4156 				entity->flags[PASSABLE] = true;
4157 				entity->flags[NOUPDATE] = true;
4158 				entity->skill[28] = 1; // is a mechanism
4159 				for ( c = 0; c < 4; c++ )
4160 				{
4161 					switch ( c )
4162 					{
4163 						case 0:
4164 							x = 16;
4165 							y = 0;
4166 							break;
4167 						case 1:
4168 							x = 0;
4169 							y = 16;
4170 							break;
4171 						case 2:
4172 							x = -16;
4173 							y = 0;
4174 							break;
4175 						case 3:
4176 							x = 0;
4177 							y = -16;
4178 							break;
4179 					}
4180 					x = ((int)(x + entity->x)) >> 4;
4181 					y = ((int)(y + entity->y)) >> 4;
4182 					if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4183 					{
4184 						if ( !map->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4185 						{
4186 							Entity* childEntity = newEntity(252, 1, map->entities, nullptr);
4187 							childEntity->x = (x << 4) + 8;
4188 							childEntity->y = (y << 4) + 8;
4189 							//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4190 							childEntity->flags[PASSABLE] = true;
4191 							if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4192 							{
4193 								childEntity->z = -26.99;
4194 							}
4195 							else
4196 							{
4197 								childEntity->z = -10.99;
4198 							}
4199 							TileEntityList.addEntity(*childEntity);
4200 							entity->boulderTrapRocksToSpawn |= (1 << c); // add this location to spawn a boulder below the trapdoor model.
4201 						}
4202 					}
4203 				}
4204 				break;
4205 			}
4206 			// headstone
4207 			case 39:
4208 				entity->sizex = 4;
4209 				entity->sizey = 4;
4210 				entity->x += 8;
4211 				entity->y += 8;
4212 				entity->sprite = 224; // gravestone_faded.vox
4213 				entity->z = 8 - models[entity->sprite]->sizez / 4;
4214 				entity->behavior = &actHeadstone;
4215 				entity->skill[28] = 1; // is a mechanism
4216 				if ( !strcmp(map->name, "The Haunted Castle") )
4217 				{
4218 					entity->flags[INVISIBLE] = true;
4219 					entity->flags[PASSABLE] = true;
4220 				}
4221 				break;
4222 			// model tester
4223 			case 40:
4224 				entity->behavior = &actRotate;
4225 				entity->sprite = 0;
4226 				break;
4227 			// lava
4228 			case 41:
4229 				entity->sizex = 8;
4230 				entity->sizey = 8;
4231 				entity->x += 8;
4232 				entity->y += 8;
4233 				entity->behavior = &actLiquid;
4234 				entity->flags[USERFLAG1] = true; // this is lava
4235 				entity->flags[SPRITE] = true;
4236 				entity->flags[INVISIBLE] = true;
4237 				entity->skill[2] = -9; // so clients know it's a liquid
4238 				break;
4239 			// ladder hole
4240 			case 43:
4241 				entity->x += 8;
4242 				entity->y += 8;
4243 				entity->sprite = 253;
4244 				entity->flags[PASSABLE] = true;
4245 				entity->behavior = &actLadderUp;
4246 				x = entity->x / 16;
4247 				y = entity->y / 16;
4248 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4249 				{
4250 					if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4251 					{
4252 						entity->z = -21.49;
4253 					}
4254 					else
4255 					{
4256 						entity->z = -5.49;
4257 					}
4258 				}
4259 				break;
4260 			// boulder
4261 			case 44:
4262 				entity->x += 8;
4263 				entity->y += 8;
4264 				entity->sprite = 245;
4265 				entity->sizex = 7;
4266 				entity->sizey = 7;
4267 				entity->behavior = &actBoulder;
4268 				entity->skill[0] = 1; // BOULDER_STOPPED
4269 				break;
4270 			// portal
4271 			case 45:
4272 				entity->x += 8;
4273 				entity->y += 8;
4274 				entity->sprite = 254;
4275 				entity->sizex = 4;
4276 				entity->sizey = 4;
4277 				entity->yaw = PI / 2;
4278 				entity->behavior = &actPortal;
4279 				if ( !strcmp(map->name, "Mages Guild") )
4280 				{
4281 					entity->skill[3] = 1; // not secret portal, just aesthetic.
4282 				}
4283 				entity->flags[PASSABLE] = true;
4284 				entity->flags[BRIGHT] = true;
4285 				break;
4286 			// secret ladder:
4287 			case 46:
4288 				entity->sizex = 4;
4289 				entity->sizey = 4;
4290 				entity->x += 8;
4291 				entity->y += 8;
4292 				entity->z = 5.45;
4293 				entity->flags[PASSABLE] = true;
4294 				entity->behavior = &actLadder;
4295 				entity->sprite = 161; // ladder
4296 				entity->skill[3] = 1; // LADDER_SECRET = 1;
4297 				break;
4298 			// table
4299 			case 59:
4300 			{
4301 				entity->sizex = 5;
4302 				entity->sizey = 4;
4303 				entity->x += 8;
4304 				entity->y += 8;
4305 				entity->z = 8;
4306 				entity->focalz = -3;
4307 				entity->sprite = 271;
4308 				entity->behavior = &actFurniture;
4309 				entity->flags[BURNABLE] = true;
4310 				entity->furnitureType = FURNITURE_TABLE;
4311 				if ( entity->furnitureDir != -1 )
4312 				{
4313 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
4314 					if ( entity->furnitureDir == 0 || entity->furnitureDir == 4 )
4315 					{
4316 						entity->sizex = 5;
4317 						entity->sizey = 4;
4318 					}
4319 					else if ( entity->furnitureDir == 2 || entity->furnitureDir == 6 )
4320 					{
4321 						entity->sizex = 4;
4322 						entity->sizey = 5;
4323 					}
4324 					else
4325 					{
4326 						entity->sizex = 6;
4327 						entity->sizey = 6;
4328 					}
4329 				}
4330 				bool doItem = false;
4331 				if ( entity->furnitureTableRandomItemChance == -1 )
4332 				{
4333 					if ( prng_get_uint() % 4 == 0 || !strcmp(map->name, "Start Map") )
4334 					{
4335 						doItem = true;
4336 					}
4337 				}
4338 				else if ( entity->furnitureTableRandomItemChance > 1 )
4339 				{
4340 					if ( prng_get_uint() % 100 < entity->furnitureTableRandomItemChance )
4341 					{
4342 						doItem = true;
4343 					}
4344 				}
4345 				if ( doItem )
4346 				{
4347 					// put an item on the table
4348 					childEntity = newEntity(8, 1, map->entities, nullptr);
4349 					setSpriteAttributes(childEntity, nullptr, nullptr);
4350 					childEntity->x = entity->x - 8;
4351 					childEntity->y = entity->y - 8;
4352 					TileEntityList.addEntity(*childEntity);
4353 					//printlog("31 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4354 					childEntity->z = 0;
4355 					childEntity->itemNotMoving = 1; // so the item retains its position
4356 					childEntity->itemNotMovingClient = 1; // so the item retains its position for clients
4357 					entity->parent = childEntity->getUID();
4358 				}
4359 
4360 				bool doChairs = false;
4361 				int numChairs = 0;
4362 				if ( entity->furnitureTableSpawnChairs == -1 )
4363 				{
4364 					if ( prng_get_uint() % 2 == 0 )
4365 					{
4366 						doChairs = true;
4367 					}
4368 				}
4369 				else if ( entity->furnitureTableSpawnChairs > 0 )
4370 				{
4371 					doChairs = true;
4372 				}
4373 				if ( doChairs )
4374 				{
4375 					// surround the table with chairs
4376 					int c;
4377 					if ( entity->furnitureTableSpawnChairs == -1 )
4378 					{
4379 						numChairs = prng_get_uint() % 4 + 1;
4380 					}
4381 					else
4382 					{
4383 						numChairs = entity->furnitureTableSpawnChairs;
4384 					}
4385 					for ( c = 0; c < numChairs; c++ )
4386 					{
4387 						childEntity = newEntity(60, 1, map->entities, nullptr);
4388 						setSpriteAttributes(childEntity, nullptr, nullptr);
4389 						childEntity->x = entity->x - 8;
4390 						childEntity->y = entity->y - 8;
4391 						//printlog("32 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4392 						childEntity->yaw = ((int)(prng_get_uint() % 80) - 40 + c * 90) * (PI / 180.f);
4393 						if ( childEntity->yaw >= PI * 2 )
4394 						{
4395 							childEntity->yaw -= PI * 2;
4396 						}
4397 						else if ( childEntity->yaw < 0 )
4398 						{
4399 							childEntity->yaw += PI * 2;
4400 						}
4401 						childEntity->x -= cos(childEntity->yaw) * 7;
4402 						childEntity->y -= sin(childEntity->yaw) * 7;
4403 						TileEntityList.addEntity(*childEntity);
4404 					}
4405 				}
4406 				break;
4407 			}
4408 			// chair
4409 			case 60:
4410 				entity->furnitureType = FURNITURE_CHAIR; // so everything knows I'm a chair
4411 				entity->sizex = 2;
4412 				entity->sizey = 2;
4413 				entity->x += 8;
4414 				entity->y += 8;
4415 				entity->z = 8;
4416 				entity->focalz = -5;
4417 				entity->sprite = 272;
4418 				entity->behavior = &actFurniture;
4419 				entity->flags[BURNABLE] = true;
4420 				if ( entity->furnitureDir == -1 )
4421 				{
4422 					if ( !entity->yaw )
4423 					{
4424 						entity->yaw = (prng_get_uint() % 360) * (PI / 180.f);
4425 					}
4426 				}
4427 				else
4428 				{
4429 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
4430 				}
4431 				break;
4432 			// MC easter egg:
4433 			case 61:
4434 				entity->sizex = 2;
4435 				entity->sizey = 2;
4436 				entity->x += 8;
4437 				entity->y += 8;
4438 				entity->z = 4;
4439 				entity->sprite = 273;
4440 				entity->behavior = &actMCaxe;
4441 				entity->flags[PASSABLE] = true;
4442 				break;
4443 			// end game portal:
4444 			case 63:
4445 				entity->x += 8;
4446 				entity->y += 8;
4447 				entity->sprite = 278;
4448 				entity->sizex = 4;
4449 				entity->sizey = 4;
4450 				entity->yaw = PI / 2;
4451 				entity->behavior = &actWinningPortal;
4452 				entity->flags[PASSABLE] = true;
4453 				entity->flags[BRIGHT] = true;
4454 				if ( strstr(map->name, "Boss") )
4455 				{
4456 					entity->flags[INVISIBLE] = true;
4457 					entity->skill[28] = 1; // is a mechanism
4458 				}
4459 				if ( strstr(map->name, "Hell") )
4460 				{
4461 					entity->skill[4] = 2;
4462 					entity->flags[INVISIBLE] = true;
4463 					entity->skill[28] = 1; // is a mechanism
4464 				}
4465 				else
4466 				{
4467 					entity->skill[4] = 1;
4468 				}
4469 				break;
4470 			// speartrap:
4471 			case 64:
4472 				entity->sizex = 6;
4473 				entity->sizey = 6;
4474 				entity->x += 8;
4475 				entity->y += 8;
4476 				entity->z = 16;
4477 				entity->focalz = 7;
4478 				entity->sprite = 282;
4479 				entity->behavior = &actSpearTrap;
4480 				entity->skill[28] = 1; // is a mechanism
4481 				entity->flags[PASSABLE] = true;
4482 				childEntity = newEntity(283, 0, map->entities, nullptr);
4483 				childEntity->x = entity->x;
4484 				childEntity->y = entity->y;
4485 				TileEntityList.addEntity(*childEntity);
4486 				//printlog("33 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4487 				childEntity->z = entity->z - 7.75 - 0.01;
4488 				childEntity->flags[PASSABLE] = true;
4489 				break;
4490 			// magic trap:
4491 			case 65:
4492 				entity->sizex = 2;
4493 				entity->sizey = 2;
4494 				entity->x += 8;
4495 				entity->y += 8;
4496 				entity->behavior = &actMagicTrap;
4497 				entity->flags[SPRITE] = true;
4498 				entity->flags[INVISIBLE] = true;
4499 				entity->flags[PASSABLE] = true;
4500 				entity->skill[28] = 1; // is a mechanism
4501 				break;
4502 			// wall buster:
4503 			case 66:
4504 				entity->sizex = 2;
4505 				entity->sizey = 2;
4506 				entity->x += 8;
4507 				entity->y += 8;
4508 				entity->behavior = &actWallBuster;
4509 				entity->flags[SPRITE] = true;
4510 				entity->flags[INVISIBLE] = true;
4511 				entity->flags[PASSABLE] = true;
4512 				entity->flags[NOUPDATE] = true;
4513 				entity->skill[28] = 1; // is a mechanism
4514 				break;
4515 			// wall builder:
4516 			case 67:
4517 				entity->sizex = 2;
4518 				entity->sizey = 2;
4519 				entity->x += 8;
4520 				entity->y += 8;
4521 				entity->behavior = &actWallBuilder;
4522 				entity->flags[SPRITE] = true;
4523 				entity->flags[INVISIBLE] = true;
4524 				entity->flags[PASSABLE] = true;
4525 				entity->flags[NOUPDATE] = true;
4526 				entity->skill[28] = 1; // is a mechanism
4527 				break;
4528 			// devil/other teleport location:
4529 			case 72:
4530 			case 73:
4531 			case 74:
4532 			case 128:
4533 				entity->sizex = 2;
4534 				entity->sizey = 2;
4535 				entity->x += 8;
4536 				entity->y += 8;
4537 				entity->behavior = &actDevilTeleport;
4538 				entity->flags[SPRITE] = true;
4539 				entity->flags[INVISIBLE] = true;
4540 				entity->flags[PASSABLE] = true;
4541 				entity->flags[NOUPDATE] = true;
4542 				break;
4543 
4544 			// east crystal shard:
4545 			case 98:
4546 			{
4547 				if ( darkmap )
4548 				{
4549 					list_RemoveNode(entity->mynode);
4550 					entity = NULL;
4551 					break;
4552 				}
4553 				entity->behavior = &actCrystalShard;
4554 				entity->x += 1;
4555 				entity->y += 8;
4556 				entity->z -= 1;
4557 				entity->sprite = 587;
4558 				entity->flags[PASSABLE] = true;
4559 				entity->flags[BRIGHT] = true;
4560 				break;
4561 			}
4562 			// south crystal shard:
4563 			case 99:
4564 			{
4565 				if ( darkmap )
4566 				{
4567 					list_RemoveNode(entity->mynode);
4568 					entity = NULL;
4569 					break;
4570 				}
4571 				entity->behavior = &actCrystalShard;
4572 				entity->x += 8;
4573 				entity->y += 1;
4574 				entity->z -= 1;
4575 				entity->yaw += PI / 2.0;
4576 				entity->sprite = 587;
4577 				entity->flags[PASSABLE] = true;
4578 				entity->flags[BRIGHT] = true;
4579 				break;
4580 			}
4581 			// west crystal shard:
4582 			case 100:
4583 			{
4584 				if ( darkmap )
4585 				{
4586 					list_RemoveNode(entity->mynode);
4587 					entity = NULL;
4588 					break;
4589 				}
4590 				entity->behavior = &actCrystalShard;
4591 				entity->x += 15;
4592 				entity->y += 8;
4593 				entity->z -= 1;
4594 				entity->yaw += PI;
4595 				entity->sprite = 587;
4596 				entity->flags[PASSABLE] = true;
4597 				entity->flags[BRIGHT] = true;
4598 				break;
4599 			}
4600 			// north crystal shard:
4601 			case 101:
4602 			{
4603 				if ( darkmap )
4604 				{
4605 					list_RemoveNode(entity->mynode);
4606 					entity = NULL;
4607 					break;
4608 				}
4609 				entity->behavior = &actCrystalShard;
4610 				entity->x += 8;
4611 				entity->y += 15;
4612 				entity->z -= 1;
4613 				entity->yaw += 3 * PI / 2.0;
4614 				entity->sprite = 587;
4615 				entity->flags[PASSABLE] = true;
4616 				entity->flags[BRIGHT] = true;
4617 				break;
4618 			}
4619 
4620 			// boulder trap east
4621 			case 102:
4622 			{
4623 				entity->sizex = 2;
4624 				entity->sizey = 2;
4625 				entity->x += 8;
4626 				entity->y += 8;
4627 				entity->behavior = &actBoulderTrapEast;
4628 				entity->flags[SPRITE] = true;
4629 				entity->flags[INVISIBLE] = true;
4630 				entity->flags[PASSABLE] = true;
4631 				entity->flags[NOUPDATE] = true;
4632 				entity->skill[28] = 1; // is a mechanism
4633 				entity->boulderTrapPreDelay = entity->boulderTrapPreDelay * TICKS_PER_SECOND; // convert seconds to ticks from editor
4634 
4635 				x = ((int)(entity->x)) >> 4;
4636 				y = ((int)(entity->y)) >> 4;
4637 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4638 				{
4639 					if ( !map->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4640 					{
4641 						Entity* childEntity = newEntity(252, 1, map->entities, nullptr);
4642 						childEntity->x = (x << 4) + 8;
4643 						childEntity->y = (y << 4) + 8;
4644 						//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4645 						childEntity->flags[PASSABLE] = true;
4646 						if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4647 						{
4648 							childEntity->z = -26.99;
4649 						}
4650 						else
4651 						{
4652 							childEntity->z = -10.99;
4653 						}
4654 						TileEntityList.addEntity(*childEntity);
4655 					}
4656 				}
4657 				break;
4658 			}
4659 
4660 			// boulder trap south
4661 			case 103:
4662 			{
4663 				entity->sizex = 2;
4664 				entity->sizey = 2;
4665 				entity->x += 8;
4666 				entity->y += 8;
4667 				entity->behavior = &actBoulderTrapSouth;
4668 				entity->flags[SPRITE] = true;
4669 				entity->flags[INVISIBLE] = true;
4670 				entity->flags[PASSABLE] = true;
4671 				entity->flags[NOUPDATE] = true;
4672 				entity->skill[28] = 1; // is a mechanism
4673 				entity->boulderTrapPreDelay = entity->boulderTrapPreDelay * TICKS_PER_SECOND; // convert seconds to ticks from editor
4674 
4675 				x = ((int)(entity->x)) >> 4;
4676 				y = ((int)(entity->y)) >> 4;
4677 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4678 				{
4679 					if ( !map->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4680 					{
4681 						Entity* childEntity = newEntity(252, 1, map->entities, nullptr);
4682 						childEntity->x = (x << 4) + 8;
4683 						childEntity->y = (y << 4) + 8;
4684 						//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4685 						childEntity->flags[PASSABLE] = true;
4686 						if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4687 						{
4688 							childEntity->z = -26.99;
4689 						}
4690 						else
4691 						{
4692 							childEntity->z = -10.99;
4693 						}
4694 						TileEntityList.addEntity(*childEntity);
4695 					}
4696 				}
4697 				break;
4698 			}
4699 
4700 			// boulder trap west
4701 			case 104:
4702 			{
4703 				entity->sizex = 2;
4704 				entity->sizey = 2;
4705 				entity->x += 8;
4706 				entity->y += 8;
4707 				entity->behavior = &actBoulderTrapWest;
4708 				entity->flags[SPRITE] = true;
4709 				entity->flags[INVISIBLE] = true;
4710 				entity->flags[PASSABLE] = true;
4711 				entity->flags[NOUPDATE] = true;
4712 				entity->skill[28] = 1; // is a mechanism
4713 				entity->boulderTrapPreDelay = entity->boulderTrapPreDelay * TICKS_PER_SECOND; // convert seconds to ticks from editor
4714 
4715 				x = ((int)(entity->x)) >> 4;
4716 				y = ((int)(entity->y)) >> 4;
4717 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4718 				{
4719 					if ( !map->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4720 					{
4721 						Entity* childEntity = newEntity(252, 1, map->entities, nullptr);
4722 						childEntity->x = (x << 4) + 8;
4723 						childEntity->y = (y << 4) + 8;
4724 						//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4725 						childEntity->flags[PASSABLE] = true;
4726 						if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4727 						{
4728 							childEntity->z = -26.99;
4729 						}
4730 						else
4731 						{
4732 							childEntity->z = -10.99;
4733 						}
4734 						TileEntityList.addEntity(*childEntity);
4735 					}
4736 				}
4737 				break;
4738 			}
4739 
4740 			// boulder trap north
4741 			case 105:
4742 			{
4743 				entity->sizex = 2;
4744 				entity->sizey = 2;
4745 				entity->x += 8;
4746 				entity->y += 8;
4747 				entity->behavior = &actBoulderTrapNorth;
4748 				entity->flags[SPRITE] = true;
4749 				entity->flags[INVISIBLE] = true;
4750 				entity->flags[PASSABLE] = true;
4751 				entity->flags[NOUPDATE] = true;
4752 				entity->skill[28] = 1; // is a mechanism
4753 				entity->boulderTrapPreDelay = entity->boulderTrapPreDelay * TICKS_PER_SECOND; // convert seconds to ticks from editor
4754 
4755 				x = ((int)(entity->x)) >> 4;
4756 				y = ((int)(entity->y)) >> 4;
4757 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4758 				{
4759 					if ( !map->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4760 					{
4761 						Entity* childEntity = newEntity(252, 1, map->entities, nullptr);
4762 						childEntity->x = (x << 4) + 8;
4763 						childEntity->y = (y << 4) + 8;
4764 						//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4765 						childEntity->flags[PASSABLE] = true;
4766 						if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4767 						{
4768 							childEntity->z = -26.99;
4769 						}
4770 						else
4771 						{
4772 							childEntity->z = -10.99;
4773 						}
4774 						TileEntityList.addEntity(*childEntity);
4775 					}
4776 				}
4777 				break;
4778 			}
4779 
4780 			// power crystal
4781 			case 106:
4782 			{
4783 				entity->sizex = 4;
4784 				entity->sizey = 4;
4785 				entity->x += 8;
4786 				entity->y += 8;
4787 				entity->z = 6.5;
4788 				entity->behavior = &actPowerCrystalBase;
4789 				entity->sprite = 577; //crystal base
4790 				entity->yaw = entity->yaw * (PI / 2); // rotate as set in editor
4791 				entity->flags[PASSABLE] = false;
4792 
4793 				childEntity = newEntity(578, 0, map->entities, nullptr); //floating crystal
4794 				childEntity->parent = entity->getUID();
4795 
4796 				childEntity->x = entity->x;
4797 				childEntity->y = entity->y;
4798 				childEntity->sizex = 4;
4799 				childEntity->sizey = 4;
4800 				childEntity->crystalStartZ = entity->z - 10; //start position
4801 				childEntity->z = childEntity->crystalStartZ - 0.4 + ((prng_get_uint() % 8) * 0.1); // start the height randomly
4802 				childEntity->crystalMaxZVelocity = 0.02; //max velocity
4803 				childEntity->crystalMinZVelocity = 0.001; //min velocity
4804 				childEntity->crystalTurnVelocity = 0.2; //yaw turning velocity
4805 				childEntity->vel_z = childEntity->crystalMaxZVelocity * ((prng_get_uint() % 99) * 0.01 + 0.01); // start the velocity randomly
4806 
4807 				childEntity->crystalNumElectricityNodes = entity->crystalNumElectricityNodes; //number of electricity nodes to generate in facing direction.
4808 				childEntity->crystalTurnReverse = entity->crystalTurnReverse;
4809 				childEntity->crystalSpellToActivate = entity->crystalSpellToActivate;
4810 				if ( childEntity->crystalSpellToActivate )
4811 				{
4812 					childEntity->z = childEntity->crystalStartZ + 5;
4813 					childEntity->vel_z = childEntity->crystalMaxZVelocity * 2;
4814 				}
4815 				childEntity->yaw = entity->yaw;
4816 				childEntity->sizex = 4;
4817 				childEntity->sizey = 4;
4818 				childEntity->behavior = &actPowerCrystal;
4819 				childEntity->flags[PASSABLE] = true;
4820 				TileEntityList.addEntity(*childEntity);
4821 
4822 				node_t* tempNode = list_AddNodeLast(&entity->children);
4823 				tempNode->element = childEntity; // add the node to the children list.
4824 				tempNode->deconstructor = &emptyDeconstructor;
4825 				tempNode->size = sizeof(Entity*);
4826 
4827 				break;
4828 			}
4829 			// set beartrap
4830 			case 107:
4831 			{
4832 				entity->skill[0] = 0;
4833 				entity->sizex = 4;
4834 				entity->sizey = 4;
4835 				entity->x += 8;
4836 				entity->y += 8;
4837 				entity->z = 6.75;
4838 
4839 				//entity->focalz = -5;
4840 				entity->sprite = 668;
4841 
4842 				entity->behavior = &actBeartrap;
4843 				entity->flags[PASSABLE] = true;
4844 				entity->flags[UPDATENEEDED] = true;
4845 				if ( !entity->yaw )
4846 				{
4847 					entity->yaw = (prng_get_uint() % 360) * (PI / 180.f);
4848 				}
4849 				entity->roll = -PI / 2; // flip the model
4850 
4851 				entity->skill[11] = DECREPIT; //status
4852 				entity->skill[12] = 0; //beatitude
4853 				entity->skill[13] = 1; //qty
4854 				entity->skill[14] = 0; //appearance
4855 				entity->skill[15] = 0; //identified
4856 				break;
4857 			}
4858 			case 108: //stalag column
4859 				entity->x += 8;
4860 				entity->y += 8;
4861 				entity->sprite = 580;
4862 				entity->sizex = 8;
4863 				entity->sizey = 8;
4864 				entity->z = -7.75;
4865 				entity->flags[BLOCKSIGHT] = false;
4866 				entity->behavior = &actStalagColumn;
4867 				break;
4868 			case 109: //stalagmite single
4869 				entity->x += 8;
4870 				entity->y += 8;
4871 				entity->sprite = 581;
4872 				entity->sizex = 4;
4873 				entity->sizey = 4;
4874 				entity->z = 1.75;
4875 				entity->flags[BLOCKSIGHT] = false;
4876 				entity->behavior = &actStalagFloor;
4877 				break;
4878 			case 110: //stalagmite multiple
4879 				entity->x += 8;
4880 				entity->y += 8;
4881 				entity->sprite = 582;
4882 				entity->sizex = 7;
4883 				entity->sizey = 7;
4884 				entity->z = -1;
4885 				entity->flags[BLOCKSIGHT] = false;
4886 				entity->behavior = &actStalagFloor;
4887 				break;
4888 			case 111: //stalagtite single
4889 				entity->x += 8;
4890 				entity->y += 8;
4891 				entity->sprite = 583;
4892 				entity->sizex = 4;
4893 				entity->sizey = 4;
4894 				entity->z = -1.75;
4895 				x = entity->x / 16;
4896 				y = entity->y / 16;
4897 				entity->flags[BLOCKSIGHT] = false;
4898 				entity->behavior = &actStalagCeiling;
4899 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4900 				{
4901 					if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4902 					{
4903 						entity->flags[PASSABLE] = true;
4904 						entity->z -= 16;
4905 					}
4906 				}
4907 				break;
4908 			case 112: //stalagtite multiple
4909 				entity->x += 8;
4910 				entity->y += 8;
4911 				entity->sprite = 584;
4912 				entity->sizex = 7;
4913 				entity->sizey = 7;
4914 				entity->z = 1;
4915 				x = entity->x / 16;
4916 				y = entity->y / 16;
4917 				entity->flags[BLOCKSIGHT] = false;
4918 				entity->behavior = &actStalagCeiling;
4919 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
4920 				{
4921 					if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
4922 					{
4923 						entity->flags[PASSABLE] = true;
4924 						entity->z -= 16;
4925 					}
4926 				}
4927 				break;
4928 			//North/South gate inverted: //TODO: Adjust this. It's a copypaste of door.
4929 			case 113:
4930 				entity->x += 8;
4931 				entity->y += 8;
4932 				entity->yaw -= PI / 2.0;
4933 				entity->sprite = 1;
4934 				entity->flags[PASSABLE] = true;
4935 				entity->behavior = &actDoorFrame;
4936 
4937 				//entity->skill[28] = 1; //It's a mechanism.
4938 				childEntity = newEntity(186, 0, map->entities, nullptr);
4939 				childEntity->x = entity->x;
4940 				childEntity->y = entity->y;
4941 				TileEntityList.addEntity(*childEntity);
4942 				//printlog("23 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4943 				childEntity->sizex = 8;
4944 				childEntity->sizey = 1;
4945 				childEntity->yaw -= PI / 2.0;
4946 				childEntity->gateInverted = 1; // inverted.
4947 				childEntity->gateStatus = 1; // open.
4948 				childEntity->skill[28] = 1; //It's a mechanism.
4949 				childEntity->behavior = &actGate;
4950 				childEntity->skill[0] = 1; // signify behavior code of DOOR_DIR
4951 
4952 				// copy editor options from frame to gate itself.
4953 				childEntity->gateDisableOpening = entity->gateDisableOpening;
4954 
4955 				childEntity = newEntity(1, 0, map->entities, nullptr);
4956 				childEntity->flags[INVISIBLE] = true;
4957 				childEntity->flags[BLOCKSIGHT] = true;
4958 				childEntity->x = entity->x - 7;
4959 				childEntity->y = entity->y;
4960 				TileEntityList.addEntity(*childEntity);
4961 				//printlog("24 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4962 				childEntity->sizex = 2;
4963 				childEntity->sizey = 2;
4964 				childEntity->behavior = &actDoorFrame;
4965 
4966 				childEntity = newEntity(1, 0, map->entities, nullptr);
4967 				childEntity->flags[INVISIBLE] = true;
4968 				childEntity->flags[BLOCKSIGHT] = true;
4969 				childEntity->x = entity->x + 7;
4970 				childEntity->y = entity->y;
4971 				TileEntityList.addEntity(*childEntity);
4972 				//printlog("25 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4973 				childEntity->sizex = 2;
4974 				childEntity->sizey = 2;
4975 				childEntity->behavior = &actDoorFrame;
4976 				break;
4977 			//East/west gate inverted: //TODO: Adjust this. It's a copypaste of door.
4978 			case 114:
4979 				entity->x += 8;
4980 				entity->y += 8;
4981 				entity->sprite = 1;
4982 				entity->flags[PASSABLE] = true;
4983 				entity->behavior = &actDoorFrame;
4984 
4985 				childEntity = newEntity(186, 0, map->entities, nullptr);
4986 				childEntity->x = entity->x;
4987 				childEntity->y = entity->y;
4988 				TileEntityList.addEntity(*childEntity);
4989 				//printlog("26 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
4990 				childEntity->sizex = 1;
4991 				childEntity->gateInverted = 1; // inverted.
4992 				childEntity->gateStatus = 1; // open.
4993 				childEntity->sizey = 8;
4994 				childEntity->skill[28] = 1; //It's a mechanism.
4995 				childEntity->behavior = &actGate;
4996 				childEntity->skill[0] = 0; // signify behavior code of DOOR_DIR
4997 
4998 				// copy editor options from frame to gate itself.
4999 				childEntity->gateDisableOpening = entity->gateDisableOpening;
5000 
5001 				childEntity = newEntity(1, 0, map->entities, nullptr);
5002 				childEntity->flags[INVISIBLE] = true;
5003 				childEntity->flags[BLOCKSIGHT] = true;
5004 				childEntity->x = entity->x;
5005 				childEntity->y = entity->y - 7;
5006 				TileEntityList.addEntity(*childEntity);
5007 				//printlog("27 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
5008 				childEntity->sizex = 2;
5009 				childEntity->sizey = 2;
5010 				childEntity->behavior = &actDoorFrame;
5011 
5012 				childEntity = newEntity(1, 0, map->entities, nullptr);
5013 				childEntity->flags[INVISIBLE] = true;
5014 				childEntity->flags[BLOCKSIGHT] = true;
5015 				childEntity->x = entity->x;
5016 				childEntity->y = entity->y + 7;
5017 				TileEntityList.addEntity(*childEntity);
5018 				//printlog("28 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
5019 				childEntity->sizex = 2;
5020 				childEntity->sizey = 2;
5021 				childEntity->behavior = &actDoorFrame;
5022 				break;
5023 			//Switch with timer.
5024 			case 115:
5025 				entity->sizex = 1;
5026 				entity->sizey = 1;
5027 				entity->x += 8;
5028 				entity->y += 8;
5029 				entity->z = 7;
5030 				entity->sprite = 585; // this is the switch base.
5031 				entity->flags[PASSABLE] = true;
5032 				childEntity = newEntity(586, 0, map->entities, nullptr);
5033 				childEntity->x = entity->x;
5034 				childEntity->y = entity->y;
5035 				TileEntityList.addEntity(*childEntity);
5036 				//printlog("22 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
5037 				childEntity->z = 8;
5038 				childEntity->leverTimerTicks = std::max(entity->leverTimerTicks, 1) * TICKS_PER_SECOND; // convert seconds to ticks from editor, make sure not less than 1
5039 				childEntity->leverStatus = 0; // set default to off.
5040 				childEntity->focalz = -4.5;
5041 				childEntity->sizex = 1;
5042 				childEntity->sizey = 1;
5043 				childEntity->sprite = 586; // this is the switch handle.
5044 				childEntity->roll = -PI / 4; // "off" position
5045 				childEntity->flags[PASSABLE] = true;
5046 				childEntity->behavior = &actSwitchWithTimer;
5047 				break;
5048 			// pedestal
5049 			case 116:
5050 			{
5051 				entity->sizex = 4;
5052 				entity->sizey = 4;
5053 				entity->x += 8;
5054 				entity->y += 8;
5055 				entity->z = 4.5;
5056 				entity->behavior = &actPedestalBase;
5057 				entity->sprite = 601; //pedestal base
5058 				entity->flags[PASSABLE] = false;
5059 				entity->pedestalOrbType = entity->pedestalOrbType + 1;// set in editor as 0-3, need 1-4.
5060 				if ( entity->pedestalHasOrb == 1 ) // set in editor
5061 				{
5062 					entity->pedestalHasOrb = entity->pedestalOrbType;
5063 				}
5064 				//entity->pedestalInvertedPower // set in editor
5065 				entity->pedestalInit = 0;
5066 				//entity->pedestalInGround = 0; // set in editor
5067 				//entity->pedestalLockOrb // set in editor
5068 				if ( entity->pedestalInGround )
5069 				{
5070 					entity->z += 11;
5071 					entity->flags[PASSABLE] = true;
5072 				}
5073 
5074 				childEntity = newEntity(602 + entity->pedestalOrbType - 1, 0, map->entities, nullptr); //floating orb
5075 				childEntity->parent = entity->getUID();
5076 				childEntity->behavior = &actPedestalOrb;
5077 				childEntity->x = entity->x;
5078 				childEntity->y = entity->y;
5079 				TileEntityList.addEntity(*childEntity);
5080 				childEntity->z = -2;
5081 				childEntity->sizex = 2;
5082 				childEntity->sizey = 2;
5083 				childEntity->flags[UNCLICKABLE] = true;
5084 				childEntity->flags[PASSABLE] = true;
5085 				childEntity->flags[INVISIBLE] = false;
5086 				if ( entity->pedestalInGround )
5087 				{
5088 					childEntity->z += 11;
5089 					childEntity->orbStartZ = -2;
5090 				}
5091 				childEntity->pedestalOrbInit();
5092 
5093 				node_t* tempNode = list_AddNodeLast(&entity->children);
5094 				tempNode->element = childEntity; // add the node to the children list.
5095 				tempNode->deconstructor = &emptyDeconstructor;
5096 				tempNode->size = sizeof(Entity*);
5097 				break;
5098 			}
5099 			// mid game portal:
5100 			case 117:
5101 				entity->x += 8;
5102 				entity->y += 8;
5103 				entity->sprite = 614;
5104 				entity->sizex = 4;
5105 				entity->sizey = 4;
5106 				entity->yaw = PI / 2;
5107 				entity->behavior = &actMidGamePortal;
5108 				entity->flags[PASSABLE] = true;
5109 				entity->flags[BRIGHT] = true;
5110 				if ( strstr(map->name, "Boss") )
5111 				{
5112 					entity->flags[INVISIBLE] = true;
5113 					entity->skill[28] = 1; // is a mechanism
5114 				}
5115 				/*if ( strstr(map->name, "Hell") )
5116 				{
5117 					entity->skill[4] = 2;
5118 				}
5119 				else
5120 				{
5121 					entity->skill[4] = 1;
5122 				}*/
5123 				break;
5124 			// teleporter.
5125 			case 118:
5126 				entity->x += 8;
5127 				entity->y += 8;
5128 				entity->flags[PASSABLE] = true;
5129 				if ( entity->teleporterType == 0 )
5130 				{
5131 					entity->sprite = 618; // ladder hole
5132 					entity->behavior = &actTeleporter;
5133 					x = entity->x / 16;
5134 					y = entity->y / 16;
5135 					if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
5136 					{
5137 						if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
5138 						{
5139 							entity->z = -21.49;
5140 						}
5141 						else
5142 						{
5143 							entity->z = -5.49;
5144 						}
5145 					}
5146 				}
5147 				else if ( entity->teleporterType == 1 )
5148 				{
5149 					entity->sizex = 4;
5150 					entity->sizey = 4;
5151 					entity->z = 5.45;
5152 					entity->flags[PASSABLE] = true;
5153 					entity->behavior = &actTeleporter;
5154 					entity->sprite = 619; // ladder
5155 				}
5156 				else
5157 				{
5158 					entity->sprite = 254;
5159 					entity->sizex = 4;
5160 					entity->sizey = 4;
5161 					entity->yaw = PI / 2;
5162 					entity->behavior = &actTeleporter;
5163 					entity->flags[PASSABLE] = true;
5164 					entity->flags[BRIGHT] = true;
5165 				}
5166 				break;
5167 			// ceiling tile:
5168 			case 119:
5169 				entity->x += 8;
5170 				entity->y += 8;
5171 				entity->z = -24;
5172 				if ( entity->ceilingTileModel != 0 )
5173 				{
5174 					entity->sprite = entity->ceilingTileModel;
5175 				}
5176 				else
5177 				{
5178 					entity->sprite = 621;
5179 				}
5180 				entity->sizex = 8;
5181 				entity->sizey = 8;
5182 				//entity->yaw = PI / 2;
5183 				entity->behavior = &actCeilingTile;
5184 				entity->flags[PASSABLE] = true;
5185 				entity->flags[BLOCKSIGHT] = false;
5186 				//entity->flags[BRIGHT] = true;
5187 				break;
5188 			// spell trap ceiling
5189 			case 120:
5190 			{
5191 				entity->sizex = 2;
5192 				entity->sizey = 2;
5193 				entity->x += 8;
5194 				entity->y += 8;
5195 				entity->behavior = &actMagicTrapCeiling;
5196 				entity->flags[SPRITE] = true;
5197 				entity->flags[INVISIBLE] = true;
5198 				entity->flags[PASSABLE] = true;
5199 				entity->flags[NOUPDATE] = true;
5200 				entity->skill[28] = 1; // is a mechanism
5201 				entity->spellTrapRefireRate = entity->spellTrapRefireRate * TICKS_PER_SECOND; // convert seconds to ticks from editor
5202 
5203 				x = ((int)(entity->x)) >> 4;
5204 				y = ((int)(entity->y)) >> 4;
5205 				//map->tiles[y * MAPLAYERS + x * MAPLAYERS * map->height] = 208; //entity->spellTrapCeilingModel
5206 				Entity* childEntity = nullptr;
5207 				if ( x >= 0 && y >= 0 && x < map->width && y < map->height )
5208 				{
5209 					if ( !map->tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map->height] )
5210 					{
5211 						childEntity = newEntity(644, 1, map->entities, nullptr);
5212 						childEntity->parent = entity->getUID();
5213 						childEntity->x = entity->x;
5214 						childEntity->y = entity->y;
5215 						//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
5216 						childEntity->flags[PASSABLE] = true;
5217 						if ( !map->tiles[(MAPLAYERS - 1) + y * MAPLAYERS + x * MAPLAYERS * map->height] )
5218 						{
5219 							childEntity->z = -22.99;
5220 						}
5221 						else
5222 						{
5223 							childEntity->z = -6.99;
5224 						}
5225 						TileEntityList.addEntity(*childEntity);
5226 						node_t* tempNode = list_AddNodeLast(&entity->children);
5227 						tempNode->element = childEntity; // add the node to the children list.
5228 						tempNode->deconstructor = &emptyDeconstructor;
5229 						tempNode->size = sizeof(Entity*);
5230 
5231 						childEntity = newEntity(645, 1, map->entities, nullptr);
5232 						childEntity->parent = entity->getUID();
5233 						childEntity->x = entity->x;
5234 						childEntity->y = entity->y;
5235 						childEntity->z = 8.24;
5236 						TileEntityList.addEntity(*childEntity);
5237 						//printlog("30 Generated entity. Sprite: %d Uid: %d X: %.2f Y: %.2f\n",childEntity->sprite,childEntity->getUID(),childEntity->x,childEntity->y);
5238 						childEntity->flags[PASSABLE] = true;
5239 						tempNode = list_AddNodeLast(&entity->children);
5240 						tempNode->element = childEntity; // add the node to the children list.
5241 						tempNode->deconstructor = &emptyDeconstructor;
5242 						tempNode->size = sizeof(Entity*);
5243 					}
5244 				}
5245 				break;
5246 			}
5247 			// arcane chair
5248 			case 121:
5249 				entity->furnitureType = FURNITURE_CHAIR; // so everything knows I'm a chair
5250 				entity->sizex = 2;
5251 				entity->sizey = 2;
5252 				entity->x += 8;
5253 				entity->y += 8;
5254 				entity->z = 8;
5255 				entity->focalz = -5;
5256 				entity->sprite = 626;
5257 				entity->behavior = &actFurniture;
5258 				entity->flags[BURNABLE] = true;
5259 				if ( entity->furnitureDir == -1 && !entity->yaw )
5260 				{
5261 					entity->yaw = (prng_get_uint() % 360) * (PI / 180.f);
5262 				}
5263 				else
5264 				{
5265 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5266 				}
5267 				break;
5268 			// arcane bed
5269 			case 122:
5270 				entity->furnitureType = FURNITURE_BED; // so everything knows I'm a bed
5271 				entity->x += 8;
5272 				entity->y += 8;
5273 				entity->z = 4;
5274 				entity->sprite = 627;
5275 				entity->behavior = &actFurniture;
5276 				entity->flags[BURNABLE] = true;
5277 				if ( entity->furnitureDir == -1 && !entity->yaw )
5278 				{
5279 					entity->furnitureDir = (prng_get_uint() % 4);
5280 					entity->furnitureDir *= 2; // create an even number
5281 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5282 				}
5283 				else
5284 				{
5285 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5286 				}
5287 				if ( entity->furnitureDir == 0 || entity->furnitureDir == 4 )
5288 				{
5289 					entity->sizex = 8;
5290 					entity->sizey = 4;
5291 				}
5292 				else if ( entity->furnitureDir == 2 || entity->furnitureDir == 6 )
5293 				{
5294 					entity->sizex = 4;
5295 					entity->sizey = 8;
5296 				}
5297 				else
5298 				{
5299 					entity->sizex = 8;
5300 					entity->sizey = 8;
5301 				}
5302 				break;
5303 			// bunk bed
5304 			case 123:
5305 				entity->furnitureType = FURNITURE_BUNKBED; // so everything knows I'm a bunkbed
5306 				entity->x += 8;
5307 				entity->y += 8;
5308 				entity->z = 1.75;
5309 				entity->sprite = 628;
5310 				entity->behavior = &actFurniture;
5311 				entity->flags[BURNABLE] = true;
5312 				if ( entity->furnitureDir == -1 && !entity->yaw )
5313 				{
5314 					entity->furnitureDir = (prng_get_uint() % 4);
5315 					entity->furnitureDir *= 2; // create an even number
5316 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5317 				}
5318 				else
5319 				{
5320 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5321 				}
5322 				if ( entity->furnitureDir == 0 || entity->furnitureDir == 4 )
5323 				{
5324 					entity->sizex = 8;
5325 					entity->sizey = 4;
5326 				}
5327 				else if ( entity->furnitureDir == 2 || entity->furnitureDir == 6 )
5328 				{
5329 					entity->sizex = 4;
5330 					entity->sizey = 8;
5331 				}
5332 				else
5333 				{
5334 					entity->sizex = 8;
5335 					entity->sizey = 8;
5336 				}
5337 				break;
5338 			// column.
5339 			case 124:
5340 			{
5341 				entity->x += 8;
5342 				entity->y += 8;
5343 				entity->sprite = 629;
5344 				entity->sizex = 6;
5345 				entity->sizey = 6;
5346 				entity->z = -7.75;
5347 				entity->flags[BLOCKSIGHT] = false;
5348 				entity->behavior = &actColumn;
5349 				break;
5350 			}
5351 			// podium
5352 			case 125:
5353 			{
5354 				entity->sizex = 3;
5355 				entity->sizey = 3;
5356 				entity->x += 8;
5357 				entity->y += 8;
5358 				entity->z = 7.75;
5359 				entity->focalz = -3;
5360 				entity->sprite = 630;
5361 				entity->behavior = &actFurniture;
5362 				entity->furnitureType = FURNITURE_PODIUM;
5363 				entity->flags[BURNABLE] = true;
5364 				if ( entity->furnitureDir == -1 && !entity->yaw )
5365 				{
5366 					entity->furnitureDir = (prng_get_uint() % 4);
5367 					entity->furnitureDir *= 2; // create an even number
5368 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5369 				}
5370 				else
5371 				{
5372 					entity->yaw = entity->furnitureDir * 45 * (PI / 180.f);
5373 				}
5374 				break;
5375 			}
5376 			// piston.
5377 			case 126:
5378 			{
5379 				entity->x += 8;
5380 				entity->y += 8;
5381 				entity->sprite = 631;
5382 				entity->sizex = 8;
5383 				entity->sizey = 8;
5384 				entity->z = 0;
5385 				entity->flags[BLOCKSIGHT] = false;
5386 				entity->behavior = &actPistonBase;
5387 
5388 				childEntity = newEntity(632, 1, map->entities, nullptr); //cam1
5389 				childEntity->parent = entity->getUID();
5390 				childEntity->x = entity->x + 2.25;
5391 				childEntity->y = entity->y + 2.25;
5392 				childEntity->behavior = &actPistonCam;
5393 				childEntity->pistonCamRotateSpeed = 0.2;
5394 				childEntity->flags[UNCLICKABLE] = true;
5395 				TileEntityList.addEntity(*childEntity);
5396 				/*if ( multiplayer != CLIENT )
5397 				{
5398 					entity_uids--;
5399 				}
5400 				childEntity->setUID(-3);*/
5401 				childEntity = newEntity(633, 1, map->entities, nullptr); //cam2
5402 				childEntity->parent = entity->getUID();
5403 				childEntity->x = entity->x - 2.25;
5404 				childEntity->y = entity->y - 2.25;
5405 				childEntity->behavior = &actPistonCam;
5406 				childEntity->pistonCamRotateSpeed = -0.2;
5407 				childEntity->flags[UNCLICKABLE] = true;
5408 				TileEntityList.addEntity(*childEntity);
5409 				/*if ( multiplayer != CLIENT )
5410 				{
5411 					entity_uids--;
5412 				}
5413 				childEntity->setUID(-3);*/
5414 				break;
5415 			}
5416 			// grass texture
5417 			case 127:
5418 			{
5419 				entity->x += 8;
5420 				entity->y += 8;
5421 				entity->sprite = entity->floorDecorationModel;
5422 				entity->sizex = 0.01;
5423 				entity->sizey = 0.01;
5424 				entity->z = 7.5 - entity->floorDecorationHeightOffset * 0.25;
5425 				entity->x += entity->floorDecorationXOffset * 0.25;
5426 				entity->y += entity->floorDecorationYOffset * 0.25;
5427 				if ( entity->floorDecorationRotation == -1 )
5428 				{
5429 					entity->yaw = (prng_get_uint() % 8) * (PI / 4);
5430 				}
5431 				else
5432 				{
5433 					entity->yaw = entity->floorDecorationRotation * (PI / 4);
5434 				}
5435 				entity->flags[BLOCKSIGHT] = false;
5436 				entity->flags[PASSABLE] = true;
5437 				if ( entity->floorDecorationInteractText1 == 0 )
5438 				{
5439 					entity->flags[UNCLICKABLE] = true;
5440 				}
5441 				entity->behavior = &actFloorDecoration;
5442 				/*if ( multiplayer != CLIENT )
5443 				{
5444 					entity_uids--;
5445 				}
5446 				entity->setUID(-3);*/
5447 				break;
5448 			}
5449 			// expansion end game portal:
5450 			case 129:
5451 				entity->x += 8;
5452 				entity->y += 8;
5453 				entity->sprite = 614;
5454 				entity->sizex = 4;
5455 				entity->sizey = 4;
5456 				entity->yaw = PI / 2;
5457 				entity->behavior = &actExpansionEndGamePortal;
5458 				entity->flags[PASSABLE] = true;
5459 				entity->flags[BRIGHT] = true;
5460 				//entity->flags[INVISIBLE] = true;
5461 				entity->portalVictoryType = 3;
5462 				entity->skill[28] = 1; // is a mechanism
5463 				break;
5464 			//sound source
5465 			case 130:
5466 				entity->sizex = 2;
5467 				entity->sizey = 2;
5468 				entity->x += 8;
5469 				entity->y += 8;
5470 				entity->behavior = &actSoundSource;
5471 				entity->flags[SPRITE] = true;
5472 				entity->flags[INVISIBLE] = true;
5473 				entity->flags[PASSABLE] = true;
5474 				entity->flags[NOUPDATE] = true;
5475 				entity->skill[28] = 1; // is a mechanism
5476 				break;
5477 			//light source
5478 			case 131:
5479 				entity->sizex = 2;
5480 				entity->sizey = 2;
5481 				entity->x += 8;
5482 				entity->y += 8;
5483 				entity->behavior = &actLightSource;
5484 				entity->flags[SPRITE] = true;
5485 				entity->flags[INVISIBLE] = true;
5486 				entity->flags[PASSABLE] = true;
5487 				//entity->flags[NOUPDATE] = true;
5488 				entity->skill[28] = 1; // is a mechanism
5489 				break;
5490 			//text source
5491 			case 132:
5492 				entity->sizex = 2;
5493 				entity->sizey = 2;
5494 				entity->x += 8;
5495 				entity->y += 8;
5496 				entity->behavior = &actTextSource;
5497 				entity->flags[SPRITE] = true;
5498 				entity->flags[INVISIBLE] = true;
5499 				entity->flags[PASSABLE] = true;
5500 				entity->flags[NOUPDATE] = true;
5501 				entity->skill[28] = 1; // is a mechanism
5502 				break;
5503 			//signal timer
5504 			case 133:
5505 				entity->sizex = 2;
5506 				entity->sizey = 2;
5507 				entity->x += 8;
5508 				entity->y += 8;
5509 				entity->behavior = &actSignalTimer;
5510 				entity->flags[SPRITE] = true;
5511 				entity->flags[INVISIBLE] = true;
5512 				entity->flags[PASSABLE] = true;
5513 				entity->flags[NOUPDATE] = true;
5514 				entity->skill[28] = 1; // is a mechanism
5515 				break;
5516 			//custom teleporter
5517 			case 161:
5518 				entity->x += 8;
5519 				entity->y += 8;
5520 				entity->sprite = entity->portalCustomSprite;
5521 				entity->sizex = 4;
5522 				entity->sizey = 4;
5523 				entity->yaw = PI / 2;
5524 				entity->behavior = &actCustomPortal;
5525 				entity->flags[PASSABLE] = true;
5526 				if ( entity->portalCustomSpriteAnimationFrames > 0 )
5527 				{
5528 					entity->flags[BRIGHT] = true;
5529 				}
5530 				if ( entity->portalCustomRequiresPower )
5531 				{
5532 					entity->flags[INVISIBLE] = true;
5533 				}
5534 				entity->z = 7.5 - entity->portalCustomZOffset * 0.25;
5535 				if ( entity->portalCustomRequiresPower == 1 )
5536 				{
5537 					entity->skill[28] = 1; // is a mechanism
5538 				}
5539 				break;
5540 			case 162:
5541 			{
5542 				// readable book
5543 				entity->sizex = 4;
5544 				entity->sizey = 4;
5545 				entity->x += 8;
5546 				entity->y += 8;
5547 				entity->roll = PI / 2.0;
5548 				entity->yaw = (prng_get_uint() % 360) * PI / 180.0;
5549 				entity->flags[PASSABLE] = true;
5550 				entity->behavior = &actItem;
5551 				entity->skill[10] = READABLE_BOOK;
5552 				if ( entity->skill[11] == 0 ) //random
5553 				{
5554 					entity->skill[11] = 1 + prng_get_uint() % 4; // status
5555 				}
5556 				else
5557 				{
5558 					entity->skill[11]--; //editor set number, sets this value to 0-5, with 1 being BROKEN, 5 being EXCELLENT
5559 				}
5560 				if ( entity->skill[12] == 10 ) //random, else the value of this variable is the curse/bless
5561 				{
5562 					if ( prng_get_uint() % 2 == 0 )   // 50% chance of curse/bless
5563 					{
5564 						entity->skill[12] = -2 + prng_get_uint() % 5;
5565 					}
5566 					else
5567 					{
5568 						entity->skill[12] = 0;
5569 					}
5570 				}
5571 				entity->skill[13] = 1; // qty
5572 
5573 				// assemble the book string.
5574 				char buf[256] = "";
5575 				int totalChars = 0;
5576 				for ( int i = 40; i <= 52; ++i )
5577 				{
5578 					if ( i == 28 ) // circuit_status
5579 					{
5580 						continue;
5581 					}
5582 					if ( entity->skill[i] != 0 )
5583 					{
5584 						for ( int c = 0; c < 4; ++c )
5585 						{
5586 							buf[totalChars] = static_cast<char>((entity->skill[i] >> (c * 8)) & 0xFF);
5587 							++totalChars;
5588 						}
5589 					}
5590 				}
5591 				if ( buf[totalChars] != '\0' )
5592 				{
5593 					buf[totalChars] = '\0';
5594 				}
5595 				std::string output = buf;
5596 				size_t found = output.find("\\n");
5597 				while ( found != std::string::npos )
5598 				{
5599 					output.erase(found, 2);
5600 					output.insert(found, 1, '\n');
5601 					found = output.find("\\n");
5602 				}
5603 				strcpy(buf, output.c_str());
5604 
5605 				entity->skill[14] = getBook(buf);
5606 
5607 				if ( entity->skill[15] == 1 ) // editor set as identified
5608 				{
5609 					entity->skill[15] = 1;
5610 				}
5611 				else if ( entity->skill[15] == 0 ) // unidentified (default)
5612 				{
5613 					entity->skill[15] = 0;
5614 				}
5615 				else  if ( entity->skill[15] == 2 ) // editor set as random
5616 				{
5617 					entity->skill[15] = prng_get_uint() % 2;
5618 				}
5619 				else
5620 				{
5621 					entity->skill[15] = 0; // unidentified.
5622 				}
5623 
5624 				item = newItemFromEntity(entity);
5625 				entity->sprite = itemModel(item);
5626 				if ( !entity->itemNotMoving )
5627 				{
5628 					entity->z = 7.5 - models[entity->sprite]->sizey * .25;
5629 				}
5630 				entity->itemNotMoving = 1; // so the item retains its position
5631 				entity->itemNotMovingClient = 1; // so the item retains its position for clients
5632 				free(item);
5633 				item = nullptr;
5634 			}
5635 				break;
5636 			default:
5637 				break;
5638 		}
5639 		if ( entity )
5640 		{
5641 			nextnode = node->next;
5642 			TileEntityList.addEntity(*entity);
5643 		}
5644 	}
5645 
5646 	for ( node = map->entities->first; node != nullptr; )
5647 	{
5648 		Entity* postProcessEntity = (Entity*)node->element;
5649 		node = node->next;
5650 		if ( postProcessEntity )
5651 		{
5652 			if ( postProcessEntity->behavior == &actItem )
5653 			{
5654 				// see if there's any platforms to set items upon.
5655 				for ( node_t* tmpnode = map->entities->first; tmpnode != nullptr; tmpnode = tmpnode->next )
5656 				{
5657 					Entity* tmpentity = (Entity*)tmpnode->element;
5658 					if ( (tmpentity->behavior == &actFurniture
5659 							&& (tmpentity->x == postProcessEntity->x) && (tmpentity->y == postProcessEntity->y)
5660 						) )
5661 					{
5662 						if ( postProcessEntity->z > 4 )
5663 						{
5664 							if ( tmpentity->sprite == 271 )
5665 							{
5666 								// is table
5667 								postProcessEntity->z -= 6;
5668 								tmpentity->parent = postProcessEntity->getUID();
5669 							}
5670 							else if ( tmpentity->sprite == 630 )
5671 							{
5672 								// is podium
5673 								postProcessEntity->z -= 6;
5674 								tmpentity->parent = postProcessEntity->getUID();
5675 							}
5676 						}
5677 						break;
5678 					}
5679 				}
5680 			}
5681 			else if ( postProcessEntity->sprite == 252 && postProcessEntity->z <= -10 )
5682 			{
5683 				// trapdoor for boulder traps.
5684 				int findx = static_cast<int>(postProcessEntity->x) >> 4;
5685 				int findy = static_cast<int>(postProcessEntity->y) >> 4;
5686 				list_t* entitiesOnTile = TileEntityList.getTileList(findx, findy);
5687 				for ( node_t* tmpnode = entitiesOnTile->first; tmpnode != nullptr; tmpnode = tmpnode->next )
5688 				{
5689 					Entity* tmpentity = (Entity*)tmpnode->element;
5690 					if ( tmpentity && tmpentity != postProcessEntity )
5691 					{
5692 						if ( tmpentity->behavior != &actMonster
5693 							&& !tmpentity->flags[PASSABLE]
5694 							&& tmpentity->behavior != &actFurniture )
5695 						{
5696 							// remove the trapdoor since we've spawned over a gate, chest, door etc.
5697 							list_RemoveNode(postProcessEntity->mynode);
5698 							break;
5699 						}
5700 					}
5701 				}
5702 			}
5703 			else if ( postProcessEntity->sprite == 586 || postProcessEntity->sprite == 585
5704 				|| postProcessEntity->sprite == 184 || postProcessEntity->sprite == 185 )
5705 			{
5706 				int findx = static_cast<int>(postProcessEntity->x) >> 4;
5707 				int findy = static_cast<int>(postProcessEntity->y) >> 4;
5708 				if ( !map->tiles[findy * MAPLAYERS + findx * MAPLAYERS * map->height] )
5709 				{
5710 					// remove the lever as it is over a pit.
5711 					printlog("[MAP GENERATOR] Removed switch over a pit at x:%d y:%d.", findx, findy);
5712 					list_RemoveNode(postProcessEntity->mynode);
5713 				}
5714 			}
5715 		}
5716 	}
5717 	if ( vampireQuestChest )
5718 	{
5719 		for ( c = 0; c < MAXPLAYERS; ++c )
5720 		{
5721 			if ( client_classes[c] == CLASS_ACCURSED )
5722 			{
5723 				vampireQuestChest->chestHasVampireBook = 1;
5724 				break;
5725 			}
5726 		}
5727 	}
5728 
5729 	for ( node = map->entities->first; node != nullptr; )
5730 	{
5731 		Entity* postProcessEntity = (Entity*)node->element;
5732 		node = node->next;
5733 		if ( postProcessEntity )
5734 		{
5735 			if ( postProcessEntity->behavior == &actTextSource )
5736 			{
5737 				textSourceScript.parseScriptInMapGeneration(*postProcessEntity);
5738 			}
5739 		}
5740 	}
5741 }
5742 
mapLevel(int player)5743 void mapLevel(int player)
5744 {
5745 	int x, y;
5746 	for ( y = 0; y < map.height; ++y )
5747 	{
5748 		for ( x = 0; x < map.width; ++x )
5749 		{
5750 			if ( map.tiles[OBSTACLELAYER + y * MAPLAYERS + x * MAPLAYERS * map.height] )
5751 			{
5752 				if ( !minimap[y][x] )
5753 				{
5754 					minimap[y][x] = 4;
5755 				}
5756 			}
5757 			else if ( map.tiles[y * MAPLAYERS + x * MAPLAYERS * map.height] )
5758 			{
5759 				if ( !minimap[y][x] )
5760 				{
5761 					minimap[y][x] = 3;
5762 				}
5763 			}
5764 			else
5765 			{
5766 				minimap[y][x] = 0;
5767 			}
5768 		}
5769 	}
5770 }
5771 
mapFoodOnLevel(int player)5772 void mapFoodOnLevel(int player)
5773 {
5774 	int numFood = 0;
5775 	bool previouslyIdentifiedFood = false;
5776 	for ( node_t* node = map.entities->first; node != nullptr; node = node->next )
5777 	{
5778 		Entity* entity = (Entity*)node->element;
5779 		if ( entity && entity->behavior == &actItem )
5780 		{
5781 			Item* item = newItemFromEntity(entity);
5782 			if ( item )
5783 			{
5784 				if ( itemCategory(item) == FOOD )
5785 				{
5786 					if ( entity->itemShowOnMap != 0 )
5787 					{
5788 						previouslyIdentifiedFood = true;
5789 					}
5790 					else
5791 					{
5792 						++numFood;
5793 					}
5794 					entity->itemShowOnMap = 1;
5795 				}
5796 				free(item);
5797 			}
5798 		}
5799 	}
5800 	if ( numFood == 0 && previouslyIdentifiedFood )
5801 	{
5802 		messagePlayer(player, language[3425]);
5803 	}
5804 	else if ( numFood == 0 )
5805 	{
5806 		messagePlayer(player, language[3423]);
5807 	}
5808 	else
5809 	{
5810 		messagePlayerColor(player, SDL_MapRGB(mainsurface->format, 0, 255, 0),language[3424]);
5811 	}
5812 }
5813 
loadMainMenuMap(bool blessedAdditionMaps,bool forceVictoryMap)5814 int loadMainMenuMap(bool blessedAdditionMaps, bool forceVictoryMap)
5815 {
5816 	bool foundVictory = false;
5817 	for ( node_t* node = topscores.first; node != nullptr && !foundVictory; node = node->next )
5818 	{
5819 		score_t* score = (score_t*)node->element;
5820 		if ( score && score->victory == 3 )
5821 		{
5822 			foundVictory = true;
5823 		}
5824 	}
5825 	for ( node_t* node = topscoresMultiplayer.first; node != nullptr && !foundVictory; node = node->next )
5826 	{
5827 		score_t* score = (score_t*)node->element;
5828 		if ( score && score->victory == 3 )
5829 		{
5830 			foundVictory = true;
5831 		}
5832 	}
5833 
5834 	std::string fullMapName;
5835 
5836 	if ( forceVictoryMap || (foundVictory && rand() % 5 == 0) )
5837 	{
5838 		fullMapName = physfsFormatMapName("mainmenu9");
5839 		loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5840 		menucam.x = 34.3;
5841 		menucam.y = 15;
5842 		menucam.z = -20;
5843 		menucam.ang = 5.84;
5844 		return 1;
5845 	}
5846 	else if ( blessedAdditionMaps )
5847 	{
5848 		switch ( rand() % 4 )
5849 		{
5850 			case 0:
5851 				fullMapName = physfsFormatMapName("mainmenu5");
5852 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5853 				menucam.x = 30.8;
5854 				menucam.y = 24.3;
5855 				menucam.z = 0;
5856 				menucam.ang = 2.76;
5857 				break;
5858 			case 1:
5859 				fullMapName = physfsFormatMapName("mainmenu6");
5860 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5861 				menucam.x = 11;
5862 				menucam.y = 4;
5863 				menucam.z = 0;
5864 				menucam.ang = 2.4;
5865 				break;
5866 			case 2:
5867 				fullMapName = physfsFormatMapName("mainmenu7");
5868 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5869 				menucam.x = 8.7;
5870 				menucam.y = 9.3;
5871 				menucam.z = 0;
5872 				menucam.ang = 5.8;
5873 				break;
5874 			case 3:
5875 				fullMapName = physfsFormatMapName("mainmenu8");
5876 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5877 				menucam.x = 3.31;
5878 				menucam.y = 5.34;
5879 				menucam.z = 0;
5880 				menucam.ang = 0.96;
5881 				break;
5882 			default:
5883 				break;
5884 		}
5885 	}
5886 	else
5887 	{
5888 		switch ( rand() % 4 )
5889 		{
5890 			case 0:
5891 				fullMapName = physfsFormatMapName("mainmenu1");
5892 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5893 				menucam.x = 8;
5894 				menucam.y = 4.5;
5895 				menucam.z = 0;
5896 				menucam.ang = 0.6;
5897 				break;
5898 			case 1:
5899 				fullMapName = physfsFormatMapName("mainmenu2");
5900 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5901 				menucam.x = 7;
5902 				menucam.y = 4;
5903 				menucam.z = -4;
5904 				menucam.ang = 1.0;
5905 				break;
5906 			case 2:
5907 				fullMapName = physfsFormatMapName("mainmenu3");
5908 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5909 				menucam.x = 5;
5910 				menucam.y = 3;
5911 				menucam.z = 0;
5912 				menucam.ang = 1.0;
5913 				break;
5914 			case 3:
5915 				fullMapName = physfsFormatMapName("mainmenu4");
5916 				loadMap(fullMapName.c_str(), &map, map.entities, map.creatures);
5917 				menucam.x = 6;
5918 				menucam.y = 14.5;
5919 				menucam.z = -24;
5920 				menucam.ang = 5.0;
5921 				break;
5922 		}
5923 	}
5924 
5925 	return 0;
5926 }
5927 
5928