1 #include "Directories.h"
2 #include "Font.h"
3 #include "HImage.h"
4 #include "Handle_Items.h"
5 #include "Local.h"
6 #include "Sys_Globals.h"
7 #include "Timer_Control.h"
8 #include "Types.h"
9 #include "MouseSystem.h"
10 #include "Button_System.h"
11 #include "Font_Control.h"
12 #include "Isometric_Utils.h"
13 #include "VObject.h"
14 #include "WorldDat.h"
15 #include "Render_Dirty.h"
16 #include "SysUtil.h"
17 #include "WordWrap.h"
18 #include "Environment.h"
19 #include "Interface_Items.h"
20 #include "Soldier_Find.h"
21 #include "World_Items.h"
22 #include "Text.h"
23 #include "Overhead_Map.h"
24 #include "Cursor_Modes.h"
25 #include "EditScreen.h"
26 #include "EditorTerrain.h"
27 #include "EditorItems.h"
28 #include "EditorMercs.h"
29 #include "EditorBuildings.h"
30 #include "EditorMapInfo.h"
31 #include "EditorDefines.h"
32 #include "Editor_Taskbar_Utils.h"
33 #include "Editor_Taskbar_Creation.h"
34 #include "Editor_Callback_Prototypes.h"
35 #include "Editor_Modes.h"
36 #include "Text_Input.h"
37 #include "Item_Statistics.h"
38 #include "Map_Information.h"
39 #include "Sector_Summary.h"
40 #include "Pits.h"
41 #include "Lighting.h"
42 #include "Keys.h"
43 #include "Debug.h"
44 #include "JAScreens.h"
45 #include "Video.h"
46 #include "VSurface.h"
47 
48 #include "ContentManager.h"
49 #include "GameInstance.h"
50 
51 #include <string_theory/format>
52 #include <string_theory/string>
53 
54 #include <stdarg.h>
55 
56 
57 //editor icon storage vars
58 INT32	giEditMercDirectionIcons[2];
59 SGPVObject* guiMercInventoryPanel;
60 SGPVObject* guiOmertaMap;
61 SGPVSurface* guiMercInvPanelBuffers[9];
62 SGPVSurface* guiMercTempBuffer;
63 SGPVObject* guiExclamation;
64 SGPVObject* guiKeyImage;
65 
66 //editor Mouseregion storage vars
67 static MOUSE_REGION TerrainTileButtonRegion[NUM_TERRAIN_TILE_REGIONS];
68 static MOUSE_REGION ItemsRegion;
69 static MOUSE_REGION MercRegion;
70 static MOUSE_REGION EditorRegion;
71 
EnableEditorRegion(INT8 bRegionID)72 void EnableEditorRegion( INT8 bRegionID )
73 {
74 	switch( bRegionID )
75 	{
76 		case BASE_TERRAIN_TILE_REGION_ID:
77 		case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
78 			TerrainTileButtonRegion[bRegionID].Enable();
79 			break;
80 		case ITEM_REGION_ID:
81 			ItemsRegion.Enable();
82 			break;
83 		case MERC_REGION_ID:
84 			MercRegion.Enable();
85 			break;
86 	}
87 }
88 
DisableEditorRegion(INT8 bRegionID)89 void DisableEditorRegion( INT8	bRegionID )
90 {
91 	switch( bRegionID )
92 	{
93 		case BASE_TERRAIN_TILE_REGION_ID:
94 		case 1: case 2: case 3: case 4: case 5: case 6: case 7:
95 			TerrainTileButtonRegion[bRegionID].Disable();
96 			break;
97 		case ITEM_REGION_ID:
98 			ItemsRegion.Disable();
99 			break;
100 		case MERC_REGION_ID:
101 			MercRegion.Disable();
102 			break;
103 	}
104 }
105 
106 
RemoveEditorRegions(void)107 static void RemoveEditorRegions(void)
108 {
109 	INT32 x;
110 	MSYS_RemoveRegion( &EditorRegion );
111 	for(x = BASE_TERRAIN_TILE_REGION_ID; x < NUM_TERRAIN_TILE_REGIONS; x++ )
112 	{
113 		MSYS_RemoveRegion( &TerrainTileButtonRegion[ x ] );
114 	}
115 	MSYS_RemoveRegion( &ItemsRegion );
116 	MSYS_RemoveRegion( &MercRegion );
117 }
118 
119 
InitEditorRegions()120 static void InitEditorRegions()
121 {
122 	/* By doing this, all of the buttons underneath are blanketed and can't be
123 	 * used anymore. Any new buttons will cover this up as well. Think of it as a
124 	 * barrier between the editor buttons and the game's interface panel buttons
125 	 * and regions. */
126 	MSYS_DefineRegion(&EditorRegion, 0, EDITOR_TASKBAR_POS_Y, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_NORMAL, 0, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
127 
128 	// Create the regions for the terrain tile selections.
129 	UINT16       x   = 261;
130 	UINT16 const y   = EDITOR_TASKBAR_POS_Y + 9;
131 	INT32        idx =   0;
132 	FOR_EACHX(MOUSE_REGION, i, TerrainTileButtonRegion, x += 42)
133 	{
134 		MOUSE_REGION& r = *i;
135 		MSYS_DefineRegion(&r, x, y, x + 42, y + 22, MSYS_PRIORITY_NORMAL, 0, MSYS_NO_CALLBACK, TerrainTileButtonRegionCallback);
136 		MSYS_SetRegionUserData(&r, 0, idx++);
137 		r.Disable();
138 	}
139 	gfShowTerrainTileButtons = FALSE;
140 
141 	// Create the region for the items selection window.
142 	MSYS_DefineRegion(&ItemsRegion, 100, EDITOR_TASKBAR_POS_Y, 540, EDITOR_TASKBAR_POS_Y + 80, MSYS_PRIORITY_NORMAL, 0, MouseMovedInItemsRegion, MouseClickedInItemsRegion);
143 	ItemsRegion.Disable();
144 
145 	// Create the region for the merc inventory panel.
146 	MSYS_DefineRegion(&MercRegion, 175, EDITOR_TASKBAR_POS_Y + 1, 450, EDITOR_TASKBAR_POS_Y + 80, MSYS_PRIORITY_NORMAL, 0, MouseMovedInMercRegion, MouseClickedInMercRegion);
147 	MercRegion.Disable();
148 }
149 
150 
LoadEditorImages(void)151 static void LoadEditorImages(void)
152 {
153 	//Set up the merc inventory panel
154 	guiMercInventoryPanel = AddVideoObjectFromFile(EDITORDIR "/invpanel.sti");
155 	//Set up small omerta map
156 	guiOmertaMap          = AddVideoObjectFromFile(EDITORDIR "/omerta.sti");
157 	//Set up the merc directional buttons.
158 	giEditMercDirectionIcons[0] = LoadGenericButtonIcon(EDITORDIR "/arrowsoff.sti");
159 	giEditMercDirectionIcons[1] = LoadGenericButtonIcon(EDITORDIR "/arrowson.sti");
160 
161 	guiExclamation = AddVideoObjectFromFile(EDITORDIR "/exclamation.sti");
162 	guiKeyImage    = AddVideoObjectFromFile(EDITORDIR "/keyimage.sti");
163 }
164 
165 
DeleteEditorImages(void)166 static void DeleteEditorImages(void)
167 {
168 	//The merc inventory panel
169 	DeleteVideoObject(guiMercInventoryPanel);
170 	DeleteVideoObject(guiOmertaMap);
171 	//The merc directional buttons
172 	UnloadGenericButtonIcon( (INT16)giEditMercDirectionIcons[0] );
173 	UnloadGenericButtonIcon( (INT16)giEditMercDirectionIcons[1] );
174 }
175 
176 
CreateEditorBuffers(void)177 static void CreateEditorBuffers(void)
178 {
179 	INT32						i;
180 
181 	//create buffer for the transition slot for merc items.  This slot contains the newly
182 	//selected item graphic in it's inventory size version.  This buffer is then scaled down
183 	//into the associated merc inventory panel slot buffer which is approximately 20% smaller.
184 	guiMercTempBuffer = AddVideoSurface(60, 25, PIXEL_DEPTH);
185 
186 	//create the nine buffers for the merc's inventory slots.
187 	for( i = 0; i < 9; i++ )
188 	{
189 		guiMercInvPanelBuffers[i] = AddVideoSurface(i < 3 ? MERCINV_SMSLOT_WIDTH : MERCINV_LGSLOT_WIDTH, MERCINV_SLOT_HEIGHT, PIXEL_DEPTH);
190 		guiMercInvPanelBuffers[i]->SetTransparency(0);
191 	}
192 }
193 
194 
DeleteEditorBuffers(void)195 static void DeleteEditorBuffers(void)
196 {
197 	INT32 i;
198 	DeleteVideoSurface(guiMercTempBuffer);
199 	for( i = 0; i < 9; i++ )
200 	{
201 		DeleteVideoSurface(guiMercInvPanelBuffers[i]);
202 	}
203 }
204 
205 
ShowEditorToolbar(TaskMode const iNewTaskMode)206 static void ShowEditorToolbar(TaskMode const iNewTaskMode)
207 {
208 	switch( iNewTaskMode )
209 	{
210 		case TASK_TERRAIN:
211 			ShowEditorButtons(FIRST_TERRAIN_BUTTON, LAST_TERRAIN_BUTTON);
212 			break;
213 		case TASK_BUILDINGS:
214 			ShowEditorButtons(FIRST_BUILDINGS_BUTTON, LAST_BUILDINGS_BUTTON);
215 			break;
216 		case TASK_ITEMS:
217 			ShowEditorButtons(FIRST_ITEMS_BUTTON, LAST_ITEMS_BUTTON);
218 			break;
219 		case TASK_MERCS:
220 			ShowEditorButtons(FIRST_MERCS_TEAMMODE_BUTTON, LAST_MERCS_TEAMMODE_BUTTON);
221 			break;
222 		case TASK_MAPINFO:
223 			ShowEditorButtons(FIRST_MAPINFO_BUTTON, LAST_MAPINFO_BUTTON);
224 			break;
225 		case TASK_OPTIONS:
226 			ShowEditorButtons(FIRST_OPTIONS_BUTTON, LAST_OPTIONS_BUTTON);
227 			break;
228 		default:
229 			return;
230 	}
231 }
232 
233 
HideEditorToolbar(TaskMode const iOldTaskMode)234 static void HideEditorToolbar(TaskMode const iOldTaskMode)
235 {
236 	INT32 i, iStart, iEnd;
237 	switch( iOldTaskMode )
238 	{
239 		case TASK_TERRAIN:
240 			iStart = FIRST_TERRAIN_BUTTON;
241 			iEnd = LAST_TERRAIN_BUTTON;
242 			break;
243 		case TASK_BUILDINGS:
244 			iStart = FIRST_BUILDINGS_BUTTON;
245 			iEnd = LAST_BUILDINGS_BUTTON;
246 			break;
247 		case TASK_ITEMS:
248 			iStart = FIRST_ITEMS_BUTTON;
249 			iEnd = LAST_ITEMS_BUTTON;
250 			break;
251 		case TASK_MERCS:
252 			iStart = FIRST_MERCS_BUTTON;
253 			iEnd = LAST_MERCS_BUTTON;
254 			break;
255 		case TASK_MAPINFO:
256 			iStart = FIRST_MAPINFO_BUTTON;
257 			iEnd = LAST_MAPINFO_BUTTON;
258 			break;
259 		case TASK_OPTIONS:
260 			iStart = FIRST_OPTIONS_BUTTON;
261 			iEnd = LAST_OPTIONS_BUTTON;
262 			break;
263 		default:
264 			return;
265 	}
266 	for( i = iStart; i <= iEnd; i++ )
267 	{
268 		HideButton( iEditorButton[ i ] );
269 		UnclickEditorButton( i );
270 	}
271 }
272 
CreateEditorTaskbar()273 void CreateEditorTaskbar()
274 {
275 	InitEditorRegions();
276 	LoadEditorImages();
277 	CreateEditorBuffers();
278 	CreateEditorTaskbarInternal();
279 	HideItemStatsPanel();
280 }
281 
282 
DeleteEditorTaskbar()283 void DeleteEditorTaskbar()
284 {
285 	iOldTaskMode = iCurrentTaskbar;
286 
287 	FOR_EACH(GUIButtonRef, i, iEditorButton) RemoveButton(*i);
288 
289 	RemoveEditorRegions();
290 	DeleteEditorImages();
291 	DeleteEditorBuffers();
292 }
293 
294 
DoTaskbar(void)295 void DoTaskbar(void)
296 {
297 	if (iTaskMode == TASK_NONE || iTaskMode == iCurrentTaskbar)
298 	{
299 		return;
300 	}
301 
302 	gfRenderTaskbar = TRUE;
303 
304 	HideEditorToolbar( iCurrentTaskbar );
305 
306 	//Special code when exiting previous editor tab
307 	switch( iCurrentTaskbar )
308 	{
309 		case TASK_TERRAIN:
310 			UnclickEditorButton( TAB_TERRAIN );
311 			HideTerrainTileButtons();
312 			break;
313 		case TASK_BUILDINGS:
314 			UnclickEditorButton( TAB_BUILDINGS );
315 			KillTextInputMode();
316 			break;
317 		case TASK_ITEMS:
318 			UnclickEditorButton( TAB_ITEMS );
319 			HideItemStatsPanel();
320 			if( eInfo.fActive )
321 				ClearEditorItemsInfo();
322 			gfShowPits = FALSE;
323 			RemoveAllPits();
324 			break;
325 		case TASK_MERCS:
326 			UnclickEditorButton( TAB_MERCS );
327 			IndicateSelectedMerc( SELECT_NO_MERC );
328 			SetMercEditingMode( MERC_NOMODE );
329 			break;
330 		case TASK_MAPINFO:
331 			UnclickEditorButton( TAB_MAPINFO );
332 			ExtractAndUpdateMapInfo();
333 			KillTextInputMode();
334 			HideExitGrids();
335 			break;
336 		case TASK_OPTIONS:
337 			UnclickEditorButton( TAB_OPTIONS );
338 			break;
339 		default:
340 			break;
341 	}
342 
343 	//Setup the new tab mode
344 	iCurrentTaskbar = iTaskMode;
345 	ShowEditorToolbar( iTaskMode );
346 	iTaskMode = TASK_NONE;
347 
348 	//Special code when entering a new editor tab
349 	switch( iCurrentTaskbar )
350 	{
351 		case TASK_MERCS:
352 			ClickEditorButton( TAB_MERCS );
353 			ClickEditorButton( MERCS_ENEMY);
354 			iDrawMode = DRAW_MODE_ENEMY;
355 			SetMercEditingMode( MERC_TEAMMODE );
356 			fBuildingShowRoofs = FALSE;
357 			UpdateRoofsView();
358 			break;
359 		case TASK_TERRAIN:
360 			ClickEditorButton( TAB_TERRAIN );
361 			ShowTerrainTileButtons();
362 			SetEditorTerrainTaskbarMode( TERRAIN_FGROUND_TEXTURES );
363 			break;
364 		case TASK_BUILDINGS:
365 			ClickEditorButton( TAB_BUILDINGS );
366 			if(fBuildingShowRoofs)
367 				ClickEditorButton( BUILDING_TOGGLE_ROOF_VIEW );
368 			if(fBuildingShowWalls)
369 				ClickEditorButton( BUILDING_TOGGLE_WALL_VIEW );
370 			if(fBuildingShowRoomInfo)
371 				ClickEditorButton( BUILDING_TOGGLE_INFO_VIEW );
372 			if( gfCaves )
373 			{
374 				ClickEditorButton( BUILDING_CAVE_DRAWING );
375 				iDrawMode = DRAW_MODE_CAVES;
376 			}
377 			else
378 			{
379 				ClickEditorButton( BUILDING_NEW_ROOM );
380 				iDrawMode = DRAW_MODE_ROOM;
381 			}
382 			TerrainTileDrawMode = TERRAIN_TILES_BRETS_STRANGEMODE;
383 			SetEditorSmoothingMode( gMapInformation.ubEditorSmoothingType );
384 			gusSelectionType = gusSavedBuildingSelectionType;
385 			SetupTextInputForBuildings();
386 			break;
387 		case TASK_ITEMS:
388 			SetFont( FONT10ARIAL );
389 			SetFontForeground( FONT_YELLOW );
390 			ClickEditorButton( TAB_ITEMS );
391 			ClickEditorButton( ITEMS_WEAPONS + eInfo.uiItemType - TBAR_MODE_ITEM_WEAPONS );
392 			InitEditorItemsInfo( eInfo.uiItemType );
393 			ShowItemStatsPanel();
394 			gfShowPits = TRUE;
395 			AddAllPits();
396 			iDrawMode = DRAW_MODE_PLACE_ITEM;
397 			break;
398 		case TASK_MAPINFO:
399 			ClickEditorButton( TAB_MAPINFO );
400 			if ( gfFakeLights )
401 				ClickEditorButton( MAPINFO_TOGGLE_FAKE_LIGHTS );
402 			ClickEditorButton( MAPINFO_ADD_LIGHT1_SOURCE );
403 			iDrawMode = DRAW_MODE_LIGHT;
404 			TerrainTileDrawMode = TERRAIN_TILES_BRETS_STRANGEMODE;
405 			SetupTextInputForMapInfo();
406 			break;
407 		case TASK_OPTIONS:
408 			ClickEditorButton( TAB_OPTIONS );
409 			iDrawMode           = DRAW_MODE_NOTHING;
410 			TerrainTileDrawMode = TERRAIN_TILES_NODRAW;
411 			break;
412 		default:
413 			break;
414 	}
415 }
416 
417 
DisableEditorTaskbar()418 void DisableEditorTaskbar()
419 {
420 	FOR_EACH(GUIButtonRef, i, iEditorButton) DisableButton(*i);
421 }
422 
423 
EnableEditorTaskbar(void)424 void EnableEditorTaskbar(void)
425 {
426 	INT32 x;
427 
428 	for(x = 0; x < NUMBER_EDITOR_BUTTONS; x++ )
429 		EnableButton( iEditorButton[ x ] );
430 	//Keep permanent buttons disabled.
431 	DisableButton( iEditorButton[ MERCS_1 ] );
432 	DisableButton( iEditorButton[ MAPINFO_LIGHT_PANEL ] );
433 	DisableButton( iEditorButton[ MAPINFO_RADIO_PANEL ] );
434 	DisableButton( iEditorButton[ ITEMSTATS_PANEL ] );
435 	DisableButton( iEditorButton[ MERCS_PLAYERTOGGLE ] );
436 	DisableButton( iEditorButton[ MERCS_PLAYER ] );
437 	if( iCurrentTaskbar == TASK_ITEMS )
438 		DetermineItemsScrolling();
439 }
440 
441 //A specialized mprint function that'll restore the editor panel underneath the
442 //string before rendering the string.  This is obviously only useful for drawing text
443 //in the editor taskbar.
MPrintEditor(INT16 x,INT16 y,const ST::string & str)444 void MPrintEditor(INT16 x, INT16 y, const ST::string& str)
445 {
446 	UINT16 uiStringLength, uiStringHeight;
447 
448 	uiStringLength = StringPixLength( str, FontDefault );
449 	uiStringHeight = GetFontHeight( FontDefault );
450 
451 	ClearTaskbarRegion( x, y, (INT16)(x+uiStringLength), (INT16)(y+uiStringHeight) );
452 	MPrint(x, TASKBAR_Y + y, str);
453 }
454 
ClearTaskbarRegion(INT16 sLeft,INT16 sTop,INT16 sRight,INT16 sBottom)455 void ClearTaskbarRegion( INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
456 {
457 	sTop    += TASKBAR_Y;
458 	sBottom += TASKBAR_Y;
459 	ColorFillVideoSurfaceArea( ButtonDestBuffer, sLeft, sTop, sRight, sBottom, gusEditorTaskbarColor );
460 
461 	if( !sLeft )
462 	{
463 		ColorFillVideoSurfaceArea( ButtonDestBuffer, 0, sTop, 1, sBottom, gusEditorTaskbarHiColor );
464 		sLeft++;
465 	}
466 	if( sTop == EDITOR_TASKBAR_POS_Y )
467 	{
468 		ColorFillVideoSurfaceArea( ButtonDestBuffer, sLeft, EDITOR_TASKBAR_POS_Y, sRight, EDITOR_TASKBAR_POS_Y+1, gusEditorTaskbarHiColor );
469 		sTop++;
470 	}
471 	if (sBottom == SCREEN_HEIGHT)
472 	{
473 		ColorFillVideoSurfaceArea(ButtonDestBuffer, sLeft, SCREEN_HEIGHT - 1, sRight, SCREEN_HEIGHT, gusEditorTaskbarLoColor);
474 	}
475 	if (sRight == SCREEN_WIDTH)
476 	{
477 		ColorFillVideoSurfaceArea(ButtonDestBuffer, SCREEN_WIDTH - 1, sTop, SCREEN_WIDTH, sBottom, gusEditorTaskbarLoColor);
478 	}
479 
480 	InvalidateRegion( sLeft, sTop, sRight, sBottom );
481 }
482 
483 
484 //Kris:
485 //This is a new function which duplicates the older "yellow info boxes" that
486 //are common throughout the editor.  This draws the yellow box with the indentation
487 //look.
DrawEditorInfoBox(const ST::string & str,SGPFont const font,UINT16 x,UINT16 y,UINT16 w,UINT16 h)488 void DrawEditorInfoBox(const ST::string& str, SGPFont const font, UINT16 x, UINT16 y, UINT16 w, UINT16 h)
489 {
490 	UINT16 usFillColorDark, usFillColorLight, usFillColorBack;
491 	UINT16 x2, y2;
492 
493 	y  += TASKBAR_Y;
494 	x2  = x + w;
495 	y2  = y + h;
496 
497 	usFillColorDark = Get16BPPColor(FROMRGB(24, 61, 81));
498 	usFillColorLight = Get16BPPColor(FROMRGB(136, 138, 135));
499 	usFillColorBack = Get16BPPColor(FROMRGB(250, 240, 188));
500 
501 	ColorFillVideoSurfaceArea(ButtonDestBuffer, x, y, x2, y2, usFillColorDark);
502 	ColorFillVideoSurfaceArea(ButtonDestBuffer, x + 1, y + 1, x2, y2, usFillColorLight);
503 	ColorFillVideoSurfaceArea(ButtonDestBuffer, x + 1, y + 1, x2 - 1, y2 - 1, usFillColorBack);
504 
505 	UINT16 const usStrWidth = StringPixLength(str, font);
506 	if( usStrWidth > w )
507 	{ //the string is too long, so use the wrapped method
508 		y += 1;
509 		DisplayWrappedString(x, y, w, 2, font, FONT_BLACK, str, FONT_BLACK, CENTER_JUSTIFIED | MARK_DIRTY);
510 		return;
511 	}
512 	//center the string vertically and horizontally.
513 	SetFontAttributes(font, FONT_BLACK, NO_SHADOW);
514 	x += (w - StringPixLength(str, font)) / 2;
515 	y += (h - GetFontHeight(font)) / 2;
516 	MPrint(x, y, str);
517 	InvalidateRegion( x, y, x2, y2 );
518 }
519 
ClickEditorButton(INT32 iEditorButtonID)520 void ClickEditorButton( INT32 iEditorButtonID )
521 {
522 	if ( iEditorButtonID < 0 || iEditorButtonID >= NUMBER_EDITOR_BUTTONS )
523 		return;
524 	GUIButtonRef const b = iEditorButton[iEditorButtonID];
525 	if (b) b->uiFlags |= BUTTON_CLICKED_ON;
526 }
527 
UnclickEditorButton(INT32 iEditorButtonID)528 void UnclickEditorButton( INT32 iEditorButtonID )
529 {
530 	if ( iEditorButtonID < 0 || iEditorButtonID >= NUMBER_EDITOR_BUTTONS )
531 		return;
532 	GUIButtonRef const b = iEditorButton[iEditorButtonID];
533 	if (b) b->uiFlags &= ~BUTTON_CLICKED_ON;
534 }
535 
HideEditorButton(INT32 iEditorButtonID)536 void HideEditorButton( INT32 iEditorButtonID )
537 {
538 	HideButton( iEditorButton[ iEditorButtonID ] );
539 }
540 
ShowEditorButton(INT32 iEditorButtonID)541 void ShowEditorButton( INT32 iEditorButtonID )
542 {
543 	ShowButton( iEditorButton[ iEditorButtonID ] );
544 }
545 
DisableEditorButton(INT32 iEditorButtonID)546 void DisableEditorButton( INT32 iEditorButtonID )
547 {
548 	DisableButton( iEditorButton[ iEditorButtonID ] );
549 }
550 
EnableEditorButton(INT32 iEditorButtonID)551 void EnableEditorButton( INT32 iEditorButtonID )
552 {
553 	EnableButton( iEditorButton[ iEditorButtonID ] );
554 }
555 
556 
UnclickEditorButtons(INT32 iFirstEditorButtonID,INT32 iLastEditorButtonID)557 void UnclickEditorButtons( INT32 iFirstEditorButtonID, INT32 iLastEditorButtonID )
558 {
559 	INT32 i;
560 	for( i = iFirstEditorButtonID; i <= iLastEditorButtonID; i++ )
561 	{
562 		GUIButtonRef const b = iEditorButton[i];
563 		Assert( b );
564 		b->uiFlags &= (~BUTTON_CLICKED_ON);
565 	}
566 }
567 
HideEditorButtons(INT32 iFirstEditorButtonID,INT32 iLastEditorButtonID)568 void HideEditorButtons( INT32 iFirstEditorButtonID, INT32 iLastEditorButtonID )
569 {
570 	INT32 i;
571 	for( i = iFirstEditorButtonID; i <= iLastEditorButtonID; i++ )
572 		HideButton( iEditorButton[ i ] );
573 }
574 
ShowEditorButtons(INT32 iFirstEditorButtonID,INT32 iLastEditorButtonID)575 void ShowEditorButtons( INT32 iFirstEditorButtonID, INT32 iLastEditorButtonID )
576 {
577 	INT32 i;
578 	for( i = iFirstEditorButtonID; i <= iLastEditorButtonID; i++ )
579 		ShowButton( iEditorButton[ i ] );
580 }
581 
DisableEditorButtons(INT32 iFirstEditorButtonID,INT32 iLastEditorButtonID)582 void DisableEditorButtons( INT32 iFirstEditorButtonID, INT32 iLastEditorButtonID )
583 {
584 	INT32 i;
585 	for( i = iFirstEditorButtonID; i <= iLastEditorButtonID; i++ )
586 		DisableButton( iEditorButton[ i ] );
587 }
588 
EnableEditorButtons(INT32 iFirstEditorButtonID,INT32 iLastEditorButtonID)589 void EnableEditorButtons( INT32 iFirstEditorButtonID, INT32 iLastEditorButtonID )
590 {
591 	INT32 i;
592 	for( i = iFirstEditorButtonID; i <= iLastEditorButtonID; i++ )
593 		EnableButton( iEditorButton[ i ] );
594 }
595 
596 
RenderEntryPoint(INT16 const gridno,const ST::string & label)597 static void RenderEntryPoint(INT16 const gridno, const ST::string& label)
598 {
599 	if (gridno == -1) return;
600 	INT16 x;
601 	INT16 y;
602 	GetGridNoScreenPos(gridno, 0, &x, &y);
603 	if (x < -40 || SCREEN_WIDTH <= x || y < -20 || TASKBAR_Y - 20 <= y) return;
604 	DisplayWrappedString(x, y - 5, 40, 2, FONT10ARIAL, FONT_YELLOW, label, FONT_BLACK, CENTER_JUSTIFIED | MARK_DIRTY);
605 }
606 
607 
RenderMapEntryPointsAndLights(void)608 static void RenderMapEntryPointsAndLights(void)
609 {
610 	if (gfSummaryWindowActive) return;
611 
612 	SetFontShadow(FONT_NEARBLACK);
613 	RenderEntryPoint(gMapInformation.sNorthGridNo,    "North Entry Point");
614 	RenderEntryPoint(gMapInformation.sWestGridNo,     "West Entry Point");
615 	RenderEntryPoint(gMapInformation.sEastGridNo,     "East Entry Point");
616 	RenderEntryPoint(gMapInformation.sSouthGridNo,    "South Entry Point");
617 	RenderEntryPoint(gMapInformation.sCenterGridNo,   "Center Entry Point");
618 	RenderEntryPoint(gMapInformation.sIsolatedGridNo, "Isolated Entry Point");
619 
620 	//Do the lights now.
621 	CFOR_EACH_LIGHT_SPRITE(l)
622 	{
623 		INT16       x;
624 		INT16       y;
625 		INT16 const gridno = l->iY * WORLD_COLS + l->iX;
626 		GetGridNoScreenPos(gridno, 0, &x, &y);
627 		if (x < -40 || SCREEN_WIDTH <= x || y < -50 || TASKBAR_Y - 60 <= y) continue;
628 
629 		UINT8          colour;
630 		ST::string text;
631 		if (l->uiFlags & LIGHT_PRIMETIME)
632 		{
633 			colour = FONT_ORANGE;
634 			text   = "Prime";
635 		}
636 		else if (l->uiFlags & LIGHT_NIGHTTIME)
637 		{
638 			colour = FONT_RED;
639 			text   = "Night";
640 		}
641 		else
642 		{
643 			colour = FONT_YELLOW;
644 			text   = "24Hour";
645 		}
646 		DisplayWrappedString(x, y - 5, 50, 2, FONT10ARIAL, colour, text, FONT_BLACK, CENTER_JUSTIFIED | MARK_DIRTY);
647 	}
648 }
649 
650 
BuildTriggerName(OBJECTTYPE const & o)651 static ST::string BuildTriggerName(OBJECTTYPE const& o)
652 {
653 	if (o.usItem == SWITCH)
654 	{
655 		switch (o.bFrequency)
656 		{
657 			case PANIC_FREQUENCY:   return "Panic Trigger1";
658 			case PANIC_FREQUENCY_2: return "Panic Trigger2";
659 			case PANIC_FREQUENCY_3: return "Panic Trigger3";
660 			default: return ST::format("Trigger{}", o.bFrequency - 50);
661 		}
662 	}
663 	else
664 	{ // Action item
665 		if (o.bDetonatorType == BOMB_PRESSURE)
666 		{
667 			return "Pressure Action";
668 		}
669 		else switch (o.bFrequency)
670 		{
671 			case PANIC_FREQUENCY:   return "Panic Action1";
672 			case PANIC_FREQUENCY_2: return "Panic Action2";
673 			case PANIC_FREQUENCY_3: return "Panic Action3";
674 			default: return ST::format("Action{}", o.bFrequency - 50);
675 		}
676 	}
677 }
678 
679 
RenderDoorLockInfo()680 static void RenderDoorLockInfo()
681 {
682 	ST::string str;
683 	FOR_EACH_DOOR(d)
684 	{
685 		INT16 screen_x;
686 		INT16 screen_y;
687 		GetGridNoScreenPos(d.sGridNo, 0, &screen_x, &screen_y);
688 		INT16 const x = screen_x;
689 		INT16 const y = screen_y;
690 		if (y > 390) continue;
691 
692 		if (d.ubLockID != 255)
693 			str = ST::format("{}", LockTable[d.ubLockID].ubEditorName);
694 		else
695 			str = "No Lock ID";
696 		DisplayWrappedString(x - 10, y - 40, 60, 2, FONT10ARIAL, FONT_LTKHAKI, str, FONT_BLACK, CENTER_JUSTIFIED | MARK_DIRTY);
697 
698 		ST::string trap_type;
699 		switch (d.ubTrapID)
700 		{
701 			case NO_TRAP:        continue;
702 			case EXPLOSION:      trap_type = "Explosion Trap";      break;
703 			case ELECTRIC:       trap_type = "Electric Trap";       break;
704 			case SIREN:          trap_type = "Siren Trap";          break;
705 			case SILENT_ALARM:   trap_type = "Silent Alarm";        break;
706 			case BROTHEL_SIREN:  trap_type = "Brothel Siren Trap";  break;
707 			case SUPER_ELECTRIC: trap_type = "Super Electric Trap"; break;
708 		}
709 		SetFontAttributes(FONT10ARIAL, FONT_RED);
710 		MPrint(x + 20 - StringPixLength(trap_type, FONT10ARIAL) / 2, y, trap_type);
711 		str = ST::format("Trap Level {}", d.ubTrapLevel);
712 		MPrint(x + 20 - StringPixLength(str, FONT10ARIAL) / 2, y + 10, str);
713 	}
714 }
715 
716 
RenderSelectedItemBlownUp(void)717 static void RenderSelectedItemBlownUp(void)
718 {
719 	INT16 screen_x;
720 	INT16 screen_y;
721 	GetGridNoScreenPos(gsItemGridNo, 0, &screen_x, &screen_y);
722 	if (screen_y > (EDITOR_TASKBAR_POS_Y - 20)) return;
723 
724 	OBJECTTYPE const& o    = *gpItem;
725 	const ItemModel * item = GCM->getItem(o.usItem);
726 	INT16             x;
727 	INT16             y;
728 
729 	// Display the enlarged item graphic
730 	SGPVObject  const& vo = GetInterfaceGraphicForItem(item);
731 	ETRLEObject const& e  = vo.SubregionProperties(item->getGraphicNum());
732 	x = screen_x - e.sOffsetX + (40 - e.usWidth)  / 2;
733 	y = screen_y - e.sOffsetY + (20 - e.usHeight) / 2;
734 	BltVideoObjectOutline(FRAME_BUFFER, &vo, item->getGraphicNum(), x, y, Get16BPPColor(FROMRGB(0, 140, 170)));
735 
736 	// Display the item name above it
737 	SetFontAttributes(FONT10ARIAL, FONT_YELLOW);
738 	ST::string item_name;
739 	if (o.usItem == ACTION_ITEM || o.usItem == SWITCH)
740 	{
741 		item_name = BuildTriggerName(o);
742 	}
743 	else if (item->getItemClass() == IC_KEY)
744 	{
745 		item_name = ST::format("{}", LockTable[o.ubKeyID].ubEditorName);
746 	}
747 	else
748 	{
749 		item_name = ItemNames[o.usItem];
750 	}
751 	x  = screen_x - (StringPixLength(item_name, FONT10ARIAL) - 40) / 2;
752 	y -= 10;
753 	MPrint(x, y, item_name);
754 
755 	if (o.usItem == ACTION_ITEM)
756 	{
757 		SetFont(FONT10ARIALBOLD);
758 		SetFontForeground(FONT_LTKHAKI);
759 		ST::string name = GetActionItemName(&o);
760 		x  = screen_x - (StringPixLength(name, FONT10ARIALBOLD) - 40) / 2;
761 		y += 10;
762 		MPrint(x, y, name);
763 		SetFontForeground(FONT_YELLOW);
764 	}
765 
766 	// Count the number of items in the current pool, and display that.
767 	INT32 n = 0;
768 	for (ITEM_POOL const* i = GetItemPool(gsItemGridNo, 0); i; i = i->pNext)
769 	{
770 		++n;
771 	}
772 	MPrint(screen_x, screen_y + 10, ST::format("{}", n));
773 
774 	// If the item is hidden, render a blinking H (just like DG)
775 	WORLDITEM const& wi = GetWorldItem(gpItemPool->iItemIndex);
776 	if (wi.bVisible == HIDDEN_ITEM || wi.bVisible == BURIED)
777 	{
778 		SetFont(FONT10ARIALBOLD);
779 		if (GetJA2Clock() % 1000 > 500) SetFontForeground(249);
780 		MPrint(screen_x + 16, screen_y + 7, "H");
781 		InvalidateRegion(screen_x + 16, screen_y + 7, screen_x + 24, screen_y + 27);
782 	}
783 }
784 
785 
RenderEditorInfo(void)786 static void RenderEditorInfo(void)
787 {
788 	ST::string FPSText;
789 
790 	SetFontAttributes(FONT12POINT1, FONT_BLACK, NO_SHADOW);
791 
792 	//Display the mapindex position
793 	const GridNo iMapIndex = GetMouseMapPos();
794 	if (iMapIndex != NOWHERE)
795 		FPSText = ST::format("   ({})   ", iMapIndex);
796 	else
797 		FPSText = "          ";
798 	MPrintEditor(50 - StringPixLength(FPSText, FONT12POINT1) / 2, 103, FPSText);
799 
800 	switch( iCurrentTaskbar )
801 	{
802 		case TASK_OPTIONS:
803 			if( !gfWorldLoaded || giCurrentTilesetID < 0 )
804 				MPrint(260, EDITOR_TASKBAR_POS_Y + 85, "No map currently loaded.");
805 			else
806 				MPrint(260, EDITOR_TASKBAR_POS_Y + 85, ST::format("File:  {}, Current Tileset:  {}", g_filename, gTilesets[giCurrentTilesetID].zName));
807 			break;
808 		case TASK_TERRAIN:
809 			if( gusSelectionType == LINESELECTION )
810 				wszSelType[LINESELECTION] = ST::format("Width: {}", gusSelectionWidth);
811 			DrawEditorInfoBox(wszSelType[gusSelectionType], FONT12POINT1, 220, 70, 60, 30);
812 			FPSText = ST::format("{}%", gusSelectionDensity);
813 			DrawEditorInfoBox(FPSText, FONT12POINT1, 310, 70, 40, 30);
814 			break;
815 		case TASK_ITEMS:
816 			RenderEditorItemsInfo();
817 			UpdateItemStatsPanel();
818 			break;
819 		case TASK_BUILDINGS:
820 			UpdateBuildingsInfo();
821 			if( gusSelectionType == LINESELECTION )
822 				wszSelType[LINESELECTION] = ST::format("Width: {}", gusSelectionWidth);
823 			DrawEditorInfoBox(wszSelType[gusSelectionType], FONT12POINT1, 530, 70, 60, 30);
824 			break;
825 		case TASK_MERCS:
826 			UpdateMercsInfo();
827 			break;
828 		case TASK_MAPINFO:
829 			UpdateMapInfo();
830 			if( gusSelectionType == LINESELECTION )
831 				wszSelType[LINESELECTION] = ST::format("Width: {}", gusSelectionWidth);
832 			DrawEditorInfoBox(wszSelType[gusSelectionType], FONT12POINT1, 450, 70, 60, 30);
833 			break;
834 		default:
835 			break;
836 	}
837 }
838 
839 //This is in ButtonSystem.c as a hack.  Because we need to save the buffer whenever we do a full
840 //taskbar render, we need to draw the buttons without hilites, hence this flag.  This flag is
841 //always true in ButtonSystem.c, so it won't effect anything else.
842 extern BOOLEAN gfGotoGridNoUI;
843 
ProcessEditorRendering()844 void ProcessEditorRendering()
845 {
846 	BOOLEAN fSaveBuffer = FALSE;
847 	if( gfRenderTaskbar ) //do a full taskbar render.
848 	{
849 		ClearTaskbarRegion(0, 0, SCREEN_WIDTH, EDITOR_TASKBAR_HEIGHT);
850 		RenderTerrainTileButtons();
851 		MarkButtonsDirty();
852 		gfRenderTaskbar = FALSE;
853 		fSaveBuffer = TRUE;
854 		gfRenderDrawingMode = TRUE;
855 		gfRenderHilights = FALSE;
856 		gfRenderMercInfo = TRUE;
857 	}
858 	if( gfRenderDrawingMode )
859 	{
860 		if( iCurrentTaskbar == TASK_BUILDINGS || iCurrentTaskbar == TASK_TERRAIN || iCurrentTaskbar == TASK_ITEMS )
861 		{
862 			ShowCurrentDrawingMode();
863 			gfRenderDrawingMode = FALSE;
864 		}
865 	}
866 	//render dynamically changed buttons only
867 	RenderButtons( );
868 
869 	if( gfSummaryWindowActive )
870 		RenderSummaryWindow();
871 	else if( !gfGotoGridNoUI && !InOverheadMap() )
872 		RenderMercStrings();
873 
874 	if( gfEditingDoor )
875 		RenderDoorEditingWindow();
876 
877 	if( TextInputMode() )
878 		RenderAllTextFields();
879 	RenderEditorInfo();
880 
881 	if( !gfSummaryWindowActive && !gfGotoGridNoUI && !InOverheadMap() )
882 	{
883 		if( gpItem && gsItemGridNo != -1 )
884 			RenderSelectedItemBlownUp();
885 		if( iCurrentTaskbar == TASK_MAPINFO )
886 			RenderMapEntryPointsAndLights();
887 		if( (iDrawMode == DRAW_MODE_PLACE_ITEM && eInfo.uiItemType == TBAR_MODE_ITEM_KEYS) ||
888 			iDrawMode == DRAW_MODE_DOORKEYS )
889 		{
890 			RenderDoorLockInfo();
891 		}
892 	}
893 
894 
895 
896 	if( fSaveBuffer )
897 		BlitBufferToBuffer(FRAME_BUFFER, guiSAVEBUFFER, 0, EDITOR_TASKBAR_POS_Y, SCREEN_WIDTH, EDITOR_TASKBAR_HEIGHT);
898 
899 	//Make sure this is TRUE at all times.
900 	//It is set to false when before we save the buffer, so the buttons don't get
901 	//rendered with hilites, in case the mouse is over one.
902 	gfRenderHilights = TRUE;
903 
904 	RenderButtonsFastHelp();
905 
906 }
907 
908 
909