1 //------------------------------------------------------------------------
2 //  LEVEL LOAD / SAVE / NEW
3 //------------------------------------------------------------------------
4 //
5 //  Eureka DOOM Editor
6 //
7 //  Copyright (C) 2001-2019 Andrew Apted
8 //  Copyright (C)      2015 Ioan Chera
9 //  Copyright (C) 1997-2003 Andr� Majorel et al
10 //
11 //  This program is free software; you can redistribute it and/or
12 //  modify it under the terms of the GNU General Public License
13 //  as published by the Free Software Foundation; either version 2
14 //  of the License, or (at your option) any later version.
15 //
16 //  This program is distributed in the hope that it will be useful,
17 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 //  GNU General Public License for more details.
20 //
21 //------------------------------------------------------------------------
22 //
23 //  Based on Yadex which incorporated code from DEU 5.21 that was put
24 //  in the public domain in 1994 by Rapha�l Quinet and Brendon Wyber.
25 //
26 //------------------------------------------------------------------------
27 
28 #include "main.h"
29 
30 #include "lib_adler.h"
31 
32 #include "e_basis.h"
33 #include "e_checks.h"
34 #include "e_main.h"  // CalculateLevelBounds()
35 #include "m_config.h"
36 #include "m_files.h"
37 #include "m_loadsave.h"
38 #include "m_nodes.h"
39 #include "m_udmf.h"
40 #include "r_subdiv.h"
41 #include "w_rawdef.h"
42 #include "w_wad.h"
43 
44 #include "ui_window.h"
45 #include "ui_file.h"
46 
47 
48 int last_given_file;
49 
50 
51 // this is only used to prevent a M_SaveMap which happens inside
52 // CMD_BuildAllNodes from building that saved level twice.
53 bool inhibit_node_build;
54 
55 
56 static void SaveLevel(const char *level);
57 
58 static const char * overwrite_message =
59 	"The %s PWAD already contains this map.  "
60 	"This operation will destroy that map (overwrite it)."
61 	"\n\n"
62 	"Are you sure you want to continue?";
63 
64 
RemoveEditWad()65 void RemoveEditWad()
66 {
67 	if (! edit_wad)
68 		return;
69 
70 	MasterDir_Remove(edit_wad);
71 	delete edit_wad;
72 
73 	edit_wad  = NULL;
74 	Pwad_name = NULL;
75 }
76 
77 
ReplaceEditWad(Wad_file * new_wad)78 static void ReplaceEditWad(Wad_file *new_wad)
79 {
80 	RemoveEditWad();
81 
82 	edit_wad = new_wad;
83 
84 	Pwad_name = edit_wad->PathName();
85 
86 	MasterDir_Add(edit_wad);
87 }
88 
89 
FreshLevel()90 static void FreshLevel()
91 {
92 	BA_ClearAll();
93 
94 	Sector *sec = new Sector;
95 	Sectors.push_back(sec);
96 
97 	sec->SetDefaults();
98 
99 	for (int i = 0 ; i < 4 ; i++)
100 	{
101 		Vertex *v = new Vertex;
102 		Vertices.push_back(v);
103 
104 		v->SetRawX((i >= 2) ? 256 : -256);
105 		v->SetRawY((i==1 || i==2) ? 256 :-256);
106 
107 		SideDef *sd = new SideDef;
108 		SideDefs.push_back(sd);
109 
110 		sd->SetDefaults(false);
111 
112 		LineDef *ld = new LineDef;
113 		LineDefs.push_back(ld);
114 
115 		ld->start = i;
116 		ld->end   = (i+1) % 4;
117 		ld->flags = MLF_Blocking;
118 		ld->right = i;
119 	}
120 
121 	for (int pl = 1 ; pl <= 4 ; pl++)
122 	{
123 		Thing *th = new Thing;
124 		Things.push_back(th);
125 
126 		th->type  = pl;
127 		th->angle = 90;
128 
129 		th->SetRawX((pl == 1) ? 0 : (pl - 3) * 48);
130 		th->SetRawY((pl == 1) ? 48 : (pl == 3) ? -48 : 0);
131 	}
132 
133 	CalculateLevelBounds();
134 
135 	ZoomWholeMap();
136 
137 	Editor_DefaultState();
138 }
139 
140 
Project_AskFile(char * filename)141 static bool Project_AskFile(char *filename)
142 {
143 	// this returns false if user cancelled
144 
145 	Fl_Native_File_Chooser chooser;
146 
147 	chooser.title("Pick file to create");
148 	chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
149 	chooser.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM);
150 	chooser.filter("Wads\t*.wad");
151 	chooser.directory(Main_FileOpFolder());
152 
153 	// Show native chooser
154 	switch (chooser.show())
155 	{
156 		case -1:
157 			LogPrintf("New Project: error choosing file:\n");
158 			LogPrintf("   %s\n", chooser.errmsg());
159 
160 			DLG_Notify("Unable to create a new project:\n\n%s", chooser.errmsg());
161 			return false;
162 
163 		case 1:
164 			LogPrintf("New Project: cancelled by user\n");
165 			return false;
166 
167 		default:
168 			break;  // OK
169 	}
170 
171 	// if extension is missing, add ".wad"
172 
173 	strcpy(filename, chooser.filename());
174 
175 	char *pos = (char *)fl_filename_ext(filename);
176 	if (! *pos)
177 		strcat(filename, ".wad");
178 
179 	return true;
180 }
181 
182 
Project_ApplyChanges(UI_ProjectSetup * dialog)183 void Project_ApplyChanges(UI_ProjectSetup *dialog)
184 {
185 	// grab the new information
186 
187 	Game_name = StringDup(dialog->game);
188 	Port_name = StringDup(dialog->port);
189 
190 	SYS_ASSERT(Game_name);
191 
192 	Iwad_name = StringDup(M_QueryKnownIWAD(Game_name));
193 	SYS_ASSERT(Iwad_name);
194 
195 	Level_format = dialog->map_format;
196 	Udmf_namespace = dialog->name_space;
197 
198 	SYS_ASSERT(Level_format != MAPF_INVALID);
199 
200 	Resource_list.clear();
201 
202 	for (int i = 0 ; i < UI_ProjectSetup::RES_NUM ; i++)
203 	{
204 		if (dialog->res[i])
205 			Resource_list.push_back(StringDup(dialog->res[i]));
206 	}
207 
208 	Fl::wait(0.1);
209 
210 	Main_LoadResources();
211 
212 	Fl::wait(0.1);
213 }
214 
215 
CMD_ManageProject()216 void CMD_ManageProject()
217 {
218 	UI_ProjectSetup * dialog = new UI_ProjectSetup(false /* new_project */, false /* is_startup */);
219 
220 	bool ok = dialog->Run();
221 
222 	if (ok)
223 	{
224 		Project_ApplyChanges(dialog);
225 	}
226 
227 	delete dialog;
228 }
229 
230 
CMD_NewProject()231 void CMD_NewProject()
232 {
233 	if (! Main_ConfirmQuit("create a new project"))
234 		return;
235 
236 
237 	/* first, ask for the output file */
238 
239 	char filename[FL_PATH_MAX];
240 
241 	if (! Project_AskFile(filename))
242 		return;
243 
244 
245 	/* second, query what Game, Port and Resources to use */
246 
247 	UI_ProjectSetup * dialog = new UI_ProjectSetup(true /* new_project */, false /* is_startup */);
248 
249 	bool ok = dialog->Run();
250 
251 	if (! ok)
252 	{
253 		delete dialog;
254 		return;
255 	}
256 
257 
258 	/* third, delete file if it already exists
259 	   [ the file chooser should have asked for confirmation ]
260 	 */
261 
262 	if (FileExists(filename))
263 	{
264 		// TODO??  M_BackupWad(wad);
265 
266 		if (! FileDelete(filename))
267 		{
268 			DLG_Notify("Unable to delete the existing file.");
269 
270 			delete dialog;
271 			return;
272 		}
273 
274 		Fl::wait(0.1);
275 		Fl::wait(0.1);
276 	}
277 
278 
279 	RemoveEditWad();
280 
281 	// this calls Main_LoadResources which resets the master directory
282 	Project_ApplyChanges(dialog);
283 
284 	delete dialog;
285 
286 
287 	// determine map name (same as first level in the IWAD)
288 	const char *map_name = "MAP01";
289 
290 	short idx = game_wad->LevelFindFirst();
291 
292 	if (idx >= 0)
293 	{
294 		idx = game_wad->LevelHeader(idx);
295 		map_name = game_wad->GetLump(idx)->Name();
296 	}
297 
298 	LogPrintf("Creating New File : %s in %s\n", map_name, filename);
299 
300 
301 	Wad_file * wad = Wad_file::Open(filename, 'w');
302 
303 	if (! wad)
304 	{
305 		DLG_Notify("Unable to create the new WAD file.");
306 		return;
307 	}
308 
309 	edit_wad = wad;
310 	Pwad_name = edit_wad->PathName();
311 
312 	MasterDir_Add(edit_wad);
313 
314 
315 	FreshLevel();
316 
317 	// save it now : sets Level_name and window title
318 	SaveLevel(map_name);
319 }
320 
321 
MissingIWAD_Dialog()322 bool MissingIWAD_Dialog()
323 {
324 	UI_ProjectSetup * dialog = new UI_ProjectSetup(false /* new_project */, true /* is_startup */);
325 
326 	bool ok = dialog->Run();
327 
328 	if (ok)
329 	{
330 		Game_name = StringDup(dialog->game);
331 		SYS_ASSERT(Game_name);
332 
333 		Iwad_name = StringDup(M_QueryKnownIWAD(Game_name));
334 		SYS_ASSERT(Iwad_name);
335 	}
336 
337 	delete dialog;
338 
339 	return ok;
340 }
341 
342 
CMD_FreshMap()343 void CMD_FreshMap()
344 {
345 	if (! edit_wad)
346 	{
347 		DLG_Notify("Cannot create a fresh map unless editing a PWAD.");
348 		return;
349 	}
350 
351 	if (edit_wad->IsReadOnly())
352 	{
353 		DLG_Notify("Cannot create a fresh map : file is read-only.");
354 		return;
355 	}
356 
357 	if (! Main_ConfirmQuit("create a fresh map"))
358 		return;
359 
360 
361 	UI_ChooseMap * dialog = new UI_ChooseMap(Level_name);
362 
363 	dialog->PopulateButtons(toupper(Level_name[0]), edit_wad);
364 
365 	const char *map_name = dialog->Run();
366 
367 	delete dialog;
368 
369 	// cancelled?
370 	if (! map_name)
371 		return;
372 
373 	// would this replace an existing map?
374 	if (edit_wad->LevelFind(map_name) >= 0)
375 	{
376 		if (DLG_Confirm("Cancel|&Overwrite",
377 		                overwrite_message, "current") <= 0)
378 		{
379 			return;
380 		}
381 	}
382 
383 
384 	M_BackupWad(edit_wad);
385 
386 	LogPrintf("Created NEW map : %s\n", map_name);
387 
388 	FreshLevel();
389 
390 	// save it now : sets Level_name and window title
391 	SaveLevel(map_name);
392 }
393 
394 
395 //------------------------------------------------------------------------
396 //  LOADING CODE
397 //------------------------------------------------------------------------
398 
399 static Wad_file * load_wad;
400 
401 // TODO ideally static, but needed by m_udmf.cc too
402 short loading_level;
403 
404 static int bad_linedef_count;
405 
406 static int bad_sector_refs;
407 static int bad_sidedef_refs;
408 
409 
410 
UpperCaseShortStr(char * buf,int max_len)411 static void UpperCaseShortStr(char *buf, int max_len)
412 {
413 	for (int i = 0 ; (i < max_len) && buf[i] ; i++)
414 	{
415 		buf[i] = toupper(buf[i]);
416 	}
417 }
418 
419 
Load_LookupAndSeek(const char * name)420 Lump_c * Load_LookupAndSeek(const char *name)
421 {
422 	short idx = load_wad->LevelLookupLump(loading_level, name);
423 
424 	if (idx < 0)
425 		return NULL;
426 
427 	Lump_c *lump = load_wad->GetLump(idx);
428 
429 	if (! lump->Seek())
430 	{
431 		LogPrintf("WARNING: failed to seek to %s lump!\n", name);
432 	}
433 
434 	return lump;
435 }
436 
437 
LoadVertices()438 static void LoadVertices()
439 {
440 	Lump_c *lump = Load_LookupAndSeek("VERTEXES");
441 	if (! lump)
442 		FatalError("No vertex lump!\n");
443 
444 	int count = lump->Length() / sizeof(raw_vertex_t);
445 
446 # if DEBUG_LOAD
447 	PrintDebug("GetVertices: num = %d\n", count);
448 # endif
449 
450 	Vertices.reserve(count);
451 
452 	for (int i = 0 ; i < count ; i++)
453 	{
454 		raw_vertex_t raw;
455 
456 		if (! lump->Read(&raw, sizeof(raw)))
457 			FatalError("Error reading vertices.\n");
458 
459 		Vertex *vert = new Vertex;
460 
461 		vert->raw_x = INT_TO_COORD(LE_S16(raw.x));
462 		vert->raw_y = INT_TO_COORD(LE_S16(raw.y));
463 
464 		Vertices.push_back(vert);
465 	}
466 }
467 
468 
LoadSectors()469 static void LoadSectors()
470 {
471 	Lump_c *lump = Load_LookupAndSeek("SECTORS");
472 	if (! lump)
473 		FatalError("No sector lump!\n");
474 
475 	int count = lump->Length() / sizeof(raw_sector_t);
476 
477 # if DEBUG_LOAD
478 	PrintDebug("GetSectors: num = %d\n", count);
479 # endif
480 
481 	Sectors.reserve(count);
482 
483 	for (int i = 0 ; i < count ; i++)
484 	{
485 		raw_sector_t raw;
486 
487 		if (! lump->Read(&raw, sizeof(raw)))
488 			FatalError("Error reading sectors.\n");
489 
490 		Sector *sec = new Sector;
491 
492 		sec->floorh = LE_S16(raw.floorh);
493 		sec->ceilh  = LE_S16(raw.ceilh);
494 
495 		UpperCaseShortStr(raw.floor_tex, 8);
496 		UpperCaseShortStr(raw. ceil_tex, 8);
497 
498 		sec->floor_tex = BA_InternaliseShortStr(raw.floor_tex, 8);
499 		sec->ceil_tex  = BA_InternaliseShortStr(raw.ceil_tex,  8);
500 
501 		sec->light = LE_U16(raw.light);
502 		sec->type  = LE_U16(raw.type);
503 		sec->tag   = LE_S16(raw.tag);
504 
505 		Sectors.push_back(sec);
506 	}
507 }
508 
509 
CreateFallbackSector()510 static void CreateFallbackSector()
511 {
512 	LogPrintf("Creating a fallback sector.\n");
513 
514 	Sector *sec = new Sector;
515 
516 	sec->SetDefaults();
517 
518 	Sectors.push_back(sec);
519 }
520 
CreateFallbackSideDef()521 static void CreateFallbackSideDef()
522 {
523 	// we need a valid sector too!
524 	if (NumSectors == 0)
525 		CreateFallbackSector();
526 
527 	LogPrintf("Creating a fallback sidedef.\n");
528 
529 	SideDef *sd = new SideDef;
530 
531 	sd->SetDefaults(false);
532 
533 	SideDefs.push_back(sd);
534 }
535 
CreateFallbackVertices()536 static void CreateFallbackVertices()
537 {
538 	LogPrintf("Creating two fallback vertices.\n");
539 
540 	Vertex *v1 = new Vertex;
541 	Vertex *v2 = new Vertex;
542 
543 	v1->raw_x = INT_TO_COORD(-777);
544 	v1->raw_y = INT_TO_COORD(-777);
545 
546 	v2->raw_x = INT_TO_COORD(555);
547 	v2->raw_y = INT_TO_COORD(555);
548 
549 	Vertices.push_back(v1);
550 	Vertices.push_back(v2);
551 }
552 
553 
ValidateSidedefRefs(LineDef * ld,int num)554 void ValidateSidedefRefs(LineDef * ld, int num)
555 {
556 	if (ld->right >= NumSideDefs || ld->left >= NumSideDefs)
557 	{
558 		LogPrintf("WARNING: linedef #%d has invalid sidedefs (%d / %d)\n",
559 				  num, ld->right, ld->left);
560 
561 		bad_sidedef_refs++;
562 
563 		// ensure we have a usable sidedef
564 		if (NumSideDefs == 0)
565 			CreateFallbackSideDef();
566 
567 		if (ld->right >= NumSideDefs)
568 			ld->right = 0;
569 
570 		if (ld->left >= NumSideDefs)
571 			ld->left = 0;
572 	}
573 }
574 
ValidateVertexRefs(LineDef * ld,int num)575 void ValidateVertexRefs(LineDef *ld, int num)
576 {
577 	if (ld->start >= NumVertices || ld->end >= NumVertices ||
578 	    ld->start == ld->end)
579 	{
580 		LogPrintf("WARNING: linedef #%d has invalid vertices (%d -> %d)\n",
581 		          num, ld->start, ld->end);
582 
583 		bad_linedef_count++;
584 
585 		// ensure we have a valid vertex
586 		if (NumVertices < 2)
587 			CreateFallbackVertices();
588 
589 		ld->start = 0;
590 		ld->end   = NumVertices - 1;
591 	}
592 }
593 
ValidateSectorRef(SideDef * sd,int num)594 void ValidateSectorRef(SideDef *sd, int num)
595 {
596 	if (sd->sector >= NumSectors)
597 	{
598 		LogPrintf("WARNING: sidedef #%d has invalid sector (%d)\n",
599 		          num, sd->sector);
600 
601 		bad_sector_refs++;
602 
603 		// ensure we have a valid sector
604 		if (NumSectors == 0)
605 			CreateFallbackSector();
606 
607 		sd->sector = 0;
608 	}
609 }
610 
611 
LoadHeader()612 static void LoadHeader()
613 {
614 	Lump_c *lump = load_wad->GetLump(load_wad->LevelHeader(loading_level));
615 
616 	int length = lump->Length();
617 
618 	if (length == 0)
619 		return;
620 
621 	HeaderData.resize(length);
622 
623 	if (! lump->Seek())
624 		FatalError("Error seeking to header lump!\n");
625 
626 	if (! lump->Read(& HeaderData[0], length))
627 		FatalError("Error reading header lump.\n");
628 }
629 
630 
LoadBehavior()631 static void LoadBehavior()
632 {
633 	// IOANCH 9/2015: support Hexen maps
634 	Lump_c *lump = Load_LookupAndSeek("BEHAVIOR");
635 	if (! lump)
636 		FatalError("No BEHAVIOR lump!\n");
637 
638 	int length = lump->Length();
639 
640 	BehaviorData.resize(length);
641 
642 	if (length == 0)
643 		return;
644 
645 	if (! lump->Read(& BehaviorData[0], length))
646 		FatalError("Error reading BEHAVIOR.\n");
647 }
648 
649 
LoadScripts()650 static void LoadScripts()
651 {
652 	// the SCRIPTS lump is usually absent
653 	Lump_c *lump = Load_LookupAndSeek("SCRIPTS");
654 	if (! lump)
655 		return;
656 
657 	int length = lump->Length();
658 
659 	ScriptsData.resize(length);
660 
661 	if (length == 0)
662 		return;
663 
664 	if (! lump->Read(& ScriptsData[0], length))
665 		FatalError("Error reading SCRIPTS.\n");
666 }
667 
668 
LoadThings()669 static void LoadThings()
670 {
671 	Lump_c *lump = Load_LookupAndSeek("THINGS");
672 	if (! lump)
673 		FatalError("No things lump!\n");
674 
675 	int count = lump->Length() / sizeof(raw_thing_t);
676 
677 # if DEBUG_LOAD
678 	PrintDebug("GetThings: num = %d\n", count);
679 # endif
680 
681 	for (int i = 0 ; i < count ; i++)
682 	{
683 		raw_thing_t raw;
684 
685 		if (! lump->Read(&raw, sizeof(raw)))
686 			FatalError("Error reading things.\n");
687 
688 		Thing *th = new Thing;
689 
690 		th->raw_x = INT_TO_COORD(LE_S16(raw.x));
691 		th->raw_y = INT_TO_COORD(LE_S16(raw.y));
692 
693 		th->angle   = LE_U16(raw.angle);
694 		th->type    = LE_U16(raw.type);
695 		th->options = LE_U16(raw.options);
696 
697 		Things.push_back(th);
698 	}
699 }
700 
701 
702 // IOANCH 9/2015
LoadThings_Hexen()703 static void LoadThings_Hexen()
704 {
705 	Lump_c *lump = Load_LookupAndSeek("THINGS");
706 	if (! lump)
707 		FatalError("No things lump!\n");
708 
709 	int count = lump->Length() / sizeof(raw_hexen_thing_t);
710 
711 # if DEBUG_LOAD
712 	PrintDebug("GetThings: num = %d\n", count);
713 # endif
714 
715 	for (int i = 0; i < count; ++i)
716 	{
717 		raw_hexen_thing_t raw;
718 
719 		if (! lump->Read(&raw, sizeof(raw)))
720 			FatalError("Error reading things.\n");
721 
722 		Thing *th = new Thing;
723 
724 		th->tid = LE_S16(raw.tid);
725 		th->raw_x = INT_TO_COORD(LE_S16(raw.x));
726 		th->raw_y = INT_TO_COORD(LE_S16(raw.y));
727 		th->raw_h = INT_TO_COORD(LE_S16(raw.height));
728 
729 		th->angle = LE_U16(raw.angle);
730 		th->type = LE_U16(raw.type);
731 		th->options = LE_U16(raw.options);
732 
733 		th->special = raw.special;
734 		th->arg1 = raw.args[0];
735 		th->arg2 = raw.args[1];
736 		th->arg3 = raw.args[2];
737 		th->arg4 = raw.args[3];
738 		th->arg5 = raw.args[4];
739 
740 		Things.push_back(th);
741 	}
742 }
743 
744 
LoadSideDefs()745 static void LoadSideDefs()
746 {
747 	Lump_c *lump = Load_LookupAndSeek("SIDEDEFS");
748 	if (! lump)
749 		FatalError("No sidedefs lump!\n");
750 
751 	int count = lump->Length() / sizeof(raw_sidedef_t);
752 
753 # if DEBUG_LOAD
754 	PrintDebug("GetSidedefs: num = %d\n", count);
755 # endif
756 
757 	for (int i = 0 ; i < count ; i++)
758 	{
759 		raw_sidedef_t raw;
760 
761 		if (! lump->Read(&raw, sizeof(raw)))
762 			FatalError("Error reading sidedefs.\n");
763 
764 		SideDef *sd = new SideDef;
765 
766 		sd->x_offset = LE_S16(raw.x_offset);
767 		sd->y_offset = LE_S16(raw.y_offset);
768 
769 		// convert empty names to the "-" null texture
770 		if (raw.upper_tex[0] == 0) strcpy(raw.upper_tex, "-");
771 		if (raw.lower_tex[0] == 0) strcpy(raw.lower_tex, "-");
772 		if (raw.  mid_tex[0] == 0) strcpy(raw.  mid_tex, "-");
773 
774 		UpperCaseShortStr(raw.upper_tex, 8);
775 		UpperCaseShortStr(raw.lower_tex, 8);
776 		UpperCaseShortStr(raw.  mid_tex, 8);
777 
778 		sd->upper_tex = BA_InternaliseShortStr(raw.upper_tex, 8);
779 		sd->lower_tex = BA_InternaliseShortStr(raw.lower_tex, 8);
780 		sd->  mid_tex = BA_InternaliseShortStr(raw.  mid_tex, 8);
781 
782 		sd->sector = LE_U16(raw.sector);
783 
784 		ValidateSectorRef(sd, i);
785 
786 		SideDefs.push_back(sd);
787 	}
788 }
789 
790 
LoadLineDefs()791 static void LoadLineDefs()
792 {
793 	Lump_c *lump = Load_LookupAndSeek("LINEDEFS");
794 	if (! lump)
795 		FatalError("No linedefs lump!\n");
796 
797 	int count = lump->Length() / sizeof(raw_linedef_t);
798 
799 # if DEBUG_LOAD
800 	PrintDebug("GetLinedefs: num = %d\n", count);
801 # endif
802 
803 	if (count == 0)
804 		return;
805 
806 	for (int i = 0 ; i < count ; i++)
807 	{
808 		raw_linedef_t raw;
809 
810 		if (! lump->Read(&raw, sizeof(raw)))
811 			FatalError("Error reading linedefs.\n");
812 
813 		LineDef *ld = new LineDef;
814 
815 		ld->start = LE_U16(raw.start);
816 		ld->end   = LE_U16(raw.end);
817 
818 		ld->flags = LE_U16(raw.flags);
819 		ld->type  = LE_U16(raw.type);
820 		ld->tag   = LE_S16(raw.tag);
821 
822 		ld->right = LE_U16(raw.right);
823 		ld->left  = LE_U16(raw.left);
824 
825 		if (ld->right == 0xFFFF) ld->right = -1;
826 		if (ld-> left == 0xFFFF) ld-> left = -1;
827 
828 		ValidateVertexRefs(ld, i);
829 		ValidateSidedefRefs(ld, i);
830 
831 		LineDefs.push_back(ld);
832 	}
833 }
834 
835 
836 // IOANCH 9/2015
LoadLineDefs_Hexen()837 static void LoadLineDefs_Hexen()
838 {
839 	Lump_c *lump = Load_LookupAndSeek("LINEDEFS");
840 	if (! lump)
841 		FatalError("No linedefs lump!\n");
842 
843 	int count = lump->Length() / sizeof(raw_hexen_linedef_t);
844 
845 # if DEBUG_LOAD
846 	PrintDebug("GetLinedefs: num = %d\n", count);
847 # endif
848 
849 	if (count == 0)
850 		return;
851 
852 	for (int i = 0 ; i < count ; i++)
853 	{
854 		raw_hexen_linedef_t raw;
855 
856 		if (! lump->Read(&raw, sizeof(raw)))
857 			FatalError("Error reading linedefs.\n");
858 
859 		LineDef *ld = new LineDef;
860 
861 		ld->start = LE_U16(raw.start);
862 		ld->end   = LE_U16(raw.end);
863 
864 		ld->flags = LE_U16(raw.flags);
865 		ld->type = raw.type;
866 		ld->tag  = raw.args[0];
867 		ld->arg2 = raw.args[1];
868 		ld->arg3 = raw.args[2];
869 		ld->arg4 = raw.args[3];
870 		ld->arg5 = raw.args[4];
871 
872 		ld->right = LE_U16(raw.right);
873 		ld->left  = LE_U16(raw.left);
874 
875 		if (ld->right == 0xFFFF) ld->right = -1;
876 		if (ld-> left == 0xFFFF) ld-> left = -1;
877 
878 		ValidateVertexRefs(ld, i);
879 		ValidateSidedefRefs(ld, i);
880 
881 		LineDefs.push_back(ld);
882 	}
883 }
884 
885 
RemoveUnusedVerticesAtEnd()886 static void RemoveUnusedVerticesAtEnd()
887 {
888 	if (NumVertices == 0)
889 		return;
890 
891 	bitvec_c used_verts(NumVertices);
892 
893 	for (int i = 0 ; i < NumLineDefs ; i++)
894 	{
895 		used_verts.set(LineDefs[i]->start);
896 		used_verts.set(LineDefs[i]->end);
897 	}
898 
899 	int new_count = NumVertices;
900 
901 	while (new_count > 2 && !used_verts.get(new_count-1))
902 		new_count--;
903 
904 	// we directly modify the vertex array here (which is not
905 	// normally kosher, but level loading is a special case).
906 	if (new_count < NumVertices)
907 	{
908 		LogPrintf("Removing %d unused vertices at end\n", NumVertices - new_count);
909 
910 		for (int i = new_count ; i < NumVertices ; i++)
911 			delete Vertices[i];
912 
913 		Vertices.resize(new_count);
914 	}
915 }
916 
917 
ShowLoadProblem()918 static void ShowLoadProblem()
919 {
920 	LogPrintf("Map load problems:\n");
921 	LogPrintf("   %d linedefs with bad vertex refs\n", bad_linedef_count);
922 	LogPrintf("   %d linedefs with bad sidedef refs\n", bad_sidedef_refs);
923 	LogPrintf("   %d sidedefs with bad sector refs\n", bad_sector_refs);
924 
925 	static char message[MSG_BUF_LEN];
926 
927 	if (bad_linedef_count > 0)
928 	{
929 		snprintf(message, sizeof(message),
930 			"Found %d linedefs with bad vertex references.\n"
931 			"These references have been replaced.",
932 			bad_linedef_count);
933 	}
934 	else
935 	{
936 		snprintf(message, sizeof(message),
937 			"Found %d bad sector refs, %d bad sidedef refs.\n"
938 			"These references have been replaced.",
939 			bad_sector_refs, bad_sidedef_refs);
940 	}
941 
942 	DLG_Notify("Map validation report:\n\n%s", message);
943 }
944 
945 
GetLevelFormat(Wad_file * wad,const char * level)946 void GetLevelFormat(Wad_file *wad, const char *level)
947 {
948 	int lev_num = wad->LevelFind(level);
949 
950 	// ignore failure here, it will be caught later
951 	if (lev_num >= 0)
952 	{
953 		Level_format = wad->LevelFormat(lev_num);
954 	}
955 }
956 
957 
958 //
959 // Read in the level data
960 //
961 
LoadLevel(Wad_file * wad,const char * level)962 void LoadLevel(Wad_file *wad, const char *level)
963 {
964 	short lev_num = wad->LevelFind(level);
965 
966 	if (lev_num < 0)
967 		FatalError("No such map: %s\n", level);
968 
969 	LoadLevelNum(wad, lev_num);
970 
971 	// reset various editor state
972 	Editor_ClearAction();
973 	Selection_InvalidateLast();
974 
975 	edit.Selected->clear_all();
976 	edit.highlight.clear();
977 
978 	main_win->UpdateTotals();
979 	main_win->UpdateGameInfo();
980 	main_win->InvalidatePanelObj();
981 	main_win->redraw();
982 
983 	if (main_win)
984 	{
985 		main_win->SetTitle(wad->PathName(), level, wad->IsReadOnly());
986 
987 		// load the user state associated with this map
988 		crc32_c adler_crc;
989 
990 		BA_LevelChecksum(adler_crc);
991 
992 		if (! M_LoadUserState())
993 		{
994 			M_DefaultUserState();
995 		}
996 	}
997 
998 	Level_name = StringUpper(level);
999 
1000 	Status_Set("Loaded %s", Level_name);
1001 
1002 	RedrawMap();
1003 }
1004 
1005 
LoadLevelNum(Wad_file * wad,short lev_num)1006 void LoadLevelNum(Wad_file *wad, short lev_num)
1007 {
1008 	load_wad = wad;
1009 	loading_level = lev_num;
1010 
1011 	Level_format = load_wad->LevelFormat(loading_level);
1012 
1013 	BA_ClearAll();
1014 
1015 	bad_linedef_count = 0;
1016 	bad_sector_refs   = 0;
1017 	bad_sidedef_refs  = 0;
1018 
1019 	LoadHeader();
1020 
1021 	if (Level_format == MAPF_UDMF)
1022 	{
1023 		UDMF_LoadLevel();
1024 	}
1025 	else
1026 	{
1027 		if (Level_format == MAPF_Hexen)
1028 			LoadThings_Hexen();
1029 		else
1030 			LoadThings();
1031 
1032 		LoadVertices();
1033 		LoadSectors();
1034 		LoadSideDefs();
1035 
1036 		if (Level_format == MAPF_Hexen)
1037 		{
1038 			LoadLineDefs_Hexen();
1039 
1040 			LoadBehavior();
1041 			LoadScripts();
1042 		}
1043 		else
1044 		{
1045 			LoadLineDefs();
1046 		}
1047 	}
1048 
1049 	if (bad_linedef_count || bad_sector_refs || bad_sidedef_refs)
1050 	{
1051 		ShowLoadProblem();
1052 	}
1053 
1054 	// Node builders create a lot of new vertices for segs.
1055 	// However they just get in the way for editing, so remove them.
1056 	RemoveUnusedVerticesAtEnd();
1057 
1058 	SideDefs_Unpack(true);
1059 
1060 	CalculateLevelBounds();
1061 	Subdiv_InvalidateAll();
1062 
1063 	MadeChanges = 0;
1064 }
1065 
1066 
1067 //
1068 // open a new wad file.
1069 // when 'map_name' is not NULL, try to open that map.
1070 //
OpenFileMap(const char * filename,const char * map_name)1071 void OpenFileMap(const char *filename, const char *map_name)
1072 {
1073 	if (! Main_ConfirmQuit("open another map"))
1074 		return;
1075 
1076 
1077 	Wad_file *wad = NULL;
1078 
1079 	// make sure file exists, as Open() with 'a' would create it otherwise
1080 	if (FileExists(filename))
1081 	{
1082 		wad = Wad_file::Open(filename, 'a');
1083 	}
1084 
1085 	if (! wad)
1086 	{
1087 		// FIXME: get an error message, add it here
1088 
1089 		DLG_Notify("Unable to open that WAD file.");
1090 		return;
1091 	}
1092 
1093 
1094 	// determine which level to use
1095 	int lev_num = -1;
1096 
1097 	if (map_name)
1098 	{
1099 		lev_num = wad->LevelFind(map_name);
1100 	}
1101 
1102 	if (lev_num < 0)
1103 	{
1104 		lev_num = wad->LevelFindFirst();
1105 	}
1106 
1107 	if (lev_num < 0)
1108 	{
1109 		DLG_Notify("No levels found in that WAD.");
1110 
1111 		delete wad;
1112 		return;
1113 	}
1114 
1115 	if (wad->FindLump(EUREKA_LUMP))
1116 	{
1117 		if (! M_ParseEurekaLump(wad))
1118 		{
1119 			delete wad;
1120 			return;
1121 		}
1122 	}
1123 
1124 
1125 	/* OK, open it */
1126 
1127 
1128 	// this wad replaces the current PWAD
1129 	ReplaceEditWad(wad);
1130 
1131 	SYS_ASSERT(edit_wad == wad);
1132 
1133 
1134 	// always grab map_name from the actual level
1135 	{
1136 		short idx = edit_wad->LevelHeader(lev_num);
1137 		map_name  = edit_wad->GetLump(idx)->Name();
1138 	}
1139 
1140 	LogPrintf("Loading Map : %s of %s\n", map_name, edit_wad->PathName());
1141 
1142 	LoadLevel(edit_wad, map_name);
1143 
1144 	// must be after LoadLevel as we need the Level_format
1145 	Main_LoadResources();
1146 }
1147 
1148 
CMD_OpenMap()1149 void CMD_OpenMap()
1150 {
1151 	if (! Main_ConfirmQuit("open another map"))
1152 		return;
1153 
1154 
1155 	UI_OpenMap * dialog = new UI_OpenMap();
1156 
1157 	const char *map_name = NULL;
1158 	bool did_load = false;
1159 
1160 	Wad_file *wad = dialog->Run(&map_name, &did_load);
1161 
1162 	delete dialog;
1163 
1164 	if (! wad)	// cancelled
1165 		return;
1166 
1167 
1168 	// this shouldn't happen -- but just in case...
1169 	if (wad->LevelFind(map_name) < 0)
1170 	{
1171 		DLG_Notify("Hmmmm, cannot find that map !?!");
1172 
1173 		delete wad;
1174 		return;
1175 	}
1176 
1177 
1178 	if (did_load && wad->FindLump(EUREKA_LUMP))
1179 	{
1180 		if (! M_ParseEurekaLump(wad))
1181 		{
1182 			delete wad;
1183 			return;
1184 		}
1185 	}
1186 
1187 
1188 	// does this wad replace the currently edited wad?
1189 	bool new_resources = false;
1190 
1191 	if (did_load)
1192 	{
1193 		SYS_ASSERT(wad != edit_wad);
1194 		SYS_ASSERT(wad != game_wad);
1195 
1196 		ReplaceEditWad(wad);
1197 
1198 		new_resources = true;
1199 	}
1200 	// ...or does it remove the edit_wad? (e.g. wad == game_wad)
1201 	else if (edit_wad && wad != edit_wad)
1202 	{
1203 		RemoveEditWad();
1204 
1205 		new_resources = true;
1206 	}
1207 
1208 	LogPrintf("Loading Map : %s of %s\n", map_name, wad->PathName());
1209 
1210 	LoadLevel(wad, map_name);
1211 
1212 	if (new_resources)
1213 	{
1214 		// this can invalidate the 'wad' var (since it closes/reopens
1215 		// all wads in the master_dir), so it MUST be after LoadLevel.
1216 		// less importantly, we need to know the Level_format.
1217 		Main_LoadResources();
1218 	}
1219 }
1220 
1221 
CMD_GivenFile()1222 void CMD_GivenFile()
1223 {
1224 	const char *mode = EXEC_Param[0];
1225 
1226 	int index = last_given_file;
1227 
1228 	if (! mode[0] || y_stricmp(mode, "current") == 0)
1229 	{
1230 		// index = index + 0;
1231 	}
1232 	else if (y_stricmp(mode, "next") == 0)
1233 	{
1234 		index = index + 1;
1235 	}
1236 	else if (y_stricmp(mode, "prev") == 0)
1237 	{
1238 		index = index - 1;
1239 	}
1240 	else if (y_stricmp(mode, "first") == 0)
1241 	{
1242 		index = 0;
1243 	}
1244 	else if (y_stricmp(mode, "last") == 0)
1245 	{
1246 		index = (int)Pwad_list.size() - 1;
1247 	}
1248 	else
1249 	{
1250 		Beep("GivenFile: unknown keyword: %s", mode);
1251 		return;
1252 	}
1253 
1254 	if (index < 0 || index >= (int)Pwad_list.size())
1255 	{
1256 		Beep("No more files");
1257 		return;
1258 	}
1259 
1260 	last_given_file = index;
1261 
1262 	// TODO: remember last map visited in this wad
1263 
1264 	OpenFileMap(Pwad_list[index], NULL);
1265 }
1266 
1267 
CMD_FlipMap()1268 void CMD_FlipMap()
1269 {
1270 	const char *mode = EXEC_Param[0];
1271 
1272 	if (! mode[0])
1273 	{
1274 		Beep("FlipMap: missing keyword");
1275 		return;
1276 	}
1277 
1278 
1279 	if (! Main_ConfirmQuit("open another map"))
1280 		return;
1281 
1282 
1283 	Wad_file *wad = edit_wad ? edit_wad : game_wad;
1284 
1285 	// the level might not be found (lev_num < 0) -- that is OK
1286 	int lev_idx = wad->LevelFind(Level_name);
1287 	int max_idx = wad->LevelCount() - 1;
1288 
1289 	if (max_idx < 0)
1290 	{
1291 		Beep("No maps ?!?");
1292 		return;
1293 	}
1294 
1295 	SYS_ASSERT(lev_idx <= max_idx);
1296 
1297 
1298 	if (y_stricmp(mode, "next") == 0)
1299 	{
1300 		if (lev_idx < 0)
1301 			lev_idx = 0;
1302 		else if (lev_idx < max_idx)
1303 			lev_idx++;
1304 		else
1305 		{
1306 			Beep("No more maps");
1307 			return;
1308 		}
1309 	}
1310 	else if (y_stricmp(mode, "prev") == 0)
1311 	{
1312 		if (lev_idx < 0)
1313 			lev_idx = max_idx;
1314 		else if (lev_idx > 0)
1315 			lev_idx--;
1316 		else
1317 		{
1318 			Beep("No more maps");
1319 			return;
1320 		}
1321 	}
1322 	else if (y_stricmp(mode, "first") == 0)
1323 	{
1324 		lev_idx = 0;
1325 	}
1326 	else if (y_stricmp(mode, "last") == 0)
1327 	{
1328 		lev_idx = max_idx;
1329 	}
1330 	else
1331 	{
1332 		Beep("FlipMap: unknown keyword: %s", mode);
1333 		return;
1334 	}
1335 
1336 	SYS_ASSERT(lev_idx >= 0);
1337 	SYS_ASSERT(lev_idx <= max_idx);
1338 
1339 
1340 	short lump_idx = wad->LevelHeader(lev_idx);
1341 	Lump_c * lump  = wad->GetLump(lump_idx);
1342 	const char *map_name = lump->Name();
1343 
1344 	LogPrintf("Flipping Map to : %s\n", map_name);
1345 
1346 	LoadLevel(wad, map_name);
1347 }
1348 
1349 
1350 //------------------------------------------------------------------------
1351 //  SAVING CODE
1352 //------------------------------------------------------------------------
1353 
1354 static short saving_level;
1355 
1356 
SaveHeader(const char * level)1357 static void SaveHeader(const char *level)
1358 {
1359 	int size = (int)HeaderData.size();
1360 
1361 	Lump_c *lump = edit_wad->AddLevel(level, size, &saving_level);
1362 
1363 	if (size > 0)
1364 	{
1365 		lump->Write(& HeaderData[0], size);
1366 	}
1367 
1368 	lump->Finish();
1369 }
1370 
1371 
SaveBehavior()1372 static void SaveBehavior()
1373 {
1374 	int size = (int)BehaviorData.size();
1375 
1376 	Lump_c *lump = edit_wad->AddLump("BEHAVIOR", size);
1377 
1378 	if (size > 0)
1379 	{
1380 		lump->Write(& BehaviorData[0], size);
1381 	}
1382 
1383 	lump->Finish();
1384 }
1385 
1386 
SaveScripts()1387 static void SaveScripts()
1388 {
1389 	int size = (int)ScriptsData.size();
1390 
1391 	if (size > 0)
1392 	{
1393 		Lump_c *lump = edit_wad->AddLump("SCRIPTS", size);
1394 
1395 		lump->Write(& ScriptsData[0], size);
1396 		lump->Finish();
1397 	}
1398 }
1399 
1400 
SaveVertices()1401 static void SaveVertices()
1402 {
1403 	int size = NumVertices * (int)sizeof(raw_vertex_t);
1404 
1405 	Lump_c *lump = edit_wad->AddLump("VERTEXES", size);
1406 
1407 	for (int i = 0 ; i < NumVertices ; i++)
1408 	{
1409 		const Vertex *vert = Vertices[i];
1410 
1411 		raw_vertex_t raw;
1412 
1413 		raw.x = LE_S16(COORD_TO_INT(vert->raw_x));
1414 		raw.y = LE_S16(COORD_TO_INT(vert->raw_y));
1415 
1416 		lump->Write(&raw, sizeof(raw));
1417 	}
1418 
1419 	lump->Finish();
1420 }
1421 
1422 
SaveSectors()1423 static void SaveSectors()
1424 {
1425 	int size = NumSectors * (int)sizeof(raw_sector_t);
1426 
1427 	Lump_c *lump = edit_wad->AddLump("SECTORS", size);
1428 
1429 	for (int i = 0 ; i < NumSectors ; i++)
1430 	{
1431 		const Sector *sec = Sectors[i];
1432 
1433 		raw_sector_t raw;
1434 
1435 		raw.floorh = LE_S16(sec->floorh);
1436 		raw.ceilh  = LE_S16(sec->ceilh);
1437 
1438 		W_StoreString(raw.floor_tex, sec->FloorTex(), sizeof(raw.floor_tex));
1439 		W_StoreString(raw.ceil_tex,  sec->CeilTex(),  sizeof(raw.ceil_tex));
1440 
1441 		raw.light = LE_U16(sec->light);
1442 		raw.type  = LE_U16(sec->type);
1443 		raw.tag   = LE_U16(sec->tag);
1444 
1445 		lump->Write(&raw, sizeof(raw));
1446 	}
1447 
1448 	lump->Finish();
1449 }
1450 
1451 
SaveThings()1452 static void SaveThings()
1453 {
1454 	int size = NumThings * (int)sizeof(raw_thing_t);
1455 
1456 	Lump_c *lump = edit_wad->AddLump("THINGS", size);
1457 
1458 	for (int i = 0 ; i < NumThings ; i++)
1459 	{
1460 		const Thing *th = Things[i];
1461 
1462 		raw_thing_t raw;
1463 
1464 		raw.x = LE_S16(COORD_TO_INT(th->raw_x));
1465 		raw.y = LE_S16(COORD_TO_INT(th->raw_y));
1466 
1467 		raw.angle   = LE_U16(th->angle);
1468 		raw.type    = LE_U16(th->type);
1469 		raw.options = LE_U16(th->options);
1470 
1471 		lump->Write(&raw, sizeof(raw));
1472 	}
1473 
1474 	lump->Finish();
1475 }
1476 
1477 
1478 // IOANCH 9/2015
SaveThings_Hexen()1479 static void SaveThings_Hexen()
1480 {
1481 	int size = NumThings * (int)sizeof(raw_hexen_thing_t);
1482 
1483 	Lump_c *lump = edit_wad->AddLump("THINGS", size);
1484 
1485 	for (int i = 0 ; i < NumThings ; i++)
1486 	{
1487 		const Thing *th = Things[i];
1488 
1489 		raw_hexen_thing_t raw;
1490 
1491 		raw.tid = LE_S16(th->tid);
1492 
1493 		raw.x = LE_S16(COORD_TO_INT(th->raw_x));
1494 		raw.y = LE_S16(COORD_TO_INT(th->raw_y));
1495 		raw.height = LE_S16(COORD_TO_INT(th->raw_h));
1496 
1497 		raw.angle   = LE_U16(th->angle);
1498 		raw.type    = LE_U16(th->type);
1499 		raw.options = LE_U16(th->options);
1500 
1501 		raw.special = th->special;
1502 		raw.args[0] = th->arg1;
1503 		raw.args[1] = th->arg2;
1504 		raw.args[2] = th->arg3;
1505 		raw.args[3] = th->arg4;
1506 		raw.args[4] = th->arg5;
1507 
1508 		lump->Write(&raw, sizeof(raw));
1509 	}
1510 
1511 	lump->Finish();
1512 }
1513 
1514 
SaveSideDefs()1515 static void SaveSideDefs()
1516 {
1517 	int size = NumSideDefs * (int)sizeof(raw_sidedef_t);
1518 
1519 	Lump_c *lump = edit_wad->AddLump("SIDEDEFS", size);
1520 
1521 	for (int i = 0 ; i < NumSideDefs ; i++)
1522 	{
1523 		const SideDef *side = SideDefs[i];
1524 
1525 		raw_sidedef_t raw;
1526 
1527 		raw.x_offset = LE_S16(side->x_offset);
1528 		raw.y_offset = LE_S16(side->y_offset);
1529 
1530 		W_StoreString(raw.upper_tex, side->UpperTex(), sizeof(raw.upper_tex));
1531 		W_StoreString(raw.lower_tex, side->LowerTex(), sizeof(raw.lower_tex));
1532 		W_StoreString(raw.mid_tex,   side->MidTex(),   sizeof(raw.mid_tex));
1533 
1534 		raw.sector = LE_U16(side->sector);
1535 
1536 		lump->Write(&raw, sizeof(raw));
1537 	}
1538 
1539 	lump->Finish();
1540 }
1541 
1542 
SaveLineDefs()1543 static void SaveLineDefs()
1544 {
1545 	int size = NumLineDefs * (int)sizeof(raw_linedef_t);
1546 
1547 	Lump_c *lump = edit_wad->AddLump("LINEDEFS", size);
1548 
1549 	for (int i = 0 ; i < NumLineDefs ; i++)
1550 	{
1551 		const LineDef *ld = LineDefs[i];
1552 
1553 		raw_linedef_t raw;
1554 
1555 		raw.start = LE_U16(ld->start);
1556 		raw.end   = LE_U16(ld->end);
1557 
1558 		raw.flags = LE_U16(ld->flags);
1559 		raw.type  = LE_U16(ld->type);
1560 		raw.tag   = LE_S16(ld->tag);
1561 
1562 		raw.right = (ld->right >= 0) ? LE_U16(ld->right) : 0xFFFF;
1563 		raw.left  = (ld->left  >= 0) ? LE_U16(ld->left)  : 0xFFFF;
1564 
1565 		lump->Write(&raw, sizeof(raw));
1566 	}
1567 
1568 	lump->Finish();
1569 }
1570 
1571 
1572 // IOANCH 9/2015
SaveLineDefs_Hexen()1573 static void SaveLineDefs_Hexen()
1574 {
1575 	int size = NumLineDefs * (int)sizeof(raw_hexen_linedef_t);
1576 
1577 	Lump_c *lump = edit_wad->AddLump("LINEDEFS", size);
1578 
1579 	for (int i = 0 ; i < NumLineDefs ; i++)
1580 	{
1581 		const LineDef *ld = LineDefs[i];
1582 
1583 		raw_hexen_linedef_t raw;
1584 
1585 		raw.start = LE_U16(ld->start);
1586 		raw.end   = LE_U16(ld->end);
1587 
1588 		raw.flags = LE_U16(ld->flags);
1589 		raw.type  = ld->type;
1590 
1591 		raw.args[0] = ld->tag;
1592 		raw.args[1] = ld->arg2;
1593 		raw.args[2] = ld->arg3;
1594 		raw.args[3] = ld->arg4;
1595 		raw.args[4] = ld->arg5;
1596 
1597 		raw.right = (ld->right >= 0) ? LE_U16(ld->right) : 0xFFFF;
1598 		raw.left  = (ld->left  >= 0) ? LE_U16(ld->left)  : 0xFFFF;
1599 
1600 		lump->Write(&raw, sizeof(raw));
1601 	}
1602 
1603 	lump->Finish();
1604 }
1605 
1606 
EmptyLump(const char * name)1607 static void EmptyLump(const char *name)
1608 {
1609 	edit_wad->AddLump(name)->Finish();
1610 }
1611 
1612 
1613 //
1614 // Write out the level data
1615 //
1616 
SaveLevel(const char * level)1617 static void SaveLevel(const char *level)
1618 {
1619 	// set global level name now (for debugging code)
1620 	Level_name = StringUpper(level);
1621 
1622 	edit_wad->BeginWrite();
1623 
1624 	// remove previous version of level (if it exists)
1625 	int lev_num = edit_wad->LevelFind(level);
1626 	int level_lump = -1;
1627 
1628 	if (lev_num >= 0)
1629 	{
1630 		level_lump = edit_wad->LevelHeader(lev_num);
1631 
1632 		edit_wad->RemoveLevel(lev_num);
1633 	}
1634 
1635 	edit_wad->InsertPoint(level_lump);
1636 
1637 	SaveHeader(level);
1638 
1639 	if (Level_format == MAPF_UDMF)
1640 	{
1641 		UDMF_SaveLevel();
1642 	}
1643 	else
1644 	{
1645 		// IOANCH 9/2015: save Hexen format maps
1646 		if (Level_format == MAPF_Hexen)
1647 		{
1648 			SaveThings_Hexen();
1649 			SaveLineDefs_Hexen();
1650 		}
1651 		else
1652 		{
1653 			SaveThings();
1654 			SaveLineDefs();
1655 		}
1656 
1657 		SaveSideDefs();
1658 		SaveVertices();
1659 
1660 		EmptyLump("SEGS");
1661 		EmptyLump("SSECTORS");
1662 		EmptyLump("NODES");
1663 
1664 		SaveSectors();
1665 
1666 		EmptyLump("REJECT");
1667 		EmptyLump("BLOCKMAP");
1668 
1669 		if (Level_format == MAPF_Hexen)
1670 		{
1671 			SaveBehavior();
1672 			SaveScripts();
1673 		}
1674 	}
1675 
1676 	// write out the new directory
1677 	edit_wad->EndWrite();
1678 
1679 
1680 	// build the nodes
1681 	if (bsp_on_save && ! inhibit_node_build)
1682 	{
1683 		BuildNodesAfterSave(saving_level);
1684 	}
1685 
1686 
1687 	// this is mainly for Next/Prev-map commands
1688 	// [ it doesn't change the on-disk wad file at all ]
1689 	edit_wad->SortLevels();
1690 
1691 	M_WriteEurekaLump(edit_wad);
1692 
1693 	M_AddRecent(edit_wad->PathName(), Level_name);
1694 
1695 	Status_Set("Saved %s", Level_name);
1696 
1697 	if (main_win)
1698 	{
1699 		main_win->SetTitle(edit_wad->PathName(), Level_name, false);
1700 
1701 		// save the user state associated with this map
1702 		M_SaveUserState();
1703 	}
1704 
1705 	MadeChanges = 0;
1706 }
1707 
1708 
M_SaveMap()1709 bool M_SaveMap()
1710 {
1711 	// we require a wad file to save into.
1712 	// if there is none, then need to create one via Export function.
1713 
1714 	if (! edit_wad)
1715 	{
1716 		return M_ExportMap();
1717 	}
1718 
1719 	if (edit_wad->IsReadOnly())
1720 	{
1721 		if (DLG_Confirm("Cancel|&Export",
1722 		                "The current pwad is a READ-ONLY file. "
1723 						"Do you want to export this map into a new file?") <= 0)
1724 		{
1725 			return false;
1726 		}
1727 
1728 		return M_ExportMap();
1729 	}
1730 
1731 
1732 	M_BackupWad(edit_wad);
1733 
1734 	LogPrintf("Saving Map : %s in %s\n", Level_name, edit_wad->PathName());
1735 
1736 	SaveLevel(Level_name);
1737 
1738 	return true;
1739 }
1740 
1741 
M_ExportMap()1742 bool M_ExportMap()
1743 {
1744 	Fl_Native_File_Chooser chooser;
1745 
1746 	chooser.title("Pick file to export to");
1747 	chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
1748 	chooser.filter("Wads\t*.wad");
1749 	chooser.directory(Main_FileOpFolder());
1750 
1751 	// Show native chooser
1752 	switch (chooser.show())
1753 	{
1754 		case -1:
1755 			LogPrintf("Export Map: error choosing file:\n");
1756 			LogPrintf("   %s\n", chooser.errmsg());
1757 
1758 			DLG_Notify("Unable to export the map:\n\n%s", chooser.errmsg());
1759 			return false;
1760 
1761 		case 1:
1762 			LogPrintf("Export Map: cancelled by user\n");
1763 			return false;
1764 
1765 		default:
1766 			break;  // OK
1767 	}
1768 
1769 	// if extension is missing then add ".wad"
1770 	char filename[FL_PATH_MAX];
1771 
1772 	strcpy(filename, chooser.filename());
1773 
1774 	char *pos = (char *)fl_filename_ext(filename);
1775 	if (! *pos)
1776 		strcat(filename, ".wad");
1777 
1778 
1779 	// don't export into a file we currently have open
1780 	if (MasterDir_HaveFilename(filename))
1781 	{
1782 		DLG_Notify("Unable to export the map:\n\nFile already in use");
1783 		return false;
1784 	}
1785 
1786 
1787 	// does the file already exist?  if not, create it...
1788 	bool exists = FileExists(filename);
1789 
1790 	Wad_file *wad;
1791 
1792 	if (exists)
1793 	{
1794 		wad = Wad_file::Open(filename, 'a');
1795 
1796 		if (wad && wad->IsReadOnly())
1797 		{
1798 			DLG_Notify("Cannot export the map into a READ-ONLY file.");
1799 
1800 			delete wad;
1801 			return false;
1802 		}
1803 
1804 		// adopt iwad/port/resources of the target wad
1805 		if (wad->FindLump(EUREKA_LUMP))
1806 		{
1807 			if (! M_ParseEurekaLump(wad))
1808 			{
1809 				delete wad;
1810 				return false;
1811 			}
1812 		}
1813 	}
1814 	else
1815 	{
1816 		wad = Wad_file::Open(filename, 'w');
1817 	}
1818 
1819 	if (! wad)
1820 	{
1821 		DLG_Notify("Unable to export the map:\n\n%s",
1822 		           "Error creating output file");
1823 		return false;
1824 	}
1825 
1826 
1827 	// ask user for map name
1828 
1829 	UI_ChooseMap * dialog = new UI_ChooseMap(Level_name);
1830 
1831 	dialog->PopulateButtons(toupper(Level_name[0]), wad);
1832 
1833 	const char *map_name = dialog->Run();
1834 
1835 	delete dialog;
1836 
1837 
1838 	// cancelled?
1839 	if (! map_name)
1840 	{
1841 		delete wad;
1842 		return false;
1843 	}
1844 
1845 
1846 	// we will write into the chosen wad.
1847 	// however if the level already exists, get confirmation first
1848 
1849 	if (exists && wad->LevelFind(map_name) >= 0)
1850 	{
1851 		if (DLG_Confirm("Cancel|&Overwrite",
1852 		                overwrite_message, "selected") <= 0)
1853 		{
1854 			delete wad;
1855 			return false;
1856 		}
1857 	}
1858 
1859 	// back-up an existing wad
1860 	if (exists)
1861 	{
1862 		M_BackupWad(wad);
1863 	}
1864 
1865 
1866 	LogPrintf("Exporting Map : %s in %s\n", map_name, wad->PathName());
1867 
1868 	// the new wad replaces the current PWAD
1869 	ReplaceEditWad(wad);
1870 
1871 	SaveLevel(map_name);
1872 
1873 	// do this after the save (in case it fatal errors)
1874 	Main_LoadResources();
1875 
1876 	return true;
1877 }
1878 
1879 
CMD_SaveMap()1880 void CMD_SaveMap()
1881 {
1882 	M_SaveMap();
1883 }
1884 
1885 
CMD_ExportMap()1886 void CMD_ExportMap()
1887 {
1888 	M_ExportMap();
1889 }
1890 
1891 
1892 //------------------------------------------------------------------------
1893 //  COPY, RENAME and DELETE MAP
1894 //------------------------------------------------------------------------
1895 
CMD_CopyMap()1896 void CMD_CopyMap()
1897 {
1898 	if (! edit_wad)
1899 	{
1900 		DLG_Notify("Cannot copy a map unless editing a PWAD.");
1901 		return;
1902 	}
1903 
1904 	if (edit_wad->IsReadOnly())
1905 	{
1906 		DLG_Notify("Cannot copy map : file is read-only.");
1907 		return;
1908 	}
1909 
1910 	// ask user for map name
1911 
1912 	UI_ChooseMap * dialog = new UI_ChooseMap(Level_name, edit_wad);
1913 
1914 	dialog->PopulateButtons(toupper(Level_name[0]), edit_wad);
1915 
1916 	const char *new_name = dialog->Run();
1917 
1918 	delete dialog;
1919 
1920 	// cancelled?
1921 	if (! new_name)
1922 		return;
1923 
1924 	// sanity check that the name is different
1925 	// (should be prevented by the choose-map dialog)
1926 	if (y_stricmp(new_name, Level_name) == 0)
1927 	{
1928 		Beep("Name is same!?!");
1929 		return;
1930 	}
1931 
1932 	// perform the copy (just a save)
1933 	LogPrintf("Copying Map : %s --> %s\n", Level_name, new_name);
1934 
1935 	SaveLevel(new_name);
1936 
1937 	Status_Set("Copied to %s", Level_name);
1938 }
1939 
1940 
CMD_RenameMap()1941 void CMD_RenameMap()
1942 {
1943 	if (! edit_wad)
1944 	{
1945 		DLG_Notify("Cannot rename a map unless editing a PWAD.");
1946 		return;
1947 	}
1948 
1949 	if (edit_wad->IsReadOnly())
1950 	{
1951 		DLG_Notify("Cannot rename map : file is read-only.");
1952 		return;
1953 	}
1954 
1955 
1956 	// ask user for map name
1957 
1958 	UI_ChooseMap * dialog = new UI_ChooseMap(Level_name, edit_wad /* rename_wad */);
1959 
1960 	// pick level format from the IWAD
1961 	// [ user may be trying to rename map after changing the IWAD ]
1962 	char format = 'M';
1963 	{
1964 		short idx = game_wad->LevelFindFirst();
1965 
1966 		if (idx >= 0)
1967 		{
1968 			idx = game_wad->LevelHeader(idx);
1969 			const char *name = game_wad->GetLump(idx)->Name();
1970 			format = toupper(name[0]);
1971 		}
1972 	}
1973 
1974 	dialog->PopulateButtons(format, edit_wad);
1975 
1976 	const char *new_name = dialog->Run();
1977 
1978 	delete dialog;
1979 
1980 	// cancelled?
1981 	if (! new_name)
1982 		return;
1983 
1984 	// sanity check that the name is different
1985 	// (should be prevented by the choose-map dialog)
1986 	if (y_stricmp(new_name, Level_name) == 0)
1987 	{
1988 		Beep("Name is same!?!");
1989 		return;
1990 	}
1991 
1992 
1993 	// perform the rename
1994 	short lev_num = edit_wad->LevelFind(Level_name);
1995 
1996 	if (lev_num >= 0)
1997 	{
1998 		short level_lump = edit_wad->LevelHeader(lev_num);
1999 
2000 		edit_wad->BeginWrite();
2001 		edit_wad->RenameLump(level_lump, new_name);
2002 		edit_wad->EndWrite();
2003 	}
2004 
2005 	Level_name = StringUpper(new_name);
2006 
2007 	main_win->SetTitle(edit_wad->PathName(), Level_name, false);
2008 
2009 	Status_Set("Renamed to %s", Level_name);
2010 }
2011 
2012 
CMD_DeleteMap()2013 void CMD_DeleteMap()
2014 {
2015 	if (! edit_wad)
2016 	{
2017 		DLG_Notify("Cannot delete a map unless editing a PWAD.");
2018 		return;
2019 	}
2020 
2021 	if (edit_wad->IsReadOnly())
2022 	{
2023 		DLG_Notify("Cannot delete map : file is read-only.");
2024 		return;
2025 	}
2026 
2027 	if (edit_wad->LevelCount() < 2)
2028 	{
2029 		// perhaps ask either to Rename map, or Delete the file (and Eureka will shut down)
2030 
2031 		DLG_Notify("Cannot delete the last map in a PWAD.");
2032 		return;
2033 	}
2034 
2035 	if (DLG_Confirm("Cancel|&Delete",
2036 	                "Are you sure you want to delete this map? "
2037 					"It will be permanently removed from the current PWAD.") <= 0)
2038 	{
2039 		return;
2040 	}
2041 
2042 	LogPrintf("Deleting Map : %s...\n", Level_name);
2043 
2044 	short lev_num = edit_wad->LevelFind(Level_name);
2045 
2046 	if (lev_num < 0)
2047 	{
2048 		Beep("No such map ?!?");
2049 		return;
2050 	}
2051 
2052 
2053 	// kick it to the curb
2054 	edit_wad->BeginWrite();
2055 	edit_wad->RemoveLevel(lev_num);
2056 	edit_wad->EndWrite();
2057 
2058 
2059 	// choose a new level to load
2060 	{
2061 		if (lev_num >= edit_wad->LevelCount())
2062 			lev_num =  edit_wad->LevelCount() - 1;
2063 
2064 		short lump_idx = edit_wad->LevelHeader(lev_num);
2065 		Lump_c * lump  = edit_wad->GetLump(lump_idx);
2066 		const char *map_name = lump->Name();
2067 
2068 		LogPrintf("OK.  Loading : %s....\n", map_name);
2069 
2070 		LoadLevel(edit_wad, map_name);
2071 	}
2072 }
2073 
2074 //--- editor settings ---
2075 // vi:ts=4:sw=4:noexpandtab
2076