/* ************************************************************************* ArmageTron -- Just another Tron Lightcycle Game in 3D. Copyright (C) 2000 Manuel Moos (manuel@moosnet.de) ************************************************************************** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *************************************************************************** */ #include "tMemManager.h" #include "ePlayer.h" //#include "tInitExit.h" #include "tConfiguration.h" #include "eNetGameObject.h" #include "rConsole.h" #include "eTimer.h" #include "tSysTime.h" #include "rFont.h" #include "uMenu.h" #include "tToDo.h" #include "rScreen.h" #include #include #include #include "rRender.h" #include "rSysdep.h" #include "nAuthentification.h" #include "tDirectories.h" #include "eTeam.h" #include "eVoter.h" #include "tReferenceHolder.h" #include "nServerInfo.h" #include "nConfig.h" #include tList se_PlayerNetIDs; static ePlayer* se_Players = NULL; static tReferenceHolder< ePlayerNetID > se_PlayerReferences; class PasswordStorage { public: tString username; nKrawall::nScrambledPassword password; bool save; PasswordStorage(): save(false){}; }; static tArray S_passwords; void se_DeletePasswords(){ S_passwords.SetLen(0); st_SaveConfig(); /* REAL timeout = tSysTimeFloat() + 3; while(tSysTimeFloat() < timeout){ sr_ResetRenderState(true); rViewport::s_viewportFullscreen.Select(); sr_ClearGL(); uMenu::GenericBackground(); REAL w=16*3/640.0; REAL h=32*3/480.0; //REAL middle=-.6; Color(1,1,1); DisplayText(0,.8,w,h,tOutput("$network_opts_deletepw_complete")); sr_SwapGL(); } */ tConsole::Message("$network_opts_deletepw_complete", tOutput(), 5); } class tConfItemPassword:public tConfItemBase{ public: tConfItemPassword():tConfItemBase("PASSWORD"){} ~tConfItemPassword(){}; // write the complete passwords virtual void WriteVal(std::ostream &s){ int i; bool first = 1; for (i = S_passwords.Len()-1; i>=0; i--) { PasswordStorage &storage = S_passwords[i]; if (storage.save) { if (!first) s << "\nPASSWORD\t"; first = false; s << "1 "; nKrawall::WriteScrambledPassword(storage.password, s); s << '\t' << storage.username; } } if (first) s << "0 "; } // read one password virtual void ReadVal(std::istream &s){ // static char in[20]; int test; s >> test; if (test != 0) { PasswordStorage &storage = S_passwords[S_passwords.Len()]; nKrawall::ReadScrambledPassword(s, storage.password); storage.username.ReadLine(s); storage.save = true; } } }; static tConfItemPassword p; // password request menu class eMenuItemPassword: public uMenuItemString { public: eMenuItemPassword(uMenu *M,tString &c): uMenuItemString(M,"$login_password_title","$login_password_help",c){} virtual ~eMenuItemPassword(){} virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0) { tString* pwback = content; tString star; for (int i=content->Len()-2; i>=0; i--) star << "*"; content = ☆ uMenuItemString::Render(x,y, alpha, selected); content = pwback; } virtual bool Event(SDL_Event &e){ #ifndef DEDICATED if (e.type==SDL_KEYDOWN && (e.key.keysym.sym==SDLK_KP_ENTER || e.key.keysym.sym==SDLK_RETURN)){ MyMenu()->Exit(); return true; } // else if (e.type==SDL_KEYDOWN && // uActionGlobal::IsBreakingGlobalBind(e.key.keysym.sym)) // return su_HandleEvent(e); else #endif return uMenuItemString::Event(e); } }; static bool tr(){return true;} static uMenu *S_login=NULL; static void cancelLogin() { if (S_login) S_login->Exit(); S_login = NULL; } // password storage mode int se_PasswordStorageMode = 0; // 0: store in memory, -1: don't store, 1: store on file static tConfItem pws("PASSWORD_STORAGE", "$password_storage_help", se_PasswordStorageMode); static void PasswordCallback(tString& username, const tString& message, nKrawall::nScrambledPassword& scrambled, bool failure) { int i; // find the player with the given username: ePlayer* p = NULL; for (i = MAX_PLAYERS-1; i>=0; i--) if (ePlayer::PlayerConfig(i)->name == username) p = ePlayer::PlayerConfig(i); if (!p) p = ePlayer::PlayerConfig(0); // try to find the username in the saved passwords: PasswordStorage *storage = NULL; for (i = S_passwords.Len()-1; i>=0; i--) if (p->name == S_passwords(i).username) storage = &S_passwords(i); if (!storage) { // find an empty slot for (i = S_passwords.Len()-1; i>=0; i--) if (S_passwords(i).username.Len() < 1) storage = &S_passwords(i); if (!storage) storage = &S_passwords[S_passwords.Len()]; failure = true; } // immediately return the stored password if it was not marked as wrong: if (!failure) { username = storage->username; memcpy(scrambled, storage->password, sizeof(nKrawall::nScrambledPassword)); return; } else storage->username.Clear(); // password was not stored. Request it from user: uMenu login(message, false); // password storage; tString password; eMenuItemPassword pw(&login, password); uMenuItemString us(&login, "$login_username","$login_username_help", p->name); uMenuItemSelection storepw(&login, "$login_storepw_text", "$login_storepw_help", se_PasswordStorageMode); storepw.NewChoice("$login_storepw_dont_text", "$login_storepw_dont_help", -1); storepw.NewChoice("$login_storepw_mem_text", "$login_storepw_mem_help", 0); storepw.NewChoice("$login_storepw_disk_text", "$login_storepw_disk_help", 1); uMenuItemFunction cl(&login, "$login_cancel", "$login_cancel_help", &cancelLogin); login.SetSelected(1); // force a small console while we are in here rSmallConsoleCallback cb(&tr); S_login = &login; login.Enter(); // return username/scrambled password if (S_login) { username = p->name; nKrawall::ScramblePassword(password, scrambled); // clear the PW from memory for (i = password.Len()-2; i>=0; i--) password(i) = 'a'; if (se_PasswordStorageMode >= 0) { storage->username = p->name; memcpy(storage->password, scrambled, sizeof(nKrawall::nScrambledPassword)); storage->save = (se_PasswordStorageMode > 0); } } else // or log out sn_SetNetState(nSTANDALONE); S_login = NULL; } static void ResultCallback(const tString& username, const tString& origUsername, int user, bool success) { int i; if (success) { bool found = false; for (i = se_PlayerNetIDs.Len()-1; i>=0 && !found; i--) { ePlayerNetID *p = se_PlayerNetIDs(i); if (p->Owner() == user && p->name == origUsername) { p->name = username; p->Auth(); found = true; } } for (i = se_PlayerNetIDs.Len()-1; i>=0 && !found; i--) { ePlayerNetID *p = se_PlayerNetIDs(i); if (p->Owner() == user && p->name == username) { p->Auth(); found = true; } } for (i = se_PlayerNetIDs.Len()-1; i>=0 && !found; i--) { ePlayerNetID *p = se_PlayerNetIDs(i); if (p->Owner() == user) { p->name = username; p->Auth(); found = true; } } // request other logins for (i = se_PlayerNetIDs.Len()-1; i>=0; i--) { ePlayerNetID *p = se_PlayerNetIDs(i); p->IsAuth(); } } else { if (sn_GetNetState() == nSERVER) nAuthentification::RequestLogin(username, user, "$login_request_failed", true); } } // menu item to silence selected players class eMenuItemSilence: public uMenuItemToggle { public: eMenuItemSilence(uMenu *m, ePlayerNetID* p ) : uMenuItemToggle( m, tOutput(""),tOutput("$silence_player_help" ), p->AccessSilenced() ) { this->title.Clear(); this->title.SetTemplateParameter(1, p->name ); this->title << "$silence_player_text"; player_ = p; } ~eMenuItemSilence() { } private: tCONTROLLED_PTR( ePlayerNetID ) player_; // keep player referenced }; // menu where you can silence players void ePlayerNetID::SilenceMenu() { uMenu menu( "$player_police_silence_text" ); int size = se_PlayerNetIDs.Len(); eMenuItemSilence** items = tNEW( eMenuItemSilence* )[ size ]; int i; for ( i = size-1; i>=0; --i ) { ePlayerNetID* player = se_PlayerNetIDs[ i ]; if ( player->IsHuman() ) { items[i] = tNEW( eMenuItemSilence )( &menu, player ); } else { items[i] = 0; } } menu.Enter(); for ( i = size - 1; i>=0; --i ) { if( items[i] ) delete items[i]; } delete[] items; } void ePlayerNetID::PoliceMenu() { uMenu menu( "$player_police_text" ); uMenuItemFunction kick( &menu, "$player_police_kick_text", "$player_police_kick_help", eVoter::KickMenu ); uMenuItemFunction silence( &menu, "$player_police_silence_text", "$player_police_silence_help", ePlayerNetID::SilenceMenu ); menu.Enter(); } static char *default_instant_chat[MAX_INSTANT_CHAT]= {"LOL!", ":-)", ":-(", "Well done!", "Almost got you...", "Hehe!", "Got one!", "", "", "", "", ""}; ePlayer * ePlayer::PlayerConfig(int p){ uPlayerPrototype *P = uPlayerPrototype::PlayerConfig(p); return dynamic_cast(P); // return (ePlayer*)P; } void ePlayer::StoreConfitem(tConfItemBase *c){ tASSERT(CurrentConfitem < PLAYER_CONFITEMS); configuration[CurrentConfitem++] = c; } void ePlayer::DeleteConfitems(){ while (CurrentConfitem>0){ CurrentConfitem--; tDESTROY(configuration[CurrentConfitem]); } } uActionPlayer *ePlayer::se_instantChatAction[MAX_INSTANT_CHAT]; static const tString& se_UserName() { srand( (unsigned)time( NULL ) ); static tString ret = getenv( "USER" ); return ret; } ePlayer::ePlayer(){ nAuthentification::SetUserPasswordCallback(&PasswordCallback); nAuthentification::SetLoginResultCallback (&ResultCallback); nameTeamAfterMe = false; favoriteNumberOfPlayersPerTeam = 3; CurrentConfitem = 0; bool getUserName = false; if ( id == 0 ) { name = se_UserName(); getUserName = ( name.Len() > 1 ); } if ( !getUserName ) name << "Player " << id+1; tString confname; confname << "PLAYER_"<< id+1; StoreConfitem(tNEW(tConfItemLine) (confname, "$player_name_confitem_help", name)); confname.Clear(); confname << "CAMCENTER_"<< id+1; centerIncamOnTurn=true; StoreConfitem(tNEW(tConfItem) (confname, "$camcenter_help", centerIncamOnTurn) ); confname.Clear(); startCamera=CAMERA_SMART; confname << "START_CAM_"<< id+1; StoreConfitem(tNEW(tConfItem) (confname, "$start_cam_help", reinterpret_cast(startCamera))); confname.Clear(); confname << "START_FOV_"<< id+1; startFOV=90; StoreConfitem(tNEW(tConfItem) (confname, "$start_fov_help", startFOV)); confname.Clear(); int i; for(i=CAMERA_SMART_IN;i>=0;i--){ confname << "ALLOW_CAM_"<< id+1 << "_" << i; StoreConfitem(tNEW(tConfItem) (confname, "$allow_cam_help", allowCam[i])); allowCam[i]=true; confname.Clear(); } for(i=MAX_INSTANT_CHAT-1;i>=0;i--){ confname << "INSTANT_CHAT_STRING_" << id+1 << '_' << i+1; StoreConfitem(tNEW(tConfItemLine) (confname, "$instant_chat_string_help", instantChatString[i])); instantChatString[i]=default_instant_chat[i]; confname.Clear(); } confname << "SPECTATOR_MODE_"<< id+1; StoreConfitem(tNEW(tConfItem)(confname, "$spectator_mode_help", spectate)); spectate=false; confname.Clear(); confname << "NAME_TEAM_AFTER_PLAYER_"<< id+1; StoreConfitem(tNEW(tConfItem)(confname, "$name_team_after_player_help", nameTeamAfterMe)); nameTeamAfterMe=false; confname.Clear(); confname << "FAV_NUM_PER_TEAM_PLAYER_"<< id+1; StoreConfitem(tNEW(tConfItem)(confname, "$fav_num_per_team_player_help", favoriteNumberOfPlayersPerTeam )); favoriteNumberOfPlayersPerTeam = 3; confname.Clear(); confname << "AUTO_INCAM_"<< id+1; autoSwitchIncam=false; StoreConfitem(tNEW(tConfItem) (confname, "$auto_incam_help", autoSwitchIncam)); confname.Clear(); confname << "CAMWOBBLE_"<< id+1; wobbleIncam=false; StoreConfitem(tNEW(tConfItem) (confname, "$camwobble_help", wobbleIncam)); confname.Clear(); confname << "COLOR_B_"<< id+1; StoreConfitem(tNEW(tConfItem) (confname, "$color_b_help", rgb[2])); confname.Clear(); confname << "COLOR_G_"<< id+1; StoreConfitem(tNEW(tConfItem) (confname, "$color_g_help", rgb[1])); confname.Clear(); confname << "COLOR_R_"<< id+1; StoreConfitem(tNEW(tConfItem) (confname, "$color_r_help", rgb[0])); confname.Clear(); static int r = rand() / ( RAND_MAX >> 2 ) + se_UserName().Len(); int cid = ( r + id ) % 4; static REAL R[MAX_PLAYERS]={1,.2,.2,1}; static REAL G[MAX_PLAYERS]={.2,1,.2,1}; static REAL B[MAX_PLAYERS]={.2,.2,1,.2}; rgb[0]=int(R[cid]*15); rgb[1]=int(G[cid]*15); rgb[2]=int(B[cid]*15); cam=NULL; } ePlayer::~ePlayer(){ tCHECK_DEST; DeleteConfitems(); } #ifndef DEDICATED void ePlayer::Render(){ if (cam) cam->Render(); } #endif static void se_DisplayChatLocally( ePlayerNetID* p, const tString& say ) { if ( p && !p->IsSilenced() ) { tString say2 = say; say2.RemoveHex(); tString message; message << *p; message << ": " << ColorString(1,1,.5) << say2 << '\n'; con << message; } } static nVersionFeature se_chatRelay( 3 ); void handle_chat( nMessage& ); static nDescriptor chat_handler(200,handle_chat,"Chat"); static nMessage* se_NewChatMessage( ePlayerNetID* player, const tString& message ) { tASSERT( player ); nMessage *m=tNEW(nMessage) (chat_handler); m->Write( player->ID() ); if ( message.Len() <= se_SpamMaxLen ) *m << message; else { tString cut( message ); cut.SetLen( se_SpamMaxLen ); *m << cut; } return m; } static nMessage* se_OldChatMessage( ePlayerNetID* player, const tString& message ) { tASSERT( player ); tString console; console << *player; console << " : " << ColorString(1,1,.5) << message << '\n'; nMessage *m = sn_ConsoleOutMessage( console ); return m; } void se_BroadcastChat( ePlayerNetID* p, const tString& say ) { // create chat messages tJUST_CONTROLLED_PTR< nMessage > mNew = se_NewChatMessage( p, say ); tJUST_CONTROLLED_PTR< nMessage > mOld = se_OldChatMessage( p, say ); // send them to the users for ( int user = MAXCLIENTS; user > 0; --user ) { if ( sn_Connections[ user ].socket > 0 ) { if ( sn_Connections[ user ].version.Max() >= 3 ) mNew->Send( user ); else mOld->Send( user ); } } } //The Basic Remote Admin Password static tString sg_adminPass = "NONE"; static tConfItemLine sg_adminPassConf( "ADMIN_PASS", sg_adminPass ); void handle_chat(nMessage &m){ nTimeRolling currentTime = tSysTimeFloat(); unsigned short id; m.Read(id); tString say; m >> say; tJUST_CONTROLLED_PTR< ePlayerNetID > p=dynamic_cast(nNetObject::ObjectDangerous(id)); if(sn_GetNetState()==nSERVER){ if (p) { // check if the player is owned by the sender to avoid cheating if( p->Owner() != m.SenderID() ) { Cheater( m.SenderID() ); nReadError(); return; } // spam protection: REAL lengthMalus = say.Len() / 20.0; if ( lengthMalus > 4.0 ) { lengthMalus = 4.0; } // if (p->lastSaid[0] && (p->lastSaid[0] == say)) { /* if (p->lastSaid[0] == say) { return; } else { p->lastSaid[0] = say; } */ double acceptableTime = 5; bool alreadySaid = false; for (short unsigned int c=0; c<4; c++) { if ((say == p->lastSaid[c]) && ((currentTime - p->lastSaidTimes[c]) < acceptableTime)) { alreadySaid = true; } } if (alreadySaid) { return; } else { p->lastSaid[12] = p->lastSaid[11]; p->lastSaidTimes[12] = p->lastSaidTimes[11]; p->lastSaid[11] = p->lastSaid[10]; p->lastSaidTimes[11] = p->lastSaidTimes[10]; p->lastSaid[10] = p->lastSaid[9]; p->lastSaidTimes[10] = p->lastSaidTimes[9]; p->lastSaid[9] = p->lastSaid[8]; p->lastSaidTimes[9] = p->lastSaidTimes[8]; p->lastSaid[8] = p->lastSaid[7]; p->lastSaidTimes[8] = p->lastSaidTimes[7]; p->lastSaid[7] = p->lastSaid[6]; p->lastSaidTimes[7] = p->lastSaidTimes[6]; p->lastSaid[6] = p->lastSaid[5]; p->lastSaidTimes[6] = p->lastSaidTimes[5]; p->lastSaid[5] = p->lastSaid[4]; p->lastSaidTimes[5] = p->lastSaidTimes[4]; p->lastSaid[4] = p->lastSaid[3]; p->lastSaidTimes[4] = p->lastSaidTimes[3]; p->lastSaid[3] = p->lastSaid[2]; p->lastSaidTimes[3] = p->lastSaidTimes[2]; p->lastSaid[2] = p->lastSaid[1]; p->lastSaidTimes[2] = p->lastSaidTimes[1]; p->lastSaid[1] = p->lastSaid[0]; p->lastSaidTimes[1] = p->lastSaidTimes[0]; p->lastSaid[0] = say; p->lastSaidTimes[0] = currentTime; } nSpamProtection::Level spamLevel = p->chatSpam_.CheckSpam( 1.0f + lengthMalus, m.SenderID() ); bool pass = false; tString command="", say2=say; if (say.ge2(sg_adminPass) && sg_adminPass != "NONE" && sg_adminPass != ""){ // con << "passed\n"; pass = true; for (int i=sg_adminPass.Len(); i= "say") { if (command.ge2("say")) { tString tocm = "", out =""; for (int i=4; i= "com") { else if (command.ge2("com")) { tString tocm = "", out=""; for (int i=4; i= "cm") { else if (command.ge2("cm")) { tString tocm = ""; for (int i=3; i= "ul") { else if (command.ge2("ul")) { for ( int i2 = se_PlayerNetIDs.Len()-1; i2>=0; --i2 ) { ePlayerNetID* p2 = se_PlayerNetIDs(i2); tString tos; tos << p2->Owner(); tos << ": "; tos << p2->name; tos << "\n"; sn_ConsoleOut(tos, p->Owner()); } } //kill player command, should be useful for mis-behaving people :D //else if (command >= "ki") { /* else if (command.ge2("ki")) { tString toki = ""; for (int i=3; i 16 || helper < 0) {sn_ConsoleOut("bad user id.\n ", p->Owner()); return;} else if (helper == p->Owner()) {sn_ConsoleOut("why you want to kill urself silly!\n", p->Owner()); return;} ePlayerNetID* p2 = se_PlayerNetIDs(helper); if (p2->Object()->Alive()) { con << "about to kill\n"; p2->Object()->Kill(); con << "killed.\n"; } //sn_ConsoleOut(p2->name + " has been killed", p->Owner()); } */ //else if (command >= "nm") { // else if (command.ge2("nm")) { //Start new match here // } // added in kick command //else if (command >= "ku") { else if (command.ge2("ku")) { tString toku = "", reason = ""; for (int i=3; i 6) { for (int i=6; i 16 || helper < 0) {sn_ConsoleOut("bad user id.\n ", p->Owner()); return;} else if (helper == p->Owner()) {sn_ConsoleOut("why you want to kick urself silly!\n", p->Owner()); return;} // sn_KillUser(helper, reason); sn_KillUser(helper, "You have been kicked by the server administrator, for a good reason."); } else { //send it to LoadAll here... //tConfItemLine::ReadVal(command); tString ems = "nothing to be done with "; ems << command << " to bad so sad.\n"; sn_ConsoleOut(ems, p->Owner()); return; } // con << command << "\n"; } if (say.ge2("/me")) { tString msg; for (int i=4; ir/15.0, p->g/15.0, p->b/15.0 ) << p->name ; console << " " << ColorString(1,1,.5) << msg << '\n'; sn_ConsoleOut( console ); return; } say.RemoveHex(); if ( spamLevel < nSpamProtection::Level_Mild && say.Len() <= se_SpamMaxLen+2 && ( !p->IsSilenced() ) && pass != true ) { se_BroadcastChat( p, say ); se_DisplayChatLocally( p, say); } } } else { se_DisplayChatLocally( p, say ); } } void ePlayerNetID::Chat(const tString &s) { switch (sn_GetNetState()) { case nCLIENT: { se_NewChatMessage( this, s )->BroadCast(); break; } case nSERVER: { se_BroadcastChat( this, s ); } default: { se_DisplayChatLocally( this, s ); break; } } } //return the playernetid for a given name static ePlayerNetID* identifyPlayer(tString inname) { for(int i=0; iname) return p; } return NULL; } static void ConsoleSay_conf(std::istream &s) { // read the message tString message; message.ReadLine( s ); switch (sn_GetNetState()) { case nCLIENT: { tString realname = ePlayer::PlayerConfig(0)->Name(); ePlayerNetID *me = 0; me = identifyPlayer(realname); se_NewChatMessage( me, message )->BroadCast(); break; } case nSERVER: { tString send; send << ColorString( 1,0,0 ); send << "Admin"; send << ColorString( 1,1,.5 ); send << ": " << message << "\n"; // display it sn_ConsoleOut( send ); } default: { tString realname = ePlayer::PlayerConfig(0)->Name(); ePlayerNetID *me = 0; me = identifyPlayer(realname); se_DisplayChatLocally( me, message ); break; } } } static tConfItemFunc ConsoleSay_c("SAY",&ConsoleSay_conf); class eMenuItemChat: uMenuItemString{ ePlayer *me; public: eMenuItemChat(uMenu *M,tString &c,ePlayer *Me): uMenuItemString(M,"$chat_title_text","",c, se_SpamMaxLen ),me(Me){} virtual ~eMenuItemChat(){} //virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0); virtual bool Event(SDL_Event &e){ #ifndef DEDICATED if (e.type==SDL_KEYDOWN && (e.key.keysym.sym==SDLK_KP_ENTER || e.key.keysym.sym==SDLK_RETURN)){ for(int i=se_PlayerNetIDs.Len()-1;i>=0;i--) if (se_PlayerNetIDs(i)->pID==me->ID()) se_PlayerNetIDs(i)->Chat(*content); MyMenu()->Exit(); return true; } else if (e.type==SDL_KEYDOWN && uActionGlobal::IsBreakingGlobalBind(e.key.keysym.sym)) return su_HandleEvent(e, true); else #endif return uMenuItemString::Event(e); } }; void se_ChatState(ePlayerNetID::ChatFlags flag, bool cs){ for(int i=se_PlayerNetIDs.Len()-1;i>=0;i--) { ePlayerNetID *p = se_PlayerNetIDs[i]; if (p->Owner()==sn_myNetID && p->pID >= 0){ p->SetChatting( flag, cs ); } } } static ePlayer *chatter=NULL; void do_chat(){ if (chatter){ se_ChatState( ePlayerNetID::ChatFlags_Chat, true); sr_con.SetHeight(15,false); se_SetShowScoresAuto(false); tString say; uMenu chat_menu("",false); eMenuItemChat s(&chat_menu,say,chatter); chat_menu.SetCenter(-.75); chat_menu.SetBot(-2); chat_menu.SetTop(-.7); chat_menu.Enter(); se_ChatState( ePlayerNetID::ChatFlags_Chat, false ); sr_con.SetHeight(7,false); se_SetShowScoresAuto(true); chatter=NULL; } } bool ePlayer::Act(uAction *act,REAL x){ eGameObject *object=NULL; if (s_chat==*reinterpret_cast(act)){ if(x>0) { chatter=this; st_ToDo(&do_chat); } return true; } else{ if ( x > 0 ) { int i; uActionPlayer* pact = reinterpret_cast(act); for(i=MAX_INSTANT_CHAT-1;i>=0;i--){ uActionPlayer* pcompare = se_instantChatAction[i]; if (pact == pcompare && x>=0){ for(int j=se_PlayerNetIDs.Len()-1;j>=0;j--) if (se_PlayerNetIDs(j)->pID==ID()) se_PlayerNetIDs(j)->Chat(instantChatString[i]); } } } int i; for(i=se_PlayerNetIDs.Len()-1;i>=0;i--) if (se_PlayerNetIDs[i]->pID==id && se_PlayerNetIDs[i]->object) object=se_PlayerNetIDs[i]->object; bool ret = ((cam && cam->Act(reinterpret_cast(act),x)) || (object && se_GameTime()>=0 && object->Act(reinterpret_cast(act),x))); if (ret && bool(netPlayer)) netPlayer->Activity(); return ret; } } rViewport * ePlayer::PlayerViewport(int p){ if (!PlayerConfig(p)) return NULL; for (int i=rViewportConfiguration::CurrentViewportConfiguration()->num_viewports-1;i>=0;i--) if (sr_viewportBelongsToPlayer[i] == p) return rViewportConfiguration::CurrentViewport(i); return NULL; } bool ePlayer::PlayerIsInGame(int p){ return PlayerViewport(p) && PlayerConfig(p); } static tConfItemBase *vpbtp[MAX_VIEWPORTS]; void ePlayer::Init(){ se_Players = tNEW( ePlayer[MAX_PLAYERS] ); int i; for(i=MAX_INSTANT_CHAT-1;i>=0;i--){ tString id; id << "INSTANT_CHAT_"; id << i+1; tOutput desc; desc.SetTemplateParameter(1, i+1); desc << "$input_instant_chat_text"; tOutput help; help.SetTemplateParameter(1, i+1); help << "$input_instant_chat_help"; ePlayer::se_instantChatAction[i]=tNEW(uActionPlayer) (id, desc, help); //,desc, "Issues a special instant chat macro."); } for(i=MAX_VIEWPORTS-1;i>=0;i--){ tString id; id << "VIEWPORT_TO_PLAYER_"; id << i+1; vpbtp[i] = tNEW(tConfItem(id,"$viewport_belongs_help", s_newViewportBelongsToPlayer[i])); s_newViewportBelongsToPlayer[i]=i; } } void ePlayer::Exit(){ int i; for(i=MAX_INSTANT_CHAT-1;i>=0;i--) tDESTROY(ePlayer::se_instantChatAction[i]); for(i=MAX_VIEWPORTS-1;i>=0;i--) tDESTROY(vpbtp[i]); delete[] se_Players; se_Players = NULL; } uActionPlayer ePlayer::s_chat("CHAT"); int pingCharity = 100; static nSpamProtectionSettings se_chatSpamSettings( 1.0f, tOutput("$spam_protection") ); ePlayerNetID::ePlayerNetID(int p):nNetObject(),listID(-1), teamListID(-1) ,pID(p), chatSpam_( se_chatSpamSettings ) { nameTeamAfterMe = false; greeted = true; auth = true; chatting_ = false; chatFlags_ = 0; disconnected = false; if (p>=0){ ePlayer *P = ePlayer::PlayerConfig(p); if (P){ name=P->Name(); r= P->rgb[0]; g= P->rgb[1]; b= P->rgb[2]; pingCharity=::pingCharity; } } else name="AI"; lastSaid.SetLen(12); lastSaidTimes.SetLen(12); se_PlayerNetIDs.Add(this,listID); object=NULL; /* if(sn_GetNetState()!=nSERVER) ping=sn_Connections[0].ping; else */ ping=0; // hehe! server has no ping. lastSync=tSysTimeFloat(); RequestSync(); score=0; // rubberstatus=0; MyInitAfterCreation(); } ePlayerNetID::ePlayerNetID(nMessage &m):nNetObject(m),listID(-1), teamListID(-1) , chatSpam_( se_chatSpamSettings ) { greeted =false; chatting_ =false; disconnected=false; chatFlags_ =0; nameTeamAfterMe = false; lastSaid.SetLen(12); lastSaidTimes.SetLen(12); pID=-1; se_PlayerNetIDs.Add(this,listID); object=NULL; ping=sn_Connections[m.SenderID()].ping; lastSync=tSysTimeFloat(); if(sn_GetNetState()==nSERVER) RequestSync(); score=0; // rubberstatus=0; #ifdef KRAWALL_SERVER auth=false; #else auth=true; #endif } void ePlayerNetID::Activity() { // the player was active; therefore, he cannot possibly be chatting_ or disconnected. // but do nothing if we are in client mode and the player is not local to this computer if (sn_GetNetState() != nSERVER && Owner() != ::sn_myNetID) return; if (chatting_ || disconnected) { #ifdef DEBUG con << *this << " showed activity and lost chat status.\n"; #endif RequestSync(); } chatting_ = disconnected = false; } bool se_SilenceAll = false; // flag indicating whether everyone should be silenced static tSettingItem se_silAll("SILENCE_ALL", se_SilenceAll); void ePlayerNetID::MyInitAfterCreation() { this->CreateVoter(); this->silenced_ = se_SilenceAll; } void ePlayerNetID::InitAfterCreation() { MyInitAfterCreation(); if (sn_GetNetState() == nSERVER) { #ifndef KRAWALL_SERVER GetScoreFromDisconnectedCopy(); #endif FindDefaultTeam(); } } bool ePlayerNetID::ClearToTransmit(int user) const{ return ( ( !nextTeam || nextTeam->HasBeenTransmitted( user ) ) && ( !currentTeam || currentTeam->HasBeenTransmitted( user ) ) ) ; } ePlayerNetID::~ePlayerNetID() { // se_PlayerNetIDs.Remove(this,listID); if ( sn_GetNetState() == nSERVER && disconnected ) { tOutput mess; tString name; name << *this << ColorString(1,.5,.5); mess.SetTemplateParameter(1, name); mess.SetTemplateParameter(2, score); mess << "$player_left_game"; sn_ConsoleOut(mess); } RemoveFromGame(); ClearObject(); //con << "Player info sent.\n"; for(int i=MAX_PLAYERS-1;i>=0;i--){ ePlayer *p = ePlayer::PlayerConfig(i); if (p && static_cast(p->netPlayer)==this) p->netPlayer=NULL; } if ( currentTeam ) { currentTeam->RemovePlayer( this ); } #ifdef DEBUG con << *this << " destroyed.\n"; #endif } static void player_removed_from_game_handler(nMessage &m) { // and the ID of the player that was removed unsigned short id; m.Read(id); ePlayerNetID* p = dynamic_cast< ePlayerNetID* >( nNetObject::ObjectDangerous( id ) ); if ( p && sn_GetNetState() != nSERVER ) { p->RemoveFromGame(); } } static nDescriptor player_removed_from_game(202,&player_removed_from_game_handler,"player_removed_from_game"); void ePlayerNetID::RemoveFromGame() { // release voter if ( this->voter_ ) this->voter_->RemoveFromGame(); this->voter_ = 0; if ( sn_GetNetState() != nCLIENT ) { nMessage *m=new nMessage(player_removed_from_game); m->Write(this->ID()); m->BroadCast(); if ( listID >= 0 ){ tString name; tOutput mess; name << *this << ColorString(1,.5,.5); mess.SetTemplateParameter(1, name); mess << "$player_leaving_game"; sn_ConsoleOut(mess); } } se_PlayerNetIDs.Remove(this, listID); SetTeamWish( NULL ); SetTeam( NULL ); UpdateTeam(); ControlObject( NULL ); // currentTeam = NULL; } bool ePlayerNetID::ActionOnQuit() { tControlledPTR< ePlayerNetID > holder( this ); // else { this->RemoveFromGame(); se_PlayerNetIDs.Remove(this,listID); return true; } } void ePlayerNetID::ActionOnDelete() { tControlledPTR< ePlayerNetID > holder( this ); this->RemoveFromGame(); se_PlayerNetIDs.Remove(this,listID); } void ePlayerNetID::PrintName(tString &s) const { s << "ePlayerNetID nr. " << ID() << ", name " << name; } bool ePlayerNetID::AcceptClientSync() const{ return true; } void ePlayerNetID::Auth(){ auth = true; GetScoreFromDisconnectedCopy(); } bool ePlayerNetID::IsAuth() const{ #ifdef KRAWALL_SERVER if (!auth) nAuthentification::RequestLogin(name, Owner(), "$login_request_first"); #endif return auth; } // create our voter or find it void ePlayerNetID::CreateVoter() { // only count nonlocal players with voting support as voters if ( this->Owner() != 0 && sn_Connections[ this->Owner() ].version.Max() >= 3 ) { this->voter_ = eVoter::GetVoter( this->Owner() ); } } void ePlayerNetID::WriteSync(nMessage &m){ lastSync=tSysTimeFloat(); nNetObject::WriteSync(m); m.Write(r); m.Write(g); m.Write(b); m.Write(pingCharity); m << name; //if(sn_GetNetState()==nSERVER) m << ping; m << static_cast(chatting_); m << score; m << static_cast(disconnected); m << nextTeam; m << currentTeam; m << favoriteNumberOfPlayersPerTeam; m << nameTeamAfterMe; } void ePlayerNetID::ReadSync(nMessage &m){ nNetObject::ReadSync(m); tString oldname(name); tString oldprintname;; oldprintname << *this << ColorString(.5,1,.5); m.Read(r); m.Read(g); m.Read(b); m.Read(pingCharity); m >> name; if (sn_GetNetState()==nSERVER){ tOutput mess; if(name.Len()>16) { name.SetLen(16); name[name.Len()-1]='\0'; } tString printname; printname << *this << ColorString(.5,1,.5); mess.SetTemplateParameter(1, printname); mess.SetTemplateParameter(2, oldprintname); //oldname.RemoveHex(); //name.RemoveHex(); // std::cout << oldname.Len() << ":" << name.Len(); // std::cout << oldname << ":" << name; if (oldname.Len()<=1 && name.Len()>=1){ #ifdef KRAWALL_SERVER auth = false; if (sn_GetNetState() == nSERVER) nAuthentification::RequestLogin(RemoveColors(name), Owner(), "$login_request_first"); #endif mess << "$player_entered_game"; sn_ConsoleOut(mess); } else if (strcmp(oldname,name)) { #ifdef KRAWALL_SERVER auth = false; if (sn_GetNetState() == nSERVER) nAuthentification::RequestLogin(name, Owner(), "$login_request_namechange"); name = oldname; // restore the old name until the new one is authenticated #endif mess << "$player_renamed"; sn_ConsoleOut(mess); } } if (sn_GetNetState()==nCLIENT && Owner()==::sn_myNetID) name=oldname; REAL p; m >> p; if (sn_GetNetState()!=nSERVER) ping=p; // if (!m.End()) { unsigned short newchat; m >> newchat; if (Owner() != ::sn_myNetID) chatting_=newchat; } // if (!m.End()) { if(sn_GetNetState()!=nSERVER) m >> score; else{ int s; m >> s; } } if (!m.End()){ unsigned short newdisc; m >> newdisc; if (Owner() != ::sn_myNetID && sn_GetNetState()!=nSERVER) disconnected = newdisc; } if (!m.End()) { if ( nSERVER != sn_GetNetState() ) { eTeam *newCurrentTeam, *newNextTeam; m >> newNextTeam; m >> newCurrentTeam; // update team if ( newCurrentTeam != currentTeam ) { if ( newCurrentTeam ) newCurrentTeam->AddPlayerDirty( this ); } } else { eTeam* t; m >> t; m >> t; } m >> favoriteNumberOfPlayersPerTeam; m >> nameTeamAfterMe; } // con << "Player info updated.\n"; // make sure we did not accidentally overwrite values // ePlayer::Update(); // update the team if ( nSERVER == sn_GetNetState() ) { if ( nextTeam ) nextTeam->UpdateProperties(); if ( currentTeam ) currentTeam->UpdateProperties(); } } nNOInitialisator ePlayerNetID_init(201,"ePlayerNetID"); nDescriptor &ePlayerNetID::CreatorDescriptor() const{ return ePlayerNetID_init; } void ePlayerNetID::ControlObject(eNetGameObject *c){ if (bool(object) && c!=object) ClearObject(); if (!c) { return; } object=c; c->team = currentTeam; if (bool(object)) object->SetPlayer(this); #ifdef DEBUG //con << "Player " << name << " controlles new object.\n"; #endif NewObject(); } void ePlayerNetID::ClearObject(){ if (object) { tJUST_CONTROLLED_PTR< eNetGameObject > x=object; object=NULL; x->RemoveFromGame(); x->SetPlayer( NULL ); } #ifdef DEBUG //con << "Player " << name << " controlles nothing.\n"; #endif } void ePlayerNetID::Greet(){ if (!greeted){ tOutput o; o.SetTemplateParameter(1, RemoveColors(name)); o.SetTemplateParameter(2, sn_programVersion); o << "$player_welcome"; tString s; s << o; s << "\n"; GreetHighscores(s); s << "\n"; for(int k=0;k<5;k++) if (sn_greeting[k].Len()>1) s << sn_greeting[k] << "\n"; s << "\n"; //std::cout << s; sn_ConsoleOut(s,Owner()); greeted=true; } } eNetGameObject *ePlayerNetID::Object() const{ return object; } void se_SaveToScoreFile(const tOutput &o){ tString s(o); #ifdef DEBUG if (sn_GetNetState()!=nCLIENT){ #else if (sn_GetNetState()==nSERVER){ #endif std::ofstream o; if ( tDirectories::Var().Open(o, "scorelog.txt", std::ios::app) ) o << RemoveColors(s); } #ifdef DEBUG } #else } #endif // void ePlayerNetID::SetRubber(REAL rubber2) {rubberstatus = rubber2;} void ePlayerNetID::AddScore(int points, const tOutput& reasonwin, const tOutput& reasonloose) { if (points==0) return; score += points; if (currentTeam) currentTeam->AddScore( points ); tString name; name << *this; name << ColorString(1,1,1); tOutput message; message.SetTemplateParameter(1, name); message.SetTemplateParameter(2, points > 0 ? points : -points); if (points>0) { if (reasonwin.IsEmpty()) message << "$player_win_default"; else message.Append(reasonwin); } else { if (reasonloose.IsEmpty()) message << "$player_loose_default"; else message.Append(reasonloose); } sn_ConsoleOut(message); RequestSync(true); se_SaveToScoreFile(message); } int ePlayerNetID::TotalScore() const { if ( currentTeam ) { return score;// + currentTeam->Score() * 5; } else { return score; } } void ePlayerNetID::SwapPlayersNo(int a,int b){ if (0>a || se_PlayerNetIDs.Len()<=a) return; if (0>b || se_PlayerNetIDs.Len()<=b) return; if (a==b) return; ePlayerNetID *A=se_PlayerNetIDs(a); ePlayerNetID *B=se_PlayerNetIDs(b); se_PlayerNetIDs(b)=A; se_PlayerNetIDs(a)=B; A->listID=b; B->listID=a; } void ePlayerNetID::SortByScore(){ // bubble sort (AAARRGGH! but good for lists that change not much) bool inorder=false; while (!inorder){ inorder=true; int i; for(i=se_PlayerNetIDs.Len()-2;i>=0;i--) if (se_PlayerNetIDs(i)->TotalScore() < se_PlayerNetIDs(i+1)->TotalScore() ){ SwapPlayersNo(i,i+1); inorder=false; } } } void ePlayerNetID::ResetScore(){ int i; for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){ se_PlayerNetIDs(i)->score=0; if (sn_GetNetState()==nSERVER) se_PlayerNetIDs(i)->RequestSync(); } for(i=eTeam::teams.Len()-1;i>=0;i--){ eTeam::teams(i)->ResetScore(); if (sn_GetNetState()==nSERVER) eTeam::teams(i)->RequestSync(); } } void ePlayerNetID::DisplayScores(){ sr_ResetRenderState(true); REAL W=sr_screenWidth; REAL H=sr_screenHeight; REAL MW=400; REAL MH=(MW*3)/4; if(W>MW) W=MW; if(H>MH) H=MH; #ifndef DEDICATED if (sr_glOut){ ::Color(1,1,1); rTextField c(-.7,.6,10/W,18/H); if ( eTeam::maxPlayers > 1 ) c << eTeam::Ranking(); c << "\n"; c << Ranking(); } #endif } tString ePlayerNetID::Ranking( int MAX, bool cut ){ SortByScore(); tString ret; if (se_PlayerNetIDs.Len()>0){ ret << ColorString(1,.5,.5); ret << tOutput("$player_scoretable_name"); ret << ColorString(1,1,1); ret.SetPos(33, cut ); ret << tOutput("$player_scoretable_alive"); ret.SetPos(40, cut ); ret << tOutput("$player_scoretable_score"); ret.SetPos(47, cut ); ret << tOutput("$player_scoretable_ping"); ret.SetPos(53, cut ); ret << tOutput("$player_scoretable_team"); ret.SetPos(69, cut ); ret << "\n"; int max = se_PlayerNetIDs.Len(); if ( max > MAX && MAX > 0 ) { max = MAX ; } for(int i=0;iname; /* if (name.ge2("0x")) { tString name2 = ""; name2.SetLen(15); for (unsigned short int c=6; cr/15.0, p->g/15.0, p->b/15.0 ) << name << ColorString(1,1,1); line.SetPos((33+posDisplacement), false ); if ( p->Object() && p->Object()->Alive() ) { line << tOutput("$player_scoretable_alive_yes"); } else { line << tOutput("$player_scoretable_alive_no"); } line.SetPos((40+posDisplacement), cut ); line << p->score; if (p->IsActive()) { line.SetPos((47+posDisplacement), cut ); //line << "ping goes here"; line << int(p->ping*1000); line.SetPos((53+posDisplacement), cut ); if ( p->currentTeam ) { //tString teamtemp = p->currentTeam->Name(); //teamtemp.RemoveHex(); line << RemoveColors(p->currentTeam->Name()); line.SetPos((69+posDisplacement), cut ); } } else line << tOutput("$player_scoretable_inactive"); ret << line << "\n"; } if ( max < se_PlayerNetIDs.Len() ) { ret << "...\n"; } } else ret << tOutput("$player_scoretable_nobody"); return ret; } tString & operator << (tString &s,const ePlayer &p){ return s << ColorString(p.rgb[0]/15.0, p.rgb[1]/15.0, p.rgb[2]/15.0) << p.Name(); } tString & operator << (tString &s,const ePlayerNetID &p){ REAL r,g,b; p.Color(r,g,b); return s << ColorString(r, g, b) << p.name; } void ePlayerNetID::CompleteRebuild(){ for(int i=MAX_PLAYERS-1;i>=0;i--){ ePlayer *local_p=ePlayer::PlayerConfig(i); if (local_p) local_p->netPlayer = NULL; } Update(); } // Update the netPlayer_id list void ePlayerNetID::Update(){ #ifdef DEDICATED if (sr_glOut) #endif { for(int i=MAX_PLAYERS-1;i>=0;i--){ bool in_game=ePlayer::PlayerIsInGame(i); ePlayer *local_p=ePlayer::PlayerConfig(i); tCONTROLLED_PTR(ePlayerNetID) &p=local_p->netPlayer; if (!p && in_game && !local_p->spectate) // insert new player { p=tNEW(ePlayerNetID) (i); p->FindDefaultTeam(); p->RequestSync(); } if (bool(p) && (!in_game || local_p->spectate) && // remove player p->Owner() == ::sn_myNetID ) { p->RemoveFromGame(); if (p->object) p->object->player = NULL; p->object = NULL; p = NULL; } if (bool(p) && in_game){ // update p->favoriteNumberOfPlayersPerTeam=ePlayer::PlayerConfig(i)->favoriteNumberOfPlayersPerTeam; p->nameTeamAfterMe=ePlayer::PlayerConfig(i)->nameTeamAfterMe; p->r=ePlayer::PlayerConfig(i)->rgb[0]; p->g=ePlayer::PlayerConfig(i)->rgb[1]; p->b=ePlayer::PlayerConfig(i)->rgb[2]; p->pingCharity=::pingCharity; tString tempname = ePlayer::PlayerConfig(i)->Name(); tempname.RemoveHex(); p->name=tempname; if ( ::sn_GetNetState() != nCLIENT ) { p->RequestSync(); } } } } // update the ping charity int old_c=sn_pingCharityServer; sn_pingCharityServer=::pingCharity; #ifndef DEDICATED if (sn_GetNetState()==nCLIENT) #endif sn_pingCharityServer+=100000; int i; for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){ ePlayerNetID *pni=se_PlayerNetIDs(i); int new_ps=pni->pingCharity; new_ps+=int(pni->ping*500); if (new_ps< sn_pingCharityServer) sn_pingCharityServer=new_ps; } if (sn_pingCharityServer<0) sn_pingCharityServer=0; if (old_c!=sn_pingCharityServer) { tOutput o; o.SetTemplateParameter(1, old_c); o.SetTemplateParameter(2, sn_pingCharityServer); o << "$player_pingcharity_changed"; con << o; } // update team assignment for(i=se_PlayerNetIDs.Len()-1;i>=0;i--) { ePlayerNetID* player = se_PlayerNetIDs(i); player->UpdateTeam(); } // update the teams as well for (i=eTeam::teams.Len()-1; i>=0; --i) { eTeam::teams(i)->UpdateProperties(); } } void ePlayerNetID::ThrowOutDisconnected() { int i; // find all disconnected players for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){ ePlayerNetID *pni=se_PlayerNetIDs(i); if (pni->disconnected) { // remove it from the list of players (so it won't be deleted twice...) se_PlayerNetIDs.Remove(pni, pni->listID); } } se_PlayerReferences.ReleaseAll(); } void ePlayerNetID::GetScoreFromDisconnectedCopy() { int i; // find a copy for(i=se_PlayerNetIDs.Len()-1;i>=0;i--){ ePlayerNetID *pni=se_PlayerNetIDs(i); if (pni->disconnected && pni->name == name && pni->Owner() == 0) { #ifdef DEBUG con << name << " reconnected.\n"; #endif pni->RequestSync(); RequestSync(); score = pni->score; ControlObject(pni->Object()); // object->ePlayer = this; pni->object = NULL; if (bool(object)) chatting_ = true; pni->disconnected = false; se_PlayerNetIDs.Remove(pni, pni->listID); se_PlayerReferences.Remove( pni ); // really delete it without a message } } } static bool show_scores=false; static bool ass=true; void se_AutoShowScores(){ if (ass) show_scores=true; } void se_UserShowScores(bool show){ show_scores=show; } void se_SetShowScoresAuto(bool a){ ass=a; } static void scores(){ if (show_scores){ ePlayerNetID::DisplayScores(); } } static rPerFrameTask pf(&scores); static bool force_small_cons(){ return show_scores; } static rSmallConsoleCallback sc(&force_small_cons); static void cd(){ show_scores = false; } static uActionGlobal score("SCORE"); static bool sf(REAL x){ if (x>0) show_scores = !show_scores; return true; } static uActionGlobalFunc saf(&score,&sf); static rCenterDisplayCallback c_d(&cd); tOutput& operator << (tOutput& o, const ePlayerNetID& p) { tString x; x << p; o << x; return o; } eCallbackGreeting *eCallbackGreeting::anchor = NULL; ePlayerNetID* eCallbackGreeting::greeted = NULL; tString eCallbackGreeting::Greet(ePlayerNetID* player) { greeted = player; return Exec(anchor); } eCallbackGreeting::eCallbackGreeting(STRINGRETFUNC* f) :tCallbackString((tCallbackString*&)anchor, f) { } void ePlayerNetID::GreetHighscores(tString &s){ s << eCallbackGreeting::Greet(this); // tOutput o; // gHighscoresBase::Greet(this,o); // s << o; } // ******************* // * chatting_ * // ******************* void ePlayerNetID::SetChatting ( ChatFlags flag, bool chatting ) { if ( sn_GetNetState() == nSTANDALONE && flag == ChatFlags_Menu ) { chatting = false; } if ( chatting ) { chatFlags_ |= flag; if ( !chatting_ ) this->RequestSync(); chatting_ = true; } else { chatFlags_ &= ~flag; if ( 0 == chatFlags_ ) { if ( chatting_ ) this->RequestSync(); chatting_ = false; } } } // ******************* // * team management * // ******************* // put a new player into a default team void ePlayerNetID::FindDefaultTeam( ) { static bool recursion = false; if ( recursion ) { return; } if ( !IsHuman() ) { SetTeam( NULL ); return; } recursion = true; // find the team with the least number of players on it eTeam *min = NULL; for ( int i=eTeam::teams.Len()-1; i>=0; --i ) { eTeam *t = eTeam::teams( i ); if ( t->IsHuman() && ( !min || min->NumHumanPlayers() > t->NumHumanPlayers() ) ) min = t; } if ( !eTeam::NewTeamAllowed() || ( min && min->NumHumanPlayers() < favoriteNumberOfPlayersPerTeam && min->PlayerMayJoin( this ) ) ) SetTeamWish( min ); // join the team else CreateNewTeamWish(); // create a new team recursion = false; }; // register me in the given team (callable on the server) void ePlayerNetID::SetTeam( eTeam* newTeam ) { // check if the team change is legal tASSERT ( !newTeam || nCLIENT != sn_GetNetState() ); if (newTeam && !newTeam->PlayerMayJoin( this ) ) { tOutput message; message.SetTemplateParameter(1, RemoveColors(name)); if ( newTeam ) message.SetTemplateParameter(2, newTeam->Name() ); else message.SetTemplateParameter(2, "NULL"); message << "$player_nojoin_team"; sn_ConsoleOut( message, Owner() ); static bool recursion = false; if ( !recursion ) { recursion = true; if ( !nextTeam ) FindDefaultTeam(); recursion = false; } return; } SetTeamForce( newTeam ); } // register me in the given team (callable on the server) void ePlayerNetID::SetTeamForce( eTeam* newTeam ) { // check if the team change is legal tASSERT ( !newTeam || nCLIENT != sn_GetNetState() ); nextTeam = newTeam; } // register me in the given team (callable on the server) void ePlayerNetID::UpdateTeam() { // check if work is needed if ( nextTeam == currentTeam ) { return; } // check if the team change is legal if ( nCLIENT == sn_GetNetState() ) { return; } if ( bool( nextTeam ) && !nextTeam->PlayerMayJoin( this ) ) { tOutput message; message.SetTemplateParameter(1, name); if ( nextTeam ) message.SetTemplateParameter(2, nextTeam->Name() ); else message.SetTemplateParameter(2, "NULL"); message << "$player_nojoin_team"; sn_ConsoleOut( message, Owner() ); static bool recursion = false; if ( !recursion ) { recursion = true; if ( !currentTeam ) { FindDefaultTeam(); UpdateTeam(); } else { nextTeam = currentTeam; } recursion = false; } return; } UpdateTeamForce(); } void ePlayerNetID::UpdateTeamForce() { // check if work is needed if ( nextTeam == currentTeam ) { return; } eTeam *oldTeam = currentTeam; if ( nextTeam ) nextTeam->AddPlayer ( this ); else if ( oldTeam ) oldTeam->RemovePlayer( this ); if( nCLIENT != sn_GetNetState() && GetRefcount() > 0 ) { RequestSync(); } } // create a new team and join it (on the server) void ePlayerNetID::CreateNewTeam() { // check if the team change is legal tASSERT ( nCLIENT != sn_GetNetState() ); if ( !eTeam::NewTeamAllowed() || ( bool( currentTeam ) && ( currentTeam->NumHumanPlayers() == 1 ) ) ) { tOutput message; message.SetTemplateParameter(1, RemoveColors(name)); message << "$player_nocreate_team"; sn_ConsoleOut( message, Owner() ); if ( !currentTeam ) FindDefaultTeam(); return; } tOutput message; message.SetTemplateParameter(1, RemoveColors(name)); message << "$player_creates_team"; sn_ConsoleOut( message ); // create the new team and join it tJUST_CONTROLLED_PTR< eTeam > newTeam = tNEW( eTeam ); nextTeam = newTeam; } const unsigned short TEAMCHANGE = 0; const unsigned short NEW_TEAM = 1; // express the wish to be part of the given team (always callable) void ePlayerNetID::SetTeamWish(eTeam* newTeam) { if ( nCLIENT == sn_GetNetState() && Owner() == sn_myNetID ) { nMessage* m = NewControlMessage(); (*m) << TEAMCHANGE; (*m) << newTeam; m->BroadCast(); } else SetTeam( newTeam ); } // express the wish to create a new team and join it void ePlayerNetID::CreateNewTeamWish() { if ( nCLIENT == sn_GetNetState() ) { nMessage* m = NewControlMessage(); (*m) << NEW_TEAM; m->BroadCast(); } else CreateNewTeam(); } // receive the team control wish void ePlayerNetID::ReceiveControlNet(nMessage &m) { short messageType; m >> messageType; switch (messageType) { case NEW_TEAM: { CreateNewTeam(); break; } case TEAMCHANGE: { eTeam *newTeam; m >> newTeam; SetTeam( newTeam ); break; } default: { tASSERT(0); } } } void ePlayerNetID::Color( REAL&a_r, REAL&a_g, REAL&a_b ) const { if ( ( static_cast(currentTeam) ) && ( currentTeam->IsHuman() ) ) { REAL w = 5; REAL r_w = 2; REAL g_w = 1; REAL b_w = 2; a_r=(r_w*r + w*currentTeam->R())/( 15.0 * ( w + r_w ) ); a_g=(g_w*g + w*currentTeam->G())/( 15.0 * ( w + g_w ) ); a_b=(b_w*b + w*currentTeam->B())/( 15.0 * ( w + b_w ) ); } else { a_r = r/15.0; a_g = g/15.0; a_b = b/15.0; } } void ePlayerNetID::TrailColor( REAL&a_r, REAL&a_g, REAL&a_b ) const { Color( a_r, a_g, a_b ); /* if ( ( static_cast(currentTeam) ) && ( currentTeam->IsHuman() ) ) { int w = 6; a_r=(2*r + w*currentTeam->R())/( 15.0 * ( w + 2 ) ); a_g=(2*g + w*currentTeam->G())/( 15.0 * ( w + 2 ) ); a_b=(2*b + w*currentTeam->B())/( 15.0 * ( w + 2 ) ); } else { a_r = r/15.0; a_g = g/15.0; a_b = b/15.0; } */ } /* void ePlayerNetID::AddRef() { nNetObject::AddRef(); } void ePlayerNetID::Release() { nNetObject::Release(); } */ static void Kick_conf(std::istream &s) { // read name of player to be kicked tString name; name.ReadLine( s ); for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) { ePlayerNetID* p = se_PlayerNetIDs(i); if ( p && p->name == name ) { int owner = p->Owner(); if ( owner > 0 ) { sn_KillUser( owner, "$network_kill_kick" ); } return; } } tOutput o; o.SetTemplateParameter( 1, name ); o << "$network_kick_notfound"; con << o; } static tConfItemFunc kick_conf("KICK",&Kick_conf); static tString sg_url = ""; static tConfItemLine sg_urlConf( "URL", sg_url ); class gServerInfoAdmin: public nServerInfoAdmin { public: gServerInfoAdmin(){}; private: virtual tString GetUsers() const { tString ret; for ( int i = se_PlayerNetIDs.Len()-1; i>=0; --i ) { ePlayerNetID* p = se_PlayerNetIDs(i); if ( p->IsHuman() ) { ret << p->name << "\n"; } } return ret; } virtual tString GetOptions() const { return tString(); } virtual tString GetUrl() const { return sg_url; } }; static gServerInfoAdmin sg_serverAdmin;