1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: buttons.cpp
5 	Desc: contains code for all buttons in the editor
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 "editor.hpp"
14 #include "entity.hpp"
15 #include "files.hpp"
16 #include "player.hpp"
17 
18 button_t* butX;
19 button_t* but_;
20 button_t* butTilePalette;
21 button_t* butSprite;
22 button_t* butPencil;
23 button_t* butPoint;
24 button_t* butBrush;
25 button_t* butSelect;
26 button_t* butFill;
27 button_t* butFile;
28 button_t* butNew;
29 button_t* butOpen;
30 button_t* butDir;
31 button_t* butSave;
32 button_t* butSaveAs;
33 button_t* butExit;
34 button_t* butEdit;
35 button_t* butCut;
36 button_t* butCopy;
37 button_t* butPaste;
38 button_t* butDelete;
39 button_t* butSelectAll;
40 button_t* butUndo;
41 button_t* butRedo;
42 button_t* butView;
43 button_t* butToolbox;
44 button_t* butStatusBar;
45 button_t* butAllLayers;
46 button_t* butHoverText;
47 button_t* butViewSprites;
48 button_t* butGrid;
49 button_t* but3DMode;
50 button_t* butMap;
51 button_t* butAttributes;
52 button_t* butClearMap;
53 button_t* butHelp;
54 button_t* butAbout;
55 button_t* butEditorControls;
56 button_t* butMonsterHelm;
57 button_t* butMonsterWeapon;
58 button_t* butMonsterShield;
59 button_t* butMonsterArmor;
60 button_t* butMonsterRing;
61 button_t* butMonsterAmulet;
62 button_t* butMonsterBoots;
63 button_t* butMonsterGloves;
64 button_t* butMonsterItem1;
65 button_t* butMonsterItem2;
66 button_t* butMonsterItem3;
67 button_t* butMonsterItem4;
68 button_t* butMonsterItem5;
69 button_t* butMonsterItem6;
70 button_t* butMonsterCloak;
71 button_t* butMonsterMask;
72 button_t* butMonsterOK;
73 button_t* butMonsterX;
74 button_t* butMonsterCancel;
75 button_t* butMonsterItemOK;
76 button_t* butMonsterItemX;
77 button_t* butMonsterItemCancel;
78 button_t* butItemOK;
79 button_t* butItemCancel;
80 button_t* butItemX;
81 
82 bool exitFromItemWindow = false;
83 
updateMapNames()84 static void updateMapNames()
85 {
86 	DIR* dir;
87 	struct dirent* ent;
88 	mapNames.clear();
89 	// file list
90 	std::string path;
91 	if ( savewindow > 0 )
92 	{
93 		path = physfs_saveDirectory + "maps/";
94 	}
95 	else
96 	{
97 		path = physfs_openDirectory + "maps/";
98 	}
99 	if ( (dir = openDataDir(path.c_str())) != NULL )
100 	{
101 		while ( (ent = readdir(dir)) != NULL )
102 		{
103 			if ( strstr(ent->d_name, ".lmp") != NULL || (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, ".")) )
104 			{
105 				mapNames.push_back(ent->d_name);
106 			}
107 		}
108 		closedir(dir);
109 	}
110 	else
111 	{
112 		// could not open directory
113 		printlog("failed to open map directory for viewing!\n");
114 		return;
115 	}
116 	std::sort(mapNames.begin(), mapNames.end());
117 }
118 
updateModFolderNames()119 static void updateModFolderNames()
120 {
121 	modFolderNames.clear();
122 	std::string path = outputdir;
123 	path.append(PHYSFS_getDirSeparator()).append("mods/");
124 	modFolderNames = directoryContents(path.c_str(), true, false);
125 	if ( !modFolderNames.empty() )
126 	{
127 		std::list<std::string>::iterator it = std::find(modFolderNames.begin(), modFolderNames.end(), "..");
128 		modFolderNames.erase(it);
129 		std::sort(mapNames.begin(), mapNames.end());
130 	}
131 }
132 
writeLevelsTxt(std::string modFolder)133 void writeLevelsTxt(std::string modFolder)
134 {
135 	std::string path = outputdir;
136 	path.append(PHYSFS_getDirSeparator()).append("mods/").append(modFolder);
137 	if ( access(path.c_str(), F_OK) == 0 )
138 	{
139 		std::string writeFile = modFolder + "/maps/levels.txt";
140 		PHYSFS_File *physfp = PHYSFS_openWrite(writeFile.c_str());
141 		if ( physfp != NULL )
142 		{
143 			PHYSFS_writeBytes(physfp, "map: start\n", 11);
144 			PHYSFS_writeBytes(physfp, "gen: mine\n", 10);
145 			PHYSFS_writeBytes(physfp, "gen: mine\n", 10);
146 			PHYSFS_writeBytes(physfp, "gen: mine\n", 10);
147 			PHYSFS_writeBytes(physfp, "gen: mine\n", 10);
148 			PHYSFS_writeBytes(physfp, "map: minetoswamp\n", 17);
149 			PHYSFS_writeBytes(physfp, "gen: swamp\n", 11);
150 			PHYSFS_writeBytes(physfp, "gen: swamp\n", 11);
151 			PHYSFS_writeBytes(physfp, "gen: swamp\n", 11);
152 			PHYSFS_writeBytes(physfp, "gen: swamp\n", 11);
153 			PHYSFS_writeBytes(physfp, "map: swamptolabyrinth\n", 22);
154 			PHYSFS_writeBytes(physfp, "gen: labyrinth\n", 15);
155 			PHYSFS_writeBytes(physfp, "gen: labyrinth\n", 15);
156 			PHYSFS_writeBytes(physfp, "gen: labyrinth\n", 15);
157 			PHYSFS_writeBytes(physfp, "gen: labyrinth\n", 15);
158 			PHYSFS_writeBytes(physfp, "map: labyrinthtoruins\n", 22);
159 			PHYSFS_writeBytes(physfp, "gen: ruins\n", 11);
160 			PHYSFS_writeBytes(physfp, "gen: ruins\n", 11);
161 			PHYSFS_writeBytes(physfp, "gen: ruins\n", 11);
162 			PHYSFS_writeBytes(physfp, "gen: ruins\n", 11);
163 			PHYSFS_writeBytes(physfp, "map: boss\n", 10);
164 			PHYSFS_writeBytes(physfp, "gen: hell\n", 10);
165 			PHYSFS_writeBytes(physfp, "gen: hell\n", 10);
166 			PHYSFS_writeBytes(physfp, "gen: hell\n", 10);
167 			PHYSFS_writeBytes(physfp, "map: hellboss\n", 14);
168 			PHYSFS_writeBytes(physfp, "map: hamlet\n", 12);
169 			PHYSFS_writeBytes(physfp, "gen: caves\n", 11);
170 			PHYSFS_writeBytes(physfp, "gen: caves\n", 11);
171 			PHYSFS_writeBytes(physfp, "gen: caves\n", 11);
172 			PHYSFS_writeBytes(physfp, "gen: caves\n", 11);
173 			PHYSFS_writeBytes(physfp, "map: cavestocitadel\n", 20);
174 			PHYSFS_writeBytes(physfp, "gen: citadel\n", 13);
175 			PHYSFS_writeBytes(physfp, "gen: citadel\n", 13);
176 			PHYSFS_writeBytes(physfp, "gen: citadel\n", 13);
177 			PHYSFS_writeBytes(physfp, "gen: citadel\n", 13);
178 			PHYSFS_writeBytes(physfp, "map: sanctum", 12);
179 			PHYSFS_close(physfp);
180 		}
181 		else
182 		{
183 			printlog("[PhysFS]: Failed to open %s/maps/levels.txt for writing.", path.c_str());
184 		}
185 	}
186 	else
187 	{
188 		printlog("[PhysFS]: Failed to write levels.txt in %s", path.c_str());
189 	}
190 }
191 
192 // Corner buttons
193 
buttonExit(button_t * my)194 void buttonExit(button_t* my)
195 {
196 	button_t* button;
197 
198 	// this shouldn't work if a window is already open
199 	if ( subwindow )
200 	{
201 		return;
202 	}
203 
204 	menuVisible = 0;
205 	subwindow = 1;
206 	subx1 = xres / 2 - 128;
207 	subx2 = xres / 2 + 128;
208 	suby1 = yres / 2 - 32;
209 	suby2 = yres / 2 + 32;
210 	strcpy(subtext, "Are you sure you want to quit?\nAny unsaved work will be lost.");
211 
212 	button = newButton();
213 	strcpy(button->label, "Yes");
214 	button->x = subx1 + 32;
215 	button->y = suby2 - 24;
216 	button->sizex = 32;
217 	button->sizey = 16;
218 	button->action = &buttonExitConfirm;
219 	button->visible = 1;
220 	button->focused = 1;
221 
222 	button = newButton();
223 	strcpy(button->label, "No");
224 	button->x = subx2 - 56;
225 	button->y = suby2 - 24;
226 	button->sizex = 24;
227 	button->sizey = 16;
228 	button->action = &buttonCloseSubwindow;
229 	button->visible = 1;
230 	button->focused = 1;
231 }
232 
buttonExitConfirm(button_t * my)233 void buttonExitConfirm(button_t* my)
234 {
235 	mainloop = 0; // gracefully stops the game/editor
236 }
237 
buttonIconify(button_t * my)238 void buttonIconify(button_t* my)
239 {
240 	// aka minimize
241 	SDL_MinimizeWindow(screen);
242 }
243 
244 // Toolbox buttons
245 
buttonTilePalette(button_t * my)246 void buttonTilePalette(button_t* my)
247 {
248 	tilepalette = 1;
249 }
250 
buttonSprite(button_t * my)251 void buttonSprite(button_t* my)
252 {
253 	makeUndo();
254 	spritepalette = 1;
255 }
256 
buttonPencil(button_t * my)257 void buttonPencil(button_t* my)
258 {
259 	selectedTool = 0;
260 	selectedarea = false;
261 }
262 
buttonPoint(button_t * my)263 void buttonPoint(button_t* my)
264 {
265 	selectedTool = 1;
266 	selectedarea = false;
267 }
268 
buttonBrush(button_t * my)269 void buttonBrush(button_t* my)
270 {
271 	selectedTool = 2;
272 	selectedarea = false;
273 }
274 
buttonSelect(button_t * my)275 void buttonSelect(button_t* my)
276 {
277 	selectedTool = 3;
278 	selectedarea = false;
279 }
280 
buttonFill(button_t * my)281 void buttonFill(button_t* my)
282 {
283 	selectedTool = 4;
284 	selectedarea = false;
285 }
286 
287 // File menu
288 
buttonFile(button_t * my)289 void buttonFile(button_t* my)
290 {
291 	if ( menuVisible != 1 )
292 	{
293 		menuVisible = 1;
294 	}
295 	else
296 	{
297 		menuVisible = 0;
298 	}
299 }
300 
buttonNew(button_t * my)301 void buttonNew(button_t* my)
302 {
303 	button_t* button;
304 
305 	editproperty = 0;
306 	inputstr = map.name;
307 	snprintf(widthtext, 4, "%d", map.width);
308 	snprintf(heighttext, 4, "%d", map.height);
309 	strcpy(nametext, map.name);
310 	strcpy(authortext, map.author);
311 	snprintf(skyboxtext, 4, "%d", map.skybox);
312 	for ( int z = 0; z < MAPFLAGS; ++z )
313 	{
314 		snprintf(mapflagtext[z], 4, "%d", map.flags[z]);
315 	}
316 	if ( map.flags[MAP_FLAG_DISABLETRAPS] > 0 )
317 	{
318 		strcpy(mapflagtext[MAP_FLAG_DISABLETRAPS], "[x]");
319 	}
320 	else
321 	{
322 		strcpy(mapflagtext[MAP_FLAG_DISABLETRAPS], "[ ]");
323 	}
324 	if ( map.flags[MAP_FLAG_DISABLEMONSTERS] > 0 )
325 	{
326 		strcpy(mapflagtext[MAP_FLAG_DISABLEMONSTERS], "[x]");
327 	}
328 	else
329 	{
330 		strcpy(mapflagtext[MAP_FLAG_DISABLEMONSTERS], "[ ]");
331 	}
332 	if ( map.flags[MAP_FLAG_DISABLELOOT] > 0 )
333 	{
334 		strcpy(mapflagtext[MAP_FLAG_DISABLELOOT], "[x]");
335 	}
336 	else
337 	{
338 		strcpy(mapflagtext[MAP_FLAG_DISABLELOOT], "[ ]");
339 	}
340 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 24) & static_cast<int>(0xFF) )
341 	{
342 		strcpy(mapflagtext[MAP_FLAG_DISABLEDIGGING], "[x]");
343 	}
344 	else
345 	{
346 		strcpy(mapflagtext[MAP_FLAG_DISABLEDIGGING], "[ ]");
347 	}
348 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 16) & static_cast<int>(0xFF) )
349 	{
350 		strcpy(mapflagtext[MAP_FLAG_DISABLETELEPORT], "[x]");
351 	}
352 	else
353 	{
354 		strcpy(mapflagtext[MAP_FLAG_DISABLETELEPORT], "[ ]");
355 	}
356 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 8) & static_cast<int>(0xFF) )
357 	{
358 		strcpy(mapflagtext[MAP_FLAG_DISABLELEVITATION], "[x]");
359 	}
360 	else
361 	{
362 		strcpy(mapflagtext[MAP_FLAG_DISABLELEVITATION], "[ ]");
363 	}
364 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 0) & static_cast<int>(0xFF) )
365 	{
366 		strcpy(mapflagtext[MAP_FLAG_GENADJACENTROOMS], "[x]");
367 	}
368 	else
369 	{
370 		strcpy(mapflagtext[MAP_FLAG_GENADJACENTROOMS], "[ ]");
371 	}
372 	if ( (map.flags[MAP_FLAG_GENBYTES4] >> 24) & static_cast<int>(0xFF) )
373 	{
374 		strcpy(mapflagtext[MAP_FLAG_DISABLEOPENING], "[x]");
375 	}
376 	else
377 	{
378 		strcpy(mapflagtext[MAP_FLAG_DISABLEOPENING], "[ ]");
379 	}
380 	if ( (map.flags[MAP_FLAG_GENBYTES4] >> 16) & static_cast<int>(0xFF) )
381 	{
382 		strcpy(mapflagtext[MAP_FLAG_DISABLEMESSAGES], "[x]");
383 	}
384 	else
385 	{
386 		strcpy(mapflagtext[MAP_FLAG_DISABLEMESSAGES], "[ ]");
387 	}
388 	if ( (map.flags[MAP_FLAG_GENBYTES4] >> 8) & static_cast<int>(0xFF) )
389 	{
390 		strcpy(mapflagtext[MAP_FLAG_DISABLEHUNGER], "[x]");
391 	}
392 	else
393 	{
394 		strcpy(mapflagtext[MAP_FLAG_DISABLEHUNGER], "[ ]");
395 	}
396 	cursorflash = ticks;
397 	menuVisible = 0;
398 	subwindow = 1;
399 	newwindow = 1;
400 	subx1 = xres / 2 - 200;
401 	subx2 = xres / 2 + 200;
402 	suby1 = yres / 2 - 200;
403 	suby2 = yres / 2 + 200;
404 	strcpy(subtext, "New map:");
405 
406 	button = newButton();
407 	strcpy(button->label, "Create");
408 	button->x = subx2 - 64;
409 	button->y = suby2 - 48;
410 	button->sizex = 56;
411 	button->sizey = 16;
412 	button->action = &buttonNewConfirm;
413 	button->visible = 1;
414 	button->focused = 1;
415 
416 	button = newButton();
417 	strcpy(button->label, "Cancel");
418 	button->x = subx2 - 64;
419 	button->y = suby2 - 24;
420 	button->sizex = 56;
421 	button->sizey = 16;
422 	button->action = &buttonCloseSubwindow;
423 	button->visible = 1;
424 	button->focused = 1;
425 
426 	button = newButton();
427 	strcpy(button->label, "X");
428 	button->x = subx2 - 16;
429 	button->y = suby1;
430 	button->sizex = 16;
431 	button->sizey = 16;
432 	button->action = &buttonCloseSubwindow;
433 	button->visible = 1;
434 	button->focused = 1;
435 }
436 
buttonNewConfirm(button_t * my)437 void buttonNewConfirm(button_t* my)
438 {
439 	int x, y, z, c;
440 	clearUndos();
441 	free(map.tiles);
442 	list_FreeAll(map.entities);
443 	strcpy(map.name, nametext);
444 	strcpy(map.author, authortext);
445 	map.skybox = atoi(skyboxtext);
446 	for ( z = 0; z < MAPFLAGS; ++z )
447 	{
448 		if ( z == MAP_FLAG_DISABLETRAPS )
449 		{
450 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLETRAPS], "[x]", 3) )
451 			{
452 				map.flags[MAP_FLAG_DISABLETRAPS] = 1;
453 			}
454 			else
455 			{
456 				map.flags[MAP_FLAG_DISABLETRAPS] = 0;
457 			}
458 		}
459 		else if ( z == MAP_FLAG_DISABLEMONSTERS )
460 		{
461 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEMONSTERS], "[x]", 3) )
462 			{
463 				map.flags[MAP_FLAG_DISABLEMONSTERS] = 1;
464 			}
465 			else
466 			{
467 				map.flags[MAP_FLAG_DISABLEMONSTERS] = 0;
468 			}
469 		}
470 		else if ( z == MAP_FLAG_DISABLELOOT )
471 		{
472 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLELOOT], "[x]", 3) )
473 			{
474 				map.flags[MAP_FLAG_DISABLELOOT] = 1;
475 			}
476 			else
477 			{
478 				map.flags[MAP_FLAG_DISABLELOOT] = 0;
479 			}
480 		}
481 		else if ( z == MAP_FLAG_GENBYTES3 )
482 		{
483 			map.flags[z] = 0;
484 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEDIGGING], "[x]", 3) )
485 			{
486 				map.flags[z] |= (1 << 24) & 0xFF;
487 			}
488 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLETELEPORT], "[x]", 3) )
489 			{
490 				map.flags[z] |= (1 << 16) & 0xFF;
491 			}
492 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLELEVITATION], "[x]", 3) )
493 			{
494 				map.flags[z] |= (1 << 8) & 0xFF;
495 			}
496 			if ( !strncmp(mapflagtext[MAP_FLAG_GENADJACENTROOMS], "[x]", 3) )
497 			{
498 				map.flags[z] |= (1 << 0) & 0xFF;
499 			}
500 		}
501 		else if ( z == MAP_FLAG_GENBYTES4 )
502 		{
503 			map.flags[z] = 0;
504 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEOPENING], "[x]", 3) )
505 			{
506 				map.flags[z] |= (1 << 24) & 0xFF;
507 			}
508 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEMESSAGES], "[x]", 3) )
509 			{
510 				map.flags[z] |= (1 << 16) & 0xFF;
511 			}
512 			if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEHUNGER], "[x]", 3) )
513 			{
514 				map.flags[z] |= (1 << 8) & 0xFF;
515 			}
516 		}
517 		else
518 		{
519 			map.flags[z] = atoi(mapflagtext[z]);
520 		}
521 	}
522 	map.width = atoi(widthtext);
523 	map.height = atoi(heighttext);
524 	map.width = std::min(std::max(MINWIDTH, map.width), MAXWIDTH);
525 	map.height = std::min(std::max(MINHEIGHT, map.height), MAXHEIGHT);
526 	map.tiles = (int*) malloc(sizeof(int) * MAPLAYERS * map.height * map.width);
527 	for ( z = 0; z < MAPLAYERS; z++ )
528 	{
529 		for ( y = 0; y < map.height; y++ )
530 		{
531 			for ( x = 0; x < map.width; x++ )
532 			{
533 				if ( z == OBSTACLELAYER )
534 				{
535 					if (x == 0 || y == 0 || x == map.width - 1 || y == map.height - 1)
536 					{
537 						map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = 2;
538 					}
539 					else
540 					{
541 						map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = 0;
542 					}
543 				}
544 				else
545 				{
546 					map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = 1;
547 				}
548 			}
549 		}
550 	}
551 	if ( vismap != NULL )
552 	{
553 		free(vismap);
554 	}
555 	vismap = (bool*) malloc(sizeof(bool) * map.width * map.height);
556 	if ( lightmap != NULL )
557 	{
558 		free(lightmap);
559 	}
560 	if ( lightmapSmoothed != NULL )
561 	{
562 		free(lightmapSmoothed);
563 	}
564 	lightmap = (int*) malloc(sizeof(Sint32) * map.width * map.height);
565 	lightmapSmoothed = (int*)malloc(sizeof(Sint32) * map.width * map.height);
566 	for (c = 0; c < map.width * map.height; c++ )
567 	{
568 		lightmap[c] = 0;
569 		lightmapSmoothed[c] = 0;
570 	}
571 	strcpy(message, "                             Created a new map.");
572 	filename[0] = 0;
573 	oldfilename[0] = 0;
574 	messagetime = 60;
575 	buttonCloseSubwindow(my);
576 }
577 
buttonOpen(button_t * my)578 void buttonOpen(button_t* my)
579 {
580 	button_t* button;
581 	DIR* dir = NULL;
582 	struct dirent* ent = NULL;
583 	unsigned long c = 0;
584 
585 	inputstr = filename;
586 	cursorflash = ticks;
587 	menuVisible = 0;
588 	subwindow = 1;
589 	openwindow = 1;
590 	slidery = 0;
591 	selectedFile = 0;
592 	subx1 = xres / 2 - 160;
593 	subx2 = xres / 2 + 160;
594 	suby1 = yres / 2 - 120;
595 	suby2 = yres / 2 + 120;
596 	strcpy(subtext, "Open file:");
597 
598 	button = newButton();
599 	strcpy(button->label, " Open ");
600 	button->x = subx2 - 64;
601 	button->y = suby2 - 48;
602 	button->sizex = 56;
603 	button->sizey = 16;
604 	button->action = &buttonOpenConfirm;
605 	button->visible = 1;
606 	button->focused = 1;
607 
608 	button = newButton();
609 	strcpy(button->label, "Cancel");
610 	button->x = subx2 - 64;
611 	button->y = suby2 - 24;
612 	button->sizex = 56;
613 	button->sizey = 16;
614 	button->action = &buttonCloseSubwindow;
615 	button->visible = 1;
616 	button->focused = 1;
617 
618 	button = newButton();
619 	strcpy(button->label, "X");
620 	button->x = subx2 - 16;
621 	button->y = suby1;
622 	button->sizex = 16;
623 	button->sizey = 16;
624 	button->action = &buttonCloseSubwindow;
625 	button->visible = 1;
626 	button->focused = 1;
627 
628 	updateMapNames();
629 }
630 
buttonSetSaveDirectoryFolder(button_t * my)631 void buttonSetSaveDirectoryFolder(button_t* my)
632 {
633 	std::string filepath = outputdir;
634 	bool inModFolder = false;
635 	if ( strcmp(foldername, ".") == 0 || strcmp(foldername, "") == 0 )
636 	{
637 		physfs_saveDirectory = BASE_DATA_DIR;
638 	}
639 	else if ( strcmp(foldername, BASE_DATA_DIR) )
640 	{
641 		filepath.append(PHYSFS_getDirSeparator()).append("mods/").append(foldername);
642 		physfs_saveDirectory = filepath + PHYSFS_getDirSeparator();
643 		inModFolder = true;
644 	}
645 	else
646 	{
647 		physfs_saveDirectory = BASE_DATA_DIR;
648 	}
649 	if ( access(physfs_saveDirectory.c_str(), F_OK) == 0 )
650 	{
651 		printlog("[PhysFS]: Changed save directory folder to %s", physfs_saveDirectory.c_str());
652 	}
653 	else if ( inModFolder )
654 	{
655 		printlog("[PhysFS]: Directory %s does not exist. Creating new mod folder...", physfs_saveDirectory.c_str());
656 
657 		if ( PHYSFS_mkdir(foldername) )
658 		{
659 			std::string dir = foldername;
660 			std::string folder = "/books";
661 			PHYSFS_mkdir((dir + folder).c_str());
662 			folder = "/editor";
663 			PHYSFS_mkdir((dir + folder).c_str());
664 
665 			folder = "/images";
666 			PHYSFS_mkdir((dir + folder).c_str());
667 			std::string subfolder = "/sprites";
668 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
669 			subfolder = "/system";
670 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
671 			subfolder = "/tiles";
672 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
673 
674 			folder = "/items";
675 			PHYSFS_mkdir((dir + folder).c_str());
676 			subfolder = "/images";
677 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
678 
679 			folder = "/lang";
680 			PHYSFS_mkdir((dir + folder).c_str());
681 			folder = "/maps";
682 			PHYSFS_mkdir((dir + folder).c_str());
683 			writeLevelsTxt(foldername);
684 
685 			folder = "/models";
686 			PHYSFS_mkdir((dir + folder).c_str());
687 			subfolder = "/creatures";
688 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
689 			subfolder = "/decorations";
690 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
691 			subfolder = "/doors";
692 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
693 			subfolder = "/items";
694 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
695 			subfolder = "/particles";
696 			PHYSFS_mkdir((dir + folder + subfolder).c_str());
697 
698 			folder = "/music";
699 			PHYSFS_mkdir((dir + folder).c_str());
700 			folder = "/sound";
701 			PHYSFS_mkdir((dir + folder).c_str());
702 			printlog("[PhysFS]: New folder %s created.", physfs_saveDirectory.c_str());
703 			strcpy(message, "                      Created a new mod folder.");
704 			messagetime = 60;
705 		}
706 		else
707 		{
708 			physfs_saveDirectory = BASE_DATA_DIR;
709 			printlog("[PhysFS]: Unable to create mods/ folder %s.", physfs_saveDirectory.c_str());
710 		}
711 	}
712 	updateModFolderNames();
713 }
714 
buttonSetOpenDirectoryFolder(button_t * my)715 void buttonSetOpenDirectoryFolder(button_t* my)
716 {
717 	if ( PHYSFS_unmount(physfs_openDirectory.c_str()) )
718 	{
719 		std::string filepath = outputdir;
720 		if ( strcmp(foldername, ".") == 0 || strcmp(foldername, "") == 0 )
721 		{
722 			physfs_openDirectory = BASE_DATA_DIR;
723 		}
724 		else if ( strcmp(foldername, BASE_DATA_DIR) )
725 		{
726 			filepath.append(PHYSFS_getDirSeparator()).append("mods/").append(foldername);
727 			physfs_openDirectory = filepath + PHYSFS_getDirSeparator();
728 		}
729 		else
730 		{
731 			physfs_openDirectory = BASE_DATA_DIR;
732 		}
733 		if ( PHYSFS_mount(physfs_openDirectory.c_str(), NULL, 1) )
734 		{
735 			printlog("[PhysFS]: Changed open directory folder to %s", physfs_openDirectory.c_str());
736 		}
737 		else
738 		{
739 			printlog("[PhysFS]: Failed to change open directory folder to %s", physfs_openDirectory.c_str());
740 			physfs_openDirectory = BASE_DATA_DIR;
741 			PHYSFS_mount(BASE_DATA_DIR, NULL, 1);
742 		}
743 	}
744 	else
745 	{
746 		printlog("[PhysFS]: Failed to change open directory folder.");
747 	}
748 	updateModFolderNames();
749 }
750 
buttonPHYSFSDirDefault(button_t * my)751 void buttonPHYSFSDirDefault(button_t* my)
752 {
753 	strcpy(foldername, BASE_DATA_DIR);
754 	buttonSetSaveDirectoryFolder(nullptr);
755 	buttonSetOpenDirectoryFolder(nullptr);
756 }
757 
buttonOpenDirectory(button_t * my)758 void buttonOpenDirectory(button_t* my)
759 {
760 	button_t* button;
761 
762 	inputstr = foldername;
763 	cursorflash = ticks;
764 	menuVisible = 0;
765 	subwindow = 1;
766 	openwindow = 2;
767 	slidery = 0;
768 	selectedFile = 0;
769 	subx1 = xres / 2 - 160;
770 	subx2 = xres / 2 + 160;
771 	suby1 = yres / 2 - 150;
772 	suby2 = yres / 2 + 150;
773 	strcpy(subtext, "Choose mod folders to read/write maps:");
774 
775 	button = newButton();
776 	strcpy(button->label, "Set as save directory");
777 	button->x = subx2 - 16 - strlen(button->label) * TTF12_WIDTH;
778 	button->y = suby2 - 90;
779 	button->sizex = strlen(button->label) * TTF12_WIDTH + 8;
780 	button->sizey = 16;
781 	button->action = &buttonSetSaveDirectoryFolder;
782 	button->visible = 1;
783 	button->focused = 1;
784 
785 	button = newButton();
786 	strcpy(button->label, "Reset to default");
787 	button->x = subx2 - 16 - strlen(button->label) * TTF12_WIDTH;
788 	button->y = suby2 - 54;
789 	button->sizex = strlen(button->label) * TTF12_WIDTH + 8;
790 	button->sizey = 16;
791 	button->action = &buttonPHYSFSDirDefault;
792 	button->visible = 1;
793 	button->focused = 1;
794 
795 	button = newButton();
796 	strcpy(button->label, "Set as load directory");
797 	button->x = subx2 - 16 - strlen(button->label) * TTF12_WIDTH;
798 	button->y = suby2 - 72;
799 	button->sizex = strlen(button->label) * TTF12_WIDTH + 8;
800 	button->sizey = 16;
801 	button->action = &buttonSetOpenDirectoryFolder;
802 	button->visible = 1;
803 	button->focused = 1;
804 
805 	button = newButton();
806 	strcpy(button->label, "X");
807 	button->x = subx2 - 16;
808 	button->y = suby1;
809 	button->sizex = 16;
810 	button->sizey = 16;
811 	button->action = &buttonCloseSubwindow;
812 	button->visible = 1;
813 	button->focused = 1;
814 
815 	updateModFolderNames();
816 }
817 
buttonOpenConfirm(button_t * my)818 void buttonOpenConfirm(button_t* my)
819 {
820 	int c, c2;
821 	clearUndos();
822 	strcpy(oldfilename, filename);
823 	strcpy(message, "");
824 	for ( c = 0; c < 32; c++ )
825 	{
826 		if (filename[c] == 0)
827 		{
828 			break;
829 		}
830 	}
831 	/*for ( c2 = 0; c2 < 32 - c; c2++ )
832 	{
833 		strcat(message, " ");
834 	}*/
835 	std::string fullMapName = physfsFormatMapName(filename);
836 	printlog("opening map file '%s'...\n", fullMapName.c_str());
837 	if (loadMap(fullMapName.c_str(), &map, map.entities, map.creatures) == -1)
838 	{
839 		strcat(message, "Failed to open ");
840 		strcat(message, filename);
841 	}
842 	else
843 	{
844 		strcat(message, "Opened '");
845 		strcat(message, filename);
846 		strcat(message, "'");
847 	}
848 	messagetime = 60; // 60*50 ms = 3000 ms (3 seconds)
849 	buttonCloseSubwindow(my);
850 }
851 
buttonSave(button_t * my)852 void buttonSave(button_t* my)
853 {
854 	int c, c2;
855 	menuVisible = 0;
856 	strcpy(oldfilename, filename);
857 	inputstr = filename;
858 	if (filename[0] == 0)
859 	{
860 		buttonSaveAs(my);
861 	}
862 	else
863 	{
864 		strcpy(message, "");
865 		for ( c = 0; c < 32; c++ )
866 		{
867 			if (filename[c] == 0)
868 			{
869 				break;
870 			}
871 		}
872 		/*for ( c2 = 0; c2 < 32 - c; c2++ )
873 		{
874 			strcat(message, " ");
875 		}*/
876 		printlog("saving map file '%s'...\n", filename);
877 
878 		std::string path = physfs_saveDirectory;
879 		path.append("maps/").append(filename);
880 		if (saveMap(path.c_str()))
881 		{
882 			strcat(message, "Failed to save ");
883 			strcat(message, path.c_str());
884 		}
885 		else
886 		{
887 			strcat(message, "Saved '");
888 			strcat(message, path.c_str());
889 			strcat(message, "'");
890 		}
891 		messagetime = 60; // 60*50 ms = 3000 ms (3 seconds)
892 		buttonCloseSubwindow(my);
893 	}
894 }
895 
buttonSaveAs(button_t * my)896 void buttonSaveAs(button_t* my)
897 {
898 	button_t* button;
899 
900 	cursorflash = ticks;
901 	menuVisible = 0;
902 	subwindow = 1;
903 	savewindow = 1;
904 	slidery = 0;
905 	selectedFile = 0;
906 	subx1 = xres / 2 - 160;
907 	subx2 = xres / 2 + 160;
908 	suby1 = yres / 2 - 120;
909 	suby2 = yres / 2 + 120;
910 	strcpy(subtext, "Save file:");
911 
912 	button = newButton();
913 	strcpy(button->label, " Save ");
914 	button->x = subx2 - 64;
915 	button->y = suby2 - 48;
916 	button->sizex = 56;
917 	button->sizey = 16;
918 	button->action = &buttonSave;
919 	button->visible = 1;
920 	button->focused = 1;
921 
922 	button = newButton();
923 	strcpy(button->label, "Cancel");
924 	button->x = subx2 - 64;
925 	button->y = suby2 - 24;
926 	button->sizex = 56;
927 	button->sizey = 16;
928 	button->action = &buttonCloseSubwindow;
929 	button->visible = 1;
930 	button->focused = 1;
931 
932 	button = newButton();
933 	strcpy(button->label, "X");
934 	button->x = subx2 - 16;
935 	button->y = suby1;
936 	button->sizex = 16;
937 	button->sizey = 16;
938 	button->action = &buttonCloseSubwindow;
939 	button->visible = 1;
940 	button->focused = 1;
941 
942 	updateMapNames();
943 }
944 
945 // Edit menu
946 
buttonEdit(button_t * my)947 void buttonEdit(button_t* my)
948 {
949 	if ( menuVisible != 2 )
950 	{
951 		menuVisible = 2;
952 	}
953 	else
954 	{
955 		menuVisible = 0;
956 	}
957 }
958 
buttonCut(button_t * my)959 void buttonCut(button_t* my)
960 {
961 	menuVisible = 0;
962 	if ( !selectedarea )
963 	{
964 		return;
965 	}
966 	buttonCopy(my);
967 	selectedarea = true;
968 	buttonDelete(my);
969 }
970 
buttonCopy(button_t * my)971 void buttonCopy(button_t* my)
972 {
973 	menuVisible = 0;
974 	int x, y;
975 
976 	// copy the selected tiles
977 	if (selectedarea && !pasting)
978 	{
979 		copymap.width = selectedarea_x2 - selectedarea_x1 + 1;
980 		copymap.height = selectedarea_y2 - selectedarea_y1 + 1;
981 		if ( copymap.tiles != NULL )
982 		{
983 			free(copymap.tiles);
984 		}
985 		copymap.tiles = (Sint32*) malloc(sizeof(Sint32) * copymap.width * copymap.height * MAPLAYERS);
986 		memset(copymap.tiles, 0, sizeof(Sint32)*copymap.width * copymap.height * MAPLAYERS);
987 		for ( x = 0; x < copymap.width; x++ )
988 		{
989 			for ( y = 0; y < copymap.height; y++ )
990 			{
991 				copymap.tiles[drawlayer + y * MAPLAYERS + x * MAPLAYERS * copymap.height] = map.tiles[drawlayer + (y + selectedarea_y1) * MAPLAYERS + (x + selectedarea_x1) * MAPLAYERS * map.height];
992 			}
993 		}
994 		copymap.name[0] = drawlayer;
995 	}
996 	selectedarea = false;
997 }
998 
buttonPaste(button_t * my)999 void buttonPaste(button_t* my)
1000 {
1001 	menuVisible = 0;
1002 
1003 	// paste the selected tiles
1004 	if ( copymap.tiles != NULL )
1005 	{
1006 		pasting = true;
1007 		selectedarea = false;
1008 	}
1009 }
1010 
buttonDelete(button_t * my)1011 void buttonDelete(button_t* my)
1012 {
1013 	menuVisible = 0;
1014 	makeUndo();
1015 
1016 	// delete the selected entity, if there is one
1017 	if (selectedEntity != NULL)
1018 	{
1019 		list_RemoveNode(selectedEntity->mynode);
1020 		selectedEntity = NULL;
1021 		lastSelectedEntity = NULL;
1022 	}
1023 	if (selectedarea)
1024 	{
1025 		// delete all selected tiles
1026 		int x, y;
1027 		for ( x = selectedarea_x1; x <= selectedarea_x2; x++ )
1028 		{
1029 			for ( y = selectedarea_y1; y <= selectedarea_y2; y++ )
1030 			{
1031 				map.tiles[drawlayer + y * MAPLAYERS + x * MAPLAYERS * map.height] = 0;
1032 			}
1033 		}
1034 		selectedarea = false;
1035 	}
1036 }
1037 
buttonCycleSprites(button_t * my)1038 void buttonCycleSprites(button_t* my)
1039 {
1040 	SDL_Rect pos;
1041 	char tmp[4];
1042 	Entity* entity = nullptr;
1043 	Entity* lastEntity = nullptr;
1044 	bool entityWasSelected = false;
1045 	for ( node_t* node = map.entities->first; node != nullptr; node = node->next )
1046 	{
1047 		entity = (Entity*)node->element;
1048 		pos.x = entity->x * (TEXTURESIZE / 16) - camx;
1049 		pos.y = entity->y * (TEXTURESIZE / 16) - camy;
1050 		if ( (omousex / TEXTURESIZE) * 32 == pos.x && (omousey / TEXTURESIZE) * 32 == pos.y )
1051 		{
1052 			// set lastEntity to each entity on the tile.
1053 			lastEntity = entity;
1054 		}
1055 	}
1056 
1057 	if ( lastEntity != nullptr )
1058 	{
1059 		if ( selectedEntity )
1060 		{
1061 			entityWasSelected = true;
1062 		}
1063 
1064 		selectedEntity = nullptr;
1065 		lastSelectedEntity = nullptr;
1066 
1067 		// create new entity on the list, copying and removing the previous last one.
1068 		entity = newEntity(lastEntity->sprite, 0, map.entities, nullptr);
1069 		setSpriteAttributes(entity, lastEntity, lastEntity);
1070 		list_RemoveNode(lastEntity->mynode);
1071 
1072 		if ( entityWasSelected )
1073 		{
1074 			selectedEntity = entity;
1075 			lastSelectedEntity = selectedEntity;
1076 		}
1077 	}
1078 }
1079 
buttonSelectAll(button_t * my)1080 void buttonSelectAll(button_t* my)
1081 {
1082 	menuVisible = 0;
1083 	selectedTool = 3;
1084 	selectedarea = true;
1085 	selectingspace = false;
1086 	selectedarea_x1 = 0;
1087 	selectedarea_x2 = map.width - 1;
1088 	selectedarea_y1 = 0;
1089 	selectedarea_y2 = map.height - 1;
1090 }
1091 
buttonUndo(button_t * my)1092 void buttonUndo(button_t* my)
1093 {
1094 	menuVisible = 0;
1095 	undo();
1096 }
1097 
buttonRedo(button_t * my)1098 void buttonRedo(button_t* my)
1099 {
1100 	menuVisible = 0;
1101 	redo();
1102 }
1103 
1104 // View menu
1105 
buttonView(button_t * my)1106 void buttonView(button_t* my)
1107 {
1108 	if ( menuVisible != 3 )
1109 	{
1110 		menuVisible = 3;
1111 	}
1112 	else
1113 	{
1114 		menuVisible = 0;
1115 	}
1116 }
1117 
buttonToolbox(button_t * my)1118 void buttonToolbox(button_t* my)
1119 {
1120 	toolbox = (toolbox == 0);
1121 	butTilePalette->visible = (butTilePalette->visible == 0);
1122 	butPencil->visible = (butPencil->visible == 0);
1123 	butSprite->visible = (butSprite->visible == 0);
1124 	butPoint->visible = (butPoint->visible == 0);
1125 	butBrush->visible = (butBrush->visible == 0);
1126 	butSelect->visible = (butSelect->visible == 0);
1127 	butFill->visible = (butFill->visible == 0);
1128 }
1129 
buttonStatusBar(button_t * my)1130 void buttonStatusBar(button_t* my)
1131 {
1132 	statusbar = (statusbar == 0);
1133 }
1134 
buttonAllLayers(button_t * my)1135 void buttonAllLayers(button_t* my)
1136 {
1137 	alllayers = (alllayers == 0);
1138 }
1139 
buttonViewSprites(button_t * my)1140 void buttonViewSprites(button_t* my)
1141 {
1142 	viewsprites = (viewsprites == 0);
1143 }
1144 
buttonGrid(button_t * my)1145 void buttonGrid(button_t* my)
1146 {
1147 	showgrid = (showgrid == 0);
1148 }
1149 
button3DMode(button_t * my)1150 void button3DMode(button_t* my)
1151 {
1152 	mode3d = (mode3d == false);
1153 }
1154 
buttonHoverText(button_t * my)1155 void buttonHoverText(button_t* my)
1156 {
1157 	hovertext = (hovertext == false);
1158 }
1159 
1160 // Map menu
1161 
buttonMap(button_t * my)1162 void buttonMap(button_t* my)
1163 {
1164 	if ( menuVisible != 4 )
1165 	{
1166 		menuVisible = 4;
1167 	}
1168 	else
1169 	{
1170 		menuVisible = 0;
1171 	}
1172 }
1173 
buttonAttributes(button_t * my)1174 void buttonAttributes(button_t* my)
1175 {
1176 	button_t* button;
1177 
1178 	editproperty = 0;
1179 	inputstr = map.name;
1180 	snprintf(widthtext, 4, "%d", map.width);
1181 	snprintf(heighttext, 4, "%d", map.height);
1182 	strcpy(nametext, map.name);
1183 	strcpy(authortext, map.author);
1184 	snprintf(skyboxtext, 4, "%d", map.skybox);
1185 	for ( int z = 0; z < MAPFLAGS; ++z )
1186 	{
1187 		if ( z < MAP_FLAG_GENBYTES1 || z > MAP_FLAG_GENBYTES6 )
1188 		{
1189 			snprintf(mapflagtext[z], 4, "%d", map.flags[z]);
1190 		}
1191 	}
1192 
1193 	snprintf(mapflagtext[MAP_FLAG_GENTOTALMIN], 4, "%d", (map.flags[MAP_FLAG_GENBYTES1] >> 24) & static_cast<int>(0xFF));
1194 	snprintf(mapflagtext[MAP_FLAG_GENTOTALMAX], 4, "%d", (map.flags[MAP_FLAG_GENBYTES1] >> 16) & static_cast<int>(0xFF));
1195 	snprintf(mapflagtext[MAP_FLAG_GENMONSTERMIN], 4, "%d", (map.flags[MAP_FLAG_GENBYTES1] >> 8) & static_cast<int>(0xFF));
1196 	snprintf(mapflagtext[MAP_FLAG_GENMONSTERMAX], 4, "%d", (map.flags[MAP_FLAG_GENBYTES1] >> 0) & static_cast<int>(0xFF));
1197 	snprintf(mapflagtext[MAP_FLAG_GENLOOTMIN], 4, "%d", (map.flags[MAP_FLAG_GENBYTES2] >> 24) & static_cast<int>(0xFF));
1198 	snprintf(mapflagtext[MAP_FLAG_GENLOOTMAX], 4, "%d", (map.flags[MAP_FLAG_GENBYTES2] >> 16) & static_cast<int>(0xFF));
1199 	snprintf(mapflagtext[MAP_FLAG_GENDECORATIONMIN], 4, "%d", (map.flags[MAP_FLAG_GENBYTES2] >> 8) & static_cast<int>(0xFF));
1200 	snprintf(mapflagtext[MAP_FLAG_GENDECORATIONMAX], 4, "%d", (map.flags[MAP_FLAG_GENBYTES2] >> 0) & static_cast<int>(0xFF));
1201 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 24) & static_cast<int>(0xFF) )
1202 	{
1203 		strcpy(mapflagtext[MAP_FLAG_DISABLEDIGGING], "[x]");
1204 	}
1205 	else
1206 	{
1207 		strcpy(mapflagtext[MAP_FLAG_DISABLEDIGGING], "[ ]");
1208 	}
1209 
1210 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 16) & static_cast<int>(0xFF) )
1211 	{
1212 		strcpy(mapflagtext[MAP_FLAG_DISABLETELEPORT], "[x]");
1213 	}
1214 	else
1215 	{
1216 		strcpy(mapflagtext[MAP_FLAG_DISABLETELEPORT], "[ ]");
1217 	}
1218 
1219 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 8) & static_cast<int>(0xFF) )
1220 	{
1221 		strcpy(mapflagtext[MAP_FLAG_DISABLELEVITATION], "[x]");
1222 	}
1223 	else
1224 	{
1225 		strcpy(mapflagtext[MAP_FLAG_DISABLELEVITATION], "[ ]");
1226 	}
1227 
1228 	if ( (map.flags[MAP_FLAG_GENBYTES3] >> 0) & static_cast<int>(0xFF) )
1229 	{
1230 		strcpy(mapflagtext[MAP_FLAG_GENADJACENTROOMS], "[x]");
1231 	}
1232 	else
1233 	{
1234 		strcpy(mapflagtext[MAP_FLAG_GENADJACENTROOMS], "[ ]");
1235 	}
1236 	if ( (map.flags[MAP_FLAG_GENBYTES4] >> 24) & static_cast<int>(0xFF) )
1237 	{
1238 		strcpy(mapflagtext[MAP_FLAG_DISABLEOPENING], "[x]");
1239 	}
1240 	else
1241 	{
1242 		strcpy(mapflagtext[MAP_FLAG_DISABLEOPENING], "[ ]");
1243 	}
1244 	if ( (map.flags[MAP_FLAG_GENBYTES4] >> 16) & static_cast<int>(0xFF) )
1245 	{
1246 		strcpy(mapflagtext[MAP_FLAG_DISABLEMESSAGES], "[x]");
1247 	}
1248 	else
1249 	{
1250 		strcpy(mapflagtext[MAP_FLAG_DISABLEMESSAGES], "[ ]");
1251 	}
1252 	if ( (map.flags[MAP_FLAG_GENBYTES4] >> 8) & static_cast<int>(0xFF) )
1253 	{
1254 		strcpy(mapflagtext[MAP_FLAG_DISABLEHUNGER], "[x]");
1255 	}
1256 	else
1257 	{
1258 		strcpy(mapflagtext[MAP_FLAG_DISABLEHUNGER], "[ ]");
1259 	}
1260 
1261 	if ( map.flags[MAP_FLAG_DISABLETRAPS] > 0 )
1262 	{
1263 		strcpy(mapflagtext[MAP_FLAG_DISABLETRAPS], "[x]");
1264 	}
1265 	else
1266 	{
1267 		strcpy(mapflagtext[MAP_FLAG_DISABLETRAPS], "[ ]");
1268 	}
1269 	if ( map.flags[MAP_FLAG_DISABLEMONSTERS] > 0 )
1270 	{
1271 		strcpy(mapflagtext[MAP_FLAG_DISABLEMONSTERS], "[x]");
1272 	}
1273 	else
1274 	{
1275 		strcpy(mapflagtext[MAP_FLAG_DISABLEMONSTERS], "[ ]");
1276 	}
1277 	if ( map.flags[MAP_FLAG_DISABLELOOT] > 0 )
1278 	{
1279 		strcpy(mapflagtext[MAP_FLAG_DISABLELOOT], "[x]");
1280 	}
1281 	else
1282 	{
1283 		strcpy(mapflagtext[MAP_FLAG_DISABLELOOT], "[ ]");
1284 	}
1285 
1286 	cursorflash = ticks;
1287 	menuVisible = 0;
1288 	subwindow = 1;
1289 	newwindow = 1;
1290 	subx1 = xres / 2 - 200;
1291 	subx2 = xres / 2 + 200;
1292 	suby1 = yres / 2 - 200;
1293 	suby2 = yres / 2 + 200;
1294 	strcpy(subtext, "Map properties:");
1295 
1296 	button = newButton();
1297 	strcpy(button->label, "  OK  ");
1298 	button->x = subx2 - 64;
1299 	button->y = suby2 - 48;
1300 	button->sizex = 56;
1301 	button->sizey = 16;
1302 	button->action = &buttonAttributesConfirm;
1303 	button->visible = 1;
1304 	button->focused = 1;
1305 
1306 	button = newButton();
1307 	strcpy(button->label, "Cancel");
1308 	button->x = subx2 - 64;
1309 	button->y = suby2 - 24;
1310 	button->sizex = 56;
1311 	button->sizey = 16;
1312 	button->action = &buttonCloseSubwindow;
1313 	button->visible = 1;
1314 	button->focused = 1;
1315 
1316 	button = newButton();
1317 	strcpy(button->label, "X");
1318 	button->x = subx2 - 16;
1319 	button->y = suby1;
1320 	button->sizex = 16;
1321 	button->sizey = 16;
1322 	button->action = &buttonCloseSubwindow;
1323 	button->visible = 1;
1324 	button->focused = 1;
1325 }
1326 
buttonAttributesConfirm(button_t * my)1327 void buttonAttributesConfirm(button_t* my)
1328 {
1329 	int x, y, z, c;
1330 	map_t mapcopy;
1331 	makeUndo();
1332 
1333 	// make a copy of the current map
1334 	mapcopy.width = map.width;
1335 	mapcopy.height = map.height;
1336 	mapcopy.tiles = (int*) malloc(sizeof(int) * MAPLAYERS * mapcopy.width * mapcopy.height);
1337 	for ( z = 0; z < MAPLAYERS; z++ )
1338 	{
1339 		for ( y = 0; y < map.height; y++ )
1340 		{
1341 			for ( x = 0; x < map.width; x++ )
1342 			{
1343 				mapcopy.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * mapcopy.height];
1344 			}
1345 		}
1346 	}
1347 
1348 	// allocate memory for a new map
1349 	free(map.tiles);
1350 	map.width = atoi(widthtext);
1351 	map.height = atoi(heighttext);
1352 	map.width = std::min(std::max(MINWIDTH, map.width), MAXWIDTH);
1353 	map.height = std::min(std::max(MINHEIGHT, map.height), MAXHEIGHT);
1354 	map.skybox = atoi(skyboxtext);
1355 	if ( map.skybox > numtiles )
1356 	{
1357 		map.skybox = 0;
1358 	}
1359 	map.flags[MAP_FLAG_CEILINGTILE] = atoi(mapflagtext[MAP_FLAG_CEILINGTILE]);
1360 	if ( map.flags[MAP_FLAG_CEILINGTILE] >= numtiles )
1361 	{
1362 		map.flags[MAP_FLAG_CEILINGTILE] = 0;
1363 	}
1364 
1365 	// start storing some misc bytes within the Sint32 flags to save space:
1366 	map.flags[MAP_FLAG_GENBYTES1] = 0; // clear the flag 1 slot.
1367 	if ( atoi(mapflagtext[MAP_FLAG_GENTOTALMIN]) >= 0 )
1368 	{
1369 		map.flags[MAP_FLAG_GENBYTES1] |= atoi(mapflagtext[MAP_FLAG_GENTOTALMIN]) << 24; // store in first leftmost byte.
1370 	}
1371 	if ( atoi(mapflagtext[MAP_FLAG_GENTOTALMAX]) >= 0 )
1372 	{
1373 		map.flags[MAP_FLAG_GENBYTES1] |= atoi(mapflagtext[MAP_FLAG_GENTOTALMAX]) << 16; // store in second leftmost byte.
1374 	}
1375 	if ( atoi(mapflagtext[MAP_FLAG_GENMONSTERMIN]) >= 0 )
1376 	{
1377 		map.flags[MAP_FLAG_GENBYTES1] |= atoi(mapflagtext[MAP_FLAG_GENMONSTERMIN]) << 8; // store in third leftmost byte.
1378 	}
1379 	if ( atoi(mapflagtext[MAP_FLAG_GENMONSTERMAX]) >= 0 )
1380 	{
1381 		map.flags[MAP_FLAG_GENBYTES1] |= atoi(mapflagtext[MAP_FLAG_GENMONSTERMAX]) << 0; // store in fourth leftmost byte.
1382 	}
1383 
1384 	map.flags[MAP_FLAG_GENBYTES2] = 0; // clear the flag 2 slot.
1385 	if ( atoi(mapflagtext[MAP_FLAG_GENMONSTERMIN]) >= 0 )
1386 	{
1387 		map.flags[MAP_FLAG_GENBYTES2] |= atoi(mapflagtext[MAP_FLAG_GENLOOTMIN]) << 24; // store in first leftmost byte.
1388 	}
1389 	if ( atoi(mapflagtext[MAP_FLAG_GENMONSTERMAX]) >= 0 )
1390 	{
1391 		map.flags[MAP_FLAG_GENBYTES2] |= atoi(mapflagtext[MAP_FLAG_GENLOOTMAX]) << 16; // store in second leftmost byte.
1392 	}
1393 	if ( atoi(mapflagtext[MAP_FLAG_GENDECORATIONMIN]) >= 0 )
1394 	{
1395 		map.flags[MAP_FLAG_GENBYTES2] |= atoi(mapflagtext[MAP_FLAG_GENDECORATIONMIN]) << 8; // store in third leftmost byte.
1396 	}
1397 	if ( atoi(mapflagtext[MAP_FLAG_GENDECORATIONMAX]) >= 0 )
1398 	{
1399 		map.flags[MAP_FLAG_GENBYTES2] |= atoi(mapflagtext[MAP_FLAG_GENDECORATIONMAX]) << 0; // store in fourth leftmost byte.
1400 	}
1401 
1402 	map.flags[MAP_FLAG_GENBYTES3] = 0; // clear the flag 3 slot.
1403 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEDIGGING], "[x]", 3) )
1404 	{
1405 		map.flags[MAP_FLAG_GENBYTES3] |= (1 << 24); // store in first leftmost byte.
1406 	}
1407 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLETELEPORT], "[x]", 3) )
1408 	{
1409 		map.flags[MAP_FLAG_GENBYTES3] |= (1 << 16); // store in second leftmost byte.
1410 	}
1411 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLELEVITATION], "[x]", 3) )
1412 	{
1413 		map.flags[MAP_FLAG_GENBYTES3] |= (1 << 8); // store in third leftmost byte.
1414 	}
1415 	if ( !strncmp(mapflagtext[MAP_FLAG_GENADJACENTROOMS], "[x]", 3) )
1416 	{
1417 		map.flags[MAP_FLAG_GENBYTES3] |= (1 << 0); // store in fourth leftmost byte.
1418 	}
1419 	map.flags[MAP_FLAG_GENBYTES4] = 0; // clear the flag 4 slot.
1420 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEOPENING], "[x]", 3) )
1421 	{
1422 		map.flags[MAP_FLAG_GENBYTES4] |= (1 << 24); // store in first leftmost byte.
1423 	}
1424 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEMESSAGES], "[x]", 3) )
1425 	{
1426 		map.flags[MAP_FLAG_GENBYTES4] |= (1 << 16); // store in second leftmost byte.
1427 	}
1428 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEHUNGER], "[x]", 3) )
1429 	{
1430 		map.flags[MAP_FLAG_GENBYTES4] |= (1 << 8); // store in third leftmost byte.
1431 	}
1432 
1433 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLETRAPS], "[x]", 3) )
1434 	{
1435 		map.flags[MAP_FLAG_DISABLETRAPS] = 1;
1436 	}
1437 	else
1438 	{
1439 		map.flags[MAP_FLAG_DISABLETRAPS] = 0;
1440 	}
1441 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLEMONSTERS], "[x]", 3) )
1442 	{
1443 		map.flags[MAP_FLAG_DISABLEMONSTERS] = 1;
1444 	}
1445 	else
1446 	{
1447 		map.flags[MAP_FLAG_DISABLEMONSTERS] = 0;
1448 	}
1449 	if ( !strncmp(mapflagtext[MAP_FLAG_DISABLELOOT], "[x]", 3) )
1450 	{
1451 		map.flags[MAP_FLAG_DISABLELOOT] = 1;
1452 	}
1453 	else
1454 	{
1455 		map.flags[MAP_FLAG_DISABLELOOT] = 0;
1456 	}
1457 
1458 	map.tiles = (int*) malloc(sizeof(int) * MAPLAYERS * map.height * map.width);
1459 	strcpy(map.name, nametext);
1460 	strcpy(map.author, authortext);
1461 	if ( vismap != NULL )
1462 	{
1463 		free(vismap);
1464 	}
1465 	vismap = (bool*) malloc(sizeof(bool) * map.width * map.height);
1466 	if ( lightmap != NULL )
1467 	{
1468 		free(lightmap);
1469 	}
1470 	if ( lightmapSmoothed != NULL )
1471 	{
1472 		free(lightmapSmoothed);
1473 	}
1474 	lightmap = (int*)malloc(sizeof(Sint32) * map.width * map.height);
1475 	lightmapSmoothed = (int*)malloc(sizeof(Sint32) * map.width * map.height);
1476 	for ( c = 0; c < map.width * map.height; c++ )
1477 	{
1478 		lightmap[c] = 0;
1479 		lightmapSmoothed[c] = 0;
1480 	}
1481 
1482 	// transfer data from the new map to the old map and fill extra space with empty data
1483 	for ( z = 0; z < MAPLAYERS; z++ )
1484 	{
1485 		for ( y = 0; y < map.height; y++ )
1486 		{
1487 			for ( x = 0; x < map.width; x++ )
1488 			{
1489 				if ( x >= mapcopy.width || y >= mapcopy.height )
1490 				{
1491 					map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = 0;
1492 				}
1493 				else
1494 				{
1495 					map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = mapcopy.tiles[z + y * MAPLAYERS + x * MAPLAYERS * mapcopy.height];
1496 				}
1497 			}
1498 		}
1499 	}
1500 	free(mapcopy.tiles);
1501 	strcpy(message, "                       Modified map attributes.");
1502 	messagetime = 60;
1503 	buttonCloseSubwindow(my);
1504 }
1505 
buttonClearMap(button_t * my)1506 void buttonClearMap(button_t* my)
1507 {
1508 	button_t* button;
1509 
1510 	menuVisible = 0;
1511 	subwindow = 1;
1512 	subx1 = xres / 2 - 160;
1513 	subx2 = xres / 2 + 160;
1514 	suby1 = yres / 2 - 56;
1515 	suby2 = yres / 2 + 56;
1516 	strcpy(subtext, "Warning:\n\nThis option will completely erase your\nentire map.\n\nAre you sure you want to continue?\n");
1517 
1518 	button = newButton();
1519 	strcpy(button->label, "OK");
1520 	button->x = subx1 + 64;
1521 	button->y = suby2 - 24;
1522 	button->sizex = 24;
1523 	button->sizey = 16;
1524 	button->action = &buttonClearMapConfirm;
1525 	button->visible = 1;
1526 	button->focused = 1;
1527 
1528 	button = newButton();
1529 	strcpy(button->label, "Cancel");
1530 	button->x = subx2 - 112;
1531 	button->y = suby2 - 24;
1532 	button->sizex = 56;
1533 	button->sizey = 16;
1534 	button->action = &buttonCloseSubwindow;
1535 	button->visible = 1;
1536 	button->focused = 1;
1537 
1538 	button = newButton();
1539 	strcpy(button->label, "X");
1540 	button->x = subx2 - 16;
1541 	button->y = suby1;
1542 	button->sizex = 16;
1543 	button->sizey = 16;
1544 	button->action = &buttonCloseSubwindow;
1545 	button->visible = 1;
1546 	button->focused = 1;
1547 }
1548 
buttonClearMapConfirm(button_t * my)1549 void buttonClearMapConfirm(button_t* my)
1550 {
1551 	long x, y, z;
1552 	makeUndo();
1553 	for ( z = 0; z < MAPLAYERS; z++ )
1554 	{
1555 		for ( y = 0; y < map.height; y++ )
1556 		{
1557 			for ( x = 0; x < map.width; x++ )
1558 			{
1559 				map.tiles[z + y * MAPLAYERS + x * MAPLAYERS * map.height] = 0;
1560 			}
1561 		}
1562 	}
1563 	list_FreeAll(map.entities);
1564 	buttonCloseSubwindow(my);
1565 }
1566 
1567 // Help menu
1568 
buttonHelp(button_t * my)1569 void buttonHelp(button_t* my)
1570 {
1571 	if ( menuVisible != 5 )
1572 	{
1573 		menuVisible = 5;
1574 	}
1575 	else
1576 	{
1577 		menuVisible = 0;
1578 	}
1579 }
1580 
buttonAbout(button_t * my)1581 void buttonAbout(button_t* my)
1582 {
1583 	button_t* button;
1584 
1585 	menuVisible = 0;
1586 	subwindow = 1;
1587 	subx1 = xres / 2 - 160;
1588 	subx2 = xres / 2 + 160;
1589 	suby1 = yres / 2 - 56;
1590 	suby2 = yres / 2 + 56;
1591 	strcpy(subtext, "Barony: Map Editor v2.4"
1592 		"\n\nSee EDITING for full documentation."
1593 		"\n\nThis software is copyright 2018 (c)"
1594 		"\nSheridan Rathbun, all rights reserved."
1595 		"\n\nSee LICENSE for details.\n");
1596 
1597 	button = newButton();
1598 	strcpy(button->label, "OK");
1599 	button->x = xres / 2 - 12;
1600 	button->y = suby2 - 24;
1601 	button->sizex = 24;
1602 	button->sizey = 16;
1603 	button->action = &buttonCloseSubwindow;
1604 	button->visible = 1;
1605 	button->focused = 1;
1606 
1607 	button = newButton();
1608 	strcpy(button->label, "X");
1609 	button->x = subx2 - 16;
1610 	button->y = suby1;
1611 	button->sizex = 16;
1612 	button->sizey = 16;
1613 	button->action = &buttonCloseSubwindow;
1614 	button->visible = 1;
1615 	button->focused = 1;
1616 }
1617 
buttonEditorToolsHelp(button_t * my)1618 void buttonEditorToolsHelp(button_t* my)
1619 {
1620 	node_t* node;
1621 	node_t* nextnode;
1622 	button_t* button;
1623 	for ( node = button_l.first; node != NULL; node = nextnode )
1624 	{
1625 		nextnode = node->next;
1626 		button = (button_t*)node->element;
1627 		if ( button->focused )
1628 		{
1629 			list_RemoveNode(button->node);
1630 			continue;
1631 		}
1632 	}
1633 	subwindow = 1;
1634 	if ( newwindow == 16 )
1635 	{
1636 		newwindow = 17;
1637 		subx1 = xres / 2 - 280;
1638 		subx2 = xres / 2 + 280;
1639 		suby1 = yres / 2 - 190;
1640 		suby2 = yres / 2 + 190;
1641 
1642 		button = newButton();
1643 		strcpy(button->label, "OK");
1644 		button->sizex = 9 * 12 + 8;
1645 		button->x = xres / 2 - button->sizex - 4;
1646 		button->y = suby2 - 24;
1647 		button->sizey = 16;
1648 		button->action = &buttonCloseSubwindow;
1649 		button->visible = 1;
1650 		button->focused = 1;
1651 
1652 		button = newButton();
1653 		strcpy(button->label, "Next Page");
1654 		button->x = xres / 2 + 4;
1655 		button->y = suby2 - 24;
1656 		button->sizex = strlen(button->label) * 12 + 8;
1657 		button->sizey = 16;
1658 		button->action = &buttonEditorToolsHelp;
1659 		button->visible = 1;
1660 		button->focused = 1;
1661 
1662 		button = newButton();
1663 		strcpy(button->label, "X");
1664 		button->x = subx2 - 16;
1665 		button->y = suby1;
1666 		button->sizex = 16;
1667 		button->sizey = 16;
1668 		button->action = &buttonCloseSubwindow;
1669 		button->visible = 1;
1670 		button->focused = 1;
1671 	}
1672 	else
1673 	{
1674 		buttonEditorControls(nullptr);
1675 	}
1676 }
1677 
buttonEditorControls(button_t * my)1678 void buttonEditorControls(button_t* my)
1679 {
1680 	button_t* button;
1681 
1682 	menuVisible = 0;
1683 	subwindow = 1;
1684 	newwindow = 16;
1685 	subx1 = xres / 2 - 250;
1686 	subx2 = xres / 2 + 250;
1687 	suby1 = yres / 2 - 210;
1688 	suby2 = yres / 2 + 210;
1689 
1690 	button = newButton();
1691 	strcpy(button->label, "OK");
1692 	button->sizex = 9 * 12 + 8;
1693 	button->x = xres / 2 - button->sizex - 4;
1694 	button->y = suby2 - 24;
1695 	button->sizey = 16;
1696 	button->action = &buttonCloseSubwindow;
1697 	button->visible = 1;
1698 	button->focused = 1;
1699 
1700 	button = newButton();
1701 	strcpy(button->label, "Next Page");
1702 	button->x = xres / 2 + 4;
1703 	button->y = suby2 - 24;
1704 	button->sizex = strlen(button->label) * 12 + 8;
1705 	button->sizey = 16;
1706 	button->action = &buttonEditorToolsHelp;
1707 	button->visible = 1;
1708 	button->focused = 1;
1709 
1710 	button = newButton();
1711 	strcpy(button->label, "X");
1712 	button->x = subx2 - 16;
1713 	button->y = suby1;
1714 	button->sizex = 16;
1715 	button->sizey = 16;
1716 	button->action = &buttonCloseSubwindow;
1717 	button->visible = 1;
1718 	button->focused = 1;
1719 }
1720 
1721 // Subwindows
buttonCloseSubwindow(button_t * my)1722 void buttonCloseSubwindow(button_t* my)
1723 {
1724 	int c;
1725 
1726 	// close window
1727 	selectedEntity = NULL;
1728 	subwindow = 0;
1729 	newwindow = 0;
1730 	openwindow = 0;
1731 	savewindow = 0;
1732 	editproperty = 0;
1733 	strcpy(filename, oldfilename);
1734 }
1735 
buttonSpriteProperties(button_t * my)1736 void buttonSpriteProperties(button_t* my)
1737 {
1738 	button_t* button;
1739 	int c = 0;
1740 	Stat* tmpSpriteStats = NULL;
1741 	int spriteType = 0;
1742 	int spacing = 20;
1743 	int pad_y2;
1744 	int pad_x3;
1745 	int pad_x4;
1746 	char tmpStr[32] = "";
1747 	int itemIndex = 0;
1748 
1749 	if ( selectedEntity == NULL && lastSelectedEntity != NULL )
1750 	{
1751 		if ( checkSpriteType(lastSelectedEntity->sprite) != 0 )
1752 		{
1753 			selectedEntity = lastSelectedEntity;
1754 		}
1755 		else
1756 		{
1757 			strcpy(message, "No properties available for previous sprite.");
1758 			messagetime = 60;
1759 		}
1760 	}
1761 
1762 	if ( selectedEntity != NULL )
1763 	{
1764 		editproperty = 0;
1765 		for ( int i = 0; i < (sizeof(spriteProperties) / sizeof(spriteProperties[0])); i++ )
1766 		{
1767 			strcpy(spriteProperties[i], "");
1768 		}
1769 
1770 		spriteType = checkSpriteType(selectedEntity->sprite);
1771 		switch ( spriteType )
1772 		{
1773 			case 1: //monsters
1774 				tmpSpriteStats = selectedEntity->getStats();
1775 				if ( tmpSpriteStats != nullptr )
1776 				{
1777 					if ( exitFromItemWindow == true )
1778 					{
1779 						exitFromItemWindow = false;
1780 						// retreives any modified monster stats, to be restored when window is closed.
1781 
1782 						for ( int i = 0; i < sizeof(spriteProperties) / sizeof(spriteProperties[0]); i++ )
1783 						{
1784 							strcpy(spriteProperties[i], tmpSpriteProperties[i]);
1785 						}
1786 					}
1787 					else
1788 					{
1789 						copyMonsterStatToPropertyStrings(tmpSpriteStats);
1790 					}
1791 					inputstr = spriteProperties[0];
1792 					initMonsterPropertiesWindow();
1793 				}
1794 				tmpSpriteStats = NULL;
1795 				break;
1796 			case 2: //chests
1797 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->yaw));
1798 				snprintf(spriteProperties[1], 4, "%d", selectedEntity->skill[9]);
1799 				snprintf(spriteProperties[2], 4, "%d", selectedEntity->chestLocked);
1800 				inputstr = spriteProperties[0];
1801 				cursorflash = ticks;
1802 				menuVisible = 0;
1803 				subwindow = 1;
1804 				newwindow = 3;
1805 				subx1 = xres / 2 - 160;
1806 				subx2 = xres / 2 + 160;
1807 				suby1 = yres / 2 - 105;
1808 				suby2 = yres / 2 + 105;
1809 				strcpy(subtext, "Chest Properties:");
1810 				break;
1811 			case 3: //items
1812 				itemSelect = 1;
1813 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->skill[10])); //ID
1814 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->skill[11])); //status
1815 				if ( (int)selectedEntity->skill[12] == 10 )
1816 				{
1817 					strcpy(spriteProperties[2], "00"); //bless random
1818 				}
1819 				else
1820 				{
1821 					snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->skill[12])); //bless
1822 				}
1823 				snprintf(spriteProperties[3], 4, "%d", static_cast<int>(selectedEntity->skill[13])); //count
1824 				snprintf(spriteProperties[4], 4, "%d", static_cast<int>(selectedEntity->skill[15])); //identified
1825 				snprintf(spriteProperties[5], 4, "%d", static_cast<int>(selectedEntity->skill[16])); //category if random
1826 				inputstr = spriteProperties[0];
1827 				cursorflash = ticks;
1828 				menuVisible = 0;
1829 				subwindow = 1;
1830 				newwindow = 4;
1831 				slidery = 0;
1832 				subx1 = xres / 2 - 200;
1833 				subx2 = xres / 2 + 200;
1834 				suby1 = yres / 2 - 140;
1835 				suby2 = yres / 2 + 140;
1836 				strcpy(subtext, "Item Properties:");
1837 				break;
1838 			case 4:
1839 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->skill[0])); //Monster to Spawn
1840 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->skill[1])); //Qty
1841 				snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->skill[2])); //Time Between Spawns
1842 				snprintf(spriteProperties[3], 4, "%d", static_cast<int>(selectedEntity->skill[3])); //Amount of Spawns
1843 				snprintf(spriteProperties[4], 4, "%d", static_cast<int>(selectedEntity->skill[4])); //Requires Power
1844 				snprintf(spriteProperties[5], 4, "%d", static_cast<int>(selectedEntity->skill[5])); //Chance to Stop Working
1845 				inputstr = spriteProperties[0];
1846 				cursorflash = ticks;
1847 				menuVisible = 0;
1848 				subwindow = 1;
1849 				newwindow = 6;
1850 				subx1 = xres / 2 - 210;
1851 				subx2 = xres / 2 + 210;
1852 				suby1 = yres / 2 - 140;
1853 				suby2 = yres / 2 + 140;
1854 				strcpy(subtext, "Summoning Trap Properties:");
1855 				break;
1856 			case 5:
1857 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->yaw)); //Orientation
1858 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->crystalNumElectricityNodes)); //Powered Distance
1859 				snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->crystalTurnReverse)); //Rotation direction
1860 				snprintf(spriteProperties[3], 4, "%d", static_cast<int>(selectedEntity->crystalSpellToActivate)); //Spell to activate
1861 				inputstr = spriteProperties[0];
1862 				cursorflash = ticks;
1863 				menuVisible = 0;
1864 				subwindow = 1;
1865 				newwindow = 7;
1866 				subx1 = xres / 2 - 210;
1867 				subx2 = xres / 2 + 210;
1868 				suby1 = yres / 2 - 120;
1869 				suby2 = yres / 2 + 120;
1870 				strcpy(subtext, "Power Crystal Properties:");
1871 				break;
1872 			case 6:
1873 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->leverTimerTicks));
1874 				inputstr = spriteProperties[0];
1875 				cursorflash = ticks;
1876 				menuVisible = 0;
1877 				subwindow = 1;
1878 				newwindow = 8;
1879 				subx1 = xres / 2 - 120;
1880 				subx2 = xres / 2 + 120;
1881 				suby1 = yres / 2 - 60;
1882 				suby2 = yres / 2 + 60;
1883 				strcpy(subtext, "Lever Timer Properties:");
1884 				break;
1885 			case 7:
1886 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->boulderTrapRefireAmount));
1887 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->boulderTrapRefireDelay));
1888 				snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->boulderTrapPreDelay));
1889 				inputstr = spriteProperties[0];
1890 				cursorflash = ticks;
1891 				menuVisible = 0;
1892 				subwindow = 1;
1893 				newwindow = 9;
1894 				subx1 = xres / 2 - 170;
1895 				subx2 = xres / 2 + 170;
1896 				suby1 = yres / 2 - 100;
1897 				suby2 = yres / 2 + 100;
1898 				strcpy(subtext, "Boulder Trap Properties:");
1899 				break;
1900 			case 8:
1901 				snprintf(spriteProperties[0], 2, "%d", static_cast<int>(selectedEntity->pedestalOrbType));
1902 				snprintf(spriteProperties[1], 2, "%d", static_cast<int>(selectedEntity->pedestalHasOrb));
1903 				snprintf(spriteProperties[2], 2, "%d", static_cast<int>(selectedEntity->pedestalInvertedPower));
1904 				snprintf(spriteProperties[3], 2, "%d", static_cast<int>(selectedEntity->pedestalInGround));
1905 				snprintf(spriteProperties[4], 2, "%d", static_cast<int>(selectedEntity->pedestalLockOrb));
1906 				inputstr = spriteProperties[0];
1907 				cursorflash = ticks;
1908 				menuVisible = 0;
1909 				subwindow = 1;
1910 				newwindow = 10;
1911 				subx1 = xres / 2 - 170;
1912 				subx2 = xres / 2 + 170;
1913 				suby1 = yres / 2 - 110;
1914 				suby2 = yres / 2 + 110;
1915 				strcpy(subtext, "Pedestal Properties:");
1916 				break;
1917 			case 9:
1918 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->teleporterX));
1919 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->teleporterY));
1920 				snprintf(spriteProperties[2], 2, "%d", static_cast<int>(selectedEntity->teleporterType));
1921 				inputstr = spriteProperties[0];
1922 				cursorflash = ticks;
1923 				menuVisible = 0;
1924 				subwindow = 1;
1925 				newwindow = 11;
1926 				subx1 = xres / 2 - 170;
1927 				subx2 = xres / 2 + 170;
1928 				suby1 = yres / 2 - 100;
1929 				suby2 = yres / 2 + 100;
1930 				strcpy(subtext, "Teleporter Properties:");
1931 				break;
1932 			case 10:
1933 				snprintf(spriteProperties[0], 5, "%d", static_cast<int>(selectedEntity->ceilingTileModel));
1934 				inputstr = spriteProperties[0];
1935 				cursorflash = ticks;
1936 				menuVisible = 0;
1937 				subwindow = 1;
1938 				newwindow = 12;
1939 				subx1 = xres / 2 - 170;
1940 				subx2 = xres / 2 + 170;
1941 				suby1 = yres / 2 - 60;
1942 				suby2 = yres / 2 + 60;
1943 				strcpy(subtext, "Ceiling Tile Properties:");
1944 				break;
1945 			case 11:
1946 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->spellTrapType));
1947 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->spellTrapRefire));
1948 				snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->spellTrapLatchPower));
1949 				snprintf(spriteProperties[3], 5, "%d", static_cast<int>(selectedEntity->spellTrapFloorTile));
1950 				snprintf(spriteProperties[4], 4, "%d", static_cast<int>(selectedEntity->spellTrapRefireRate));
1951 				inputstr = spriteProperties[0];
1952 				cursorflash = ticks;
1953 				menuVisible = 0;
1954 				subwindow = 1;
1955 				newwindow = 13;
1956 				subx1 = xres / 2 - 200;
1957 				subx2 = xres / 2 + 200;
1958 				suby1 = yres / 2 - 110;
1959 				suby2 = yres / 2 + 110;
1960 				strcpy(subtext, "Spell Trap Properties:");
1961 				break;
1962 			case 12:
1963 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->furnitureDir));
1964 				inputstr = spriteProperties[0];
1965 				cursorflash = ticks;
1966 				menuVisible = 0;
1967 				subwindow = 1;
1968 				newwindow = 14;
1969 				subx1 = xres / 2 - 170;
1970 				subx2 = xres / 2 + 170;
1971 				suby1 = yres / 2 - 60;
1972 				suby2 = yres / 2 + 60;
1973 				strcpy(subtext, "Furniture Properties:");
1974 				break;
1975 			case 13:
1976 			{
1977 				snprintf(spriteProperties[0], 5, "%d", static_cast<int>(selectedEntity->floorDecorationModel));
1978 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->floorDecorationRotation));
1979 				snprintf(spriteProperties[2], 5, "%d", static_cast<int>(selectedEntity->floorDecorationHeightOffset));
1980 				snprintf(spriteProperties[3], 5, "%d", static_cast<int>(selectedEntity->floorDecorationXOffset));
1981 				snprintf(spriteProperties[4], 5, "%d", static_cast<int>(selectedEntity->floorDecorationYOffset));
1982 				char buf[256] = "";
1983 				int totalChars = 0;
1984 				for ( int i = 8; i < 60; ++i )
1985 				{
1986 					if ( selectedEntity->skill[i] != 0 && i != 28 ) // skill[28] is circuit status.
1987 					{
1988 						for ( int c = 0; c < 4; ++c )
1989 						{
1990 							if ( static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF) == '\0'
1991 								&& i != 59 && selectedEntity->skill[i + 1] != 0 )
1992 							{
1993 								// don't add '\0' termination unless the next skill slot is empty as we have more data to read.
1994 							}
1995 							else
1996 							{
1997 								buf[totalChars] = static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF);
1998 								++totalChars;
1999 							}
2000 						}
2001 					}
2002 				}
2003 				if ( buf[totalChars] != '\0' )
2004 				{
2005 					buf[totalChars] = '\0';
2006 				}
2007 				strncpy(spriteProperties[5], buf, 48);
2008 				strncpy(spriteProperties[6], buf + 48, 48);
2009 				strncpy(spriteProperties[7], buf + 96, 48);
2010 				strncpy(spriteProperties[8], buf + 144, 48);
2011 				inputstr = spriteProperties[0];
2012 				cursorflash = ticks;
2013 				menuVisible = 0;
2014 				subwindow = 1;
2015 				newwindow = 15;
2016 				subx1 = xres / 2 - 200;
2017 				subx2 = xres / 2 + 200;
2018 				suby1 = yres / 2 - 180;
2019 				suby2 = yres / 2 + 180;
2020 				strcpy(subtext, "Decoration Model Properties:");
2021 				break;
2022 			}
2023 			case 14:
2024 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->soundSourceToPlay));
2025 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->soundSourceVolume));
2026 				snprintf(spriteProperties[2], 2, "%d", static_cast<int>(selectedEntity->soundSourceLatchOn));
2027 				snprintf(spriteProperties[3], 5, "%d", static_cast<int>(selectedEntity->soundSourceDelay));
2028 				snprintf(spriteProperties[4], 2, "%d", static_cast<int>(selectedEntity->soundSourceOrigin));
2029 				inputstr = spriteProperties[0];
2030 				cursorflash = ticks;
2031 				menuVisible = 0;
2032 				subwindow = 1;
2033 				newwindow = 18;
2034 				subx1 = xres / 2 - 230;
2035 				subx2 = xres / 2 + 230;
2036 				suby1 = yres / 2 - 112;
2037 				suby2 = yres / 2 + 112;
2038 				strcpy(subtext, "Sound Source Properties:");
2039 				break;
2040 			case 15:
2041 				snprintf(spriteProperties[0], 2, "%d", static_cast<int>(selectedEntity->lightSourceAlwaysOn));
2042 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->lightSourceBrightness));
2043 				snprintf(spriteProperties[2], 2, "%d", static_cast<int>(selectedEntity->lightSourceInvertPower));
2044 				snprintf(spriteProperties[3], 2, "%d", static_cast<int>(selectedEntity->lightSourceLatchOn));
2045 				snprintf(spriteProperties[4], 3, "%d", static_cast<int>(selectedEntity->lightSourceRadius));
2046 				snprintf(spriteProperties[5], 2, "%d", static_cast<int>(selectedEntity->lightSourceFlicker));
2047 				snprintf(spriteProperties[6], 5, "%d", static_cast<int>(selectedEntity->lightSourceDelay));
2048 				inputstr = spriteProperties[0];
2049 				cursorflash = ticks;
2050 				menuVisible = 0;
2051 				subwindow = 1;
2052 				newwindow = 19;
2053 				subx1 = xres / 2 - 200;
2054 				subx2 = xres / 2 + 200;
2055 				suby1 = yres / 2 - 160;
2056 				suby2 = yres / 2 + 160;
2057 				strcpy(subtext, "Light Source Properties:");
2058 				break;
2059 			case 16:
2060 			{
2061 				Uint32 r = (Uint32)(selectedEntity->textSourceColorRGB >> 16) & 0xFF;
2062 				Uint32 g = (Uint32)(selectedEntity->textSourceColorRGB >> 8) & 0xFF;
2063 				Uint32 b = (Uint32)(selectedEntity->textSourceColorRGB >> 0) & 0xFF;
2064 				snprintf(spriteProperties[0], 4, "%d", r);
2065 				snprintf(spriteProperties[1], 4, "%d", g);
2066 				snprintf(spriteProperties[2], 4, "%d", b);
2067 				char buf[256] = "";
2068 				int totalChars = 0;
2069 				for ( int i = 4; i < 60; ++i )
2070 				{
2071 					if ( selectedEntity->skill[i] != 0 && i != 28 ) // skill[28] is circuit status.
2072 					{
2073 						for ( int c = 0; c < 4; ++c )
2074 						{
2075 							if ( static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF) == '\0'
2076 								&& i != 59 && selectedEntity->skill[i + 1] != 0 )
2077 							{
2078 								// don't add '\0' termination unless the next skill slot is empty as we have more data to read.
2079 							}
2080 							else
2081 							{
2082 								buf[totalChars] = static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF);
2083 								++totalChars;
2084 							}
2085 						}
2086 					}
2087 				}
2088 				if ( buf[totalChars] != '\0' )
2089 				{
2090 					buf[totalChars] = '\0';
2091 				}
2092 				strncpy(spriteProperties[3], buf, 48);
2093 				strncpy(spriteProperties[4], buf + 48, 48);
2094 				strncpy(spriteProperties[5], buf + 96, 48);
2095 				strncpy(spriteProperties[6], buf + 144, 48);
2096 				strncpy(spriteProperties[7], buf + 192, 48);
2097 				snprintf(spriteProperties[8], 5, "%d", static_cast<int>(selectedEntity->textSourceDelay));
2098 				snprintf(spriteProperties[9], 2, "%d", static_cast<int>((selectedEntity->textSourceVariables4W >> 8) & 0xFF));
2099 				inputstr = spriteProperties[0];
2100 				cursorflash = ticks;
2101 				menuVisible = 0;
2102 				subwindow = 1;
2103 				newwindow = 20;
2104 				subx1 = xres / 2 - 200;
2105 				subx2 = xres / 2 + 200;
2106 				suby1 = yres / 2 - 140;
2107 				suby2 = yres / 2 + 140;
2108 				strcpy(subtext, "Text Source Properties:");
2109 				break;
2110 			}
2111 			case 17:
2112 				snprintf(spriteProperties[0], 2, "%d", static_cast<int>(selectedEntity->signalInputDirection));
2113 				snprintf(spriteProperties[1], 5, "%d", static_cast<int>(selectedEntity->signalActivateDelay));
2114 				snprintf(spriteProperties[2], 5, "%d", static_cast<int>(selectedEntity->signalTimerInterval));
2115 				snprintf(spriteProperties[3], 5, "%d", static_cast<int>(selectedEntity->signalTimerRepeatCount));
2116 				snprintf(spriteProperties[4], 2, "%d", static_cast<int>(selectedEntity->signalTimerLatchInput));
2117 				inputstr = spriteProperties[0];
2118 				cursorflash = ticks;
2119 				menuVisible = 0;
2120 				subwindow = 1;
2121 				newwindow = 21;
2122 				subx1 = xres / 2 - 220;
2123 				subx2 = xres / 2 + 220;
2124 				suby1 = yres / 2 - 120;
2125 				suby2 = yres / 2 + 120;
2126 				strcpy(subtext, "Signal Timer Properties:");
2127 				break;
2128 			case 18: // custom portal
2129 			{
2130 				snprintf(spriteProperties[0], 5, "%d", static_cast<int>(selectedEntity->portalCustomSprite));
2131 				snprintf(spriteProperties[1], 2, "%d", static_cast<int>(selectedEntity->portalCustomSpriteAnimationFrames));
2132 				snprintf(spriteProperties[2], 5, "%d", static_cast<int>(selectedEntity->portalCustomZOffset));
2133 				snprintf(spriteProperties[3], 3, "%d", static_cast<int>(selectedEntity->portalCustomLevelsToJump));
2134 				snprintf(spriteProperties[5], 2, "%d", static_cast<int>(selectedEntity->portalCustomRequiresPower));
2135 				snprintf(spriteProperties[6], 2, "%d", static_cast<int>((selectedEntity->portalNotSecret ? 0 : 1)));
2136 
2137 				char buf[64] = "";
2138 				int totalChars = 0;
2139 				for ( int i = 11; i <= 18; ++i )
2140 				{
2141 					if ( selectedEntity->skill[i] != 0 && i != 28 ) // skill[28] is circuit status.
2142 					{
2143 						for ( int c = 0; c < 4; ++c )
2144 						{
2145 							if ( static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF) == '\0'
2146 								&& i != 18 && selectedEntity->skill[i + 1] != 0 )
2147 							{
2148 								// don't add '\0' termination unless the next skill slot is empty as we have more data to read.
2149 							}
2150 							else
2151 							{
2152 								buf[totalChars] = static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF);
2153 								++totalChars;
2154 							}
2155 						}
2156 					}
2157 				}
2158 				if ( buf[totalChars] != '\0' )
2159 				{
2160 					buf[totalChars] = '\0';
2161 				}
2162 				strncpy(spriteProperties[4], buf, 32);
2163 
2164 				inputstr = spriteProperties[0];
2165 				cursorflash = ticks;
2166 				menuVisible = 0;
2167 				subwindow = 1;
2168 				newwindow = 22;
2169 				subx1 = xres / 2 - 220;
2170 				subx2 = xres / 2 + 220;
2171 				suby1 = yres / 2 - 140;
2172 				suby2 = yres / 2 + 140;
2173 				strcpy(subtext, "Custom Exit Properties:");
2174 				break;
2175 			}
2176 			case 19: // tables
2177 				snprintf(spriteProperties[0], 3, "%d", static_cast<int>(selectedEntity->furnitureDir));
2178 				snprintf(spriteProperties[1], 3, "%d", static_cast<int>(selectedEntity->furnitureTableSpawnChairs));
2179 				snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->furnitureTableRandomItemChance));
2180 				inputstr = spriteProperties[0];
2181 				cursorflash = ticks;
2182 				menuVisible = 0;
2183 				subwindow = 1;
2184 				newwindow = 23;
2185 				subx1 = xres / 2 - 170;
2186 				subx2 = xres / 2 + 170;
2187 				suby1 = yres / 2 - 100;
2188 				suby2 = yres / 2 + 100;
2189 				strcpy(subtext, "Table Properties:");
2190 				break;
2191 			case 20: // readablebook
2192 			{
2193 				snprintf(spriteProperties[0], 3, "%d", static_cast<int>(selectedEntity->skill[11])); // status
2194 				if ( (int)selectedEntity->skill[12] == 10 )
2195 				{
2196 					strcpy(spriteProperties[1], "00"); //bless random
2197 				}
2198 				else
2199 				{
2200 					snprintf(spriteProperties[1], 3, "%d", static_cast<int>(selectedEntity->skill[12])); //bless
2201 				}
2202 				snprintf(spriteProperties[2], 3, "%d", static_cast<int>(selectedEntity->skill[15])); // identified
2203 				char buf[64] = "";
2204 				int totalChars = 0;
2205 				for ( int i = 40; i <= 52; ++i )
2206 				{
2207 					if ( selectedEntity->skill[i] != 0 && i != 28 ) // skill[28] is circuit status.
2208 					{
2209 						for ( int c = 0; c < 4; ++c )
2210 						{
2211 							if ( static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF) == '\0'
2212 								&& i != 52 && selectedEntity->skill[i + 1] != 0 )
2213 							{
2214 								// don't add '\0' termination unless the next skill slot is empty as we have more data to read.
2215 							}
2216 							else
2217 							{
2218 								buf[totalChars] = static_cast<char>((selectedEntity->skill[i] >> (c * 8)) & 0xFF);
2219 								++totalChars;
2220 							}
2221 						}
2222 					}
2223 				}
2224 				if ( buf[totalChars] != '\0' )
2225 				{
2226 					buf[totalChars] = '\0';
2227 				}
2228 				strncpy(spriteProperties[3], buf, 32);
2229 
2230 				inputstr = spriteProperties[0];
2231 				cursorflash = ticks;
2232 				menuVisible = 0;
2233 				subwindow = 1;
2234 				newwindow = 24;
2235 				subx1 = xres / 2 - 220;
2236 				subx2 = xres / 2 + 220;
2237 				suby1 = yres / 2 - 110;
2238 				suby2 = yres / 2 + 110;
2239 				strcpy(subtext, "Readable Book Properties:");
2240 			}
2241 				break;
2242 			case 21:
2243 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->doorForceLockedUnlocked));
2244 				snprintf(spriteProperties[1], 4, "%d", static_cast<int>(selectedEntity->doorDisableLockpicks));
2245 				snprintf(spriteProperties[2], 4, "%d", static_cast<int>(selectedEntity->doorDisableOpening));
2246 				inputstr = spriteProperties[0];
2247 				cursorflash = ticks;
2248 				menuVisible = 0;
2249 				subwindow = 1;
2250 				newwindow = 26;
2251 				subx1 = xres / 2 - 170;
2252 				subx2 = xres / 2 + 170;
2253 				suby1 = yres / 2 - 100;
2254 				suby2 = yres / 2 + 100;
2255 				strcpy(subtext, "Door Properties:");
2256 				break;
2257 			case 22:
2258 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->gateDisableOpening));
2259 				inputstr = spriteProperties[0];
2260 				cursorflash = ticks;
2261 				menuVisible = 0;
2262 				subwindow = 1;
2263 				newwindow = 27;
2264 				subx1 = xres / 2 - 170;
2265 				subx2 = xres / 2 + 170;
2266 				suby1 = yres / 2 - 60;
2267 				suby2 = yres / 2 + 60;
2268 				strcpy(subtext, "Gate Properties:");
2269 				break;
2270 			case 23: // player spawn
2271 				snprintf(spriteProperties[0], 4, "%d", static_cast<int>(selectedEntity->playerStartDir));
2272 				inputstr = spriteProperties[0];
2273 				cursorflash = ticks;
2274 				menuVisible = 0;
2275 				subwindow = 1;
2276 				newwindow = 28;
2277 				subx1 = xres / 2 - 170;
2278 				subx2 = xres / 2 + 170;
2279 				suby1 = yres / 2 - 60;
2280 				suby2 = yres / 2 + 60;
2281 				strcpy(subtext, "Player Spawn Properties:");
2282 				break;
2283 			default:
2284 				strcpy(message, "No properties available for current sprite.");
2285 				messagetime = 60;
2286 			break;
2287 		}
2288 
2289 		//remaining buttons
2290 		switch ( spriteType )
2291 		{
2292 			case 1: //monsters
2293 				tmpSpriteStats = selectedEntity->getStats();
2294 				if ( tmpSpriteStats != nullptr )
2295 				{
2296 
2297 					butMonsterOK = newButton();
2298 					strcpy(butMonsterOK->label, "  OK  ");
2299 					butMonsterOK->x = subx2 - 64;
2300 					butMonsterOK->y = suby2 - 48;
2301 					butMonsterOK->sizex = 56;
2302 					butMonsterOK->sizey = 16;
2303 					butMonsterOK->action = &buttonSpritePropertiesConfirm;
2304 					butMonsterOK->visible = 1;
2305 					butMonsterOK->focused = 1;
2306 
2307 					butMonsterCancel = newButton();
2308 					strcpy(butMonsterCancel->label, "Cancel");
2309 					butMonsterCancel->x = subx2 - 64;
2310 					butMonsterCancel->y = suby2 - 24;
2311 					butMonsterCancel->sizex = 56;
2312 					butMonsterCancel->sizey = 16;
2313 					butMonsterCancel->action = &buttonCloseSpriteSubwindow;
2314 					butMonsterCancel->visible = 1;
2315 					butMonsterCancel->focused = 1;
2316 
2317 					butMonsterX = newButton();
2318 					strcpy(butMonsterX->label, "X");
2319 					butMonsterX->x = subx2 - 16;
2320 					butMonsterX->y = suby1;
2321 					butMonsterX->sizex = 16;
2322 					butMonsterX->sizey = 16;
2323 					butMonsterX->action = &buttonCloseSpriteSubwindow;
2324 					butMonsterX->visible = 1;
2325 					butMonsterX->focused = 1;
2326 
2327 					pad_y2 = suby1 + 28 + 2 * spacing;
2328 					pad_x3 = 40;
2329 					pad_x4 = subx2 - 112;
2330 					itemIndex = 0;
2331 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2332 					{
2333 						strcpy(tmpStr, "NULL");
2334 					}
2335 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2336 					{
2337 						strcpy(tmpStr, "RAND");
2338 					}
2339 					else
2340 					{
2341 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2342 					}
2343 
2344 					if ( canWearEquip(selectedEntity, itemIndex) )
2345 					{
2346 						butMonsterHelm = newButton();
2347 						strcpy(butMonsterHelm->label, tmpStr);
2348 						butMonsterHelm->x = pad_x4 - 10;
2349 						butMonsterHelm->y = pad_y2 + spacing - 4;
2350 						butMonsterHelm->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2351 						butMonsterHelm->sizey = 16;
2352 						butMonsterHelm->action = &buttonMonsterItems;
2353 						butMonsterHelm->visible = 1;
2354 						butMonsterHelm->focused = 1;
2355 					}
2356 
2357 					pad_y2 += spacing * 2;
2358 					itemIndex = 6;
2359 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2360 					{
2361 						strcpy(tmpStr, "NULL");
2362 					}
2363 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2364 					{
2365 						strcpy(tmpStr, "RAND");
2366 					}
2367 					else
2368 					{
2369 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2370 					}
2371 					if ( canWearEquip(selectedEntity, itemIndex) )
2372 					{
2373 						butMonsterAmulet = newButton();
2374 						strcpy(butMonsterAmulet->label, tmpStr);
2375 						butMonsterAmulet->x = pad_x4 - 10;
2376 						butMonsterAmulet->y = pad_y2 + spacing - 4;
2377 						butMonsterAmulet->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2378 						butMonsterAmulet->sizey = 16;
2379 						butMonsterAmulet->action = &buttonMonsterItems;
2380 						butMonsterAmulet->visible = 1;
2381 						butMonsterAmulet->focused = 1;
2382 					}
2383 
2384 					pad_y2 += spacing * 2;
2385 					itemIndex = 3;
2386 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2387 					{
2388 						strcpy(tmpStr, "NULL");
2389 					}
2390 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2391 					{
2392 						strcpy(tmpStr, "RAND");
2393 					}
2394 					else
2395 					{
2396 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2397 					}
2398 					if ( canWearEquip(selectedEntity, itemIndex) )
2399 					{
2400 						butMonsterArmor = newButton();
2401 						strcpy(butMonsterArmor->label, tmpStr);
2402 						butMonsterArmor->x = pad_x4 - 10;
2403 						butMonsterArmor->y = pad_y2 + spacing - 4;
2404 						butMonsterArmor->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2405 						butMonsterArmor->sizey = 16;
2406 						butMonsterArmor->action = &buttonMonsterItems;
2407 						butMonsterArmor->visible = 1;
2408 						butMonsterArmor->focused = 1;
2409 					}
2410 
2411 					pad_y2 += spacing * 2;
2412 					itemIndex = 4;
2413 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2414 					{
2415 						strcpy(tmpStr, "NULL");
2416 					}
2417 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2418 					{
2419 						strcpy(tmpStr, "RAND");
2420 					}
2421 					else
2422 					{
2423 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2424 					}
2425 					if ( canWearEquip(selectedEntity, itemIndex) )
2426 					{
2427 						butMonsterBoots = newButton();
2428 						strcpy(butMonsterBoots->label, tmpStr);
2429 						butMonsterBoots->x = pad_x4 - 10;
2430 						butMonsterBoots->y = pad_y2 + spacing - 4;
2431 						butMonsterBoots->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2432 						butMonsterBoots->sizey = 16;
2433 						butMonsterBoots->action = &buttonMonsterItems;
2434 						butMonsterBoots->visible = 1;
2435 						butMonsterBoots->focused = 1;
2436 					}
2437 
2438 					pad_y2 = suby1 + 28 + 2 * spacing; //reset y coord
2439 					pad_y2 += 16;
2440 					pad_x4 -= 64;
2441 					itemIndex = 7;
2442 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2443 					{
2444 						strcpy(tmpStr, "NULL");
2445 					}
2446 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2447 					{
2448 						strcpy(tmpStr, "RAND");
2449 					}
2450 					else
2451 					{
2452 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2453 					}
2454 
2455 					if ( canWearEquip(selectedEntity, itemIndex) )
2456 					{
2457 						butMonsterCloak = newButton();
2458 						strcpy(butMonsterCloak->label, tmpStr);
2459 						butMonsterCloak->x = pad_x4 - 10;
2460 						butMonsterCloak->y = pad_y2 + spacing - 4;
2461 						butMonsterCloak->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2462 						butMonsterCloak->sizey = 16;
2463 						butMonsterCloak->action = &buttonMonsterItems;
2464 						butMonsterCloak->visible = 1;
2465 						butMonsterCloak->focused = 1;
2466 					}
2467 
2468 					pad_x4 += 64 * 2;
2469 					itemIndex = 8;
2470 
2471 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2472 					{
2473 						strcpy(tmpStr, "NULL");
2474 					}
2475 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2476 					{
2477 						strcpy(tmpStr, "RAND");
2478 					}
2479 					else
2480 					{
2481 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2482 					}
2483 
2484 					if ( canWearEquip(selectedEntity, itemIndex) )
2485 					{
2486 						butMonsterMask = newButton();
2487 						strcpy(butMonsterMask->label, tmpStr);
2488 						butMonsterMask->x = pad_x4 - 10;
2489 						butMonsterMask->y = pad_y2 + spacing - 4;
2490 						butMonsterMask->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2491 						butMonsterMask->sizey = 16;
2492 						butMonsterMask->action = &buttonMonsterItems;
2493 						butMonsterMask->visible = 1;
2494 						butMonsterMask->focused = 1;
2495 					}
2496 
2497 					pad_y2 += spacing * 2;
2498 					itemIndex = 2;
2499 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2500 					{
2501 						strcpy(tmpStr, "NULL");
2502 					}
2503 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2504 					{
2505 						strcpy(tmpStr, "RAND");
2506 					}
2507 					else
2508 					{
2509 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2510 					}
2511 					if ( canWearEquip(selectedEntity, itemIndex) )
2512 					{
2513 						butMonsterShield = newButton();
2514 						strcpy(butMonsterShield->label, tmpStr);
2515 						butMonsterShield->x = pad_x4 - 10;
2516 						butMonsterShield->y = pad_y2 + spacing - 4;
2517 						butMonsterShield->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2518 						butMonsterShield->sizey = 16;
2519 						butMonsterShield->action = &buttonMonsterItems;
2520 						butMonsterShield->visible = 1;
2521 						butMonsterShield->focused = 1;
2522 					}
2523 
2524 					pad_x4 -= 64 * 2;
2525 					itemIndex = 1;
2526 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2527 					{
2528 						strcpy(tmpStr, "NULL");
2529 					}
2530 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2531 					{
2532 						strcpy(tmpStr, "RAND");
2533 					}
2534 					else
2535 					{
2536 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2537 					}
2538 					if ( canWearEquip(selectedEntity, itemIndex) )
2539 					{
2540 						butMonsterWeapon = newButton();
2541 						strcpy(butMonsterWeapon->label, tmpStr);
2542 						butMonsterWeapon->x = pad_x4 - 10;
2543 						butMonsterWeapon->y = pad_y2 + spacing - 4;
2544 						butMonsterWeapon->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2545 						butMonsterWeapon->sizey = 16;
2546 						butMonsterWeapon->action = &buttonMonsterItems;
2547 						butMonsterWeapon->visible = 1;
2548 						butMonsterWeapon->focused = 1;
2549 					}
2550 
2551 					pad_y2 += spacing * 2;
2552 					itemIndex = 5;
2553 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2554 					{
2555 						strcpy(tmpStr, "NULL");
2556 					}
2557 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2558 					{
2559 						strcpy(tmpStr, "RAND");
2560 					}
2561 					else
2562 					{
2563 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2564 					}
2565 
2566 					if ( canWearEquip(selectedEntity, itemIndex) )
2567 					{
2568 						butMonsterRing = newButton();
2569 						strcpy(butMonsterRing->label, tmpStr);
2570 						butMonsterRing->x = pad_x4 - 10;
2571 						butMonsterRing->y = pad_y2 + spacing - 4;
2572 						butMonsterRing->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2573 						butMonsterRing->sizey = 16;
2574 						butMonsterRing->action = &buttonMonsterItems;
2575 						butMonsterRing->visible = 1;
2576 						butMonsterRing->focused = 1;
2577 					}
2578 					pad_x4 += 64 * 2;
2579 					itemIndex = 9;
2580 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2581 					{
2582 						strcpy(tmpStr, "NULL");
2583 					}
2584 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2585 					{
2586 						strcpy(tmpStr, "RAND");
2587 					}
2588 					else
2589 					{
2590 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2591 					}
2592 					if ( canWearEquip(selectedEntity, itemIndex) )
2593 					{
2594 						butMonsterGloves = newButton();
2595 						strcpy(butMonsterGloves->label, tmpStr);
2596 						butMonsterGloves->x = pad_x4 - 10;
2597 						butMonsterGloves->y = pad_y2 + spacing - 4;
2598 						butMonsterGloves->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2599 						butMonsterGloves->sizey = 16;
2600 						butMonsterGloves->action = &buttonMonsterItems;
2601 						butMonsterGloves->visible = 1;
2602 						butMonsterGloves->focused = 1;
2603 					}
2604 
2605 					pad_y2 += 32 + spacing * 2;
2606 					itemIndex = 12;
2607 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2608 					{
2609 						strcpy(tmpStr, "NULL");
2610 					}
2611 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2612 					{
2613 						strcpy(tmpStr, "RAND");
2614 					}
2615 					else
2616 					{
2617 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2618 					}
2619 					butMonsterItem3 = newButton();
2620 					strcpy(butMonsterItem3->label, tmpStr);
2621 					butMonsterItem3->x = pad_x4 - 10;
2622 					butMonsterItem3->y = pad_y2 + spacing - 4;
2623 					butMonsterItem3->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2624 					butMonsterItem3->sizey = 16;
2625 					butMonsterItem3->action = &buttonMonsterItems;
2626 					butMonsterItem3->visible = 1;
2627 					butMonsterItem3->focused = 1;
2628 
2629 					itemIndex = 15;
2630 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2631 					{
2632 						strcpy(tmpStr, "NULL");
2633 					}
2634 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2635 					{
2636 						strcpy(tmpStr, "RAND");
2637 					}
2638 					else
2639 					{
2640 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2641 					}
2642 					butMonsterItem6 = newButton();
2643 					strcpy(butMonsterItem6->label, tmpStr);
2644 					butMonsterItem6->x = pad_x4 - 10;
2645 					butMonsterItem6->y = pad_y2 + 2 * spacing - 4;
2646 					butMonsterItem6->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2647 					butMonsterItem6->sizey = 16;
2648 					butMonsterItem6->action = &buttonMonsterItems;
2649 					butMonsterItem6->visible = 1;
2650 					butMonsterItem6->focused = 1;
2651 
2652 					pad_x4 -= 64;
2653 					itemIndex = 11;
2654 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2655 					{
2656 						strcpy(tmpStr, "NULL");
2657 					}
2658 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2659 					{
2660 						strcpy(tmpStr, "RAND");
2661 					}
2662 					else
2663 					{
2664 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2665 					}
2666 					butMonsterItem2 = newButton();
2667 					strcpy(butMonsterItem2->label, tmpStr);
2668 					butMonsterItem2->x = pad_x4 - 10;
2669 					butMonsterItem2->y = pad_y2 + spacing - 4;
2670 					butMonsterItem2->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2671 					butMonsterItem2->sizey = 16;
2672 					butMonsterItem2->action = &buttonMonsterItems;
2673 					butMonsterItem2->visible = 1;
2674 					butMonsterItem2->focused = 1;
2675 
2676 					itemIndex = 14;
2677 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2678 					{
2679 						strcpy(tmpStr, "NULL");
2680 					}
2681 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2682 					{
2683 						strcpy(tmpStr, "RAND");
2684 					}
2685 					else
2686 					{
2687 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2688 					}
2689 					butMonsterItem5 = newButton();
2690 					strcpy(butMonsterItem5->label, tmpStr);
2691 					butMonsterItem5->x = pad_x4 - 10;
2692 					butMonsterItem5->y = pad_y2 + 2 * spacing - 4;
2693 					butMonsterItem5->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2694 					butMonsterItem5->sizey = 16;
2695 					butMonsterItem5->action = &buttonMonsterItems;
2696 					butMonsterItem5->visible = 1;
2697 					butMonsterItem5->focused = 1;
2698 
2699 					pad_x4 -= 64;
2700 					itemIndex = 10;
2701 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2702 					{
2703 						strcpy(tmpStr, "NULL");
2704 					}
2705 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2706 					{
2707 						strcpy(tmpStr, "RAND");
2708 					}
2709 					else
2710 					{
2711 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2712 					}
2713 					butMonsterItem1 = newButton();
2714 					strcpy(butMonsterItem1->label, tmpStr);
2715 					butMonsterItem1->x = pad_x4 - 10;
2716 					butMonsterItem1->y = pad_y2 + spacing - 4;
2717 					butMonsterItem1->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2718 					butMonsterItem1->sizey = 16;
2719 					butMonsterItem1->action = &buttonMonsterItems;
2720 					butMonsterItem1->visible = 1;
2721 					butMonsterItem1->focused = 1;
2722 
2723 					itemIndex = 13;
2724 					if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 0 )
2725 					{
2726 						strcpy(tmpStr, "NULL");
2727 					}
2728 					else if ( tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES] == 1 )
2729 					{
2730 						strcpy(tmpStr, "RAND");
2731 					}
2732 					else
2733 					{
2734 						snprintf(tmpStr, 4, "%d", tmpSpriteStats->EDITOR_ITEMS[itemIndex * ITEM_SLOT_NUMPROPERTIES]);
2735 					}
2736 					butMonsterItem4 = newButton();
2737 					strcpy(butMonsterItem4->label, tmpStr);
2738 					butMonsterItem4->x = pad_x4 - 10;
2739 					butMonsterItem4->y = pad_y2 + 2 * spacing - 4;
2740 					butMonsterItem4->sizex = pad_x4 + pad_x3 - (pad_x4 - 10);
2741 					butMonsterItem4->sizey = 16;
2742 					butMonsterItem4->action = &buttonMonsterItems;
2743 					butMonsterItem4->visible = 1;
2744 					butMonsterItem4->focused = 1;
2745 				}
2746 				break;
2747 			case 3: //items
2748 				butItemOK = newButton();
2749 				strcpy(butItemOK->label, "  OK  ");
2750 				butItemOK->x = subx2 - 128;
2751 				butItemOK->y = suby2 - 24;
2752 				butItemOK->sizex = 56;
2753 				butItemOK->sizey = 16;
2754 				butItemOK->action = &buttonSpritePropertiesConfirm;
2755 				butItemOK->visible = 1;
2756 				butItemOK->focused = 1;
2757 
2758 				butItemCancel = newButton();
2759 				strcpy(butItemCancel->label, "Cancel");
2760 				butItemCancel->x = subx2 - 64;
2761 				butItemCancel->y = suby2 - 24;
2762 				butItemCancel->sizex = 56;
2763 				butItemCancel->sizey = 16;
2764 				butItemCancel->action = &buttonCloseSpriteSubwindow;
2765 				butItemCancel->visible = 1;
2766 				butItemCancel->focused = 1;
2767 
2768 				butItemX = newButton();
2769 				strcpy(butItemX->label, "X");
2770 				butItemX->x = subx2 - 16;
2771 				butItemX->y = suby1;
2772 				butItemX->sizex = 16;
2773 				butItemX->sizey = 16;
2774 				butItemX->action = &buttonCloseSpriteSubwindow;
2775 				butItemX->visible = 1;
2776 				butItemX->focused = 1;
2777 				break;
2778 			default:
2779 				button = newButton();
2780 				strcpy(button->label, "  OK  ");
2781 				button->x = subx2 - 64;
2782 				button->y = suby2 - 48;
2783 				button->sizex = 56;
2784 				button->sizey = 16;
2785 				button->action = &buttonSpritePropertiesConfirm;
2786 				button->visible = 1;
2787 				button->focused = 1;
2788 				break;
2789 		}
2790 
2791 		if ( spriteType != 1 && spriteType != 3 )
2792 		{
2793 			button = newButton();
2794 			strcpy(button->label, "Cancel");
2795 			button->x = subx2 - 64;
2796 			button->y = suby2 - 24;
2797 			button->sizex = 56;
2798 			button->sizey = 16;
2799 			button->action = &buttonCloseSpriteSubwindow;
2800 			button->visible = 1;
2801 			button->focused = 1;
2802 
2803 			button = newButton();
2804 			strcpy(button->label, "X");
2805 			button->x = subx2 - 16;
2806 			button->y = suby1;
2807 			button->sizex = 16;
2808 			button->sizey = 16;
2809 			button->action = &buttonCloseSpriteSubwindow;
2810 			button->visible = 1;
2811 			button->focused = 1;
2812 		}
2813 	}
2814 }
2815 
buttonSpritePropertiesConfirm(button_t * my)2816 void buttonSpritePropertiesConfirm(button_t* my)
2817 {
2818 	Stat* tmpSpriteStats = NULL;
2819 	button_t* button = NULL;
2820 	if ( selectedEntity != NULL )
2821 	{
2822 		int spriteType = checkSpriteType(selectedEntity->sprite);
2823 		switch ( spriteType )
2824 		{
2825 			case 1: //monsters
2826 				tmpSpriteStats = selectedEntity->getStats();
2827 				if ( tmpSpriteStats != nullptr )
2828 				{
2829 					if ( my == butMonsterItemOK )
2830 					{
2831 						if ( strcmp(spriteProperties[0], "0") < 0 )
2832 						{
2833 							strcpy(spriteProperties[0], "1");
2834 						}
2835 						tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES] = (Sint32)atoi(spriteProperties[0]);
2836 						tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 1] = (Sint32)atoi(spriteProperties[1]);
2837 						if ( strcmp(spriteProperties[2], "00") == 0 )
2838 						{
2839 							selectedEntity->skill[12] = 10; //bless random
2840 						}
2841 						else
2842 						{
2843 							tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 2] = (Sint32)atoi(spriteProperties[2]); //bless
2844 						}
2845 						if ( strcmp(spriteProperties[3], "0") == 0 )
2846 						{
2847 							tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 2] = 1; //reset quantity to 1
2848 						}
2849 						if ( strcmp(spriteProperties[3], "0") == 0 )
2850 						{
2851 							tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 3] = 1; //reset quantity to 1
2852 						}
2853 						else
2854 						{
2855 							tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 3] = (Sint32)atoi(spriteProperties[3]); //quantity
2856 						}
2857 						tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 4] = (Sint32)atoi(spriteProperties[4]);
2858 						tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 5] = (Sint32)atoi(spriteProperties[5]);
2859 						tmpSpriteStats->EDITOR_ITEMS[(itemSlotSelected)* ITEM_SLOT_NUMPROPERTIES + 6] = (Sint32)atoi(spriteProperties[6]);
2860 						newwindow = 2;
2861 
2862 						/*button = newButton();
2863 						strcpy(button->label, "Cancel");
2864 						button->x = subx2 - 64;
2865 						button->y = suby2 - 24;
2866 						button->sizex = 56;
2867 						button->sizey = 16;
2868 						button->action = &buttonCloseSpriteSubwindow;
2869 						button->visible = 1;
2870 						button->focused = 1;
2871 
2872 						button = newButton();
2873 						strcpy(button->label, "X");
2874 						button->x = subx2 - 16;
2875 						button->y = suby1;
2876 						button->sizex = 16;
2877 						button->sizey = 16;
2878 						button->action = &buttonCloseSpriteSubwindow;
2879 						button->visible = 1;
2880 						button->focused = 1;
2881 
2882 						button = newButton();
2883 						strcpy(button->label, "  OK  ");
2884 						button->x = subx2 - 64;
2885 						button->y = suby2 - 48;
2886 						button->sizex = 56;
2887 						button->sizey = 16;
2888 						button->action = &buttonSpritePropertiesConfirm;
2889 						button->visible = 1;
2890 						button->focused = 1;*/
2891 
2892 						//butItemOK->visible = 0;
2893 						//butItemCancel->visible = 0;
2894 						//butItemX->visible = 0;
2895 						if ( butMonsterItemOK != NULL )
2896 						{
2897 							butMonsterItemOK->visible = 0;
2898 						}
2899 						if ( butMonsterItemX != NULL )
2900 						{
2901 							butMonsterItemX->visible = 0;
2902 						}
2903 						if ( butMonsterItemCancel != NULL )
2904 						{
2905 							butMonsterItemCancel->visible = 0;
2906 						}
2907 
2908 						// retrieves any modified monster stats, restored when window is closed.
2909 
2910 						for ( int i = 0; i < sizeof(spriteProperties) / sizeof(spriteProperties[0]); i++ )
2911 						{
2912 							strcpy(spriteProperties[i], tmpSpriteProperties[i]);
2913 						}
2914 					}
2915 					else
2916 					{
2917 						strcpy(tmpSpriteStats->name, spriteProperties[0]);
2918 						tmpSpriteStats->MAXHP = (Sint32)atoi(spriteProperties[1]);
2919 						tmpSpriteStats->HP = (Sint32)atoi(spriteProperties[2]);
2920 						tmpSpriteStats->MAXMP = (Sint32)atoi(spriteProperties[3]);
2921 						tmpSpriteStats->MP = (Sint32)atoi(spriteProperties[4]);
2922 						tmpSpriteStats->LVL = (Sint32)atoi(spriteProperties[5]);
2923 						tmpSpriteStats->GOLD = (Sint32)atoi(spriteProperties[6]);
2924 						tmpSpriteStats->STR = (Sint32)atoi(spriteProperties[7]);
2925 						tmpSpriteStats->DEX = (Sint32)atoi(spriteProperties[8]);
2926 						tmpSpriteStats->CON = (Sint32)atoi(spriteProperties[9]);
2927 						tmpSpriteStats->INT = (Sint32)atoi(spriteProperties[10]);
2928 						tmpSpriteStats->PER = (Sint32)atoi(spriteProperties[11]);
2929 						tmpSpriteStats->CHR = (Sint32)atoi(spriteProperties[12]);
2930 
2931 						tmpSpriteStats->RANDOM_MAXHP = (Sint32)atoi(spriteProperties[13]) - tmpSpriteStats->MAXHP;
2932 						if ( tmpSpriteStats->RANDOM_MAXHP < 0 )
2933 						{
2934 							tmpSpriteStats->RANDOM_MAXHP = 0;
2935 						}
2936 						tmpSpriteStats->RANDOM_HP = (Sint32)atoi(spriteProperties[14]) - tmpSpriteStats->HP;
2937 						if ( tmpSpriteStats->RANDOM_HP < 0 )
2938 						{
2939 							tmpSpriteStats->RANDOM_HP = 0;
2940 						}
2941 						tmpSpriteStats->RANDOM_MAXMP = (Sint32)atoi(spriteProperties[15]) - tmpSpriteStats->MAXMP;
2942 						if ( tmpSpriteStats->RANDOM_MAXMP < 0 )
2943 						{
2944 							tmpSpriteStats->RANDOM_MAXMP = 0;
2945 						}
2946 						tmpSpriteStats->RANDOM_MP = (Sint32)atoi(spriteProperties[16]) - tmpSpriteStats->MP;
2947 						if ( tmpSpriteStats->RANDOM_MP < 0 )
2948 						{
2949 							tmpSpriteStats->RANDOM_MP = 0;
2950 						}
2951 						tmpSpriteStats->RANDOM_LVL = (Sint32)atoi(spriteProperties[17]) - tmpSpriteStats->LVL;
2952 						if ( tmpSpriteStats->RANDOM_LVL < 0 )
2953 						{
2954 							tmpSpriteStats->RANDOM_LVL = 0;
2955 						}
2956 						tmpSpriteStats->RANDOM_GOLD = (Sint32)atoi(spriteProperties[18]) - tmpSpriteStats->GOLD;
2957 						if ( tmpSpriteStats->RANDOM_GOLD < 0 )
2958 						{
2959 							tmpSpriteStats->RANDOM_GOLD = 0;
2960 						}
2961 						tmpSpriteStats->RANDOM_STR = (Sint32)atoi(spriteProperties[19]) - tmpSpriteStats->STR;
2962 						if ( tmpSpriteStats->RANDOM_STR < 0 )
2963 						{
2964 							tmpSpriteStats->RANDOM_STR = 0;
2965 						}
2966 						tmpSpriteStats->RANDOM_DEX = (Sint32)atoi(spriteProperties[20]) - tmpSpriteStats->DEX;
2967 						if ( tmpSpriteStats->RANDOM_DEX < 0 )
2968 						{
2969 							tmpSpriteStats->RANDOM_DEX = 0;
2970 						}
2971 						tmpSpriteStats->RANDOM_CON = (Sint32)atoi(spriteProperties[21]) - tmpSpriteStats->CON;
2972 						if ( tmpSpriteStats->RANDOM_CON < 0 )
2973 						{
2974 							tmpSpriteStats->RANDOM_CON = 0;
2975 						}
2976 						tmpSpriteStats->RANDOM_INT = (Sint32)atoi(spriteProperties[22]) - tmpSpriteStats->INT;
2977 						if ( tmpSpriteStats->RANDOM_INT < 0 )
2978 						{
2979 							tmpSpriteStats->RANDOM_INT = 0;
2980 						}
2981 						tmpSpriteStats->RANDOM_PER = (Sint32)atoi(spriteProperties[23]) - tmpSpriteStats->PER;
2982 						if ( tmpSpriteStats->RANDOM_PER < 0 )
2983 						{
2984 							tmpSpriteStats->RANDOM_PER = 0;
2985 						}
2986 						tmpSpriteStats->RANDOM_CHR = (Sint32)atoi(spriteProperties[24]) - tmpSpriteStats->CHR;
2987 						if ( tmpSpriteStats->RANDOM_CHR < 0 )
2988 						{
2989 							tmpSpriteStats->RANDOM_CHR = 0;
2990 						}
2991 						tmpSpriteStats->MISC_FLAGS[STAT_FLAG_NPC] = (Sint32)atoi(spriteProperties[25]);
2992 						if ( !strcmp(spriteProperties[31], "disable") )
2993 						{
2994 							tmpSpriteStats->MISC_FLAGS[STAT_FLAG_DISABLE_MINIBOSS] = 1;
2995 						}
2996 						else
2997 						{
2998 							tmpSpriteStats->MISC_FLAGS[STAT_FLAG_DISABLE_MINIBOSS] = 0;
2999 						}
3000 					}
3001 				}
3002 				break;
3003 			case 2: //chest
3004 				selectedEntity->yaw = (real_t)atoi(spriteProperties[0]);
3005 				selectedEntity->skill[9] = (Sint32)atoi(spriteProperties[1]);
3006 				selectedEntity->chestLocked = (Sint32)atoi(spriteProperties[2]);
3007 				break;
3008 			case 3: //items
3009 				if ( strcmp(spriteProperties[0], "0") == 0 )
3010 				{
3011 					strcpy(spriteProperties[0], "1");
3012 				}
3013 				selectedEntity->skill[10] = (Sint32)atoi(spriteProperties[0]); //id
3014 				selectedEntity->skill[11] = (Sint32)atoi(spriteProperties[1]); //status
3015 				if ( strcmp(spriteProperties[2], "00") == 0 )
3016 				{
3017 					selectedEntity->skill[12] = 10; //bless random
3018 				}
3019 				else
3020 				{
3021 					selectedEntity->skill[12] = (Sint32)atoi(spriteProperties[2]); //bless
3022 				}
3023 				if ( strcmp(spriteProperties[3], "0") == 0 )
3024 				{
3025 					selectedEntity->skill[13] = 1; //reset quantity to 1
3026 				}
3027 				else
3028 				{
3029 					selectedEntity->skill[13] = (Sint32)atoi(spriteProperties[3]); //quantity
3030 				}
3031 				selectedEntity->skill[15] = (Sint32)atoi(spriteProperties[4]); //identified
3032 				selectedEntity->skill[16] = (Sint32)atoi(spriteProperties[5]); //cateogry if random
3033 				break;
3034 			case 4: //summoning traps
3035 				if ( (Sint32)atoi(spriteProperties[0]) < -1 || (Sint32)atoi(spriteProperties[0]) == 6
3036 					|| (Sint32)atoi(spriteProperties[0]) == 12 || (Sint32)atoi(spriteProperties[0]) == 16 )
3037 				{
3038 					selectedEntity->skill[0] = 0;
3039 				}
3040 				else
3041 				{
3042 					selectedEntity->skill[0] = (Sint32)atoi(spriteProperties[0]); //Monster to Spawn
3043 				}
3044 
3045 				if ( (Sint32)atoi(spriteProperties[1]) == 0 )
3046 				{
3047 					selectedEntity->skill[1] = 1;
3048 				}
3049 				else
3050 				{
3051 					selectedEntity->skill[1] = (Sint32)atoi(spriteProperties[1]); //Qty
3052 				}
3053 
3054 				if ( (Sint32)atoi(spriteProperties[2]) == 0 )
3055 				{
3056 					selectedEntity->skill[2] = 1;
3057 				}
3058 				else
3059 				{
3060 					selectedEntity->skill[2] = (Sint32)atoi(spriteProperties[2]); //Time Between Spawns
3061 				}
3062 
3063 				if ( (Sint32)atoi(spriteProperties[3]) == 0 )
3064 				{
3065 					selectedEntity->skill[3] = 1;
3066 				}
3067 				else
3068 				{
3069 					selectedEntity->skill[3] = (Sint32)atoi(spriteProperties[3]); //Amount of Spawns
3070 				}
3071 				selectedEntity->skill[4] = (Sint32)atoi(spriteProperties[4]); //Requires Power
3072 				selectedEntity->skill[5] = (Sint32)atoi(spriteProperties[5]); //Chance to Stop Working
3073 				break;
3074 			case 5: //power crystal
3075 				selectedEntity->yaw = (real_t)atoi(spriteProperties[0]);
3076 				selectedEntity->crystalNumElectricityNodes = (Sint32)atoi(spriteProperties[1]);
3077 				selectedEntity->crystalTurnReverse = (Sint32)atoi(spriteProperties[2]);
3078 				selectedEntity->crystalSpellToActivate = (Sint32)atoi(spriteProperties[3]);
3079 				break;
3080 			case 6: //lever timer
3081 				if ( (Sint32)atoi(spriteProperties[0]) == 0 )
3082 				{
3083 					selectedEntity->leverTimerTicks = 1;
3084 				}
3085 				else
3086 				{
3087 					selectedEntity->leverTimerTicks = (Sint32)atoi(spriteProperties[0]);
3088 				}
3089 				break;
3090 			case 7: //boulder trap
3091 				selectedEntity->boulderTrapRefireAmount = (Sint32)atoi(spriteProperties[0]);
3092 				if ( (Sint32)atoi(spriteProperties[1]) < 2 )
3093 				{
3094 					selectedEntity->boulderTrapRefireDelay = 2;
3095 				}
3096 				else
3097 				{
3098 					selectedEntity->boulderTrapRefireDelay = (Sint32)atoi(spriteProperties[1]);
3099 				}
3100 				if ( (Sint32)atoi(spriteProperties[2]) < 0 )
3101 				{
3102 					selectedEntity->boulderTrapPreDelay = 0;
3103 				}
3104 				else
3105 				{
3106 					selectedEntity->boulderTrapPreDelay = (Sint32)atoi(spriteProperties[2]);
3107 				}
3108 				break;
3109 			case 8: //pedestal
3110 				selectedEntity->pedestalOrbType = (Sint32)atoi(spriteProperties[0]);
3111 				selectedEntity->pedestalHasOrb = (Sint32)atoi(spriteProperties[1]);
3112 				selectedEntity->pedestalInvertedPower = (Sint32)atoi(spriteProperties[2]);
3113 				selectedEntity->pedestalInGround = (Sint32)atoi(spriteProperties[3]);
3114 				selectedEntity->pedestalLockOrb = (Sint32)atoi(spriteProperties[4]);
3115 				break;
3116 			case 9: //teleporter
3117 				selectedEntity->teleporterX = (Sint32)atoi(spriteProperties[0]);
3118 				selectedEntity->teleporterY = (Sint32)atoi(spriteProperties[1]);
3119 				selectedEntity->teleporterType = (Sint32)atoi(spriteProperties[2]);
3120 				break;
3121 			case 10: //ceiling tile model
3122 				selectedEntity->ceilingTileModel = (Sint32)atoi(spriteProperties[0]);
3123 				break;
3124 			case 11: //spell trap ceiling
3125 				selectedEntity->spellTrapType = (Sint32)atoi(spriteProperties[0]);
3126 				selectedEntity->spellTrapRefire = (Sint32)atoi(spriteProperties[1]);
3127 				selectedEntity->spellTrapLatchPower = (Sint32)atoi(spriteProperties[2]);
3128 				selectedEntity->spellTrapFloorTile = (Sint32)atoi(spriteProperties[3]);
3129 				selectedEntity->spellTrapRefireRate = (Sint32)atoi(spriteProperties[4]);
3130 				break;
3131 			case 12: //furniture
3132 				selectedEntity->furnitureDir = (Sint32)atoi(spriteProperties[0]);
3133 				break;
3134 			case 13: //floor decoration
3135 			{
3136 				selectedEntity->floorDecorationModel = (Sint32)atoi(spriteProperties[0]);
3137 				selectedEntity->floorDecorationRotation = (Sint32)atoi(spriteProperties[1]);
3138 				selectedEntity->floorDecorationHeightOffset = (Sint32)atoi(spriteProperties[2]);
3139 				selectedEntity->floorDecorationXOffset = (Sint32)atoi(spriteProperties[3]);
3140 				selectedEntity->floorDecorationYOffset = (Sint32)atoi(spriteProperties[4]);
3141 
3142 				int totalChars = 0;
3143 				char checkChr = 'a';
3144 				const int kMaxCharacters = 192; // 4x48 char fields.
3145 				for ( int i = 8; i < 60 && totalChars < kMaxCharacters; ++i )
3146 				{
3147 					selectedEntity->skill[i] = 0;
3148 				}
3149 				for ( int i = 8; i < 60 && totalChars < kMaxCharacters; ++i )
3150 				{
3151 					if ( i == 28 ) // circuit_status
3152 					{
3153 						continue;
3154 					}
3155 					for ( int c = 0; c < 4; ++c )
3156 					{
3157 						if ( totalChars >= 144 )
3158 						{
3159 							selectedEntity->skill[i] |= (spriteProperties[8][totalChars - 144]) << (c * 8);
3160 							checkChr = spriteProperties[8][totalChars - 144];
3161 						}
3162 						else if ( totalChars >= 96 )
3163 						{
3164 							selectedEntity->skill[i] |= (spriteProperties[7][totalChars - 96]) << (c * 8);
3165 							checkChr = spriteProperties[7][totalChars - 96];
3166 						}
3167 						else if ( totalChars >= 48 )
3168 						{
3169 							selectedEntity->skill[i] |= (spriteProperties[6][totalChars - 48]) << (c * 8);
3170 							checkChr = spriteProperties[6][totalChars - 48];
3171 						}
3172 						else
3173 						{
3174 							selectedEntity->skill[i] |= (spriteProperties[5][totalChars]) << (c * 8);
3175 							checkChr = spriteProperties[5][totalChars];
3176 						}
3177 						if ( checkChr == '\0' )
3178 						{
3179 							totalChars += (48 - (totalChars % 48));
3180 						}
3181 						else
3182 						{
3183 							++totalChars;
3184 						}
3185 					}
3186 				}
3187 			}
3188 				break;
3189 			case 14: //sound source
3190 				selectedEntity->soundSourceToPlay = (Sint32)atoi(spriteProperties[0]);
3191 				selectedEntity->soundSourceVolume = (Sint32)atoi(spriteProperties[1]);
3192 				selectedEntity->soundSourceLatchOn = (Sint32)atoi(spriteProperties[2]);
3193 				selectedEntity->soundSourceDelay = (Sint32)atoi(spriteProperties[3]);
3194 				selectedEntity->soundSourceOrigin = (Sint32)atoi(spriteProperties[4]);
3195 				break;
3196 			case 15: //light source
3197 				selectedEntity->lightSourceAlwaysOn = (Sint32)atoi(spriteProperties[0]);
3198 				selectedEntity->lightSourceBrightness = (Sint32)atoi(spriteProperties[1]);
3199 				selectedEntity->lightSourceInvertPower = (Sint32)atoi(spriteProperties[2]);
3200 				selectedEntity->lightSourceLatchOn = (Sint32)atoi(spriteProperties[3]);
3201 				selectedEntity->lightSourceRadius = (Sint32)atoi(spriteProperties[4]);
3202 				selectedEntity->lightSourceFlicker = (Sint32)atoi(spriteProperties[5]);
3203 				selectedEntity->lightSourceDelay = (Sint32)atoi(spriteProperties[6]);
3204 				break;
3205 			case 16: // text source
3206 			{
3207 				Uint32 r = (Uint32)atoi(spriteProperties[0]);
3208 				Uint32 g = (Uint32)atoi(spriteProperties[1]);
3209 				Uint32 b = (Uint32)atoi(spriteProperties[2]);
3210 				selectedEntity->textSourceColorRGB = 0;
3211 				selectedEntity->textSourceColorRGB |= (r << 16);
3212 				selectedEntity->textSourceColorRGB |= (g << 8);
3213 				selectedEntity->textSourceColorRGB |= (b << 0);
3214 				selectedEntity->textSourceDelay = (Sint32)atoi(spriteProperties[8]);
3215 				selectedEntity->textSourceVariables4W = 0;
3216 				selectedEntity->textSourceVariables4W |= ((Sint32)atoi(spriteProperties[9]) & 0xFF) << 8;
3217 				int totalChars = 0;
3218 				char checkChr = 'a';
3219 				const int kMaxCharacters = 220; //55 skills, starting at 4 ending at 59, skipping 28. storing 4 chars each.
3220 				for ( int i = 4; i < 60 && totalChars < kMaxCharacters; ++i )
3221 				{
3222 					selectedEntity->skill[i] = 0;
3223 				}
3224 				for ( int i = 4; i < 60 && totalChars < kMaxCharacters; ++i )
3225 				{
3226 					if ( i == 28 ) // circuit_status
3227 					{
3228 						continue;
3229 					}
3230 					for ( int c = 0; c < 4; ++c )
3231 					{
3232 						if ( totalChars >= 192 )
3233 						{
3234 							selectedEntity->skill[i] |= (spriteProperties[7][totalChars - 192]) << (c * 8);
3235 							checkChr = spriteProperties[7][totalChars - 192];
3236 						}
3237 						else if ( totalChars >= 144 )
3238 						{
3239 							selectedEntity->skill[i] |= (spriteProperties[6][totalChars - 144]) << (c * 8);
3240 							checkChr = spriteProperties[6][totalChars - 144];
3241 						}
3242 						else if ( totalChars >= 96 )
3243 						{
3244 							selectedEntity->skill[i] |= (spriteProperties[5][totalChars - 96]) << (c * 8);
3245 							checkChr = spriteProperties[5][totalChars - 96];
3246 						}
3247 						else if ( totalChars >= 48 )
3248 						{
3249 							selectedEntity->skill[i] |= (spriteProperties[4][totalChars - 48]) << (c * 8);
3250 							checkChr = spriteProperties[4][totalChars - 48];
3251 						}
3252 						else
3253 						{
3254 							selectedEntity->skill[i] |= (spriteProperties[3][totalChars]) << (c * 8);
3255 							checkChr = spriteProperties[3][totalChars];
3256 						}
3257 						if ( checkChr == '\0' )
3258 						{
3259 							totalChars += (48 - (totalChars % 48));
3260 						}
3261 						else
3262 						{
3263 							++totalChars;
3264 						}
3265 					}
3266 				}
3267 				break;
3268 			}
3269 			case 17:
3270 				selectedEntity->signalInputDirection = (Sint32)atoi(spriteProperties[0]);
3271 				selectedEntity->signalActivateDelay = (Sint32)atoi(spriteProperties[1]);
3272 				selectedEntity->signalTimerInterval = (Sint32)atoi(spriteProperties[2]);
3273 				selectedEntity->signalTimerRepeatCount = (Sint32)atoi(spriteProperties[3]);
3274 				selectedEntity->signalTimerLatchInput = (Sint32)atoi(spriteProperties[4]);
3275 				break;
3276 			case 18: // custom portal
3277 			{
3278 				selectedEntity->portalCustomSprite = (Sint32)atoi(spriteProperties[0]);
3279 				selectedEntity->portalCustomSpriteAnimationFrames = (Sint32)atoi(spriteProperties[1]);
3280 				selectedEntity->portalCustomZOffset = (Sint32)atoi(spriteProperties[2]);
3281 				selectedEntity->portalCustomLevelsToJump = (Sint32)atoi(spriteProperties[3]);
3282 				selectedEntity->portalCustomRequiresPower = (Sint32)atoi(spriteProperties[5]);
3283 				int isSecret = (Sint32)atoi(spriteProperties[6]);
3284 				selectedEntity->portalNotSecret = isSecret ? 0 : 1;
3285 
3286 				int totalChars = 0;
3287 				char checkChr = 'a';
3288 				const int kMaxCharacters = 32;
3289 				for ( int i = 11; i <= 18 && totalChars < kMaxCharacters; ++i )
3290 				{
3291 					selectedEntity->skill[i] = 0;
3292 				}
3293 				for ( int i = 11; i <= 18 && totalChars < kMaxCharacters; ++i )
3294 				{
3295 					if ( i == 28 ) // circuit_status
3296 					{
3297 						continue;
3298 					}
3299 					for ( int c = 0; c < 4; ++c )
3300 					{
3301 						selectedEntity->skill[i] |= (spriteProperties[4][totalChars]) << (c * 8);
3302 						checkChr = spriteProperties[4][totalChars];
3303 						++totalChars;
3304 					}
3305 				}
3306 			}
3307 				break;
3308 			case 19: // tables
3309 				selectedEntity->furnitureDir = (Sint32)atoi(spriteProperties[0]);
3310 				selectedEntity->furnitureTableSpawnChairs = (Sint32)atoi(spriteProperties[1]);
3311 				selectedEntity->furnitureTableRandomItemChance = (Sint32)atoi(spriteProperties[2]);
3312 				break;
3313 			case 20: // readablebook
3314 			{
3315 				selectedEntity->skill[11] = (Sint32)atoi(spriteProperties[0]); // status
3316 				if ( strcmp(spriteProperties[1], "00") == 0 )
3317 				{
3318 					selectedEntity->skill[12] = 10; //bless random
3319 				}
3320 				else
3321 				{
3322 					selectedEntity->skill[12] = (Sint32)atoi(spriteProperties[1]); //bless
3323 				}
3324 				selectedEntity->skill[15] = (Sint32)atoi(spriteProperties[2]); // identified
3325 				int totalChars = 0;
3326 				char checkChr = 'a';
3327 				const int kMaxCharacters = 48;
3328 				for ( int i = 40; i <= 52 && totalChars < kMaxCharacters; ++i )
3329 				{
3330 					selectedEntity->skill[i] = 0;
3331 				}
3332 				for ( int i = 40; i <= 52 && totalChars < kMaxCharacters; ++i )
3333 				{
3334 					if ( i == 28 ) // circuit_status
3335 					{
3336 						continue;
3337 					}
3338 					for ( int c = 0; c < 4; ++c )
3339 					{
3340 						selectedEntity->skill[i] |= (spriteProperties[3][totalChars]) << (c * 8);
3341 						checkChr = spriteProperties[3][totalChars];
3342 						++totalChars;
3343 					}
3344 				}
3345 			}
3346 				break;
3347 			case 21: // doors
3348 				selectedEntity->doorForceLockedUnlocked = (Sint32)atoi(spriteProperties[0]);
3349 				selectedEntity->doorDisableLockpicks = (Sint32)atoi(spriteProperties[1]);
3350 				selectedEntity->doorDisableOpening = (Sint32)atoi(spriteProperties[2]);
3351 				break;
3352 			case 22: // gates
3353 				selectedEntity->gateDisableOpening = (Sint32)atoi(spriteProperties[0]);
3354 				break;
3355 			case 23: // player spawn
3356 				selectedEntity->playerStartDir = (Sint32)atoi(spriteProperties[0]);
3357 				break;
3358 			default:
3359 				break;
3360 		}
3361 
3362 		strcpy(message, "                 Modified sprite properties.");
3363 		messagetime = 60;
3364 	}
3365 
3366 	if ( my == butMonsterItemOK && tmpSpriteStats != NULL )
3367 	{
3368 		//copyMonsterStatToPropertyStrings(tmpSpriteStats);
3369 		exitFromItemWindow = true;
3370 		inputstr = spriteProperties[0];
3371 		initMonsterPropertiesWindow();
3372 
3373 		buttonSpriteProperties(my);
3374 		itemSlotSelected = -1;
3375 	}
3376 	else
3377 	{
3378 		if ( my == butMonsterOK )
3379 		{
3380 			makeUndo();
3381 		}
3382 		buttonCloseSpriteSubwindow(my);
3383 	}
3384 }
3385 
buttonCloseSpriteSubwindow(button_t * my)3386 void buttonCloseSpriteSubwindow(button_t* my)
3387 {
3388 	Stat* tmpSpriteStats = NULL;
3389 	// close window
3390 	if ( my == butMonsterItemCancel || my == butMonsterItemX )
3391 	{
3392 		if ( selectedEntity != NULL )
3393 		{
3394 			tmpSpriteStats = selectedEntity->getStats();
3395 		}
3396 		if ( tmpSpriteStats != NULL )
3397 		{
3398 			//copyMonsterStatToPropertyStrings(tmpSpriteStats);
3399 			exitFromItemWindow = true;
3400 			inputstr = spriteProperties[0];
3401 			initMonsterPropertiesWindow();
3402 
3403 			buttonSpriteProperties(my);
3404 			itemSlotSelected = -1;
3405 			if ( butMonsterItemOK != NULL )
3406 			{
3407 				butMonsterItemOK->visible = 0;
3408 			}
3409 			if ( butMonsterItemX != NULL )
3410 			{
3411 				butMonsterItemX->visible = 0;
3412 			}
3413 			if ( butMonsterItemCancel != NULL )
3414 			{
3415 				butMonsterItemCancel->visible = 0;
3416 			}
3417 		}
3418 	}
3419 	else {
3420 		selectedEntity = NULL;
3421 		newwindow = 0;
3422 		subwindow = 0;
3423 		editproperty = 0;
3424 		spritepalette = 0;
3425 	}
3426 }
3427 
buttonMonsterItems(button_t * my)3428 void buttonMonsterItems(button_t* my)
3429 {
3430 	int spacing = 20;
3431 	int pad_y2 = suby1 + 28 + 2 * spacing;
3432 	int pad_x3 = 40;
3433 	int pad_x4 = subx2 - 112;
3434 	char tmpStr[32] = "";
3435 	button_t* button = NULL;
3436 
3437 	itemSelect = 0;
3438 
3439 	inputstr = spriteProperties[0];
3440 	cursorflash = ticks;
3441 	menuVisible = 0;
3442 	subwindow = 1;
3443 	slidery = 0;
3444 	subx1 = xres / 2 - 200;
3445 	subx2 = xres / 2 + 200;
3446 	suby1 = yres / 2 - 158;
3447 	suby2 = yres / 2 + 158;
3448 	strcpy(subtext, "Monster Item Properties:");
3449 
3450 	Stat* tmpSpriteStats = selectedEntity->getStats();
3451 
3452 	// stores any modified monster stats, to be restored when window is closed.
3453 
3454 	for ( int i = 0; i < sizeof(spriteProperties) / sizeof(spriteProperties[0]); i++ )
3455 	{
3456 		strcpy(tmpSpriteProperties[i], spriteProperties[i]);
3457 	}
3458 
3459 	if ( my == butMonsterHelm )
3460 	{
3461 		itemSlotSelected = 0;
3462 	}
3463 	else if ( my == butMonsterWeapon )
3464 	{
3465 		itemSlotSelected = 1;
3466 	}
3467 	else if ( my == butMonsterShield )
3468 	{
3469 		itemSlotSelected = 2;
3470 	}
3471 	else if ( my == butMonsterArmor )
3472 	{
3473 		itemSlotSelected = 3;
3474 	}
3475 	else if ( my == butMonsterBoots )
3476 	{
3477 		itemSlotSelected = 4;
3478 	}
3479 	else if ( my == butMonsterRing )
3480 	{
3481 		itemSlotSelected = 5;
3482 	}
3483 	else if ( my == butMonsterAmulet )
3484 	{
3485 		itemSlotSelected = 6;
3486 	}
3487 	else if ( my == butMonsterCloak )
3488 	{
3489 		itemSlotSelected = 7;
3490 	}
3491 	else if ( my == butMonsterMask )
3492 	{
3493 		itemSlotSelected = 8;
3494 	}
3495 	else if ( my == butMonsterGloves )
3496 	{
3497 		itemSlotSelected = 9;
3498 	}
3499 	else if ( my == butMonsterItem1 )
3500 	{
3501 		itemSlotSelected = 10;
3502 	}
3503 	else if ( my == butMonsterItem2 )
3504 	{
3505 		itemSlotSelected = 11;
3506 	}
3507 	else if ( my == butMonsterItem3 )
3508 	{
3509 		itemSlotSelected = 12;
3510 	}
3511 	else if ( my == butMonsterItem4 )
3512 	{
3513 		itemSlotSelected = 13;
3514 	}
3515 	else if ( my == butMonsterItem5 )
3516 	{
3517 		itemSlotSelected = 14;
3518 	}
3519 	else if ( my == butMonsterItem6 )
3520 	{
3521 		itemSlotSelected = 15;
3522 	}
3523 	else
3524 	{
3525 		itemSlotSelected = -1;
3526 	}
3527 
3528 	newwindow = 5;
3529 
3530 
3531 	if ( butMonsterHelm != NULL )
3532 	{
3533 		butMonsterHelm->visible = 0;
3534 	}
3535 	if ( butMonsterWeapon != NULL )
3536 	{
3537 		butMonsterWeapon->visible = 0;
3538 	}
3539 	if ( butMonsterShield != NULL )
3540 	{
3541 		butMonsterShield->visible = 0;
3542 	}
3543 	if ( butMonsterArmor != NULL )
3544 	{
3545 		butMonsterArmor->visible = 0;
3546 	}
3547 	if ( butMonsterRing != NULL )
3548 	{
3549 		butMonsterRing->visible = 0;
3550 	}
3551 	if ( butMonsterAmulet != NULL )
3552 	{
3553 		butMonsterAmulet->visible = 0;
3554 	}
3555 	if ( butMonsterBoots != NULL )
3556 	{
3557 		butMonsterBoots->visible = 0;
3558 	}
3559 	if ( butMonsterCloak != NULL )
3560 	{
3561 		butMonsterCloak->visible = 0;
3562 	}
3563 	if ( butMonsterMask != NULL )
3564 	{
3565 		butMonsterMask->visible = 0;
3566 	}
3567 	if ( butMonsterGloves != NULL )
3568 	{
3569 		butMonsterGloves->visible = 0;
3570 	}
3571 	if ( butMonsterItem1 != NULL )
3572 	{
3573 		butMonsterItem1->visible = 0;
3574 	}
3575 	if ( butMonsterItem2 != NULL )
3576 	{
3577 		butMonsterItem2->visible = 0;
3578 	}
3579 	if ( butMonsterItem3 != NULL )
3580 	{
3581 		butMonsterItem3->visible = 0;
3582 	}
3583 	if ( butMonsterItem4 != NULL )
3584 	{
3585 		butMonsterItem4->visible = 0;
3586 	}
3587 	if ( butMonsterItem5 != NULL )
3588 	{
3589 		butMonsterItem5->visible = 0;
3590 	}
3591 	if ( butMonsterItem6 != NULL )
3592 	{
3593 		butMonsterItem6->visible = 0;
3594 	}
3595 	if ( butMonsterOK != NULL )
3596 	{
3597 		butMonsterOK->visible = 0;
3598 	}
3599 	if ( butMonsterCancel != NULL )
3600 	{
3601 		butMonsterCancel->visible = 0;
3602 	}
3603 	if ( butMonsterX != NULL )
3604 	{
3605 		butMonsterX->visible = 0;
3606 	}
3607 	snprintf(spriteProperties[0], 5, "%d", tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 0]);
3608 	snprintf(spriteProperties[1], 5, "%d", tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 1]);
3609 	if ( (int)tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 2] == 10 )
3610 	{
3611 		strcpy(spriteProperties[2], "00"); //bless random
3612 	}
3613 	else
3614 	{
3615 		snprintf(spriteProperties[2], 4, "%d", (int)tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 2]); //bless
3616 	}
3617 	snprintf(spriteProperties[3], 5, "%d", tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 3]);
3618 	snprintf(spriteProperties[4], 5, "%d", tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 4]);
3619 	snprintf(spriteProperties[5], 5, "%d", tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 5]);
3620 	snprintf(spriteProperties[6], 5, "%d", tmpSpriteStats->EDITOR_ITEMS[itemSlotSelected * ITEM_SLOT_NUMPROPERTIES + 6]);
3621 
3622 	butMonsterItemOK = newButton();
3623 	strcpy(butMonsterItemOK->label, "  OK  ");
3624 	butMonsterItemOK->x = subx2 - 128;
3625 	butMonsterItemOK->y = suby2 - 24;
3626 	butMonsterItemOK->sizex = 56;
3627 	butMonsterItemOK->sizey = 16;
3628 	butMonsterItemOK->action = &buttonSpritePropertiesConfirm;
3629 	butMonsterItemOK->visible = 1;
3630 	butMonsterItemOK->focused = 1;
3631 
3632 	butMonsterItemCancel = newButton();
3633 	strcpy(butMonsterItemCancel->label, "Cancel");
3634 	butMonsterItemCancel->x = subx2 - 64;
3635 	butMonsterItemCancel->y = suby2 - 24;
3636 	butMonsterItemCancel->sizex = 56;
3637 	butMonsterItemCancel->sizey = 16;
3638 	butMonsterItemCancel->action = &buttonCloseSpriteSubwindow;
3639 	butMonsterItemCancel->visible = 1;
3640 	butMonsterItemCancel->focused = 1;
3641 
3642 	butMonsterItemX = newButton();
3643 	strcpy(butMonsterItemX->label, "X");
3644 	butMonsterItemX->x = subx2 - 16;
3645 	butMonsterItemX->y = suby1;
3646 	butMonsterItemX->sizex = 16;
3647 	butMonsterItemX->sizey = 16;
3648 	butMonsterItemX->action = &buttonCloseSpriteSubwindow;
3649 	butMonsterItemX->visible = 1;
3650 	butMonsterItemX->focused = 1;
3651 }
3652 
initMonsterPropertiesWindow()3653 void initMonsterPropertiesWindow() {
3654 	cursorflash = ticks;
3655 	menuVisible = 0;
3656 	subwindow = 1;
3657 	newwindow = 2;
3658 	subx1 = xres / 2 - 200;
3659 	subx2 = xres / 2 + 200;
3660 	suby1 = yres / 2 - 190;
3661 	suby2 = yres / 2 + 190;
3662 	strcpy(subtext, "Sprite properties: ");
3663 	strcat(subtext, spriteEditorNameStrings[selectedEntity->sprite]);
3664 }
3665 
copyMonsterStatToPropertyStrings(Stat * tmpSpriteStats)3666 void copyMonsterStatToPropertyStrings(Stat* tmpSpriteStats)
3667 {
3668 	if ( tmpSpriteStats != NULL )
3669 	{
3670 		strcpy(spriteProperties[0], tmpSpriteStats->name);
3671 		snprintf(spriteProperties[1], 5, "%d", tmpSpriteStats->MAXHP);
3672 		snprintf(spriteProperties[2], 5, "%d", tmpSpriteStats->HP);
3673 		snprintf(spriteProperties[3], 5, "%d", tmpSpriteStats->MAXMP);
3674 		snprintf(spriteProperties[4], 5, "%d", tmpSpriteStats->MP);
3675 		snprintf(spriteProperties[5], 4, "%d", tmpSpriteStats->LVL);
3676 		snprintf(spriteProperties[6], 4, "%d", tmpSpriteStats->GOLD);
3677 		snprintf(spriteProperties[7], 4, "%d", tmpSpriteStats->STR);
3678 		snprintf(spriteProperties[8], 4, "%d", tmpSpriteStats->DEX);
3679 		snprintf(spriteProperties[9], 4, "%d", tmpSpriteStats->CON);
3680 		snprintf(spriteProperties[10], 4, "%d", tmpSpriteStats->INT);
3681 		snprintf(spriteProperties[11], 4, "%d", tmpSpriteStats->PER);
3682 		snprintf(spriteProperties[12], 4, "%d", tmpSpriteStats->CHR);
3683 		snprintf(spriteProperties[13], 5, "%d", tmpSpriteStats->RANDOM_MAXHP + tmpSpriteStats->MAXHP);
3684 		snprintf(spriteProperties[14], 5, "%d", tmpSpriteStats->RANDOM_HP + tmpSpriteStats->HP);
3685 		snprintf(spriteProperties[15], 5, "%d", tmpSpriteStats->RANDOM_MAXMP + tmpSpriteStats->MAXMP);
3686 		snprintf(spriteProperties[16], 5, "%d", tmpSpriteStats->RANDOM_MP + tmpSpriteStats->MP);
3687 		snprintf(spriteProperties[17], 4, "%d", tmpSpriteStats->RANDOM_LVL + tmpSpriteStats->LVL);
3688 		snprintf(spriteProperties[18], 4, "%d", tmpSpriteStats->RANDOM_GOLD + tmpSpriteStats->GOLD);
3689 		snprintf(spriteProperties[19], 4, "%d", tmpSpriteStats->RANDOM_STR + tmpSpriteStats->STR);
3690 		snprintf(spriteProperties[20], 4, "%d", tmpSpriteStats->RANDOM_DEX + tmpSpriteStats->DEX);
3691 		snprintf(spriteProperties[21], 4, "%d", tmpSpriteStats->RANDOM_CON + tmpSpriteStats->CON);
3692 		snprintf(spriteProperties[22], 4, "%d", tmpSpriteStats->RANDOM_INT + tmpSpriteStats->INT);
3693 		snprintf(spriteProperties[23], 4, "%d", tmpSpriteStats->RANDOM_PER + tmpSpriteStats->PER);
3694 		snprintf(spriteProperties[24], 4, "%d", tmpSpriteStats->RANDOM_CHR + tmpSpriteStats->CHR);
3695 		snprintf(spriteProperties[25], 4, "%d", tmpSpriteStats->MISC_FLAGS[STAT_FLAG_NPC]);
3696 		if ( tmpSpriteStats->MISC_FLAGS[STAT_FLAG_DISABLE_MINIBOSS] == 0 )
3697 		{
3698 			strcpy(spriteProperties[31], "");
3699 		}
3700 		else
3701 		{
3702 			strcpy(spriteProperties[31], "disable");
3703 		}
3704 	}
3705 	return;
3706 }
3707