src/tron/gStatistics.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023   
00024 ***************************************************************************
00025 file by guru3/tank program
00026 
00027 */
00028 
00029 #include "gStatistics.h"
00030 #include "tConfiguration.h"
00031 
00032 //0 is flat file
00033 //1 will be database
00034 static int statOutputType = 0;
00035 static tSettingItem<int> sot_ci("STAT_OUTPUT", statOutputType);
00036 
00037 gStatistics* gStats;
00038 
00039 gStatistics::gStatistics()
00040 {
00041     highscores = new gStatList("highscores", statOutputType);
00042     won_rounds = new gStatList("won_rounds", statOutputType);
00043     won_matches = new gStatList("won_matches", statOutputType);
00044     //  ladder = new gStatList("ladder", statOutputType);
00045     kills = new gStatList("kills", statOutputType);
00046     deaths = new gStatList("deaths", statOutputType);
00047 }
00048 
00049 gStatistics::~gStatistics()
00050 {
00051     delete highscores;
00052     delete won_rounds;
00053     delete won_matches;
00054     //  delete ladder;
00055     delete kills;
00056     delete deaths;
00057 }
00058 
00059 /* original code stripped out to be replaced with the new stuff....
00060 
00061 class gHighscoresBase{
00062     int id;
00063     static tList<gHighscoresBase> highscoreList;
00064 protected:
00065     tArray<tString> highName;
00066 
00067     char*   highscore_file;
00068     tOutput desc;
00069     int     maxSize;
00070 
00071     // find the player at position i
00072     ePlayerNetID *online(int p){
00073         for (int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
00074             if (se_PlayerNetIDs(i)->IsHuman() && !strcmp(se_PlayerNetIDs(i)->GetUserName(),highName[p]))
00075                 return se_PlayerNetIDs(i);
00076 
00077         return NULL;
00078     }
00079 
00080     // i is the active player, j the passive one
00081     virtual void swap_entries(int i,int j){
00082         Swap(highName[i],highName[j]);
00083 
00084         // swap: i is now the passive player
00085 
00086         // send the poor guy who just dropped a message
00087         ePlayerNetID *p=online(i);
00088         if (p){
00089             tColoredString name;
00090             name << *p << tColoredString::ColorString(1,.5,.5);
00091 
00092             tOutput message;
00093             message.SetTemplateParameter(1, static_cast<const char *>(name));
00094             message.SetTemplateParameter(2, static_cast<const char *>(highName[j]));
00095             message.SetTemplateParameter(3, i+1);
00096             message.SetTemplateParameter(4, desc);
00097 
00098             if (i<j)
00099                 message <<  "$league_message_rose" ;
00100             else
00101                 message <<  "$league_message_dropped" ;
00102 
00103             message << "\n";
00104 
00105             tString s;
00106             s << message;
00107             sn_ConsoleOut(s,p->Owner());
00108             // con << message;
00109         }
00110 
00111     }
00112 
00113     void load_Name(std::istream &s,int i){
00114         char c=' ';
00115         while (s.good() && !s.eof() && isspace(c))
00116             s.get(c);
00117         s.putback(c);
00118 
00119         // read and filter name
00120         tString name;
00121         name.ReadLine( s );
00122         ePlayerNetID::FilterName( name, highName[i] );
00123     }
00124 
00125     void save_Name(std::ostream &s,int i){
00126         s << highName[i];
00127     }
00128 
00129 
00130 public:
00131 
00132     virtual void Save()=0;
00133     virtual void Load()=0;
00134 
00135     // returns if i should stay above j
00136     virtual bool inorder(int i,int j)=0;
00137 
00138     void sort(){
00139         // since single score items travel up the
00140         // score ladder, this is the most efficient sort algorithm:
00141 
00142         for(int i=1;i<highName.Len();i++)
00143             for(int j=i;j>=1 && !inorder(j-1,j);j--)
00144                 swap_entries(j,j-1);
00145     }
00146 
00147 
00148     int checkPos(int found){
00149         // move him up
00150         int newpos=found;
00151         while(newpos>0 && !inorder(newpos-1,newpos)){
00152             swap_entries(newpos,newpos-1);
00153             newpos--;
00154         }
00155 
00156         // move him down
00157         while(newpos<highName.Len()-1 && !inorder(newpos,newpos+1)){
00158             swap_entries(newpos,newpos+1);
00159             newpos++;
00160         }
00161 
00162         //Save();
00163 
00164         return newpos;
00165     }
00166 
00167     int Find(const char *name,bool force=false){
00168         int found=highName.Len();
00169         for(int i=found-1;i>=0 ;i--)
00170             if(highName[i].Len()<=1 || !strcmp(highName[i],name)){
00171                 found=i;
00172             }
00173 
00174         if (force && highName[found].Len()<=1)
00175             highName[found]=name;
00176 
00177         return found;
00178     }
00179 
00180     gHighscoresBase(char *name,char *sd,int max=0)
00181             :id(-1),highscore_file(name),desc(sd),maxSize(max){
00182         highscoreList.Add(this,id);
00183     }
00184 
00185     virtual ~gHighscoresBase(){
00186         highscoreList.Remove(this,id);
00187     }
00188 
00189     virtual void greet_this(ePlayerNetID *p,tOutput &o){
00190         //    tOutput o;
00191 
00192         int f=Find(p->GetUserName())+1;
00193         int l=highName.Len();
00194 
00195         o.SetTemplateParameter(1, f);
00196         o.SetTemplateParameter(2, l);
00197         o.SetTemplateParameter(3, desc);
00198 
00199         if (l>=f)
00200             o << "$league_message_greet";
00201         else
00202             o << "$league_message_greet_new";
00203 
00204         //    s << o;
00205     }
00206 
00207     static void Greet(ePlayerNetID *p,tOutput &o){
00208         o << "$league_message_greet_intro";
00209         for(int i=highscoreList.Len()-1;i>=0;i--){
00210             highscoreList(i)->greet_this(p,o);
00211             if (i>1)
00212                 o << "$league_message_greet_sep" << " ";
00213             if (i==1)
00214                 o << " " << "$league_message_greet_lastsep" << " ";
00215         }
00216         o << ".\n";
00217     }
00218 
00219     static void SaveAll(){
00220         if ( !tRecorder::IsRunning() )
00221             for(int i=highscoreList.Len()-1;i>=0;i--)
00222                 highscoreList(i)->Save();
00223     }
00224 
00225     static void LoadAll(){
00226         if ( !tRecorder::IsRunning() )
00227             for(int i=highscoreList.Len()-1;i>=0;i--)
00228                 highscoreList(i)->Load();
00229     }
00230 };
00231 
00232 
00233 tString GreetHighscores()
00234 {
00235     tOutput o;
00236     gHighscoresBase::Greet(eCallbackGreeting::Greeted(),o);
00237     tString s;
00238     s << o;
00239     return s;
00240 }
00241 
00242 static eCallbackGreeting g(GreetHighscores);
00243 
00244 tList<gHighscoresBase> gHighscoresBase::highscoreList;
00245 
00246 template<class T>class highscores: public gHighscoresBase{
00247     protected:
00248     tArray<T>    high_score;
00249 
00250     virtual void swap_entries(int i,int j){
00251         Swap(high_score[i],high_score[j]);
00252         gHighscoresBase::swap_entries(i,j);
00253     }
00254 
00255     public:
00256     virtual void Load(){
00257         std::ifstream s;
00258 
00259         if ( tDirectories::Var().Open ( s, highscore_file ) )
00260         {
00261             int i=0;
00262             while (s.good() && !s.eof())
00263             {
00264                 s >> high_score[i];
00265                 load_Name(s,i);
00266                 // con << highName[i] << " " << high_score[i] << '\n';
00267                 i++;
00268             }
00269         }
00270     }
00271 
00272     // returns if i should stay above j
00273     virtual bool inorder(int i,int j)
00274     {
00275         return (highName[j].Len()<=1 || high_score[i]>=high_score[j]);
00276     }
00277 
00278 
00279     virtual void Save(){
00280         std::ofstream s;
00281 
00282         sort();
00283 
00284         if ( tDirectories::Var().Open ( s, highscore_file ) )
00285         {
00286             int i=0;
00287             int max=high_score.Len();
00288             if (maxSize && max>maxSize)
00289                 max=maxSize;
00290             while (highName[i].Len()>1 && i<max){
00291                 tString mess;
00292                 mess << high_score[i];
00293                 mess.SetPos(10, false );
00294                 s << mess;
00295                 save_Name(s,i);
00296                 s << '\n';
00297                 i++;
00298                 //std::cout << mess;
00299                 //save_Name(std::cout,i);
00300                 //std::cout << '\n';
00301             }
00302         }
00303     }
00304 
00305     void checkPos(int found,const tString &name,T score){
00306         tOutput message;
00307         // find the name in the list
00308         bool isnew=false;
00309 
00310         message.SetTemplateParameter(1, name);
00311         message.SetTemplateParameter(2, desc);
00312         message.SetTemplateParameter(3, score);
00313 
00314         if (highName[found].Len()<=1){
00315             highName[found]=name;
00316             message << "$highscore_message_entered";
00317             high_score[found]=score;
00318             isnew=true;
00319         }
00320         else if (score>high_score[found]){
00321             message << "$highscore_message_improved";
00322             high_score[found]=score;
00323         }
00324         else
00325             return;
00326 
00327         // move him up
00328         int newpos=gHighscoresBase::checkPos(found);
00329 
00330         message.SetTemplateParameter(4, newpos + 1);
00331 
00332         if (newpos!=found || isnew)
00333             if (newpos==0)
00334                 message << "$highscore_message_move_top";
00335             else
00336                 message << "$highscore_message_move_pos";
00337         else
00338             if (newpos==0)
00339                 message << "$highscore_message_stay_top";
00340             else
00341                 message << "$highscore_message_stay_pos";
00342 
00343         message << "\n";
00344 
00345         ePlayerNetID *p=online(newpos);
00346         //con << message;
00347         if (p)
00348             sn_ConsoleOut(tString(message),p->Owner());
00349         //Save();
00350     }
00351 
00352     void Add( ePlayerNetID* player,T AddScore)
00353     {
00354         tASSERT( player );
00355         tString const & name = player->GetUserName();
00356         int f=Find(name,true);
00357         checkPos(f,name,AddScore+high_score[f]);
00358     }
00359 
00360     void Add( eTeam* team,T AddScore)
00361     {
00362         if ( team->NumHumanPlayers() > 0 )
00363         {
00364             for ( int i = team->NumPlayers() - 1 ; i>=0; --i )
00365             {
00366                 ePlayerNetID* player = team->Player( i );
00367                 if ( player->IsHuman() )
00368                 {
00369                     this->Add( player, AddScore );
00370                 }
00371             }
00372         }
00373     }
00374 
00375     void Check(const ePlayerNetID* player,T score){
00376         tASSERT( player );
00377         tString name = player->GetUserName();
00378         int len = high_score.Len();
00379         if (len<=0 || score>high_score[len-1]){
00380             // find the name in the list
00381             int found=Find(name,true);
00382             checkPos(found,name,score);
00383         }
00384     }
00385 
00386     highscores(char *name,char *sd,int max=0)
00387             :gHighscoresBase(name,sd,max){
00388         //              Load();
00389     }
00390 
00391     virtual ~highscores(){
00392         //              Save();
00393     }
00394 };
00395 
00396 
00397 
00398 static REAL ladder_min_bet=1;
00399 static tSettingItem<REAL> ldd_mb("LADDER_MIN_BET",
00400                                  ladder_min_bet);
00401 
00402 static REAL ladder_perc_bet=10;
00403 static tSettingItem<REAL> ldd_pb("LADDER_PERCENT_BET",
00404                                  ladder_perc_bet);
00405 
00406 static REAL ladder_tax=1;
00407 static tSettingItem<REAL> ldd_tex("LADDER_TAX",
00408                                   ladder_tax);
00409 
00410 static REAL ladder_lose_perc_on_load=.2;
00411 static tSettingItem<REAL> ldd_lpl("LADDER_LOSE_PERCENT_ON_LOAD",
00412                                   ladder_lose_perc_on_load);
00413 
00414 static REAL ladder_lose_min_on_load=.2;
00415 static tSettingItem<REAL> ldd_lml("LADDER_LOSE_MIN_ON_LOAD",
00416                                   ladder_lose_min_on_load);
00417 
00418 static REAL ladder_gain_extra=1;
00419 static tSettingItem<REAL> ldd_ga("LADDER_GAIN_EXTRA",
00420                                  ladder_gain_extra);
00421 
00422 
00423 class ladder: public highscores<REAL>{
00424 public:
00425     virtual void Load(){
00426         highscores<REAL>::Load();
00427 
00428         sort();
00429 
00430         int end=highName.Len();
00431 
00432         for(int i=highName.Len()-1;i>=0;i--){
00433 
00434             // make them lose some points
00435 
00436             REAL loss=ladder_lose_perc_on_load*high_score[i]*.01;
00437             if (loss<ladder_lose_min_on_load)
00438                 loss=ladder_lose_min_on_load;
00439             high_score[i]-=loss;
00440 
00441             if (high_score[i]<0)
00442                 end=i;
00443         }
00444 
00445         // remove the bugggers with less than 0 points
00446         highName.SetLen(end);
00447         high_score.SetLen(end);
00448     }
00449 
00450     void checkPos(int found,const tString &name,REAL score){
00451         tOutput message;
00452 
00453         message.SetTemplateParameter(1, name);
00454         message.SetTemplateParameter(2, desc);
00455         message.SetTemplateParameter(3, score);
00456 
00457         // find the name in the list
00458         bool isnew=false;
00459         if (highName[found].Len()<=1){
00460             highName[found]=name;
00461             message << "$ladder_message_entered";
00462             high_score[found]=score;
00463             isnew=true;
00464         }
00465         else{
00466             REAL diff=score-high_score[found];
00467             message.SetTemplateParameter(5, static_cast<float>(fabs(diff)));
00468 
00469             if (diff>0)
00470                 message << "$ladder_message_gained";
00471             else
00472                 message << "$ladder_message_lost";
00473 
00474             high_score[found]=score;
00475         }
00476 
00477         // move him up
00478         int newpos=gHighscoresBase::checkPos(found);
00479 
00480         message.SetTemplateParameter(4, newpos + 1);
00481 
00482         if (newpos!=found || isnew)
00483             if (newpos==0)
00484                 message << "$ladder_message_move_top";
00485             else
00486                 message << "$ladder_message_move_pos";
00487         else
00488             if (newpos==0)
00489                 message << "$ladder_message_stay_top";
00490             else
00491                 message << "$ladder_message_stay_pos";
00492 
00493         message << "\n";
00494 
00495         ePlayerNetID *p=online(newpos);
00496         // con << message;
00497         if (p){
00498             sn_ConsoleOut(tString(message),p->Owner());
00499         }
00500 
00501         // Save();
00502     }
00503 
00504     void Add(const tString &name,REAL AddScore){
00505         int found=Find(name,true);
00506         checkPos(found,name,AddScore+high_score[found]);
00507     }
00508 
00509     // ladder mechanics: what happens if someone wins?
00510     void winner( eTeam *winningTeam ){
00511         tASSERT( winningTeam );
00512 
00513         // AI won? bail out.
00514         if ( winningTeam->NumHumanPlayers() <= 0 )
00515         {
00516             return;
00517         }
00518 
00519         // only do something in multiplayer mode
00520         int i;
00521         int count=0;
00522 
00523         tArray<ePlayerNetID*> active;
00524 
00525         for(i=se_PlayerNetIDs.Len()-1;i>=0;i--)
00526         {
00527             ePlayerNetID* p=se_PlayerNetIDs(i);
00528 
00529             // only take enemies of the current winners (and the winners themselves) into the list
00530             if (p->IsHuman() && ( p->CurrentTeam() == winningTeam || eTeam::Enemies( winningTeam, p ) ) )
00531             {
00532                 count++;
00533                 active[active.Len()] = p;
00534             }
00535         }
00536 
00537         // only one active player? quit.
00538         if ( active.Len() <= 1 )
00539         {
00540             return;
00541         }
00542 
00543         // collect the bets
00544         tArray<int> nums;
00545         tArray<REAL> bet;
00546 
00547         REAL pot=0;
00548 
00549         for(i=active.Len()-1;i>=0;i--){
00550 
00551             nums[i]=Find(active(i)->GetUserName(),true);
00552 
00553             if (high_score[nums[i]]<0)
00554                 high_score[nums[i]]=0;
00555 
00556             bet[i]=high_score[nums[i]]*ladder_perc_bet*.01;
00557             if (bet[i]<ladder_min_bet)
00558                 bet[i]=ladder_min_bet;
00559             pot+=bet[i];
00560         }
00561 
00562         pot-=pot*ladder_tax*.01; // you have to pay to the bank :-)
00563 
00564         // now bet[i] tells us how much player nums[i] has betted
00565         // and pot is the overall bet. Add something to it, prop to
00566         // the winners ping+ping charity:
00567 
00568         // take the bet from the losers and give it to the winner
00569         for(i=active.Len()-1; i>=0; i--)
00570         {
00571             ePlayerNetID* player = active(i);
00572             if(player->CurrentTeam() == winningTeam )
00573             {
00574                 REAL pc=player->ping + player->pingCharity*.001;
00575                 if (pc<0)
00576                     pc=0;
00577                 if (pc>1) // add sensible bounds
00578                     pc=1;
00579 
00580                 REAL potExtra = pc*ladder_gain_extra;
00581 
00582                 if ( player->Object() && player->Object()->Alive() )
00583                 {
00584                     potExtra *= 2.0f;
00585                 }
00586 
00587                 Add(player->GetUserName(), ( pot / winningTeam->NumHumanPlayers() + potExtra ) - bet[i] );
00588             }
00589             else
00590             {
00591                 Add(player->GetUserName(),-bet[i]);
00592             }
00593         }
00594     }
00595 
00596     ladder(char *name,char *sd,int max=0)
00597             :highscores<REAL>(name,sd,max){
00598         //              Load();
00599     }
00600 
00601     virtual ~ladder(){
00602         //              Save();
00603     }
00604 };
00605 
00606 
00607 static highscores<int> highscore("highscores.txt","$highscore_description",100);
00608 static highscores<int> highscore_won_rounds("won_rounds.txt",
00609         "$won_rounds_description");
00610 static highscores<int> highscore_won_matches("won_matches.txt",
00611         "$won_matches_description");
00612 static ladder highscore_ladder("ladder.txt",
00613                                "$ladder_description");
00614 
00615 void check_hs(){
00616     if (sg_singlePlayer)
00617         if(se_PlayerNetIDs.Len()>0 && se_PlayerNetIDs(0)->IsHuman())
00618             highscore.Check(se_PlayerNetIDs(0),se_PlayerNetIDs(0)->Score());
00619 }
00620 
00621 gHighscoresBase::SaveAll();
00622 
00623 highscore_won_rounds.Add(eTeam::teams[winner-1] ,1);
00624 highscore_ladder.winner(eTeam::teams(winner-1));
00625 
00626 check_hs();
00627 
00628 highscore_won_matches.Add( winningTeam, 1 );
00629 
00630 check_hs();
00631 
00632 gHighscoresBase::LoadAll();
00633 
00634 gHighscoresBase::SaveAll();
00635 
00636 */

Generated on Sat Mar 15 22:56:10 2008 for Armagetron Advanced by  doxygen 1.5.4