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 "rSDL.h"
00029
00030 #include "eVoter.h"
00031
00032 #include "tMemManager.h"
00033 #include "tSysTime.h"
00034 #include "tDirectories.h"
00035
00036 #include "uMenu.h"
00037
00038 #include "nConfig.h"
00039 #include "nServerInfo.h"
00040
00041 #include "rConsole.h"
00042
00043 #include "ePlayer.h"
00044 #include "eGrid.h"
00045
00046 #ifndef DEDICATED
00047
00048 static bool se_useServerControlledKick = false;
00049 static nSettingItem< bool > se_usc( "VOTE_USE_SERVER_CONTROLLED_KICK", se_useServerControlledKick );
00050 #endif
00051
00052
00053 static unsigned short se_votingItemID = 0;
00054 static float se_votingTimeout = 300.0f;
00055 static nSettingItem< float > se_vt( "VOTING_TIMEOUT", se_votingTimeout );
00056
00057
00058 static float se_votingTimeoutPerVoter = 0.0f;
00059 static nSettingItem< float > se_vtp( "VOTING_TIMEOUT_PER_VOTER", se_votingTimeoutPerVoter );
00060
00061 static float se_votingStartDecay = 60.0f;
00062 static nSettingItem< float > se_vsd( "VOTING_START_DECAY", se_votingStartDecay );
00063
00064 static float se_votingDecay = 60.0f;
00065 static nSettingItem< float > se_vd( "VOTING_DECAY", se_votingDecay );
00066
00067
00068 static float se_votingSpamIssue = 1.0f;
00069 static nSettingItem< float > se_vsi( "VOTING_SPAM_ISSUE", se_votingSpamIssue );
00070
00071
00072 static float se_votingSpamReject = 5.0f;
00073 static nSettingItem< float > se_vsr( "VOTING_SPAM_REJECT", se_votingSpamReject );
00074
00075 static bool se_allowVoting = false;
00076 static tSettingItem< bool > se_av( "ALLOW_VOTING", se_allowVoting );
00077
00078 static bool se_allowVotingSpectator = false;
00079 static tSettingItem< bool > se_avo( "ALLOW_VOTING_SPECTATOR", se_allowVotingSpectator );
00080
00081
00082 static int se_suspendRounds = 5;
00083 static tSettingItem< int > se_sr( "VOTING_SUSPEND_ROUNDS", se_suspendRounds );
00084
00085 static int se_minVoters = 3;
00086 static tSettingItem< int > se_mv( "MIN_VOTERS", se_minVoters );
00087
00088
00089 static int se_votingBias = 0;
00090 static tSettingItem< int > se_vb( "VOTING_BIAS", se_votingBias );
00091
00092
00093 static int se_votingBiasKick = 0;
00094 static tSettingItem< int > se_vbKick( "VOTING_BIAS_KICK", se_votingBiasKick );
00095
00096
00097 static int se_votingBiasSuspend = 0;
00098 static tSettingItem< int > se_vbSuspend( "VOTING_BIAS_SUSPEND", se_votingBiasSuspend );
00099
00100
00101 static int se_votingBiasInclude = 0;
00102 static tSettingItem< int > se_vbInclude( "VOTING_BIAS_INCLUDE", se_votingBiasInclude );
00103
00104
00105 static int se_votingBiasCommand = 0;
00106 static tSettingItem< int > se_vbCommand( "VOTING_BIAS_COMMAND", se_votingBiasCommand );
00107
00108
00109 static int se_votingPrivacy = 1;
00110 static tSettingItem< int > se_vp( "VOTING_PRIVACY", se_votingPrivacy );
00111
00112
00113 static int se_maxVotes = 5;
00114 static tSettingItem< int > se_maxVotesSI( "MAX_VOTES", se_maxVotes );
00115
00116
00117 static int se_maxVotesPerVoter = 2;
00118 static tSettingItem< int > se_maxVotesPerVoterSI( "MAX_VOTES_PER_VOTER", se_maxVotesPerVoter );
00119
00120
00121 static int se_minTimeBetweenKicks = 300;
00122 static tSettingItem< int > se_minTimeBetweenKicksSI( "VOTING_KICK_TIME", se_minTimeBetweenKicks );
00123
00124
00125 static int se_minTimeBetweenHarms = 180;
00126 static tSettingItem< int > se_minTimeBetweenHarmsSI( "VOTING_HARM_TIME", se_minTimeBetweenHarms );
00127
00128
00129 static int se_votingMaturity = 300;
00130 static tSettingItem< int > se_votingMaturitySI( "VOTING_MATURITY", se_votingMaturity );
00131
00132 #ifdef KRAWALL_SERVER
00133
00134 static tAccessLevel se_accessLevelVoteKick = tAccessLevel_Program;
00135 static tSettingItem< tAccessLevel > se_accessLevelVoteKickSI( "ACCESS_LEVEL_VOTE_KICK", se_accessLevelVoteKick );
00136
00137
00138 static tAccessLevel se_accessLevelVoteSuspend = tAccessLevel_Program;
00139 static tSettingItem< tAccessLevel > se_accessLevelVoteSuspendSI( "ACCESS_LEVEL_VOTE_SUSPEND", se_accessLevelVoteSuspend );
00140
00141
00142 static tAccessLevel se_accessLevelVoteInclude = tAccessLevel_Moderator;
00143 static tSettingItem< tAccessLevel > se_accessLevelVoteIncludeSI( "ACCESS_LEVEL_VOTE_INCLUDE", se_accessLevelVoteInclude );
00144
00145
00146 static tAccessLevel se_accessLevelVoteIncludeExecute = tAccessLevel_Moderator;
00147 static tSettingItem< tAccessLevel > se_accessLevelVoteIncludeExecuteSI( "ACCESS_LEVEL_VOTE_INCLUDE_EXECUTE", se_accessLevelVoteIncludeExecute );
00148
00149
00150 static tAccessLevel se_accessLevelVoteCommand = tAccessLevel_Moderator;
00151 static tSettingItem< tAccessLevel > se_accessLevelVoteCommandSI( "ACCESS_LEVEL_VOTE_COMMAND", se_accessLevelVoteCommand );
00152
00153
00154
00155 static tAccessLevel se_accessLevelVoteCommandExecute = tAccessLevel_Moderator;
00156 static tSettingItem< tAccessLevel > se_accessLevelVoteCommandExecuteSI( "ACCESS_LEVEL_VOTE_COMMAND_EXECUTE", se_accessLevelVoteCommandExecute );
00157 #endif
00158
00159 static eVoter* se_GetVoter( const nMessage& m )
00160 {
00161 return eVoter::GetVoter( m.SenderID(), true );
00162 }
00163
00164 eVoterPlayerInfo::eVoterPlayerInfo(): suspended_(0){}
00165
00166 static tAccessLevel se_GetAccessLevel( int userID )
00167 {
00168 tAccessLevel ret = tAccessLevel_Default;
00169
00170
00171 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
00172 {
00173 ePlayerNetID* p = se_PlayerNetIDs(i);
00174
00175 if ( p->Owner() == userID )
00176 {
00177 if( p->GetAccessLevel() < ret )
00178 {
00179 ret = p->GetAccessLevel();
00180 }
00181 }
00182 }
00183
00184 return ret;
00185 }
00186
00187
00188 class eVoteItem: public tListMember
00189 {
00190 friend class eMenuItemVote;
00191 public:
00192
00193 eVoteItem( void ): creationTime_( tSysTimeFloat() ), user_( 0 ), id_( ++se_votingItemID ), menuItem_( 0 )
00194 {
00195 items_.Add( this );
00196 };
00197
00198 virtual ~eVoteItem( void );
00199
00200 bool FillFromMessage( nMessage& m )
00201 {
00202
00203 nCurrentSenderID cloak;
00204 if ( se_votingPrivacy > 1 )
00205 cloak.SetID(0);
00206
00207 if ( !DoFillFromMessage( m ) )
00208 return false;
00209
00210 if ( sn_GetNetState() == nSERVER )
00211 {
00212 if ( !CheckValid( m.SenderID() ) )
00213 return false;
00214
00215 ReBroadcast( m.SenderID() );
00216 }
00217 return true;
00218 }
00219
00220
00221 void ReBroadcast( int exceptTo = -1 )
00222 {
00223
00224 if ( sn_GetNetState() == nSERVER )
00225 {
00226
00227 tOutput voteMessage;
00228 voteMessage.SetTemplateParameter( 1, suggestor_->Name( user_ ) );
00229 voteMessage.SetTemplateParameter( 2, GetDescription() );
00230 voteMessage << "$vote_submitted";
00231
00232
00233 if ( se_votingPrivacy <= -1 )
00234 sn_ConsoleOut( voteMessage );
00235 else if ( se_votingPrivacy <= 1 )
00236 con << voteMessage;
00237
00238 static nVersionFeature serverControlledVotes( 10 );
00239
00240
00241 tJUST_CONTROLLED_PTR< nMessage > retNew = this->CreateMessage();
00242 tJUST_CONTROLLED_PTR< nMessage > retLegacy = this->CreateMessageLegacy();
00243 for ( int i = MAXCLIENTS; i > 0; --i )
00244 {
00245 if ( sn_Connections[ i ].socket && i != exceptTo && 0 != eVoter::GetVoter( i ) )
00246 {
00247 if ( serverControlledVotes.Supported( i ) )
00248 {
00249 retNew->Send( i );
00250 }
00251 else if ( retLegacy )
00252 {
00253 retLegacy->Send( i );
00254 }
00255 }
00256 }
00257
00258 }
00259
00260 con << tOutput( "$vote_new", GetDescription() );
00261
00262 this->Evaluate();
00263 };
00264
00265 nMessage* CreateMessage( void ) const
00266 {
00267 nMessage* m = tNEW( nMessage )( this->DoGetDescriptor() );
00268 this->DoFillToMessage( *m );
00269 return m;
00270 }
00271
00272 nMessage* CreateMessageLegacy( void ) const
00273 {
00274 nDescriptor * descriptor = this->DoGetDescriptorLegacy();
00275 if ( descriptor )
00276 {
00277 nMessage* m = tNEW( nMessage )( *descriptor );
00278 this->DoFillToMessageLegacy( *m );
00279 return m;
00280 }
00281 else
00282 {
00283 return 0;
00284 }
00285 }
00286
00287 void SendMessage( void ) const
00288 {
00289 this->CreateMessage()->BroadCast();
00290 }
00291
00292
00293 void Vote( bool accept );
00294
00295 static bool AcceptNewVote( eVoter * voter, int senderID )
00296 {
00297
00298 nCurrentSenderID cloak;
00299 if ( se_votingPrivacy > 0 )
00300 cloak.SetID(0);
00301
00302 int i;
00303
00304
00305 for ( i = items_.Len()-1; i>=0; --i )
00306 {
00307 items_[i]->Evaluate();
00308 }
00309
00310
00311 if ( sn_GetNetState() == nCLIENT )
00312 return true;
00313
00314
00315 if ( !voter )
00316 {
00317 return false;
00318 }
00319
00320
00321 if ( !se_allowVoting )
00322 {
00323 tOutput message("$vote_disabled");
00324 sn_ConsoleOut( message, senderID );
00325 return false;
00326 }
00327
00328
00329 for ( i = MAXCLIENTS; i > 0; --i )
00330 {
00331 if ( sn_Connections[ i ].socket )
00332 eVoter::GetVoter( i );
00333 }
00334
00335
00336 if ( eVoter::voters_.Len() < se_minVoters )
00337 {
00338 tOutput message("$vote_toofew");
00339 sn_ConsoleOut( message, senderID );
00340 return false;
00341 }
00342
00343
00344 if ( voter->IsSpamming( senderID ) )
00345 {
00346 return false;
00347 }
00348
00349
00350 int voteCount = 0;
00351 for ( i = items_.Len()-1; i>=0; --i )
00352 {
00353 eVoteItem * other = items_[i];
00354 if ( other->suggestor_ == voter )
00355 voteCount ++;
00356 }
00357 if ( voteCount >= se_maxVotesPerVoter )
00358 {
00359 tOutput message("$vote_overflow");
00360 sn_ConsoleOut( message, senderID );
00361 return false;
00362 }
00363
00364 if ( items_.Len() < se_maxVotes )
00365 {
00366 voter->Spam( senderID, se_votingSpamIssue, tOutput("$spam_vote_kick_issue") );
00367 return true;
00368 }
00369 else
00370 {
00371 tOutput message("$vote_overflow");
00372 sn_ConsoleOut( message, senderID );
00373 return false;
00374 }
00375 }
00376
00377 static bool AcceptNewVote( nMessage const & m )
00378 {
00379 return AcceptNewVote( se_GetVoter( m ), m.SenderID() );
00380 }
00381
00382 void RemoveVoter( eVoter* voter )
00383 {
00384
00385 for ( int res = 1; res >= 0; --res )
00386 this->voters_[ res ].Remove( voter );
00387 }
00388
00389 void RemoveVoterCompletely( eVoter* voter )
00390 {
00391 RemoveVoter( voter );
00392 if ( suggestor_ == voter )
00393 {
00394 suggestor_ = 0;
00395 user_ = 0;
00396 }
00397 }
00398
00399
00400 static void GetControlMessage( nMessage& m )
00401 {
00402 if ( sn_GetNetState() == nSERVER )
00403 {
00404 unsigned short id;
00405 m.Read( id );
00406
00407 bool result;
00408 m >> result;
00409 result = result ? 1 : 0;
00410
00411 for ( int i = items_.Len()-1; i>=0; --i )
00412 {
00413 eVoteItem* vote = items_[i];
00414 if ( vote->id_ == id )
00415 {
00416
00417 tCONTROLLED_PTR( eVoter ) voter = se_GetVoter( m );
00418 if ( voter )
00419 {
00420
00421 tOutput voteMessage;
00422 voteMessage.SetTemplateParameter( 1, voter->Name( m.SenderID() ) );
00423 voteMessage.SetTemplateParameter( 2, vote->GetDescription() );
00424 if ( result )
00425 voteMessage << "$vote_vote_for";
00426 else
00427 voteMessage << "$vote_vote_against";
00428
00429
00430 if ( se_votingPrivacy <= -2 )
00431 sn_ConsoleOut( voteMessage );
00432 else if ( se_votingPrivacy <= 0 )
00433 con << voteMessage;
00434
00435
00436 vote->RemoveVoter( voter );
00437
00438
00439 vote->voters_[ result ].Insert( voter );
00440 }
00441
00442
00443 vote->Evaluate();
00444 return;
00445 }
00446 }
00447 }
00448 }
00449
00450
00451 void GetStats( int& pro, int& con, int& total ) const
00452 {
00453 pro = voters_[1].Len();
00454 con = voters_[0].Len();
00455 total = eVoter::voters_.Len();
00456 }
00457
00458
00459 void BroadcastMessage( const tOutput& message ) const
00460 {
00461 if ( sn_GetNetState() == nSERVER )
00462 {
00463 tOutput m;
00464 m.SetTemplateParameter( 1, this->GetDescription() );
00465 m.Append( message );
00466
00467 sn_ConsoleOut( m );
00468 }
00469 }
00470
00471
00472 virtual tAccessLevel DoGetAccessLevel() const
00473 {
00474 return tAccessLevel_Default;
00475 }
00476
00477
00478 virtual int DoGetExtraBias() const
00479 {
00480 return 0;
00481 }
00482
00483
00484 virtual void Evaluate()
00485 {
00486 int pro, con, total;
00487
00488 GetStats( pro, con, total );
00489
00490 int bias = se_votingBias + DoGetExtraBias();
00491
00492
00493 con += bias;
00494 total += bias;
00495
00496
00497 if ( se_votingDecay > 0 )
00498 {
00499 int reduce = int( ( tSysTimeFloat() - this->creationTime_ - se_votingStartDecay ) / se_votingDecay );
00500 if ( reduce > 0 )
00501 {
00502 total -= reduce;
00503 }
00504 }
00505
00506 if ( sn_GetNetState() == nSERVER )
00507 {
00508
00509 if ( con >= pro && con * 2 >= total )
00510 {
00511 if ( this->suggestor_ )
00512 this->suggestor_->Spam( user_, se_votingSpamReject, tOutput("$spam_vote_rejected") );
00513
00514 tOutput voteMessage;
00515 voteMessage.SetTemplateParameter( 1, GetDescription() );
00516 voteMessage.SetTemplateParameter( 2, pro-1 );
00517 voteMessage.SetTemplateParameter( 3, con-se_votingBias );
00518 voteMessage.SetTemplateParameter( 4, total-se_votingBias);
00519 voteMessage << "$vote_rejected";
00520 this->BroadcastMessage( voteMessage );
00521 delete this;
00522 return;
00523 }
00524
00525
00526 if ( pro >= con && pro * 2 > total )
00527 {
00528 this->DoExecute();
00529 tOutput voteMessage;
00530 voteMessage.SetTemplateParameter( 1, GetDescription() );
00531 voteMessage.SetTemplateParameter( 2, pro-1 );
00532 voteMessage.SetTemplateParameter( 3, con-se_votingBias );
00533 voteMessage.SetTemplateParameter( 4, total-se_votingBias);
00534 voteMessage << "$vote_accepted";
00535 this->BroadcastMessage( voteMessage );
00536 delete this;
00537 return;
00538 }
00539 }
00540
00541
00542 int relevantNumVoters = sn_GetNetState() == nCLIENT ? se_PlayerNetIDs.Len() + MAXCLIENTS : eVoter::voters_.Len();
00543 if ( this->creationTime_ < tSysTimeFloat() - se_votingTimeout - se_votingTimeoutPerVoter * relevantNumVoters )
00544 {
00545 this->BroadcastMessage( tOutput( "$vote_timeout" ) );
00546
00547 delete this;
00548 return;
00549 }
00550 }
00551
00552
00553 static const tList< eVoteItem >& GetItems() { return items_; }
00554 inline eVoter* GetSuggestor() const { return suggestor_; }
00555 inline tString GetDescription() const{ return this->DoGetDescription(); }
00556 inline tString GetDetails() const{ return this->DoGetDetails(); }
00557
00558 unsigned short GetID(){ return id_; }
00559 void UpdateMenuItem();
00560
00561
00562 bool CheckValid( int senderID )
00563 {
00564 if ( sn_GetNetState() != nSERVER )
00565 {
00566 return true;
00567 }
00568
00569
00570 if ( !suggestor_ )
00571 {
00572 suggestor_ = eVoter::GetVoter( senderID );
00573 if ( !suggestor_ )
00574 return false;
00575
00576
00577 this->voters_[1].Insert( suggestor_ );
00578
00579 user_ = senderID;
00580 }
00581
00582
00583 tAccessLevel accessLevel = se_GetAccessLevel( senderID );
00584 if ( accessLevel < tCurrentAccessLevel::GetAccessLevel() )
00585 {
00586 accessLevel = tCurrentAccessLevel::GetAccessLevel();
00587 }
00588
00589 tAccessLevel required = DoGetAccessLevel();
00590 if ( accessLevel > required )
00591 {
00592 sn_ConsoleOut(tOutput("$player_vote_accesslevel",
00593 tCurrentAccessLevel::GetName( accessLevel ),
00594 tCurrentAccessLevel::GetName( required ) ),
00595 senderID );
00596
00597 return false;
00598 }
00599
00600 return DoCheckValid( senderID );
00601 }
00602
00603 virtual void Update()
00604 {}
00605 protected:
00606 virtual bool DoFillFromMessage( nMessage& m )
00607 {
00608
00609 user_ = m.SenderID();
00610
00611
00612 if(sn_GetNetState()!=nSERVER)
00613 {
00614 m.Read( id_ );
00615 }
00616
00617 return true;
00618 };
00619
00620 virtual bool DoCheckValid( int senderID ){ return true; }
00621
00622 virtual void DoFillToMessage( nMessage& m ) const
00623 {
00624 if(sn_GetNetState()==nSERVER)
00625 {
00626
00627 m.Write( id_ );
00628 }
00629 };
00630
00631 protected:
00632 virtual tString DoGetDetails() const
00633 {
00634 tString ret;
00635 if ( se_votingPrivacy <= -1 && bool( suggestor_ ) )
00636 ret << tOutput( "$vote_submitter_text", suggestor_->Name( user_ ) ) << " ";
00637
00638 return ret;
00639 }
00640 static tList< eVoteItem > items_;
00641 private:
00642 virtual nDescriptor * DoGetDescriptorLegacy() const
00643 {
00644 return 0;
00645 }
00646
00647 virtual void DoFillToMessageLegacy( nMessage& m ) const
00648 {
00649 return DoFillToMessage( m );
00650 };
00651
00652 virtual nDescriptor& DoGetDescriptor() const = 0;
00653 virtual tString DoGetDescription() const = 0;
00654 virtual void DoExecute() = 0;
00655
00656 nTimeAbsolute creationTime_;
00657 tCONTROLLED_PTR( eVoter ) suggestor_;
00658 unsigned int user_;
00659 tArray< tCONTROLLED_PTR( eVoter ) > voters_[2];
00660 unsigned short id_;
00661 eMenuItemVote *menuItem_;
00662
00663 eVoteItem& operator=( const eVoteItem& );
00664 eVoteItem( const eVoteItem& );
00665 };
00666
00667 tList< eVoteItem > eVoteItem::items_;
00668
00669 void se_CancelAllVotes( std::istream & )
00670 {
00671 if ( sn_GetNetState() == nCLIENT )
00672 {
00673 return;
00674 }
00675
00676 sn_ConsoleOut( tOutput( "$vote_cancel_all" ) );
00677
00678 tList< eVoteItem > const & items = eVoteItem::GetItems();
00679
00680 while ( items.Len() )
00681 {
00682 delete items(0);
00683 }
00684 }
00685
00686 static tConfItemFunc se_cancelAllVotes_conf( "VOTES_CANCEL", &se_CancelAllVotes );
00687
00688 static nDescriptor vote_handler(230,eVoteItem::GetControlMessage,"vote cast");
00689
00690
00691 void eVoteItem::Vote( bool accept )
00692 {
00693 tJUST_CONTROLLED_PTR< nMessage > m = tNEW( nMessage )( vote_handler );
00694 *m << id_;
00695 *m << accept;
00696 m->BroadCast();
00697
00698 delete this;
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 enum Vote
00710 {
00711 Vote_Approve,
00712 Vote_Reject,
00713 Vote_DontMind
00714 };
00715
00716 #ifdef _MSC_VER
00717 #pragma warning ( disable: 4355 )
00718 #endif
00719
00720
00721 class eMenuItemVote: public uMenuItemSelection< Vote >
00722 {
00723 friend class eVoteItem;
00724 friend class eVoteItemServerControlled;
00725
00726 public:
00727 eMenuItemVote(uMenu *m, eVoteItem* v )
00728 : uMenuItemSelection< Vote >( m, tOutput(""), tOutput("$vote_help"), vote_ )
00729 , item_( v )
00730 , vote_ ( Vote_DontMind )
00731 , reject_ ( *this, "$vote_reject" , "$vote_reject_help" , Vote_Reject )
00732 , dontMind_ ( *this, "$vote_dont_mind" , "$vote_dont_mind_help" , Vote_DontMind )
00733 , approve_ ( *this, "$vote_approve" , "$vote_approve_help" , Vote_Approve )
00734 {
00735 tASSERT( v );
00736
00737 if ( v )
00738 {
00739 v->menuItem_ = this;
00740 v->UpdateMenuItem();
00741 }
00742 }
00743
00744 ~eMenuItemVote()
00745 {
00746 if ( item_ )
00747 {
00748 item_->menuItem_ = 0;
00749
00750 switch ( vote_ )
00751 {
00752 case Vote_Approve:
00753 item_->Vote( true );
00754 break;
00755 case Vote_Reject:
00756 item_->Vote( false );
00757 break;
00758 default:
00759 break;
00760 }
00761 }
00762 }
00763
00764 private:
00765 eVoteItem* item_;
00766 Vote vote_;
00767 uSelectEntry< Vote > reject_, dontMind_, approve_;
00768 };
00769
00770
00771
00772
00773 static void se_HandleServerVoteChanged( nMessage& m );
00774 static nDescriptor server_vote_expired_handler(233,se_HandleServerVoteChanged,"Server controlled vote expired");
00775
00776
00777 class eVoteItemServerControlled: public virtual eVoteItem
00778 {
00779 public:
00780
00781 eVoteItemServerControlled()
00782 : description_( "No Info" )
00783 , details_( "No Info" )
00784 , expired_( false )
00785 {
00786 }
00787
00788 eVoteItemServerControlled( tString const & description, tString const & details )
00789 : description_( description )
00790 , details_( details )
00791 , expired_( false )
00792 {}
00793
00794 ~eVoteItemServerControlled()
00795 {
00796 if ( sn_GetNetState() == nSERVER )
00797 {
00798 expired_ = true;
00799 SendChanged();
00800 }
00801 }
00802
00803 static void s_HandleChanged( nMessage & m )
00804 {
00805 unsigned short id;
00806 m.Read( id );
00807 for ( int i = items_.Len()-1; i>=0; --i )
00808 {
00809 eVoteItem* vote = items_[i];
00810 if ( vote->GetID() == id )
00811 {
00812 eVoteItemServerControlled * vote2 = dynamic_cast< eVoteItemServerControlled * >( vote );
00813 if ( vote2 )
00814 vote2->HandleChanged( m );
00815 }
00816 }
00817 }
00818
00819 void HandleChanged( nMessage & m )
00820 {
00821 unsigned short expired;
00822 m.Read( expired );
00823 expired_ = expired;
00824 m >> description_;
00825 m >> details_;
00826
00827 Update();
00828 UpdateMenuItem();
00829 }
00830
00831 void SendChanged()
00832 {
00833 tJUST_CONTROLLED_PTR< nMessage > m = tNEW( nMessage )( server_vote_expired_handler );
00834 *m << GetID();
00835 *m << (unsigned short)expired_;
00836 *m << description_;
00837 *m << details_;
00838 m->BroadCast();
00839 }
00840 protected:
00841
00842 virtual bool DoFillFromMessage( nMessage& m )
00843 {
00844 m >> description_;
00845 m >> details_;
00846 return eVoteItem::DoFillFromMessage( m );
00847 };
00848
00849 virtual void DoFillToMessage( nMessage& m ) const
00850 {
00851 m << description_;
00852 m << details_;
00853 eVoteItem::DoFillToMessage( m );
00854 };
00855
00856 virtual void DoExecute(){};
00857 protected:
00858 virtual nDescriptor& DoGetDescriptor() const;
00859
00860 virtual void Evaluate()
00861 {
00862
00863 if ( sn_GetNetState() == nSERVER )
00864 {
00865 Update();
00866 SendChanged();
00867 }
00868
00869 if ( expired_ )
00870 delete this;
00871 else
00872 eVoteItem::Evaluate();
00873 }
00874
00875 virtual tString DoGetDescription() const
00876 {
00877 return expired_ ? tString("Expired vote") : description_;
00878 }
00879
00880 virtual tString DoGetDetails() const
00881 {
00882 return expired_ ? tString("Expired vote") : details_;
00883 }
00884 protected:
00885 mutable tString description_;
00886 mutable tString details_;
00887 private:
00888 bool expired_;
00889 };
00890
00891 static void se_HandleServerVoteChanged( nMessage& m )
00892 {
00893 eVoteItemServerControlled::s_HandleChanged( m );
00894 }
00895
00896 static void se_HandleNewServerVote( nMessage& m )
00897 {
00898 if ( sn_GetNetState() != nCLIENT || eVoteItem::AcceptNewVote( m ) )
00899 {
00900
00901 eVoteItem* item = tNEW( eVoteItemServerControlled )();
00902 if ( !item->FillFromMessage( m ) )
00903 delete item;
00904 }
00905 }
00906
00907 static nDescriptor new_server_vote_handler(232,se_HandleNewServerVote,"Server controlled vote");
00908
00909
00910 nDescriptor& eVoteItemServerControlled::DoGetDescriptor() const
00911 {
00912 return new_server_vote_handler;
00913 }
00914
00915
00916
00917
00918 class nMachineObserver: public nMachineDecorator
00919 {
00920 public:
00921 nMachineObserver( nMachine & machine )
00922 : nMachineDecorator( machine ), machine_( &machine ){}
00923
00924 nMachine * GetMachine()
00925 {
00926 return machine_;
00927 }
00928 protected:
00929 virtual void OnDestroy()
00930 {
00931 machine_ = 0;
00932 }
00933 private:
00934 nMachine * machine_;
00935 };
00936
00937 static tString se_voteKickToServer("");
00938 static int se_voteKickToPort = 4534;
00939 static tSettingItem< tString > se_voteKickToServerConf( "VOTE_KICK_TO_SERVER", se_voteKickToServer );
00940 static tSettingItem< int > se_voteKickToPortConf( "VOTE_KICK_TO_PORT", se_voteKickToPort );
00941
00942
00943
00944
00945 static int se_kickMinHarm = 0;
00946 static tSettingItem< int > se_kickMinHarmSI( "VOTING_KICK_MINHARM", se_kickMinHarm );
00947
00948
00949 static tString se_voteKickReason("");
00950 static tConfItemLine se_voteKickReasonConf( "VOTE_KICK_REASON", se_voteKickReason );
00951
00952 void se_VoteKickUser( int user )
00953 {
00954 if ( user == 0 )
00955 {
00956 return;
00957 }
00958
00959 tString reason;
00960 if ( se_voteKickReason.Len() >= 2 )
00961 {
00962 reason = se_voteKickReason;
00963 }
00964 else
00965 {
00966 reason = tOutput("$voted_kill_kick");
00967 }
00968
00969 if ( se_voteKickToServer.Len() < 2 )
00970 {
00971 sn_KickUser( user, reason );
00972 }
00973 else
00974 {
00975
00976 nServerInfoRedirect redirect( se_voteKickToServer, se_voteKickToPort );
00977 sn_KickUser( user, reason, 1, &redirect );
00978 }
00979 }
00980
00981 void se_VoteKickPlayer( ePlayerNetID * p )
00982 {
00983 if ( !p )
00984 {
00985 return;
00986 }
00987
00988 se_VoteKickUser( p->Owner() );
00989 }
00990
00991
00992 class eVoteItemHarm: public virtual eVoteItem
00993 {
00994 public:
00995
00996 eVoteItemHarm( ePlayerNetID* player = 0 )
00997 : player_( player )
00998 , machine_(NULL)
00999 , name_( "(Player who already left)" )
01000 {}
01001
01002 ~eVoteItemHarm()
01003 {
01004 delete machine_;
01005 machine_ = NULL;
01006 }
01007
01008
01009 ePlayerNetID * GetPlayer() const
01010 {
01011 ePlayerNetID const * player = player_;
01012 return const_cast< ePlayerNetID * >( player );
01013 }
01014 protected:
01015
01016 virtual nDescriptor * DoGetDescriptorLegacy() const
01017 {
01018 return &eVoteItemHarm::DoGetDescriptor();
01019 }
01020
01021 virtual void DoFillToMessageLegacy( nMessage& m ) const
01022 {
01023 return eVoteItemHarm::DoFillToMessage( m );
01024 };
01025
01026 virtual bool DoFillFromMessage( nMessage& m )
01027 {
01028
01029 unsigned short id;
01030 m.Read(id);
01031 tJUST_CONTROLLED_PTR< ePlayerNetID > p=dynamic_cast<ePlayerNetID *>(nNetObject::ObjectDangerous(id));
01032 player_ = p;
01033
01034 return eVoteItem::DoFillFromMessage( m );
01035 }
01036
01037 virtual bool DoCheckValid( int senderID )
01038 {
01039
01040 if ( sn_GetNetState() == nCLIENT && senderID == 0 )
01041 {
01042 return true;
01043 }
01044
01045 eVoter * sender = eVoter::GetVoter( senderID );
01046
01047 double time = tSysTimeFloat();
01048
01049
01050 if ( sender && sender->lastChange_ + se_votingMaturity > tSysTimeFloat() && sender->lastChange_ * 2 > tSysTimeFloat() )
01051 {
01052 REAL time = sender->lastChange_ + se_votingMaturity - tSysTimeFloat();
01053 tOutput message( "$vote_maturity", time );
01054 sn_ConsoleOut( message, senderID );
01055 return false;
01056 }
01057
01058
01059 if ( sender )
01060 sender->lastNameChangePreventor_ = time;
01061
01062
01063 if ( player_ && sn_GetNetState() != nCLIENT )
01064 {
01065
01066 if ( player_->Owner() == 0 )
01067 {
01068 sn_ConsoleOut( tOutput( "$vote_kick_local", player_->GetName() ), senderID );
01069 return false;
01070 }
01071
01072 name_ = player_->GetName();
01073 eVoter * voter = eVoter::GetVoter( player_->Owner() );
01074 if ( voter )
01075 {
01076 machine_ = tNEW( nMachineObserver )( voter->machine_ );
01077
01078 if ( time < voter->lastHarmVote_ + se_minTimeBetweenHarms )
01079 {
01080 tOutput message("$vote_redundant");
01081 sn_ConsoleOut( message, senderID );
01082 return false;
01083 }
01084 else
01085 {
01086 voter->lastHarmVote_ = time;
01087 voter->lastNameChangePreventor_ = time;
01088 }
01089
01090
01091 voter->harmCount_++;
01092 }
01093 }
01094
01095 return eVoteItem::DoCheckValid( senderID );
01096 };
01097
01098 virtual void DoFillToMessage( nMessage& m ) const
01099 {
01100 if ( player_ )
01101 m.Write( player_->ID() );
01102 else
01103 m.Write( 0 );
01104
01105 eVoteItem::DoFillToMessage( m );
01106 };
01107
01108 protected:
01109 virtual nDescriptor& DoGetDescriptor() const;
01110
01111
01112 virtual char const * DoGetPrefix() const = 0;
01113
01114 virtual tString DoGetDescription() const
01115 {
01116
01117 if ( player_ )
01118 name_ = player_->GetName();
01119
01120 return tString( tOutput( tString("$") + DoGetPrefix() + "_player_text", name_ ) );
01121 }
01122
01123 virtual tString DoGetDetails() const
01124 {
01125
01126 if ( player_ )
01127 name_ = player_->GetName();
01128
01129 return eVoteItem::DoGetDetails() + tString( tOutput( tString("$") + DoGetPrefix() + "_player_details_text", name_ ) );
01130 }
01131
01132 nMachine * GetMachine() const
01133 {
01134 if ( !machine_ )
01135 {
01136 return 0;
01137 }
01138 else
01139 {
01140 return machine_->GetMachine();
01141 }
01142 }
01143 private:
01144 nObserverPtr< ePlayerNetID > player_;
01145 nMachineObserver * machine_;
01146 mutable tString name_;
01147 };
01148
01149
01150 class eVoteItemKick: public virtual eVoteItemHarm
01151 {
01152 public:
01153
01154 eVoteItemKick( ePlayerNetID* player )
01155 : eVoteItemHarm( player )
01156 {}
01157
01158 ~eVoteItemKick()
01159 {}
01160
01161 protected:
01162
01163 virtual char const * DoGetPrefix() const{ return "kick"; }
01164
01165 #ifdef KRAWALL_SERVER
01166
01167 virtual tAccessLevel DoGetAccessLevel() const
01168 {
01169 return se_accessLevelVoteKick;
01170 }
01171 #endif
01172
01173
01174 virtual int DoGetExtraBias() const
01175 {
01176 return se_votingBiasKick;
01177 }
01178
01179 virtual bool DoCheckValid( int senderID )
01180 {
01181 ePlayerNetID * player = GetPlayer();
01182
01183
01184 if ( player && sn_GetNetState() != nCLIENT )
01185 {
01186 eVoter * voter = eVoter::GetVoter( player->Owner() );
01187 if ( voter )
01188 {
01189 double time = tSysTimeFloat();
01190 if ( time < voter->lastKickVote_ + se_minTimeBetweenKicks )
01191 {
01192 tOutput message("$vote_redundant");
01193 sn_ConsoleOut( message, senderID );
01194 return false;
01195 }
01196 else
01197 {
01198 voter->lastKickVote_ = time;
01199 voter->lastNameChangePreventor_ = time;
01200 }
01201 }
01202 }
01203
01204 return eVoteItemHarm::DoCheckValid( senderID );
01205 };
01206
01207 virtual void DoExecute()
01208 {
01209 ePlayerNetID * player = GetPlayer();
01210 nMachine * machine = GetMachine();
01211 if ( player )
01212 {
01213
01214 se_VoteKickPlayer( player );
01215 }
01216 else if ( machine )
01217 {
01218
01219
01220 bool kick = false;
01221 for ( int user = MAXCLIENTS; user > 0; --user )
01222 {
01223 if ( &nMachine::GetMachine( user ) == machine )
01224 {
01225 se_VoteKickUser( user );
01226 kick = true;
01227 }
01228 }
01229
01230
01231
01232 if ( !kick )
01233 {
01234 machine->OnKick();
01235 }
01236 }
01237 }
01238
01239 private:
01240 };
01241
01242
01243 class eVoteItemHarmServerControlled: public virtual eVoteItemServerControlled, public virtual eVoteItemHarm
01244 {
01245 public:
01246
01247 eVoteItemHarmServerControlled( ePlayerNetID* player = 0 )
01248 : eVoteItemHarm( player )
01249 {}
01250
01251 ~eVoteItemHarmServerControlled()
01252 {}
01253 protected:
01254 virtual bool DoFillFromMessage( nMessage& m )
01255 {
01256
01257 tASSERT( sn_GetNetState() != nCLIENT );
01258
01259
01260 bool ret = eVoteItemHarm::DoFillFromMessage( m );
01261
01262
01263 Update();
01264
01265 return ret;
01266 };
01267
01268 virtual void DoFillToMessage( nMessage& m ) const
01269 {
01270
01271 tASSERT( sn_GetNetState() != nCLIENT );
01272
01273 eVoteItemServerControlled::DoFillToMessage( m );
01274 };
01275 private:
01276 virtual void Update()
01277 {
01278 description_ = eVoteItemHarm::DoGetDescription();
01279 details_ = eVoteItemHarm::DoGetDetails();
01280 }
01281
01282 virtual nDescriptor& DoGetDescriptor() const
01283 {
01284 return eVoteItemServerControlled::DoGetDescriptor();
01285 }
01286
01287 virtual tString DoGetDescription() const
01288 {
01289 return eVoteItemServerControlled::DoGetDescription();
01290 }
01291
01292 virtual tString DoGetDetails() const
01293 {
01294 return eVoteItemServerControlled::DoGetDetails();
01295 }
01296 };
01297
01298
01299 class eVoteItemSuspend: public virtual eVoteItemHarmServerControlled
01300 {
01301 public:
01302
01303 eVoteItemSuspend( ePlayerNetID* player = 0 )
01304 : eVoteItemHarm( player )
01305 {}
01306
01307 ~eVoteItemSuspend()
01308 {}
01309 protected:
01310
01311 virtual char const * DoGetPrefix() const{ return "suspend"; }
01312
01313 #ifdef KRAWALL_SERVER
01314
01315 virtual tAccessLevel DoGetAccessLevel() const
01316 {
01317 return se_accessLevelVoteSuspend;
01318 }
01319 #endif
01320
01321
01322 virtual int DoGetExtraBias() const
01323 {
01324 return se_votingBiasSuspend;
01325 }
01326
01327 virtual void DoExecute()
01328 {
01329 ePlayerNetID * player = GetPlayer();
01330 if ( player )
01331 {
01332 player->Suspend( se_suspendRounds );
01333 }
01334 }
01335 };
01336
01337
01338 class eVoteItemKickServerControlled: public virtual eVoteItemHarmServerControlled, public virtual eVoteItemKick
01339 {
01340 public:
01341
01342 eVoteItemKickServerControlled( bool fromMenu, ePlayerNetID* player )
01343 : eVoteItemHarm( player ), eVoteItemKick( player ), fromMenu_( fromMenu )
01344 {}
01345
01346 ~eVoteItemKickServerControlled()
01347 {}
01348 protected:
01349 virtual bool DoCheckValid( int senderID )
01350 {
01351
01352 ePlayerNetID * p = GetPlayer();
01353 if ( fromMenu_ && p && p->GetVoter()->HarmCount() - 1 < se_kickMinHarm )
01354 {
01355
01356 eVoteItem * item = tNEW ( eVoteItemSuspend )( p );
01357
01358
01359 if ( !item->CheckValid( senderID ) )
01360 {
01361 delete item;
01362 }
01363 else
01364 {
01365
01366 item->Update();
01367 item->ReBroadcast( senderID );
01368 }
01369
01370
01371 return false;
01372 }
01373
01374
01375 return eVoteItemHarm::DoCheckValid( senderID );
01376 };
01377
01378 virtual void DoExecute()
01379 {
01380 eVoteItemKick::DoExecute();
01381 }
01382 private:
01383 bool fromMenu_;
01384 };
01385
01386 static void se_HandleKickVote( nMessage& m )
01387 {
01388
01389 if ( eVoteItem::AcceptNewVote( m ) )
01390 {
01391 eVoteItemHarm* item = tNEW( eVoteItemKickServerControlled )( true, 0 );
01392 if ( !item->FillFromMessage( m ) )
01393 {
01394 delete item;
01395 return;
01396 }
01397 }
01398 }
01399
01400 static nDescriptor kill_vote_handler(231,se_HandleKickVote,"Kick vote");
01401
01402
01403 nDescriptor& eVoteItemHarm::DoGetDescriptor() const
01404 {
01405 return kill_vote_handler;
01406 }
01407
01408 static void se_SendKick( ePlayerNetID* p )
01409 {
01410 eVoteItemKick kick( p );
01411 kick.SendMessage();
01412 }
01413
01414 #ifdef KRAWALL_SERVER
01415
01416
01417 class eAccessConsoleFilter: public tConsoleFilter
01418 {
01419 public:
01420 eAccessConsoleFilter( tAccessLevel level )
01421 :level_( level )
01422 {
01423 }
01424
01425 void Send()
01426 {
01427 bool canSee[ MAXCLIENTS+1 ];
01428 for( int i = MAXCLIENTS; i>=0; --i )
01429 {
01430 canSee[i] = false;
01431 }
01432
01433
01434 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
01435 {
01436 ePlayerNetID* player = se_PlayerNetIDs(i);
01437 if ( player->GetAccessLevel() <= level_ )
01438 {
01439 canSee[ player->Owner() ] = true;
01440 }
01441 }
01442
01443
01444 for( int i = MAXCLIENTS; i>=0; --i )
01445 {
01446 if ( canSee[i] )
01447 {
01448 sn_ConsoleOut( message_, i );
01449 }
01450 }
01451
01452 message_.Clear();
01453 }
01454
01455 ~eAccessConsoleFilter()
01456 {
01457 Send();
01458 }
01459 private:
01460
01461 virtual int DoGetPriority() const{ return -100; }
01462
01463
01464 virtual void DoFilterLine( tString &line )
01465 {
01466
01467 message_ << tColoredString::ColorString(1,.3,.3) << "RA: " << tColoredString::ColorString(1,1,1) << line << "\n";
01468
01469
01470 if (message_.Len() > 600)
01471 { Send();
01472 }
01473 }
01474
01475 tAccessLevel level_;
01476 tColoredString message_;
01477 };
01478
01479
01480 class eVoteItemInclude: public eVoteItemServerControlled
01481 {
01482 public:
01483
01484 eVoteItemInclude( tString const & file, tAccessLevel submitterLevel )
01485 : eVoteItemServerControlled()
01486 , file_( file )
01487 {
01488 description_ = tOutput( "$vote_include_text", file );
01489 file_ = tString( "vote/" ) + file_;
01490 details_ = tOutput( "$vote_include_details_text", file_ );
01491
01492 if ( submitterLevel > se_accessLevelVoteIncludeExecute )
01493 {
01494 submitterLevel = se_accessLevelVoteIncludeExecute;
01495 }
01496 level_ = submitterLevel;
01497 }
01498
01499 ~eVoteItemInclude()
01500 {}
01501 protected:
01502
01503 virtual tAccessLevel DoGetAccessLevel() const
01504 {
01505 return se_accessLevelVoteInclude;
01506 }
01507
01508
01509 virtual int DoGetExtraBias() const
01510 {
01511 return se_votingBiasInclude;
01512 }
01513
01514 bool Open( std::ifstream & s, int userToNotify )
01515 {
01516 if ( tDirectories::Config().Open(s, file_ ) || tDirectories::Var().Open(s, file_ ) )
01517 {
01518 return true;
01519 }
01520 else
01521 {
01522 con << tOutput( "$vote_include_error", file_ );
01523 sn_ConsoleOut( tOutput( "$vote_include_error", file_ ), userToNotify );
01524 return false;
01525 }
01526 }
01527
01528 virtual bool DoCheckValid( int senderID )
01529 {
01530 std::ifstream s;
01531 return ( Open( s, senderID ) && eVoteItemServerControlled::DoCheckValid( senderID ) );
01532 }
01533
01534 virtual void DoExecute()
01535 {
01536
01537 tCurrentAccessLevel accessLevel( level_, true );
01538
01539
01540 std::ifstream s;
01541 if ( Open( s, 0 ) )
01542 {
01543 sn_ConsoleOut( tOutput( "$vote_include_message", file_ ) );
01544 eAccessConsoleFilter filter( level_ );
01545 tConfItemBase::LoadAll(s);
01546 tConfItemBase::LoadPlayback();
01547 }
01548 }
01549
01550 tString file_;
01551 tAccessLevel level_;
01552 };
01553
01554
01555 class eVoteItemCommand: public eVoteItemServerControlled
01556 {
01557 public:
01558
01559 eVoteItemCommand( tString const & command, tAccessLevel submitterLevel )
01560 : eVoteItemServerControlled()
01561 , command_( command )
01562 {
01563 description_ = tOutput( "$vote_command_text", command );
01564 details_ = tOutput( "$vote_command_details_text", command );
01565
01566 if ( submitterLevel > se_accessLevelVoteCommandExecute )
01567 {
01568 submitterLevel = se_accessLevelVoteCommandExecute;
01569 }
01570 level_ = submitterLevel;
01571 }
01572
01573 ~eVoteItemCommand()
01574 {}
01575 protected:
01576
01577 virtual tAccessLevel DoGetAccessLevel() const
01578 {
01579 return se_accessLevelVoteCommand;
01580 }
01581
01582
01583 virtual int DoGetExtraBias() const
01584 {
01585 return se_votingBiasCommand;
01586 }
01587
01588 virtual void DoExecute()
01589 {
01590
01591 tCurrentAccessLevel accessLevel( level_, true );
01592
01593
01594 std::istringstream s( static_cast< char const * >( command_ ) );
01595 sn_ConsoleOut( tOutput( "$vote_command_message" ) );
01596 eAccessConsoleFilter filter( tAccessLevel_Default );
01597 tConfItemBase::LoadLine(s);
01598 tConfItemBase::LoadPlayback();
01599 }
01600
01601 tString command_;
01602 tAccessLevel level_;
01603 };
01604
01605 #endif
01606
01607
01608
01609
01610
01611
01612 class eMenuItemKick: public uMenuItemAction
01613 {
01614 public:
01615 eMenuItemKick(uMenu *m, ePlayerNetID* p )
01616 : uMenuItemAction( m, tOutput(""),tOutput("$kick_player_help" ) )
01617 {
01618 this->name_.Clear();
01619 this->name_.SetTemplateParameter(1, p->GetName() );
01620 this->name_ << "$kick_player_text";
01621 player_ = p;
01622 }
01623
01624 ~eMenuItemKick()
01625 {
01626 }
01627
01628 virtual void Enter()
01629 {
01630 if(sn_GetNetState()==nSERVER)
01631 {
01632
01633 se_VoteKickPlayer( player_ );
01634 }
01635 {
01636
01637 se_SendKick( player_ );
01638 }
01639
01640
01641 this->menu->Exit();
01642 }
01643 private:
01644 tCONTROLLED_PTR( ePlayerNetID ) player_;
01645 };
01646
01647
01648
01649
01650
01651 static nSpamProtectionSettings se_voteSpamProtection( 50.0f, "SPAM_PROTECTION_VOTE", tOutput("$vote_spam_protection") );
01652
01653 eVoter::eVoter( nMachine & machine )
01654 : nMachineDecorator( machine ), machine_( machine ), votingSpam_( se_voteSpamProtection )
01655 {
01656 selfReference_ = this;
01657 voters_.Add( this );
01658 harmCount_ = 0;
01659 lastKickVote_ = -1E+40;
01660 lastHarmVote_ = -1E+40;
01661 lastNameChangePreventor_ = -1E+40;
01662 lastChange_ = tSysTimeFloat();
01663 }
01664
01665 eVoter::~eVoter()
01666 {
01667 voters_.Remove( this );
01668 }
01669
01670 void eVoter::Spam( int user, REAL spamLevel, tOutput const & message )
01671 {
01672 if ( sn_GetNetState() == nSERVER )
01673 votingSpam_.CheckSpam( spamLevel, user, message );
01674 }
01675
01676 bool eVoter::IsSpamming( int user )
01677 {
01678 if ( sn_GetNetState() == nSERVER )
01679 {
01680 return nSpamProtection::Level_Ok != votingSpam_.CheckSpam( 0.0f, user, tOutput("$spam_vote_kick_issue") );
01681 }
01682
01683 return false;
01684 }
01685
01686
01687
01688
01689
01690
01693
01694
01695 void eVoter::OnDestroy( void )
01696 {
01697 tJUST_CONTROLLED_PTR< eVoter > keepAlive( this );
01698 selfReference_ = 0;
01699 }
01700
01701
01702
01703
01704
01705
01706
01710
01711
01712 REAL eVoter::Age() const
01713 {
01714 return tSysTimeFloat() - lastChange_;
01715 }
01716
01717
01718
01719
01720
01721
01722
01723
01726
01727
01728 bool eVoter::AllowNameChange( void ) const
01729 {
01730 return tSysTimeFloat() > this->lastNameChangePreventor_ + se_minTimeBetweenKicks;
01731 }
01732
01733 void eVoter::RemoveFromGame()
01734 {
01735 tCONTROLLED_PTR( eVoter ) keeper( this );
01736
01737 voters_.Remove( this );
01738
01739
01740 for ( int i = eVoteItem::GetItems().Len()-1; i>=0; --i )
01741 {
01742 eVoteItem::GetItems()( i )->RemoveVoterCompletely( this );
01743 }
01744 }
01745
01746 void eVoter::KickMenu()
01747 {
01748 uMenu menu( "$player_police_kick_text" );
01749
01750 int size = se_PlayerNetIDs.Len();
01751 eMenuItemKick** items = tNEW( eMenuItemKick* )[ size ];
01752
01753 int i;
01754 for ( i = size-1; i>=0; --i )
01755 {
01756 ePlayerNetID* player = se_PlayerNetIDs[ i ];
01757 if ( player->IsHuman() )
01758 {
01759 items[i] = tNEW( eMenuItemKick )( &menu, player );
01760 }
01761 else
01762 {
01763 items[i] = 0;
01764 }
01765 }
01766
01767 menu.Enter();
01768
01769 for ( i = size - 1; i>=0; --i )
01770 {
01771 if( items[i] )
01772 delete items[i];
01773 }
01774 delete[] items;
01775 }
01776
01777 #ifndef DEDICATED
01778 static bool se_KeepConsoleSmall()
01779 {
01780 return true;
01781 }
01782 #endif
01783
01784 static uMenu* votingMenu = 0;
01785
01786 void eVoter::VotingMenu()
01787 {
01788 static bool recursion = false;
01789 if ( ! recursion )
01790 {
01791
01792
01793 if ( !VotingPossible() )
01794 return;
01795
01796 #ifndef DEDICATED
01797 rSmallConsoleCallback SmallConsole( se_KeepConsoleSmall );
01798
01799
01800 int size = eVoteItem::GetItems().Len();
01801 if ( size == 0 )
01802 return;
01803
01804
01805 uMenu menu( "$voting_menu_text" );
01806
01807 eMenuItemVote** items = tNEW( eMenuItemVote* )[ size ];
01808
01809 int i;
01810 for ( i = size-1; i>=0; --i )
01811 {
01812 items[i] = tNEW( eMenuItemVote )( &menu, eVoteItem::GetItems()( i ) );
01813 }
01814
01815
01816 recursion = true;
01817 votingMenu = &menu;
01818 menu.Enter();
01819 votingMenu = 0;
01820 recursion = false;
01821
01822 for ( i = size - 1; i>=0; --i )
01823 {
01824 delete items[i];
01825 }
01826 delete[] items;
01827
01828
01829 VotingPossible();
01830 #endif
01831 }
01832 }
01833
01834 bool eVoter::VotingPossible()
01835 {
01836
01837 for ( int i = eVoteItem::GetItems().Len()-1; i>=0; --i )
01838 {
01839 eVoteItem::GetItems()( i )->Evaluate();
01840 }
01841
01842 if ( sn_GetNetState() != nCLIENT )
01843 {
01844 return false;
01845 }
01846
01847 return eVoteItem::GetItems().Len() > 0;
01848 }
01849
01850 eVoter* eVoter::GetVoter( int ID, bool complain )
01851 {
01852
01853 #ifdef DEDICATED
01854 if ( ID == 0 )
01855 return NULL;
01856 #endif
01857
01858
01859 if ( !se_allowVotingSpectator )
01860 {
01861 bool player = false;
01862 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
01863 {
01864 ePlayerNetID* p = se_PlayerNetIDs(i);
01865 if ( p->Owner() == ID && !p->IsSpectating() )
01866 player = true;
01867 }
01868 if (!player)
01869 {
01870 if ( complain )
01871 {
01872 tOutput message("$vote_disabled_spectator");
01873 sn_ConsoleOut( message, ID );
01874 }
01875 return NULL;
01876 }
01877 }
01878
01879
01880 nMachine & machine = nMachine::GetMachine( ID );
01881
01882 return GetVoter( machine );
01883 }
01884
01885 eVoter* eVoter::GetVoter( nMachine & machine )
01886 {
01887
01888 nMachineDecorator * run = machine.GetDecorators();
01889 while ( run )
01890 {
01891 eVoter * voter = dynamic_cast< eVoter * >( run );
01892 if ( voter )
01893 {
01894
01895 if ( voter->ListID() < 0 )
01896 {
01897 voters_.Add( voter );
01898 voter->lastKickVote_ = -1E30;
01899 voter->lastNameChangePreventor_ = -1E30;
01900 }
01901
01902
01903 return voter;
01904 }
01905
01906 run = run->Next();
01907 }
01908
01909
01910 return tNEW(eVoter)( machine );
01911 }
01912
01913 tList< eVoter > eVoter::voters_;
01914
01915 static void se_Cleanup()
01916 {
01917 if ( nCallbackLoginLogout::User() == 0 )
01918 {
01919 if ( votingMenu )
01920 {
01921 votingMenu->Exit();
01922 }
01923
01924 if ( !nCallbackLoginLogout::Login() && eGrid::CurrentGrid() )
01925 {
01926
01927 }
01928
01929
01930 const tList< eVoteItem >& list = eVoteItem::GetItems();
01931 while ( list.Len() > 0 )
01932 {
01933 delete list(0);
01934 }
01935 }
01936 else if ( nCallbackLoginLogout::Login() )
01937 {
01938
01939 const tList< eVoteItem >& list = eVoteItem::GetItems();
01940 for ( int i = list.Len()-1; i >= 0; -- i)
01941 {
01942 eVoteItem* vote = list( i );
01943 nMessage* m = vote->CreateMessage();
01944 m->Send( nCallbackLoginLogout::User() );
01945 }
01946 }
01947 }
01948
01949
01950 static nCallbackLoginLogout se_cleanup( se_Cleanup );
01951
01952 eVoteItem::~eVoteItem( void )
01953 {
01954 items_.Remove( this );
01955
01956 if ( menuItem_ )
01957 {
01958 menuItem_->item_ = 0;
01959 menuItem_->title.Clear();
01960 menuItem_->helpText.Clear();
01961 menuItem_ = 0;
01962 }
01963 }
01964
01965 void eVoteItem::UpdateMenuItem( void )
01966 {
01967 if ( menuItem_ )
01968 {
01969 menuItem_->title.Clear();
01970 menuItem_->title = GetDescription();
01971
01972 menuItem_->helpText.Clear();
01973 menuItem_->helpText << tString( tOutput( "$vote_details_help", GetDetails() ) );
01974 }
01975 }
01976
01977
01978
01979
01980
01981
01986
01987
01988 tString eVoter::Name( int senderID ) const
01989 {
01990 tString name;
01991
01992
01993 for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i )
01994 {
01995 ePlayerNetID* p = se_PlayerNetIDs(i);
01996 if ( eVoter::GetVoter( p->Owner() ) == this && ( senderID < 0 || p->Owner() == senderID ) )
01997 {
01998 if ( name.Len() > 1 )
01999 name << ", ";
02000 name << p->GetName();
02001 }
02002 }
02003
02004 if ( name.Len() < 2 )
02005 name = machine_.GetIP();
02006
02007 return name;
02008 }
02009
02010
02011
02012
02013
02014
02017
02018
02019 void eVoter::PlayerChanged( void )
02020 {
02021 this->lastChange_ = tSysTimeFloat();
02022 }
02023
02024
02025
02026
02027
02028
02031
02032
02033 void eVoter::HandleChat( ePlayerNetID * p, std::istream & message )
02034 {
02035
02036 nCurrentSenderID cloak;
02037 if ( se_votingPrivacy > 1 )
02038 cloak.SetID(0);
02039
02040 if ( !p )
02041 {
02042 return;
02043 }
02044
02045
02046 tString command;
02047 message >> command;
02048 tToLower( command );
02049
02050 eVoter * voter = p->GetVoter();
02051 if ( !eVoteItem::AcceptNewVote( voter, p->Owner() ) )
02052 {
02053 return;
02054 }
02055
02056 eVoteItem * item = 0;
02057
02058 if ( command == "kick" )
02059 {
02060 tString name;
02061 name.ReadLine( message );
02062 ePlayerNetID * toKick = ePlayerNetID::FindPlayerByName( name, p );
02063 if ( toKick )
02064 {
02065
02066 item = tNEW( eVoteItemKickServerControlled )( false, toKick );
02067 }
02068 }
02069 else if ( command == "suspend" )
02070 {
02071 tString name;
02072 name.ReadLine( message );
02073 ePlayerNetID * toSuspend = ePlayerNetID::FindPlayerByName( name, p );
02074 if ( toSuspend )
02075 {
02076
02077 item = tNEW( eVoteItemSuspend )( toSuspend );
02078 }
02079 }
02080 #ifdef KRAWALL_SERVER
02081 else if ( command == "include" )
02082 {
02083 tString file;
02084 file.ReadLine( message );
02085 {
02086
02087 item = tNEW( eVoteItemInclude )( file, p->GetAccessLevel() );
02088 }
02089 }
02090 else if ( command == "command" )
02091 {
02092 tString console;
02093 console.ReadLine( message );
02094 {
02095
02096 item = tNEW( eVoteItemCommand )( console, p->GetAccessLevel() );
02097 }
02098 }
02099 #endif
02100 else
02101 {
02102 #ifdef KRAWALL_SERVER
02103 sn_ConsoleOut( tOutput("$vote_unknown_command", command, "suspend, kick, include, command" ), p->Owner() );
02104 #else
02105 sn_ConsoleOut( tOutput("$vote_unknown_command", command, "suspend, kick" ), p->Owner() );
02106 #endif
02107 }
02108
02109
02110 if ( !item )
02111 {
02112 return;
02113 }
02114
02115
02116 if ( !item->CheckValid( p->Owner() ) )
02117 {
02118 delete item;
02119 return;
02120 }
02121
02122
02123 item->Update();
02124 item->ReBroadcast( p->Owner() );
02125 }
02126