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 "eEventNotification.h"
00029 #include "tMemManager.h"
00030 #include "ePlayer.h"
00031
00032 #include "tConfiguration.h"
00033 #include "eNetGameObject.h"
00034 #include "rConsole.h"
00035 #include "eTimer.h"
00036 #include "tSysTime.h"
00037 #include "rFont.h"
00038 #include "uMenu.h"
00039 #include "tToDo.h"
00040 #include "rScreen.h"
00041 #include <string>
00042 #include <fstream>
00043 #include <iostream>
00044 #include <deque>
00045 #include "rRender.h"
00046 #include "rFont.h"
00047 #include "rSysdep.h"
00048 #include "nAuthentication.h"
00049 #include "tDirectories.h"
00050 #include "eTeam.h"
00051 #include "eVoter.h"
00052 #include "tReferenceHolder.h"
00053 #include "tRandom.h"
00054 #include "uInputQueue.h"
00055 #include "nServerInfo.h"
00056 #include "tRecorder.h"
00057 #include "nConfig.h"
00058 #include <time.h>
00059 #include "tRuby.h"
00060
00061 tColoredString & operator << (tColoredString &s,const ePlayer &p){
00062 return s << tColoredString::ColorString(p.rgb[0]/15.0,
00063 p.rgb[1]/15.0,
00064 p.rgb[2]/15.0)
00065 << p.Name();
00066 }
00067
00068 tColoredString & operator << (tColoredString &s,const ePlayerNetID &p){
00069 return s << p.GetColoredName();
00070 }
00071
00072 std::ostream & operator << (std::ostream &s,const ePlayerNetID &p){
00073 return s << p.GetColoredName();
00074 }
00075
00076 eAccessLevelHolder::eAccessLevelHolder()
00077 {
00078 accessLevel = tAccessLevel_Default;
00079 }
00080
00081 void eAccessLevelHolder::SetAccessLevel( tAccessLevel level )
00082 {
00083
00084
00085
00086
00087 if ( level < tCurrentAccessLevel::GetAccessLevel() )
00088 {
00089 con << "INTERNAL ERROR, security violation attempted. Clamping it.\n";
00090 st_Breakpoint();
00091 accessLevel = tCurrentAccessLevel::GetAccessLevel();
00092 }
00093
00094 accessLevel = level;
00095 }
00096
00097 tCONFIG_ENUM( eCamMode );
00098
00099 tList<ePlayerNetID> se_PlayerNetIDs;
00100 static ePlayer* se_Players = NULL;
00101
00102 bool se_assignTeamAutomatically = true;
00103 static tSettingItem< bool > se_assignTeamAutomaticallyConf( "AUTO_TEAM", se_assignTeamAutomatically );
00104
00105 static bool se_allowTeamChanges = true;
00106 static tSettingItem< bool > se_allowTeamChangesConf( "ALLOW_TEAM_CHANGE", se_allowTeamChanges );
00107
00108 static bool se_enableChat = true;
00109 static tSettingItem<bool> se_enaChat("ENABLE_CHAT", se_enableChat);
00110
00111 static tReferenceHolder< ePlayerNetID > se_PlayerReferences;
00112
00113 class PasswordStorage
00114 {
00115 public:
00116 tString username;
00117 tString methodCongested;
00118 nKrawall::nScrambledPassword password;
00119 bool save;
00120
00121 PasswordStorage(): save(false){};
00122 };
00123
00124 static bool operator == ( PasswordStorage const & a, PasswordStorage const & b )
00125 {
00126 return
00127 a.username == b.username &&
00128 a.methodCongested == b.methodCongested;
00129 }
00130
00131 static tArray<PasswordStorage> S_passwords;
00132
00133
00134
00135
00136
00137
00138 bool se_legacyLogNames = false;
00139 static tSettingItem<bool> se_llnConf("LEGACY_LOG_NAMES", se_legacyLogNames );
00140
00141
00142 static std::string se_EscapeName( tString const & original, bool keepAt = true )
00143 {
00144 std::ostringstream filter;
00145
00146 int lastC = 'x';
00147 for( int i = 0; i < original.Len()-1; ++i )
00148 {
00149 unsigned int c = static_cast< unsigned char >( original[i] );
00150
00151
00152 switch (c)
00153 {
00154
00155 case ' ':
00156 filter << "\\_";
00157 break;
00158 case '@':
00159 if ( keepAt )
00160 {
00161 filter << '@';
00162 }
00163 else
00164 {
00165 filter << "\\@";
00166 }
00167 break;
00168 case '\\':
00169 case '%':
00170 case ':':
00171 filter.put('\\');
00172 filter.put(c);
00173 break;
00174 case 'x':
00175
00176 if ( lastC == '0' )
00177 {
00178 filter << "\\x";
00179 break;
00180 }
00181 default:
00182 if ( 0x20 < c && 0x7f >= c )
00183 {
00184
00185 filter.put(c);
00186 }
00187 else
00188 {
00189
00190 filter << '%' << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << c;
00191 }
00192 }
00193
00194 lastC = c;
00195 }
00196
00197
00198 return filter.str();
00199 }
00200
00201 #ifdef KRAWALL_SERVER
00202
00203 static std::string se_UnEscapeName( tString const & original )
00204 {
00205 std::ostringstream filter;
00206
00207 int lastC = 'x';
00208 for( int i = 0; i < original.Len()-1; ++i )
00209 {
00210 int c = original[i];
00211
00212 if ( lastC == '\\' )
00213 {
00214 if ( c == '_' )
00215 {
00216 c = ' ';
00217 }
00218 filter.put(c);
00219 }
00220 else if ( c == '%' )
00221 {
00222
00223 char hex[3];
00224 hex[0] = original[i+1];
00225 hex[1] = original[i+2];
00226 hex[2] = 0;
00227 i += 2;
00228
00229 int decoded;
00230 std::istringstream s(hex);
00231 s >> std::hex >> decoded;
00232 tASSERT( !s.fail() );
00233 filter.put(decoded);
00234 }
00235 else if ( c != '\\' )
00236 {
00237 filter.put(c);
00238 }
00239
00240 lastC = c;
00241 }
00242
00243
00244 return filter.str();
00245 }
00246 #endif
00247
00248
00249 static tString se_UnauthenticatedUserName( tString const & name )
00250 {
00251 tString ret;
00252 ePlayerNetID::FilterName( name, ret );
00253 if ( se_legacyLogNames )
00254 {
00255 return ret;
00256 }
00257 else
00258 {
00259 return tString( se_EscapeName( ret, false ).c_str() );
00260 }
00261 }
00262
00263 void se_DeletePasswords(){
00264 S_passwords.SetLen(0);
00265
00266 st_SaveConfig();
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 tConsole::Message("$network_opts_deletepw_complete", tOutput(), 5);
00296 }
00297
00298 class tConfItemPassword:public tConfItemBase{
00299 public:
00300 tConfItemPassword():tConfItemBase("PASSWORD"){}
00301 ~tConfItemPassword(){};
00302
00303
00304 virtual void WriteVal(std::ostream &s){
00305 int i;
00306 bool first = 1;
00307 for (i = S_passwords.Len()-1; i>=0; i--)
00308 {
00309 PasswordStorage &storage = S_passwords[i];
00310 if (storage.save )
00311 {
00312 if (!first)
00313 s << "\nPASSWORD\t";
00314 first = false;
00315
00316 s << "1 ";
00317 nKrawall::WriteScrambledPassword(storage.password, s);
00318 s << '\t' << storage.methodCongested;
00319 s << '\t' << storage.username;
00320 }
00321 }
00322 if (first)
00323 s << "0 ";
00324 }
00325
00326
00327 virtual void ReadVal(std::istream &s){
00328
00329 int test;
00330 s >> test;
00331 if (test != 0)
00332 {
00333 PasswordStorage &storage = S_passwords[S_passwords.Len()];
00334 nKrawall::ReadScrambledPassword(s, storage.password);
00335 s >> storage.methodCongested;
00336 storage.username.ReadLine(s);
00337
00338 storage.save = true;
00339
00340
00341 for( int i = S_passwords.Len() - 2; i >= 0; --i )
00342 {
00343 PasswordStorage &other = S_passwords[i];
00344 if ( other == storage )
00345 {
00346 storage.save = false;
00347 break;
00348 }
00349 }
00350 }
00351 }
00352 };
00353
00354 static tConfItemPassword se_p;
00355
00356
00357 class eMenuItemUserName: public uMenuItemString
00358 {
00359 public:
00360 eMenuItemUserName(uMenu *M,tString &c):
00361 uMenuItemString(M,"$login_username","$login_username_help",c){}
00362 virtual ~eMenuItemUserName(){}
00363
00364 virtual bool Event(SDL_Event &e){
00365 #ifndef DEDICATED
00366 if (e.type==SDL_KEYDOWN &&
00367 (e.key.keysym.sym==SDLK_KP_ENTER || e.key.keysym.sym==SDLK_RETURN)){
00368
00369
00370 MyMenu()->SetSelected(0);
00371 return true;
00372 }
00373 else
00374 #endif
00375 return uMenuItemString::Event(e);
00376 }
00377 };
00378
00379
00380 class eMenuItemPassword: public uMenuItemString
00381 {
00382 public:
00383 static bool entered;
00384
00385 eMenuItemPassword(uMenu *M,tString &c):
00386 uMenuItemString(M,"$login_password_title","$login_password_help",c)
00387 {
00388 entered = false;
00389 }
00390 virtual ~eMenuItemPassword(){}
00391
00392 virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0)
00393 {
00394 tString* pwback = content;
00395 tString star;
00396 for (int i=content->Len()-2; i>=0; i--)
00397 star << "*";
00398 content = ☆
00399 uMenuItemString::Render(x,y, alpha, selected);
00400 content = pwback;
00401 }
00402
00403 virtual bool Event(SDL_Event &e){
00404 #ifndef DEDICATED
00405 if (e.type==SDL_KEYDOWN &&
00406 (e.key.keysym.sym==SDLK_KP_ENTER || e.key.keysym.sym==SDLK_RETURN)){
00407
00408 entered = true;
00409 MyMenu()->Exit();
00410 return true;
00411 }
00412 else
00413 #endif
00414 return uMenuItemString::Event(e);
00415 }
00416 };
00417
00418 bool eMenuItemPassword::entered;
00419
00420 static bool tr(){return true;}
00421
00422
00423 int se_PasswordStorageMode = 0;
00424 static tConfItem<int> pws("PASSWORD_STORAGE",
00425 "$password_storage_help",
00426 se_PasswordStorageMode);
00427
00428 static void PasswordCallback( nKrawall::nPasswordRequest const & request,
00429 nKrawall::nPasswordAnswer & answer )
00430 {
00431 int i;
00432
00433 tString& username = answer.username;
00434 const tString& message = request.message;
00435 nKrawall::nScrambledPassword& scrambled = answer.scrambled;
00436 bool failure = request.failureOnLastTry;
00437
00438 if ( request.method != "md5" && request.method != "bmd5" )
00439 {
00440 con << "Unknown password scrambling method requested.";
00441 answer.aborted = true;
00442 return;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 tString methodCongested = request.method + '|' + request.prefix + '|' + request.suffix;
00472
00473 PasswordStorage *storage = NULL;
00474 for (i = S_passwords.Len()-1; i>=0; i--)
00475 {
00476 PasswordStorage & candidate = S_passwords(i);
00477 if (answer.username == candidate.username &&
00478 methodCongested == candidate.methodCongested
00479 )
00480 storage = &candidate;
00481 }
00482
00483 if (!storage)
00484 {
00485
00486 for (i = S_passwords.Len()-1; i>=0; i--)
00487 if (S_passwords(i).username.Len() < 1)
00488 storage = &S_passwords(i);
00489
00490 if (!storage)
00491 storage = &S_passwords[S_passwords.Len()];
00492
00493 failure = true;
00494 }
00495
00496 static char const * section = "PASSWORD_MENU";
00497 tRecorder::Playback( section, failure );
00498 tRecorder::Record( section, failure );
00499
00500
00501 if (!failure)
00502 {
00503 if ( storage )
00504 {
00505 answer.username = storage->username;
00506 answer.scrambled = storage->password;
00507 }
00508 answer.automatic = true;
00509
00510 return;
00511 }
00512 else
00513 storage->username.Clear();
00514
00515
00516 uInputScrambler scrambler;
00517
00518
00519 uMenu login(message, false);
00520
00521
00522 tString password;
00523
00524 eMenuItemPassword pw(&login, password);
00525 eMenuItemUserName us(&login, username);
00526 us.SetColorMode( rTextField::COLOR_IGNORE );
00527
00528 uMenuItemSelection<int> storepw(&login,
00529 "$login_storepw_text",
00530 "$login_storepw_help",
00531 se_PasswordStorageMode);
00532 storepw.NewChoice("$login_storepw_dont_text",
00533 "$login_storepw_dont_help",
00534 -1);
00535 storepw.NewChoice("$login_storepw_mem_text",
00536 "$login_storepw_mem_help",
00537 0);
00538 storepw.NewChoice("$login_storepw_disk_text",
00539 "$login_storepw_disk_help",
00540 1);
00541
00542 uMenuItemExit cl(&login, "$login_cancel", "$login_cancel_help" );
00543
00544 login.SetSelected(1);
00545
00546
00547
00548
00549 for(int i = 0; i < MAX_PLAYERS; ++i) {
00550 tString const &id = se_Players[i].globalID;
00551 if(id.Len() <= username.Len() || id(username.Len() - 1) != '@') {
00552 continue;
00553 }
00554 bool match = true;
00555 for(int j = username.Len() - 2; j >= 0; --j) {
00556 if(username(j) != id(j)) {
00557 match = false;
00558 break;
00559 }
00560 }
00561 if(match) {
00562 login.SetSelected(0);
00563 }
00564 }
00565
00566
00567 rSmallConsoleCallback cb(&tr);
00568
00569 login.Enter();
00570
00571
00572 {
00573
00574 request.ScramblePassword( nKrawall::nScrambleInfo( username ), password, scrambled );
00575
00576
00577 answer.aborted = !eMenuItemPassword::entered;
00578
00579
00580 for (i = password.Len()-2; i>=0; i--)
00581 password(i) = 'a';
00582
00583 if (se_PasswordStorageMode >= 0)
00584 {
00585 storage->username = username;
00586 storage->methodCongested = methodCongested;
00587 storage->password = scrambled;
00588 storage->save = (se_PasswordStorageMode > 0);
00589 }
00590 }
00591 }
00592
00593 #ifdef DEDICATED
00594 #ifndef KRAWALL_SERVER
00595
00596
00597 static void se_AdminLogin_ReallyOnlyCallFromChatKTHNXBYE( ePlayerNetID * p )
00598 {
00599
00600
00601
00602 {
00603 tCurrentAccessLevel elevator( tAccessLevel_Owner, true );
00604 p->BeLoggedIn();
00605 }
00606
00607 sn_ConsoleOut("You have been logged in!\n",p->Owner());
00608 tString serverLoginMessage;
00609 serverLoginMessage << "Remote admin login for user \"" << p->GetUserName() << "\" accepted.\n";
00610 sn_ConsoleOut(serverLoginMessage, 0);
00611 }
00612 #endif
00613 #endif
00614
00615 #ifdef KRAWALL_SERVER
00616
00617 static tAccessLevel se_playAccessLevel = tAccessLevel_Program;
00618 static tSettingItem< tAccessLevel > se_playAccessLevelConf( "ACCESS_LEVEL_PLAY", se_playAccessLevel );
00619
00620
00621 static tAccessLevel se_playAccessLevelSliding = tAccessLevel_Program;
00622 static tSettingItem< tAccessLevel > se_playAccessLevelSlidingConf( "ACCESS_LEVEL_PLAY_SLIDING", se_playAccessLevelSliding );
00623
00624
00625 static int se_playAccessLevelSliders = 4;
00626 static tSettingItem< int > se_playAccessLevelSlidersConf( "ACCESS_LEVEL_PLAY_SLIDERS", se_playAccessLevelSliders );
00627
00628 static tAccessLevel se_accessLevelRequiredToPlay = tAccessLevel_Program;
00629 static void UpdateAccessLevelRequiredToPlay()
00630 {
00631 int newAccessLevel = se_accessLevelRequiredToPlay;
00632
00633
00634 if ( newAccessLevel < se_playAccessLevelSliding )
00635 newAccessLevel = se_playAccessLevelSliding;
00636
00637 if ( newAccessLevel > se_playAccessLevel )
00638 newAccessLevel = se_playAccessLevel;
00639
00640 bool changed = true;
00641 while ( changed )
00642 {
00643 changed = false;
00644
00645
00646 int countAbove = 0, countOn = 0;
00647
00648 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
00649 {
00650 ePlayerNetID* player = se_PlayerNetIDs(i);
00651
00652
00653 if ( !player->IsHuman() || !player->NextTeam() )
00654 continue;
00655
00656 if ( player->GetAccessLevel() < newAccessLevel )
00657 {
00658 countAbove++;
00659 }
00660 else if ( player->GetAccessLevel() == newAccessLevel )
00661 {
00662 countOn++;
00663 }
00664 }
00665
00666 if ( countAbove >= se_playAccessLevelSliders && newAccessLevel > se_playAccessLevelSliding )
00667 {
00668
00669 newAccessLevel --;
00670 changed = true;
00671 }
00672 else if ( countOn + countAbove < se_playAccessLevelSliders && newAccessLevel < se_playAccessLevel )
00673 {
00674
00675 newAccessLevel ++;
00676 changed = true;
00677 }
00678 }
00679
00680 if ( se_accessLevelRequiredToPlay != newAccessLevel )
00681 {
00682 sn_ConsoleOut( tOutput( "$access_level_play_changed",
00683 tCurrentAccessLevel::GetName( se_accessLevelRequiredToPlay ),
00684 tCurrentAccessLevel::GetName( static_cast< tAccessLevel >( newAccessLevel ) ) ) );
00685
00686 se_accessLevelRequiredToPlay = static_cast< tAccessLevel >( newAccessLevel );
00687 }
00688 }
00689
00690 tAccessLevel ePlayerNetID::AccessLevelRequiredToPlay()
00691 {
00692 return se_accessLevelRequiredToPlay;
00693 }
00694
00695
00696 static tAccessLevel se_hideAccessLevelOf = tAccessLevel_Program;
00697 static tSettingItem< tAccessLevel > se_hideAccessLevelOfConf( "ACCESS_LEVEL_HIDE_OF", se_hideAccessLevelOf );
00698
00699
00700 static tAccessLevel se_hideAccessLevelTo = tAccessLevel_Moderator;
00701 static tSettingItem< tAccessLevel > se_hideAccessLevelToConf( "ACCESS_LEVEL_HIDE_TO", se_hideAccessLevelTo );
00702
00703
00704 static bool se_Hide( ePlayerNetID const * hider, tAccessLevel currentLevel )
00705 {
00706 tASSERT( hider );
00707
00708 return
00709 hider->GetAccessLevel() >= se_hideAccessLevelOf &&
00710 hider->StealthMode() &&
00711 currentLevel > se_hideAccessLevelTo;
00712 }
00713
00714
00715 static bool se_Hide( ePlayerNetID const * hider, ePlayerNetID const * seeker )
00716 {
00717 if ( !seeker )
00718 {
00719 return se_Hide( hider, tCurrentAccessLevel::GetAccessLevel() );
00720 }
00721
00722 if ( seeker == hider )
00723 {
00724 return false;
00725 }
00726
00727 return se_Hide( hider, seeker->GetAccessLevel() );
00728 }
00729
00730
00731 void se_SecretConsoleOut( tOutput const & message, tAccessLevel hider, ePlayerNetID const * exception1, ePlayerNetID const * exception2 = 0 )
00732 {
00733
00734 if ( hider < se_hideAccessLevelOf )
00735 {
00736 sn_ConsoleOut( message );
00737 }
00738 else
00739 {
00740
00741 con << message;
00742
00743 bool canSee[ MAXCLIENTS+1 ];
00744 for( int i = MAXCLIENTS; i>=0; --i )
00745 {
00746 canSee[i] = false;
00747 }
00748
00749
00750 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
00751 {
00752 ePlayerNetID* player = se_PlayerNetIDs(i);
00753 if ( player->GetAccessLevel() <= se_hideAccessLevelTo || player == exception1 || player == exception2 )
00754 {
00755 canSee[ player->Owner() ] = true;
00756 }
00757 }
00758
00759
00760 for( int i = MAXCLIENTS; i>=0; --i )
00761 {
00762 if ( canSee[i] )
00763 {
00764 sn_ConsoleOut( message, i );
00765 }
00766 }
00767 }
00768 }
00769
00770
00771 void se_SecretConsoleOut( tOutput const & message, ePlayerNetID const * hider, ePlayerNetID const * admin = 0 )
00772 {
00773 tASSERT( hider );
00774 se_SecretConsoleOut( message, hider->GetAccessLevel(), hider, admin );
00775 }
00776
00777 static void ResultCallback( nKrawall::nCheckResult const & result )
00778 {
00779 tString username = result.username;
00780 tString authority = result.authority;
00781 bool success = result.success;
00782
00783 ePlayerNetID * player = dynamic_cast< ePlayerNetID * >( static_cast< nNetObject * >( result.user ) );
00784 if ( !player || player->Owner() <= 0 )
00785 {
00786
00787 return;
00788 }
00789
00790 tString authName = username + "@" + authority;
00791
00792
00793 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
00794 {
00795 ePlayerNetID* player = se_PlayerNetIDs(i);
00796 if ( player->IsAuthenticated() && player->GetRawAuthenticatedName() == authName )
00797 {
00798 sn_ConsoleOut( tOutput("$login_request_failed_dup"), player->Owner() );
00799 return;
00800 }
00801 }
00802
00803 if (success)
00804 {
00805 player->Authenticate( authName, result.accessLevel );
00806
00807
00808
00809
00810 for ( std::deque< tString >::const_iterator i = result.blurb.begin(); i != result.blurb.end(); ++i )
00811 {
00812 std::istringstream s( static_cast< char const * >( *i ) );
00813 tString token, rest;
00814 s >> token;
00815 rest.ReadLine( s );
00816
00817 std::ostringstream o;
00818 o << "AUTHORITY_BLURB_" << token << " " << player->GetFilteredAuthenticatedName() << " " << rest << std::endl;
00819
00820 se_SaveToLadderLog( o.str().c_str() );
00821 }
00822 }
00823 else
00824 {
00825 if ( sn_GetNetState() == nSERVER )
00826 {
00827 tOutput out( tOutput("$login_failed_message", result.error ) );
00828 sn_ConsoleOut( out, player->Owner() );
00829 con << out;
00830
00831
00832 if ( result.automatic )
00833 {
00834 nAuthentication::RequestLogin( authority ,username , *player, "$login_request_failed" );
00835 }
00836 }
00837 }
00838
00839
00840 ePlayerNetID::RequestScheduledLogins();
00841 }
00842 #else
00843
00844
00845
00846
00847
00848
00849
00850 static bool se_Hide( ePlayerNetID const * hider, ePlayerNetID const * seeker )
00851 {
00852 return false;
00853 }
00854 #endif
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 class eMenuItemSilence: public uMenuItemToggle
00870 {
00871 public:
00872 eMenuItemSilence(uMenu *m, ePlayerNetID* p )
00873 : uMenuItemToggle( m, tOutput(""),tOutput("$silence_player_help" ), p->AccessSilenced() )
00874 {
00875 this->title.Clear();
00876 this->title.SetTemplateParameter(1, p->GetColoredName() );
00877 this->title << "$silence_player_text";
00878 player_ = p;
00879 }
00880
00881 ~eMenuItemSilence()
00882 {
00883 }
00884 private:
00885 tCONTROLLED_PTR( ePlayerNetID ) player_;
00886 };
00887
00888
00889
00890
00891
00892 void ePlayerNetID::SilenceMenu()
00893 {
00894 uMenu menu( "$player_police_silence_text" );
00895
00896 int size = se_PlayerNetIDs.Len();
00897 eMenuItemSilence** items = tNEW( eMenuItemSilence* )[ size ];
00898
00899 int i;
00900 for ( i = size-1; i>=0; --i )
00901 {
00902 ePlayerNetID* player = se_PlayerNetIDs[ i ];
00903 if ( player->IsHuman() )
00904 {
00905 items[i] = tNEW( eMenuItemSilence )( &menu, player );
00906 }
00907 else
00908 {
00909 items[i] = 0;
00910 }
00911
00912 }
00913
00914 menu.Enter();
00915
00916 for ( i = size - 1; i>=0; --i )
00917 {
00918 if( items[i] ) delete items[i];
00919 }
00920 delete[] items;
00921 }
00922
00923 void ePlayerNetID::PoliceMenu()
00924 {
00925 uMenu menu( "$player_police_text" );
00926
00927 uMenuItemFunction kick( &menu, "$player_police_kick_text", "$player_police_kick_help", eVoter::KickMenu );
00928 uMenuItemFunction silence( &menu, "$player_police_silence_text", "$player_police_silence_help", ePlayerNetID::SilenceMenu );
00929
00930 menu.Enter();
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955 #ifndef DEDICATED
00956
00957 static char const * default_instant_chat[]=
00958 {"/team \\",
00959 "/msg \\",
00960 "/me \\",
00961 "LOL!",
00962 "/team 1 Yes Oui Ja",
00963 "/team 0 No Non Nein",
00964 "/team I'm going in!",
00965 "Give the rim a break; hug a tree instead.",
00966 "Lag is a myth. It is only in your brain.",
00967 "Rubber kills gameplay!",
00968 "Every time you double bind, God kills a kitten.",
00969 "http://www.armagetronad.net",
00970 "Only idiots keep their instant chat at default values.",
00971 "/me wanted to download pr0n, but only got this stupid game.",
00972 "Speed for weaks!",
00973 "This server sucks! I'm going home.",
00974 "Grind EVERYTHING! And 180 some more!",
00975 "/me has an interesting mental disorder.",
00976 "Ah, a nice, big, roomy box all for me!",
00977 "Go that way! No, the other way!",
00978 "WD! No points!",
00979 "/me is a noob.",
00980 "/me just installed this game and still doesn't know how to talk.",
00981 "/team You all suck, I want a new team.",
00982 "Are you the real \"Player 1\"?",
00983 "0x5aff91Only idiots0xffa962 write in0xc560ff color all0x87dfff the time!",
00984 NULL};
00985
00986 #endif
00987
00988
00989 ePlayer * ePlayer::PlayerConfig(int p){
00990 uPlayerPrototype *P = uPlayerPrototype::PlayerConfig(p);
00991 return dynamic_cast<ePlayer*>(P);
00992
00993 }
00994
00995 void ePlayer::StoreConfitem(tConfItemBase *c){
00996 tASSERT(CurrentConfitem < PLAYER_CONFITEMS);
00997 configuration[CurrentConfitem++] = c;
00998 }
00999
01000 void ePlayer::DeleteConfitems(){
01001 while (CurrentConfitem>0){
01002 CurrentConfitem--;
01003 tDESTROY(configuration[CurrentConfitem]);
01004 }
01005 }
01006
01007 uActionPlayer *ePlayer::se_instantChatAction[MAX_INSTANT_CHAT];
01008
01009 #ifdef WIN32
01010 #include <lmcons.h>
01011 #include <windows.h>
01012 #ifndef ULEN
01013
01014 #define ULEN 20
01015 #endif
01016 static tString se_UserNameHelper()
01017 {
01018 char name[ULEN+1];
01019 DWORD len = ULEN;
01020 if ( GetUserName( name, &len ) )
01021 return tString( name );
01022
01023 return tString();
01024 }
01025 #else
01026 static char const * se_UserNameHelper()
01027 {
01028 return getenv( "USER" );
01029 }
01030 #endif
01031
01032 static const tString& se_UserName()
01033 {
01034 srand( (unsigned)time( NULL ) );
01035
01036 static tString ret( se_UserNameHelper() );
01037 return ret;
01038 }
01039
01040 ePlayer::ePlayer():cockpit(0){
01041 nAuthentication::SetUserPasswordCallback(&PasswordCallback);
01042 #ifdef KRAWALL_SERVER
01043 nAuthentication::SetLoginResultCallback (&ResultCallback);
01044 #endif
01045
01046 nameTeamAfterMe = false;
01047 favoriteNumberOfPlayersPerTeam = 3;
01048
01049 CurrentConfitem = 0;
01050
01051 bool getUserName = false;
01052 if ( id == 0 )
01053 {
01054 name = se_UserName();
01055 getUserName = ( name.Len() > 1 );
01056 }
01057 if ( !getUserName )
01058 name << "Player " << id+1;
01059
01060 #ifndef DEDICATED
01061 tString confname;
01062
01063 confname << "PLAYER_"<< id+1;
01064 StoreConfitem(tNEW(tConfItemLine) (confname,
01065 "$player_name_confitem_help",
01066 name));
01067
01068 confname.Clear();
01069
01070 confname << "TEAMNAME_"<< id+1;
01071 StoreConfitem(tNEW(tConfItemLine) (confname,
01072 "$team_name_confitem_help",
01073 teamname));
01074
01075 confname.Clear();
01076
01077 confname << "USER_"<< id+1;
01078 StoreConfitem(tNEW(tConfItemLine) (confname,
01079 "$player_user_confitem_help",
01080 globalID));
01081
01082 confname.Clear();
01083 confname << "AUTO_LOGIN_"<< id+1;
01084 StoreConfitem(tNEW(tConfItem<bool>)(confname,
01085 "$auto_login_help",
01086 autoLogin));
01087 autoLogin = false;
01088
01089 confname.Clear();
01090
01091 confname << "CAMCENTER_"<< id+1;
01092 centerIncamOnTurn=true;
01093 StoreConfitem(tNEW(tConfItem<bool>)
01094 (confname,
01095 "$camcenter_help",
01096 centerIncamOnTurn) );
01097
01098 confname.Clear();
01099 startCamera=CAMERA_SMART;
01100 confname << "START_CAM_"<< id+1;
01101 StoreConfitem(tNEW(tConfItem<eCamMode>) (confname,
01102 "$start_cam_help",
01103 startCamera));
01104
01105 confname.Clear();
01106 confname << "START_FOV_"<< id+1;
01107 startFOV=90;
01108 StoreConfitem(tNEW(tConfItem<int>) (confname,
01109 "$start_fov_help",
01110 startFOV));
01111 confname.Clear();
01112
01113 confname.Clear();
01114 confname << "SMART_GLANCE_CUSTOM_"<< id+1;
01115 smartCustomGlance=true;
01116 StoreConfitem(tNEW(tConfItem<bool>) (confname,
01117 "$camera_smart_glance_custom_help",
01118 smartCustomGlance));
01119 confname.Clear();
01120
01121 int i;
01122 for(i=CAMERA_COUNT-1;i>=0;i--){
01123 confname << "ALLOW_CAM_"<< id+1 << "_" << i;
01124 StoreConfitem(tNEW(tConfItem<bool>) (confname,
01125 "$allow_cam_help",
01126 allowCam[i]));
01127 allowCam[i]=true;
01128 confname.Clear();
01129 }
01130
01131 for(i=MAX_INSTANT_CHAT-1;i>=0;i--){
01132 confname << "INSTANT_CHAT_STRING_" << id+1 << '_' << i+1;
01133 StoreConfitem(tNEW(tConfItemLine) (confname,
01134 "$instant_chat_string_help",
01135 instantChatString[i]));
01136 confname.Clear();
01137 }
01138
01139 for(i=0; i < MAX_INSTANT_CHAT;i++){
01140 if (!default_instant_chat[i])
01141 break;
01142
01143 instantChatString[i]=default_instant_chat[i];
01144 }
01145
01146 confname << "SPECTATOR_MODE_"<< id+1;
01147 StoreConfitem(tNEW(tConfItem<bool>)(confname,
01148 "$spectator_mode_help",
01149 spectate));
01150 spectate=false;
01151 confname.Clear();
01152
01153 confname << "HIDE_IDENTITY_"<< id+1;
01154 StoreConfitem(tNEW(tConfItem<bool>)(confname,
01155 "$hide_identity_help",
01156 stealth));
01157 stealth=false;
01158 confname.Clear();
01159
01160 confname << "NAME_TEAM_AFTER_PLAYER_"<< id+1;
01161 StoreConfitem(tNEW(tConfItem<bool>)(confname,
01162 "$name_team_after_player_help",
01163 nameTeamAfterMe));
01164 nameTeamAfterMe=false;
01165 confname.Clear();
01166
01167 confname << "FAV_NUM_PER_TEAM_PLAYER_"<< id+1;
01168 StoreConfitem(tNEW(tConfItem<int>)(confname,
01169 "$fav_num_per_team_player_help",
01170 favoriteNumberOfPlayersPerTeam ));
01171 favoriteNumberOfPlayersPerTeam = 3;
01172 confname.Clear();
01173
01174
01175 confname << "AUTO_INCAM_"<< id+1;
01176 autoSwitchIncam=false;
01177 StoreConfitem(tNEW(tConfItem<bool>) (confname,
01178 "$auto_incam_help",
01179 autoSwitchIncam));
01180 confname.Clear();
01181
01182 confname << "CAMWOBBLE_"<< id+1;
01183 wobbleIncam=false;
01184 StoreConfitem(tNEW(tConfItem<bool>) (confname,
01185 "$camwobble_help",
01186 wobbleIncam));
01187
01188 confname.Clear();
01189 confname << "COLOR_B_"<< id+1;
01190 StoreConfitem(tNEW(tConfItem<int>) (confname,
01191 "$color_b_help",
01192 rgb[2]));
01193
01194 confname.Clear();
01195 confname << "COLOR_G_"<< id+1;
01196 StoreConfitem(tNEW(tConfItem<int>) (confname,
01197 "$color_g_help",
01198 rgb[1]));
01199
01200 confname.Clear();
01201 confname << "COLOR_R_"<< id+1;
01202 StoreConfitem(tNEW(tConfItem<int>) (confname,
01203 "$color_r_help",
01204 rgb[0]));
01205 confname.Clear();
01206 #endif
01207
01208 tRandomizer & randomizer = tRandomizer::GetInstance();
01209
01210 static int r = randomizer.Get(4) + se_UserName().Len();
01211 int cid = ( r + id ) % 4;
01212
01213 static REAL R[MAX_PLAYERS]={1,.2,.2,1};
01214 static REAL G[MAX_PLAYERS]={.2,1,.2,1};
01215 static REAL B[MAX_PLAYERS]={.2,.2,1,.2};
01216
01217 rgb[0]=int(R[cid]*15);
01218 rgb[1]=int(G[cid]*15);
01219 rgb[2]=int(B[cid]*15);
01220
01221 cam=NULL;
01222 }
01223
01224 ePlayer::~ePlayer(){
01225 tCHECK_DEST;
01226 DeleteConfitems();
01227 }
01228
01229 #ifndef DEDICATED
01230 void ePlayer::Render(){
01231 if (cam) cam->Render();
01232 }
01233 #endif
01234
01235 static void chat( ePlayer * chatter, tString const & msgCore );
01236 void se_rubyEval(tString msgCore) {
01237 #ifdef HAVE_LIBRUBY
01238 try {
01239 tRuby::Safe safe(0.3);
01240 safe.Load(tDirectories::Data(), "scripts/subbanese.rb");
01241 VALUE val = safe.Eval(msgCore);
01242 VALUE to_s = rb_funcall(val, rb_intern("to_s"), 0);
01243 tString res("result: ");
01244 res << StringValuePtr(to_s);
01245
01246 switch (sn_GetNetState())
01247 {
01248 case nSTANDALONE:
01249 case nCLIENT:
01250 {
01251 ePlayerNetID * me = ePlayer::PlayerConfig( 0 )->netPlayer;
01252 me->Chat(res);
01253 }
01254 break;
01255 case nSERVER:
01256 tColoredString send;
01257 send << tColoredString::ColorString( 1,0,0 );
01258 send << "Admin";
01259 send << tColoredString::ColorString( 1,1,.5 );
01260 send << ": " << res << "\n";
01261 sn_ConsoleOut(send);
01262 break;
01263 }
01264 }
01265 catch (std::runtime_error & e) {
01266 std::cout << e.what() << '\n';
01267 }
01268 catch(...) {
01269 std::cout << "unhandled exception\n";
01270 }
01271 #endif
01272 }
01273
01274 static void se_RequestLogin( ePlayerNetID * p );
01275
01276
01277 #ifdef KRAWALL_SERVER
01278 static bool se_IsUserBanned( ePlayerNetID * p, tString const & name );
01279 #endif
01280
01281
01282 static void se_LoginWanted( nMessage & m )
01283 {
01284 #ifdef KRAWALL_SERVER
01285
01286
01287 ePlayerNetID * p;
01288 m >> p;
01289
01290 if ( p && m.SenderID() == p->Owner() && !p->IsAuthenticated() )
01291 {
01292
01293 m >> p->loginWanted;
01294 tString authName;
01295
01296
01297 m >> authName;
01298 p->SetRawAuthenticatedName( authName );
01299
01300
01301 if ( se_IsUserBanned( p, authName ) )
01302 {
01303 return;
01304 }
01305
01306 se_RequestLogin( p );
01307 }
01308 #else
01309 sn_ConsoleOut( tOutput( "$login_not_supported" ), m.SenderID() );
01310 #endif
01311 }
01312
01313 static nDescriptor se_loginWanted(204,se_LoginWanted,"AuthWanted");
01314
01315
01316 static void se_WantLogin( ePlayer * lp )
01317 {
01318
01319 if( sn_GetNetState() != nCLIENT )
01320 {
01321 return;
01322 }
01323
01324
01325 static nVersionFeature authentication( 15 );
01326 if( !authentication.Supported(0) )
01327 {
01328 return;
01329 }
01330
01331 tASSERT(lp);
01332 ePlayerNetID *p = lp->netPlayer;
01333 if ( !p )
01334 {
01335 return;
01336 }
01337
01338 nMessage *m = new nMessage( se_loginWanted );
01339
01340
01341 *m << p;
01342
01343
01344 *m << p->loginWanted;
01345
01346
01347 *m << lp->globalID;
01348
01349 m->Send( 0 );
01350
01351
01352 p->loginWanted = false;
01353 }
01354
01355 void ePlayer::SendAuthNames()
01356 {
01357
01358 if( sn_GetNetState() != nCLIENT )
01359 {
01360 return;
01361 }
01362 for(int i=MAX_PLAYERS-1;i>=0;i--)
01363 {
01364 se_WantLogin( ePlayer::PlayerConfig(i) );
01365 }
01366 }
01367
01368
01369 static void se_RequestLogin( ePlayerNetID * p )
01370 {
01371 tString userName = p->GetUserName();
01372 tString authority;
01373 if ( p->Owner() != 0 && p->loginWanted )
01374 {
01375 #ifdef KRAWALL_SERVER
01376 if ( p->GetRawAuthenticatedName().Len() > 1 )
01377 {
01378 nKrawall::SplitUserName( p->GetRawAuthenticatedName(), userName, authority );
01379 }
01380
01381 p->loginWanted =
01382 !nAuthentication::RequestLogin( authority,
01383 userName,
01384 *p,
01385 authority.Len() > 1 ? tOutput( "$login_request", authority ) : tOutput( "$login_request_local" ) );
01386 #endif
01387 }
01388 }
01389
01390 void ePlayerNetID::RequestScheduledLogins()
01391 {
01392 for( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
01393 {
01394 se_RequestLogin( se_PlayerNetIDs(i) );
01395 }
01396 }
01397
01398 void ePlayer::LogIn()
01399 {
01400
01401 if( sn_GetNetState() != nCLIENT )
01402 {
01403 return;
01404 }
01405
01406
01407 for(int i=MAX_PLAYERS-1;i>=0;i--)
01408 {
01409 ePlayer * lp = ePlayer::PlayerConfig(i);
01410 if ( lp && lp->netPlayer )
01411 {
01412 lp->netPlayer->loginWanted = true;
01413 se_WantLogin( lp );
01414 }
01415 }
01416 }
01417
01418 static void se_DisplayChatLocally( ePlayerNetID* p, const tString& say )
01419 {
01420 #ifdef DEBUG_X
01421 if (strstr( say, "BUG" ) )
01422 {
01423 st_Breakpoint();
01424 }
01425 #endif
01426
01427 if ( p && !p->IsSilenced() && se_enableChat )
01428 {
01429
01430
01431 tColoredString message;
01432 message << *p;
01433 message << tColoredString::ColorString(1,1,.5);
01434 message << ": " << say << '\n';
01435 con << message;
01436
01437 if (say.StartsWith("eval ")) {
01438 se_rubyEval(say.SubStr(5));
01439 }
01440 }
01441 }
01442
01443 static bool se_enableNameHilighting=true;
01444 static tSettingItem< bool > se_enableNameHilightingConf("ENABLE_NAME_HILIGHTING",se_enableNameHilighting);
01445
01446 static void se_DisplayChatLocallyClient( ePlayerNetID* p, const tString& message )
01447 {
01448 if ( p && !p->IsSilenced() && se_enableChat )
01449 {
01450 if (!p->Object() || !p->Object()->Alive()) {
01451 con << tOutput("$dead_console_decoration");
01452 }
01453
01454 tString actualMessage(message);
01455
01456 if(se_enableNameHilighting) {
01457
01458 rViewportConfiguration* viewportConfiguration = rViewportConfiguration::CurrentViewportConfiguration();
01459 if(viewportConfiguration == 0) return;
01460 for ( int viewport = viewportConfiguration->num_viewports-1; viewport >= 0; --viewport ) {
01461 int playerID = sr_viewportBelongsToPlayer[ viewport ];
01462
01463
01464 ePlayer* player = ePlayer::PlayerConfig( playerID );
01465 if(player == 0) continue;
01466 ePlayerNetID* netPlayer = player->netPlayer;
01467 if(netPlayer == 0) continue;
01468 if(netPlayer == p) continue;
01469 tString const &name = netPlayer->GetName();
01470
01471 if ( name.size() > 0 )
01472 {
01473
01474 for(tString::size_type pos = actualMessage.find(name); pos != tString::npos; pos = actualMessage.find(name, pos+16)) {
01475
01476 tString::size_type lastcolorpos = actualMessage.rfind("0x", pos);
01477 tString lastcolorstring;
01478 if(lastcolorpos != tString::npos) {
01479 lastcolorstring = actualMessage.SubStr(lastcolorpos, 8);
01480 } else {
01481 lastcolorstring = "0xffff7f";
01482 }
01483
01484 if(lastcolorpos >= pos - 8) {
01485
01486 pos -= 16 - name.size();
01487 continue;
01488 }
01489
01490
01491 actualMessage.insert(pos+name.size(), lastcolorstring);
01492 actualMessage.insert(pos, "0xff887f");
01493 }
01494 }
01495 }
01496 }
01497 con << actualMessage << "\n";
01498
01499 tString msgCore = tColoredString::RemoveColors(message);
01500 int skip = msgCore.find(": eval");
01501 if (skip > 0) {
01502 se_rubyEval(msgCore.SubStr(skip + 6));
01503 }
01504 }
01505
01506 }
01507
01508 static nVersionFeature se_chatRelay( 3 );
01509
01511 static nVersionFeature se_chatHandlerClient( 6 );
01512
01513
01514 void handle_chat( nMessage& );
01515 static nDescriptor chat_handler(200,handle_chat,"Chat");
01516
01517
01518 bool Contains( const tString & search_for_text, const tString & text_to_search ) {
01519 int m = strlen(search_for_text);
01520 int n = strlen(text_to_search);
01521 int a, b;
01522 for (b=0; b<=n-m; ++b) {
01523 for (a=0; a<m && search_for_text[a] == text_to_search[a+b]; ++a)
01524 ;
01525 if (a>=m)
01526
01527 return true;
01528 }
01529 return false;
01530 }
01531
01532
01533 typedef tString const & (ePlayerNetID::*SE_NameGetter)() const;
01534
01535
01536 typedef tString (*SE_NameFilter)( tString const & );
01537
01538
01539 static tString se_NameFilterID( tString const & name )
01540 {
01541 return name;
01542 }
01543
01544
01545 typedef bool (*SE_NameHider)( ePlayerNetID const * hider, ePlayerNetID const * seeker );
01546
01547
01548 static bool se_NonHide( ePlayerNetID const * hider, ePlayerNetID const * seeker )
01549 {
01550 return false;
01551 }
01552
01553
01554
01555
01556 ePlayerNetID * CompareBufferToPlayerNames
01557 ( const tString & nameRaw,
01558 int & num_matches,
01559 ePlayerNetID * requester,
01560 SE_NameGetter GetName,
01561 SE_NameFilter Filter,
01562 SE_NameHider Hider )
01563 {
01564 num_matches = 0;
01565 ePlayerNetID * match = 0;
01566
01567
01568 tString name = (*Filter)( nameRaw );
01569
01570
01571 for ( int a = se_PlayerNetIDs.Len()-1; a>=0; --a ) {
01572 ePlayerNetID* toMessage = se_PlayerNetIDs(a);
01573
01574 if ( (*Hider)( toMessage, requester ) )
01575 {
01576 continue;
01577 }
01578
01579 tString playerName = (*Filter)( (toMessage->*GetName)() );
01580
01581
01582 if ( playerName == name )
01583 {
01584 num_matches = 1;
01585 return toMessage;
01586 }
01587
01588 if ( Contains(name, playerName)) {
01589 match= toMessage;
01590 num_matches+=1;
01591 }
01592 }
01593
01594
01595 return match;
01596 }
01597
01598
01599 ePlayerNetID * ePlayerNetID::FindPlayerByName( tString const & name, ePlayerNetID * requester )
01600 {
01601 int num_matches = 0;
01602
01603
01604 ePlayerNetID * ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetName, &se_NameFilterID, &se_NonHide );
01605 if ( ret && num_matches == 1 )
01606 {
01607 return ret;
01608 }
01609
01610
01611 SE_NameFilter Filter = &ePlayerNetID::FilterName;
01612
01613
01614 if ( !ret )
01615 {
01616 ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetName, Filter, &se_NonHide );
01617 }
01618 if ( ret && num_matches == 1 )
01619 {
01620 return ret;
01621 }
01622
01623 #ifdef KRAWALL_SERVER
01624
01625 if ( !ret )
01626 {
01627 ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetUserName, &se_NameFilterID, &se_Hide );
01628 }
01629 if ( ret && num_matches == 1 )
01630 {
01631 return ret;
01632 }
01633
01634
01635 if ( !ret )
01636 {
01637 ret = CompareBufferToPlayerNames( name, num_matches, requester, &ePlayerNetID::GetUserName, Filter, &se_Hide );
01638 }
01639 if ( ret && num_matches == 1 )
01640 {
01641 return ret;
01642 }
01643 #endif
01644
01645
01646 else if (num_matches > 1) {
01647 tOutput toSender( "$msg_toomanymatches", name );
01648 if ( requester )
01649 {
01650 sn_ConsoleOut(toSender,requester->Owner() );
01651 }
01652 else
01653 {
01654 con << toSender;
01655 }
01656 return NULL;
01657 }
01658
01659 else {
01660 tOutput toSender( "$msg_nomatch", name );
01661 if ( requester )
01662 {
01663 sn_ConsoleOut(toSender,requester->Owner() );
01664 }
01665 else
01666 {
01667 con << toSender;
01668 }
01669 return NULL;
01670 }
01671
01672 return 0;
01673 }
01674
01675 static ePlayerNetID * se_FindPlayerInChatCommand( ePlayerNetID * sender, char const * command, std::istream & s )
01676 {
01677 tString player;
01678 s >> player;
01679
01680 if (player == "" )
01681 {
01682 sn_ConsoleOut( tOutput( "$chatcommand_requires_player", command ), sender->Owner() );
01683 return 0;
01684 }
01685
01686 return ePlayerNetID::FindPlayerByName( player, sender );
01687 }
01688
01689
01690 void handle_chat_client( nMessage & );
01691 static nDescriptor chat_handler_client(203,handle_chat_client,"Chat Client");
01692
01693 void handle_chat_client(nMessage &m)
01694 {
01695 if(sn_GetNetState()!=nSERVER)
01696 {
01697 unsigned short id;
01698 m.Read(id);
01699 tColoredString say;
01700 m >> say;
01701
01702 tJUST_CONTROLLED_PTR< ePlayerNetID > p=dynamic_cast<ePlayerNetID *>(nNetObject::ObjectDangerous(id));
01703
01704 se_DisplayChatLocallyClient( p, say );
01705 }
01706 }
01707
01708
01709 template< class TARGET >
01710 void se_AppendChat( TARGET & out, tString const & message )
01711 {
01712 if ( message.Len() <= se_SpamMaxLen*2 )
01713 out << message;
01714 else
01715 {
01716 tString cut( message );
01717 cut.SetLen( se_SpamMaxLen*2 );
01718 out << cut;
01719 }
01720 }
01721
01722
01723 static tColoredString se_BuildChatString( ePlayerNetID const * sender, tString const & message )
01724 {
01725 tColoredString console;
01726 console << *sender;
01727 console << tColoredString::ColorString(1,1,.5) << ": ";
01728 se_AppendChat( console, message );
01729
01730 return console;
01731 }
01732
01733
01734 static tColoredString se_BuildChatString( eTeam const *team, ePlayerNetID const *sender, tString const &message )
01735 {
01736 tColoredString console;
01737 console << *sender;
01738
01739 if( !sender->CurrentTeam() )
01740 {
01741
01742 console << tColoredString::ColorString(1,1,.5) << " --> " << tOutput("$player_spectator_message");
01743 }
01744 else if (sender->CurrentTeam() == team)
01745 {
01746
01747 console << tColoredString::ColorString(1,1,.5) << " --> ";
01748 console << tColoredString::ColorString(team->R(),team->G(),team->B()) << tOutput("$player_team_message");
01749 }
01750 else {
01751
01752 eTeam *senderTeam = sender->CurrentTeam();
01753 console << tColoredString::ColorString(1,1,.5) << " (";
01754 console << tColoredString::ColorString(senderTeam->R(),senderTeam->G(),senderTeam->B()) << senderTeam->Name();
01755 console << tColoredString::ColorString(1,1,.5) << ") --> ";
01756 console << tColoredString::ColorString(team->R(),team->G(),team->B()) << team->Name();
01757 }
01758
01759 console << tColoredString::ColorString(1,1,.5) << ": ";
01760 se_AppendChat( console, message );
01761
01762 return console;
01763 }
01764
01765
01766 static tColoredString se_BuildChatString( ePlayerNetID const * sender, ePlayerNetID const * receiver, tString const & message )
01767 {
01768 tColoredString console;
01769 console << *sender;
01770 console << tColoredString::ColorString(1,1,.5) << " --> ";
01771 console << *receiver;
01772 console << tColoredString::ColorString(1,1,.5) << ": ";
01773 se_AppendChat( console, message );
01774
01775 return console;
01776 }
01777
01778
01779 static nMessage* se_ServerControlledChatMessageConsole( ePlayerNetID const * player, tString const & toConsole )
01780 {
01781 tASSERT( player );
01782
01783 nMessage *m=tNEW(nMessage) (chat_handler_client);
01784
01785 m->Write( player->ID() );
01786 *m << toConsole;
01787
01788 return m;
01789 }
01790
01791
01792 static nMessage* se_ServerControlledChatMessage( ePlayerNetID const * sender, tString const & message )
01793 {
01794 tASSERT( sender );
01795
01796 return se_ServerControlledChatMessageConsole( sender, se_BuildChatString( sender, message ) );
01797 }
01798
01799
01800 static nMessage* se_ServerControlledChatMessage( ePlayerNetID const * sender, ePlayerNetID const * receiver, tString const & message )
01801 {
01802 tASSERT( sender );
01803 tASSERT( receiver );
01804
01805 return se_ServerControlledChatMessageConsole( sender, se_BuildChatString( sender, receiver, message ) );
01806 }
01807
01808
01809 static nMessage* se_ServerControlledChatMessage( eTeam const * team, ePlayerNetID const * sender, tString const & message )
01810 {
01811 tASSERT( sender );
01812
01813 return se_ServerControlledChatMessageConsole( sender, se_BuildChatString(team, sender, message) );
01814 }
01815
01816
01817 static nMessage* se_NewChatMessage( ePlayerNetID const * player, tString const & message )
01818 {
01819 tASSERT( player );
01820
01821 nMessage *m=tNEW(nMessage) (chat_handler);
01822 m->Write( player->ID() );
01823 se_AppendChat( *m, message );
01824
01825 return m;
01826 }
01827
01828
01829 static nMessage* se_OldChatMessage( tString const & line )
01830 {
01831 return sn_ConsoleOutMessage( line + "\n" );
01832 }
01833
01834
01835 static nMessage* se_OldChatMessage( ePlayerNetID const * player, tString const & message )
01836 {
01837 tASSERT( player );
01838
01839 return se_OldChatMessage( se_BuildChatString( player, message ) );
01840 }
01841
01842
01843
01844 void se_BroadcastChat( ePlayerNetID* p, const tString& say )
01845 {
01846
01847 tJUST_CONTROLLED_PTR< nMessage > mServerControlled = se_ServerControlledChatMessage( p, say );
01848 tJUST_CONTROLLED_PTR< nMessage > mNew = se_NewChatMessage( p, say );
01849 tJUST_CONTROLLED_PTR< nMessage > mOld = se_OldChatMessage( p, say );
01850
01851
01852 for ( int user = MAXCLIENTS; user > 0; --user )
01853 {
01854 if ( sn_Connections[ user ].socket )
01855 {
01856 if ( se_chatHandlerClient.Supported( user ) )
01857 mServerControlled->Send( user );
01858 else if ( se_chatRelay.Supported( user ) )
01859 mNew->Send( user );
01860 else
01861 mOld->Send( user );
01862 }
01863 }
01864 }
01865
01866
01867
01868 void se_BroadcastChatLine( ePlayerNetID* p, const tString& line, const tString& forOldClients )
01869 {
01870
01871 tJUST_CONTROLLED_PTR< nMessage > mServerControlled = se_ServerControlledChatMessageConsole( p, line );
01872 tJUST_CONTROLLED_PTR< nMessage > mNew = se_NewChatMessage( p, forOldClients );
01873 tJUST_CONTROLLED_PTR< nMessage > mOld = se_OldChatMessage( line );
01874
01875
01876 for ( int user = MAXCLIENTS; user > 0; --user )
01877 {
01878 if ( sn_Connections[ user ].socket )
01879 {
01880 if ( se_chatHandlerClient.Supported( user ) )
01881 mServerControlled->Send( user );
01882 else if ( se_chatRelay.Supported( user ) )
01883 mNew->Send( user );
01884 else
01885 mOld->Send( user );
01886 }
01887 }
01888 }
01889
01890
01891 void se_SendPrivateMessage( ePlayerNetID const * sender, ePlayerNetID const * receiver, ePlayerNetID const * eavesdropper, tString const & message )
01892 {
01893 tASSERT( sender );
01894 tASSERT( receiver );
01895
01896
01897 int cid = eavesdropper->Owner();
01898
01899
01900 if ( se_chatHandlerClient.Supported( cid ) )
01901 {
01902
01903 se_ServerControlledChatMessage( sender, receiver, message )->Send( cid );
01904 }
01905 else
01906 {
01907 tColoredString say;
01908 say << tColoredString::ColorString(1,1,.5) << "( --> ";
01909 say << *receiver;
01910 say << tColoredString::ColorString(1,1,.5) << " ) ";
01911 say << message;
01912
01913
01914 if ( se_chatRelay.Supported( cid ) )
01915 {
01916
01917 se_NewChatMessage( sender, say )->Send( cid );
01918 }
01919 else
01920 {
01921
01922 se_OldChatMessage( sender, say )->Send( cid );
01923 }
01924 }
01925 }
01926
01927
01928 void se_SendTeamMessage( eTeam const * team, ePlayerNetID const * sender ,ePlayerNetID const * receiver, tString const & message )
01929 {
01930 tASSERT( receiver );
01931 tASSERT( sender );
01932
01933 int clientID = receiver->Owner();
01934 if ( clientID == 0 )
01935 return;
01936
01937 if ( se_chatHandlerClient.Supported( clientID ) ) {
01938 se_ServerControlledChatMessage( team, sender, message )->Send( clientID );
01939 }
01940 else {
01941 tColoredString say;
01942 say << tColoredString::ColorString(1,1,.5) << "( " << *sender;
01943
01944 if( !sender->CurrentTeam() )
01945 {
01946
01947 say << tColoredString::ColorString(1,1,.5) << " --> " << tOutput("$player_spectator_message");
01948 }
01949 else if (sender->CurrentTeam() == team) {
01950
01951 say << tColoredString::ColorString(1,1,.5) << " --> ";
01952 say << tColoredString::ColorString(team->R(),team->G(),team->B()) << tOutput("$player_team_message");;
01953 }
01954
01955 else {
01956 eTeam *senderTeam = sender->CurrentTeam();
01957 say << tColoredString::ColorString(1,1,.5) << " (";
01958 say << tColoredString::ColorString(team->R(),team->G(),team->B()) << team->Name();
01959 say << tColoredString::ColorString(1,1,.5) << " ) --> ";
01960 say << tColoredString::ColorString(senderTeam->R(),senderTeam->G(),senderTeam->B()) << senderTeam->Name();
01961 }
01962 say << tColoredString::ColorString(1,1,.5) << " ) ";
01963 say << message;
01964
01965
01966 if ( se_chatRelay.Supported( clientID ) )
01967
01968 se_NewChatMessage( sender, say )->Send( clientID );
01969 else
01970
01971 se_OldChatMessage( sender, say )->Send( clientID );
01972 }
01973 }
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994 ePlayerNetID * se_GetAlivePlayerFromUserID( int uid )
01995 {
01996
01997 for ( int a = se_PlayerNetIDs.Len()-1; a>=0; --a )
01998 {
01999 ePlayerNetID * p = se_PlayerNetIDs(a);
02000 if ( p && p->Owner() == uid &&
02001 ( ( p->Object() && p->Object()->Alive() ) ) )
02002 return p;
02003 }
02004
02005
02006 return 0;
02007 }
02008
02009
02010 static tString sg_adminPass( "NONE" );
02011 static tConfItemLine sg_adminPassConf( "ADMIN_PASS", sg_adminPass );
02012
02013 #ifdef DEDICATED
02014
02015
02016 class eAdminConsoleFilter:public tConsoleFilter{
02017 public:
02018 eAdminConsoleFilter( int netID )
02019 :netID_( netID )
02020 {
02021 }
02022
02023 ~eAdminConsoleFilter()
02024 {
02025 sn_ConsoleOut( message_, netID_ );
02026 }
02027 private:
02028
02029 virtual int DoGetPriority() const{ return -100; }
02030
02031
02032 virtual void DoFilterLine( tString &line )
02033 {
02034
02035 message_ << tColoredString::ColorString(1,.3,.3) << "RA: " << tColoredString::ColorString(1,1,1) << line << "\n";
02036
02037
02038 if (message_.Len() > 600)
02039 {
02040 sn_ConsoleOut( message_, netID_ );
02041 message_.Clear();
02042 }
02043 }
02044
02045 int netID_;
02046 tColoredString message_;
02047 };
02048
02049 static tString se_InterceptCommands;
02050 static tConfItemLine se_InterceptCommandsConf( "INTERCEPT_COMMANDS", se_InterceptCommands );
02051
02052 static bool se_interceptUnknownCommands = false;
02053 static tSettingItem<bool> se_interceptUnknownCommandsConf("INTERCEPT_UNKNOWN_COMMANDS",
02054 se_interceptUnknownCommands);
02055
02056
02057 static tAccessLevel se_adminAccessLevel = tAccessLevel_Moderator;
02058 static tSettingItem< tAccessLevel > se_adminAccessLevelConf( "ACCESS_LEVEL_ADMIN", se_adminAccessLevel );
02059
02060 void handle_command_intercept(ePlayerNetID *p, tString say) {
02061 con << "[cmd] " << *p << ": " << say << '\n';
02062 }
02063
02064 #ifdef KRAWALL_SERVER
02065
02066
02067 static tAccessLevel se_opAccessLevel = tAccessLevel_TeamLeader;
02068 static tSettingItem< tAccessLevel > se_opAccessLevelConf( "ACCESS_LEVEL_OP", se_opAccessLevel );
02069
02070
02071 static tAccessLevel se_opAccessLevelMax = tAccessLevel_Moderator;
02072 static tSettingItem< tAccessLevel > se_opAccessLevelMaxConf( "ACCESS_LEVEL_OP_MAX", se_opAccessLevelMax );
02073
02074
02075 typedef void (*OPFUNC)( ePlayerNetID * admin, ePlayerNetID * victim, int level );
02076 static void se_ChangeAccess( ePlayerNetID * admin, std::istream & s, char const * command, OPFUNC F )
02077 {
02078 if ( admin->GetAccessLevel() <= se_opAccessLevel )
02079 {
02080 ePlayerNetID * victim = se_FindPlayerInChatCommand( admin, command, s );
02081 if ( victim )
02082 {
02083 if ( victim == admin )
02084 {
02085 sn_ConsoleOut( tOutput( "$access_level_op_self", command ), admin->Owner() );
02086 }
02087 else if ( victim->GetAccessLevel() < admin->GetAccessLevel() )
02088 {
02089 sn_ConsoleOut( tOutput( "$access_level_op_overpowered", command ), admin->Owner() );
02090 }
02091 else
02092 {
02093
02094 int level = 1;
02095 s >> level;
02096
02097 (*F)( admin, victim, static_cast< tAccessLevel >( level ) );
02098 }
02099 }
02100 }
02101 else
02102 {
02103 sn_ConsoleOut( tOutput( "$access_level_op_denied", command ), admin->Owner() );
02104 }
02105 }
02106
02107
02108 void se_OpBase( ePlayerNetID * admin, ePlayerNetID * victim, char const * command, int accessLevel )
02109 {
02110 tString authName = victim->GetUserName() + "@L_OP";
02111 if ( victim->IsAuthenticated() )
02112 {
02113 authName = victim->GetRawAuthenticatedName();
02114 }
02115
02116 if ( accessLevel < se_opAccessLevelMax )
02117 accessLevel = se_opAccessLevelMax;
02118
02119
02120 if ( !victim->IsHuman() )
02121 {
02122 sn_ConsoleOut( tOutput( "$access_level_op_denied_ai", command ), admin->Owner() );
02123 }
02124
02125 if ( accessLevel > admin->GetAccessLevel() )
02126 {
02127 victim->Authenticate( authName, static_cast< tAccessLevel >( accessLevel ), admin );
02128 }
02129 else
02130 {
02131 sn_ConsoleOut( tOutput( "$access_level_op_denied_max", command ), admin->Owner() );
02132 }
02133 }
02134
02135 void se_Op( ePlayerNetID * admin, ePlayerNetID * victim, int level )
02136 {
02137 int accessLevel = admin->GetAccessLevel() + 1;
02138
02139
02140 if ( accessLevel < level )
02141 {
02142 accessLevel = level;
02143 }
02144
02145 se_OpBase( admin, victim, "/op", accessLevel );
02146 }
02147
02148
02149 void se_DeOp( ePlayerNetID * admin, ePlayerNetID * victim, int )
02150 {
02151 if ( victim->IsAuthenticated() )
02152 {
02153 victim->DeAuthenticate( admin );
02154 }
02155 }
02156
02157 void se_Demote( ePlayerNetID * admin, ePlayerNetID * victim, int level );
02158
02159
02160 void se_Promote( ePlayerNetID * admin, ePlayerNetID * victim, int level )
02161 {
02162 if ( level < 0 )
02163 {
02164 se_Demote( admin, victim, -level );
02165 return;
02166 }
02167
02168 int accessLevelInt = victim->GetAccessLevel() - level;
02169 tAccessLevel accessLevel = static_cast< tAccessLevel >( accessLevelInt );
02170 if ( accessLevel > tAccessLevel_Authenticated )
02171 {
02172 accessLevel = tAccessLevel_Authenticated;
02173 }
02174 if ( accessLevel < tCurrentAccessLevel::GetAccessLevel() + 1 )
02175 {
02176 accessLevel = static_cast< tAccessLevel >( tCurrentAccessLevel::GetAccessLevel() + 1 );
02177 }
02178
02179 if ( victim->IsAuthenticated() )
02180 {
02181 victim->SetAccessLevel( accessLevel );
02182
02183 se_SecretConsoleOut( tOutput( "$access_level_promote",
02184 victim->GetLogName(),
02185 tCurrentAccessLevel::GetName( accessLevel ),
02186 admin->GetLogName() ), victim, admin );
02187 }
02188 else
02189 {
02190 se_OpBase( admin, victim, "/promote", accessLevel );
02191 }
02192 }
02193
02194
02195 void se_Demote( ePlayerNetID * admin, ePlayerNetID * victim, int level )
02196 {
02197
02198 if ( level < 0 )
02199 {
02200 se_Promote( admin, victim, -level );
02201 return;
02202 }
02203
02204 int accessLevelInt = victim->GetAccessLevel() + level;
02205 tAccessLevel accessLevel = static_cast< tAccessLevel >( accessLevelInt );
02206
02207 if ( accessLevel <= tAccessLevel_Authenticated )
02208 {
02209 se_SecretConsoleOut( tOutput( "$access_level_demote",
02210 victim->GetLogName(),
02211 tCurrentAccessLevel::GetName( accessLevel ),
02212 admin->GetLogName() ), victim, admin );
02213
02214 victim->SetAccessLevel( accessLevel );
02215 }
02216 else if ( victim->IsAuthenticated() )
02217 {
02218 victim->DeAuthenticate( admin );
02219 }
02220 }
02221
02222
02223 static tAccessLevel se_teamAccessLevel = tAccessLevel_TeamLeader;
02224 static tSettingItem< tAccessLevel > se_teamAccessLevelConf( "ACCESS_LEVEL_TEAM", se_teamAccessLevel );
02225
02226
02227 static eTeam * se_GetManagedTeam( ePlayerNetID * admin )
02228 {
02229
02230 eTeam * team = admin->CurrentTeam();
02231 ePlayerNetID::eTeamSet const & invitations = admin->GetInvitations();
02232
02233
02234
02235 if ( !team && invitations.size() == 1 )
02236 {
02237 team = *invitations.begin();
02238 }
02239
02240 return team;
02241 }
02242
02243
02244 static bool se_CanManageTeam( ePlayerNetID * admin, bool emergency )
02245 {
02246
02247 if ( admin->GetAccessLevel() <= se_teamAccessLevel )
02248 {
02249 return true;
02250 }
02251
02252
02253 if ( !emergency )
02254 {
02255 return false;
02256 }
02257
02258
02259
02260
02261
02262
02263 eTeam * team = admin->CurrentTeam();
02264 if ( !team )
02265 {
02266 return false;
02267 }
02268
02269
02270 for( int i = team->NumPlayers()-1; i >= 0; --i )
02271 {
02272 ePlayerNetID * otherPlayer = team->Player(i);
02273 if ( otherPlayer->IsHuman() && otherPlayer->GetAccessLevel() < admin->GetAccessLevel() )
02274 {
02275 return false;
02276 }
02277 }
02278
02279 return true;
02280 }
02281
02282
02283 typedef void (eTeam::*INVITE)( ePlayerNetID * victim );
02284 static void se_Invite( char const * command, ePlayerNetID * admin, std::istream & s, INVITE invite )
02285 {
02286 if ( se_CanManageTeam( admin, invite == &eTeam::Invite ) )
02287 {
02288
02289 eTeam * team = se_GetManagedTeam( admin );
02290
02291 if ( team )
02292 {
02293 ePlayerNetID * victim = se_FindPlayerInChatCommand( admin, command, s );
02294 if ( victim )
02295 {
02296
02297 (team->*invite)( victim );
02298 }
02299 }
02300 else
02301 {
02302 sn_ConsoleOut( tOutput( "$invite_no_team", command ), admin->Owner() );
02303 }
02304 }
02305 else
02306 {
02307 sn_ConsoleOut( tOutput( "$access_level_op_denied", command ), admin->Owner() );
02308 }
02309 }
02310
02311
02312 static void se_Lock( char const * command, ePlayerNetID * admin, std::istream & s, bool lock )
02313 {
02314 if ( se_CanManageTeam( admin, !lock ) )
02315 {
02316
02317 eTeam * team = se_GetManagedTeam( admin );
02318
02319 if ( team )
02320 {
02321 team->SetLocked( lock );
02322 }
02323 else
02324 {
02325 sn_ConsoleOut( tOutput( "$invite_no_team", command ), admin->Owner() );
02326 }
02327 }
02328 else
02329 {
02330 sn_ConsoleOut( tOutput( "$access_level_op_denied", command ), admin->Owner() );
02331 }
02332 }
02333
02334 #else // KRAWALL
02335
02336 static eTeam * se_GetManagedTeam( ePlayerNetID * admin )
02337 {
02338 return admin->CurrentTeam();
02339 }
02340 #endif // KRAWALL
02341
02342
02343
02344
02345 static void se_AdminLogin_ReallyOnlyCallFromChatKTHNXBYE( ePlayerNetID * p, std::istream & s )
02346 {
02347 tString params("");
02348 params.ReadLine( s );
02349 #ifndef KRAWALL_SERVER
02350 if ( params == "" )
02351 return;
02352 #endif
02353
02354
02355
02356
02357
02358
02359 {
02360 int lastNonSpace = params.Len() - 2;
02361 while ( lastNonSpace >= 0 && isblank(params[lastNonSpace]) )
02362 {
02363 --lastNonSpace;
02364 }
02365
02366 if ( lastNonSpace < params.Len() - 2 )
02367 {
02368 params = params.SubStr( 0, lastNonSpace + 1 );
02369 }
02370 }
02371
02372 #ifndef KRAWALL_SERVER
02373
02374
02375 bool accept = true;
02376 static const char * section = "REMOTE_LOGIN";
02377 if ( !tRecorder::Playback( section, accept ) )
02378 accept = ( params == sg_adminPass && sg_adminPass != "NONE" );
02379 tRecorder::Record( section, accept );
02380
02381
02382
02383 if ( accept ) {
02384
02385
02386 se_AdminLogin_ReallyOnlyCallFromChatKTHNXBYE( p );
02387 }
02388 else
02389 {
02390 tString failedLogin;
02391 sn_ConsoleOut("Login denied!\n",p->Owner());
02392 failedLogin << "Remote admin login for user \"" << p->GetUserName();
02393 failedLogin << "\" using password \"" << params << "\" rejected.\n";
02394 sn_ConsoleOut(failedLogin, 0);
02395 }
02396 #else
02397 if ( sn_GetNetState() == nSERVER && p->Owner() != sn_myNetID )
02398 {
02399 if ( p->IsAuthenticated() )
02400 {
02401 sn_ConsoleOut( "$login_request_redundant", p->Owner() );
02402 return;
02403 }
02404
02405 if ( p->GetRawAuthenticatedName().Len() <= 1 || params.StrPos("@") >= 0 )
02406 {
02407 if ( params.StrPos( "@" ) >= 0 )
02408 {
02409 p->SetRawAuthenticatedName( params );
02410 }
02411 else
02412 {
02413 p->SetRawAuthenticatedName( p->GetUserName() + "@" + params );
02414 }
02415 }
02416
02417
02418 if ( se_IsUserBanned( p, p->GetRawAuthenticatedName() ) )
02419 {
02420 return;
02421 }
02422
02423 p->loginWanted = true;
02424
02425 se_RequestLogin( p );
02426 }
02427 #endif
02428 }
02429
02430
02431 static void se_AdminLogout( ePlayerNetID * p )
02432 {
02433 #ifdef KRAWALL_SERVER
02434
02435 if ( p->IsAuthenticated() )
02436 {
02437 p->DeAuthenticate();
02438 }
02439 #else
02440 if ( p->IsLoggedIn() )
02441 {
02442 sn_ConsoleOut("You have been logged out!\n",p->Owner());
02443 }
02444 p->BeNotLoggedIn();
02445 #endif
02446 }
02447
02448
02449 static void se_AdminAdmin( ePlayerNetID * p, std::istream & s )
02450 {
02451 if ( p->GetAccessLevel() > se_adminAccessLevel )
02452 {
02453 sn_ConsoleOut( tOutput( "$access_level_admin_denied" ), p->Owner() );
02454 return;
02455 }
02456
02457 tString str;
02458 str.ReadLine(s);
02459 con << "Remote admin command by " << *p << "0xRESETT: " << str << "\n";
02460 std::istringstream stream(&str(0));
02461
02462
02463 eAdminConsoleFilter consoleFilter( p->Owner() );
02464
02465 if ( tRecorder::IsPlayingBack() )
02466 {
02467 tConfItemBase::LoadPlayback();
02468 }
02469 else
02470 {
02471 tConfItemBase::LoadLine(stream);
02472 }
02473 }
02474
02475 static void handle_chat_admin_commands( ePlayerNetID * p, tString const & command, tString const & say, std::istream & s )
02476 {
02477 if (command == "/login")
02478 {
02479
02480
02481 se_AdminLogin_ReallyOnlyCallFromChatKTHNXBYE( p, s );
02482 }
02483 else if (command == "/logout")
02484 {
02485 se_AdminLogout( p );
02486 }
02487 #ifdef KRAWALL_SERVER
02488 else if ( command == "/op" )
02489 {
02490 se_ChangeAccess( p, s, "/op", &se_Op );
02491 }
02492 else if ( command == "/deop" )
02493 {
02494 se_ChangeAccess( p, s, "/deop", &se_DeOp );
02495 }
02496 else if ( command == "/promote" )
02497 {
02498 se_ChangeAccess( p, s, "/promote", &se_Promote );
02499 }
02500 else if ( command == "/demote" )
02501 {
02502 se_ChangeAccess( p, s, "/demote", &se_Demote );
02503 }
02504 else if ( command == "/invite" )
02505 {
02506 se_Invite( command, p, s, &eTeam::Invite );
02507 }
02508 else if ( command == "/uninvite" )
02509 {
02510 se_Invite( command, p, s, &eTeam::UnInvite );
02511 }
02512 else if ( command == "/lock" )
02513 {
02514 se_Lock( command, p, s, true );
02515 }
02516 else if ( command == "/unlock" )
02517 {
02518 se_Lock( command, p, s, false );
02519 }
02520 #endif
02521 else if ( command == "/admin" )
02522 {
02523 se_AdminAdmin( p, s );
02524 }
02525 else
02526 if (se_interceptUnknownCommands)
02527 {
02528 handle_command_intercept(p, say);
02529 }
02530 else
02531 {
02532 sn_ConsoleOut( tOutput( "$chat_command_unknown", command ), p->Owner() );
02533 }
02534 }
02535 #else // DEDICATED
02536
02537 static eTeam * se_GetManagedTeam( ePlayerNetID * admin )
02538 {
02539 return admin->CurrentTeam();
02540 }
02541 #endif // DEDICATED
02542
02543
02544 static REAL se_alreadySaidTimeout=5.0;
02545 static tSettingItem<REAL> se_alreadySaidTimeoutConf("SPAM_PROTECTION_REPEAT",
02546 se_alreadySaidTimeout);
02547
02548 #ifndef KRAWALL_SERVER
02549
02550 static bool se_allowShuffleUp=false;
02551 static tSettingItem<bool> se_allowShuffleUpConf("TEAM_ALLOW_SHUFFLE_UP",
02552 se_allowShuffleUp);
02553 #else
02554 static tAccessLevel se_shuffleUpAccessLevel = tAccessLevel_TeamMember;
02555 static tSettingItem< tAccessLevel > se_shuffleUpAccessLevelConf( "ACCESS_LEVEL_SHUFFLE_UP", se_shuffleUpAccessLevel );
02556 #endif
02557
02558
02559 static tString se_helpMessage("");
02560 static tConfItemLine se_helpMessageConf("HELP_MESSAGE",se_helpMessage);
02561
02562 static bool se_silenceAll = false;
02563
02564
02565 static tAccessLevel se_chatAccessLevel = tAccessLevel_Program;
02566 static tSettingItem< tAccessLevel > se_chatAccessLevelConf( "ACCESS_LEVEL_CHAT", se_chatAccessLevel );
02567
02568
02569 REAL se_chatRequestTimeout = 60;
02570 static tSettingItem< REAL > se_chatRequestTimeoutConf( "ACCESS_LEVEL_CHAT_TIMEOUT", se_chatRequestTimeout );
02571
02572
02573 static tAccessLevel se_teamSpyAccessLevel = tAccessLevel_Moderator;
02574 static tSettingItem< tAccessLevel > se_teamSpyAccessLevelConf( "ACCESS_LEVEL_SPY_TEAM", se_teamSpyAccessLevel );
02575
02576
02577 static tAccessLevel se_msgSpyAccessLevel = tAccessLevel_Owner;
02578 static tSettingItem< tAccessLevel > se_msgSpyAccessLevelConf( "ACCESS_LEVEL_SPY_MSG", se_msgSpyAccessLevel );
02579
02580
02581 static tAccessLevel se_ipAccessLevel = tAccessLevel_Moderator;
02582 static tSettingItem< tAccessLevel > se_ipAccessLevelConf( "ACCESS_LEVEL_IPS", se_ipAccessLevel );
02583
02584 static tSettingItem<bool> se_silAll("SILENCE_ALL",
02585 se_silenceAll);
02586
02587
02588 class eChatSpamTester
02589 {
02590 public:
02591 eChatSpamTester( ePlayerNetID * p, tString const & say )
02592 : tested_( false ), shouldBlock_( false ), player_( p ), say_( say )
02593 {
02594 }
02595
02596 bool Block()
02597 {
02598 if ( !tested_ )
02599 {
02600 shouldBlock_ = Check();
02601 tested_ = true;
02602 }
02603
02604 return shouldBlock_;
02605 }
02606
02607 bool Check()
02608 {
02609 nTimeRolling currentTime = tSysTimeFloat();
02610
02611
02612 for (short c = 0; c < player_->lastSaid.Len(); c++)
02613 {
02614 if( (say_.StripWhitespace() == player_->lastSaid[c].StripWhitespace()) && ( (currentTime - player_->lastSaidTimes[c]) < se_alreadySaidTimeout) )
02615 {
02616 sn_ConsoleOut( tOutput("$spam_protection_repeat", say_ ), player_->Owner() );
02617 return true;
02618 }
02619 }
02620
02621 REAL lengthMalus = say_.Len() / 20.0;
02622 if ( lengthMalus > 4.0 )
02623 {
02624 lengthMalus = 4.0;
02625 }
02626
02627 if ( nSpamProtection::Level_Mild <= player_->chatSpam_.CheckSpam( 1+lengthMalus, player_->Owner(), tOutput("$spam_chat") ) )
02628 {
02629 return true;
02630 }
02631
02632 #ifdef KRAWALL_SERVER
02633 if ( player_->GetAccessLevel() > se_chatAccessLevel )
02634 {
02635
02636 static double nextRequest = 0;
02637 double now = tSysTimeFloat();
02638 if ( now > nextRequest && se_chatRequestTimeout > 0 )
02639 {
02640 sn_ConsoleOut( tOutput("$access_level_chat_request", player_->GetColoredName(), player_->GetLogName() ), player_->Owner() );
02641 nextRequest = now + se_chatRequestTimeout;
02642 }
02643 else
02644 {
02645 sn_ConsoleOut( tOutput("$access_level_chat_denied" ), player_->Owner() );
02646 }
02647
02648 return true;
02649 }
02650 #endif
02651
02652
02653 {
02654 for( short zz = 12; zz>=1; zz-- )
02655 {
02656 player_->lastSaid[zz] = player_->lastSaid[zz-1];
02657 player_->lastSaidTimes[zz] = player_->lastSaidTimes[zz-1];
02658 }
02659
02660 player_->lastSaid[0] = say_;
02661 player_->lastSaidTimes[0] = currentTime;
02662 }
02663
02664 return false;
02665 }
02666
02667 bool tested_;
02668 bool shouldBlock_;
02669 ePlayerNetID * player_;
02670 tString say_;
02671 };
02672
02673
02674 bool IsSilencedWithWarning( ePlayerNetID const * p )
02675 {
02676 if ( !se_enableChat && ! p->IsLoggedIn() )
02677 {
02678
02679 sn_ConsoleOut( tOutput( "$spam_protection_silenceall" ), p->Owner() );
02680 return true;
02681 }
02682 else if ( p->IsSilenced() )
02683 {
02684 if(se_silenceAll) {
02685
02686 sn_ConsoleOut( tOutput( "$spam_protection_silenced_default" ), p->Owner() );
02687 } else {
02688
02689 sn_ConsoleOut( tOutput( "$spam_protection_silenced" ), p->Owner() );
02690 }
02691 return true;
02692 }
02693
02694 return false;
02695 }
02696
02697
02698 static void se_ChatMe( ePlayerNetID * p, std::istream & s, eChatSpamTester & spam )
02699 {
02700 if ( IsSilencedWithWarning(p) || spam.Block() )
02701 {
02702 return;
02703 }
02704
02705 tString msg;
02706 msg.ReadLine( s );
02707
02708 tColoredString console;
02709 console << tColoredString::ColorString(1,1,1) << "* ";
02710 console << *p;
02711 console << tColoredString::ColorString(1,1,.5) << " " << msg;
02712 console << tColoredString::ColorString(1,1,1) << " *";
02713
02714 tColoredString forOldClients;
02715 forOldClients << tColoredString::ColorString(1,1,1) << "*"
02716 << tColoredString::ColorString(1,1,.5) << msg
02717 << tColoredString::ColorString(1,1,1) << "*";
02718
02719 se_BroadcastChatLine( p, console, forOldClients );
02720 console << "\n";
02721 sn_ConsoleOut(console,0);
02722 return;
02723 }
02724
02725
02726 static void se_ChatTeamLeave( ePlayerNetID * p )
02727 {
02728 if ( se_assignTeamAutomatically )
02729 {
02730 sn_ConsoleOut(tOutput("$player_teamleave_disallowed"), p->Owner() );
02731 return;
02732 }
02733 if(!p->TeamChangeAllowed()) {
02734 sn_ConsoleOut(tOutput("$player_disallowed_teamchange"), p->Owner() );
02735 return;
02736 }
02737
02738 eTeam * leftTeam = p->NextTeam();
02739 if ( leftTeam )
02740 {
02741 if ( !leftTeam )
02742 leftTeam = p->CurrentTeam();
02743
02744 if ( leftTeam->NumPlayers() > 1 )
02745 {
02746 sn_ConsoleOut( tOutput( "$player_leave_team_wish",
02747 tColoredString::RemoveColors(p->GetName()),
02748 tColoredString::RemoveColors(leftTeam->Name()) ) );
02749 }
02750 else
02751 {
02752 sn_ConsoleOut( tOutput( "$player_leave_game_wish",
02753 tColoredString::RemoveColors(p->GetName()) ) );
02754 }
02755 }
02756
02757 p->SetTeamWish(0);
02758 }
02759
02760
02761 static void se_ChatTeam( ePlayerNetID * p, std::istream & s, eChatSpamTester & spam )
02762 {
02763 eTeam *currentTeam = se_GetManagedTeam( p );
02764
02765
02766 if ( ( !currentTeam && IsSilencedWithWarning(p) ) || spam.Block() )
02767 {
02768 return;
02769 }
02770
02771 tString msg;
02772 msg.ReadLine( s );
02773
02774
02775 tColoredString messageForServerAndSender = se_BuildChatString(currentTeam, p, msg);
02776 messageForServerAndSender << "\n";
02777
02778 if (currentTeam != NULL)
02779 {
02780 sn_ConsoleOut(messageForServerAndSender, 0);
02781 sn_ConsoleOut(messageForServerAndSender, p->Owner());
02782
02783
02784 int numTeamPlayers = currentTeam->NumPlayers();
02785 for (int teamPlayerIndex = 0; teamPlayerIndex < numTeamPlayers; teamPlayerIndex++) {
02786 if (currentTeam->Player(teamPlayerIndex)->Owner() != p->Owner())
02787 se_SendTeamMessage(currentTeam, p, currentTeam->Player(teamPlayerIndex), msg);
02788 }
02789
02790
02791 for( int i = se_PlayerNetIDs.Len() - 1; i >=0; --i )
02792 {
02793 ePlayerNetID * admin = se_PlayerNetIDs(i);
02794
02795 if (
02796
02797 se_GetManagedTeam( admin ) == 0 && admin != p &&
02798 (
02799
02800 admin->GetAccessLevel() <= se_teamSpyAccessLevel ||
02801
02802 currentTeam->IsInvited( admin )
02803 )
02804 )
02805 {
02806 se_SendTeamMessage(currentTeam, p, admin, msg);
02807 }
02808 }
02809 }
02810 else
02811 {
02812 sn_ConsoleOut(messageForServerAndSender, 0);
02813 sn_ConsoleOut(messageForServerAndSender, p->Owner());
02814
02815
02816 for( int i = se_PlayerNetIDs.Len() - 1; i >=0; --i )
02817 {
02818 ePlayerNetID * spectator = se_PlayerNetIDs(i);
02819
02820 if ( se_GetManagedTeam( spectator ) == 0 && spectator != p )
02821 {
02822 se_SendTeamMessage(currentTeam, p, spectator, msg);
02823 }
02824 }
02825 }
02826 }
02827
02828
02829 static void se_ChatMsg( ePlayerNetID * p, std::istream & s, eChatSpamTester & spam )
02830 {
02831
02832 if ( spam.Block() )
02833 {
02834 return;
02835 }
02836
02837
02838 ePlayerNetID * receiver = se_FindPlayerInChatCommand( p, "/msg", s );
02839
02840
02841 if ( receiver ) {
02842
02843 std::ws(s);
02844
02845
02846 tString msg_core;
02847 msg_core.ReadLine(s);
02848
02849
02850 tColoredString toServer = se_BuildChatString( p, receiver, msg_core );
02851 toServer << '\n';
02852
02853
02854 sn_ConsoleOut(toServer,0);
02855
02856 if ( p->CurrentTeam() == receiver->CurrentTeam() || !IsSilencedWithWarning(p) )
02857 {
02858
02859 sn_ConsoleOut(toServer, p->Owner());
02860
02861
02862 if ( p->Owner() != receiver->Owner() )
02863 se_SendPrivateMessage( p, receiver, receiver, msg_core );
02864 }
02865
02866
02867 for( int i = se_PlayerNetIDs.Len() - 1; i >=0; --i )
02868 {
02869 ePlayerNetID * admin = se_PlayerNetIDs(i);
02870
02871 if ( admin != receiver && admin != p && admin->GetAccessLevel() <= se_msgSpyAccessLevel )
02872 {
02873 se_SendPrivateMessage( p, receiver, admin, msg_core );
02874 }
02875 }
02876 }
02877 }
02878
02879 static void se_SendTo( std::string const & message, ePlayerNetID * receiver )
02880 {
02881 if ( receiver )
02882 {
02883 sn_ConsoleOut(message.c_str(), receiver->Owner());
02884 }
02885 else
02886 {
02887 con << message;
02888 }
02889 }
02890
02891
02892 static void se_SendTeamMember( ePlayerNetID const * player, int indent, std::ostream & tos )
02893 {
02894
02895 for( int i = indent-1; i >= 0; --i )
02896 {
02897 tos << ' ';
02898 }
02899
02900 tos << *player << "\n";
02901 }
02902
02903
02904 static void se_ListTeam( ePlayerNetID * receiver, eTeam * team )
02905 {
02906 std::ostringstream tos;
02907
02908
02909 tColoredString teamName;
02910 teamName << tColoredStringProxy( team->R()/15.0f, team->G()/15.0f, team->B()/15.0f ) << team->Name();
02911 tos << teamName << "0xRESETT";
02912 if ( team->IsLocked() )
02913 {
02914 tos << " " << tOutput( "$invite_team_locked_list" );
02915 }
02916 tos << ":\n";
02917
02918
02919 int teamMembers = team->NumPlayers();
02920
02921 int indent = 0;
02922
02923 for( int i = (teamMembers/2)*2-1; i>=0; i -= 2 )
02924 {
02925 se_SendTeamMember( team->Player(i), indent, tos );
02926 indent += 2;
02927 }
02928
02929 for( int i = 0; i < teamMembers; i += 2 )
02930 {
02931 se_SendTeamMember( team->Player(i), indent, tos );
02932 indent -= 2;
02933 }
02934
02935 tos << "\n";
02936
02937 se_SendTo( tos.str(), receiver );
02938 }
02939
02940 static void se_ListTeams( ePlayerNetID * receiver )
02941 {
02942 int numTeams = 0;
02943
02944 for ( int i = eTeam::teams.Len() - 1; i >= 0; --i )
02945 {
02946 eTeam * team = eTeam::teams[i];
02947 if ( team->NumPlayers() > 1 || team->IsLocked() )
02948 {
02949 numTeams++;
02950 se_ListTeam( receiver, team );
02951 }
02952 }
02953
02954 if ( numTeams == 0 )
02955 {
02956 se_SendTo( std::string( tString( tOutput("$no_real_teams") ) ), receiver );
02957 }
02958 }
02959
02960 static void teams_conf(std::istream &s)
02961 {
02962 se_ListTeams( 0 );
02963 }
02964
02965 static tConfItemFunc teams("TEAMS",&teams_conf);
02966
02967
02968 static void se_ChatTeams( ePlayerNetID * p )
02969 {
02970 se_ListTeams( p );
02971 }
02972
02973 static void se_ListPlayers( ePlayerNetID * receiver )
02974 {
02975 for ( int i2 = se_PlayerNetIDs.Len()-1; i2>=0; --i2 )
02976 {
02977 ePlayerNetID* p2 = se_PlayerNetIDs(i2);
02978 std::ostringstream tos;
02979 tos << p2->Owner();
02980 tos << ": ";
02981 if ( p2->GetAccessLevel() < tAccessLevel_Default && !se_Hide( p2, receiver ) )
02982 {
02983
02984
02985 tos << p2->GetFilteredAuthenticatedName() << " ( " << p2->GetName() << ", "
02986 << tCurrentAccessLevel::GetName( p2->GetAccessLevel() )
02987 << " )";
02988 }
02989 else
02990 {
02991 tos << p2->GetName();
02992 }
02993 if ( tCurrentAccessLevel::GetAccessLevel() <= se_ipAccessLevel )
02994 {
02995 tString IP = p2->GetMachine().GetIP();
02996 if ( IP.Len() > 1 )
02997 {
02998 tos << ", IP = " << IP;
02999 }
03000 }
03001 tos << "\n";
03002
03003 se_SendTo( tos.str(), receiver );
03004 }
03005 }
03006
03007 static void players_conf(std::istream &s)
03008 {
03009 se_ListPlayers( 0 );
03010 }
03011
03012 static tConfItemFunc players("PLAYERS",&players_conf);
03013
03014
03015 static void se_ChatPlayers( ePlayerNetID * p )
03016 {
03017 se_ListPlayers( p );
03018 }
03019
03020
03021 static void se_ChatShuffle( ePlayerNetID * p, std::istream & s )
03022 {
03023 tString msg;
03024 msg.ReadLine( s );
03025
03026
03027
03028
03029
03030
03031
03032 int IDNow = p->TeamListID();
03033 if (!p->CurrentTeam())
03034 {
03035 sn_ConsoleOut(tOutput("$player_not_on_team"), p->Owner());
03036 return;
03037 }
03038 int len = p->CurrentTeam()->NumPlayers();
03039 int IDWish = len-1;
03040
03041
03042 if (msg.Len() > 1)
03043 {
03044 IDWish = IDNow;
03045 if ( msg[0] == '+' )
03046 IDWish += msg.ToInt(1);
03047 else if ( msg[0] == '-' )
03048 IDWish -= msg.ToInt(1);
03049 else
03050 IDWish = msg.ToInt()-1;
03051 }
03052
03053 if (IDWish < 0)
03054 IDWish = 0;
03055 if (IDWish >= len)
03056 IDWish = len-1;
03057
03058 if(IDWish < IDNow)
03059 {
03060 #ifndef KRAWALL_SERVER
03061 if ( !se_allowShuffleUp )
03062 {
03063 sn_ConsoleOut(tOutput("$player_noshuffleup"), p->Owner());
03064 return;
03065 }
03066 #else
03067 if ( !p->GetAccessLevel() > se_shuffleUpAccessLevel )
03068 {
03069 sn_ConsoleOut(tOutput("$access_level_shuffle_up_denied"), p->Owner());
03070 return;
03071 }
03072 #endif
03073 }
03074
03075 if( IDNow == IDWish )
03076 {
03077 sn_ConsoleOut(tOutput("$player_noshuffle"), p->Owner());
03078 return;
03079 }
03080
03081 p->CurrentTeam()->Shuffle( IDNow, IDWish );
03082 se_ListTeam( p, p->CurrentTeam() );
03083 }
03084
03085 void handle_chat( nMessage &m )
03086 {
03087 nTimeRolling currentTime = tSysTimeFloat();
03088 unsigned short id;
03089 m.Read(id);
03090 tColoredString say;
03091 m >> say;
03092
03093 tJUST_CONTROLLED_PTR< ePlayerNetID > p=dynamic_cast<ePlayerNetID *>(nNetObject::ObjectDangerous(id));
03094
03095
03096 if ( p )
03097 p->lastActivity_ = currentTime;
03098
03099 if(sn_GetNetState()==nSERVER){
03100 if (p)
03101 {
03102
03103 tCurrentAccessLevel levelOverride( p->GetAccessLevel() );
03104
03105
03106 if( p->Owner() != m.SenderID() )
03107 {
03108 Cheater( m.SenderID() );
03109 nReadError();
03110 return;
03111 }
03112
03113 eChatSpamTester spam( p, say );
03114
03115 if (say.StartsWith("/")) {
03116 std::string sayStr(say);
03117 std::istringstream s(sayStr);
03118
03119 tString command;
03120 s >> command;
03121
03122
03123 tToLower( command );
03124
03125 tConfItemBase::EatWhitespace(s);
03126
03127
03128 #ifdef DEDICATED
03129 if (se_InterceptCommands.StrPos(command) != -1)
03130 {
03131 handle_command_intercept(p, say);
03132 return;
03133 }
03134 else
03135 #endif
03136 if (command == "/me") {
03137 se_ChatMe( p, s, spam );
03138 return;
03139 }
03140 else if (command == "/teamname") {
03141 tString msg;
03142 msg.ReadLine( s );
03143 p->SetTeamname(msg);
03144 return;
03145 }
03146 else if (command == "/teamleave") {
03147 se_ChatTeamLeave( p );
03148 return;
03149 }
03150 else if (command == "/teamleave" || command=="/spectate") {
03151 p->SetTeamWish(NULL);
03152 return;
03153 }
03154 else if (command == "/teamshuffle" || command == "/shuffle") {
03155 se_ChatShuffle( p, s );
03156 return;
03157 }
03158 else if (command == "/team")
03159 {
03160 se_ChatTeam( p, s, spam );
03161 return;
03162 }
03163 else if (command == "/msg" ) {
03164 se_ChatMsg( p, s, spam );
03165 return;
03166 }
03167 else if (command == "/help")
03168 {
03169 sn_ConsoleOut(se_helpMessage + "\n", p->Owner());
03170 se_DisplayChatLocally(p, say);
03171 return;
03172 }
03173 else if (command == "/players") {
03174 se_ChatPlayers( p );
03175 return;
03176 }
03177 else if (command == "/vote" || command == "/callvote") {
03178 eVoter::HandleChat( p, s );
03179 return;
03180 }
03181 else if (command == "/teams") {
03182 se_ChatTeams( p );
03183 return;
03184 }
03185 #ifdef DEDICATED
03186 else {
03187 handle_chat_admin_commands( p, command, say, s );
03188 return;
03189 }
03190 #endif
03191 }
03192
03193
03194 if ( spam.Block() )
03195 {
03196 return;
03197 }
03198
03199
03200 if ( say.Len() <= se_SpamMaxLen+2 && !IsSilencedWithWarning(p) )
03201 {
03202 se_BroadcastChat( p, say );
03203 se_DisplayChatLocally( p, say);
03204 }
03205 }
03206 }
03207 else
03208 {
03209 se_DisplayChatLocally( p, say );
03210 }
03211 }
03212
03213
03214
03215 static bool IsLegalPlayerName( tString const & name )
03216 {
03217
03218 tString stripped( tColoredString::RemoveColors( name ) );
03219
03220
03221 for ( int i = stripped.Len()-2; i>=0; --i )
03222 {
03223 if ( !isblank( stripped(i) ) )
03224 return true;
03225 }
03226
03227 return false;
03228 }
03229
03230 void ePlayerNetID::Chat(const tString &s_orig)
03231 {
03232 tColoredString s( s_orig );
03233 s.NetFilter();
03234
03235 switch (sn_GetNetState())
03236 {
03237 case nCLIENT:
03238 {
03239 if(s_orig.StartsWith("/console") ) {
03240 tString params("");
03241 if (s_orig.StrPos(" ") == -1)
03242 return;
03243 else
03244 params = s_orig.SubStr(s_orig.StrPos(" ") + 1);
03245
03246 if ( tRecorder::IsPlayingBack() )
03247 {
03248 tConfItemBase::LoadPlayback();
03249 }
03250 else
03251 {
03252 std::stringstream s(static_cast< char const * >( params ) );
03253 tConfItemBase::LoadAll(s);
03254 }
03255 std::cout << "console selected\n";
03256 } else
03257 se_NewChatMessage( this, s )->BroadCast();
03258 break;
03259 }
03260 case nSERVER:
03261 {
03262 se_BroadcastChat( this, s );
03263 }
03264 default:
03265 {
03266 if(s_orig.StartsWith("/console") ) {
03267 tString params("");
03268 if (s_orig.StrPos(" ") == -1)
03269 return;
03270 else
03271 params = s_orig.SubStr(s_orig.StrPos(" ") + 1);
03272
03273 if ( tRecorder::IsPlayingBack() )
03274 {
03275 tConfItemBase::LoadPlayback();
03276 }
03277 else
03278 {
03279 std::stringstream s(static_cast< char const * >( params ) );
03280 tConfItemBase::LoadAll(s);
03281 }
03282 std::cout << "console selected\n";
03283 } else
03284 se_DisplayChatLocally( this, s );
03285
03286 break;
03287 }
03288 }
03289 }
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307 static ePlayerNetID* se_GetLocalPlayer()
03308 {
03309 for(int i=0; i<se_PlayerNetIDs.Len(); i++)
03310 {
03311 ePlayerNetID *p = se_PlayerNetIDs[i];
03312
03313 if( p->Owner() == sn_myNetID )
03314 return p;
03315 }
03316 return NULL;
03317 }
03318
03319 static void ConsoleSay_conf(std::istream &s)
03320 {
03321
03322 tString message;
03323 message.ReadLine( s, true );
03324
03325 switch (sn_GetNetState())
03326 {
03327 case nCLIENT:
03328 {
03329 ePlayerNetID *me = se_GetLocalPlayer();
03330
03331 if (me)
03332 me->Chat( message );
03333
03334 break;
03335 }
03336 case nSERVER:
03337 {
03338 tColoredString send;
03339 send << tColoredString::ColorString( 1,0,0 );
03340 send << "Admin";
03341 send << tColoredString::ColorString( 1,1,.5 );
03342 send << ": " << message << "\n";
03343
03344
03345 sn_ConsoleOut( send );
03346
03347 break;
03348 }
03349 default:
03350 {
03351 ePlayerNetID *me = se_GetLocalPlayer();
03352
03353 if ( me )
03354 se_DisplayChatLocally( me, message );
03355
03356 break;
03357 }
03358 }
03359 }
03360
03361 static tConfItemFunc ConsoleSay_c("SAY",&ConsoleSay_conf);
03362
03363 struct eChatInsertionCommand
03364 {
03365 tString insertion_;
03366
03367 eChatInsertionCommand( tString const & insertion )
03368 : insertion_( insertion )
03369 {}
03370 };
03371
03372
03373 static uMenuItemStringWithHistory::history_t &se_chatHistory() {
03374 static uMenuItemStringWithHistory::history_t instance("chat_history.txt");
03375 return instance;
03376 }
03377 static int se_chatHistoryMaxSize=10;
03378 static tSettingItem< int > se_chatHistoryMaxSizeConf("HISTORY_SIZE_CHAT",se_chatHistoryMaxSize);
03379
03381 class eAutoCompleterChat : public uAutoCompleter{
03382 public:
03385 eAutoCompleterChat(std::deque<tString> &words):uAutoCompleter(words) {};
03386 int DoFullCompletion(tString &string, int pos, int len, tString &match) {
03387 tString actualString;
03388 if(pos - len == 0 || pos - len == 6 && string.StartsWith("/team ")) {
03389 actualString = match + ": ";
03390 } else if(pos - len == 5 && string.StartsWith("/msg ") || string.StartsWith("/admin ")) {
03391 actualString = Simplify(match) + " ";
03392 } else {
03393 actualString = match + " ";
03394 }
03395 return DoCompletion(string, pos, len, actualString);
03396 }
03397 tString Simplify(tString const &str) {
03398 return ePlayerNetID::FilterName(str);
03399 }
03400 };
03401
03403 class eMenuItemChat : protected uMenuItemStringWithHistory{
03404 ePlayer *me;
03405 public:
03411 eMenuItemChat(uMenu *M,tString &c,ePlayer *Me,uAutoCompleter *completer):
03412 uMenuItemStringWithHistory(M,"$chat_title_text","",c, se_SpamMaxLen, se_chatHistory(), se_chatHistoryMaxSize, completer),me(Me) {}
03413
03414 virtual ~eMenuItemChat(){ }
03415
03416 virtual bool Event(SDL_Event &e){
03417 #ifndef DEDICATED
03418 if (e.type==SDL_KEYDOWN &&
03419 (e.key.keysym.sym==SDLK_KP_ENTER || e.key.keysym.sym==SDLK_RETURN)){
03420
03421 for(int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
03422 if (se_PlayerNetIDs(i)->pID==me->ID())
03423 se_PlayerNetIDs(i)->Chat(*content);
03424
03425 MyMenu()->Exit();
03426 return true;
03427 }
03428 else if (e.type==SDL_KEYDOWN &&
03429 uActionGlobal::IsBreakingGlobalBind(e.key.keysym.sym))
03430 return su_HandleEvent(e, true);
03431 else
03432 {
03433 if ( uMenuItemStringWithHistory::Event(e) )
03434 {
03435 return true;
03436 }
03437
03438 else if ( e.key.keysym.sym < SDLK_NUMLOCK || e.key.keysym.sym > SDLK_COMPOSE )
03439 {
03440
03441 try
03442 {
03443 return su_HandleEvent(e, false);
03444 }
03445 catch ( eChatInsertionCommand & insertion )
03446 {
03447 if ( content->Len() + insertion.insertion_.Len() <= maxLength_ )
03448 {
03449 *content = content->SubStr( 0, cursorPos ) + insertion.insertion_ + content->SubStr( cursorPos );
03450 cursorPos += insertion.insertion_.Len()-1;
03451 }
03452
03453 return true;
03454 }
03455 }
03456 }
03457 #endif // DEDICATED
03458
03459 return false;
03460 }
03461 };
03462
03463
03464 void se_ChatState(ePlayerNetID::ChatFlags flag, bool cs){
03465 for(int i=se_PlayerNetIDs.Len()-1;i>=0;i--)
03466 {
03467 ePlayerNetID *p = se_PlayerNetIDs[i];
03468 if (p->Owner()==sn_myNetID && p->pID >= 0){
03469 p->SetChatting( flag, cs );
03470 }
03471 }
03472 }
03473
03474 static ePlayer * se_chatterPlanned=NULL;
03475 static ePlayer * se_chatter =NULL;
03476 static tString se_say;
03477 static void do_chat(){
03478 if (se_chatterPlanned){
03479 su_ClearKeys();
03480
03481 se_chatter=se_chatterPlanned;
03482 se_chatterPlanned=NULL;
03483 se_ChatState( ePlayerNetID::ChatFlags_Chat, true);
03484
03485 sr_con.SetHeight(15,false);
03486 se_SetShowScoresAuto(false);
03487
03488 uMenu chat_menu("",false);
03489
03490 std::deque<tString> players;
03491 unsigned short int max=se_PlayerNetIDs.Len();
03492 for(unsigned short int i=0;i<max;i++){
03493 ePlayerNetID *p=se_PlayerNetIDs(i);
03494 players.push_back(p->GetName());
03495 }
03496 eAutoCompleterChat completer(players);
03497
03498
03499 eMenuItemChat s(&chat_menu,se_say,se_chatter,&completer);
03500 chat_menu.SetCenter(-.75);
03501 chat_menu.SetBot(-2);
03502 chat_menu.SetTop(-.7);
03503 chat_menu.Enter();
03504
03505 se_ChatState( ePlayerNetID::ChatFlags_Chat, false );
03506
03507 sr_con.SetHeight(7,false);
03508 se_SetShowScoresAuto(true);
03509 }
03510 se_chatter=NULL;
03511 se_chatterPlanned=NULL;
03512 }
03513
03514 static void chat( ePlayer * chatter, tString const & say )
03515 {
03516 se_chatterPlanned = chatter;
03517 se_say = say;
03518 st_ToDo(&do_chat);
03519 }
03520
03521 static void chat( ePlayer * chatter )
03522 {
03523 chat( chatter, tString() );
03524 }
03525
03526 static bool se_allowControlDuringChat = false;
03527 static nSettingItem<bool> se_allowControlDuringChatConf("ALLOW_CONTROL_DURING_CHAT",se_allowControlDuringChat);
03528
03529 uActionPlayer se_toggleSpectator("TOGGLE_SPECTATOR", 0);
03530
03531 bool ePlayer::Act(uAction *act,REAL x){
03532 eGameObject *object=NULL;
03533
03534 if ( act == &se_toggleSpectator && x > 0 )
03535 {
03536 spectate = !spectate;
03537 con << tOutput(spectate ? "$player_toggle_spectator_on" : "$player_toggle_spectator_off", name );
03538 if ( !spectate )
03539 {
03540 ePlayerNetID::Update();
03541 }
03542 return true;
03543 }
03544 else if (!se_chatter && s_chat==*reinterpret_cast<uActionPlayer *>(act)){
03545 if(x>0) {
03546 chat( this );
03547 }
03548 return true;
03549 }
03550 else{
03551 if ( x > 0 )
03552 {
03553 int i;
03554 uActionPlayer* pact = reinterpret_cast<uActionPlayer *>(act);
03555 for(i=MAX_INSTANT_CHAT-1;i>=0;i--){
03556 uActionPlayer* pcompare = se_instantChatAction[i];
03557 if (pact == pcompare && x>=0){
03558 for(int j=se_PlayerNetIDs.Len()-1;j>=0;j--)
03559 if (se_PlayerNetIDs(j)->pID==ID())
03560 {
03561 tString say = instantChatString[i];
03562 bool sendImmediately = true;
03563 if ( say.Len() > 2 && say[say.Len()-2] == '\\' )
03564 {
03565
03566
03567 say = say.SubStr( 0, say.Len()-2 );
03568 sendImmediately = false;
03569 }
03570
03571 if ( se_chatter == this )
03572 {
03573
03574 throw eChatInsertionCommand( say );
03575 }
03576 else
03577 {
03578 if ( sendImmediately )
03579 {
03580
03581 se_PlayerNetIDs(j)->Chat(say);
03582 }
03583 else
03584 {
03585
03586 chat( this, say );
03587 }
03588 }
03589 return true;
03590 }
03591 }
03592 }
03593 }
03594
03595
03596 if ( se_chatter && !se_allowControlDuringChat )
03597 return false;
03598
03599 int i;
03600 for(i=se_PlayerNetIDs.Len()-1;i>=0;i--)
03601 if (se_PlayerNetIDs[i]->pID==id && se_PlayerNetIDs[i]->object)
03602 object=se_PlayerNetIDs[i]->object;
03603
03604 bool objectAct = false;
03605 bool ret = ((cam && cam->Act(reinterpret_cast<uActionCamera *>(act),x)) ||
03606 ( objectAct = (object && se_GameTime()>=0 && object->Act(reinterpret_cast<uActionPlayer *>(act),x))));
03607
03608 if (bool(netPlayer) && (objectAct || !se_chatter))
03609 netPlayer->Activity();
03610
03611 return ret;
03612 }
03613
03614 }
03615
03616 rViewport * ePlayer::PlayerViewport(int p){
03617 if (!PlayerConfig(p)) return NULL;
03618
03619 for (int i=rViewportConfiguration::CurrentViewportConfiguration()->num_viewports-1;i>=0;i--)
03620 if (sr_viewportBelongsToPlayer[i] == p)
03621 return rViewportConfiguration::CurrentViewport(i);
03622
03623 return NULL;
03624 }
03625
03626 bool ePlayer::PlayerIsInGame(int p){
03627 return PlayerViewport(p) && PlayerConfig(p);
03628 }
03629
03630 static tConfItemBase *vpbtp[MAX_VIEWPORTS];
03631
03632 void ePlayer::Init(){
03633 se_Players = tNEW( ePlayer[MAX_PLAYERS] );
03634
03635 int i;
03636 for(i=MAX_INSTANT_CHAT-1;i>=0;i--){
03637 tString id;
03638 id << "INSTANT_CHAT_";
03639 id << i+1;
03640 tOutput desc;
03641 desc.SetTemplateParameter(1, i+1);
03642 desc << "$input_instant_chat_text";
03643
03644 tOutput help;
03645 help.SetTemplateParameter(1, i+1);
03646 help << "$input_instant_chat_help";
03647 ePlayer::se_instantChatAction[i]=tNEW(uActionPlayer) (id, desc, help);
03648
03649 }
03650
03651
03652 for(i=MAX_VIEWPORTS-1;i>=0;i--){
03653 tString id;
03654 id << "VIEWPORT_TO_PLAYER_";
03655 id << i+1;
03656 vpbtp[i] = tNEW(tConfItem<int>(id,"$viewport_belongs_help",
03657 s_newViewportBelongsToPlayer[i]));
03658 s_newViewportBelongsToPlayer[i]=i;
03659 }
03660 }
03661
03662 void ePlayer::Exit(){
03663 int i;
03664 for(i=MAX_INSTANT_CHAT-1;i>=0;i--)
03665 tDESTROY(ePlayer::se_instantChatAction[i]);
03666
03667 for(i=MAX_VIEWPORTS-1;i>=0;i--)
03668 tDESTROY(vpbtp[i]);
03669
03670 delete[] se_Players;
03671 se_Players = NULL;
03672 }
03673
03674 uActionPlayer ePlayer::s_chat("CHAT");
03675
03676 int pingCharity = 100;
03677 static const int maxPingCharity = 300;
03678
03679 static void sg_ClampPingCharity( int & pingCharity )
03680 {
03681 if (pingCharity < 0 )
03682 pingCharity = 0;
03683 if (pingCharity > maxPingCharity )
03684 pingCharity = maxPingCharity;
03685 }
03686
03687 static void sg_ClampPingCharity( unsigned short & pingCharity )
03688 {
03689 if (pingCharity > maxPingCharity )
03690 pingCharity = maxPingCharity;
03691 }
03692
03693 static void sg_ClampPingCharity()
03694 {
03695 sg_ClampPingCharity( ::pingCharity );
03696 }
03697
03698 static int IMPOSSIBLY_LOW_SCORE=(-1 << 31);
03699
03700 static nSpamProtectionSettings se_chatSpamSettings( 1.0f, "SPAM_PROTECTION_CHAT", tOutput("$spam_protection") );
03701
03702 ePlayerNetID::ePlayerNetID(int p):nNetObject(),listID(-1), teamListID(-1), allowTeamChange_(false), registeredMachine_(0), pID(p),chatSpam_( se_chatSpamSettings )
03703 {
03704
03705 lastAccessLevel = tAccessLevel_Default;
03706
03707 favoriteNumberOfPlayersPerTeam = 1;
03708
03709 nameTeamAfterMe = false;
03710
03711 r = g = b = 15;
03712
03713 greeted = true;
03714 chatting_ = false;
03715 spectating_ = false;
03716 stealth_ = false;
03717 chatFlags_ = 0;
03718 disconnected = false;
03719 suspended_ = 0;
03720
03721 loginWanted = false;
03722
03723
03724 if (p>=0){
03725 ePlayer *P = ePlayer::PlayerConfig(p);
03726 if (P){
03727 SetName( P->Name() );
03728 teamname = P->Teamname();
03729 r= P->rgb[0];
03730 g= P->rgb[1];
03731 b= P->rgb[2];
03732
03733 sg_ClampPingCharity();
03734 pingCharity=::pingCharity;
03735
03736 loginWanted = P->autoLogin;
03737 }
03738 }
03739
03740
03741
03742
03743
03744
03745
03746 lastSaid.SetLen(12);
03747 lastSaidTimes.SetLen(12);
03748
03749 se_PlayerNetIDs.Add(this,listID);
03750 object=NULL;
03751
03752
03753
03754
03755
03756
03757 ping=0;
03758
03759 lastSync=tSysTimeFloat();
03760
03761 RequestSync();
03762 score=0;
03763 lastScore_=IMPOSSIBLY_LOW_SCORE;
03764
03765
03766 MyInitAfterCreation();
03767
03768 if(sn_GetNetState()==nSERVER)
03769 RequestSync();
03770 }
03771
03772
03773
03774
03775 ePlayerNetID::ePlayerNetID(nMessage &m):nNetObject(m),listID(-1), teamListID(-1)
03776 , allowTeamChange_(false), registeredMachine_(0), chatSpam_( se_chatSpamSettings )
03777 {
03778
03779 lastAccessLevel = tAccessLevel_Default;
03780
03781 greeted =false;
03782 chatting_ =false;
03783 spectating_ =false;
03784 stealth_ =false;
03785 disconnected=false;
03786 suspended_ = 0;
03787 chatFlags_ =0;
03788
03789 r = g = b = 15;
03790
03791 nameTeamAfterMe = false;
03792 teamname = "";
03793
03794 lastSaid.SetLen(12);
03795 lastSaidTimes.SetLen(12);
03796
03797 pID=-1;
03798 se_PlayerNetIDs.Add(this,listID);
03799 object=NULL;
03800 ping=sn_Connections[m.SenderID()].ping;
03801 lastSync=tSysTimeFloat();
03802
03803 loginWanted = false;
03804
03805 score=0;
03806 lastScore_=IMPOSSIBLY_LOW_SCORE;
03807
03808 }
03809
03810 void ePlayerNetID::Activity()
03811 {
03812
03813
03814
03815 if (sn_GetNetState() != nSERVER && Owner() != ::sn_myNetID)
03816 return;
03817
03818 if (chatting_ || disconnected)
03819 {
03820 #ifdef DEBUG
03821 con << *this << " showed activity and lost chat status.\n";
03822 #endif
03823 RequestSync();
03824 }
03825
03826 chatting_ = disconnected = false;
03827
03828
03829 this->lastActivity_ = tSysTimeFloat();
03830 }
03831
03832 static int se_maxPlayersPerIP = 4;
03833 static tSettingItem<int> se_maxPlayersPerIPConf( "MAX_PLAYERS_SAME_IP", se_maxPlayersPerIP );
03834
03835
03836
03837 static tJUST_CONTROLLED_PTR< ePlayerNetID > se_legacySpectators[MAXCLIENTS+2];
03838
03839 static void se_ClearLegacySpectator( int owner )
03840 {
03841 ePlayerNetID * player = se_legacySpectators[ owner ];
03842
03843
03844 if ( player )
03845 {
03846 player->RemoveFromGame();
03847 }
03848
03849 se_legacySpectators[ owner ] = NULL;
03850 }
03851
03852
03853 static void se_LegacySpectatorClearer()
03854 {
03855 se_ClearLegacySpectator( nCallbackLoginLogout::User() );
03856 }
03857 static nCallbackLoginLogout se_legacySpectatorClearer( se_LegacySpectatorClearer );
03858
03859
03860
03861 void ePlayerNetID::MyInitAfterCreation()
03862 {
03863 this->CreateVoter();
03864
03865 this->silenced_ = se_silenceAll;
03866
03867
03868 if ( Owner() != 0 && sn_GetNetState() == nSERVER )
03869 {
03870 this->RegisterWithMachine();
03871 if ( se_maxPlayersPerIP < nMachine::GetMachine(Owner()).GetPlayerCount() )
03872 {
03873
03874 sn_DisconnectUser( Owner(), "$network_kill_too_many_players" );
03875
03876
03877
03878 throw nKillHim();
03879 }
03880
03881
03882 se_ClearLegacySpectator( Owner() );
03883
03884
03885 if ( GetVoter() )
03886 {
03887 suspended_ = GetVoter()->suspended_;
03888 }
03889 }
03890
03891 this->wait_ = 0;
03892
03893 this->lastActivity_ = tSysTimeFloat();
03894 }
03895
03896 void ePlayerNetID::InitAfterCreation()
03897 {
03898 MyInitAfterCreation();
03899 }
03900
03901 bool ePlayerNetID::ClearToTransmit(int user) const{
03902 return ( ( !nextTeam || nextTeam->HasBeenTransmitted( user ) ) &&
03903 ( !currentTeam || currentTeam->HasBeenTransmitted( user ) ) ) ;
03904 }
03905
03906 ePlayerNetID::~ePlayerNetID()
03907 {
03908
03909 if ( sn_GetNetState() == nSERVER && disconnected )
03910 {
03911 tOutput mess;
03912 tColoredString name;
03913 name << *this << tColoredString::ColorString(1,.5,.5);
03914 mess.SetTemplateParameter(1, name);
03915 mess.SetTemplateParameter(2, score);
03916 mess << "$player_left_game";
03917 sn_ConsoleOut(mess);
03918 }
03919
03920 UnregisterWithMachine();
03921
03922 RemoveFromGame();
03923
03924 ClearObject();
03925
03926
03927 for(int i=MAX_PLAYERS-1;i>=0;i--){
03928 ePlayer *p = ePlayer::PlayerConfig(i);
03929
03930 if (p && static_cast<ePlayerNetID *>(p->netPlayer)==this)
03931 p->netPlayer=NULL;
03932 }
03933
03934 if ( currentTeam )
03935 {
03936 currentTeam->RemovePlayer( this );
03937 }
03938
03939 #ifdef DEBUG
03940 con << *this << " destroyed.\n";
03941 #endif
03942 }
03943
03944 static void player_removed_from_game_handler(nMessage &m)
03945 {
03946
03947 unsigned short id;
03948 m.Read(id);
03949 ePlayerNetID* p = dynamic_cast< ePlayerNetID* >( nNetObject::ObjectDangerous( id ) );
03950 if ( p && sn_GetNetState() != nSERVER )
03951 {
03952 p->RemoveFromGame();
03953 }
03954 }
03955
03956 static nDescriptor player_removed_from_game(202,&player_removed_from_game_handler,"player_removed_from_game");
03957
03958 void ePlayerNetID::RemoveFromGame()
03959 {
03960
03961 this->UnregisterWithMachine();
03962
03963
03964 if ( this->voter_ )
03965 this->voter_->RemoveFromGame();
03966 this->voter_ = 0;
03967
03968
03969 LogScoreDifference();
03970
03971 if ( sn_GetNetState() != nCLIENT )
03972 {
03973 nameFromClient_ = nameFromServer_;
03974
03975 nMessage *m=new nMessage(player_removed_from_game);
03976 m->Write(this->ID());
03977 m->BroadCast();
03978
03979 if ( listID >= 0 ){
03980 if ( ( IsSpectating() || !se_assignTeamAutomatically ) && CurrentTeam() == NULL )
03981 {
03982
03983 tColoredString playerName;
03984 playerName << *this << tColoredString::ColorString(1,.5,.5);
03985
03986
03987 sn_ConsoleOut( tOutput( "$player_left_spectator", playerName ) );
03988 }
03989
03990 if ( IsHuman() && sn_GetNetState() == nSERVER && NULL != sn_Connections[Owner()].socket )
03991 {
03992 tString ladder;
03993 ladder << "PLAYER_LEFT " << userName_ << " " << nMachine::GetMachine(Owner()).GetIP() << "\n";
03994 se_SaveToLadderLog(ladder);
03995 tString notificationMessage(userName_);
03996 notificationMessage << " left the grid";
03997 se_sendEventNotification(tString("Player left"), notificationMessage);
03998 }
03999 }
04000 }
04001
04002 se_PlayerNetIDs.Remove(this, listID);
04003 SetTeamWish( NULL );
04004 SetTeam( NULL );
04005 UpdateTeam();
04006 ControlObject( NULL );
04007
04008 }
04009
04010 bool ePlayerNetID::ActionOnQuit()
04011 {
04012 tControlledPTR< ePlayerNetID > holder( this );
04013
04014
04015 se_ClearLegacySpectator( Owner() );
04016
04017 this->RemoveFromGame();
04018 return true;
04019 }
04020
04021 void ePlayerNetID::ActionOnDelete()
04022 {
04023 tControlledPTR< ePlayerNetID > holder( this );
04024
04025 if ( sn_GetNetState() == nSERVER )
04026 {
04027
04028
04029 int playerCount = 0;
04030 for ( int i = se_PlayerNetIDs.Len()-1; i >= 0; --i )
04031 {
04032 if ( se_PlayerNetIDs[i]->Owner() == Owner() )
04033 playerCount++;
04034 }
04035
04036
04037 if ( playerCount == 1 )
04038 {
04039
04040 LogScoreDifference();
04041
04042
04043 se_ClearLegacySpectator( Owner() );
04044
04045
04046 se_legacySpectators[ Owner() ] = this;
04047 spectating_ = true;
04048
04049
04050 SetTeamWish( NULL );
04051 SetTeam( NULL );
04052 UpdateTeam();
04053
04054
04055 ControlObject( NULL );
04056
04057
04058 TakeOwnership();
04059 RequestSync();
04060
04061 return;
04062 }
04063 }
04064
04065
04066 this->RemoveFromGame();
04067 }
04068
04069 void ePlayerNetID::PrintName(tString &s) const
04070 {
04071 s << "ePlayerNetID nr. " << ID() << ", name " << GetName();
04072 }
04073
04074
04075 bool ePlayerNetID::AcceptClientSync() const{
04076 return true;
04077 }
04078
04079 #ifdef KRAWALL_SERVER
04080
04081
04082 template< class P > class eUserConfig: public tConfItemBase
04083 {
04084 public:
04085 P Get(tString const & name ) const
04086 {
04087 typename Properties::const_iterator iter = properties.find( name );
04088 if ( iter != properties.end() )
04089 {
04090 return (*iter).second;
04091 }
04092
04093 return GetDefault();
04094 }
04095 protected:
04096 typedef std::map< tString, P > Properties;
04097
04098 eUserConfig( char const * name )
04099 : tConfItemBase( name )
04100 {
04101 requiredLevel = tAccessLevel_Owner;
04102 }
04103
04104 virtual P ReadRawVal(tString const & name, std::istream &s) const = 0;
04105 virtual P GetDefault() const = 0;
04106 virtual void TransformName( tString & name ) const {};
04107
04108 virtual void ReadVal(std::istream &s)
04109 {
04110 tString name;
04111 s >> name;
04112
04113 TransformName( name );
04114
04115 P value = ReadRawVal(name, s);
04116
04117 properties[name] = value;
04118 }
04119
04120 Properties properties;
04121 private:
04122
04123 virtual void WriteVal(std::ostream &s)
04124 {
04125 tASSERT(0);
04126 }
04127
04128 virtual bool Writable(){
04129 return false;
04130 }
04131
04132 virtual bool Save(){
04133 return false;
04134 }
04135 };
04136
04137
04138 class eUserLevel: public eUserConfig< tAccessLevel >
04139 {
04140 public:
04141 eUserLevel()
04142 : eUserConfig< tAccessLevel >( "USER_LEVEL" )
04143 {
04144 requiredLevel = tAccessLevel_Owner;
04145 }
04146
04147 tAccessLevel GetDefault() const
04148 {
04149 return tAccessLevel_DefaultAuthenticated;
04150 }
04151
04152 virtual tAccessLevel ReadRawVal(tString const & name, std::istream &s) const
04153 {
04154 int levelInt;
04155 s >> levelInt;
04156 tAccessLevel level = static_cast< tAccessLevel >( levelInt );
04157
04158 if ( s.fail() )
04159 {
04160 if(printErrors)
04161 {
04162 con << tOutput( "$user_level_usage" );
04163 }
04164 return GetDefault();
04165 }
04166
04167 if(printChange)
04168 {
04169 con << tOutput( "$user_level_change", name, tCurrentAccessLevel::GetName( level ) );
04170 }
04171
04172 return level;
04173 }
04174 };
04175
04176 static eUserLevel se_userLevel;
04177
04178
04179 class eReserveNick: public eUserConfig< tString >
04180 {
04181 #ifdef DEBUG
04182 static void TestEscape()
04183 {
04184 #ifdef KRAWALL_SERVER
04185 tString test("ä@%bla:");
04186 tString esc(se_EscapeName( test, false ).c_str());
04187 tString rev(se_UnEscapeName( esc ).c_str());
04188 tASSERT( test == rev );
04189 #endif
04190 }
04191 #endif
04192 public:
04193 eReserveNick()
04194 : eUserConfig< tString >( "RESERVE_SCREEN_NAME" )
04195 {
04196 #ifdef DEBUG
04197 TestEscape();
04198 #endif
04199 }
04200
04201
04202
04203 virtual void TransformName( tString & name ) const
04204 {
04205 name = ePlayerNetID::FilterName( name );
04206 }
04207
04208 tString GetDefault() const
04209 {
04210 return tString();
04211 }
04212
04213 virtual tString ReadRawVal(tString const & name, std::istream &s) const
04214 {
04215 tString user;
04216 s >> user;
04217
04218 if ( user == "" )
04219 {
04220 con << tOutput( "$reserve_screen_name_usage" );
04221 return GetDefault();
04222 }
04223
04224 user = se_UnEscapeName( user ).c_str();
04225
04226 con << tOutput( "$reserve_screen_name_change", name, user );
04227
04228 return user;
04229 }
04230 };
04231
04232 static eReserveNick se_reserveNick;
04233
04234
04235 class eAlias: public eUserConfig< tString >
04236 {
04237 public:
04238 eAlias()
04239 : eUserConfig< tString >( "USER_ALIAS" )
04240 {
04241 }
04242
04243 tString GetDefault() const
04244 {
04245 return tString();
04246 }
04247
04248 virtual tString ReadRawVal(tString const & name, std::istream &s) const
04249 {
04250 tString alias;
04251 s >> alias;
04252
04253 if ( alias == "" )
04254 {
04255 con << tOutput( "$alias_usage" );
04256 return GetDefault();
04257 }
04258
04259 alias = se_UnEscapeName( alias ).c_str();
04260
04261 con << tOutput( "$alias_change", name, alias );
04262
04263 return alias;
04264 }
04265 };
04266
04267 static eAlias se_alias;
04268
04269
04270 class eBanUser: public eUserConfig< bool >
04271 {
04272 public:
04273 eBanUser()
04274 : eUserConfig< bool >( "BAN_USER" )
04275 {
04276 }
04277
04278
04279 void UnBan( tString const & name )
04280 {
04281 properties[name] = false;
04282 con << tOutput( "$unban_user_message", name );
04283 }
04284
04285 void List()
04286 {
04287 bool one = false;
04288 for ( Properties::iterator i = properties.begin(); i != properties.end(); ++i )
04289 {
04290 if ( (*i).second )
04291 {
04292 if ( one )
04293 {
04294 con << ", ";
04295 }
04296 con << (*i).first;
04297 one = true;
04298 }
04299 }
04300 if ( one )
04301 {
04302 con << "\n";
04303 }
04304 }
04305
04306 bool GetDefault() const
04307 {
04308 return false;
04309 }
04310
04311 virtual bool ReadRawVal(tString const & name, std::istream &s) const
04312 {
04313 con << tOutput( "$ban_user_message", name );
04314 return true;
04315 }
04316 };
04317
04318 static eBanUser se_banUser;
04319
04320
04321 static bool se_IsUserBanned( ePlayerNetID * p, tString const & name )
04322 {
04323 if( se_banUser.Get( name ) )
04324 {
04325 sn_KickUser( p->Owner(), tOutput( "$network_kill_banned", 60, "" ) );
04326 return true;
04327 }
04328
04329 return false;
04330 }
04331
04332 class eUnBanUser: public eUserConfig< bool >
04333 {
04334 public:
04335 eUnBanUser( )
04336 : eUserConfig< bool >( "UNBAN_USER" )
04337 {
04338 }
04339
04340 bool GetDefault() const
04341 {
04342 return false;
04343 }
04344
04345 virtual bool ReadRawVal(tString const & name, std::istream &s) const
04346 {
04347 se_banUser.UnBan(name);
04348 return false;
04349 }
04350 };
04351
04352 static eUnBanUser se_unBanUser;
04353
04354 static void se_ListBannedUsers( std::istream & )
04355 {
04356 se_banUser.List();
04357 }
04358
04359 static tConfItemFunc sn_listBanConf("BAN_USER_LIST",&se_ListBannedUsers);
04360
04361 static void se_CheckAccessLevel( tAccessLevel & level, tString const & authName )
04362 {
04363 tAccessLevel newLevel = se_userLevel.Get( authName );
04364 if ( newLevel < level || newLevel > tAccessLevel_DefaultAuthenticated )
04365 {
04366 level = newLevel;
04367 }
04368 }
04369
04370 void ePlayerNetID::Authenticate( tString const & authName, tAccessLevel accessLevel_, ePlayerNetID const * admin )
04371 {
04372 tString newAuthenticatedName( se_EscapeName( authName ).c_str() );
04373
04374
04375 if ( !IsHuman() )
04376 {
04377 return;
04378 }
04379
04380 if ( !IsAuthenticated() )
04381 {
04382
04383 se_CheckAccessLevel( accessLevel_, newAuthenticatedName );
04384
04385 rawAuthenticatedName_ = authName;
04386 tString alias = se_alias.Get( newAuthenticatedName );
04387 if ( alias != "" )
04388 {
04389 rawAuthenticatedName_ = alias;
04390 newAuthenticatedName = GetFilteredAuthenticatedName();
04391
04392
04393 se_CheckAccessLevel( accessLevel_, newAuthenticatedName );
04394 }
04395
04396
04397 if ( se_IsUserBanned( this, newAuthenticatedName ) )
04398 {
04399 return;
04400 }
04401
04402
04403 if ( accessLevel_ > tAccessLevel_Authenticated )
04404 {
04405 accessLevel_ = static_cast< tAccessLevel >( tAccessLevel_Program - 1 );
04406 }
04407
04408
04409 SetAccessLevel( accessLevel_ );
04410
04411 tString order( "" );
04412 if ( admin )
04413 {
04414 order = tOutput( "$login_message_byorder",
04415 admin->GetLogName() );
04416 }
04417
04418 if ( IsHuman() )
04419 {
04420 if ( GetAccessLevel() != tAccessLevel_Default )
04421 {
04422 se_SecretConsoleOut( tOutput( "$login_message_special",
04423 GetName(),
04424 newAuthenticatedName,
04425 tCurrentAccessLevel::GetName( GetAccessLevel() ),
04426 order ), this, admin );
04427 }
04428 else
04429 {
04430 se_SecretConsoleOut( tOutput( "$login_message", GetName(), newAuthenticatedName, order ), this, admin );
04431 }
04432
04433 }
04434 }
04435
04436 GetScoreFromDisconnectedCopy();
04437 }
04438
04439 void ePlayerNetID::DeAuthenticate( ePlayerNetID const * admin ){
04440 if ( IsAuthenticated() )
04441 {
04442 if ( admin )
04443 {
04444 se_SecretConsoleOut( tOutput( "$logout_message_deop", GetName(), GetFilteredAuthenticatedName(), admin->GetLogName() ), this, admin );
04445 }
04446 else
04447 {
04448 se_SecretConsoleOut( tOutput( "$logout_message", GetName(), GetFilteredAuthenticatedName() ), this );
04449 }
04450 }
04451
04452
04453 SetAccessLevel( tAccessLevel_Default );
04454
04455 rawAuthenticatedName_ = "";
04456 }
04457
04458 bool ePlayerNetID::IsAuthenticated() const
04459 {
04460 return int(GetAccessLevel()) <= int(tAccessLevel_Authenticated);
04461 }
04462 #endif
04463
04464
04465 void ePlayerNetID::CreateVoter()
04466 {
04467
04468 if ( sn_GetNetState() != nCLIENT && this->Owner() != 0 && sn_Connections[ this->Owner() ].version.Max() >= 3 )
04469 {
04470 this->voter_ = eVoter::GetVoter( this->Owner() );
04471 if ( this->voter_ )
04472 this->voter_->PlayerChanged();
04473 }
04474 }
04475
04476 void ePlayerNetID::WriteSync(nMessage &m){
04477 lastSync=tSysTimeFloat();
04478 nNetObject::WriteSync(m);
04479 m.Write(r);
04480 m.Write(g);
04481 m.Write(b);
04482
04483
04484 if ( currentTeam || nextTeam )
04485 m.Write(pingCharity);
04486 else
04487 m.Write(1000);
04488
04489 if ( sn_GetNetState() == nCLIENT )
04490 {
04491 m << nameFromClient_;
04492 }
04493 else
04494 {
04495 m << nameFromServer_;
04496 }
04497
04498
04499 m << ping;
04500
04501
04502 unsigned short flags = ( chatting_ ? 1 : 0 ) | ( spectating_ ? 2 : 0 ) | ( stealth_ ? 4 : 0 );
04503 m << flags;
04504
04505 m << score;
04506 m << static_cast<unsigned short>(disconnected);
04507
04508 m << nextTeam;
04509 m << currentTeam;
04510
04511 m << favoriteNumberOfPlayersPerTeam;
04512 m << nameTeamAfterMe;
04513
04514 m << teamname;
04515 }
04516
04517
04518 static void se_CutString( tColoredString & string, int maxLen )
04519 {
04520 if (string.Len() > maxLen )
04521 {
04522 string = string.SubStr(0, maxLen);
04523
04524 string.RemoveTrailingColor();
04525 }
04526 }
04527
04528 static void se_CutString( tString & string, int maxLen )
04529 {
04530 se_CutString( reinterpret_cast< tColoredString & >( string ), maxLen );
04531 }
04532
04533 static bool se_bugColorOverflow=true;
04534 tSettingItem< bool > se_bugColorOverflowColor( "BUG_COLOR_OVERFLOW", se_bugColorOverflow );
04535 void Clamp( unsigned short & colorComponent )
04536 {
04537 if ( colorComponent > 15 )
04538 colorComponent = 15;
04539 }
04540
04541
04542 typedef bool TestCharacter( char c );
04543
04544
04545 static void se_StripMatchingEnds( tString & stripper, TestCharacter & beginTester, TestCharacter & endTester )
04546 {
04547 int len = stripper.Size() - 1;
04548 int first = 0, last = len;
04549
04550
04551 while ( first < len && beginTester( stripper[first] ) ) ++first;
04552 while ( last > 0 && ( !stripper[last] || endTester(stripper[last] ) ) ) --last;
04553
04554
04555 if ( first > last )
04556 {
04557 stripper = "";
04558 return;
04559 }
04560
04561
04562 if ( first > 0 || last < stripper.Len() - 1 )
04563 stripper = stripper.SubStr( first, last + 1 - first );
04564 }
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574 static bool se_IsBlank( char c )
04575 {
04576 return isblank( c );
04577 }
04578
04579
04580 static bool se_IsInvalidNameEnd( char c )
04581 {
04582 return isblank( c ) || c == ':' || c == '.';
04583 }
04584
04585
04586 static void se_StripNameEnds( tString & name )
04587 {
04588 se_StripMatchingEnds( name, se_IsBlank, se_IsInvalidNameEnd );
04589 }
04590
04591
04592 static bool se_IsNameTaken( tString const & name, ePlayerNetID const * exception )
04593 {
04594 if ( name.Len() <= 1 )
04595 return false;
04596
04597
04598 for (int i = se_PlayerNetIDs.Len()-1; i >= 0; --i )
04599 {
04600 ePlayerNetID * player = se_PlayerNetIDs(i);
04601 if ( player != exception )
04602 {
04603 if ( name == player->GetUserName() || name == ePlayerNetID::FilterName( player->GetName() ) )
04604 return true;
04605 }
04606 }
04607
04608 #ifdef KRAWALL_SERVER
04609
04610 {
04611 tString reservedFor = se_reserveNick.Get( name );
04612 if ( reservedFor != "" &&
04613 ( !exception || exception->GetAccessLevel() >= tAccessLevel_Default ||
04614 exception->GetRawAuthenticatedName() != reservedFor ) )
04615 {
04616 return true;
04617 }
04618 }
04619 #endif
04620
04621 return false;
04622 }
04623
04624 static bool se_allowImposters = false;
04625 static tSettingItem< bool > se_allowImposters1( "ALLOW_IMPOSTERS", se_allowImposters );
04626 static tSettingItem< bool > se_allowImposters2( "ALLOW_IMPOSTORS", se_allowImposters );
04627
04628 static bool se_filterColorNames=false;
04629 tSettingItem< bool > se_coloredNamesConf( "FILTER_COLOR_NAMES", se_filterColorNames );
04630 static bool se_stripNames=true;
04631 tSettingItem< bool > se_stripConf( "FILTER_NAME_ENDS", se_stripNames );
04632 static bool se_stripMiddle=true;
04633 tSettingItem< bool > se_stripMiddleConf( "FILTER_NAME_MIDDLE", se_stripMiddle );
04634
04635
04636 static void se_OptionalNameFilters( tString & remoteName )
04637 {
04638
04639 if ( se_filterColorNames )
04640 {
04641 remoteName = tColoredString::RemoveColors( remoteName );
04642 }
04643
04644
04645
04646 if ( sn_GetNetState() == nCLIENT )
04647 return;
04648
04649
04650 if ( se_stripNames )
04651 se_StripNameEnds( remoteName );
04652
04653 if ( se_stripMiddle )
04654 {
04655
04656 bool whitespace=false;
04657 int i;
04658 for ( i = 0; i < remoteName.Len()-1; ++i )
04659 {
04660 bool newWhitespace=isblank(remoteName[i]);
04661 if ( newWhitespace && whitespace )
04662 {
04663
04664 whitespace=newWhitespace=false;
04665 tString copy;
04666 for ( i = 0; i < remoteName.Len()-1; ++i )
04667 {
04668 char c = remoteName[i];
04669 newWhitespace=isblank(c);
04670 if ( !whitespace || !newWhitespace )
04671 {
04672 copy+=c;
04673 }
04674 whitespace=newWhitespace;
04675 }
04676 remoteName=copy;
04677
04678
04679 break;
04680 }
04681
04682 whitespace=newWhitespace;
04683 }
04684 }
04685
04686
04687 if ( !IsLegalPlayerName( remoteName ) )
04688 {
04689 tString oldName = remoteName;
04690
04691
04692 if ( IsLegalPlayerName( oldName ) )
04693 {
04694 remoteName = oldName;
04695 }
04696 else
04697 {
04698
04699
04700 remoteName = "Player 1";
04701 }
04702 }
04703 }
04704
04705 void ePlayerNetID::ReadSync(nMessage &m){
04706
04707 bool firstSync = ( this->ID() == 0 );
04708
04709 nNetObject::ReadSync(m);
04710
04711 m.Read(r);
04712 m.Read(g);
04713 m.Read(b);
04714
04715 if ( !se_bugColorOverflow )
04716 {
04717
04718 Clamp(r);
04719 Clamp(g);
04720 Clamp(b);
04721 }
04722
04723 m.Read(pingCharity);
04724 sg_ClampPingCharity(pingCharity);
04725
04726
04727 tString & remoteName = ( sn_GetNetState() == nCLIENT ) ? nameFromServer_ : nameFromClient_;
04728
04729
04730 {
04731
04732 m >> remoteName;
04733
04734
04735 se_OptionalNameFilters( remoteName );
04736
04737 se_CutString( remoteName, 16 );
04738 }
04739
04740
04741 if ( sn_GetNetState() != nSERVER )
04742 {
04743 UpdateName();
04744 }
04745
04746 REAL p;
04747 m >> p;
04748 if (sn_GetNetState()!=nSERVER)
04749 ping=p;
04750
04751
04752 {
04753
04754 unsigned short flags;
04755 m >> flags;
04756
04757 if (Owner() != ::sn_myNetID)
04758 {
04759 bool newChat = ( ( flags & 1 ) != 0 );
04760 bool newSpectate = ( ( flags & 2 ) != 0 );
04761 bool newStealth = ( ( flags & 4 ) != 0 );
04762
04763 if ( chatting_ != newChat || spectating_ != newSpectate || newStealth != stealth_ )
04764 lastActivity_ = tSysTimeFloat();
04765 chatting_ = newChat;
04766 spectating_ = newSpectate;
04767 stealth_ = newStealth;
04768 }
04769 }
04770
04771
04772 {
04773 if(sn_GetNetState()!=nSERVER)
04774 m >> score;
04775 else{
04776 int s;
04777 m >> s;
04778 }
04779 }
04780
04781 if (!m.End()){
04782 unsigned short newdisc;
04783 m >> newdisc;
04784
04785 if (Owner() != ::sn_myNetID && sn_GetNetState()!=nSERVER)
04786 disconnected = newdisc;
04787 }
04788
04789 if (!m.End())
04790 {
04791 if ( nSERVER != sn_GetNetState() )
04792 {
04793 eTeam *newCurrentTeam, *newNextTeam;
04794
04795 m >> newNextTeam;
04796 m >> newCurrentTeam;
04797
04798
04799 if ( newCurrentTeam != currentTeam )
04800 {
04801 if ( newCurrentTeam )
04802
04803 newCurrentTeam->AddPlayerDirty( this );
04804 else
04805 currentTeam->RemovePlayer( this );
04806 }
04807
04808 nextTeam = newNextTeam;
04809 }
04810 else
04811 {
04812 eTeam* t;
04813 m >> t;
04814 m >> t;
04815 }
04816
04817 m >> favoriteNumberOfPlayersPerTeam;
04818 m >> nameTeamAfterMe;
04819 }
04820 if (!m.End())
04821 {
04822 m >> teamname;
04823 }
04824
04825
04826
04827
04828
04829
04830 if ( nSERVER == sn_GetNetState() )
04831 {
04832 if ( nextTeam )
04833 nextTeam->UpdateProperties();
04834
04835 if ( currentTeam )
04836 currentTeam->UpdateProperties();
04837 }
04838
04839
04840 if ( firstSync && sn_GetNetState() == nSERVER )
04841 {
04842 UpdateName();
04843
04844 #ifndef KRAWALL_SERVER
04845 GetScoreFromDisconnectedCopy();
04846 #endif
04847 SetDefaultTeam();
04848
04849 RequestSync();
04850 }
04851
04852 }
04853
04854
04855 nNOInitialisator<ePlayerNetID> ePlayerNetID_init(201,"ePlayerNetID");
04856
04857 nDescriptor &ePlayerNetID::CreatorDescriptor() const{
04858 return ePlayerNetID_init;
04859 }
04860
04861
04862
04863 void ePlayerNetID::ControlObject(eNetGameObject *c){
04864 if (bool(object) && c!=object)
04865 ClearObject();
04866
04867 if (!c)
04868 {
04869 return;
04870 }
04871
04872
04873 object=c;
04874 c->team = currentTeam;
04875
04876 if (bool(object))
04877 object->SetPlayer(this);
04878 #ifdef DEBUG
04879
04880 #endif
04881
04882 NewObject();
04883 }
04884
04885 void ePlayerNetID::ClearObject(){
04886 if (object)
04887 {
04888 tJUST_CONTROLLED_PTR< eNetGameObject > x=object;
04889 object=NULL;
04890 x->RemoveFromGame();
04891 x->SetPlayer( NULL );
04892 }
04893 #ifdef DEBUG
04894
04895 #endif
04896 }
04897
04898 void ePlayerNetID::Greet(){
04899 if (!greeted){
04900 tOutput o;
04901 o.SetTemplateParameter(1, GetName() );
04902 o.SetTemplateParameter(2, sn_programVersion);
04903 o << "$player_welcome";
04904 tString s;
04905 s << o;
04906 s << "\n";
04907 GreetHighscores(s);
04908 s << "\n";
04909
04910 sn_ConsoleOut(s,Owner());
04911 greeted=true;
04912 }
04913 }
04914
04915 eNetGameObject *ePlayerNetID::Object() const{
04916 return object;
04917 }
04918
04919 static bool se_consoleLadderLog = false;
04920 static tSettingItem< bool > se_consoleLadderLogConf( "CONSOLE_LADDER_LOG", se_consoleLadderLog );
04921
04922 void se_SaveToLadderLog( tOutput const & out )
04923 {
04924 if (se_consoleLadderLog)
04925 {
04926 std::cout << "[L] " << out;
04927 std::cout.flush();
04928 }
04929 if (sn_GetNetState()!=nCLIENT && !tRecorder::IsPlayingBack())
04930 {
04931 std::ofstream o;
04932 if ( tDirectories::Var().Open(o, "ladderlog.txt", std::ios::app) )
04933 o << out;
04934 }
04935 }
04936
04937 void se_SaveToScoreFile(const tOutput &o){
04938 tString s(o);
04939
04940 #ifdef DEBUG
04941 if (sn_GetNetState()!=nCLIENT){
04942 #else
04943 if (sn_GetNetState()==nSERVER && !tRecorder::IsPlayingBack()){
04944 #endif
04945
04946 std::ofstream o;
04947 if ( tDirectories::Var().Open(o, "scorelog.txt", std::ios::app) )
04948 o << tColoredString::RemoveColors(s);
04949 }
04950 #ifdef DEBUG
04951 }
04952 #else
04953 }
04954 #endif
04955
04956
04957
04958 void ePlayerNetID::AddScore(int points,
04959 const tOutput& reasonwin,
04960 const tOutput& reasonlose)
04961 {
04962 if (points==0)
04963 return;
04964
04965 score += points;
04966 if (currentTeam)
04967 currentTeam->AddScore( points );
04968
04969 tColoredString name;
04970 name << *this << tColoredString::ColorString(1,1,1);
04971
04972 tOutput message;
04973 message.SetTemplateParameter(1, name);
04974 message.SetTemplateParameter(2, points > 0 ? points : -points);
04975
04976
04977 if (points>0)
04978 {
04979 if (reasonwin.IsEmpty())
04980 message << "$player_win_default";
04981 else
04982 message.Append(reasonwin);
04983 }
04984 else
04985 {
04986 if (reasonlose.IsEmpty())
04987 message << "$player_lose_default";
04988 else
04989 message.Append(reasonlose);
04990 }
04991
04992 sn_ConsoleOut(message);
04993 RequestSync(true);
04994
04995 se_SaveToScoreFile(message);
04996 }
04997
04998
04999
05000
05001 int ePlayerNetID::TotalScore() const
05002 {
05003 if ( currentTeam )
05004 {
05005 return score;
05006 }
05007 else
05008 {
05009 return score;
05010 }
05011 }
05012
05013
05014 void ePlayerNetID::SwapPlayersNo(int a,int b){
05015 if (0>a || se_PlayerNetIDs.Len()<=a)
05016 return;
05017 if (0>b || se_PlayerNetIDs.Len()<=b)
05018 return;
05019 if (a==b)
05020 return;
05021
05022 ePlayerNetID *A=se_PlayerNetIDs(a);
05023 ePlayerNetID *B=se_PlayerNetIDs(b);
05024
05025 se_PlayerNetIDs(b)=A;
05026 se_PlayerNetIDs(a)=B;
05027 A->listID=b;
05028 B->listID=a;
05029 }
05030
05031
05032 void ePlayerNetID::SortByScore(){
05033
05034
05035 bool inorder=false;
05036 while (!inorder){
05037 inorder=true;
05038 int i;
05039 for(i=se_PlayerNetIDs.Len()-2;i>=0;i--)
05040 if (se_PlayerNetIDs(i)->TotalScore() < se_PlayerNetIDs(i+1)->TotalScore() ){
05041 SwapPlayersNo(i,i+1);
05042 inorder=false;
05043 }
05044 }
05045 }
05046
05047 void ePlayerNetID::ResetScore(){
05048 int i;
05049 for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){
05050 se_PlayerNetIDs(i)->score=0;
05051 if (sn_GetNetState()==nSERVER)
05052 se_PlayerNetIDs(i)->RequestSync();
05053 }
05054
05055 for(i=eTeam::teams.Len()-1;i>=0;i--){
05056 eTeam::teams(i)->ResetScore();
05057 if (sn_GetNetState()==nSERVER)
05058 eTeam::teams(i)->RequestSync();
05059 }
05060
05061 ResetScoreDifferences();
05062 }
05063
05064 void ePlayerNetID::DisplayScores(){
05065 sr_ResetRenderState(true);
05066
05067 REAL W=sr_screenWidth;
05068 REAL H=sr_screenHeight;
05069
05070 REAL MW=400;
05071 REAL MH=(MW*3)/4;
05072
05073 if(W>MW)
05074 W=MW;
05075
05076 if(H>MH)
05077 H=MH;
05078
05079 #ifndef DEDICATED
05080 if (sr_glOut){
05081 ::Color(1,1,1);
05082 float y=.6;
05083
05084
05085 int maxPlayers = 20;
05086 bool showTeam = false;
05087 for ( int i = eTeam::teams.Len() - 1; i >= 0; --i )
05088 {
05089 if ( eTeam::teams[i]->NumPlayers() > 1 ||
05090 ( eTeam::teams[i]->NumPlayers() == 1 && eTeam::teams[i]->Player(0)->Score() != eTeam::teams[i]->Score() ) )
05091 {
05092 y = eTeam::RankingGraph(y);
05093 y-=.06;
05094 maxPlayers -= ( eTeam::teams.Len() > 6 ? 6 : eTeam::teams.Len() ) + 2;
05095 showTeam = true;
05096 break;
05097 }
05098 }
05099
05100
05101 RankingGraph( y , maxPlayers );
05102 }
05103 #endif
05104 }
05105
05106
05107 tString ePlayerNetID::Ranking( int MAX, bool cut ){
05108 SortByScore();
05109
05110 tString ret;
05111
05112 if (se_PlayerNetIDs.Len()>0){
05113 ret << tOutput("$player_scoretable_name");
05114 ret.SetPos(17, cut );
05115 ret << tOutput("$player_scoretable_alive");
05116 ret.SetPos(24, cut );
05117 ret << tOutput("$player_scoretable_score");
05118 ret.SetPos(31, cut );
05119 ret << tOutput("$player_scoretable_ping");
05120 ret.SetPos(37, cut );
05121 ret << tOutput("$player_scoretable_team");
05122 ret.SetPos(53, cut );
05123 ret << "\n";
05124
05125 int max = se_PlayerNetIDs.Len();
05126
05127
05128
05129 if ( MAX == max + 1 )
05130 MAX = max;
05131
05132 if ( max > MAX && MAX > 0 )
05133 {
05134 max = MAX ;
05135 }
05136
05137 for(int i=0;i<max;i++){
05138 tColoredString line;
05139 ePlayerNetID *p=se_PlayerNetIDs(i);
05140
05141
05142
05143
05144
05145
05146
05147 line << *p;
05148 line.SetPos(17, false );
05149 if ( p->Object() && p->Object()->Alive() )
05150 {
05151 line << tOutput("$player_scoretable_alive_yes");
05152 }
05153 else
05154 {
05155 line << tOutput("$player_scoretable_alive_no");
05156 }
05157 line.SetPos(24, cut );
05158 line << p->score;
05159
05160 if (p->IsActive())
05161 {
05162 line.SetPos(31, cut );
05163
05164 line << int(p->ping*1000);
05165 line.SetPos(37, cut );
05166 if ( p->currentTeam )
05167 {
05168
05169
05170 line << tColoredString::RemoveColors(p->currentTeam->Name());
05171 line.SetPos(53, cut );
05172 }
05173 }
05174 else
05175 line << tOutput("$player_scoretable_inactive");
05176 ret << line << "\n";
05177 }
05178 if ( max < se_PlayerNetIDs.Len() )
05179 {
05180 ret << "...\n";
05181 }
05182
05183 }
05184 else
05185 ret << tOutput("$player_scoretable_nobody");
05186 return ret;
05187 }
05188 float ePlayerNetID::RankingGraph( float y, int MAX ){
05189 SortByScore();
05190
05191 if (se_PlayerNetIDs.Len()>0){
05192 tColoredString name;
05193 name << tColoredString::ColorString(1.,.5,.5)
05194 << tOutput("$player_scoretable_name");
05195 DisplayText(-.7, y, .06, name.c_str(), sr_fontScoretable, -1);
05196 tColoredString alive;
05197 alive << tOutput("$player_scoretable_alive");
05198 DisplayText(-.3, y, .06, alive.c_str(), sr_fontScoretable, -1);
05199 tColoredString score;
05200 score << tOutput("$player_scoretable_score");
05201 DisplayText(.05, y, .06, score.c_str(), sr_fontScoretable, 1);
05202 tColoredString ping;
05203 ping << tOutput("$player_scoretable_ping");
05204 DisplayText(.25, y, .06, ping.c_str(), sr_fontScoretable, 1);
05205 tColoredString team;
05206 team << tOutput("$player_scoretable_team");
05207 DisplayText(.3, y, .06, team.c_str(), sr_fontScoretable, -1);
05208 y-=.06;
05209
05210 int max = se_PlayerNetIDs.Len();
05211
05212
05213
05214 if ( MAX == max + 1 )
05215 MAX = max;
05216
05217 if ( max > MAX && MAX > 0 )
05218 {
05219 max = MAX ;
05220 }
05221
05222 for(int i=0;i<max;i++){
05223 ePlayerNetID *p=se_PlayerNetIDs(i);
05224 if(p->chatting_)
05225 DisplayText(-.705, y, .06, "*", sr_fontScoretable, 1);
05226 tColoredString name;
05227 name << *p;
05228 DisplayText(-.7, y, .06, name.c_str(), sr_fontScoretable, -1);
05229 tColoredString alive;
05230 if ( p->Object() && p->Object()->Alive() )
05231 {
05232 alive << tColoredString::ColorString(0,1,0)
05233 << tOutput("$player_scoretable_alive_yes");
05234 }
05235 else
05236 {
05237 alive << tColoredString::ColorString(1,0,0)
05238 << tOutput("$player_scoretable_alive_no");
05239 }
05240 DisplayText(-.3, y, .06, alive.c_str(), sr_fontScoretable, -1);
05241 tColoredString score;
05242 score << p->score;
05243 DisplayText(.05, y, .06, score.c_str(), sr_fontScoretable, 1);
05244 if (p->IsActive())
05245 {
05246 tColoredString ping;
05247 ping << int(p->ping*1000);
05248 DisplayText(.25, y, .06, ping.c_str(), sr_fontScoretable, 1);
05249 if ( p->currentTeam )
05250 {
05251 tColoredString team;
05252 eTeam *t = p->currentTeam;
05253 team << tColoredStringProxy(t->R()/15.f, t->G()/15.f, t->B()/15.f) << t->Name();
05254 DisplayText(.3, y, .06, team.c_str(), sr_fontScoretable, -1);
05255 }
05256 }
05257 else {
05258 tColoredString noone;
05259 noone << tOutput("$player_scoretable_inactive");
05260 DisplayText(.1, y, .06, noone.c_str(), sr_fontScoretable, -1);
05261 }
05262 y-=.06;
05263 }
05264 if ( max < se_PlayerNetIDs.Len() )
05265 {
05266 DisplayText(-.7, y, .06, "...", sr_fontScoretable, -1);
05267 y-=.06;
05268 }
05269
05270 }
05271 else {
05272 tColoredString noone;
05273 noone << tOutput("$player_scoretable_nobody");
05274 DisplayText(-.7, y, .06, noone.c_str(), sr_fontScoretable, -1);
05275 }
05276 return y;
05277 }
05278
05279 void ePlayerNetID::RankingLadderLog() {
05280 SortByScore();
05281
05282 int num_humans = 0;
05283 int max = se_PlayerNetIDs.Len();
05284 for(int i = 0; i < max; ++i) {
05285 ePlayerNetID *p = se_PlayerNetIDs(i);
05286 if(p->Owner() == 0) continue;
05287
05288 tString line("ONLINE_PLAYER ");
05289
05290 line << p->GetLogName();
05291
05292 if(p->IsActive()) {
05293 line << " " << p->ping;
05294 if(p->currentTeam) {
05295 line << " " << FilterName(p->currentTeam->Name());
05296 ++num_humans;
05297 }
05298 }
05299
05300 line << '\n';
05301 se_SaveToLadderLog(line);
05302 }
05303 tString line("NUM_HUMANS ");
05304 line << num_humans << '\n';
05305 se_SaveToLadderLog(line);
05306 }
05307
05308 void ePlayerNetID::ClearAll(){
05309 for(int i=MAX_PLAYERS-1;i>=0;i--){
05310 ePlayer *local_p=ePlayer::PlayerConfig(i);
05311 if (local_p)
05312 local_p->netPlayer = NULL;
05313 }
05314 }
05315
05316 static bool se_VisibleSpectatorsSupported()
05317 {
05318 static nVersionFeature se_visibleSpectator(13);
05319 return sn_GetNetState() != nCLIENT || se_visibleSpectator.Supported(0);
05320 }
05321
05322
05323 void ePlayerNetID::SpectateAll( bool spectate ){
05324 for(int i=MAX_PLAYERS-1;i>=0;i--){
05325 ePlayer *local_p=ePlayer::PlayerConfig(i);
05326 if (local_p)
05327 {
05328 if ( se_VisibleSpectatorsSupported() && bool(local_p->netPlayer) )
05329 {
05330 local_p->netPlayer->spectating_ = spectate || local_p->spectate;
05331
05332 local_p->netPlayer->RequestSync();
05333 }
05334 else
05335 local_p->netPlayer = NULL;
05336 }
05337 }
05338 }
05339
05340 void ePlayerNetID::CompleteRebuild(){
05341 ClearAll();
05342 Update();
05343 }
05344
05345 static int se_ColorDistance( int a[3], int b[3] )
05346 {
05347 int distance = 0;
05348 for( int i = 2; i >= 0; --i )
05349 {
05350 int diff = a[i] - b[i];
05351 distance += diff * diff;
05352
05353
05354
05355
05356
05357 }
05358
05359 return distance;
05360 }
05361
05362 bool se_randomizeColor = true;
05363 static tSettingItem< bool > se_randomizeColorConf( "PLAYER_RANDOM_COLOR", se_randomizeColor );
05364
05365 static void se_RandomizeColor( ePlayer * l, ePlayerNetID * p )
05366 {
05367 int currentRGB[3];
05368 int newRGB[3];
05369 int nullRGB[3]={0,0,0};
05370
05371 static tReproducibleRandomizer randomizer;
05372
05373 for( int i = 2; i >= 0; --i )
05374 {
05375 currentRGB[i] = l->rgb[i];
05376 newRGB[i] = randomizer.Get(15);
05377 }
05378
05379 int currentMinDiff = se_ColorDistance( currentRGB, nullRGB )/2;
05380 int newMinDiff = se_ColorDistance( newRGB, nullRGB )/2;
05381
05382
05383 for ( int i = se_PlayerNetIDs.Len()-1; i >= 0; --i )
05384 {
05385 ePlayerNetID * other = se_PlayerNetIDs(i);
05386 if ( other != p )
05387 {
05388 int color[3] = { other->r, other->g, other->b };
05389 int currentDiff = se_ColorDistance( currentRGB, color );
05390 int newDiff = se_ColorDistance( newRGB, color );
05391 if ( currentDiff < currentMinDiff )
05392 {
05393 currentMinDiff = currentDiff;
05394 }
05395 if ( newDiff < newMinDiff )
05396 {
05397 newMinDiff = newDiff;
05398 }
05399 }
05400 }
05401
05402
05403 if ( currentMinDiff < newMinDiff )
05404 {
05405 for( int i = 2; i >= 0; --i )
05406 {
05407 l->rgb[i] = newRGB[i];
05408 }
05409 }
05410 }
05411
05412 static nSettingItem<int> se_pingCharityServerConf("PING_CHARITY_SERVER",sn_pingCharityServer );
05413 static nVersionFeature se_pingCharityServerControlled( 14 );
05414
05415 static int se_pingCharityMax = 500, se_pingCharityMin = 0;
05416 static tSettingItem<int> se_pingCharityMaxConf( "PING_CHARITY_MAX", se_pingCharityMax );
05417 static tSettingItem<int> se_pingCharityMinConf( "PING_CHARITY_MIN", se_pingCharityMin );
05418
05419
05420 void ePlayerNetID::Update(){
05421 #ifdef KRAWALL_SERVER
05422
05423 UpdateAccessLevelRequiredToPlay();
05424
05425
05426 tAccessLevel required = AccessLevelRequiredToPlay();
05427 for( int i=se_PlayerNetIDs.Len()-1; i >= 0; --i )
05428 {
05429 ePlayerNetID* player = se_PlayerNetIDs(i);
05430 if ( player->GetAccessLevel() > required && player->IsHuman() )
05431 {
05432 player->SetTeamWish(0);
05433 }
05434 }
05435 #endif
05436
05437 #ifdef DEDICATED
05438 if (sr_glOut)
05439 #endif
05440 {
05441 for(int i=0; i<MAX_PLAYERS; ++i ){
05442 bool in_game=ePlayer::PlayerIsInGame(i);
05443 ePlayer *local_p=ePlayer::PlayerConfig(i);
05444 tASSERT(local_p);
05445 tCONTROLLED_PTR(ePlayerNetID) &p=local_p->netPlayer;
05446
05447 if (!p && in_game && ( !local_p->spectate || se_VisibleSpectatorsSupported() ) )
05448 {
05449 p=tNEW(ePlayerNetID) (i);
05450 p->SetDefaultTeam();
05451 p->RequestSync();
05452 }
05453
05454 if (bool(p) && (!in_game || ( local_p->spectate && !se_VisibleSpectatorsSupported() ) ) &&
05455 p->Owner() == ::sn_myNetID )
05456 {
05457 p->RemoveFromGame();
05458
05459 if (p->object)
05460 p->object->player = NULL;
05461
05462 p->object = NULL;
05463 p = NULL;
05464 }
05465
05466 if (bool(p) && in_game){
05467 p->favoriteNumberOfPlayersPerTeam=ePlayer::PlayerConfig(i)->favoriteNumberOfPlayersPerTeam;
05468 p->nameTeamAfterMe=ePlayer::PlayerConfig(i)->nameTeamAfterMe;
05469
05470 if ( se_randomizeColor )
05471 {
05472 se_RandomizeColor(local_p,p);
05473 }
05474
05475 p->r=ePlayer::PlayerConfig(i)->rgb[0];
05476 p->g=ePlayer::PlayerConfig(i)->rgb[1];
05477 p->b=ePlayer::PlayerConfig(i)->rgb[2];
05478
05479 sg_ClampPingCharity();
05480 p->pingCharity=::pingCharity;
05481 p->SetTeamname(local_p->Teamname());
05482
05483
05484 if ( p->spectating_ != local_p->spectate )
05485 p->RequestSync();
05486 p->spectating_ = local_p->spectate;
05487
05488
05489 if ( p->stealth_ != local_p->stealth )
05490 p->RequestSync();
05491 p->stealth_ = local_p->stealth;
05492
05493
05494 tString newName( ePlayer::PlayerConfig(i)->Name() );
05495
05496 if ( ::sn_GetNetState() != nCLIENT || newName != p->nameFromClient_ )
05497 {
05498 p->RequestSync();
05499 }
05500
05501 p->SetName( ePlayer::PlayerConfig(i)->Name() );
05502 }
05503 }
05504
05505 }
05506
05507 int i;
05508
05509
05510
05511
05512 if ( sn_GetNetState() == nSERVER || !se_pingCharityServerControlled.Supported(0) )
05513 {
05514 int old_c=sn_pingCharityServer;
05515 sg_ClampPingCharity();
05516 sn_pingCharityServer=::pingCharity;
05517
05518 #ifndef DEDICATED
05519 if (sn_GetNetState()==nCLIENT)
05520 #endif
05521 sn_pingCharityServer+=100000;
05522
05523
05524 if ( se_pingCharityServerControlled.Supported() )
05525 {
05526 sn_pingCharityServer = se_pingCharityMax;
05527 }
05528
05529 for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){
05530 ePlayerNetID *pni=se_PlayerNetIDs(i);
05531 pni->UpdateName();
05532 int new_ps=pni->pingCharity;
05533 new_ps+=int(pni->ping*500);
05534
05535
05536 if ( sn_GetNetState() != nSERVER || pni->currentTeam || pni->nextTeam )
05537 if (new_ps < sn_pingCharityServer)
05538 sn_pingCharityServer=new_ps;
05539 }
05540 if (sn_pingCharityServer<0)
05541 sn_pingCharityServer=0;
05542
05543
05544 if ( se_pingCharityServerControlled.Supported() )
05545 {
05546 if ( sn_pingCharityServer < se_pingCharityMin )
05547 sn_pingCharityServer = se_pingCharityMin;
05548 }
05549
05550 if (old_c!=sn_pingCharityServer)
05551 {
05552 tOutput o;
05553 o.SetTemplateParameter(1, old_c);
05554 o.SetTemplateParameter(2, sn_pingCharityServer);
05555 o << "$player_pingcharity_changed";
05556 con << o;
05557
05558
05559 if (sn_GetNetState()==nSERVER)
05560 se_pingCharityServerConf.nConfItemBase::WasChanged(true);
05561 }
05562 }
05563
05564
05565 bool assigned = true;
05566 while ( assigned && sn_GetNetState() != nCLIENT )
05567 {
05568 assigned = false;
05569
05570 int players = se_PlayerNetIDs.Len();
05571
05572
05573 for( i=0; i<players; ++i )
05574 {
05575 ePlayerNetID* player = se_PlayerNetIDs(i);
05576
05577
05578 if ( player->NextTeam() != player->CurrentTeam() && player->TeamChangeAllowed() &&
05579 ( !player->NextTeam() || player->NextTeam()->PlayerMayJoin( player ) )
05580 )
05581 {
05582 player->UpdateTeam();
05583 if ( player->NextTeam() == player->CurrentTeam() )
05584 assigned = true;
05585 }
05586 }
05587
05588
05589 if ( !assigned )
05590 {
05591 for( i=players-1; i>=0; --i )
05592 {
05593 ePlayerNetID* player = se_PlayerNetIDs(i);
05594
05595
05596 if ( player->NextTeam() && !player->CurrentTeam() && player->TeamChangeAllowed() )
05597 {
05598 eTeam * wish = player->NextTeam();
05599 bool assignBack = se_assignTeamAutomatically;
05600 se_assignTeamAutomatically = true;
05601 player->FindDefaultTeam();
05602 se_assignTeamAutomatically = assignBack;
05603 player->SetTeamForce( wish );
05604
05605 if ( player->CurrentTeam() )
05606 {
05607 assigned = true;
05608 break;
05609 }
05610 }
05611 }
05612 }
05613 }
05614
05615 if ( sn_GetNetState() != nCLIENT )
05616 {
05617 for(i=se_PlayerNetIDs.Len()-1;i>=0;i--)
05618 {
05619 ePlayerNetID* player = se_PlayerNetIDs(i);
05620
05621
05622 if ( player->NextTeam() != player->CurrentTeam() && player->NextTeam() )
05623 {
05624
05625 if(!player->TeamChangeAllowed()) {
05626 player->SetTeam( player->CurrentTeam() );
05627 continue;
05628 }
05629
05630 tOutput message( "$player_joins_team_wish",
05631 player->GetName(),
05632 player->NextTeam()->Name() );
05633
05634 sn_ConsoleOut( message );
05635
05636
05637
05638 if ( eTeam::maxPlayers <= 1 )
05639 player->SetTeam( player->CurrentTeam() );
05640 }
05641 }
05642 }
05643
05644
05645 for (i=eTeam::teams.Len()-1; i>=0; --i)
05646 {
05647 eTeam::teams(i)->UpdateProperties();
05648 }
05649
05650
05651 nNetObject::ClearAllDeleted();
05652 }
05653
05654
05655 static REAL se_playerWaitMax = 10.0f;
05656 static tSettingItem< REAL > se_playerWaitMaxConf( "PLAYER_CHAT_WAIT_MAX", se_playerWaitMax );
05657
05658
05659 static REAL se_playerWaitFraction = .05f;
05660 static tSettingItem< REAL > se_playerWaitFractionConf( "PLAYER_CHAT_WAIT_FRACTION", se_playerWaitFraction );
05661
05662
05663 static bool se_playerWaitSingle = false;
05664 static tSettingItem< bool > se_playerWaitSingleConf( "PLAYER_CHAT_WAIT_SINGLE", se_playerWaitSingle );
05665
05666
05667 static bool se_playerWaitTeamleader = true;
05668 static tSettingItem< bool > se_playerWaitTeamleaderConf( "PLAYER_CHAT_WAIT_TEAMLEADER", se_playerWaitTeamleader );
05669
05670
05671 bool ePlayerNetID::WaitToLeaveChat()
05672 {
05673 static bool lastReturn = false;
05674 static double lastTime = 0;
05675 static ePlayerNetID * lastPlayer = 0;
05676 double time = tSysTimeFloat();
05677 REAL dt = time - lastTime;
05678 bool ret = false;
05679
05680 if ( !lastReturn )
05681 {
05682
05683 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
05684 {
05685 ePlayerNetID* player = se_PlayerNetIDs(i);
05686 if ( dt > 1.0 || !player->chatting_ )
05687 {
05688 player->wait_ += se_playerWaitFraction * dt;
05689 if ( player->wait_ > se_playerWaitMax )
05690 {
05691 player->wait_ = se_playerWaitMax;
05692 }
05693 }
05694 }
05695
05696 if ( dt > 1.0 )
05697 lastPlayer = 0;
05698
05699 dt = 0;
05700 }
05701
05702
05703 ePlayerNetID * maxPlayer = 0;
05704 REAL maxWait = .2;
05705
05706
05707 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
05708 {
05709 ePlayerNetID* player = se_PlayerNetIDs(i);
05710 if ( player->CurrentTeam() && player->chatting_ && ( !se_playerWaitTeamleader || player->CurrentTeam()->OldestHumanPlayer() == player ) )
05711 {
05712
05713 if ( !se_playerWaitSingle )
05714 {
05715 player->wait_ -= dt;
05716
05717
05718 if ( player->wait_ > 0 )
05719 {
05720 ret = true;
05721 }
05722 else
05723 {
05724 player->wait_ = 0;
05725 }
05726 }
05727
05728
05729 if ( ( maxPlayer != lastPlayer || NULL == maxPlayer ) && ( player->wait_ > maxWait || player == lastPlayer ) && player->wait_ > 0 )
05730 {
05731 maxWait = player->wait_;
05732 maxPlayer = player;
05733 }
05734 }
05735 }
05736
05737
05738 if ( se_playerWaitSingle && maxPlayer )
05739 {
05740 maxPlayer->wait_ -= dt;
05741
05742
05743 if ( maxPlayer->wait_ < 0 )
05744 {
05745 maxPlayer->wait_ = 0;
05746 }
05747 }
05748
05749 static double lastPrint = -2;
05750
05751
05752 if ( maxPlayer && maxPlayer != lastPlayer && tSysTimeFloat() - lastPrint > 1 )
05753 {
05754 sn_ConsoleOut( tOutput( "$gamestate_chat_wait", maxPlayer->GetName(), int(10*maxPlayer->wait_)*.1f ) );
05755 lastPlayer = maxPlayer;
05756 }
05757
05758 if ( lastPlayer == maxPlayer )
05759 {
05760 lastPrint = tSysTimeFloat();
05761 }
05762
05763
05764 lastReturn = ret;
05765 lastTime = time;
05766
05767 return ret;
05768 }
05769
05770
05771 static REAL se_chatterRemoveTime = 180.0;
05772 static tSettingItem< REAL > se_chatterRemoveTimeConf( "CHATTER_REMOVE_TIME", se_chatterRemoveTime );
05773
05774
05775 static REAL se_idleRemoveTime = 0;
05776 static tSettingItem< REAL > se_idleRemoveTimeConf( "IDLE_REMOVE_TIME", se_idleRemoveTime );
05777
05778
05779 static REAL se_idleKickTime = 0;
05780 static tSettingItem< REAL > se_idleKickTimeConf( "IDLE_KICK_TIME", se_idleKickTime );
05781
05782
05783 void ePlayerNetID::RemoveChatbots()
05784 {
05785
05786 if ( nCLIENT == sn_GetNetState() )
05787 return;
05788
05789 #ifdef KRAWALL_SERVER
05790
05791 UpdateAccessLevelRequiredToPlay();
05792 #endif
05793
05794
05795 static double lastTime = 0;
05796 double currentTime = tSysTimeFloat();
05797 REAL roundTime = currentTime - lastTime;
05798 lastTime = currentTime;
05799
05800
05801 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
05802 {
05803 ePlayerNetID *p = se_PlayerNetIDs(i);
05804 if ( p && p->IsHuman() )
05805 {
05806
05807 REAL idleTime = p->IsChatting() ? se_chatterRemoveTime : se_idleRemoveTime;
05808
05809
05810 bool shouldHaveTeam = idleTime <= 0 || p->LastActivity() - roundTime < idleTime;
05811 shouldHaveTeam &= !p->IsSpectating();
05812
05813 tColoredString name;
05814 name << *p << tColoredString::ColorString(1,.5,.5);
05815
05816
05817 if ( shouldHaveTeam )
05818 {
05819 if ( !p->CurrentTeam() )
05820 {
05821 p->SetDefaultTeam();
05822 }
05823 }
05824 else
05825 {
05826 if ( p->CurrentTeam() )
05827 {
05828 p->SetTeam( NULL );
05829 p->UpdateTeam();
05830 }
05831 }
05832
05833
05834 if ( se_idleKickTime > 0 && se_idleKickTime < p->LastActivity() - roundTime )
05835 {
05836 sn_KickUser( p->Owner(), tOutput( "$network_kill_idle" ) );
05837
05838
05839 if ( i >= se_PlayerNetIDs.Len() )
05840 i = se_PlayerNetIDs.Len()-1;
05841 }
05842 }
05843 }
05844 }
05845
05846 void ePlayerNetID::ThrowOutDisconnected()
05847 {
05848 int i;
05849
05850
05851 for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){
05852 ePlayerNetID *pni=se_PlayerNetIDs(i);
05853 if (pni->disconnected)
05854 {
05855
05856 se_PlayerNetIDs.Remove(pni, pni->listID);
05857 }
05858 }
05859
05860 se_PlayerReferences.ReleaseAll();
05861 }
05862
05863 void ePlayerNetID::GetScoreFromDisconnectedCopy()
05864 {
05865 int i;
05866
05867 for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){
05868 ePlayerNetID *pni=se_PlayerNetIDs(i);
05869 if (pni->disconnected && pni->GetUserName() == GetUserName() && pni->Owner() == 0)
05870 {
05871 #ifdef DEBUG
05872 con << GetName() << " reconnected.\n";
05873 #endif
05874
05875 pni->RequestSync();
05876 RequestSync();
05877
05878 score = pni->score;
05879
05880 ControlObject(pni->Object());
05881
05882 pni->object = NULL;
05883
05884 if (bool(object))
05885 chatting_ = true;
05886
05887 pni->disconnected = false;
05888 se_PlayerNetIDs.Remove(pni, pni->listID);
05889 se_PlayerReferences.Remove( pni );
05890 }
05891 }
05892 }
05893
05894
05895 static bool show_scores=false;
05896 static bool ass=true;
05897
05898 void se_AutoShowScores(){
05899 if (ass)
05900 show_scores=true;
05901 }
05902
05903
05904 void se_UserShowScores(bool show){
05905 show_scores=show;
05906 }
05907
05908 void se_SetShowScoresAuto(bool a){
05909 ass=a;
05910 }
05911
05912
05913 static void scores(){
05914 if (show_scores){
05915 if ( se_mainGameTimer )
05916 ePlayerNetID::DisplayScores();
05917 else
05918 show_scores = false;
05919 }
05920 }
05921
05922
05923 static rPerFrameTask pf(&scores);
05924
05925 static bool force_small_cons(){
05926 return show_scores;
05927 }
05928
05929 static rSmallConsoleCallback sc(&force_small_cons);
05930
05931 static void cd(){
05932 show_scores = false;
05933 }
05934
05935
05936
05937 static uActionGlobal score("SCORE");
05938
05939
05940 static bool sf(REAL x){
05941 if (x>0) show_scores = !show_scores;
05942 return true;
05943 }
05944
05945 static uActionGlobalFunc saf(&score,&sf);
05946
05947
05948 static rCenterDisplayCallback c_d(&cd);
05949
05950 tOutput& operator << (tOutput& o, const ePlayerNetID& p)
05951 {
05952 tColoredString x;
05953 x << p;
05954 o << x;
05955 return o;
05956 }
05957
05958
05959
05960 tCallbackString *eCallbackGreeting::anchor = NULL;
05961 ePlayerNetID* eCallbackGreeting::greeted = NULL;
05962
05963 tString eCallbackGreeting::Greet(ePlayerNetID* player)
05964 {
05965 greeted = player;
05966 return Exec(anchor);
05967 }
05968
05969 eCallbackGreeting::eCallbackGreeting(STRINGRETFUNC* f)
05970 :tCallbackString(anchor, f)
05971 {
05972 }
05973
05974 void ePlayerNetID::GreetHighscores(tString &s){
05975 s << eCallbackGreeting::Greet(this);
05976
05977
05978
05979 }
05980
05981
05982
05983
05984
05985 void ePlayerNetID::SetChatting ( ChatFlags flag, bool chatting )
05986 {
05987 if ( sn_GetNetState() == nSTANDALONE && flag == ChatFlags_Menu )
05988 {
05989 chatting = false;
05990 }
05991
05992 if ( chatting )
05993 {
05994 chatFlags_ |= flag;
05995 if ( !chatting_ )
05996 this->RequestSync();
05997
05998 chatting_ = true;
05999 }
06000 else
06001 {
06002 chatFlags_ &= ~flag;
06003 if ( 0 == chatFlags_ )
06004 {
06005 if ( chatting_ )
06006 this->RequestSync();
06007
06008 chatting_ = false;
06009 }
06010 }
06011 }
06012
06013
06014
06015
06016
06017 bool ePlayerNetID::TeamChangeAllowed( bool informPlayer ) const {
06018 if (!( allowTeamChange_ || se_allowTeamChanges ))
06019 {
06020 if ( informPlayer )
06021 {
06022 sn_ConsoleOut(tOutput("$player_teamchanges_disallowed"), Owner());
06023 }
06024 return false;
06025 }
06026
06027 int suspended = GetSuspended();
06028 if ( suspended > 0 )
06029 {
06030 if ( informPlayer )
06031 {
06032 sn_ConsoleOut(tOutput("$player_teamchanges_suspended", suspended ), Owner());
06033 }
06034 return false;
06035 }
06036
06037 #ifdef KRAWALL_SERVER
06038
06039 if (!( GetAccessLevel() <= AccessLevelRequiredToPlay() || CurrentTeam() ))
06040 {
06041 if ( informPlayer )
06042 {
06043 sn_ConsoleOut(tOutput("$player_teamchanges_accesslevel",
06044 tCurrentAccessLevel::GetName( GetAccessLevel() ),
06045 tCurrentAccessLevel::GetName( AccessLevelRequiredToPlay() ) ),
06046 Owner());
06047 }
06048 return false;
06049 }
06050 #endif
06051
06052 return true;
06053 }
06054
06055
06056 void ePlayerNetID::SetDefaultTeam( )
06057 {
06058
06059 if ( sn_GetNetState() == nCLIENT || !se_assignTeamAutomatically || spectating_ || !TeamChangeAllowed() )
06060 return;
06061
06062
06063
06064
06065
06066
06067
06068 eTeam* defaultTeam = FindDefaultTeam();
06069 if (defaultTeam)
06070 SetTeamWish(defaultTeam);
06071 else if ( eTeam::NewTeamAllowed() )
06072 CreateNewTeamWish();
06073
06074
06075 }
06076
06077
06078 eTeam* ePlayerNetID::FindDefaultTeam( )
06079 {
06080
06081 eTeam *min = NULL;
06082 for ( int i=eTeam::teams.Len()-1; i>=0; --i )
06083 {
06084 eTeam *t = eTeam::teams( i );
06085 if ( t->IsHuman() && ( !min || min->NumHumanPlayers() > t->NumHumanPlayers() ) )
06086 min = t;
06087 }
06088
06089 if ( min &&
06090
06091 eTeam::teams.Len() >= eTeam::minTeams &&
06092 min->PlayerMayJoin( this ) &&
06093
06094 ( !eTeam::NewTeamAllowed() || ( min->NumHumanPlayers() > 0 && min->NumHumanPlayers() < favoriteNumberOfPlayersPerTeam ) )
06095 )
06096 {
06097
06098 return min;
06099 }
06100
06101 return NULL;
06102 }
06103
06104
06105 void ePlayerNetID::SetTeam( eTeam* newTeam )
06106 {
06107
06108 tASSERT ( !newTeam || nCLIENT != sn_GetNetState() );
06109
06110 SetTeamForce( newTeam );
06111
06112 if (newTeam && ( !newTeam->PlayerMayJoin( this ) || IsSpectating() ) )
06113 {
06114 tOutput message;
06115 message.SetTemplateParameter( 1, GetName() );
06116 if ( newTeam )
06117 message.SetTemplateParameter(2, newTeam->Name() );
06118 else
06119 message.SetTemplateParameter(2, "NULL");
06120 message << "$player_nojoin_team";
06121
06122 sn_ConsoleOut( message, Owner() );
06123
06124 }
06125 }
06126
06127
06128 void ePlayerNetID::SetTeamname(const char* newTeamname)
06129 {
06130 teamname = newTeamname;
06131 if (bool(currentTeam) && currentTeam->OldestHumanPlayer() &&
06132 currentTeam->OldestHumanPlayer()->ID()==ID())
06133 {
06134 currentTeam->UpdateAppearance();
06135 }
06136 }
06137
06138
06139 void ePlayerNetID::SetTeamForce( eTeam* newTeam )
06140 {
06141
06142
06143 #ifdef DEBUG
06144 std::cout << "DEBUG: Player:" << this->GetName() << " SetTeamForce:" << ((newTeam)?(const char*)newTeam->Name():"NULL") << "\n";
06145 #endif
06146 nextTeam = newTeam;
06147 }
06148
06149
06150 void ePlayerNetID::UpdateTeam()
06151 {
06152
06153 if ( nextTeam == currentTeam )
06154 {
06155 return;
06156 }
06157
06158
06159 if ( nCLIENT == sn_GetNetState() )
06160 {
06161 return;
06162 }
06163
06164 if ( bool( nextTeam ) && !nextTeam->PlayerMayJoin( this ) )
06165 {
06166 tOutput message;
06167 message.SetTemplateParameter(1, GetName() );
06168 if ( nextTeam )
06169 message.SetTemplateParameter(2, nextTeam->Name() );
06170 else
06171 message.SetTemplateParameter(2, "NULL");
06172 message << "$player_nojoin_team";
06173
06174 sn_ConsoleOut( message, Owner() );
06175 return;
06176 }
06177
06178 UpdateTeamForce();
06179 }
06180
06181 void ePlayerNetID::UpdateTeamForce()
06182 {
06183
06184 if ( nextTeam == currentTeam )
06185 {
06186 return;
06187 }
06188
06189 eTeam *oldTeam = currentTeam;
06190
06191 if ( nextTeam )
06192 nextTeam->AddPlayer ( this );
06193 else if ( oldTeam )
06194 oldTeam->RemovePlayer( this );
06195
06196 if( nCLIENT != sn_GetNetState() && GetRefcount() > 0 )
06197 {
06198 RequestSync();
06199 }
06200 }
06201
06202
06203 ePlayerNetID::eTeamSet const & ePlayerNetID::GetInvitations() const
06204 {
06205 return invitations_;
06206 }
06207
06208
06209 void ePlayerNetID::CreateNewTeam()
06210 {
06211
06212 tASSERT ( nCLIENT != sn_GetNetState() );
06213
06214 if(!TeamChangeAllowed( true )) {
06215 return;
06216 }
06217
06218 if ( !eTeam::NewTeamAllowed() ||
06219 ( bool( currentTeam ) && ( currentTeam->NumHumanPlayers() == 1 ) ) ||
06220 IsSpectating() )
06221 {
06222 tOutput message;
06223 message.SetTemplateParameter(1, GetName() );
06224 message << "$player_nocreate_team";
06225
06226 sn_ConsoleOut( message, Owner() );
06227
06228
06229
06230
06231
06232
06233
06234
06235 return;
06236 }
06237
06238
06239 tJUST_CONTROLLED_PTR< eTeam > newTeam = tNEW( eTeam );
06240 nextTeam = newTeam;
06241 nextTeam->AddScore( score );
06242
06243
06244 if ( !currentTeam )
06245 {
06246 UpdateTeam();
06247 }
06248 }
06249
06250 const unsigned short TEAMCHANGE = 0;
06251 const unsigned short NEW_TEAM = 1;
06252
06253
06254
06255 void ePlayerNetID::SetTeamWish(eTeam* newTeam)
06256 {
06257 if (NextTeam()==newTeam)
06258 return;
06259
06260 if ( nSERVER == sn_GetNetState() && newTeam==NULL && CurrentTeam()!=NULL && NextTeam()!=NULL)
06261 {
06262 if ( se_assignTeamAutomatically )
06263 {
06264 sn_ConsoleOut("$no_spectators_allowed", Owner() );
06265 return;
06266 }
06267
06268 eTeam * leftTeam = NextTeam();
06269 if ( leftTeam )
06270 {
06271 if ( !leftTeam )
06272 leftTeam = CurrentTeam();
06273
06274 if ( leftTeam->NumPlayers() > 1 )
06275 {
06276 sn_ConsoleOut( tOutput( "$player_leave_team_wish",
06277 tColoredString::RemoveColors(GetName()),
06278 tColoredString::RemoveColors(leftTeam->Name()) ) );
06279 }
06280 else
06281 {
06282 sn_ConsoleOut( tOutput( "$player_leave_game_wish",
06283 tColoredString::RemoveColors(GetName()) ) );
06284 }
06285 }
06286 }
06287 if ( nCLIENT == sn_GetNetState() && Owner() == sn_myNetID )
06288 {
06289 nMessage* m = NewControlMessage();
06290
06291 (*m) << TEAMCHANGE;
06292 (*m) << newTeam;
06293
06294 m->BroadCast();
06295
06296 SetTeamForce( newTeam );
06297 }
06298 else
06299 {
06300 SetTeam( newTeam );
06301
06302
06303 if (!currentTeam)
06304 UpdateTeam();
06305 }
06306 }
06307
06308
06309 void ePlayerNetID::CreateNewTeamWish()
06310 {
06311 if ( nCLIENT == sn_GetNetState() )
06312 {
06313 nMessage* m = NewControlMessage();
06314
06315 (*m) << NEW_TEAM;
06316
06317 m->BroadCast();
06318 }
06319 else
06320
06321 CreateNewTeam();
06322 }
06323
06324
06325 void ePlayerNetID::ReceiveControlNet(nMessage &m)
06326 {
06327 short messageType;
06328 m >> messageType;
06329
06330 switch (messageType)
06331 {
06332 case NEW_TEAM:
06333 {
06334
06335 CreateNewTeam();
06336
06337 if (se_assignTeamAutomatically && NextTeam()==NULL)
06338 SetDefaultTeam();
06339
06340 break;
06341 }
06342 case TEAMCHANGE:
06343 {
06344 eTeam *newTeam;
06345
06346 m >> newTeam;
06347
06348 if(!TeamChangeAllowed( true )) {
06349 break;
06350 }
06351
06352
06353 if ( bool(newTeam) && newTeam->TeamID() < 0 )
06354 newTeam = 0;
06355
06356
06357
06358 if ( !newTeam )
06359 {
06360 if ( currentTeam )
06361 sn_ConsoleOut( tOutput( "$player_joins_team_noex" ), Owner() );
06362 break;
06363 }
06364
06365
06366 bool redundant = ( nextTeam == newTeam );
06367 bool obnoxious = ( nextTeam != currentTeam || redundant );
06368
06369 SetTeam( newTeam );
06370
06371
06372 if ( bool(nextTeam) && !redundant )
06373 {
06374 tOutput message;
06375 message.SetTemplateParameter(1, tColoredString::RemoveColors(GetName()));
06376 message.SetTemplateParameter(2, tColoredString::RemoveColors(nextTeam->Name()) );
06377 message << "$player_joins_team";
06378
06379 sn_ConsoleOut( message );
06380
06381
06382 if ( obnoxious )
06383 chatSpam_.CheckSpam( 4.0, Owner(), tOutput("$spam_teamchage") );
06384 }
06385
06386 break;
06387 }
06388 default:
06389 {
06390 tASSERT(0);
06391 }
06392 }
06393 }
06394
06395 void ePlayerNetID::Color( REAL&a_r, REAL&a_g, REAL&a_b ) const
06396 {
06397 if ( ( static_cast<bool>(currentTeam) ) && ( currentTeam->IsHuman() ) )
06398 {
06399 REAL w = 5;
06400 REAL r_w = 2;
06401 REAL g_w = 1;
06402 REAL b_w = 2;
06403
06404 int r = this->r;
06405 int g = this->g;
06406 int b = this->b;
06407
06408
06409 if ( currentTeam->NumPlayers() > 1 )
06410 {
06411 if ( r > 15 )
06412 r = 15;
06413 if ( g > 15 )
06414 g = 15;
06415 if ( b > 15 )
06416 b = 15;
06417 }
06418
06419 a_r=(r_w*r + w*currentTeam->R())/( 15.0 * ( w + r_w ) );
06420 a_g=(g_w*g + w*currentTeam->G())/( 15.0 * ( w + g_w ) );
06421 a_b=(b_w*b + w*currentTeam->B())/( 15.0 * ( w + b_w ) );
06422 }
06423 else
06424 {
06425 a_r = r/15.0;
06426 a_g = g/15.0;
06427 a_b = b/15.0;
06428 }
06429 }
06430
06431 void ePlayerNetID::TrailColor( REAL&a_r, REAL&a_g, REAL&a_b ) const
06432 {
06433 Color( a_r, a_g, a_b );
06434
06435
06436
06437
06438
06439
06440
06441
06442
06443
06444
06445
06446
06447
06448
06449
06450 }
06451
06452
06453
06454
06455
06456
06457
06458
06459
06460
06461
06462
06463
06464
06465 static unsigned short se_ReadUser( std::istream &s, ePlayerNetID * requester = 0 )
06466 {
06467
06468 tString name;
06469 s >> name;
06470
06471
06472 int num;
06473 if ( name.Convert(num) && num >= 1 && num <= MAXCLIENTS && sn_Connections[num].socket )
06474 {
06475 return num;
06476 }
06477 else
06478 {
06479
06480 ePlayerNetID * p = ePlayerNetID::FindPlayerByName( name, requester );
06481 if ( p )
06482 {
06483 return p->Owner();
06484 }
06485 }
06486
06487 return 0;
06488 }
06489
06490
06491
06492 static bool se_NeedsServer(char const * command, std::istream & s, bool strict = true )
06493 {
06494 if ( sn_GetNetState() != nSERVER && ( strict || sn_GetNetState() != nSTANDALONE ) )
06495 {
06496 tString rest;
06497 rest.ReadLine( s );
06498 con << tOutput("$only_works_on_server", command, rest );
06499 return true;
06500 }
06501
06502 return false;
06503 }
06504
06505 static void se_PlayerMessageConf(std::istream &s)
06506 {
06507 if ( se_NeedsServer( "PLAYER_MESSAGE", s ) )
06508 {
06509 return;
06510 }
06511
06512 int receiver = se_ReadUser( s );
06513
06514 tColoredString msg;
06515 msg.ReadLine(s);
06516
06517 if ( receiver <= 0 || s.good() )
06518 {
06519 con << "Usage: PLAYER_MESSAGE <user ID or name> <Message>\n";
06520 return;
06521 }
06522
06523 msg << '\n';
06524
06525 sn_ConsoleOut(msg, 0);
06526 sn_ConsoleOut(msg, receiver);
06527 }
06528
06529 static tConfItemFunc se_PlayerMessage_c("PLAYER_MESSAGE", &se_PlayerMessageConf);
06530 static tAccessLevelSetter se_messConfLevel( se_PlayerMessage_c, tAccessLevel_Moderator );
06531
06532 static tString se_defaultKickReason("");
06533 static tConfItemLine se_defaultKickReasonConf( "DEFAULT_KICK_REASON", se_defaultKickReason );
06534
06535 static void se_KickConf(std::istream &s)
06536 {
06537 if ( se_NeedsServer( "KICK", s ) )
06538 {
06539 return;
06540 }
06541
06542
06543 int num = se_ReadUser( s );
06544
06545 tString reason = se_defaultKickReason;
06546 if ( !s.eof() )
06547 reason.ReadLine(s);
06548
06549
06550 if ( num > 0 && !s.good() )
06551 {
06552 sn_KickUser( num , reason.Len() > 1 ? static_cast< char const *>( reason ) : "$network_kill_kick" );
06553 }
06554 else
06555 {
06556 con << "Usage: KICK <user ID or name> <Reason>\n";
06557 return;
06558 }
06559 }
06560
06561 static tConfItemFunc se_kickConf("KICK",&se_KickConf);
06562 static tAccessLevelSetter se_kickConfLevel( se_kickConf, tAccessLevel_Moderator );
06563
06564 static tString se_defaultKickToServer("");
06565 static int se_defaultKickToPort = 4534;
06566 static tString se_defaultKickToReason("");
06567
06568 static tSettingItem< tString > se_defaultKickToServerConf( "DEFAULT_KICK_TO_SERVER", se_defaultKickToServer );
06569 static tSettingItem< int > se_defaultKickToPortConf( "DEFAULT_KICK_TO_PORT", se_defaultKickToPort );
06570 static tConfItemLine se_defaultKickToReasonConf( "DEFAULT_KICK_TO_REASON", se_defaultKickToReason );
06571
06572 static void se_MoveToConf(std::istream &s, REAL severity )
06573 {
06574 if ( se_NeedsServer( "KICK/MOVE_TO", s ) )
06575 {
06576 return;
06577 }
06578
06579
06580 int num = se_ReadUser( s );
06581
06582
06583 tString server = se_defaultKickToServer;
06584 if ( !s.eof() )
06585 {
06586 s >> server;
06587 }
06588
06589 int port = se_defaultKickToPort;
06590 if ( !s.eof() )
06591 s >> port;
06592
06593 nServerInfoRedirect redirect( server, port );
06594
06595 tString reason = se_defaultKickToReason;
06596 if ( !s.eof() )
06597 reason.ReadLine(s);
06598
06599
06600 if ( num > 0 && !s.good() )
06601 {
06602 sn_KickUser( num , reason.Len() > 1 ? static_cast< char const *>( reason ) : "$network_kill_kick", severity, &redirect );
06603 }
06604 else
06605 {
06606 con << "Usage: KICK_TO <user ID or name> <server IP to kick to>:<server port to kick to> <Reason>\n";
06607 return;
06608 }
06609 }
06610
06611 static void se_KickToConf(std::istream &s )
06612 {
06613 se_MoveToConf( s, 1 );
06614 }
06615
06616 static tConfItemFunc se_kickToConf("KICK_TO",&se_KickToConf);
06617 static tAccessLevelSetter se_kickToConfLevel( se_kickToConf, tAccessLevel_Moderator );
06618
06619 static void se_MoveToConf(std::istream &s )
06620 {
06621 se_MoveToConf( s, 0 );
06622 }
06623
06624 static tConfItemFunc se_moveToConf("MOVE_TO",&se_MoveToConf);
06625 static tAccessLevelSetter se_moveConfLevel( se_moveToConf, tAccessLevel_Moderator );
06626
06627 static void se_BanConf(std::istream &s)
06628 {
06629 if ( se_NeedsServer( "BAN", s ) )
06630 {
06631 return;
06632 }
06633
06634
06635 int num = se_ReadUser( s );
06636
06637 if ( num == 0 && !s.good() )
06638 {
06639 con << "Usage: BAN <user ID or name> <time in minutes(defaults to 60)> <Reason>\n";
06640 return;
06641 }
06642
06643
06644 REAL banTime = 60;
06645 s >> banTime;
06646 std::ws(s);
06647
06648 tString reason;
06649 reason.ReadLine(s);
06650
06651
06652 if ( num > 0 )
06653 {
06654 nMachine::GetMachine( num ).Ban( banTime * 60, reason );
06655 sn_DisconnectUser( num , reason.Len() > 1 ? static_cast< char const *>( reason ) : "$network_kill_kick" );
06656 }
06657 }
06658
06659 static tConfItemFunc se_banConf("BAN",&se_BanConf);
06660 static tAccessLevelSetter se_banConfLevel( se_banConf, tAccessLevel_Moderator );
06661
06662 static ePlayerNetID * ReadPlayer( std::istream & s )
06663 {
06664
06665 tString name;
06666 s >> name;
06667
06668 int num = name.ToInt();
06669 if ( num > 0 )
06670 {
06671
06672 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
06673 {
06674 ePlayerNetID* p = se_PlayerNetIDs(i);
06675
06676
06677 if ( p->Owner() == num )
06678 {
06679 return p;
06680 }
06681 }
06682 }
06683
06684 return ePlayerNetID::FindPlayerByName( name );
06685 }
06686
06687 static void Kill_conf(std::istream &s)
06688 {
06689 if ( se_NeedsServer( "KILL", s, false ) )
06690 {
06691 return;
06692 }
06693
06694 ePlayerNetID * p = ReadPlayer( s );
06695 if ( p && p->Object() )
06696 {
06697 p->Object()->Kill();
06698 sn_ConsoleOut( tOutput( "$player_admin_kill", p->GetColoredName() ) );
06699 }
06700 }
06701
06702 static tConfItemFunc kill_conf("KILL",&Kill_conf);
06703 static tAccessLevelSetter se_killConfLevel( kill_conf, tAccessLevel_Moderator );
06704
06705 static void Suspend_conf_base(std::istream &s, int rounds )
06706 {
06707 if ( se_NeedsServer( "SUSPEND", s, false ) )
06708 {
06709 return;
06710 }
06711
06712 ePlayerNetID * p = ReadPlayer( s );
06713
06714 if ( rounds > 0 )
06715 {
06716 s >> rounds;
06717 }
06718
06719 if ( p )
06720 {
06721 p->Suspend( rounds );
06722 }
06723 }
06724
06725 static void Suspend_conf(std::istream &s )
06726 {
06727 Suspend_conf_base( s, 5 );
06728 }
06729
06730
06731 static void UnSuspend_conf(std::istream &s )
06732 {
06733 Suspend_conf_base( s, 0 );
06734 }
06735
06736 static tConfItemFunc suspend_conf("SUSPEND",&Suspend_conf);
06737 static tAccessLevelSetter se_suspendConfLevel( suspend_conf, tAccessLevel_Moderator );
06738
06739 static tConfItemFunc unsuspend_conf("UNSUSPEND",&UnSuspend_conf);
06740 static tAccessLevelSetter se_unsuspendConfLevel( unsuspend_conf, tAccessLevel_Moderator );
06741
06742 static void Silence_conf(std::istream &s)
06743 {
06744 if ( se_NeedsServer( "SILENCE", s ) )
06745 {
06746 return;
06747 }
06748
06749 ePlayerNetID * p = ReadPlayer( s );
06750 if ( p )
06751 {
06752 sn_ConsoleOut( tOutput( "$player_silenced", p->GetName() ) );
06753 p->SetSilenced( true );
06754 }
06755 }
06756
06757 static tConfItemFunc silence_conf("SILENCE",&Silence_conf);
06758 static tAccessLevelSetter se_silenceConfLevel( silence_conf, tAccessLevel_Moderator );
06759
06760 static void Voice_conf(std::istream &s)
06761 {
06762 if ( se_NeedsServer( "VOICE", s ) )
06763 {
06764 return;
06765 }
06766
06767 ePlayerNetID * p = ReadPlayer( s );
06768 if ( p )
06769 {
06770 sn_ConsoleOut( tOutput( "$player_voiced", p->GetName() ) );
06771 p->SetSilenced( false );
06772 }
06773 }
06774
06775 static tConfItemFunc voice_conf("VOICE",&Voice_conf);
06776 static tAccessLevelSetter se_voiceConfLevel( voice_conf, tAccessLevel_Moderator );
06777
06778 static tString sg_url;
06779 static tSettingItem< tString > sg_urlConf( "URL", sg_url );
06780
06781 static tString sg_options("Nothing special.");
06782 #ifdef DEDICATED
06783 static tConfItemLine sg_optionsConf( "SERVER_OPTIONS", sg_options );
06784 #endif
06785
06786 class gServerInfoAdmin: public nServerInfoAdmin
06787 {
06788 public:
06789 gServerInfoAdmin(){};
06790
06791 private:
06792 virtual tString GetUsers() const
06793 {
06794 tString ret;
06795
06796 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
06797 {
06798 ePlayerNetID* p = se_PlayerNetIDs(i);
06799 if ( p->IsHuman() )
06800 {
06801 ret << p->GetName() << "\n";
06802 }
06803 }
06804
06805 return ret;
06806 }
06807
06808 virtual tString GetOptions() const
06809 {
06810 se_CutString( sg_options, 240 );
06811 return sg_options;
06812 }
06813
06814 virtual tString GetUrl() const
06815 {
06816 se_CutString( sg_url, 75 );
06817 return sg_url;
06818 }
06819 };
06820
06821 static gServerInfoAdmin sg_serverAdmin;
06822
06823 class eNameMessenger
06824 {
06825 public:
06826 eNameMessenger( ePlayerNetID & player )
06827 : player_( player )
06828 , oldScreenName_( player.GetName() )
06829 , oldLogName_( player.GetLogName() )
06830 {
06831
06832 oldPrintName_ << player_ << tColoredString::ColorString(.5,1,.5);
06833 }
06834
06835 ~eNameMessenger()
06836 {
06837 if ( sn_GetNetState() == nCLIENT )
06838 {
06839 return;
06840 }
06841
06842 tString logName = player_.GetLogName();
06843 tString const & screenName = player_.GetName();
06844
06845
06846 tColoredString printName;
06847 printName << player_ << tColoredString::ColorString(.5,1,.5);
06848
06849 tOutput mess;
06850
06851 mess.SetTemplateParameter(1, printName);
06852 mess.SetTemplateParameter(2, oldPrintName_);
06853
06854
06855 if ( oldLogName_.Len() <= 1 && logName.Len() > 0 )
06856 {
06857 if ( player_.IsHuman() )
06858 {
06859 tString ladder;
06860 ladder << "PLAYER_ENTERED " << logName << " " << nMachine::GetMachine(player_.Owner()).GetIP() << " " << screenName << "\n";
06861 se_SaveToLadderLog(ladder);
06862
06863 player_.Greet();
06864
06865
06866 if ( player_.IsSpectating() || !se_assignTeamAutomatically )
06867 {
06868 mess << "$player_entered_spectator";
06869 sn_ConsoleOut(mess);
06870 }
06871 }
06872 }
06873 else if ( logName != oldLogName_ || screenName != oldScreenName_ )
06874 {
06875 tString ladder;
06876 ladder << "PLAYER_RENAMED " << oldLogName_ << " " << logName << " " << nMachine::GetMachine(player_.Owner()).GetIP() << " " << screenName << "\n";
06877 se_SaveToLadderLog(ladder);
06878
06879 if ( oldScreenName_ != screenName )
06880 {
06881 if ( bool(player_.GetVoter() ) )
06882 {
06883 player_.GetVoter()->PlayerChanged();
06884 }
06885
06886 mess << "$player_renamed";
06887
06888 sn_ConsoleOut(mess);
06889 }
06890 }
06891 }
06892
06893 ePlayerNetID & player_;
06894 tString oldScreenName_, oldLogName_;
06895 tColoredString oldPrintName_;
06896 };
06897
06898
06899
06900
06901
06902
06905
06906
06907 void ePlayerNetID::UpdateName( void )
06908 {
06909
06910 if ( this->ID() == 0 && nameFromClient_.Len() <= 1 && sn_GetNetState() == nSERVER )
06911 return;
06912
06913
06914 eNameMessenger messenger( *this );
06915
06916
06917 if ( sn_GetNetState() != nCLIENT )
06918 {
06919
06920 if ( Owner() != 0 )
06921 se_OptionalNameFilters( nameFromClient_ );
06922
06923
06924 if ( !bool(this->voter_) || voter_->AllowNameChange() || nameFromServer_.Len() <= 1 )
06925 {
06926 nameFromServer_ = nameFromClient_;
06927 }
06928 else if ( nameFromServer_ != nameFromClient_ )
06929 {
06930
06931 tOutput message( "$player_rename_rejected", nameFromServer_, nameFromClient_ );
06932 sn_ConsoleOut( message, Owner() );
06933 con << message;
06934
06935
06936 nameFromClient_ = nameFromServer_;
06937 }
06938 }
06939
06940
06941 tString newName = tColoredString::RemoveColors( nameFromServer_ );
06942 tString newUserName = se_UnauthenticatedUserName( newName );
06943
06944
06945 if ( sn_GetNetState() != nCLIENT && !se_allowImposters && se_IsNameTaken( newUserName, this ) )
06946 {
06947
06948 if ( newName.Len() > 2 && isdigit(newName(newName.Len()-2)) )
06949 {
06950 newName = newName.SubStr( 0, newName.Len()-2 );
06951 }
06952
06953
06954 for ( int i=2; i<1000; ++i )
06955 {
06956 tString testName(newName);
06957 testName << i;
06958
06959
06960 if ( testName.Len() > 17 )
06961 testName = testName.SubStr( testName.Len() - 17 );
06962
06963 newUserName = se_UnauthenticatedUserName( testName );
06964
06965 if ( !se_IsNameTaken( newUserName, this ) )
06966 {
06967 newName = testName;
06968 break;
06969 }
06970 }
06971
06972
06973 nameFromServer_ = newName;
06974 }
06975
06976
06977 coloredName_.Clear();
06978 REAL r,g,b;
06979 Color(r,g,b);
06980 coloredName_ << tColoredString::ColorString(r,g,b) << nameFromServer_;
06981
06982 if ( name_ != newName || lastAccessLevel != GetAccessLevel() )
06983 {
06984
06985 name_ = newName;
06986
06987
06988 userName_ = se_UnauthenticatedUserName( name_ );
06989
06990 if (sn_GetNetState()!=nCLIENT)
06991 {
06992
06993 RequestSync();
06994 }
06995 }
06996
06997
06998 lastAccessLevel = GetAccessLevel();
06999
07000 #ifdef KRAWALL_SERVER
07001
07002 if ( IsAuthenticated() )
07003 {
07004 userName_ = GetFilteredAuthenticatedName();
07005 if ( se_legacyLogNames )
07006 {
07007 userName_ = tString( "0:" ) + userName_;
07008 }
07009 }
07010 else
07011 {
07012 rawAuthenticatedName_ = "";
07013 }
07014 #endif
07015 }
07016
07017
07018 class ePlayerCharacterFilter
07019 {
07020 public:
07021 ePlayerCharacterFilter()
07022 {
07023 int i;
07024 filter[0]=0;
07025
07026
07027 for (i=255; i>0; --i)
07028 {
07029 filter[i] = '_';
07030 }
07031
07032
07033 for (i=126; i>32; --i)
07034 {
07035 filter[i] = i;
07036 }
07037
07038 for (i='Z'; i>='A'; --i)
07039 {
07040 filter[i] = i + ('a' - 'A');
07041 }
07042
07044 SetMap(0xc0,0xc5,'a');
07045 SetMap(0xd1,0xd6,'o');
07046 SetMap(0xd9,0xdD,'u');
07047 SetMap(0xdf,'s');
07048 SetMap(0xe0,0xe5,'a');
07049 SetMap(0xe8,0xeb,'e');
07050 SetMap(0xec,0xef,'i');
07051 SetMap(0xf0,0xf6,'o');
07052 SetMap(0xf9,0xfc,'u');
07053
07054
07055 SetMap(161,'!');
07056 SetMap(162,'c');
07057 SetMap(163,'l');
07058 SetMap(165,'y');
07059 SetMap(166,'|');
07060 SetMap(167,'s');
07061 SetMap(168,'"');
07062 SetMap(169,'c');
07063 SetMap(170,'a');
07064 SetMap(171,'"');
07065 SetMap(172,'!');
07066 SetMap(174,'r');
07067 SetMap(176,'o');
07068 SetMap(177,'+');
07069 SetMap(178,'2');
07070 SetMap(179,'3');
07071 SetMap(182,'p');
07072 SetMap(183,'.');
07073 SetMap(185,'1');
07074 SetMap(187,'"');
07075 SetMap(198,'a');
07076 SetMap(199,'c');
07077 SetMap(208,'d');
07078 SetMap(209,'n');
07079 SetMap(215,'x');
07080 SetMap(216,'o');
07081 SetMap(221,'y');
07082 SetMap(222,'p');
07083 SetMap(231,'c');
07084 SetMap(241,'n');
07085 SetMap(247,'/');
07086 SetMap(248,'o');
07087 SetMap(253,'y');
07088 SetMap(254,'p');
07089 SetMap(255,'y');
07090
07091
07092 SetMap('0','o');
07093
07094
07095 }
07096
07097 char Filter( unsigned char in )
07098 {
07099 return filter[ static_cast< unsigned int >( in )];
07100 }
07101 private:
07102 void SetMap( int in1, int in2, unsigned char out)
07103 {
07104 tASSERT( in2 <= 0xff );
07105 tASSERT( 0 <= in1 );
07106 tASSERT( in1 < in2 );
07107 for( int i = in2; i >= in1; --i )
07108 filter[ i ] = out;
07109 }
07110
07111 void SetMap( unsigned char in, unsigned char out)
07112 {
07113 filter[ static_cast< unsigned int >( in ) ] = out;
07114 }
07115
07116 char filter[256];
07117 };
07118
07119 static bool se_IsUnderscore( char c )
07120 {
07121 return c == '_';
07122 }
07123
07124
07125
07126
07127
07128
07133
07134
07135 void ePlayerNetID::FilterName( tString const & in, tString & out )
07136 {
07137 int i;
07138 static ePlayerCharacterFilter filter;
07139 out = tColoredString::RemoveColors( in );
07140
07141
07142 for ( i = out.Size()-1; i>=0; --i )
07143 {
07144 char & c = out[i];
07145
07146 c = filter.Filter( c );
07147 }
07148
07149
07150 se_StripMatchingEnds( out, se_IsUnderscore, se_IsUnderscore );
07151 }
07152
07153
07154
07155
07156
07157
07162
07163
07164 tString ePlayerNetID::FilterName( tString const & in )
07165 {
07166 tString out;
07167 FilterName( in, out );
07168 return out;
07169 }
07170
07171
07172
07173
07174
07175
07180
07181
07182 ePlayerNetID & ePlayerNetID::SetName( tString const & name )
07183 {
07184 this->nameFromClient_ = name;
07185 this->nameFromClient_.NetFilter();
07186
07187
07188 if ( !IsLegalPlayerName( nameFromClient_ ) )
07189 nameFromClient_ = "Player 1";
07190
07191 if ( sn_GetNetState() != nCLIENT )
07192 nameFromServer_ = nameFromClient_;
07193
07194 UpdateName();
07195
07196 return *this;
07197 }
07198
07199
07200
07201
07202
07203
07208
07209
07210 ePlayerNetID & ePlayerNetID::SetName( char const * name )
07211 {
07212 SetName( tString( name ) );
07213 return *this;
07214 }
07215
07216
07217
07218
07219
07220
07224
07225
07226 tString ePlayerNetID::GetFilteredAuthenticatedName( void ) const
07227 {
07228 #ifdef KRAWALL_SERVER
07229 return tString( se_EscapeName( GetRawAuthenticatedName() ).c_str() );
07230 #else
07231 return tString("");
07232 #endif
07233 }
07234
07235
07236 static bool se_allowEnemiesSameIP = false;
07237 static tSettingItem< bool > se_allowEnemiesSameIPConf( "ALLOW_ENEMIES_SAME_IP", se_allowEnemiesSameIP );
07238
07239 static bool se_allowEnemiesSameClient = false;
07240 static tSettingItem< bool > se_allowEnemiesSameClientConf( "ALLOW_ENEMIES_SAME_CLIENT", se_allowEnemiesSameClient );
07241
07242
07243
07244
07245
07246
07252
07253
07254 bool ePlayerNetID::Enemies( ePlayerNetID const * a, ePlayerNetID const * b )
07255 {
07256
07257 if ( sn_GetNetState() == nCLIENT )
07258 return true;
07259
07260
07261 if ( !a || !b )
07262 return false;
07263
07264
07265 if ( !se_allowEnemiesSameIP && a->Owner() != 0 && a->GetMachine() == b->GetMachine() )
07266 return false;
07267
07268
07269 if ( !se_allowEnemiesSameClient && a->Owner() != 0 && a->Owner() == b->Owner() )
07270 return false;
07271
07272
07273 return true;
07274 }
07275
07276
07277
07278
07279
07280
07283
07284
07285 void ePlayerNetID::RegisterWithMachine( void )
07286 {
07287 if ( !registeredMachine_ )
07288 {
07289
07290 registeredMachine_ = &this->nNetObject::DoGetMachine();
07291 registeredMachine_->AddPlayer();
07292 }
07293 }
07294
07295
07296
07297
07298
07299
07302
07303
07304 void ePlayerNetID::UnregisterWithMachine( void )
07305 {
07306 if ( registeredMachine_ )
07307 {
07308
07309 if ( GetVoter() )
07310 {
07311 GetVoter()->suspended_ = suspended_;
07312 }
07313
07314 registeredMachine_->RemovePlayer();
07315 registeredMachine_ = 0;
07316 }
07317 }
07318
07319
07320
07321
07322
07323
07327
07328
07329 nMachine & ePlayerNetID::DoGetMachine( void ) const
07330 {
07331
07332 if ( registeredMachine_ )
07333 return *registeredMachine_;
07334 else
07335 return nNetObject::DoGetMachine();
07336 }
07337
07338
07339
07340
07341
07342
07346
07347
07348 REAL ePlayerNetID::LastActivity( void ) const
07349 {
07350 return tSysTimeFloat() - lastActivity_;
07351 }
07352
07353
07354
07355
07356
07357
07360
07361
07362 void ePlayerNetID::ResetScoreDifferences( void )
07363 {
07364 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
07365 {
07366 ePlayerNetID* p = se_PlayerNetIDs(i);
07367 if ( bool(p->Object()) && p->IsHuman() )
07368 p->lastScore_ = p->score;
07369 }
07370 }
07371
07372
07373
07374
07375
07376
07380
07381
07382 void ePlayerNetID::Suspend( int rounds )
07383 {
07384 if ( rounds < 0 )
07385 {
07386 rounds = 0;
07387 }
07388
07389 int & suspended = AccessSuspended();
07390
07391 if ( suspended == rounds )
07392 {
07393 return;
07394 }
07395
07396 suspended = rounds;
07397
07398 if ( suspended == 0 )
07399 {
07400 sn_ConsoleOut( tOutput( "$player_no_longer_suspended", GetColoredName() ) );
07401 FindDefaultTeam();
07402 }
07403 else
07404 {
07405 sn_ConsoleOut( tOutput( "$player_suspended", GetColoredName(), suspended ) );
07406 SetTeam( NULL );
07407 }
07408 }
07409
07410
07411
07412
07413
07414
07417
07418
07419 void ePlayerNetID::LogScoreDifferences( void )
07420 {
07421 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
07422 {
07423 ePlayerNetID* p = se_PlayerNetIDs(i);
07424 p->LogScoreDifference();
07425
07426 int suspended = p->GetSuspended();
07427
07428
07429 if ( suspended > 0 )
07430 {
07431 if ( p->CurrentTeam() && !p->NextTeam() )
07432 {
07433 p->UpdateTeam();
07434 }
07435 else
07436 {
07437 p->Suspend( suspended - 1 );
07438 }
07439 }
07440 }
07441 }
07442
07443
07444
07445
07446
07447
07450
07451
07452 void ePlayerNetID::LogScoreDifference( void )
07453 {
07454 if ( lastScore_ > IMPOSSIBLY_LOW_SCORE && IsHuman() )
07455 {
07456 tString ret;
07457 int scoreDifference = score - lastScore_;
07458 lastScore_ = IMPOSSIBLY_LOW_SCORE;
07459 ret << "ROUND_SCORE " << scoreDifference << " " << GetUserName();
07460 if ( currentTeam )
07461 ret << " " << FilterName( currentTeam->Name() ) << " " << currentTeam->Score();
07462 ret << "\n";
07463 se_SaveToLadderLog( ret );
07464 }
07465 }
07466
07467 static void se_allowTeamChangesPlayer(bool allow, std::istream &s) {
07468 if ( se_NeedsServer( "(DIS)ALLOW_TEAM_CHANGE_PLAYER", s, false ) )
07469 {
07470 return;
07471 }
07472
07473 ePlayerNetID * p = ReadPlayer( s );
07474 if ( p )
07475 {
07476 sn_ConsoleOut( tOutput( (allow ? "$player_allowed_teamchange" : "$player_disallowed_teamchange"), p->GetName() ) );
07477 p->SetTeamChangeAllowed( allow );
07478 }
07479 }
07480 static void se_allowTeamChangesPlayer(std::istream &s) {
07481 se_allowTeamChangesPlayer(true, s);
07482 }
07483 static void se_disallowTeamChangesPlayer(std::istream &s) {
07484 se_allowTeamChangesPlayer(false, s);
07485 }
07486 static tConfItemFunc se_allowTeamChangesPlayerConf("ALLOW_TEAM_CHANGE_PLAYER", &se_allowTeamChangesPlayer);
07487 static tConfItemFunc se_disallowTeamChangesPlayerConf("DISALLOW_TEAM_CHANGE_PLAYER", &se_disallowTeamChangesPlayer);
07488 static tAccessLevelSetter se_atcConfLevel( se_allowTeamChangesPlayerConf, tAccessLevel_TeamLeader );
07489 static tAccessLevelSetter se_dtcConfLevel( se_disallowTeamChangesPlayerConf, tAccessLevel_TeamLeader );
07490
07492 int & ePlayerNetID::AccessSuspended()
07493 {
07494 return suspended_;
07495 }
07496
07498 int ePlayerNetID::GetSuspended() const
07499 {
07500 return suspended_;
07501 }