Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

MAP.CPP (23091B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // map.c
     23 
     24 #include "stdafx.h"
     25 #include "qe3.h"
     26 #include "PrefsDlg.h"
     27 
     28 qboolean	modified;		// for quit confirmation (0 = clean, 1 = unsaved,
     29 							// 2 = autosaved, but not regular saved) 
     30 
     31 char		currentmap[1024];
     32 
     33 
     34 brush_t	active_brushes;		// brushes currently being displayed
     35 brush_t	selected_brushes;	// highlighted
     36 
     37 face_t	*selected_face;
     38 brush_t	*selected_face_brush;
     39 
     40 brush_t	filtered_brushes;	// brushes that have been filtered or regioned
     41 
     42 entity_t	entities;		// head/tail of doubly linked list
     43 
     44 entity_t	*world_entity = NULL; // "classname" "worldspawn" !
     45 
     46 void AddRegionBrushes (void);
     47 void RemoveRegionBrushes (void);
     48 
     49 
     50 void DupLists()
     51 {
     52   DWORD dw = GetTickCount();
     53 
     54 }
     55 
     56 /*
     57 =============================================================
     58 
     59   Cross map selection saving
     60 
     61   this could fuck up if you have only part of a complex entity selected...
     62 =============================================================
     63 */
     64 
     65 brush_t		between_brushes;
     66 entity_t	between_entities;
     67 
     68 bool g_bRestoreBetween = false;
     69 
     70 void Map_SaveBetween (void)
     71 {
     72 
     73 	if (g_pParentWnd->ActiveXY())
     74   {
     75     g_bRestoreBetween = true;
     76     g_pParentWnd->ActiveXY()->Copy();
     77   }
     78   return;
     79 
     80 #if 0
     81 
     82 	brush_t		*b;
     83 	entity_t	*e, *e2;
     84 
     85 	between_brushes.next = selected_brushes.next;
     86 	between_brushes.prev = selected_brushes.prev;
     87 	between_brushes.next->prev = &between_brushes;
     88 	between_brushes.prev->next = &between_brushes;
     89 
     90 	between_entities.next = between_entities.prev = &between_entities;
     91 	selected_brushes.next = selected_brushes.prev = &selected_brushes;
     92 
     93 	for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
     94 	{
     95 		e = b->owner;
     96 		if (e == world_entity)
     97 			b->owner = NULL;
     98 		else
     99 		{
    100 			for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next)
    101 				if (e2 == e)
    102 					goto next;	// allready got the entity
    103 			// move the entity over
    104 			e->prev->next = e->next;
    105 			e->next->prev = e->prev;
    106 			e->next = between_entities.next;
    107 			e->prev = &between_entities;
    108 			e->next->prev = e;
    109 			e->prev->next = e;
    110 		}
    111 next: ;
    112 	}
    113 #endif
    114 }
    115 
    116 void Map_RestoreBetween (void)
    117 {
    118 	if (g_pParentWnd->ActiveXY() && g_bRestoreBetween)
    119     g_pParentWnd->ActiveXY()->Paste();
    120   return;
    121 
    122 #if 0  
    123   entity_t	*head, *tail;
    124 	brush_t		*b;
    125 
    126 	if (!between_brushes.next)
    127 		return;
    128 
    129 	for (b=between_brushes.next ; b != &between_brushes ; b=b->next)
    130 	{
    131 		if (!b->owner)
    132 		{
    133 			b->owner = world_entity;
    134 			b->onext = world_entity->brushes.onext;
    135 			b->oprev = &world_entity->brushes;
    136 			b->onext->oprev = b;
    137 			b->oprev->onext = b;
    138 		}
    139 	}
    140 
    141 	selected_brushes.next = between_brushes.next;
    142 	selected_brushes.prev = between_brushes.prev;
    143 	selected_brushes.next->prev = &selected_brushes;
    144 	selected_brushes.prev->next = &selected_brushes;
    145 
    146 	head = between_entities.next;
    147 	tail = between_entities.prev;
    148 
    149 	if (head != tail)
    150 	{
    151 		entities.prev->next = head;
    152 		head->prev = entities.prev;
    153 		tail->next = &entities;
    154 		entities.prev = tail;
    155 	}
    156 
    157 	between_brushes.next = NULL;
    158 	between_entities.next = NULL;
    159 #endif
    160 }
    161 
    162 //============================================================================
    163 
    164 bool CheckForTinyBrush(brush_t* b, int n, float fSize)
    165 {
    166   bool bTiny = false;
    167 	for (int i=0 ; i<3 ; i++)
    168 	{
    169     if (b->maxs[i] - b->mins[i] < fSize)
    170       bTiny = true;
    171   }
    172   if (bTiny)
    173     Sys_Printf("Possible problem brush (too small) #%i ", n);
    174   return bTiny;
    175 }
    176 
    177 void Map_BuildBrushData(void)
    178 {
    179 	brush_t	*b, *next;
    180 
    181 	if (active_brushes.next == NULL)
    182 		return;
    183 
    184 	Sys_BeginWait ();	// this could take a while
    185 
    186   int n = 0;
    187 	for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next)
    188 	{
    189 		next = b->next;
    190 		Brush_Build( b, true, false, false );
    191 		if (!b->brush_faces || (g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush(b, n++, g_PrefsDlg.m_fTinySize)))
    192 		{
    193 			Brush_Free (b);
    194 			Sys_Printf ("Removed degenerate brush\n");
    195 		}
    196 	}
    197 	Sys_EndWait();
    198 }
    199 
    200 entity_t *Map_FindClass (char *cname)
    201 {
    202 	entity_t	*ent;
    203 
    204 	for (ent = entities.next ; ent != &entities ; ent=ent->next)
    205 	{
    206 		if (!strcmp(cname, ValueForKey (ent, "classname")))
    207 			return ent;
    208 	}
    209 	return NULL;
    210 }
    211 
    212 /*
    213 ================
    214 Map_Free
    215 ================
    216 */
    217 void Map_Free (void)
    218 {
    219   g_bRestoreBetween = false;
    220 	if (selected_brushes.next &&
    221 		(selected_brushes.next != &selected_brushes) )
    222 	{
    223     if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES)
    224 		  Map_SaveBetween ();
    225 	}
    226 
    227 	Texture_ClearInuse ();
    228 	Pointfile_Clear ();
    229 	strcpy (currentmap, "unnamed.map");
    230 	Sys_SetTitle (currentmap);
    231 	g_qeglobals.d_num_entities = 0;
    232 	g_qeglobals.d_numterrapoints = 0;
    233 
    234 	if (!active_brushes.next)
    235 	{	// first map
    236 		active_brushes.prev = active_brushes.next = &active_brushes;
    237 		selected_brushes.prev = selected_brushes.next = &selected_brushes;
    238 		filtered_brushes.prev = filtered_brushes.next = &filtered_brushes;
    239 
    240 		entities.prev = entities.next = &entities;
    241 	}
    242 	else
    243 	{
    244 		while (active_brushes.next != &active_brushes)
    245 			Brush_Free (active_brushes.next);
    246 		while (selected_brushes.next != &selected_brushes)
    247 			Brush_Free (selected_brushes.next);
    248 		while (filtered_brushes.next != &filtered_brushes)
    249 			Brush_Free (filtered_brushes.next);
    250 
    251 		while (entities.next != &entities)
    252 			Entity_Free (entities.next);
    253 	}
    254 
    255   if (world_entity)
    256     Entity_Free(world_entity);
    257 	world_entity = NULL;
    258 }
    259 
    260 entity_t *AngledEntity()
    261 {
    262   entity_t *ent = Map_FindClass ("info_player_start");
    263 	if (!ent)
    264   {
    265 		ent = Map_FindClass ("info_player_deathmatch");
    266   }
    267   if (!ent)
    268   {
    269 		ent = Map_FindClass ("info_player_deathmatch");
    270   }
    271   if (!ent)
    272   {
    273     ent = Map_FindClass ("team_CTF_redplayer");
    274   }
    275   if (!ent)
    276   {
    277     ent = Map_FindClass ("team_CTF_blueplayer");
    278   }
    279   if (!ent)
    280   {
    281     ent = Map_FindClass ("team_CTF_redspawn");
    282   }
    283   if (!ent)
    284   {
    285     ent = Map_FindClass ("team_CTF_bluespawn");
    286   }
    287   return ent;
    288 }
    289 
    290 
    291 
    292 /*
    293 ================
    294 Map_LoadFile
    295 ================
    296 */
    297 void Map_LoadFile (char *filename)
    298 {
    299     char		*buf;
    300 	entity_t	*ent;
    301 	char         temp[1024];
    302 
    303 	Sys_BeginWait ();
    304 	Select_Deselect();
    305 	//SetInspectorMode(W_CONSOLE);
    306 
    307 	QE_ConvertDOSToUnixName( temp, filename );
    308 	Sys_Printf ("Map_LoadFile: %s\n", temp );
    309 
    310 	Map_Free ();
    311 	//++timo FIXME: maybe even easier to have Group_Init called from Map_Free?
    312 	Group_Init();
    313 
    314 	g_qeglobals.d_parsed_brushes = 0;
    315 	strcpy (currentmap, filename);
    316 
    317 	if (LoadFile (filename, (void **)&buf) != -1)
    318 	{
    319 
    320 		StartTokenParsing (buf);
    321 		g_qeglobals.d_num_entities = 0;
    322 
    323 		// Timo
    324 		// will be used in Entity_Parse to detect if a conversion between brush formats is needed
    325 		g_qeglobals.bNeedConvert = false;
    326 		g_qeglobals.bOldBrushes = false;
    327 		g_qeglobals.bPrimitBrushes = false;
    328 
    329 		while (1)
    330 		{
    331 			ent = Entity_Parse (false, &active_brushes);
    332 			if (!ent)
    333 				break;
    334 			if (!strcmp(ValueForKey (ent, "classname"), "worldspawn"))
    335 			{
    336 				if (world_entity)
    337 					Sys_Printf ("WARNING: multiple worldspawn\n");
    338 				world_entity = ent;
    339 			}
    340 			else if (!strcmp(ValueForKey (ent, "classname"), "group_info"))
    341       {
    342         // it's a group thing!
    343         Group_Add(ent);
    344         Entity_Free(ent);
    345       }
    346       else
    347 			{
    348 				// add the entity to the end of the entity list
    349 				ent->next = &entities;
    350 				ent->prev = entities.prev;
    351 				entities.prev->next = ent;
    352 				entities.prev = ent;
    353 				g_qeglobals.d_num_entities++;
    354 			}
    355 		}
    356 	}
    357 
    358   free (buf);
    359 
    360 	if (!world_entity)
    361 	{
    362 		Sys_Printf ("No worldspawn in map.\n");
    363 		Map_New ();
    364 		return;
    365 	}
    366 
    367     Sys_Printf ("--- LoadMapFile ---\n");
    368     Sys_Printf ("%s\n", temp );
    369 
    370     Sys_Printf ("%5i brushes\n",  g_qeglobals.d_parsed_brushes );
    371     Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities);
    372 
    373 	Map_RestoreBetween ();
    374 
    375 	Sys_Printf ("Map_BuildAllDisplayLists\n");
    376     Map_BuildBrushData();
    377 
    378 	// reset the "need conversion" flag
    379 	// conversion to the good format done in Map_BuildBrushData
    380 	g_qeglobals.bNeedConvert=false;
    381 
    382 	//
    383 	// move the view to a start position
    384 	//
    385   ent = AngledEntity();
    386 
    387   g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0;
    388 	if (ent)
    389 	{
    390 		GetVectorForKey (ent, "origin", g_pParentWnd->GetCamera()->Camera().origin);
    391 		GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin());
    392 		g_pParentWnd->GetCamera()->Camera().angles[YAW] = FloatForKey (ent, "angle");
    393 	}
    394 	else
    395 	{
    396 		g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0;
    397 		VectorCopy (vec3_origin, g_pParentWnd->GetCamera()->Camera().origin);
    398 		VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin());
    399 	}
    400 
    401 	Map_RegionOff ();
    402 
    403 
    404 	modified = false;
    405 	Sys_SetTitle (temp);
    406 
    407 	Texture_ShowInuse ();
    408 
    409 	Sys_EndWait();
    410 	Sys_UpdateWindows (W_ALL);
    411 
    412 }
    413 
    414 /*
    415 ===========
    416 Map_SaveFile
    417 ===========
    418 */
    419 void Map_SaveFile (char *filename, qboolean use_region )
    420 {
    421 	entity_t	*e, *next;
    422 	FILE		*f;
    423 	char         temp[1024];
    424 	int			count;
    425 
    426   if (filename == NULL || strlen(filename) == 0)
    427   {
    428     CFileDialog dlgSave(FALSE, "map", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Map Files (*.map)|*.map||", AfxGetMainWnd());
    429     if (dlgSave.DoModal() == IDOK)
    430       filename = strdup(dlgSave.m_ofn.lpstrFile);
    431     else 
    432       return;
    433   }
    434 
    435 	Pointfile_Clear ();
    436 	QE_ConvertDOSToUnixName( temp, filename );
    437 
    438 	if (!use_region)
    439 	{
    440 		char	backup[1024];
    441 
    442 		// rename current to .bak
    443 		strcpy (backup, filename);
    444 		StripExtension (backup);
    445 		strcat (backup, ".bak");
    446 		_unlink (backup);
    447 		rename (filename, backup);
    448 	}
    449 
    450 	Sys_Printf ("Map_SaveFile: %s\n", filename);
    451 
    452 	f = fopen(filename, "w");
    453 
    454 	if (!f)
    455 	{
    456 		Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename);
    457 		return;
    458 	}
    459 
    460 	if (use_region)
    461   {
    462 		AddRegionBrushes ();
    463   }
    464 
    465 	// write world entity first
    466 	Entity_Write (world_entity, f, use_region);
    467 
    468 	// then write all other ents
    469 	count = 1;
    470 	for (e=entities.next ; e != &entities ; e=next)
    471 	{
    472 		next = e->next;
    473 		if (e->brushes.onext == &e->brushes)
    474     {
    475 			Entity_Free (e);	// no brushes left, so remove it
    476     }
    477 		else
    478     {
    479 	   	fprintf (f, "// entity %i\n", count);
    480 	  	count++;
    481 			Entity_Write (e, f, use_region);
    482     }
    483 	}
    484 
    485 	// save the group info stuff
    486 	Group_Save(f);
    487 
    488 	fclose (f);
    489 
    490 	if (use_region)
    491 		RemoveRegionBrushes ();
    492 
    493 	Sys_Printf ("Saved.\n");
    494 	modified = false;
    495 
    496 	if ( !strstr( temp, "autosave" ) )
    497 		Sys_SetTitle (temp);
    498 
    499 	if (!use_region)
    500 	{
    501 		time_t	timer;
    502 		FILE	*f;
    503 
    504 		time (&timer);
    505 		MessageBeep (MB_ICONEXCLAMATION);
    506 		f = fopen ("c:/tstamps.log", "a");
    507 		if (f)
    508 		{
    509 			fprintf (f, "%s", filename);
    510 			//fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer));
    511 			fclose (f);
    512 			g_qeglobals.d_workcount = 0;
    513 		}
    514 		fclose (f);
    515 		Sys_Status ("Saved.\n", 0);
    516 	}
    517 	
    518   //Curve_WriteFile (filename);		//.trinity
    519   //Patch_WriteFile (filename);
    520 }
    521 
    522 /*
    523 ===========
    524 Map_New
    525 ===========
    526 */
    527 void Map_New (void)
    528 {
    529 	Sys_Printf ("Map_New\n");
    530 	Map_Free ();
    531 
    532   Patch_Cleanup();
    533 
    534 	world_entity = (entity_s*)qmalloc(sizeof(*world_entity));
    535 	world_entity->brushes.onext = 
    536 		world_entity->brushes.oprev = &world_entity->brushes;
    537 	SetKeyValue (world_entity, "classname", "worldspawn");
    538 	world_entity->eclass = Eclass_ForName ("worldspawn", true);
    539 
    540 	g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0;
    541 	g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0;
    542 	VectorCopy (vec3_origin, g_pParentWnd->GetCamera()->Camera().origin);
    543 	g_pParentWnd->GetCamera()->Camera().origin[2] = 48;
    544 	VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin());
    545 
    546 	Map_RestoreBetween ();
    547 
    548   Group_Init();
    549 
    550 	Sys_UpdateWindows (W_ALL);
    551 	modified = false;
    552 }
    553 
    554 /*
    555 ===========================================================
    556 
    557   REGION
    558 
    559 ===========================================================
    560 */
    561 
    562 qboolean	region_active;
    563 vec3_t	region_mins = {MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD};
    564 vec3_t	region_maxs = {MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD};
    565 
    566 brush_t	*region_sides[4];
    567 /*
    568 ===========
    569 AddRegionBrushes
    570 
    571 a regioned map will have temp walls put up at the region boundary
    572 ===========
    573 */
    574 void AddRegionBrushes (void)
    575 {
    576 	vec3_t	mins, maxs;
    577 	int		i;
    578 	texdef_t	td;
    579 
    580 	if (!region_active)
    581 		return;
    582 
    583 	memset (&td, 0, sizeof(td));
    584 	//strcpy (td.name, "REGION");
    585 	td.SetName("REGION");
    586 
    587 	mins[0] = region_mins[0] - 16;
    588 	maxs[0] = region_mins[0] + 1;
    589 	mins[1] = region_mins[1] - 16;
    590 	maxs[1] = region_maxs[1] + 16;
    591 	mins[2] = MIN_WORLD_COORD;
    592 	maxs[2] = MAX_WORLD_COORD;
    593 	region_sides[0] = Brush_Create (mins, maxs, &td);
    594 
    595 	mins[0] = region_maxs[0] - 1;
    596 	maxs[0] = region_maxs[0] + 16;
    597 	region_sides[1] = Brush_Create (mins, maxs, &td);
    598 
    599 	mins[0] = region_mins[0] - 16;
    600 	maxs[0] = region_maxs[0] + 16;
    601 	mins[1] = region_mins[1] - 16;
    602 	maxs[1] = region_mins[1] + 1;
    603 	region_sides[2] = Brush_Create (mins, maxs, &td);
    604 
    605 	mins[1] = region_maxs[1] - 1;
    606 	maxs[1] = region_maxs[1] + 16;
    607 	region_sides[3] = Brush_Create (mins, maxs, &td);
    608 
    609 	for (i=0 ; i<4 ; i++)
    610 	{
    611 		Brush_AddToList (region_sides[i], &selected_brushes);
    612 		Entity_LinkBrush (world_entity, region_sides[i]);
    613 		Brush_Build( region_sides[i] );
    614 	}
    615 }
    616 
    617 void RemoveRegionBrushes (void)
    618 {
    619 	int		i;
    620 
    621 	if (!region_active)
    622 		return;
    623 	for (i=0 ; i<4 ; i++)
    624 		Brush_Free (region_sides[i]);
    625 }
    626 
    627 
    628 qboolean Map_IsBrushFiltered (brush_t *b)
    629 {
    630 	int		i;
    631 
    632 	for (i=0 ; i<3 ; i++)
    633 	{
    634 		if (b->mins[i] > region_maxs[i])
    635 			return true;
    636 		if (b->maxs[i] < region_mins[i])
    637 			return true;
    638 	}
    639 	return false;
    640 }
    641 
    642 /*
    643 ===========
    644 Map_RegionOff
    645 
    646 Other filtering options may still be on
    647 ===========
    648 */
    649 void Map_RegionOff (void)
    650 {
    651 	brush_t	*b, *next;
    652 	int			i;
    653 
    654 	region_active = false;
    655 	for (i=0 ; i<3 ; i++)
    656 	{
    657 		region_maxs[i] = MAX_WORLD_COORD;//4096;
    658 		region_mins[i] = MIN_WORLD_COORD;//-4096;
    659 	}
    660 	
    661 	for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next)
    662 	{
    663 		next = b->next;
    664 		if (Map_IsBrushFiltered (b))
    665 			continue;		// still filtered
    666 		Brush_RemoveFromList (b);
    667     if (active_brushes.next == NULL || active_brushes.prev == NULL)
    668     {
    669       active_brushes.next = &active_brushes;
    670       active_brushes.prev = &active_brushes;
    671     }
    672 		Brush_AddToList (b, &active_brushes);
    673 	}
    674 
    675 	Sys_UpdateWindows (W_ALL);
    676 }
    677 
    678 void Map_ApplyRegion (void)
    679 {
    680 	brush_t	*b, *next;
    681 
    682 	region_active = true;
    683 	for (b=active_brushes.next ; b != &active_brushes ; b=next)
    684 	{
    685 		next = b->next;
    686 		if (!Map_IsBrushFiltered (b))
    687 			continue;		// still filtered
    688 		Brush_RemoveFromList (b);
    689 		Brush_AddToList (b, &filtered_brushes);
    690 	}
    691 
    692 	Sys_UpdateWindows (W_ALL);
    693 }
    694 
    695 
    696 /*
    697 ========================
    698 Map_RegionSelectedBrushes
    699 ========================
    700 */
    701 void Map_RegionSelectedBrushes (void)
    702 {
    703 	Map_RegionOff ();
    704 
    705 	if (selected_brushes.next == &selected_brushes)  // nothing selected
    706   {
    707     Sys_Printf("Tried to region with no selection...\n");
    708     return;
    709   }
    710 	region_active = true;
    711 	Select_GetBounds (region_mins, region_maxs);
    712 
    713 	// move the entire active_brushes list to filtered_brushes
    714 	filtered_brushes.next = active_brushes.next;
    715 	filtered_brushes.prev = active_brushes.prev;
    716 	filtered_brushes.next->prev = &filtered_brushes;
    717 	filtered_brushes.prev->next = &filtered_brushes;
    718 
    719 	// move the entire selected_brushes list to active_brushes
    720 	active_brushes.next = selected_brushes.next;
    721 	active_brushes.prev = selected_brushes.prev;
    722 	active_brushes.next->prev = &active_brushes;
    723 	active_brushes.prev->next = &active_brushes;
    724 
    725 	// clear selected_brushes
    726 	selected_brushes.next = selected_brushes.prev = &selected_brushes;
    727 
    728 	Sys_UpdateWindows (W_ALL);
    729 }
    730 
    731 
    732 /*
    733 ===========
    734 Map_RegionXY
    735 ===========
    736 */
    737 void Map_RegionXY (void)
    738 {
    739 	Map_RegionOff ();
    740 
    741 	region_mins[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale();
    742 	region_maxs[0] = g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5 * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale();
    743 	region_mins[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale();
    744 	region_maxs[1] = g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5 * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale();
    745 	region_mins[2] = -MIN_WORLD_COORD;
    746 	region_maxs[2] = MAX_WORLD_COORD;
    747 	Map_ApplyRegion ();
    748 }
    749 
    750 /*
    751 ===========
    752 Map_RegionTallBrush
    753 ===========
    754 */
    755 void Map_RegionTallBrush (void)
    756 {
    757 	brush_t	*b;
    758 
    759 	if (!QE_SingleBrush ())
    760 		return;
    761 
    762 	b = selected_brushes.next;
    763 
    764 	Map_RegionOff ();
    765 
    766 	VectorCopy (b->mins, region_mins);
    767 	VectorCopy (b->maxs, region_maxs);
    768 	region_mins[2] = MIN_WORLD_COORD;
    769 	region_maxs[2] = MAX_WORLD_COORD;
    770 
    771 
    772 	Select_Delete ();
    773 	Map_ApplyRegion ();
    774 }
    775 /*
    776 ===========
    777 Map_RegionBrush
    778 ===========
    779 */
    780 void Map_RegionBrush (void)
    781 {
    782 	brush_t	*b;
    783 
    784 	if (!QE_SingleBrush ())
    785 		return;
    786 
    787 	b = selected_brushes.next;
    788 
    789 	Map_RegionOff ();
    790 
    791 	VectorCopy (b->mins, region_mins);
    792 	VectorCopy (b->maxs, region_maxs);
    793 
    794 	Select_Delete ();
    795 	Map_ApplyRegion ();
    796 }
    797 
    798 
    799 
    800 void UniqueTargetName(CString& rStr)
    801 {
    802 	// make a unique target value
    803 	int maxtarg = 0;
    804 	for (entity_t* e=entities.next ; e != &entities ; e=e->next)
    805 	{
    806 		char* tn = ValueForKey (e, "targetname");
    807 		if (tn && tn[0])
    808 		{
    809 			int targetnum = atoi(tn+1);
    810 			if (targetnum > maxtarg)
    811 				maxtarg = targetnum;
    812 		}
    813     else
    814     {
    815 		  tn = ValueForKey (e, "target");
    816 		  if (tn && tn[0])
    817 		  {
    818 			  int targetnum = atoi(tn+1);
    819 			  if (targetnum > maxtarg)
    820 				  maxtarg = targetnum;
    821 		  }
    822     }
    823 	}
    824   rStr.Format("t%i", maxtarg+1);
    825 }
    826 
    827 //
    828 //================
    829 //Map_ImportFile
    830 // Timo 09/01/99 : called by CXYWnd::Paste & Map_ImportFile
    831 // if Map_ImportFile ( prefab ), the buffer may contain brushes in old format ( conversion needed )
    832 //================
    833 //
    834 void Map_ImportBuffer (char* buf)
    835 {
    836 	entity_t* ent;
    837 	brush_t* b = NULL;
    838 	CPtrArray ptrs;
    839 
    840 	Select_Deselect();
    841 
    842 	Undo_Start("import buffer");
    843 
    844 	g_qeglobals.d_parsed_brushes = 0;
    845 	if (buf)
    846 	{
    847 		CMapStringToString mapStr;
    848 		StartTokenParsing (buf);
    849 		g_qeglobals.d_num_entities = 0;
    850 
    851 		// Timo
    852 		// will be used in Entity_Parse to detect if a conversion between brush formats is needed
    853 		g_qeglobals.bNeedConvert = false;
    854 		g_qeglobals.bOldBrushes = false;
    855 		g_qeglobals.bPrimitBrushes = false;
    856 
    857 		while (1)
    858 		{
    859 
    860 			// use the selected brushes list as it's handy
    861 			//ent = Entity_Parse (false, &selected_brushes);
    862 			ent = Entity_Parse (false, &active_brushes);
    863 			if (!ent)
    864 				break;
    865 			//end entity for undo
    866 			Undo_EndEntity(ent);
    867 			//end brushes for undo
    868 			for(b = ent->brushes.onext; b && b != &ent->brushes; b = b->onext)
    869 			{
    870 				Undo_EndBrush(b);
    871 			}
    872 
    873 			if (!strcmp(ValueForKey (ent, "classname"), "worldspawn"))
    874 			{
    875 				// world brushes need to be added to the current world entity
    876 
    877 				b=ent->brushes.onext;
    878 				while (b && b != &ent->brushes)
    879 				{
    880 					brush_t* bNext = b->onext;
    881 					Entity_UnlinkBrush(b);
    882 					Entity_LinkBrush(world_entity, b);
    883 					ptrs.Add(b);
    884 					b = bNext;
    885 				}
    886 			}
    887 			else
    888 			{
    889 				// the following bit remaps conflicting target/targetname key/value pairs
    890 				CString str = ValueForKey(ent, "target");
    891 				CString strKey;
    892 				CString strTarget("");
    893 				if (str.GetLength() > 0)
    894 				{
    895 					if (FindEntity("target", str.GetBuffer(0)))
    896 					{
    897 						if (!mapStr.Lookup(str, strKey))
    898 						{
    899 							UniqueTargetName(strKey);
    900 							mapStr.SetAt(str, strKey);
    901 						}
    902 						strTarget = strKey;
    903 						SetKeyValue(ent, "target", strTarget.GetBuffer(0));
    904 					}
    905 				}
    906 				str = ValueForKey(ent, "targetname");
    907 				if (str.GetLength() > 0)
    908 				{
    909 					if (FindEntity("targetname", str.GetBuffer(0)))
    910 					{
    911 						if (!mapStr.Lookup(str, strKey))
    912 						{
    913 							UniqueTargetName(strKey);
    914 							mapStr.SetAt(str, strKey);
    915 						}
    916 						SetKeyValue(ent, "targetname", strKey.GetBuffer(0));
    917 					}
    918 				}
    919 				//if (strTarget.GetLength() > 0)
    920 				//  SetKeyValue(ent, "target", strTarget.GetBuffer(0));
    921 
    922 				// add the entity to the end of the entity list
    923 				ent->next = &entities;
    924 				ent->prev = entities.prev;
    925 				entities.prev->next = ent;
    926 				entities.prev = ent;
    927 				g_qeglobals.d_num_entities++;
    928 
    929 				for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
    930 				{
    931 					ptrs.Add(b);
    932 				}
    933 			}
    934 		}
    935 	}
    936 
    937 	//::ShowWindow(g_qeglobals.d_hwndEntity, FALSE);
    938 	//::LockWindowUpdate(g_qeglobals.d_hwndEntity);
    939 	g_bScreenUpdates = false; 
    940 	for (int i = 0; i < ptrs.GetSize(); i++)
    941 	{
    942 		Brush_Build(reinterpret_cast<brush_t*>(ptrs[i]), true, false);
    943 		Select_Brush(reinterpret_cast<brush_t*>(ptrs[i]), true, false);
    944 	}
    945 	//::LockWindowUpdate(NULL);
    946 	g_bScreenUpdates = true; 
    947 
    948 	ptrs.RemoveAll();
    949 
    950 	// reset the "need conversion" flag
    951 	// conversion to the good format done in Map_BuildBrushData
    952 	g_qeglobals.bNeedConvert=false;
    953 
    954 	Sys_UpdateWindows (W_ALL);
    955   //Sys_MarkMapModified();
    956 	modified = true;
    957 
    958 	Undo_End();
    959 
    960 }
    961 
    962 
    963 //
    964 //================
    965 //Map_ImportFile
    966 //================
    967 //
    968 void Map_ImportFile (char *filename)
    969 {
    970   char* buf;
    971 	char temp[1024];
    972 	Sys_BeginWait ();
    973 	QE_ConvertDOSToUnixName( temp, filename );
    974   if (LoadFile (filename, (void **)&buf) != -1)
    975   {
    976     Map_ImportBuffer(buf);
    977     free(buf);
    978     Map_BuildBrushData();
    979   }
    980 	Sys_UpdateWindows (W_ALL);
    981 	modified = true;
    982 	Sys_EndWait();
    983 }
    984 
    985 //
    986 //===========
    987 //Map_SaveSelected
    988 //===========
    989 //
    990 // Saves selected world brushes and whole entities with partial/full selections
    991 //
    992 void Map_SaveSelected(char* pFilename)
    993 {
    994 	entity_t	*e, *next;
    995 	FILE *f;
    996 	char temp[1024];
    997 	int count;
    998 
    999 	QE_ConvertDOSToUnixName(temp, pFilename);
   1000 	f = fopen(pFilename, "w");
   1001 
   1002 	if (!f)
   1003 	{
   1004 		Sys_Printf ("ERROR!!!! Couldn't open %s\n", pFilename);
   1005 		return;
   1006 	}
   1007 
   1008 	// write world entity first
   1009 	Entity_WriteSelected(world_entity, f);
   1010 
   1011 	// then write all other ents
   1012 	count = 1;
   1013 	for (e=entities.next ; e != &entities ; e=next)
   1014 	{
   1015   	fprintf (f, "// entity %i\n", count);
   1016    	count++;
   1017  		Entity_WriteSelected(e, f);
   1018 		next = e->next;
   1019 	}
   1020 	fclose (f);
   1021 }
   1022 
   1023 
   1024 //
   1025 //===========
   1026 //Map_SaveSelected
   1027 //===========
   1028 //
   1029 // Saves selected world brushes and whole entities with partial/full selections
   1030 //
   1031 void Map_SaveSelected(CMemFile* pMemFile, CMemFile* pPatchFile)
   1032 {
   1033 	entity_t	*e, *next;
   1034 	int count;
   1035 	CString strTemp;
   1036   
   1037 	// write world entity first
   1038 	Entity_WriteSelected(world_entity, pMemFile);
   1039 
   1040 	// then write all other ents
   1041 	count = 1;
   1042 	for (e=entities.next ; e != &entities ; e=next)
   1043 	{
   1044 		MemFile_fprintf(pMemFile, "// entity %i\n", count);
   1045 		count++;
   1046  		Entity_WriteSelected(e, pMemFile);
   1047 		next = e->next;
   1048 	}
   1049 
   1050   //if (pPatchFile)
   1051   //  Patch_WriteFile(pPatchFile);
   1052 }
   1053 
   1054 
   1055 void MemFile_fprintf(CMemFile* pMemFile, const char* pText, ...)
   1056 {
   1057   char Buffer[4096];
   1058   va_list args;
   1059 	va_start (args,pText);
   1060   vsprintf(Buffer, pText, args);
   1061   pMemFile->Write(Buffer, strlen(Buffer));
   1062 }