int CTeeFiles::TeeFileScan(const char *pName, int IsDir, int DirType, void *pUser) { CTeeFiles *pSelf = (CTeeFiles*)pUser; int l = str_length(pName); if(l < 4 || IsDir || str_comp(pName+l-4, ".tee") != 0) return 0; char aBuf[512]; char aFileName[41]; char aFilePath[512]; char aTeeEntry[NUM_TEE_ENTRIES][32]; str_format(aFilePath, sizeof(aFilePath), "xclient/teefiles/%s", pName); str_format(aFileName, sizeof(aFileName), pName); IOHANDLE File = pSelf->Storage()->OpenFile(aFilePath, IOFLAG_READ, IStorage::TYPE_SAVE); if(File) { char *pLine; CLineReader lr; lr.Init(File); for(int i = 0; i < NUM_TEE_ENTRIES; i++) { if(!(pLine = lr.Get())) { str_format(aBuf, sizeof(aBuf), "failed to read '%s' at line %d", aFileName, i); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf); io_close(File); mem_zero(aTeeEntry[i], sizeof(aTeeEntry[i])); break; } str_format(aTeeEntry[i], sizeof(aTeeEntry[i]), pLine); } io_close(File); } else { str_format(aBuf, sizeof(aBuf), "failed to open '%s'", aFileName); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf); return 1; } CTee Tee; str_format(Tee.m_aFilename, sizeof(Tee.m_aFilename), aFileName); str_format(Tee.m_aName, sizeof(Tee.m_aName), aTeeEntry[TEE_NAME]); str_format(Tee.m_aClan, sizeof(Tee.m_aClan), aTeeEntry[TEE_CLAN]); str_format(Tee.m_aSkin, sizeof(Tee.m_aSkin), aTeeEntry[TEE_SKIN]); Tee.m_UseCustomColor = str_toint(aTeeEntry[TEE_USECUSTOMCOLOR]); Tee.m_ColorBody = str_toint(aTeeEntry[TEE_COLORBODY]); Tee.m_ColorFeet = str_toint(aTeeEntry[TEE_COLORFEET]); Tee.m_Country = str_toint(aTeeEntry[TEE_COUNTRY]); pSelf->m_aTees.add(Tee); return 0; }
void CConsole::CResult::SetVictim(const char *pVictim) { if(!str_comp(pVictim, "me")) m_Victim = VICTIM_ME; else if(!str_comp(pVictim, "all")) m_Victim = VICTIM_ALL; else m_Victim = clamp<int>(str_toint(pVictim), 0, MAX_CLIENTS - 1); }
int CConsole::Victim(const char *pVictim) { if(!str_comp_nocase(pVictim, "me")) return CResult::VICTIM_ME; else if(!str_comp_nocase(pVictim, "all")) return CResult::VICTIM_ALL; else if(!m_pNameToIDfn) return clamp<int>(str_toint(pVictim), 0, MAX_CLIENTS - 1); else return m_pNameToIDfn(m_pNameToIDfnArg, pVictim); }
void CNetBan::ConUnban(IConsole::IResult *pResult, void *pUser) { CNetBan *pThis = static_cast<CNetBan *>(pUser); const char *pStr = pResult->GetString(0); if(StrAllnum(pStr)) pThis->UnbanByIndex(str_toint(pStr)); else { NETADDR Addr; if(net_addr_from_str(&Addr, pStr) == 0) pThis->UnbanByAddr(&Addr); else pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban error (invalid network address)"); } }
void CLuaFile::PushParameter(const char *pString) { if (m_pLua == 0) return; if (StrIsInteger(pString)) { PushInteger(str_toint(pString)); } else if (StrIsFloat(pString)) { PushInteger(str_tofloat(pString)); } else { PushString(pString); } }
int CBinds::GetKeyId(const char *pKeyName) { // check for numeric if(pKeyName[0] == '&') { int i = str_toint(pKeyName+1); if(i > 0 && i < KEY_LAST) return i; // numeric } // search for key for(int i = 0; i < KEY_LAST; i++) { if(str_comp(pKeyName, Input()->KeyName(i)) == 0) return i; } return 0; }
void CServerBan::ConBanExt(IConsole::IResult *pResult, void *pUser) { CServerBan *pThis = static_cast<CServerBan *>(pUser); const char *pStr = pResult->GetString(0); int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : 30; const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given"; if(StrAllnum(pStr)) { int ClientID = str_toint(pStr); if(ClientID < 0 || ClientID >= MAX_CLIENTS || pThis->Server()->m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY) pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid client id)"); else pThis->BanAddr(pThis->Server()->m_NetServer.ClientAddr(ClientID), Minutes*60, pReason); } else ConBan(pResult, pUser); }
void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) { void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgID, pUnpacker); CPlayer *pPlayer = m_apPlayers[ClientID]; if(!pRawMsg) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgID), MsgID, m_NetObjHandler.FailedMsgOn()); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); return; } if(MsgID == NETMSGTYPE_CL_SAY) { CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg; int Team = pMsg->m_Team; if(Team) Team = pPlayer->GetTeam(); else Team = CGameContext::CHAT_ALL; if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick()) return; pPlayer->m_LastChat = Server()->Tick(); // check for invalid chars unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage; while (*pMessage) { if(*pMessage < 32) *pMessage = ' '; pMessage++; } SendChat(ClientID, Team, pMsg->m_pMessage); } else if(MsgID == NETMSGTYPE_CL_CALLVOTE) { if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry+Server()->TickSpeed()*3 > Server()->Tick()) return; int64 Now = Server()->Tick(); pPlayer->m_LastVoteTry = Now; if(pPlayer->GetTeam() == TEAM_SPECTATORS) { SendChatTarget(ClientID, "Spectators aren't allowed to start a vote."); return; } if(m_VoteCloseTime) { SendChatTarget(ClientID, "Wait for current vote to end before calling a new one."); return; } int Timeleft = pPlayer->m_LastVoteCall + Server()->TickSpeed()*60 - Now; if(pPlayer->m_LastVoteCall && Timeleft > 0) { char aChatmsg[512] = {0}; str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (Timeleft/Server()->TickSpeed())+1); SendChatTarget(ClientID, aChatmsg); return; } char aChatmsg[512] = {0}; char aDesc[VOTE_DESC_LENGTH] = {0}; char aCmd[VOTE_CMD_LENGTH] = {0}; CNetMsg_Cl_CallVote *pMsg = (CNetMsg_Cl_CallVote *)pRawMsg; const char *pReason = pMsg->m_Reason[0] ? pMsg->m_Reason : "No reason given"; if(str_comp_nocase(pMsg->m_Type, "option") == 0) { CVoteOptionServer *pOption = m_pVoteOptionFirst; while(pOption) { if(str_comp_nocase(pMsg->m_Value, pOption->m_aDescription) == 0) { str_format(aChatmsg, sizeof(aChatmsg), "'%s' called vote to change server option '%s' (%s)", Server()->ClientName(ClientID), pOption->m_aDescription, pReason); str_format(aDesc, sizeof(aDesc), "%s", pOption->m_aDescription); str_format(aCmd, sizeof(aCmd), "%s", pOption->m_aCommand); break; } pOption = pOption->m_pNext; } if(!pOption) { str_format(aChatmsg, sizeof(aChatmsg), "'%s' isn't an option on this server", pMsg->m_Value); SendChatTarget(ClientID, aChatmsg); return; } } else if(str_comp_nocase(pMsg->m_Type, "kick") == 0) { if(!g_Config.m_SvVoteKick) { SendChatTarget(ClientID, "Server does not allow voting to kick players"); return; } if(g_Config.m_SvVoteKickMin) { int PlayerNum = 0; for(int i = 0; i < MAX_CLIENTS; ++i) if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) ++PlayerNum; if(PlayerNum < g_Config.m_SvVoteKickMin) { str_format(aChatmsg, sizeof(aChatmsg), "Kick voting requires %d players on the server", g_Config.m_SvVoteKickMin); SendChatTarget(ClientID, aChatmsg); return; } } int KickID = str_toint(pMsg->m_Value); if(KickID < 0 || KickID >= MAX_CLIENTS || !m_apPlayers[KickID]) { SendChatTarget(ClientID, "Invalid client id to kick"); return; } if(KickID == ClientID) { SendChatTarget(ClientID, "You cant kick yourself"); return; } if(Server()->IsAuthed(KickID)) { SendChatTarget(ClientID, "You cant kick admins"); char aBufKick[128]; str_format(aBufKick, sizeof(aBufKick), "'%s' called for vote to kick you", Server()->ClientName(ClientID)); SendChatTarget(KickID, aBufKick); return; } str_format(aChatmsg, sizeof(aChatmsg), "'%s' called for vote to kick '%s' (%s)", Server()->ClientName(ClientID), Server()->ClientName(KickID), pReason); str_format(aDesc, sizeof(aDesc), "Kick '%s'", Server()->ClientName(KickID)); if (!g_Config.m_SvVoteKickBantime) str_format(aCmd, sizeof(aCmd), "kick %d Kicked by vote", KickID); else { char aAddrStr[NETADDR_MAXSTRSIZE] = {0}; Server()->GetClientAddr(KickID, aAddrStr, sizeof(aAddrStr)); str_format(aCmd, sizeof(aCmd), "ban %s %d Banned by vote", aAddrStr, g_Config.m_SvVoteKickBantime); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aCmd); } } else if(str_comp_nocase(pMsg->m_Type, "spectate") == 0) { if(!g_Config.m_SvVoteSpectate) { SendChatTarget(ClientID, "Server does not allow voting to move players to spectators"); return; } int SpectateID = str_toint(pMsg->m_Value); if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !m_apPlayers[SpectateID] || m_apPlayers[SpectateID]->GetTeam() == TEAM_SPECTATORS) { SendChatTarget(ClientID, "Invalid client id to move"); return; } if(SpectateID == ClientID) { SendChatTarget(ClientID, "You cant move yourself"); return; } str_format(aChatmsg, sizeof(aChatmsg), "'%s' called for vote to move '%s' to spectators (%s)", Server()->ClientName(ClientID), Server()->ClientName(SpectateID), pReason); str_format(aDesc, sizeof(aDesc), "move '%s' to spectators", Server()->ClientName(SpectateID)); str_format(aCmd, sizeof(aCmd), "set_team %d -1", SpectateID); } if(aCmd[0]) { SendChat(-1, CGameContext::CHAT_ALL, aChatmsg); StartVote(aDesc, aCmd, pReason); pPlayer->m_Vote = 1; pPlayer->m_VotePos = m_VotePos = 1; m_VoteCreator = ClientID; pPlayer->m_LastVoteCall = Now; } } else if(MsgID == NETMSGTYPE_CL_VOTE) { if(!m_VoteCloseTime) return; if(pPlayer->m_Vote == 0) { CNetMsg_Cl_Vote *pMsg = (CNetMsg_Cl_Vote *)pRawMsg; if(!pMsg->m_Vote) return; pPlayer->m_Vote = pMsg->m_Vote; pPlayer->m_VotePos = ++m_VotePos; m_VoteUpdate = true; } } else if (MsgID == NETMSGTYPE_CL_SETTEAM && !m_World.m_Paused) { CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg; if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick())) return; // Switch team on given client and kill/respawn him if(m_pController->CanJoinTeam(pMsg->m_Team, ClientID)) { if(m_pController->CanChangeTeam(pPlayer, pMsg->m_Team)) { pPlayer->m_LastSetTeam = Server()->Tick(); if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS) m_VoteUpdate = true; pPlayer->SetTeam(pMsg->m_Team); (void)m_pController->CheckTeamBalance(); } else SendBroadcast("Teams must be balanced, please join other team", ClientID); } else { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "Only %d active players are allowed", g_Config.m_SvMaxClients-g_Config.m_SvSpectatorSlots); SendBroadcast(aBuf, ClientID); } } else if (MsgID == NETMSGTYPE_CL_SETSPECTATORMODE && !m_World.m_Paused) { CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg; if(pPlayer->GetTeam() != TEAM_SPECTATORS || pPlayer->m_SpectatorID == pMsg->m_SpectatorID || ClientID == pMsg->m_SpectatorID || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick())) return; pPlayer->m_LastSetSpectatorMode = Server()->Tick(); if(pMsg->m_SpectatorID != SPEC_FREEVIEW && (!m_apPlayers[pMsg->m_SpectatorID] || m_apPlayers[pMsg->m_SpectatorID]->GetTeam() == TEAM_SPECTATORS)) SendChatTarget(ClientID, "Invalid spectator id used"); else pPlayer->m_SpectatorID = pMsg->m_SpectatorID; } else if (MsgID == NETMSGTYPE_CL_STARTINFO) { if(pPlayer->m_IsReady) return; CNetMsg_Cl_StartInfo *pMsg = (CNetMsg_Cl_StartInfo *)pRawMsg; pPlayer->m_LastChangeInfo = Server()->Tick(); // set start infos Server()->SetClientName(ClientID, pMsg->m_pName); Server()->SetClientClan(ClientID, pMsg->m_pClan); Server()->SetClientCountry(ClientID, pMsg->m_Country); str_copy(pPlayer->m_TeeInfos.m_SkinName, pMsg->m_pSkin, sizeof(pPlayer->m_TeeInfos.m_SkinName)); pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor; pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody; pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet; m_pController->OnPlayerInfoChange(pPlayer); // send vote options CNetMsg_Sv_VoteClearOptions ClearMsg; Server()->SendPackMsg(&ClearMsg, MSGFLAG_VITAL, ClientID); CNetMsg_Sv_VoteOptionListAdd OptionMsg; int NumOptions = 0; OptionMsg.m_pDescription0 = ""; OptionMsg.m_pDescription1 = ""; OptionMsg.m_pDescription2 = ""; OptionMsg.m_pDescription3 = ""; OptionMsg.m_pDescription4 = ""; OptionMsg.m_pDescription5 = ""; OptionMsg.m_pDescription6 = ""; OptionMsg.m_pDescription7 = ""; OptionMsg.m_pDescription8 = ""; OptionMsg.m_pDescription9 = ""; OptionMsg.m_pDescription10 = ""; OptionMsg.m_pDescription11 = ""; OptionMsg.m_pDescription12 = ""; OptionMsg.m_pDescription13 = ""; OptionMsg.m_pDescription14 = ""; CVoteOptionServer *pCurrent = m_pVoteOptionFirst; while(pCurrent) { switch(NumOptions++) { case 0: OptionMsg.m_pDescription0 = pCurrent->m_aDescription; break; case 1: OptionMsg.m_pDescription1 = pCurrent->m_aDescription; break; case 2: OptionMsg.m_pDescription2 = pCurrent->m_aDescription; break; case 3: OptionMsg.m_pDescription3 = pCurrent->m_aDescription; break; case 4: OptionMsg.m_pDescription4 = pCurrent->m_aDescription; break; case 5: OptionMsg.m_pDescription5 = pCurrent->m_aDescription; break; case 6: OptionMsg.m_pDescription6 = pCurrent->m_aDescription; break; case 7: OptionMsg.m_pDescription7 = pCurrent->m_aDescription; break; case 8: OptionMsg.m_pDescription8 = pCurrent->m_aDescription; break; case 9: OptionMsg.m_pDescription9 = pCurrent->m_aDescription; break; case 10: OptionMsg.m_pDescription10 = pCurrent->m_aDescription; break; case 11: OptionMsg.m_pDescription11 = pCurrent->m_aDescription; break; case 12: OptionMsg.m_pDescription12 = pCurrent->m_aDescription; break; case 13: OptionMsg.m_pDescription13 = pCurrent->m_aDescription; break; case 14: { OptionMsg.m_pDescription14 = pCurrent->m_aDescription; OptionMsg.m_NumOptions = NumOptions; Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID); OptionMsg = CNetMsg_Sv_VoteOptionListAdd(); NumOptions = 0; OptionMsg.m_pDescription1 = ""; OptionMsg.m_pDescription2 = ""; OptionMsg.m_pDescription3 = ""; OptionMsg.m_pDescription4 = ""; OptionMsg.m_pDescription5 = ""; OptionMsg.m_pDescription6 = ""; OptionMsg.m_pDescription7 = ""; OptionMsg.m_pDescription8 = ""; OptionMsg.m_pDescription9 = ""; OptionMsg.m_pDescription10 = ""; OptionMsg.m_pDescription11 = ""; OptionMsg.m_pDescription12 = ""; OptionMsg.m_pDescription13 = ""; OptionMsg.m_pDescription14 = ""; } } pCurrent = pCurrent->m_pNext; } if(NumOptions > 0) { OptionMsg.m_NumOptions = NumOptions; Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID); NumOptions = 0; } // send tuning parameters to client SendTuningParams(ClientID); // client is ready to enter pPlayer->m_IsReady = true; CNetMsg_Sv_ReadyToEnter m; Server()->SendPackMsg(&m, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID); } else if (MsgID == NETMSGTYPE_CL_CHANGEINFO) { if(g_Config.m_SvSpamprotection && pPlayer->m_LastChangeInfo && pPlayer->m_LastChangeInfo+Server()->TickSpeed()*5 > Server()->Tick()) return; CNetMsg_Cl_ChangeInfo *pMsg = (CNetMsg_Cl_ChangeInfo *)pRawMsg; pPlayer->m_LastChangeInfo = Server()->Tick(); // set infos char aOldName[MAX_NAME_LENGTH]; str_copy(aOldName, Server()->ClientName(ClientID), sizeof(aOldName)); Server()->SetClientName(ClientID, pMsg->m_pName); if(str_comp(aOldName, Server()->ClientName(ClientID)) != 0) { char aChatText[256]; str_format(aChatText, sizeof(aChatText), "'%s' changed name to '%s'", aOldName, Server()->ClientName(ClientID)); SendChat(-1, CGameContext::CHAT_ALL, aChatText); } Server()->SetClientClan(ClientID, pMsg->m_pClan); Server()->SetClientCountry(ClientID, pMsg->m_Country); str_copy(pPlayer->m_TeeInfos.m_SkinName, pMsg->m_pSkin, sizeof(pPlayer->m_TeeInfos.m_SkinName)); pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor; pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody; pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet; m_pController->OnPlayerInfoChange(pPlayer); } else if (MsgID == NETMSGTYPE_CL_EMOTICON && !m_World.m_Paused) { CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg; if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote && pPlayer->m_LastEmote+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_LastEmote = Server()->Tick(); SendEmoticon(ClientID, pMsg->m_Emoticon); } else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused) { if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_LastKill = Server()->Tick(); pPlayer->KillCharacter(WEAPON_SELF); } }
void CGameContext::AbortVoteKickOnDisconnect(int ClientID) { if(m_VoteCloseTime && !str_comp_num(m_aVoteCommand, "kick ", 5) && str_toint(&m_aVoteCommand[5]) == ClientID) m_VoteCloseTime = -1; }
void CGameContext::ConForceVote(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *)pUserData; const char *pType = pResult->GetString(0); const char *pValue = pResult->GetString(1); const char *pReason = pResult->NumArguments() > 2 && pResult->GetString(2)[0] ? pResult->GetString(2) : "No reason given"; char aBuf[128] = {0}; if(str_comp_nocase(pType, "option") == 0) { CVoteOptionServer *pOption = pSelf->m_pVoteOptionFirst; while(pOption) { if(str_comp_nocase(pValue, pOption->m_aDescription) == 0) { str_format(aBuf, sizeof(aBuf), "admin forced server option '%s' (%s)", pValue, pReason); pSelf->SendChatTarget(-1, aBuf); pSelf->Console()->ExecuteLine(pOption->m_aCommand); break; } pOption = pOption->m_pNext; } if(!pOption) { str_format(aBuf, sizeof(aBuf), "'%s' isn't an option on this server", pValue); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); return; } } else if(str_comp_nocase(pType, "kick") == 0) { int KickID = str_toint(pValue); if(KickID < 0 || KickID >= MAX_CLIENTS || !pSelf->m_apPlayers[KickID]) { pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "Invalid client id to kick"); return; } if (!g_Config.m_SvVoteKickBantime) { str_format(aBuf, sizeof(aBuf), "kick %d %s", KickID, pReason); pSelf->Console()->ExecuteLine(aBuf); } else { char aAddrStr[NETADDR_MAXSTRSIZE] = {0}; pSelf->Server()->GetClientAddr(KickID, aAddrStr, sizeof(aAddrStr)); str_format(aBuf, sizeof(aBuf), "ban %s %d %s", aAddrStr, g_Config.m_SvVoteKickBantime, pReason); pSelf->Console()->ExecuteLine(aBuf); } } else if(str_comp_nocase(pType, "spectate") == 0) { int SpectateID = str_toint(pValue); if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !pSelf->m_apPlayers[SpectateID] || pSelf->m_apPlayers[SpectateID]->GetTeam() == TEAM_SPECTATORS) { pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "Invalid client id to move"); return; } str_format(aBuf, sizeof(aBuf), "set_team %d -1", SpectateID); pSelf->Console()->ExecuteLine(aBuf); } }
void CCountryFlags::LoadCountryflagsIndexfile() { IOHANDLE File = Storage()->OpenFile("countryflags/index.txt", IOFLAG_READ, IStorage::TYPE_ALL); if(!File) { Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", "couldn't open index file"); return; } char aOrigin[128]; CLineReader LineReader; LineReader.Init(File); char *pLine; while((pLine = LineReader.Get())) { if(!str_length(pLine) || pLine[0] == '#') // skip empty lines and comments continue; str_copy(aOrigin, pLine, sizeof(aOrigin)); char *pReplacement = LineReader.Get(); if(!pReplacement) { Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", "unexpected end of index file"); break; } if(pReplacement[0] != '=' || pReplacement[1] != '=' || pReplacement[2] != ' ') { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); continue; } int CountryCode = str_toint(pReplacement+3); if(CountryCode < CODE_LB || CountryCode > CODE_UB) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "country code '%i' not within valid code range [%i..%i]", CountryCode, CODE_LB, CODE_UB); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); continue; } // load the graphic file char aBuf[128]; str_format(aBuf, sizeof(aBuf), "countryflags/%s.png", aOrigin); CImageInfo Info; if(!Graphics()->LoadPNG(&Info, aBuf, IStorage::TYPE_ALL)) { char aMsg[128]; str_format(aMsg, sizeof(aMsg), "failed to load '%s'", aBuf); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aMsg); continue; } // add entry CCountryFlag CountryFlag; CountryFlag.m_CountryCode = CountryCode; str_copy(CountryFlag.m_aCountryCodeString, aOrigin, sizeof(CountryFlag.m_aCountryCodeString)); CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); mem_free(Info.m_pData); str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf); m_aCountryFlags.add(CountryFlag); } io_close(File); mem_zero(m_CodeIndexLUT, sizeof(m_CodeIndexLUT)); for(int i = 0; i < m_aCountryFlags.size(); ++i) m_CodeIndexLUT[max(0, (m_aCountryFlags[i].m_CountryCode-CODE_LB)%CODE_RANGE)] = i+1; }
void CMenus::RenderServerbrowserFilters(CUIRect View) { CUIRect ServerFilter = View, FilterHeader; const float FontSize = 12.0f; ServerFilter.HSplitBottom(42.5f, &ServerFilter, 0); // server filter ServerFilter.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFilter); RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerFilter, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); UI()->DoLabelScaled(&FilterHeader, Localize("Server filter"), FontSize+2.0f, 0); CUIRect Button; ServerFilter.VSplitLeft(5.0f, 0, &ServerFilter); ServerFilter.Margin(3.0f, &ServerFilter); ServerFilter.VMargin(5.0f, &ServerFilter); ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterEmpty, Localize("Has people playing"), g_Config.m_BrFilterEmpty, &Button)) g_Config.m_BrFilterEmpty ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if(DoButton_CheckBox(&g_Config.m_BrFilterSpectators, Localize("Count players only"), g_Config.m_BrFilterSpectators, &Button)) g_Config.m_BrFilterSpectators ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterFull, Localize("Server not full"), g_Config.m_BrFilterFull, &Button)) g_Config.m_BrFilterFull ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterFriends, Localize("Show friends only"), g_Config.m_BrFilterFriends, &Button)) g_Config.m_BrFilterFriends ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterPw, Localize("No password"), g_Config.m_BrFilterPw, &Button)) g_Config.m_BrFilterPw ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterCompatversion, Localize("Compatible version"), g_Config.m_BrFilterCompatversion, &Button)) g_Config.m_BrFilterCompatversion ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPure, Localize("Standard gametype"), g_Config.m_BrFilterPure, &Button)) g_Config.m_BrFilterPure ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPureMap, Localize("Standard map"), g_Config.m_BrFilterPureMap, &Button)) g_Config.m_BrFilterPureMap ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterGametypeStrict, Localize("Strict gametype filter"), g_Config.m_BrFilterGametypeStrict, &Button)) g_Config.m_BrFilterGametypeStrict ^= 1; ServerFilter.HSplitTop(5.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); UI()->DoLabelScaled(&Button, Localize("Game types:"), FontSize, -1); Button.VSplitRight(60.0f, 0, &Button); ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); static float Offset = 0.0f; if(DoEditBox(&g_Config.m_BrFilterGametype, &Button, g_Config.m_BrFilterGametype, sizeof(g_Config.m_BrFilterGametype), FontSize, &Offset)) Client()->ServerBrowserUpdate(); { ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); CUIRect EditBox; Button.VSplitRight(60.0f, &Button, &EditBox); UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), FontSize, -1); char aBuf[5]; str_format(aBuf, sizeof(aBuf), "%d", g_Config.m_BrFilterPing); static float Offset = 0.0f; DoEditBox(&g_Config.m_BrFilterPing, &EditBox, aBuf, sizeof(aBuf), FontSize, &Offset); g_Config.m_BrFilterPing = clamp(str_toint(aBuf), 0, 999); } // server address ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); UI()->DoLabelScaled(&Button, Localize("Server address:"), FontSize, -1); Button.VSplitRight(60.0f, 0, &Button); static float OffsetAddr = 0.0f; if(DoEditBox(&g_Config.m_BrFilterServerAddress, &Button, g_Config.m_BrFilterServerAddress, sizeof(g_Config.m_BrFilterServerAddress), FontSize, &OffsetAddr)) Client()->ServerBrowserUpdate(); // player country { CUIRect Rect; ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(26.0f, &Button, &ServerFilter); Button.VSplitRight(60.0f, &Button, &Rect); Button.HMargin(3.0f, &Button); if(DoButton_CheckBox(&g_Config.m_BrFilterCountry, Localize("Player country:"), g_Config.m_BrFilterCountry, &Button)) g_Config.m_BrFilterCountry ^= 1; float OldWidth = Rect.w; Rect.w = Rect.h*2; Rect.x += (OldWidth-Rect.w)/2.0f; vec4 Color(1.0f, 1.0f, 1.0f, g_Config.m_BrFilterCountry?1.0f: 0.5f); m_pClient->m_pCountryFlags->Render(g_Config.m_BrFilterCountryIndex, &Color, Rect.x, Rect.y, Rect.w, Rect.h); if(g_Config.m_BrFilterCountry && UI()->DoButtonLogic(&g_Config.m_BrFilterCountryIndex, "", 0, &Rect)) m_Popup = POPUP_COUNTRY; } ServerFilter.HSplitBottom(5.0f, &ServerFilter, 0); ServerFilter.HSplitBottom(ms_ButtonHeight-2.0f, &ServerFilter, &Button); static int s_ClearButton = 0; if(DoButton_Menu(&s_ClearButton, Localize("Reset filter"), 0, &Button)) { g_Config.m_BrFilterString[0] = 0; g_Config.m_BrFilterFull = 0; g_Config.m_BrFilterEmpty = 0; g_Config.m_BrFilterSpectators = 0; g_Config.m_BrFilterFriends = 0; g_Config.m_BrFilterCountry = 0; g_Config.m_BrFilterCountryIndex = -1; g_Config.m_BrFilterPw = 0; g_Config.m_BrFilterPing = 999; g_Config.m_BrFilterGametype[0] = 0; g_Config.m_BrFilterGametypeStrict = 0; g_Config.m_BrFilterServerAddress[0] = 0; g_Config.m_BrFilterPure = 1; g_Config.m_BrFilterPureMap = 1; g_Config.m_BrFilterCompatversion = 1; Client()->ServerBrowserUpdate(); } }
void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) { void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgID, pUnpacker); CPlayer *pPlayer = m_apPlayers[ClientID]; if(!pRawMsg) { if(g_Config.m_Debug) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgID), MsgID, m_NetObjHandler.FailedMsgOn()); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); } return; } if(MsgID == NETMSGTYPE_CL_SAY) { CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg; int Team = pMsg->m_Team; if(Team) Team = pPlayer->GetTeam(); else Team = CGameContext::CHAT_ALL; if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick()) return; pPlayer->m_LastChat = Server()->Tick(); // check for invalid chars unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage; while (*pMessage) { if(*pMessage < 32) *pMessage = ' '; pMessage++; } SendChat(ClientID, Team, pMsg->m_pMessage); } else if(MsgID == NETMSGTYPE_CL_CALLVOTE) { CNetMsg_Cl_CallVote *pMsg = (CNetMsg_Cl_CallVote *)pRawMsg; int64 Now = Server()->Tick(); if(pMsg->m_Force) { if(!Server()->IsAuthed(ClientID)) return; } else { if((g_Config.m_SvSpamprotection && ((pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry+Server()->TickSpeed()*3 > Now) || (pPlayer->m_LastVoteCall && pPlayer->m_LastVoteCall+Server()->TickSpeed()*VOTE_COOLDOWN > Now))) || pPlayer->GetTeam() == TEAM_SPECTATORS || m_VoteCloseTime) return; pPlayer->m_LastVoteTry = Now; } int Type = VOTE_UNKNOWN; char aDesc[VOTE_DESC_LENGTH] = {0}; char aCmd[VOTE_CMD_LENGTH] = {0}; const char *pReason = pMsg->m_Reason[0] ? pMsg->m_Reason : "No reason given"; if(str_comp_nocase(pMsg->m_Type, "option") == 0) { CVoteOptionServer *pOption = m_pVoteOptionFirst; while(pOption) { if(str_comp_nocase(pMsg->m_Value, pOption->m_aDescription) == 0) { str_format(aDesc, sizeof(aDesc), "%s", pOption->m_aDescription); str_format(aCmd, sizeof(aCmd), "%s", pOption->m_aCommand); if(pMsg->m_Force) { Server()->SetRconCID(ClientID); Console()->ExecuteLine(aCmd); Server()->SetRconCID(IServer::RCON_CID_SERV); ForceVote(VOTE_START_OP, aDesc, pReason); return; } Type = VOTE_START_OP; break; } pOption = pOption->m_pNext; } if(!pOption) return; } else if(str_comp_nocase(pMsg->m_Type, "kick") == 0) { if(!g_Config.m_SvVoteKick || m_pController->GetRealPlayerNum() < g_Config.m_SvVoteKickMin) return; int KickID = str_toint(pMsg->m_Value); if(KickID < 0 || KickID >= MAX_CLIENTS || !m_apPlayers[KickID] || KickID == ClientID || Server()->IsAuthed(KickID)) return; str_format(aDesc, sizeof(aDesc), "Kick '%s'", Server()->ClientName(KickID)); if (!g_Config.m_SvVoteKickBantime) str_format(aCmd, sizeof(aCmd), "kick %d Kicked by vote", KickID); else { char aAddrStr[NETADDR_MAXSTRSIZE] = {0}; Server()->GetClientAddr(KickID, aAddrStr, sizeof(aAddrStr)); str_format(aCmd, sizeof(aCmd), "ban %s %d Banned by vote", aAddrStr, g_Config.m_SvVoteKickBantime); } if(pMsg->m_Force) { Server()->SetRconCID(ClientID); Console()->ExecuteLine(aCmd); Server()->SetRconCID(IServer::RCON_CID_SERV); return; } Type = VOTE_START_KICK; m_VoteClientID = KickID; } else if(str_comp_nocase(pMsg->m_Type, "spectate") == 0) { if(!g_Config.m_SvVoteSpectate) return; int SpectateID = str_toint(pMsg->m_Value); if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !m_apPlayers[SpectateID] || m_apPlayers[SpectateID]->GetTeam() == TEAM_SPECTATORS || SpectateID == ClientID) return; str_format(aDesc, sizeof(aDesc), "move '%s' to spectators", Server()->ClientName(SpectateID)); str_format(aCmd, sizeof(aCmd), "set_team %d -1 %d", SpectateID, g_Config.m_SvVoteSpectateRejoindelay); if(pMsg->m_Force) { Server()->SetRconCID(ClientID); Console()->ExecuteLine(aCmd); Server()->SetRconCID(IServer::RCON_CID_SERV); ForceVote(VOTE_START_SPEC, aDesc, pReason); return; } Type = VOTE_START_SPEC; m_VoteClientID = SpectateID; } if(Type != VOTE_UNKNOWN) { m_VoteCreator = ClientID; StartVote(Type, aDesc, aCmd, pReason); pPlayer->m_Vote = 1; pPlayer->m_VotePos = m_VotePos = 1; pPlayer->m_LastVoteCall = Now; } } else if(MsgID == NETMSGTYPE_CL_VOTE) { if(!m_VoteCloseTime) return; if(pPlayer->m_Vote == 0) { CNetMsg_Cl_Vote *pMsg = (CNetMsg_Cl_Vote *)pRawMsg; if(!pMsg->m_Vote) return; pPlayer->m_Vote = pMsg->m_Vote; pPlayer->m_VotePos = ++m_VotePos; m_VoteUpdate = true; } } else if(MsgID == NETMSGTYPE_CL_SETTEAM && m_pController->IsTeamChangeAllowed()) { CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg; if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick()) || (pMsg->m_Team != TEAM_SPECTATORS && m_LockTeams) || pPlayer->m_TeamChangeTick > Server()->Tick()) return; pPlayer->m_LastSetTeam = Server()->Tick(); // Switch team on given client and kill/respawn him if(m_pController->CanJoinTeam(pMsg->m_Team, ClientID) && m_pController->CanChangeTeam(pPlayer, pMsg->m_Team)) { if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS) m_VoteUpdate = true; pPlayer->m_TeamChangeTick = Server()->Tick()+Server()->TickSpeed()*3; m_pController->DoTeamChange(pPlayer, pMsg->m_Team); } } else if (MsgID == NETMSGTYPE_CL_SETSPECTATORMODE && !m_World.m_Paused) { CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg; if(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_LastSetSpectatorMode = Server()->Tick(); if(!pPlayer->SetSpectatorID(pMsg->m_SpectatorID)) SendGameMsg(GAMEMSG_SPEC_INVALIDID, ClientID); } else if (MsgID == NETMSGTYPE_CL_STARTINFO) { if(pPlayer->m_IsReadyToEnter) return; CNetMsg_Cl_StartInfo *pMsg = (CNetMsg_Cl_StartInfo *)pRawMsg; pPlayer->m_LastChangeInfo = Server()->Tick(); // set start infos Server()->SetClientName(ClientID, pMsg->m_pName); Server()->SetClientClan(ClientID, pMsg->m_pClan); Server()->SetClientCountry(ClientID, pMsg->m_Country); for(int p = 0; p < 6; p++) { str_copy(pPlayer->m_TeeInfos.m_aaSkinPartNames[p], pMsg->m_apSkinPartNames[p], 24); pPlayer->m_TeeInfos.m_aUseCustomColors[p] = pMsg->m_aUseCustomColors[p]; pPlayer->m_TeeInfos.m_aSkinPartColors[p] = pMsg->m_aSkinPartColors[p]; } m_pController->OnPlayerInfoChange(pPlayer); // send vote options CNetMsg_Sv_VoteClearOptions ClearMsg; Server()->SendPackMsg(&ClearMsg, MSGFLAG_VITAL, ClientID); CVoteOptionServer *pCurrent = m_pVoteOptionFirst; while(pCurrent) { // count options for actual packet int NumOptions = 0; for(CVoteOptionServer *p = pCurrent; p && NumOptions < MAX_VOTE_OPTION_ADD; p = p->m_pNext, ++NumOptions); // pack and send vote list packet CMsgPacker Msg(NETMSGTYPE_SV_VOTEOPTIONLISTADD); Msg.AddInt(NumOptions); while(pCurrent && NumOptions--) { Msg.AddString(pCurrent->m_aDescription, VOTE_DESC_LENGTH); pCurrent = pCurrent->m_pNext; } Server()->SendMsg(&Msg, MSGFLAG_VITAL, ClientID); } // send tuning parameters to client SendTuningParams(ClientID); // client is ready to enter pPlayer->m_IsReadyToEnter = true; CNetMsg_Sv_ReadyToEnter m; Server()->SendPackMsg(&m, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID); } else if (MsgID == NETMSGTYPE_CL_EMOTICON && !m_World.m_Paused) { CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg; if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote && pPlayer->m_LastEmote+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_LastEmote = Server()->Tick(); SendEmoticon(ClientID, pMsg->m_Emoticon); } else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused) { if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_LastKill = Server()->Tick(); pPlayer->KillCharacter(WEAPON_SELF); } else if (MsgID == NETMSGTYPE_CL_READYCHANGE) { if(pPlayer->m_LastReadyChange && pPlayer->m_LastReadyChange+Server()->TickSpeed()*1 > Server()->Tick()) return; pPlayer->m_LastReadyChange = Server()->Tick(); m_pController->OnPlayerReadyChange(pPlayer); } }
void CTeeFiles::Save() { const int sz = 32; for(int i = 0; i < m_aTees.size(); i++) { CTee *pTee = Get(i); bool Rename = false; char aFilename[41]; // + ".tee" + "xxx_" char aBuf[512]; if(pTee->m_aFilename[0] == '\0') { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "teefile%d%s%s%s%d%d%d%d", i, pTee->m_aName, pTee->m_aClan, pTee->m_aSkin, pTee->m_UseCustomColor, pTee->m_ColorBody, pTee->m_ColorFeet, pTee->m_Country); str_format(aFilename, sizeof(aFilename), "%03d_%s.tee", i, md5(aBuf)); } else { if(!(str_isdigit(pTee->m_aFilename[0]) && str_isdigit(pTee->m_aFilename[1]) && str_isdigit(pTee->m_aFilename[2]) && pTee->m_aFilename[3] == '_')) { str_format(aFilename, sizeof(aFilename), "%03d_%s", i, pTee->m_aFilename); Rename = true; } else { char aNewIndex[4]; char aOldIndex[4]; str_format(aNewIndex, sizeof(aNewIndex), "%03d", i); str_format(aOldIndex, sizeof(aOldIndex), pTee->m_aFilename); str_format(aFilename, sizeof(aFilename), pTee->m_aFilename); if(str_toint(aNewIndex) != str_toint(aOldIndex)) { for(int i = 0; i < 3; i++) aFilename[i] = aNewIndex[i]; Rename = true; } } } if(Rename) { char OldName[512]; char NewName[512]; str_format(OldName, sizeof(OldName), "xclient/teefiles/%s", pTee->m_aFilename); str_format(NewName, sizeof(NewName), "xclient/teefiles/%s", aFilename); Storage()->RenameFile(OldName, NewName, IStorage::TYPE_SAVE); Storage()->RemoveFile(OldName, IStorage::TYPE_SAVE); str_format(aBuf, sizeof(aBuf), "renamed '%s' to %s", pTee->m_aFilename, aFilename); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf); } str_format(aBuf, sizeof(aBuf), "xclient/teefiles/%s", aFilename); IOHANDLE File = Storage()->OpenFile(aBuf, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!File) continue; char aTeeEntry[NUM_TEE_ENTRIES][sz]; str_format(aTeeEntry[TEE_NAME], sz, pTee->m_aName); str_format(aTeeEntry[TEE_CLAN], sz, pTee->m_aClan); str_format(aTeeEntry[TEE_SKIN], sz, pTee->m_aSkin); str_format(aTeeEntry[TEE_USECUSTOMCOLOR], sz, "%d", pTee->m_UseCustomColor); str_format(aTeeEntry[TEE_COLORBODY], sz, "%d", pTee->m_ColorBody); str_format(aTeeEntry[TEE_COLORFEET], sz, "%d", pTee->m_ColorFeet); str_format(aTeeEntry[TEE_COUNTRY], sz, "%d", pTee->m_Country); for(int j = 0; j < NUM_TEE_ENTRIES; j++) { if(!File) { str_format(aBuf, sizeof(aBuf), "failed to save '%s' at line %d", aFilename, j); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf); io_close(File); mem_zero(aTeeEntry[j], sizeof(aTeeEntry[j])); break; } io_write(File, aTeeEntry[j], str_length(aTeeEntry[j])); io_write_newline(File); } io_close(File); } }
void CMenus::RenderServerbrowserFilters(CUIRect View) { // filters CUIRect Button; View.HSplitTop(5.0f, 0, &View); View.VSplitLeft(5.0f, 0, &View); View.VSplitRight(5.0f, &View, 0); View.HSplitBottom(5.0f, &View, 0); // render filters View.HSplitTop(20.0f, &Button, &View); if (DoButton_CheckBox(&g_Config.m_BrFilterEmpty, Localize("Has people playing"), g_Config.m_BrFilterEmpty, &Button)) g_Config.m_BrFilterEmpty ^= 1; View.HSplitTop(20.0f, &Button, &View); if (DoButton_CheckBox(&g_Config.m_BrFilterFull, Localize("Server not full"), g_Config.m_BrFilterFull, &Button)) g_Config.m_BrFilterFull ^= 1; View.HSplitTop(20.0f, &Button, &View); if (DoButton_CheckBox(&g_Config.m_BrFilterPw, Localize("No password"), g_Config.m_BrFilterPw, &Button)) g_Config.m_BrFilterPw ^= 1; View.HSplitTop(20.0f, &Button, &View); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterCompatversion, Localize("Compatible version"), g_Config.m_BrFilterCompatversion, &Button)) g_Config.m_BrFilterCompatversion ^= 1; View.HSplitTop(20.0f, &Button, &View); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPure, Localize("Standard gametype"), g_Config.m_BrFilterPure, &Button)) g_Config.m_BrFilterPure ^= 1; View.HSplitTop(20.0f, &Button, &View); //button.VSplitLeft(20.0f, 0, &button); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPureMap, Localize("Standard map"), g_Config.m_BrFilterPureMap, &Button)) g_Config.m_BrFilterPureMap ^= 1; View.HSplitTop(5.0f, 0, &View); View.HSplitTop(19.0f, &Button, &View); UI()->DoLabelScaled(&Button, Localize("Game types:"), 12.0f, -1); Button.VSplitLeft(95.0f, 0, &Button); View.HSplitTop(3.0f, 0, &View); static float Offset = 0.0f; DoEditBox(&g_Config.m_BrFilterGametype, &Button, g_Config.m_BrFilterGametype, sizeof(g_Config.m_BrFilterGametype), 12.0f, &Offset); { View.HSplitTop(19.0f, &Button, &View); CUIRect EditBox; Button.VSplitRight(50.0f, &Button, &EditBox); EditBox.VSplitRight(5.0f, &EditBox, 0); UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), 12.0f, -1); char aBuf[5]; str_format(aBuf, sizeof(aBuf), "%d", g_Config.m_BrFilterPing); static float Offset = 0.0f; DoEditBox(&g_Config.m_BrFilterPing, &EditBox, aBuf, sizeof(aBuf), 12.0f, &Offset); g_Config.m_BrFilterPing = str_toint(aBuf); } View.HSplitBottom(ms_ButtonHeight, &View, &Button); static int s_ClearButton = 0; if(DoButton_Menu(&s_ClearButton, Localize("Reset filter"), 0, &Button)) { g_Config.m_BrFilterFull = 0; g_Config.m_BrFilterEmpty = 0; g_Config.m_BrFilterPw = 0; g_Config.m_BrFilterPing = 999; g_Config.m_BrFilterGametype[0] = 0; g_Config.m_BrFilterCompatversion = 1; g_Config.m_BrFilterString[0] = 0; g_Config.m_BrFilterPure = 1; g_Config.m_BrFilterPureMap = 1; } }
int CMenus::PopupFilter(CMenus *pMenus, CUIRect View) { CUIRect ServerFilter = View, FilterHeader; const float FontSize = 12.0f; // slected filter CBrowserFilter *pFilter = &pMenus->m_lFilters[pMenus->m_SelectedFilter]; CServerFilterInfo FilterInfo; pFilter->GetFilter(&FilterInfo); // server filter ServerFilter.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFilter); pMenus->RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); pMenus->RenderTools()->DrawUIRect(&ServerFilter, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); pMenus->UI()->DoLabelScaled(&FilterHeader, Localize("Server filter"), FontSize+2.0f, CUI::ALIGN_CENTER); CUIRect Button; ServerFilter.VSplitLeft(5.0f, 0, &ServerFilter); ServerFilter.Margin(3.0f, &ServerFilter); ServerFilter.VMargin(5.0f, &ServerFilter); int NewSortHash = FilterInfo.m_SortHash; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterEmpty = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterEmpty, Localize("Has people playing"), FilterInfo.m_SortHash&IServerBrowser::FILTER_EMPTY, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_EMPTY; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterSpectators = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterSpectators, Localize("Count players only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_SPECTATORS; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterFull = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterFull, Localize("Server not full"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FULL, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FULL; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterFriends = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterFriends, Localize("Show friends only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FRIENDS; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterPw = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterPw, Localize("No password"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PW, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PW; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterCompatversion = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterCompatversion, Localize("Compatible version"), FilterInfo.m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_COMPAT_VERSION; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterPure = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterPure, Localize("Standard gametype"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PURE; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterPureMap = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterPureMap, Localize("Standard map"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE_MAP, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PURE_MAP; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterGametypeStrict = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterGametypeStrict, Localize("Strict gametype filter"), FilterInfo.m_SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_GAMETYPE_STRICT; if(FilterInfo.m_SortHash != NewSortHash) { FilterInfo.m_SortHash = NewSortHash; pFilter->SetFilter(&FilterInfo); } ServerFilter.HSplitTop(5.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); pMenus->UI()->DoLabelScaled(&Button, Localize("Game types:"), FontSize, CUI::ALIGN_LEFT); Button.VSplitRight(60.0f, 0, &Button); ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); static float Offset = 0.0f; static int s_BrFilterGametype = 0; if(pMenus->DoEditBox(&s_BrFilterGametype, &Button, FilterInfo.m_aGametype, sizeof(FilterInfo.m_aGametype), FontSize, &Offset)) pFilter->SetFilter(&FilterInfo); { ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); CUIRect EditBox; Button.VSplitRight(60.0f, &Button, &EditBox); pMenus->UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), FontSize, CUI::ALIGN_LEFT); char aBuf[5]; str_format(aBuf, sizeof(aBuf), "%d", FilterInfo.m_Ping); static float Offset = 0.0f; static int s_BrFilterPing = 0; pMenus->DoEditBox(&s_BrFilterPing, &EditBox, aBuf, sizeof(aBuf), FontSize, &Offset); int NewPing = clamp(str_toint(aBuf), 0, 999); if(NewPing != FilterInfo.m_Ping) { FilterInfo.m_Ping = NewPing; pFilter->SetFilter(&FilterInfo); } } // server address ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); pMenus->UI()->DoLabelScaled(&Button, Localize("Server address:"), FontSize, CUI::ALIGN_LEFT); Button.VSplitRight(60.0f, 0, &Button); static float OffsetAddr = 0.0f; static int s_BrFilterServerAddress = 0; if(pMenus->DoEditBox(&s_BrFilterServerAddress, &Button, FilterInfo.m_aAddress, sizeof(FilterInfo.m_aAddress), FontSize, &OffsetAddr)) pFilter->SetFilter(&FilterInfo); // player country { CUIRect Rect; ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(26.0f, &Button, &ServerFilter); Button.VSplitRight(60.0f, &Button, &Rect); Button.HMargin(3.0f, &Button); static int s_BrFilterCountry = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterCountry, Localize("Player country:"), FilterInfo.m_SortHash&IServerBrowser::FILTER_COUNTRY, &Button)) { FilterInfo.m_SortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY; pFilter->SetFilter(&FilterInfo); } float OldWidth = Rect.w; Rect.w = Rect.h*2; Rect.x += (OldWidth-Rect.w)/2.0f; vec4 Color(1.0f, 1.0f, 1.0f, FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY?1.0f: 0.5f); pMenus->m_pClient->m_pCountryFlags->Render(FilterInfo.m_Country, &Color, Rect.x, Rect.y, Rect.w, Rect.h); static int s_BrFilterCountryIndex = 0; if(FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY && pMenus->UI()->DoButtonLogic(&s_BrFilterCountryIndex, "", 0, &Rect)) pMenus->m_Popup = POPUP_COUNTRY; } return 0; }
int main(int argc, char **argv) { pNet = new CNetServer; while(argc) { // ? /*if(str_comp(*argv, "-m") == 0) { argc--; argv++; net_host_lookup(*argv, &aMasterServers[NumMasters], NETTYPE_IPV4); argc--; argv++; aMasterServers[NumMasters].port = str_toint(*argv); NumMasters++; } else */if(str_comp(*argv, "-p") == 0) { argc--; argv++; PlayerNames[NumPlayers++] = *argv; argc--; argv++; PlayerScores[NumPlayers] = str_toint(*argv); } else if(str_comp(*argv, "-a") == 0) { argc--; argv++; pMap = *argv; } else if(str_comp(*argv, "-x") == 0) { argc--; argv++; MaxPlayers = str_toint(*argv); } else if(str_comp(*argv, "-t") == 0) { argc--; argv++; GameType = str_toint(*argv); } else if(str_comp(*argv, "-g") == 0) { argc--; argv++; Progression = str_toint(*argv); } else if(str_comp(*argv, "-f") == 0) { argc--; argv++; Flags = str_toint(*argv); } else if(str_comp(*argv, "-n") == 0) { argc--; argv++; pServerName = *argv; } argc--; argv++; } BuildInfoMsg(); int RunReturn = Run(); delete pNet; return RunReturn; }
void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) { void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgID, pUnpacker); CPlayer *pPlayer = m_apPlayers[ClientID]; if(!pRawMsg) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgID), MsgID, m_NetObjHandler.FailedMsgOn()); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); return; } if(MsgID == NETMSGTYPE_CL_SAY) { CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg; int Team = pMsg->m_Team; if(Team) Team = pPlayer->GetTeam(); else Team = CGameContext::CHAT_ALL; if(g_Config.m_SvSpamprotection && pPlayer->m_Last_Chat && pPlayer->m_Last_Chat+Server()->TickSpeed() > Server()->Tick()) return; pPlayer->m_Last_Chat = Server()->Tick(); // check for invalid chars unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage; while (*pMessage) { if(*pMessage < 32) *pMessage = ' '; pMessage++; } SendChat(ClientID, Team, pMsg->m_pMessage); } else if(MsgID == NETMSGTYPE_CL_CALLVOTE) { if(g_Config.m_SvSpamprotection && pPlayer->m_Last_VoteTry && pPlayer->m_Last_VoteTry+Server()->TickSpeed()*3 > Server()->Tick()) return; int64 Now = Server()->Tick(); pPlayer->m_Last_VoteTry = Now; if(pPlayer->GetTeam() == TEAM_SPECTATORS) { SendChatTarget(ClientID, "Spectators aren't allowed to start a vote."); return; } if(m_VoteCloseTime) { SendChatTarget(ClientID, "Wait for current vote to end before calling a new one."); return; } int Timeleft = pPlayer->m_Last_VoteCall + Server()->TickSpeed()*60 - Now; if(pPlayer->m_Last_VoteCall && Timeleft > 0) { char aChatmsg[512] = {0}; str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (Timeleft/Server()->TickSpeed())+1); SendChatTarget(ClientID, aChatmsg); return; } char aChatmsg[512] = {0}; char aDesc[512] = {0}; char aCmd[512] = {0}; CNetMsg_Cl_CallVote *pMsg = (CNetMsg_Cl_CallVote *)pRawMsg; if(str_comp_nocase(pMsg->m_Type, "option") == 0) { CVoteOption *pOption = m_pVoteOptionFirst; while(pOption) { if(str_comp_nocase(pMsg->m_Value, pOption->m_aCommand) == 0) { str_format(aChatmsg, sizeof(aChatmsg), "'%s' called vote to change server option '%s'", Server()->ClientName(ClientID), pOption->m_aCommand); str_format(aDesc, sizeof(aDesc), "%s", pOption->m_aCommand); str_format(aCmd, sizeof(aCmd), "%s", pOption->m_aCommand); break; } pOption = pOption->m_pNext; } if(!pOption) { str_format(aChatmsg, sizeof(aChatmsg), "'%s' isn't an option on this server", pMsg->m_Value); SendChatTarget(ClientID, aChatmsg); return; } } else if(str_comp_nocase(pMsg->m_Type, "kick") == 0) { if(!g_Config.m_SvVoteKick) { SendChatTarget(ClientID, "Server does not allow voting to kick players"); return; } int KickID = str_toint(pMsg->m_Value); if(KickID < 0 || KickID >= MAX_CLIENTS || !m_apPlayers[KickID]) { SendChatTarget(ClientID, "Invalid client id to kick"); return; } if(KickID == ClientID) { SendChatTarget(ClientID, "You cant kick yourself"); return; } if(Server()->IsAuthed(KickID)) { SendChatTarget(ClientID, "You cant kick admins"); char aBufKick[128]; str_format(aBufKick, sizeof(aBufKick), "'%s' called for vote to kick you", Server()->ClientName(ClientID)); SendChatTarget(KickID, aBufKick); return; } const char *pReason = "No reason given"; for(const char *pStr = pMsg->m_Value; *pStr; ++pStr) { if(*pStr == ' ') { pReason = pStr+1; break; } } str_format(aChatmsg, sizeof(aChatmsg), "'%s' called for vote to kick '%s' (%s)", Server()->ClientName(ClientID), Server()->ClientName(KickID), pReason); str_format(aDesc, sizeof(aDesc), "Kick '%s'", Server()->ClientName(KickID)); if (!g_Config.m_SvVoteKickBantime) str_format(aCmd, sizeof(aCmd), "kick %d Kicked by vote", KickID); else { char aBuf[64] = {0}; Server()->GetClientIP(KickID, aBuf, sizeof(aBuf)); str_format(aCmd, sizeof(aCmd), "ban %s %d Banned by vote", aBuf, g_Config.m_SvVoteKickBantime); } } if(aCmd[0]) { SendChat(-1, CGameContext::CHAT_ALL, aChatmsg); StartVote(aDesc, aCmd); pPlayer->m_Vote = 1; pPlayer->m_VotePos = m_VotePos = 1; m_VoteCreator = ClientID; pPlayer->m_Last_VoteCall = Now; } } else if(MsgID == NETMSGTYPE_CL_VOTE) { if(!m_VoteCloseTime) return; if(pPlayer->m_Vote == 0) { CNetMsg_Cl_Vote *pMsg = (CNetMsg_Cl_Vote *)pRawMsg; if(!pMsg->m_Vote) return; pPlayer->m_Vote = pMsg->m_Vote; pPlayer->m_VotePos = ++m_VotePos; m_VoteUpdate = true; } } else if (MsgID == NETMSGTYPE_CL_SETTEAM && !m_World.m_Paused) { CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg; if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_Last_SetTeam && pPlayer->m_Last_SetTeam+Server()->TickSpeed()*3 > Server()->Tick())) return; // Switch team on given client and kill/respawn him if(m_pController->CanJoinTeam(pMsg->m_Team, ClientID)) { if(m_pController->CanChangeTeam(pPlayer, pMsg->m_Team)) { pPlayer->m_Last_SetTeam = Server()->Tick(); if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS) m_VoteUpdate = true; pPlayer->SetTeam(pMsg->m_Team); (void)m_pController->CheckTeamBalance(); } else SendBroadcast("Teams must be balanced, please join other team", ClientID); } else { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "Only %d active players are allowed", g_Config.m_SvMaxClients-g_Config.m_SvSpectatorSlots); SendBroadcast(aBuf, ClientID); } } else if (MsgID == NETMSGTYPE_CL_CHANGEINFO || MsgID == NETMSGTYPE_CL_STARTINFO) { CNetMsg_Cl_ChangeInfo *pMsg = (CNetMsg_Cl_ChangeInfo *)pRawMsg; if(g_Config.m_SvSpamprotection && pPlayer->m_Last_ChangeInfo && pPlayer->m_Last_ChangeInfo+Server()->TickSpeed()*5 > Server()->Tick()) return; pPlayer->m_Last_ChangeInfo = Server()->Tick(); pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor; pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody; pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet; // copy old name char aOldName[MAX_NAME_LENGTH]; str_copy(aOldName, Server()->ClientName(ClientID), MAX_NAME_LENGTH); Server()->SetClientName(ClientID, pMsg->m_pName); if(MsgID == NETMSGTYPE_CL_CHANGEINFO && str_comp(aOldName, Server()->ClientName(ClientID)) != 0) { char aChatText[256]; str_format(aChatText, sizeof(aChatText), "'%s' changed name to '%s'", aOldName, Server()->ClientName(ClientID)); SendChat(-1, CGameContext::CHAT_ALL, aChatText); } // set skin str_copy(pPlayer->m_TeeInfos.m_SkinName, pMsg->m_pSkin, sizeof(pPlayer->m_TeeInfos.m_SkinName)); m_pController->OnPlayerInfoChange(pPlayer); if(MsgID == NETMSGTYPE_CL_STARTINFO) { // send vote options CNetMsg_Sv_VoteClearOptions ClearMsg; Server()->SendPackMsg(&ClearMsg, MSGFLAG_VITAL, ClientID); CVoteOption *pCurrent = m_pVoteOptionFirst; while(pCurrent) { CNetMsg_Sv_VoteOption OptionMsg; OptionMsg.m_pCommand = pCurrent->m_aCommand; Server()->SendPackMsg(&OptionMsg, MSGFLAG_VITAL, ClientID); pCurrent = pCurrent->m_pNext; } // send tuning parameters to client SendTuningParams(ClientID); // CNetMsg_Sv_ReadyToEnter m; Server()->SendPackMsg(&m, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID); } } else if (MsgID == NETMSGTYPE_CL_EMOTICON && !m_World.m_Paused) { CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg; if(g_Config.m_SvSpamprotection && pPlayer->m_Last_Emote && pPlayer->m_Last_Emote+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_Last_Emote = Server()->Tick(); SendEmoticon(ClientID, pMsg->m_Emoticon); } else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused) { if(pPlayer->m_Last_Kill && pPlayer->m_Last_Kill+Server()->TickSpeed()*3 > Server()->Tick()) return; pPlayer->m_Last_Kill = Server()->Tick(); pPlayer->KillCharacter(WEAPON_SELF); pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3; } }
int CConsole::CResult::GetInteger(unsigned Index) { if (Index >= m_NumArgs) return 0; return str_toint(m_apArgs[Index]); }