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