1 /*
2
3 *************************************************************************
4
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
7
8 **************************************************************************
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 ***************************************************************************
25
26 */
27
28 // I don't know if these includes are needed, I'm brute-forcing it :) - Dave
29 #include "gMenus.h"
30 #include "ePlayer.h"
31 #include "rScreen.h"
32 #include "nConfig.h"
33 #include "rConsole.h"
34 #include "tToDo.h"
35 #include "rGL.h"
36 #include "eTimer.h"
37 #include "eFloor.h"
38 #include "rRender.h"
39 #include "rModel.h"
40 #include "gGame.h"
41 #include "tRecorder.h"
42
43 #include <rRender.h>
44 #include <math.h>
45 #include "gCycle.h"
46 #include <time.h>
47
48 #include "gHud.h"
49
50
51
52 REAL subby_SpeedGaugeSize=.175, subby_SpeedGaugeLocX=0.0, subby_SpeedGaugeLocY=-0.9;
53 REAL subby_BrakeGaugeSize=.175, subby_BrakeGaugeLocX=0.48, subby_BrakeGaugeLocY=-0.9;
54 REAL subby_RubberGaugeSize=.175, subby_RubberGaugeLocX=-0.48, subby_RubberGaugeLocY=-0.9;
55 bool subby_ShowHUD=true, subby_ShowSpeedFastest=true, subby_ShowScore=true, subby_ShowAlivePeople=true, subby_ShowPing=true, subby_ShowSpeedMeter=true, subby_ShowBrakeMeter=true, subby_ShowRubberMeter=true;
56 bool showTime=false;
57 bool show24hour=false;
58 REAL subby_ScoreLocX=-0.95, subby_ScoreLocY=-0.85, subby_ScoreSize =.13;
59 REAL subby_FastestLocX=-0.0, subby_FastestLocY=-0.95, subby_FastestSize =.12;
60 REAL subby_AlivePeopleLocX=.45, subby_AlivePeopleLocY=-0.95, subby_AlivePeopleSize =.13;
61 REAL subby_PingLocX=.80, subby_PingLocY=-0.95, subby_PingSize =.13;
62
63 REAL max_player_speed=0;
64
65 #ifndef DEDICATED
66
GLmeter_subby(float value,float max,float locx,float locy,float size,const char * t,bool displayvalue=true,bool reverse=false,REAL r=.5,REAL g=.5,REAL b=1)67 void GLmeter_subby(float value,float max, float locx, float locy, float size, const char * t,bool displayvalue = true, bool reverse = false, REAL r=.5, REAL g=.5, REAL b=1)
68 {
69
70 #ifndef DEDICATED
71 if (!sr_glOut)
72 return;
73 #endif
74
75 tString title( t );
76
77 float x, y;
78 char string[50];
79 value>max?value=max:1;
80 value<0?value=0:1;
81 x= (reverse?-1:1) * cos(M_PI*value/max);
82 y= sin(M_PI*value/max);
83 if(y<size*.24) displayvalue = false; // dont display text when at minimum
84
85 /* Draws an ugly background on the gauge
86 BeginQuads();
87 Color(1.,1.,1.,.8);
88 Vertex(locx-size-.04,locy-.04,0);
89 Vertex(locx-size-.04,locy+size+.04,0);
90 Vertex(locx+size+.04,locy+size+.04,0);
91 Vertex(locx+size+.04,locy-.04,0);
92
93 Color(.1,.1,.1,.8);
94 Vertex(locx-size-.02,locy-.02,0);
95 Vertex(locx-size-.02,locy+size+.02,0);
96 Vertex(locx+size+.02,locy+size+.02,0);
97 Vertex(locx+size+.02,locy-.02,0);
98
99 RenderEnd();*/
100
101 glDisable(GL_TEXTURE_2D);
102 Color(r,g, b);
103 BeginLines();
104 Vertex(-.1*x*size+locx,.1*y*size+locy,0);
105 Vertex(-x*size+locx,y*size+locy,0);
106 RenderEnd();
107
108
109 rTextField min_t(-size-(0.1*size)+locx,locy,.12*size,.24*size);
110 rTextField max_t(+size+(0.1*size)+locx,locy,.12*size,.24*size);
111 min_t << "0xcccccc" << (reverse?max:0);
112 max_t << "0xcccccc" << (reverse?0:max);
113
114 if(displayvalue){
115 rTextField speed_t(-x*1.45*size+locx,y*1.35*size+locy,.1*size,.2*size);
116 sprintf(string,"%.1f",value);
117 speed_t << "0xccffff" << (string);
118 }
119 int length = title.Len();
120 if ( length > 0 )
121 {
122 rTextField titletext(locx-((.15*size*(length-1.5))/2.0),locy,.12*size,.24*size); //centre -1.0 for null char and -.5 for half a char width = -1.5
123 titletext << "0xff3333" << title;
124 }
125 }
126
127 class gGLMeter
128 {
129 public:
gGLMeter()130 gGLMeter()
131 : oldTime_( -100 ), oldRel_( -100 )
132 {
133 }
134
Display(float value,float max,float locx,float locy,float size,const char * t,bool displayvalue=true,bool reverse=false,REAL r=.5,REAL g=.5,REAL b=1)135 void Display( float value,float max, float locx, float locy, float size, const char * t,bool displayvalue = true, bool reverse = false, REAL r=.5, REAL g=.5, REAL b=1)
136 {
137 REAL rel = value/max;
138 REAL time = se_GameTime();
139 REAL change = rel - oldRel_;
140
141 // see if the gauge change is enough to warrant an update
142 if ( change * change * ( time - oldTime_ ) > .000001 || time < oldTime_ )
143 {
144 list_.Clear();
145 }
146
147 if ( !list_.Call() )
148 {
149 oldRel_ = rel;
150 oldTime_ = time;
151
152 rDisplayListFiller filler( list_ );
153 GLmeter_subby(value, max, locx, locy, size, t, displayvalue, reverse, r, g, b );
154 }
155 }
156 private:
157 REAL oldTime_; // last rendered game time
158 REAL oldRel_; // last rendered gauge position
159 rDisplayList list_; // caching display list
160 };
161
162 // caches stuff based on two float properties
163 class gTextCache
164 {
165 public:
gTextCache()166 gTextCache()
167 : propa_(-1), propb_(-1)
168 {
169 }
170
Call(REAL propa,REAL propb)171 bool Call( REAL propa, REAL propb )
172 {
173 if ( propa != propa_ || propb != propb_ )
174 {
175 propa_ = propa;
176 propb_ = propb;
177 list_.Clear();
178 return false;
179 }
180 else
181 {
182 return list_.Call();
183 }
184 }
185
186 rDisplayList list_;
187 private:
188 REAL propa_, propb_;
189 };
190
191 static int alivepeople, alivemates, thetopscore, hudfpscount;
192
tank_display_hud(ePlayerNetID * me)193 static void tank_display_hud( ePlayerNetID* me ){
194 static int fps = 60;
195 static REAL lastTime = 0;
196
197 if (se_mainGameTimer &&
198 se_mainGameTimer->speed > .9 &&
199 se_mainGameTimer->speed < 1.1 &&
200 se_mainGameTimer->IsSynced() )
201 {
202 REAL newtime = tSysTimeFloat();
203 REAL ts = newtime - lastTime;
204 int newfps = static_cast<int>(se_AverageFPS());
205 if (fabs((newfps-fps)*ts)>4)
206 {
207 fps = newfps;
208 lastTime = newtime;
209 }
210
211 Color(1,1,1);
212 rTextField c(-.9,-.6);
213
214 // signed short int playerID = -1;
215 // unsigned short int alivepeople2 = 0;
216 unsigned short int max = se_PlayerNetIDs.Len();
217 // signed short int scores[16];
218 // signed short int teamID = -1;
219
220 bool dohudcrap = false;
221 if (hudfpscount >= fps) {
222 hudfpscount = 0;
223 dohudcrap = true;
224 }
225 else { hudfpscount++; }
226
227
228 //Calculation, enemies (people not on me's team) alive
229 if (dohudcrap) {
230 alivepeople=0;
231 alivemates=0;
232 if (me){
233 for(unsigned short int i=0;i<max;i++){
234 ePlayerNetID *p=se_PlayerNetIDs(i);
235 if (p->Object() && p->Object()->Alive()){
236 if (p->CurrentTeam() != me->CurrentTeam()){
237 alivepeople++;
238 }else{
239 alivemates++;
240 }
241 }
242 }
243 }
244 }
245
246 /* int max = teams.Len();
247 for(int i=0;i<max;i++){
248 eTeam *t = teams(i);
249 }*/
250
251 if ( me ){
252 //Calculation, top player score
253 if (dohudcrap) {
254 // unsigned short int maxscore = 0;
255 thetopscore = 0;
256 for(unsigned short int i=0;i<max;i++){
257 ePlayerNetID* p2=se_PlayerNetIDs(i);
258 // if (p2->TotalScore() > p->TotalScore() || p2->TotalScore() > thetopscore){
259 if (p2->TotalScore() > thetopscore){
260 thetopscore = p2->TotalScore();
261 }
262 }
263 }
264
265 eCoord pcpos; // = 0 implied
266 if (me->Object() && me->Object()->Alive()) {
267 pcpos = me->Object()->Position(); }
268
269 tString line1, line2, line3;
270
271 /* line1 << "HUD: " << p->name;
272 line1.SetPos(22, true);
273 line1 << "FPS: " << fps;
274 line1.SetPos(34, true);
275 line1 << "ENEMIES: " << alivepeople << "\n";
276
277 line2 << "SCORE: " << p->TotalScore() << ", " << thetopscore;
278 line2.SetPos(22, true);
279 line2 << "PING: " << int(p->ping*1000) << "\n";
280
281 line3 << "LOCATION: " << int(pcpos.x);
282 line3 << ", " << int(pcpos.y);
283 line3.SetPos(22, true);
284 // line3 << "RUBBER: " << int(p->rubberstatus*100);
285
286
287 c <<line1 << line2; */
288
289
290 }
291 }
292 }
293
display_hud_subby(ePlayer * player)294 static void display_hud_subby( ePlayer* player ){
295 if ( !player )
296 return;
297 ePlayerNetID *me = player->netPlayer;
298
299 if (se_mainGameTimer &&
300 se_mainGameTimer->speed > .9 &&
301 se_mainGameTimer->speed < 1.1 &&
302 se_mainGameTimer->IsSynced() )
303 {
304 Color(1,1,1);
305 rTextField c(-.9,-.85);
306 rTextField t(.6,.98);
307
308 // t << "0xffffffGame Time:" << int (se_GameTime())<< " s";
309 if(subby_ShowHUD){
310 // static int max=0,lastmax=0;
311 // static int imax=-1,lastimax=0;
312 // static REAL imax=-1;
313 char fasteststring[50];
314 // REAL distance;
315 static float maxmeterspeed= 50;
316 float myping;
317 static REAL max=max_player_speed;
318 static tString name;
319 static tString ultiname;
320 // static bool wrotefastest = false;
321 // static bool wrote10 =false;
322 static bool belowzero=false;
323 static REAL ultimax=0;
324 // static REAL timelast;
325 static REAL myscore, topscore;
326 // tString realname = ePlayer::PlayerConfig(0)->Name();
327
328 // const tString& myname = me->name;
329
330 if ( me )
331 myscore = me->TotalScore();
332
333 const eGameObject *ret = NULL;
334 if(player->cam){
335 ret = player->cam->Center();
336
337 static bool firsttime =true;
338
339 if(se_GameTime()<0||!firsttime){
340 firsttime=false;
341 if((se_GameTime()<0)){
342 belowzero=true;
343 if(se_GameTime()<-1){
344 tOutput message;
345 // message<< "Last Game Fastest: " << name << " with a top speed of " << max << "\n";
346 // con << "testcon";
347 // sn_CenterMessage(message);
348 }else{
349 // timelast = se_GameTime();
350 max=0;
351 // wrotefastest = false;
352 // wrote10 =false;
353 }
354 }else if(se_GameTime()>0&&belowzero){
355 belowzero=false;
356 }
357 }
358
359 topscore =0;
360 for(int i =0 ; i< se_PlayerNetIDs.Len(); i++){
361 ePlayerNetID *p = se_PlayerNetIDs[i];
362 p->TotalScore()>topscore?topscore=p->TotalScore():1;
363
364 if(gCycle *h = (gCycle*)(p->Object())){
365
366 // change player so we always see the gauges of the cycle that is watched
367 if ( h == ret )
368 me = p;
369
370 // distance = h->distance;
371 // c << p-> name << " " << int((h ->Speed())) << " ";
372 if (h->Speed()>max){
373 max = (float) h->Speed(); // changed to float for more accuracy in reporting top speed
374 name = p->GetName();
375 // imax = i;
376
377 }
378 if( h->Speed()>ultimax){
379 ultimax = (float) h->Speed();
380 ultiname = p->GetName();
381 }
382 }
383 }
384
385 if (me!=NULL){
386 gCycle *h = dynamic_cast<gCycle *>(me->Object());
387 if (h && ( !player->netPlayer || !player->netPlayer->IsChatting()) && se_GameTime()>-2){
388 h->Speed()>maxmeterspeed?maxmeterspeed+=10:1;
389 // myscore=p->TotalScore();
390 myping = me->ping;
391
392 if(subby_ShowSpeedMeter)
393 {
394 static gGLMeter meter[MAX_PLAYERS];
395 meter[player->ID()].Display(h->Speed(),maxmeterspeed,subby_SpeedGaugeLocX,subby_SpeedGaugeLocY,subby_SpeedGaugeSize,"Speed"); // easy to use configurable meters
396 }
397 if(subby_ShowRubberMeter)
398 {
399 static gGLMeter meter[MAX_PLAYERS];
400 meter[player->ID()].Display(h->GetRubber(),sg_rubberCycle,subby_RubberGaugeLocX,subby_RubberGaugeLocY,subby_RubberGaugeSize," Rubber Used");
401 if ( gCycle::RubberMalusActive() )
402 {
403 static gGLMeter meter2[MAX_PLAYERS];
404 meter2[player->ID()].Display(100/(1+h->GetRubberMalus()),100,subby_RubberGaugeLocX,subby_RubberGaugeLocY,subby_RubberGaugeSize,"",true, false, 1,.5,.5);
405 }
406 }
407 if(subby_ShowBrakeMeter)
408 {
409 static gGLMeter meter[MAX_PLAYERS];
410 meter[player->ID()].Display(h->GetBrakingReservoir(), 1.0,subby_BrakeGaugeLocX,subby_BrakeGaugeLocY,subby_BrakeGaugeSize, " Brakes");
411 }
412
413 // bool displayfastest = true;// put into global, set via menusytem... subby to do.make sr_DISPLAYFASTESTout
414
415 if(subby_ShowSpeedFastest)
416 {
417 static gTextCache cacheArray[MAX_PLAYERS];
418 gTextCache & cache = cacheArray[player->ID()];
419 if ( !cache.Call( max, 0 ) )
420 {
421 rDisplayListFiller filler( cache.list_ );
422
423 float size= subby_FastestSize;
424 tColoredString message,messageColor;
425 messageColor << "0xbf9d50";
426
427 sprintf(fasteststring,"%.1f",max);
428 message << " Fastest: " << name << " " << fasteststring;
429 message.RemoveHex(); //cheers tank;
430 int length = message.Len();
431
432 rTextField speed_fastest(subby_FastestLocX-((.15*size*(length-1.5))/2.0),subby_FastestLocY,.15*size,.3*size);
433 /* rTextField speed_fastest(.7-((.15*size*(length-1.5))/2.0),.65,.15*size,.3*size); */
434
435 speed_fastest << messageColor << message;
436 }
437 }
438
439 if(subby_ShowScore){
440 static gTextCache cacheArray[MAX_PLAYERS];
441 gTextCache & cache = cacheArray[player->ID()];
442 if ( !cache.Call( topscore, myscore ) )
443 {
444 rDisplayListFiller filler( cache.list_ );
445
446 tString colour;
447 if(myscore==topscore){
448 colour = "0xff9d50";
449 }else if (myscore > topscore){
450 colour = "0x11ff11";
451 }else{
452 colour = "0x11ffff";
453 }
454
455 float size = subby_ScoreSize;
456 rTextField score(subby_ScoreLocX,subby_ScoreLocY,.15*size,.3*size);
457 score << " Scores\n";
458 score << "0xefefef" << "Me: Top:\n";
459 score << colour << myscore << " 0xffff00" << topscore ;
460 }
461 }
462
463 if(subby_ShowAlivePeople){
464 static gTextCache cacheArray[MAX_PLAYERS];
465 gTextCache & cache = cacheArray[player->ID()];
466 if ( !cache.Call( alivepeople, alivemates ) )
467 {
468 rDisplayListFiller filler( cache.list_ );
469
470 tString message;
471 message << "Enemies: " << alivepeople << " Friends: " << alivemates;
472 int length = message.Len();
473 float size = subby_AlivePeopleSize;
474 rTextField enemies_alive(subby_AlivePeopleLocX-((.15*size*(length-1.5))/2.0),subby_AlivePeopleLocY,.15*size,.3*size);
475 enemies_alive << "0xfefefe" << message;
476 }
477 }
478
479 if(subby_ShowPing){
480 static gTextCache cacheArray[MAX_PLAYERS];
481 gTextCache & cache = cacheArray[player->ID()];
482 if ( !cache.Call( 0, myping ) )
483 {
484 rDisplayListFiller filler( cache.list_ );
485
486 tString message;
487 message << "Ping: " << int(myping * 1000) << " ms" ;
488 int length = message.Len();
489 float size = subby_PingSize;
490 rTextField ping(subby_PingLocX-((.15*size*(length-1.5))/2.0),subby_PingLocY,.15*size,.3*size);
491 ping << "0xfefefe" << message;
492 }
493 }
494 }
495 }
496 }
497 }
498
499 }
500 tank_display_hud( me ); // call tank's version
501
502 }
503
display_fps_subby()504 static void display_fps_subby()
505 {
506 if (!(se_mainGameTimer &&
507 se_mainGameTimer->speed > .9 &&
508 se_mainGameTimer->speed < 1.1 &&
509 se_mainGameTimer->IsSynced() ) )
510 return;
511
512 static int fps = 60;
513 static REAL lastTime = 0;
514
515 REAL newtime = tSysTimeFloat();
516 REAL ts = newtime - lastTime;
517
518 static gTextCache cache;
519 if ( cache.Call( fps, (int)tSysTimeFloat() ) )
520 {
521 return;
522 }
523 if ( tRecorder::IsRunning() )
524 {
525 cache.list_.Clear();
526 }
527 rDisplayListFiller filler( cache.list_ );
528
529 float size =.15;
530 rTextField c2(.7,.85,.15*size, .3*size);
531
532 if ( tRecorder::IsRunning() )
533 {
534 std::stringstream time;
535 time.precision( 5 );
536 time << newtime;
537 {
538 c2 << "0xffffffT:" << time.str() << "\n";
539 }
540 }
541
542 int newfps = static_cast<int>(se_AverageFPS());
543 if (fabs((newfps-fps)*ts)>4)
544 {
545 fps = newfps;
546 lastTime = newtime;
547 }
548
549 if(sr_FPSOut){
550 c2 << "0xffffffFPS: " <<fps;
551 }
552 // Show the time
553 if(showTime) {
554 static int lastTime=0;
555 static char theTime[13];
556 float size =.15;
557 struct tm* thisTime;
558 time_t rawtime;
559
560 time ( &rawtime );
561 thisTime = localtime ( &rawtime );
562
563 if(thisTime->tm_min != lastTime) {
564 char h[3];
565 char m[3];
566 char ampm[3] = " ";
567
568 lastTime = thisTime->tm_min;
569
570 if(thisTime->tm_min < 10) {
571 sprintf(m, "0%d", thisTime->tm_min);
572 } else {
573 sprintf(m, "%d", thisTime->tm_min);
574 }
575
576 if(show24hour) {
577 sprintf(h, "%d", thisTime->tm_hour);
578 } else {
579 int newhour;
580
581 if(thisTime->tm_hour > 12) {
582 newhour = thisTime->tm_hour-12;
583 sprintf(ampm,"%s","PM");
584 } else {
585 newhour = thisTime->tm_hour;
586 if(newhour == 0) newhour = 12;
587 sprintf(ampm,"%s","AM");
588 }
589 sprintf(h, "%d", newhour);
590 }
591
592 sprintf(theTime, "%s:%s %s",h,m,ampm);
593 }
594
595 // float timesize = subby_ScoreSize; // -((.15*timesize*(10-1.5))/2.0)
596 rTextField the_time(.7,.9,.15*size, .3*size);
597
598 the_time << "0xffffff" << theTime;
599 }
600
601 }
602
display_hud_subby_all()603 static void display_hud_subby_all()
604 {
605 sr_ResetRenderState(true);
606 display_fps_subby();
607
608 rViewportConfiguration* viewportConfiguration = rViewportConfiguration::CurrentViewportConfiguration();
609
610 for ( int viewport = viewportConfiguration->num_viewports-1; viewport >= 0; --viewport )
611 {
612 // get the ID of the player in the viewport
613 int playerID = sr_viewportBelongsToPlayer[ viewport ];
614
615 // get the player
616 ePlayer* player = ePlayer::PlayerConfig( playerID );
617
618 // select the corrected viewport
619 viewportConfiguration->Port( viewport )->CorrectAspectBottom().Select();
620
621 // delegate
622 display_hud_subby( player );
623 }
624 }
625
626 static rPerFrameTask dfps(&display_hud_subby_all);
627 #endif // DEDICATED
628