aboutsummaryrefslogtreecommitdiff
path: root/src/parsec/m_status.cpp
blob: f17c097cce27bf3dd238bb649d5581195a72d457 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
/*
 * PARSEC - Game Status Window
 *
 * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:38 $
 *
 * Orginally written by:
 *   Copyright (c) Markus Hadwiger     <msh@parsec.org>   1998-2000
 *   Copyright (c) Andreas Varga       <sid@parsec.org>   1999-2000
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 

// C library
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// compilation flags/debug support
#include "config.h"
#include "debug.h"

// general definitions
#include "general.h"
#include "objstruc.h"

// global externals
#include "globals.h"

// subsystem headers
#include "net_defs.h"
#include "sys_defs.h"

// drawing subsystem
#include "d_font.h"

// local module header
#include "m_status.h"

// proprietary module headers
#include "con_aux.h"
#include "e_color.h"
#include "e_demo.h"
#include "e_draw.h"
#include "h_cockpt.h"
#include "m_main.h"



// generic string paste area --------------------------------------------------
//
#define PASTE_STR_LEN 2047
static char paste_str[ PASTE_STR_LEN + 1 ];


// string constants -----------------------------------------------------------
//
static char status_name_str[]			= "name";
static char status_kills_str[]			= "kills";
static char status_caption_str[]		= "         game status        ";
static char status_kill_limit_str[]		= "kill limit has been reached!";
static char status_time_limit_str[]		= "   the game time is over!   ";


// status window configuration and state variables ----------------------------
//
#define STATUS_ALPHA_LOW		0
#define STATUS_ALPHA_HIGH		255

#define STATUS_FADE_SPEED		12
#define STATUS_FADE_QUANTUM		10

#define STATUS_MARGIN	25

static int			status_fadepos 		= STATUS_ALPHA_LOW;
static int			status_fadetarget	= STATUS_ALPHA_LOW;
static refframe_t	status_lastref 		= REFFRAME_INVALID;


// fade the background alpha to a specified target ----------------------------
//
PRIVATE
int DoStatusWindowFading()
{
	if ( status_fadepos == status_fadetarget ) {

		status_lastref = REFFRAME_INVALID;

		// skip drawing code if status window is completely faded out
#if ( STATUS_ALPHA_LOW == 0 )
		return ( status_fadepos != STATUS_ALPHA_LOW );
#else
		return TRUE;
#endif

	}

	if ( status_fadepos < status_fadetarget ) {

		// fade in
		refframe_t refframecount = SYSs_GetRefFrameCount();
		if ( status_lastref == REFFRAME_INVALID ) {
			status_lastref = refframecount;
		} else {
			refframe_t delta = refframecount - status_lastref;
			for ( ; delta >= STATUS_FADE_SPEED; delta -= STATUS_FADE_SPEED ) {
				status_fadepos += STATUS_FADE_QUANTUM;
				if ( status_fadepos >= status_fadetarget ) {
					status_fadepos = status_fadetarget;
					status_lastref = REFFRAME_INVALID;
					break;
				}
				status_lastref += STATUS_FADE_SPEED;
			}
		}

	} else {

		// fade out
		refframe_t refframecount = SYSs_GetRefFrameCount();
		if ( status_lastref == REFFRAME_INVALID ) {
			status_lastref = refframecount;
		} else {
			refframe_t delta = refframecount - status_lastref;
			for ( ; delta >= STATUS_FADE_SPEED; delta -= STATUS_FADE_SPEED ) {
				status_fadepos -= STATUS_FADE_QUANTUM;
				if ( status_fadepos <= status_fadetarget ) {
					status_fadepos = status_fadetarget;
					status_lastref = REFFRAME_INVALID;
					break;
				}
				status_lastref += STATUS_FADE_SPEED;
			}
		}
	}

	return TRUE;
}


// type for writestring function pointer --------------------------------------
//
typedef void (*WSFP)( ... );

//NOTE:
// this declaration is in global scope because of the extern "C".
// only gcc needs the otherwise redundant curly braces.


// draw horizontal divider line built from minus signs ------------------------
//
static
void DrawDividerLine( WSFP wstrfp, int lx, int ly, int len )
{
	ASSERT( wstrfp != NULL );

	ASSERT( len <= PASTE_STR_LEN );
	int dpos = 0;
	for ( dpos = 0; dpos < len; dpos++ ) {
		paste_str[ dpos ] = '-';
	}
	paste_str[ dpos ] = 0;

	wstrfp( paste_str, lx, ly, TRTAB_PANELTEXT );
}


// pointer to current caption of status window --------------------------------
//
static char *statuswindow_caption;


// current metrics of status window contents ----------------------------------
//
static list_window_metrics_s statuswindow_content_metrics = { FALSE };


// draw translucent background window for status window -----------------------
//
PRIVATE
void DrawStatusWindowFrame()
{
	int frame_l		  = statuswindow_content_metrics.frame_l;
	int frame_r		  = statuswindow_content_metrics.frame_r;
	int frame_t		  = statuswindow_content_metrics.frame_t;
	int frame_b		  = statuswindow_content_metrics.frame_b;
	int chwidth		  = statuswindow_content_metrics.chwidth;
	int chheight	  = statuswindow_content_metrics.chheight;
	int text_x		  = statuswindow_content_metrics.text_x;
	int text_y		  = statuswindow_content_metrics.text_y;
	int maxcontwidth  = statuswindow_content_metrics.maxcontwidth;
	int maxcontheight = statuswindow_content_metrics.maxcontheight;

	int backx = text_x - frame_l * chwidth;
	int backy = text_y - frame_t * chheight;
	int backw = ( frame_l + frame_r + maxcontwidth ) * chwidth;
	int backh = ( frame_t + frame_b + maxcontheight ) * chheight;

	DRAW_ClippedTrRect( backx, backy, backw, backh, TRTAB_PANELBACK );
}


// draw caption of status window ----------------------------------------------
//
PRIVATE
void DrawStatusWindowCaption( WSFP wstrfp )
{
	unsigned int chwidth		  = statuswindow_content_metrics.chwidth;
	unsigned int chheight	  = statuswindow_content_metrics.chheight;
	int text_x		  = statuswindow_content_metrics.text_x;
	int text_y		  = statuswindow_content_metrics.text_y;
	unsigned int maxcontwidth  = statuswindow_content_metrics.maxcontwidth;
	unsigned int maxcontheight = statuswindow_content_metrics.maxcontheight;

	// draw list caption
	ASSERT( maxcontwidth >= strlen( statuswindow_caption ) );
	int xofs = ( ( maxcontwidth - strlen( statuswindow_caption ) ) * chwidth ) / 2;
	wstrfp( statuswindow_caption, text_x + xofs, text_y, TRTAB_PANELTEXT );
	text_y += chheight * 2;

	// draw "name" and "kills" caption
	wstrfp( status_name_str, text_x, text_y, TRTAB_PANELTEXT );
	xofs = ( maxcontwidth - strlen( status_kills_str ) ) * chwidth;
	wstrfp( status_kills_str, text_x + xofs, text_y, TRTAB_PANELTEXT );
	text_y += chheight;

	// draw separator
	DrawDividerLine( wstrfp, text_x, text_y, maxcontwidth );
	text_y += chheight;

	statuswindow_content_metrics.text_y = text_y;
}


// draw all player names and kills --------------------------------------------
//
PRIVATE
void DrawStatusWindowItems( WSFP wstrfp )
{
	unsigned int chwidth		  = statuswindow_content_metrics.chwidth;
	unsigned int chheight	  = statuswindow_content_metrics.chheight;
	int text_x		  = statuswindow_content_metrics.text_x;
	int text_y		  = statuswindow_content_metrics.text_y;
	unsigned int maxcontwidth  = statuswindow_content_metrics.maxcontwidth;
	unsigned int maxcontheight = statuswindow_content_metrics.maxcontheight;

	//FIXME: this function is EXACT the same as M_LIST::DrawPlayerListItems
	const char *voidstr = "-";

	int	sortfilter[ MAX_NET_ALLOC_SLOTS ];
	int sid = 0;
	for ( sid = 0; sid < MAX_NET_ALLOC_SLOTS; sid++ ) {
		sortfilter[ sid ] = 0;
	}

	// print playerlist (optionally sorted by number of kills)
	int pid = 0;
	for ( pid = 0; pid < MAX_NET_PROTO_PLAYERS; pid++ ) {

		int slot  = pid;
		int kills = -1;

		// search for highest kills if sorting enabled
		if ( AUX_DISABLE_SORTED_PLAYERLIST ) {
			kills = Player_KillStat[ pid ];
		} else {

			// invalidate slot
			slot = -1;

			// sort for highest kills of connected players not yet displayed
			for ( sid = 0; sid < MAX_NET_PROTO_PLAYERS; sid++ ) {
				if ( !sortfilter[ sid ] && ( Player_KillStat[ sid ] > kills ) && Player_Status[ sid ] ) {
					slot  = sid;
					kills = Player_KillStat[ sid ];
				}
			}

			// check for valid slot
			if ( slot != -1 ) {

				// do not consider slot in next round
				sortfilter[ slot ] = 1;

				// invalidate slot if disconnected and not the local player
				if ( !( ( Player_Status[ slot ] ) || ( slot == LocalPlayerId ) ) )
					slot = -1;
			}
		}

		// get name to be displayed
		const char *strp = (slot != -1) ? Player_Name[ slot ] : voidstr;
		if ( slot == LocalPlayerId )
			strp = LocalPlayerName; // so local name can be changed on the fly

		// write name
		ASSERT( maxcontwidth >= strlen( strp ) );
		int xofs = ( ( maxcontwidth - strlen( strp ) ) * chwidth ) / 2;
		wstrfp( strp, text_x, text_y, TRTAB_PANELTEXT );

		// get kills to be displayed
		char ckills_str[ 5 ] = "";
		if ( slot != -1 ) {
			ASSERT( kills >= 0 );
			sprintf( ckills_str, "%d", kills );
		} else {
			sprintf( ckills_str, "-" );
		}

		// write kill
		xofs = ( maxcontwidth - strlen( ckills_str ) ) * chwidth;
		wstrfp( ckills_str, text_x + xofs, text_y, TRTAB_PANELTEXT );

		// advance to next line
		text_y += chheight;
	}
}


// calc and store metrics for status window -----------------------------------
//
PRIVATE
void CalcStatusWindowContentMetrics()
{
	// determine caption
	statuswindow_caption = status_caption_str;

	if ( GAME_NO_SERVER() ) {

		extern int limit_reached;
		if ( limit_reached ) {
			statuswindow_caption = status_kill_limit_str;
		}

	} else {

		if ( CurGameTime == GAME_FINISHED_KILLS ) {
			statuswindow_caption = status_kill_limit_str;
		} else if ( CurGameTime == GAME_FINISHED_TIME ) {
			statuswindow_caption = status_time_limit_str;
		}
	}

	// bounds for content
	size_t maxcontwidth  = strlen( statuswindow_caption ) + STATUS_MARGIN - 2;
	unsigned int maxcontheight = 20;

	// ensure maximum content width is big enough
	for ( int lid = 0; lid < MAX_NET_PROTO_PLAYERS; lid++ )
		if ( strlen( Player_Name[ lid ] ) > maxcontwidth )
			maxcontwidth  = strlen( Player_Name[ lid ] ) + STATUS_MARGIN;

	extern int hud_line_dist;

	int chwidth  = CharsetInfo[ HUD_CHARSETNO ].width;
	int chheight = hud_line_dist;

	D_SetWStrContext( CharsetInfo[ HUD_CHARSETNO ].charsetpointer,
					  CharsetInfo[ HUD_CHARSETNO ].geompointer,
					  NULL,
					  CharsetInfo[ HUD_CHARSETNO ].width,
					  CharsetInfo[ HUD_CHARSETNO ].height );

	// frame metrics
	int frame_l = 1;
	int frame_r = 1;
	int frame_t = 2;
	int frame_b = 1;

	// text position
	int text_x = ( Screen_Width - ( frame_r + maxcontwidth ) * chwidth ) / 2;
	int text_y = InFloatingMenu ? 62 : 140;

	// store metrics
	statuswindow_content_metrics.valid			= TRUE;
	statuswindow_content_metrics.frame_l		= frame_l;
	statuswindow_content_metrics.frame_r		= frame_r;
	statuswindow_content_metrics.frame_t		= frame_t;
	statuswindow_content_metrics.frame_b		= frame_b;
	statuswindow_content_metrics.chwidth		= chwidth;
	statuswindow_content_metrics.chheight		= chheight;
	statuswindow_content_metrics.text_x			= text_x;
	statuswindow_content_metrics.text_y			= text_y;
	statuswindow_content_metrics.maxcontwidth	= maxcontwidth;
	statuswindow_content_metrics.maxcontheight	= maxcontheight;
}


// draw translucent window with game status displays ---------------------------
//
void DrawStatusWindow()
{
	// fade the window if necessary
	if ( !DoStatusWindowFading() )
		return;

	CalcStatusWindowContentMetrics();

	// check whether actual drawing disabled
	if ( AUX_DISABLE_FLOATING_MENU_DRAWING )
		return;

	// determine whether translucency should be used
	int translucent = VID_TRANSLUCENCY_SUPPORTED;

	// write text transparent only for color depths below 32 bit per pixel
	WSFP wstrfp = translucent ? (WSFP)&D_WriteTrString : (WSFP)&D_WriteString;

	// fade window alpha
	int old_text_alpha = PanelTextColor.A;
	int old_back_alpha = PanelBackColor.A;
	PanelTextColor.A = (int)(status_fadepos * ( (float) old_text_alpha / (float) STATUS_ALPHA_HIGH ));
	PanelBackColor.A = (int)(status_fadepos * ( (float) old_back_alpha / (float) STATUS_ALPHA_HIGH ));

	// draw frame
	if ( translucent ) {
		DrawStatusWindowFrame();
	}

	// draw caption
	DrawStatusWindowCaption( wstrfp );

	// draw items
	DrawStatusWindowItems( wstrfp );

	// restore window alpha
	PanelTextColor.A = old_text_alpha;
	PanelBackColor.A = old_back_alpha;
}


// check if status window is at its desired fade position ---------------------
//
int FadeFinishedStatusWindow()
{
	return ( status_fadepos == status_fadetarget );
}


// set fade target for status window to high (in) -----------------------------
//
void FadeInStatusWindow()
{
	status_fadetarget = STATUS_ALPHA_HIGH;
}


// set fade target for status window to low (out) -----------------------------
//
void FadeOutStatusWindow()
{
	status_fadetarget = STATUS_ALPHA_LOW;
}


// set fade level of status window to invisible (used upon join game) ---------
//
void HideStatusWindow()
{
	status_fadepos = STATUS_ALPHA_LOW;
}