00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "eTeam.h"
00029 #include "tSysTime.h"
00030 #include "rFont.h"
00031 #include "nConfig.h"
00032
00033 #include <set>
00034
00035 #define TEAMCOLORS 8
00036
00037 static unsigned short se_team_rgb[TEAMCOLORS][3]=
00038 { { 4, 8, 15 } ,
00039 { 15, 15, 4 } ,
00040 { 15, 4, 4 } ,
00041 { 4, 15, 4 } ,
00042 { 15, 4, 15 } ,
00043 { 4, 15, 15 } ,
00044 { 15, 15, 15 } ,
00045 { 7, 7, 7 }
00046 };
00047
00048 static tString se_team_name[TEAMCOLORS]=
00049 {
00050 tString("$team_name_blue"),
00051 tString("$team_name_gold"),
00052 tString("$team_name_red"),
00053 tString("$team_name_green"),
00054 tString("$team_name_violet"),
00055 tString("$team_name_ugly"),
00056 tString("$team_name_white"),
00057 tString("$team_name_black")
00058 };
00059
00060
00061
00062 class eTeamColorConfig {
00063 typedef tSettingItem<tString> nameConf;
00064 typedef tSettingItem<unsigned short int> colorConf;
00065 colorConf *m_red, *m_green, *m_blue;
00066 nameConf *m_name;
00067 static int teamCount;
00068 public:
00069 eTeamColorConfig() {
00070 std::ostringstream name(""), red(""), green(""), blue("");
00071 name << "TEAM_NAME_" << teamCount + 1;
00072 red << "TEAM_RED_" << teamCount + 1;
00073 green << "TEAM_GREEN_" << teamCount + 1;
00074 blue << "TEAM_BLUE_" << teamCount + 1;
00075 m_name = new nameConf (name .str().c_str(), se_team_name[teamCount]);
00076 m_red = new colorConf(red .str().c_str(), se_team_rgb [teamCount][0]);
00077 m_green = new colorConf(green.str().c_str(), se_team_rgb [teamCount][1]);
00078 m_blue = new colorConf(blue .str().c_str(), se_team_rgb [teamCount][2]);
00079 ++teamCount;
00080 }
00081 ~eTeamColorConfig() {
00082 delete m_name;
00083 delete m_red;
00084 delete m_green;
00085 delete m_blue;
00086 }
00087 };
00088
00089 int eTeamColorConfig::teamCount = 0;
00090
00091 static eTeamColorConfig se_team_config[TEAMCOLORS];
00092
00094 inline static tColoredStringProxy ColorString( const eTeam * t )
00095 {
00096 return tColoredStringProxy( t->R()/15.0f, t->G()/15.0f, t->B()/15.0f );
00097 }
00098
00099 nNOInitialisator<eTeam> eTeam_init(220,"eTeam");
00100
00101 nDescriptor &eTeam::CreatorDescriptor() const{
00102 return eTeam_init;
00103 }
00104
00105 int eTeam::minTeams=0;
00106 int eTeam::maxTeams=30;
00107 int eTeam::minPlayers=0;
00108 int eTeam::maxPlayers=3;
00109 int eTeam::maxImbalance=2;
00110 bool eTeam::balanceWithAIs=true;
00111 bool eTeam::enforceRulesOnQuit=false;
00112
00113 tList<eTeam> eTeam::teams;
00114
00115 static bool newTeamAllowed;
00116
00117 static nSettingItem<bool> se_newTeamAllowed("NEW_TEAM_ALLOWED", newTeamAllowed );
00118
00119 static bool se_allowTeamNameColor = true;
00120 static bool se_allowTeamNamePlayer = true;
00121 static bool se_allowTeamNameLeader = false;
00122
00123 static tSettingItem<bool> se_allowTeamNameColorConfig("ALLOW_TEAM_NAME_COLOR", se_allowTeamNameColor );
00124 static tSettingItem<bool> se_allowTeamNamePlayerConfig("ALLOW_TEAM_NAME_PLAYER", se_allowTeamNamePlayer );
00125 static tSettingItem<bool> se_allowTeamNameCustomConfig("ALLOW_TEAM_NAME_LEADER", se_allowTeamNameLeader );
00126
00127
00128 void eTeam::UpdateStaticFlags()
00129 {
00130 bool newTeamAllowedCurrent = teams.Len() >= maxTeams;
00131
00132 if ( newTeamAllowedCurrent != newTeamAllowed )
00133 {
00134 se_newTeamAllowed.Set( newTeamAllowedCurrent );
00135
00136 for (int i = teams.Len() - 1; i>=0; --i)
00137 teams(i)->Update();
00138 }
00139 }
00140
00141
00142 void eTeam::UpdateProperties()
00143 {
00144
00145 if ( nCLIENT != sn_GetNetState() )
00146 {
00147
00148
00149 maxPlayersLocal = maxPlayers;
00150
00151
00152
00153
00154
00155 maxImbalanceLocal = maxImbalance;
00156
00157
00158
00159
00160
00161
00162 }
00163
00164 numHumans = 0;
00165 numAIs = 0;
00166 int i;
00167 for ( i = players.Len()-1; i>=0; --i )
00168 {
00169 if ( players(i)->IsHuman() )
00170 {
00171 if ( players(i)->IsActive() )
00172 ++numHumans;
00173 }
00174 else
00175 ++numAIs;
00176 }
00177
00178 if ( nSERVER == sn_GetNetState() )
00179 RequestSync();
00180 }
00181
00182
00183 void eTeam::UpdateAppearance()
00184 {
00185 unsigned short oldr = r, oldg = g, oldb = b;
00186
00187 ePlayerNetID* oldest = OldestHumanPlayer();
00188 if ( !oldest )
00189 {
00190 oldest = OldestAIPlayer();
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 bool nameTeamColor = players.Len() > 1 && (!oldest || oldest->teamname.Len()<=1 || !oldest->nameTeamAfterMe);
00209
00210
00211
00212 if ( !se_allowTeamNameColor )
00213 nameTeamColor = false;
00214 if ( !se_allowTeamNamePlayer )
00215 nameTeamColor = true;
00216
00217 nameTeamColor = NameTeamAfterColor ( nameTeamColor );
00218
00219 tString updateName;
00220 if ( oldest )
00221 {
00222 if ( nameTeamColor )
00223 {
00224
00225 tOutput newname;
00226 newname << &se_team_name[ colorID ][0];
00227
00228 updateName = newname;
00229
00230 r = se_team_rgb[colorID][0];
00231 g = se_team_rgb[colorID][1];
00232 b = se_team_rgb[colorID][2];
00233 }
00234 else
00235 {
00236
00237 if ( players.Len() > 1 )
00238 {
00239 if ( oldest->IsHuman() )
00240 {
00241
00242 if (se_allowTeamNameLeader && oldest->teamname.Len()>1)
00243 {
00244
00245 updateName = oldest->teamname;
00246 }
00247 else
00248 {
00249
00250 tOutput newname;
00251 newname.SetTemplateParameter( 1, oldest->GetName() );
00252 newname << "$team_owned_by";
00253 updateName = newname;
00254 }
00255 }
00256 else
00257 {
00258
00259 tOutput newname;
00260 newname.SetTemplateParameter( 1, oldest->GetName() );
00261 newname << "$team_ai";
00262 updateName = newname;
00263 }
00264 }
00265 else
00266 {
00267
00268 if (oldest->teamname.Len()>1)
00269
00270 updateName = oldest->teamname;
00271 else
00272
00273 updateName = oldest->GetUserName();
00274 }
00275
00276 r = oldest->r;
00277 g = oldest->g;
00278 b = oldest->b;
00279
00280
00281 if ( sn_GetNetState() != nSERVER )
00282 {
00283 for ( int i = players.Len()-1; i>=0; --i )
00284 {
00285 players(i)->UpdateName();
00286 }
00287 }
00288 }
00289 }
00290 else
00291 {
00292
00293 updateName = tOutput("$team_empty");
00294 r = g = b = 7;
00295 }
00296
00297
00298 if (name!=updateName)
00299 {
00300
00301
00302
00303 if(sn_GetNetState()!=nCLIENT && oldest)
00304 {
00305 tOutput message;
00306 tColoredString name;
00307 name << *oldest;
00308 name << tColoredString::ColorString(1,1,1);
00309 message.SetTemplateParameter(1, name);
00310
00311 tColoredString resetColor;
00312 resetColor << tColoredString::ColorString(r,g,b);
00313 resetColor << updateName;
00314 resetColor << tColoredString::ColorString(1,1,1);
00315 message.SetTemplateParameter(2, resetColor);
00316 message << "$team_renamed";
00317 sn_ConsoleOut(message);
00318 }
00319 name = updateName;
00320 }
00321
00322 if ( nSERVER == sn_GetNetState() )
00323 RequestSync();
00324
00325
00326 if ( oldr != r || oldg != g || oldb != b )
00327 {
00328 for ( int i = players.Len() - 1; i >= 0; --i )
00329 {
00330 players(i)->UpdateName();
00331 }
00332 }
00333 }
00334
00335
00336 void eTeam::Update()
00337 {
00338 UpdateProperties();
00339 UpdateAppearance();
00340 }
00341
00342
00343 void eTeam::SetLocked( bool locked )
00344 {
00345 if ( locked && !locked_ )
00346 {
00347 sn_ConsoleOut( tOutput( "$invite_team_locked", Name() ) );
00348 }
00349 if ( !locked && locked_ )
00350 {
00351 sn_ConsoleOut( tOutput( "$invite_team_unlocked", Name() ) );
00352 }
00353
00354 locked_ = locked;
00355 }
00356
00357
00358 bool eTeam::IsLocked() const
00359 {
00360 return locked_;
00361 }
00362
00363
00364 void eTeam::Invite( ePlayerNetID * player )
00365 {
00366 tASSERT( player );
00367 if ( !IsInvited( player ) )
00368 {
00369 sn_ConsoleOut( tOutput( "$invite_team_invite", player->GetColoredName(), Name() ) );
00370 }
00371 player->invitations_.insert( this );
00372 }
00373
00374
00375 void eTeam::UnInvite( ePlayerNetID * player )
00376 {
00377 tASSERT( player );
00378 if ( player->CurrentTeam() == this )
00379 {
00380 sn_ConsoleOut( tOutput( "$invite_team_kick", player->GetColoredName(), Name() ) );
00381 player->SetTeam(0);
00382 }
00383 else
00384 {
00385 sn_ConsoleOut( tOutput( "$invite_team_uninvite", player->GetColoredName(), Name() ) );
00386 }
00387 player->invitations_.erase( this );
00388 }
00389
00390
00391 bool eTeam::IsInvited( ePlayerNetID const * player ) const
00392 {
00393 return player->invitations_.find( const_cast< eTeam * >( this ) ) != player->invitations_.end();
00394 }
00395
00396 void eTeam::AddScore ( int s )
00397 {
00398 score += s;
00399
00400 if ( nSERVER == sn_GetNetState() )
00401 RequestSync();
00402 }
00403
00404 void eTeam::ResetScore ( )
00405 {
00406 score = 0;
00407
00408 if ( nSERVER == sn_GetNetState() )
00409 RequestSync();
00410 }
00411
00412 void eTeam::SetScore ( int s )
00413 {
00414 score = s;
00415
00416 if ( nSERVER == sn_GetNetState() )
00417 RequestSync();
00418 }
00419
00420 void eTeam::AddScore(int points,
00421 const tOutput& reasonwin,
00422 const tOutput& reasonlose)
00423 {
00424 if (points==0)
00425 return;
00426
00427
00428 if ( players.Len() == 1 && maxPlayersLocal == 1 )
00429 {
00430 players[0]->AddScore( points, reasonwin, reasonlose );
00431 return;
00432 }
00433
00434 score += points;
00435
00436 tOutput message;
00437 message.SetTemplateParameter(1, tColoredString::RemoveColors(name));
00438 message.SetTemplateParameter(2, points > 0 ? points : -points);
00439
00440 if (points>0)
00441 {
00442 if (reasonwin.IsEmpty())
00443 message << "$player_win_default";
00444 else
00445 message.Append(reasonwin);
00446 }
00447 else
00448 {
00449 if (reasonlose.IsEmpty())
00450 message << "$player_lose_default";
00451 else
00452 message.Append(reasonlose);
00453 }
00454
00455 sn_ConsoleOut(message);
00456 RequestSync(true);
00457
00458 se_SaveToScoreFile(message);
00459 }
00460
00461 void eTeam::SwapTeamsNo(int a,int b){
00462 if (0>a || teams.Len()<=a)
00463 return;
00464 if (0>b || teams.Len()<=b)
00465 return;
00466 if (a==b)
00467 return;
00468
00469 eTeam *A=teams(a);
00470 eTeam *B=teams(b);
00471
00472 teams(b)=A;
00473 teams(a)=B;
00474 A->listID=b;
00475 B->listID=a;
00476 }
00477
00478 void eTeam::SortByScore(){
00479
00480
00481 bool inorder=false;
00482 while (!inorder){
00483 inorder=true;
00484 int i;
00485 for (i=teams.Len()-2;i>=0;i--)
00486 if (teams(i)->score < teams(i+1)->score){
00487 SwapTeamsNo(i,i+1);
00488 inorder=false;
00489 }
00490 }
00491 }
00492
00493 tString eTeam::Ranking( int MAX, bool cut ){
00494 SortByScore();
00495
00496 tString ret;
00497
00498 if (teams.Len()>0){
00499 ret.SetPos(2, cut );
00500 ret << tOutput("$team_scoretable_name");
00501 ret.SetPos(25, cut );
00502 ret << tOutput("$team_scoretable_score");
00503 ret.SetPos(32, cut );
00504 ret << tOutput("$team_scoretable_members");
00505 ret.SetPos(41, cut );
00506 ret << tOutput("$team_scoretable_alive");
00507 ret << "\n";
00508
00509 int max = teams.Len();
00510 if ( max > MAX && MAX > 0 )
00511 {
00512 max = MAX ;
00513 }
00514 for (int i=0;i<max;i++){
00515 tColoredString line;
00516 eTeam *t = teams(i);
00517 line << ColorString(t);
00518 tString name = t->Name();
00519
00520 name.SetPos( 24, cut );
00521
00522 line.SetPos(2, false );
00523 line << name;
00524 line.SetPos(25, false );
00525 line << t->score;
00526 line.SetPos(32, false );
00527 line << t->NumPlayers();
00528 line.SetPos(41, false);
00529 int alive=t->AlivePlayers();
00530 line << alive;
00531 ret << line << "\n";
00532 }
00533 if ( max < teams.Len() )
00534 {
00535 ret << " ...\n";
00536 }
00537 }
00538
00539
00540 return ret;
00541 }
00542 float eTeam::RankingGraph( float y, int MAX ){
00543 SortByScore();
00544
00545 tColoredString ret;
00546
00547 if (teams.Len()>0){
00548 tColoredString name;
00549 name << tColoredString::ColorString(1.,.5,.5)
00550 << tOutput("$team_scoretable_name");
00551 DisplayText(-.7, y, .06, name.c_str(), sr_fontScoretable, -1);
00552 tColoredString score;
00553 score << tOutput("$team_scoretable_score");
00554 DisplayText(-.3, y, .06, score.c_str(), sr_fontScoretable, -1);
00555 tColoredString members;
00556 members << tOutput("$team_scoretable_members");
00557 DisplayText(-.1, y, .06, members.c_str(), sr_fontScoretable, -1);
00558 tColoredString alive;
00559 alive << tOutput("$team_scoretable_alive");
00560 DisplayText(.3, y, .06, alive.c_str(), sr_fontScoretable, -1);
00561 y-=.06;
00562
00563 int max = teams.Len();
00564 if ( max > MAX && MAX > 0 )
00565 {
00566 max = MAX ;
00567 }
00568 for(int i=0;i<max;i++){
00569 eTeam *t = teams(i);
00570 tColoredString name;
00571 name << ColorString(t) << t->Name();
00572 DisplayText(-.7, y, .06, name.c_str(), sr_fontScoretable, -1);
00573 tColoredString score;
00574 score << t->score;
00575 DisplayText(-.3, y, .06, score.c_str(), sr_fontScoretable, -1);
00576 tColoredString members;
00577 members << t->NumPlayers();
00578 DisplayText(-.1, y, .06, members.c_str(), sr_fontScoretable, -1);
00579 tColoredString alive;
00580 int alivep=t->AlivePlayers();
00581 if(alivep)
00582 alive << tColoredString::ColorString(0,1,0);
00583 else
00584 alive << tColoredString::ColorString(1,0,0);
00585 alive << alivep;
00586 DisplayText(.3, y, .06, alive.c_str(), sr_fontScoretable, -1);
00587 y-=.06;
00588 }
00589 if ( max < teams.Len() )
00590 {
00591 DisplayText(-.7, y, .06, "...", sr_fontScoretable, -1);
00592 y-=.06;
00593 }
00594 }
00595 return y;
00596 }
00597
00598
00599
00600 int eTeam::NumHumanPlayers ( ) const
00601 {
00602 return numHumans;
00603 }
00604
00605 static int imbalance = 1;
00606
00607
00608 int eTeam::NumAIPlayers ( ) const
00609 {
00610 return numAIs;
00611 }
00612
00613
00614 void eTeam::EnforceConstraints()
00615 {
00616 if ( maxImbalance < 1 )
00617 maxImbalance = 1;
00618
00619 if ( minTeams > maxTeams )
00620 minTeams = maxTeams;
00621
00622 Enforce( minTeams, maxTeams, maxImbalance );
00623
00624
00625 if ( imbalance <= 0 )
00626 imbalance=0;
00627 }
00628
00629
00630 void eTeam::Enforce( int minTeams, int maxTeams, int maxImbalance)
00631 {
00632 if ( maxTeams < 1 )
00633 maxTeams = 1;
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644 if ( nCLIENT == sn_GetNetState() )
00645 return;
00646
00647 if ( maxImbalance < 1 )
00648 maxImbalance = 1;
00649
00650 if ( minTeams > maxTeams )
00651 minTeams = maxTeams;
00652
00653 if ( minPlayers > maxPlayers )
00654 minPlayers = maxPlayers;
00655
00656 bool balance = false;
00657
00658 int giveUp = 10;
00659 while ( !balance && giveUp-- > 0 )
00660 {
00661 balance = true;
00662
00663
00664 eTeam *max = NULL, *min = NULL, *ai = NULL;
00665 int maxP = minPlayers, minP = 100000;
00666 bool minLocked = false;
00667
00668 int numTeams = 0;
00669 int numHumanTeams = 0;
00670
00671 int i;
00672 for ( i = teams.Len()-1; i>=0; --i )
00673 {
00674 eTeam *t = teams(i);
00675
00676 if ( t->BalanceThisTeam() )
00677 {
00678 int humans = t->NumHumanPlayers();
00679
00680 numTeams++;
00681
00682 if ( humans > 0 )
00683 numHumanTeams++;
00684 else
00685 ai = t;
00686
00687 if ( humans > maxP )
00688 {
00689 maxP = humans;
00690 max = t;
00691 }
00692
00693
00694 if ( ( humans > 0 || t->NumPlayers() == 0 ) && humans < minP && ( minLocked || !t->IsLocked() ) )
00695 {
00696 minP = humans;
00697 min = t;
00698 minLocked = t->IsLocked();
00699 }
00700 }
00701 }
00702
00703 if ( ( numTeams > maxTeams && min ) || ( numTeams > minTeams && ai ) )
00704 {
00705
00706
00707 if ( ai )
00708 min = ai;
00709
00710 for ( i = min->NumPlayers()-1; i>=0; --i )
00711 {
00712
00713 tJUST_CONTROLLED_PTR< ePlayerNetID > pni = min->Player(i);
00714
00715
00716 if ( !pni->IsHuman() )
00717 {
00718 continue;
00719 }
00720
00721
00722 eTeam* second = NULL;
00723 int secondMinP = maxPlayers;
00724 for ( int j = teams.Len()-1; j>=0; --j )
00725 {
00726 eTeam *t = teams(j);
00727
00728 if ( t->BalanceThisTeam() )
00729 {
00730 int humans = t->NumHumanPlayers();
00731
00732 if ( humans < secondMinP && t != min )
00733 {
00734 secondMinP = humans;
00735 second = t;
00736 }
00737 }
00738 }
00739
00740 if ( second )
00741 {
00742
00743 int imbBackup = second->maxImbalanceLocal;
00744 second->maxImbalanceLocal = 99999;
00745 pni->SetTeamForce( 0 );
00746 pni->UpdateTeamForce();
00747 pni->SetTeamForce( second );
00748 pni->UpdateTeamForce();
00749 second->maxImbalanceLocal = imbBackup;
00750
00751 balance = false;
00752 }
00753 else
00754 {
00755
00756 pni->SetTeamForce( NULL );
00757 pni->UpdateTeamForce();
00758
00759 balance = false;
00760 }
00761 }
00762 }
00763 else if ( numTeams < minTeams )
00764 {
00765
00766 eTeam *newTeam = tNEW( eTeam );
00767 teams.Add( newTeam, newTeam->listID );
00768 newTeam->UpdateProperties();
00769
00770 balance = false;
00771 }
00772 else if ( ( ( maxP - maxImbalance > minP || maxP > maxPlayers ) && minP < maxPlayers ) || ( minP == 0 && maxP > 1 ) )
00773 {
00774
00775 if ( max )
00776 {
00777 ePlayerNetID* unluckyOne = max->YoungestHumanPlayer();
00778 unluckyOne->SetTeamForce( min );
00779 unluckyOne->UpdateTeamForce();
00780 balance = false;
00781 }
00782 }
00783 else if ( maxP > maxPlayers )
00784 {
00785
00786 eTeam* newTeam = tNEW( eTeam );
00787 if ( max )
00788 {
00789 ePlayerNetID* unluckyOne = max->YoungestHumanPlayer();
00790 unluckyOne->SetTeamForce( newTeam );
00791 unluckyOne->UpdateTeamForce();
00792
00793 balance = false;
00794 }
00795 }
00796 }
00797 }
00798
00799
00800
00801 static eTeam * se_ColoredTeams[TEAMCOLORS]={0,0,0,0,0,0,0,0};
00802
00803
00804 bool eTeam::NameTeamAfterColor ( bool wish )
00805 {
00806 if ( wish && colorID < 0 )
00807 {
00808 for ( int i = 0; i < TEAMCOLORS; ++i )
00809 {
00810 if ( !se_ColoredTeams[i] )
00811 {
00812 se_ColoredTeams[i] = this;
00813 colorID = i;
00814 return true;
00815 }
00816 }
00817 }
00818
00819 if ( !wish && colorID >= 0 )
00820 {
00821 se_ColoredTeams[ colorID ] = 0;
00822 colorID = -1;
00823 }
00824
00825 return colorID >= 0;
00826 }
00827
00828
00829 void eTeam::AddPlayer ( ePlayerNetID* player )
00830 {
00831 tASSERT( player );
00832
00833 tJUST_CONTROLLED_PTR< eTeam > keepalive( this );
00834
00835 if ( ! PlayerMayJoin( player ) )
00836 return;
00837
00838 tJUST_CONTROLLED_PTR< eTeam > oldTeam( player->currentTeam );
00839 tString oldTeamName("Old Team (BUG)");
00840 if ( player->currentTeam )
00841 {
00842 oldTeamName = oldTeam->Name();
00843 player->currentTeam->RemovePlayerDirty( player );
00844 oldTeam->UpdateProperties();
00845 oldTeam->UpdateAppearance();
00846 }
00847
00848 players.Add( player, player->teamListID );
00849
00850 player->currentTeam = this;
00851 player->timeJoinedTeam = tSysTimeFloat();
00852
00853 UpdateProperties();
00854
00855
00856 if ( players.Len() <= 1 )
00857 {
00858 UpdateAppearance();
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 }
00870
00871
00872 if ( sn_GetNetState() != nCLIENT )
00873 {
00874
00875 tColoredString playerName;
00876 playerName << *player << tColoredString::ColorString(.5,1,.5);
00877
00878
00879
00880 if ( ( players.Len() > 1 || colorID >= 0 ) && IsHuman() )
00881 {
00882 if ( oldTeam && oldTeam->players.Len() >= 1 )
00883 {
00884 sn_ConsoleOut( tOutput( "$player_changes_team",
00885 playerName,
00886 Name(),
00887 oldTeamName ) );
00888 }
00889 else
00890 {
00891
00892 sn_ConsoleOut( tOutput( "$player_joins_team_start",
00893 playerName,
00894 Name() ) );
00895 }
00896 }
00897 else if ( oldTeam )
00898 {
00899
00900 if ( oldTeam->players.Len() > 0 )
00901 sn_ConsoleOut( tOutput( "$player_leaves_team",
00902 playerName,
00903 oldTeamName ) );
00904 }
00905 else
00906 {
00907
00908 sn_ConsoleOut( tOutput( "$player_entered_game", playerName ) );
00909 }
00910 }
00911
00912 if ( listID < 0 )
00913 {
00914 teams.Add ( this, listID );
00915 }
00916
00917 player->UpdateName();
00918 }
00919
00920
00921 void eTeam::AddPlayerDirty ( ePlayerNetID* player )
00922 {
00923 tASSERT( player );
00924
00925 if ( player->currentTeam )
00926 {
00927 player->currentTeam->RemovePlayerDirty ( player );
00928 }
00929
00930 players.Add( player, player->teamListID );
00931 player->currentTeam = player->nextTeam = this;
00932 player->timeJoinedTeam = tSysTimeFloat();
00933
00934 if ( listID < 0 )
00935 {
00936 teams.Add ( this, listID );
00937 }
00938
00939 player->UpdateName();
00940 }
00941
00942
00943 void eTeam::RemovePlayerDirty ( ePlayerNetID* player )
00944 {
00945 tASSERT( player );
00946 tASSERT( player->currentTeam == this );
00947
00948
00949 for ( int i = players.Len()-2; i >= player->teamListID; --i )
00950 {
00951 ePlayerNetID * shuffle = players(i);
00952 players.Remove( shuffle, shuffle->teamListID );
00953 players.Add ( shuffle, shuffle->teamListID );
00954 }
00955 tASSERT ( player->teamListID == players.Len()-1 );
00956
00957
00958
00959 players.Remove ( player, player->teamListID );
00960 player->currentTeam = NULL;
00961
00962
00963 if ( listID >= 0 && players.Len() == 0 )
00964 {
00965 teams.Remove( this, listID );
00966
00967
00968 if ( colorID >= 0 )
00969 {
00970 se_ColoredTeams[ colorID ] = 0;
00971 colorID = -1;
00972 }
00973 }
00974 }
00975
00976
00977 void eTeam::RemovePlayer ( ePlayerNetID* player )
00978 {
00979 tCONTROLLED_PTR( eTeam ) safety;
00980 safety = this;
00981
00982 RemovePlayerDirty( player );
00983
00984 player->UpdateName();
00985
00986
00987 tColoredString playerName;
00988 playerName << *player << tColoredString::ColorString(1,.5,.5);
00989
00990 if ( sn_GetNetState() != nCLIENT )
00991 {
00992 if ( players.Len() > 0 || colorID >= 0 )
00993 {
00994 sn_ConsoleOut( tOutput( "$player_leaves_team",
00995 playerName,
00996 Name() ) );
00997 }
00998 else
00999 {
01000
01001 sn_ConsoleOut( tOutput( "$player_leaving_game", playerName ) );
01002 }
01003 }
01004
01005 UpdateProperties();
01006
01007
01008 if ( enforceRulesOnQuit && 0 == player->nextTeam && nCLIENT != sn_GetNetState() )
01009 imbalance = -10;
01010 }
01011
01012
01013
01014 bool eTeam::PlayerMayJoin( const ePlayerNetID* player ) const
01015 {
01016
01017 if (player->currentTeam==this)
01018 return true;
01019
01020
01021
01022 if ( !player->IsHuman() )
01023 return true;
01024
01025
01026 if ( player->GetSuspended() > 0 )
01027 return false;
01028
01029
01030 if ( IsLocked() && !IsInvited( player ) )
01031 {
01032 return false;
01033 }
01034
01035 int maxInb = maxImbalanceLocal;
01036
01037 int minP = 10000;
01038 if ( bool(player) && bool(player->currentTeam) )
01039 {
01040 minP = player->currentTeam->NumHumanPlayers() - 1;
01041
01042
01043 if ( minP == 0 && teams.Len() > minTeams )
01044 minP = 10000;
01045 }
01046
01047 for ( int i = teams.Len()-1; i>=0; --i )
01048 {
01049 eTeam *t = teams(i);
01050
01051 if ( t->BalanceThisTeam() )
01052 {
01053 int humans = t->NumHumanPlayers();
01054
01055 if ( humans < minP )
01056 {
01057 minP = humans;
01058 }
01059 }
01060 }
01061
01062 int maxPlayers = maxPlayersLocal;
01063
01064
01065 if ( numHumans < maxPlayers && ( sn_GetNetState() != nSERVER || minP + maxInb > numHumans ) )
01066 return true;
01067
01068
01069 {
01070 std::set< eTeam const * > swapTargets;
01071 swapTargets.insert( this );
01072
01073 bool goon = true;
01074 while ( goon )
01075 {
01076 goon = false;
01077 for ( std::set< eTeam const * >::iterator iter = swapTargets.begin(); iter != swapTargets.end(); ++iter )
01078 {
01079 eTeam const * team = *iter;
01080 for ( int i = team->players.Len()-1; i>=0; --i )
01081 {
01082 ePlayerNetID * otherPlayer = team->players(i);
01083 eTeam * swapTeam = otherPlayer->NextTeam();
01084 if ( swapTeam && swapTeam != otherPlayer->CurrentTeam() && swapTargets.find( swapTeam ) == swapTargets.end() )
01085 {
01086 goon = true;
01087 swapTargets.insert( swapTeam );
01088
01089
01090 if ( swapTeam == player->CurrentTeam() )
01091 return true;
01092 }
01093 }
01094 }
01095 }
01096 }
01097
01098
01099 return false;
01100 }
01101
01102
01103
01104 bool eTeam::NewTeamAllowed ()
01105 {
01106 return teams.Len() < maxTeams;
01107 }
01108
01109
01110
01111 static bool se_centerPlayerIsBoss=true;
01112 static tSettingItem<bool> se_centerPlayerIsBossConf("TEAM_CENTER_IS_BOSS", se_centerPlayerIsBoss );
01113
01114
01115 ePlayerNetID* eTeam::OldestPlayer ( ) const
01116 {
01117 ePlayerNetID* ret = NULL;
01118
01119 for (int i= players.Len(); i>=0; i--)
01120 {
01121 ePlayerNetID* p = players(i);
01122 if (!ret || ret->timeJoinedTeam > p->timeJoinedTeam || se_centerPlayerIsBoss )
01123 {
01124 ret = p;
01125 }
01126 }
01127
01128 return ret;
01129 }
01130
01131
01132 ePlayerNetID* eTeam::OldestHumanPlayer( ) const
01133 {
01134 ePlayerNetID* ret = NULL;
01135
01136 for (int i= players.Len()-1; i>=0; i--)
01137 {
01138 ePlayerNetID* p = players(i);
01139 if ( p->IsHuman() && ( !ret || ret->timeJoinedTeam > p->timeJoinedTeam || se_centerPlayerIsBoss ) )
01140 {
01141 ret = p;
01142 }
01143 }
01144
01145 return ret;
01146 }
01147
01148
01149 ePlayerNetID* eTeam::OldestAIPlayer ( ) const
01150 {
01151 ePlayerNetID* ret = NULL;
01152
01153 for (int i= players.Len()-1; i>=0; i--)
01154 {
01155 ePlayerNetID* p = players(i);
01156 if ( ( !p->IsHuman() ) && ( !ret || ret->timeJoinedTeam > p->timeJoinedTeam || se_centerPlayerIsBoss ) )
01157 {
01158 ret = p;
01159 }
01160 }
01161
01162 return ret;
01163 }
01164
01165
01166 ePlayerNetID* eTeam::YoungestPlayer ( ) const
01167 {
01168 ePlayerNetID* ret = NULL;
01169
01170 for (int i= players.Len(); i>=0; i--)
01171 {
01172 ePlayerNetID* p = players(i);
01173 if (!ret || ret->timeJoinedTeam < p->timeJoinedTeam )
01174 {
01175 ret = p;
01176 }
01177 }
01178
01179 return ret;
01180 }
01181
01182
01183 ePlayerNetID* eTeam::YoungestHumanPlayer( ) const
01184 {
01185 ePlayerNetID* ret = NULL;
01186
01187 for (int i= players.Len()-1; i>=0; i--)
01188 {
01189 ePlayerNetID* p = players(i);
01190 if ( p->IsHuman() && ( !ret || ret->timeJoinedTeam < p->timeJoinedTeam ) )
01191 {
01192 ret = p;
01193 }
01194 }
01195
01196 return ret;
01197 }
01198
01199
01200 ePlayerNetID* eTeam::YoungestAIPlayer ( ) const
01201 {
01202 ePlayerNetID* ret = NULL;
01203
01204 for (int i= players.Len()-1; i>=0; i--)
01205 {
01206 ePlayerNetID* p = players(i);
01207 if ( ( !p->IsHuman() ) && ( !ret || ret->timeJoinedTeam < p->timeJoinedTeam ) )
01208 {
01209 ret = p;
01210 }
01211 }
01212
01213 return ret;
01214 }
01215
01216
01217 bool eTeam::Alive ( ) const
01218 {
01219 for (int i= players.Len()-1; i>=0; --i)
01220 {
01221 ePlayerNetID* p = players(i);
01222 if ( p->Object() && p->Object()->Alive() )
01223 {
01224 return true;
01225 }
01226 }
01227
01228 return false;
01229 }
01230
01231
01232 int eTeam::AlivePlayers ( ) const
01233 {
01234 int ret = 0;
01235 for (int i= players.Len()-1; i>=0; --i)
01236 {
01237 ePlayerNetID* p = players(i);
01238 if ( p->Object() && p->Object()->Alive() )
01239 {
01240 ret++;
01241 }
01242 }
01243
01244 return ret;
01245 }
01246
01247
01248
01249 void eTeam::PrintName(tString &s) const
01250 {
01251 s << "Team " << name;
01252 }
01253
01254
01255
01256
01257
01258 bool eTeam::ClearToTransmit(int user) const
01259 {
01260 return true;
01261 }
01262
01263
01264
01265
01266
01267 void eTeam::WriteSync(nMessage &m)
01268 {
01269 m << r;
01270 m << g;
01271 m << b;
01272 m << name;
01273 m << maxPlayersLocal;
01274 m << maxImbalanceLocal;
01275 m << score;
01276 }
01277
01278
01279
01280 void eTeam::ReadSync(nMessage &m)
01281 {
01282 m >> r;
01283 m >> g;
01284 m >> b;
01285 m >> name;
01286 m >> maxPlayersLocal;
01287 m >> maxImbalanceLocal;
01288 m >> score;
01289
01290
01291 if ( sn_GetNetState() != nSERVER )
01292 {
01293 for ( int i = players.Len()-1; i>=0; --i )
01294 {
01295 players(i)->UpdateName();
01296 }
01297 }
01298 }
01299
01300
01301
01302 bool eTeam::SyncIsNew(nMessage &m)
01303 {
01304 return true;
01305 }
01306
01307
01308
01309
01310
01311
01312 void eTeam::WriteCreate(nMessage &m)
01313 {
01314 nNetObject::WriteCreate(m);
01315 }
01316
01317
01318
01319
01320
01321 void eTeam::ReceiveControlNet(nMessage &m)
01322 {
01323 }
01324
01325
01326
01327
01328
01329 eTeam::eTeam()
01330 :colorID(-1),listID(-1)
01331 {
01332 score = 0;
01333 locked_ = false;
01334 maxPlayersLocal = maxPlayers;
01335 maxImbalanceLocal = maxImbalance;
01336 r = g = b = 32;
01337 Update();
01338 }
01339
01340
01341
01342 eTeam::eTeam(nMessage &m)
01343 :nNetObject( m ),
01344 colorID(-1),listID(-1)
01345 {
01346 score = 0;
01347 locked_ = false;
01348 maxPlayersLocal = maxPlayers;
01349 maxImbalanceLocal = maxImbalance;
01350 r = g = b = 32;
01351 Update();
01352 }
01353
01354
01355 eTeam::~eTeam()
01356 {
01357 if ( listID >= 0 )
01358 teams.Remove( this, listID );
01359
01360 if ( colorID >= 0 )
01361 {
01362 se_ColoredTeams[ colorID ] = 0;
01363 colorID = -1;
01364 }
01365
01366
01367 for ( int i = se_PlayerNetIDs.Len()-1; i >= 0; --i )
01368 {
01369 se_PlayerNetIDs(i)->invitations_.erase( this );
01370 }
01371 }
01372
01373
01374
01375
01376
01382
01383
01384 bool eTeam::Enemies( eTeam const * team, ePlayerNetID const * player )
01385 {
01386
01387 if (!player || !team)
01388 return false;
01389
01390
01391 if ( player->CurrentTeam() == team )
01392 return false;
01393
01394
01395 if ( !player->currentTeam )
01396 return false;
01397
01398
01399 for (int i = team->players.Len()-1; i>=0; --i)
01400 if ( ePlayerNetID::Enemies( team->players(i), player ) )
01401 return true;
01402
01403 return false;
01404 }
01405
01406
01407
01408
01409
01410
01416
01417
01418 bool eTeam::Enemies( eTeam const * team1, eTeam const * team2 )
01419 {
01420
01421 if (!team1 || !team2 || team1 == team2)
01422 return false;
01423
01424
01425 for (int i = team2->players.Len()-1; i>=0; --i)
01426 if ( Enemies( team1, team2->players(i) ) )
01427 return true;
01428
01429 return false;
01430 }
01431
01432
01433
01434
01435
01436
01441
01442
01443 void eTeam::SwapPlayers( ePlayerNetID * player1, ePlayerNetID * player2 )
01444 {
01445 tASSERT( player1 );
01446 tASSERT( player2 );
01447
01448
01449 int id3 = player1->teamListID;
01450 player1->teamListID = player2->teamListID;
01451 player2->teamListID = id3;
01452
01453
01454 eTeam * team2 = player1->CurrentTeam();
01455 eTeam * team1 = player2->CurrentTeam();
01456
01457 if ( team2 )
01458 team2->players[player2->teamListID] = player2;
01459 if ( team1 )
01460 team1->players[player1->teamListID] = player1;
01461
01462
01463 player1->currentTeam = team1;
01464 player2->currentTeam = team2;
01465
01466
01467 team1 = player2->NextTeam();
01468 team2 = player1->NextTeam();
01469 if ( player1->currentTeam != player2->currentTeam )
01470 {
01471 player1->nextTeam = team1;
01472 player2->nextTeam = team2;
01473 }
01474 }
01475
01476
01477
01478
01479
01480
01485
01486
01487 void eTeam::Shuffle( int startID, int stopID )
01488 {
01489 tASSERT( 0 <= startID && startID < players.Len() );
01490 tASSERT( 0 <= stopID && stopID < players.Len() );
01491
01492 if ( startID == stopID )
01493 return;
01494
01495 tOutput message( "$team_shuffle", players[startID]->GetName(), startID+1, stopID+1 );
01496 sn_ConsoleOut( message );
01497
01498
01499 while ( startID < stopID )
01500 {
01501 SwapPlayers( players[startID], players[startID+1] );
01502 startID++;
01503 }
01504 while ( startID > stopID )
01505 {
01506 SwapPlayers( players[startID], players[startID-1] );
01507 startID--;
01508 }
01509 }
01510
01511