From 684ae6c63e0f78ee9ab9b06926607225014bfc8f Mon Sep 17 00:00:00 2001 From: savander Date: Sun, 21 Sep 2014 14:54:06 +0200 Subject: Update --- src/base/math.h | 7 ++ src/engine/server.h | 7 ++ src/engine/server/server.cpp | 186 +++++++++++++++++++++++++++++++-- src/engine/server/server.h | 31 ++++-- src/game/server/entities/character.cpp | 5 +- src/game/server/entities/character.h | 3 + src/game/server/gamecontext.cpp | 55 ++++++++-- src/game/server/gamemodes/zcatch.cpp | 80 ++++++++++++-- src/game/server/player.h | 2 + 9 files changed, 346 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/base/math.h b/src/base/math.h index d58dbf10..1728870b 100644 --- a/src/base/math.h +++ b/src/base/math.h @@ -67,4 +67,11 @@ template inline T min(T a, T b) { return a inline T max(T a, T b) { return a>b?a:b; } template inline T absolute(T a) { return a + class IServer : public IInterface { MACRO_INTERFACE("server", 0) @@ -71,6 +73,11 @@ public: //zCatch virtual void MapReload() = 0; + virtual int GetInfoTextIntervalPause() = 0; + virtual int GetInfoTextMsgInterval() = 0; + virtual int GetInfoTextInterval() = 0; + virtual std::string GetNextInfoText() = 0; + virtual int GetNumLoggedInAdmins() = 0; }; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 65affc64..8958a405 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -361,6 +361,8 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta) m_numLoggedInAdmins = 0; m_Votebans = NULL; + m_InfoTexts = NULL; + m_InfoTextInterval = -1; Init(); } @@ -374,9 +376,34 @@ CServer::~CServer() delete m_Votebans; m_Votebans = tmp; } + + // delte info texts + while(m_InfoTexts != NULL) + { + CInfoText *tmp = m_InfoTexts->m_Next; + delete m_InfoTexts; + m_InfoTexts = tmp; + } } +void CServer::UpdateLoggedInAdmins() +{ + bool gotAny = (m_numLoggedInAdmins > 0); + m_numLoggedInAdmins = 0; + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(m_aClients[i].m_State == CClient::STATE_INGAME && m_aClients[i].m_Authed >= AUTHED_SUBADMIN) + { + ++m_numLoggedInAdmins; + } + } + if(gotAny != (m_numLoggedInAdmins > 0)) + { + UpdateServerInfo(); + } +} + int CServer::TrySetClientName(int ClientID, const char *pName) { char aTrimmedName[64]; @@ -794,11 +821,6 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) // notify the mod about the drop if(pThis->m_aClients[ClientID].m_State >= CClient::STATE_READY) pThis->GameServer()->OnClientDrop(ClientID, pReason); - - // check if dropped player is admin - if (pThis->IsAuthed(ClientID)) { - pThis->DecreaseLoggedInAdmins(); - } pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY; pThis->m_aClients[ClientID].m_aName[0] = 0; @@ -808,6 +830,10 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; pThis->m_aClients[ClientID].m_Snapshots.PurgeAll(); + + // could have been an admin + pThis->UpdateLoggedInAdmins(); + return 0; } @@ -1125,7 +1151,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - IncreaseLoggedInAdmins(); + UpdateLoggedInAdmins(); } else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0) { @@ -1165,7 +1191,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (subadmin:%s)", ClientID, loginit->first.c_str()); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - IncreaseLoggedInAdmins(); + UpdateLoggedInAdmins(); } else if(g_Config.m_SvRconMaxTries) { @@ -1820,6 +1846,145 @@ void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser) } } +void CServer::ConAddInfo(IConsole::IResult *pResult, void *pUser) +{ + CServer* pThis = static_cast(pUser); + int interval = pResult->GetInteger(0); + if(interval < 1 || interval > 1440) + { + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Interval must be between 1 and 1440."); + return; + } + + // add info text + CInfoText *t = new CInfoText; + t->m_Interval = interval; + t->m_Text = std::string(pResult->GetString(1)); + // insert front + t->m_Next = pThis->m_InfoTexts; + pThis->m_InfoTexts = t; + + pThis->UpdateInfoTexts(); + + // message to console + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "Added the following info text: %s", t->m_Text.c_str()); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); +} + +void CServer::ConRemoveInfo(IConsole::IResult *pResult, void *pUser) +{ + CServer* pThis = static_cast(pUser); + int i = pResult->GetInteger(0); + int count = 0; + bool removed = false; + + CInfoText **t = &(pThis->m_InfoTexts); + while(*t != NULL) + { + if(count++ == i) + { + // remove + CInfoText *next = (*t)->m_Next; + delete *t; + *t = next; + removed = true; + break; + } + t = &((*t)->m_Next); + } + + pThis->UpdateInfoTexts(); + + if(removed) + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text removed"); + else + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text not found"); +} + +void CServer::ConListInfo(IConsole::IResult *pResult, void *pUser) +{ + CServer* pThis = static_cast(pUser); + char aBuf[128]; + int count = 0; + + CInfoText *t = pThis->m_InfoTexts; + while(t != NULL) + { + str_format(aBuf, sizeof(aBuf), "#%d interval=%d min text='%s'", count++, t->m_Interval, t->m_Text.c_str()); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); + t = t->m_Next; + } + + str_format(aBuf, sizeof(aBuf), "%d info text(s)", count); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); +} + +void CServer::UpdateInfoTexts() +{ + // in case that there are no info texts + if(m_InfoTexts == NULL) + { + m_InfoTextInterval = -1; // no interval + return; + } + + // need some random numbers later + init_rand(); + + // update interval, set it to LCM(all text intervals) + m_InfoTextInterval = 1; // lowest possible interval + CInfoText *t = m_InfoTexts; + while(t != NULL) + { + m_InfoTextInterval = lcm(m_InfoTextInterval, t->m_Interval); + t->m_IntervalTicks = TickSpeed() * 60 * t->m_Interval; // min to ticks + t->m_NextTick = rand() % t->m_IntervalTicks; // variance + t = t->m_Next; + } + m_InfoTextInterval *= TickSpeed() * 60; // min to ticks + + // count total number of messages per interval + int numMsg = 0; + t = m_InfoTexts; + while(t != NULL) + { + numMsg += m_InfoTextInterval / t->m_IntervalTicks; + t = t->m_Next; + } + + // interval between messages + m_InfoTextMsgInterval = m_InfoTextInterval / numMsg; + // additional pause to sync interval and msg interval + m_InfoTextIntervalPause = m_InfoTextInterval % numMsg; +} + +std::string CServer::GetNextInfoText() +{ + CInfoText *selectedText = NULL, + *t = m_InfoTexts; + // the counter r keeps track of how many equally due texts there are and actually helps so that every text has the same chance even though there are r-1 random decisions + int r = 1; + while(t != NULL) + { + // use this text if none is selected or this one is more due than the previously selected + // in the case that both are equally due, select one random + if(selectedText == NULL + || t->m_NextTick < selectedText->m_NextTick + || (t->m_NextTick == selectedText->m_NextTick && (rand() % ++r) == 0)) + selectedText = t; + t = t->m_Next; + } + + // return empty string if no text applies + if(selectedText == NULL) + return std::string(); + + // update tick and return string + selectedText->m_NextTick += selectedText->m_IntervalTicks; + return selectedText->m_Text; +} + void CServer::ConKick(IConsole::IResult *pResult, void *pUser) { if(pResult->NumArguments() > 1) @@ -1859,6 +2024,7 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser) pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf); } } + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Quick help: kick | ban | voteban | kill "); } void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser) @@ -1943,7 +2109,7 @@ void CServer::rconLogClientOut(int ClientID, const char *msg) char aBuf[32]; str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - DecreaseLoggedInAdmins(); + UpdateLoggedInAdmins(); } } @@ -2033,6 +2199,10 @@ void CServer::RegisterCommands() Console()->Register("add_login", "ss", CFGFLAG_SERVER, ConAddLogin, this, "Add a subadmin login. The rcon password will be user:pass with no additional spaces.", IConsole::ACCESS_LEVEL_ADMIN); Console()->Register("remove_login", "s", CFGFLAG_SERVER, ConRemoveLogin, this, "Remove a subadmin login", IConsole::ACCESS_LEVEL_ADMIN); + + Console()->Register("add_info", "is", CFGFLAG_SERVER, ConAddInfo, this, "Add a info text that is printed in the chat repeatedly in the given interval of minutes."); + Console()->Register("remove_info", "i", CFGFLAG_SERVER, ConRemoveInfo, this, "Remove a info text"); + Console()->Register("list_info", "", CFGFLAG_SERVER, ConListInfo, this, "Show all info texts"); // register console commands in sub parts m_ServerBan.InitServerBan(Console(), Storage(), this); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 7959603a..9b3ac371 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -71,12 +71,22 @@ class CServer : public IServer // keep track of how many admins are logged in int m_numLoggedInAdmins; - void DecreaseLoggedInAdmins() { - if (!--m_numLoggedInAdmins) UpdateServerInfo(); - } - void IncreaseLoggedInAdmins() { - if (++m_numLoggedInAdmins) UpdateServerInfo(); - } + void UpdateLoggedInAdmins(); + + // info messages + void UpdateInfoTexts(); + struct CInfoText + { + int m_Interval; + int m_IntervalTicks; + int m_NextTick; + std::string m_Text; + CInfoText *m_Next; + }; + CInfoText *m_InfoTexts; + int m_InfoTextInterval; + int m_InfoTextMsgInterval; + int m_InfoTextIntervalPause; public: class IGameServer *GameServer() { return m_pGameServer; } @@ -290,6 +300,15 @@ public: static void ConAddLogin(IConsole::IResult *pResult, void *pUser); static void ConRemoveLogin(IConsole::IResult *pResult, void *pUser); + // info messages + static void ConAddInfo(IConsole::IResult *pResult, void *pUser); + static void ConRemoveInfo(IConsole::IResult *pResult, void *pUser); + static void ConListInfo(IConsole::IResult *pResult, void *pUser); + int GetInfoTextIntervalPause() { return m_InfoTextIntervalPause; } + int GetInfoTextMsgInterval() { return m_InfoTextMsgInterval; } + int GetInfoTextInterval() { return m_InfoTextInterval; } + std::string GetNextInfoText(); + virtual int GetNumLoggedInAdmins() { return m_numLoggedInAdmins; } // logins diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 2c1828da..b541f240 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -89,6 +89,8 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos) m_ActiveWeapon = WEAPON_GUN; m_LastWeapon = WEAPON_HAMMER; } + + pPlayer->m_RespawnProtection = Server()->Tick() + Server()->TickSpeed() * 2; /* end zCatch */ m_LastNoAmmoSound = -1; @@ -879,10 +881,11 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon) /* zCatch */ if(From == m_pPlayer->GetCID() || Weapon == WEAPON_GAME) return false; - if(g_Config.m_SvMode == 4 && Weapon == WEAPON_GRENADE && Dmg < g_Config.m_SvGrenadeMinDamage) return false; + if(m_pPlayer->m_RespawnProtection > Server()->Tick() || GameServer()->m_apPlayers[From]->m_RespawnProtection > Server()->Tick()) + return false; m_Health = 0; m_Armor = 0; /* end zCatch */ diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 0d68707a..240ee0e2 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -73,6 +73,8 @@ public: bool HasBeenThereRecently(vec2 v, const vec2 *&pos, int firstTick, int lastTick) const; bool AimedAtCharRecently(vec2 v, const CCharacter *c, const vec2 *&pos, const vec2 *&posVictim, int firstTick); float HowCloseToXRecently(vec2 x, const vec2 *&pos, int firstTick); + void SetEmoteType(int EmoteType) { m_EmoteType = EmoteType; }; + void SetEmoteStop(int EmoteStop) { m_EmoteStop = EmoteStop; }; private: // player controlling this character @@ -105,6 +107,7 @@ private: int m_EmoteType; int m_EmoteStop; + // last tick that the player took any action ie some input int m_LastAction; int m_LastNoAmmoSound; diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 52b5b9fd..27d17c11 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -526,6 +526,14 @@ void CGameContext::OnTick() } } } + + // info messages + // execute if interval is given and message interval is due, respecting the pause + if(Server()->GetInfoTextInterval() > 0 + && ((Server()->Tick() % Server()->GetInfoTextInterval()) - Server()->GetInfoTextIntervalPause()) % Server()->GetInfoTextMsgInterval() == 0) + { + SendChat(-1, CGameContext::CHAT_ALL, Server()->GetNextInfoText().c_str()); + } // bot detection // it is based on the behaviour of some bots to shoot at a player's _exact_ position @@ -940,20 +948,16 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) if(MuteValidation(pPlayer)) { // prepare message - const char *msgForm = "/PM/ %s", - *msgFormSender = "/PM -> %s / %s"; + const char *msgForm = "/PM -> %s / %s"; int len = 32 + MAX_NAME_LENGTH + str_length(msgStart); char *msg = (char*)malloc(len * sizeof(char)); CNetMsg_Sv_Chat M; M.m_Team = 0; M.m_ClientID = ClientID; - // send to sender - str_format(msg, len * sizeof(char), msgFormSender, Server()->ClientName(recipient), msgStart); + // send to sender and recipient + str_format(msg, len * sizeof(char), msgForm, Server()->ClientName(recipient), msgStart); M.m_pMessage = msg; Server()->SendPackMsg(&M, MSGFLAG_VITAL, ClientID); - // send to recipient - str_format(msg, len * sizeof(char), msgForm, msgStart); - M.m_pMessage = msg; Server()->SendPackMsg(&M, MSGFLAG_VITAL, recipient); // tidy up free(msg); @@ -1350,6 +1354,43 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) pPlayer->m_LastEmote = Server()->Tick(); SendEmoticon(ClientID, pMsg->m_Emoticon); + CCharacter* pChr = pPlayer->GetCharacter(); + if(pChr) + { + switch(pMsg->m_Emoticon) + { + case EMOTICON_EXCLAMATION: + case EMOTICON_GHOST: + case EMOTICON_QUESTION: + case EMOTICON_WTF: + pChr->SetEmoteType(EMOTE_SURPRISE); + break; + case EMOTICON_DOTDOT: + case EMOTICON_DROP: + case EMOTICON_ZZZ: + pChr->SetEmoteType(EMOTE_BLINK); + break; + case EMOTICON_EYES: + case EMOTICON_HEARTS: + case EMOTICON_MUSIC: + pChr->SetEmoteType(EMOTE_HAPPY); + break; + case EMOTICON_OOP: + case EMOTICON_SORRY: + case EMOTICON_SUSHI: + pChr->SetEmoteType(EMOTE_PAIN); + break; + case EMOTICON_DEVILTEE: + case EMOTICON_SPLATTEE: + case EMOTICON_ZOMG: + pChr->SetEmoteType(EMOTE_ANGRY); + break; + default: + pChr->SetEmoteType(EMOTE_NORMAL); + break; + } + pChr->SetEmoteStop(Server()->Tick() + 2 * Server()->TickSpeed()); + } } else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused) { diff --git a/src/game/server/gamemodes/zcatch.cpp b/src/game/server/gamemodes/zcatch.cpp index 63ed3dfb..cd36d12f 100644 --- a/src/game/server/gamemodes/zcatch.cpp +++ b/src/game/server/gamemodes/zcatch.cpp @@ -2,7 +2,7 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ /* zCatch by erd and Teetime */ /* Modified by Teelevision for zCatch/TeeVi, see readme.txt and license.txt. */ - +#include #include #include #include @@ -122,13 +122,77 @@ int CGameController_zCatch::OnCharacterDeath(class CCharacter *pVictim, class CP void CGameController_zCatch::OnPlayerInfoChange(class CPlayer *pP) { - if(g_Config.m_SvColorIndicator && pP->m_zCatchNumKillsInARow <= 20) - { - int Num = max(0, 160 - pP->m_zCatchNumKillsInARow * 10); - pP->m_TeeInfos.m_ColorBody = Num * 0x010000 + 0xff00; - pP->m_TeeInfos.m_ColorFeet = pP->m_zCatchNumKillsInARow == 20 ? 0x40ff00 : pP->m_TeeInfos.m_ColorBody; - pP->m_TeeInfos.m_UseCustomColor = 1; - } + if(g_Config.m_SvColorIndicator) + { + switch(pP->m_zCatchNumKillsInARow){ + case 0: + pP->m_TeeInfos.m_ColorBody = 0xFFBB00; + pP->m_TeeInfos.m_ColorFeet = 0x11FF00; + break; + case 15: + pP->m_TeeInfos.m_ColorBody = 0xEEFF00; + break; + case 14: + pP->m_TeeInfos.m_ColorBody = 0xDDFF00; + break; + case 13: + pP->m_TeeInfos.m_ColorBody = 0xCCFF00; + break; + case 12: + pP->m_TeeInfos.m_ColorBody = 0xBBFF00; + break; + case 11: + pP->m_TeeInfos.m_ColorBody = 0xAAFF00; + break; + case 10: + pP->m_TeeInfos.m_ColorBody = 0x99FF00; + break; + case 9: + pP->m_TeeInfos.m_ColorBody = 0x88FF00; + break; + case 8: + pP->m_TeeInfos.m_ColorBody = 0x77FF00; + break; + case 7: + pP->m_TeeInfos.m_ColorBody = 0x66FF00; + break; + case 6: + pP->m_TeeInfos.m_ColorBody = 0x55FF00; + break; + case 5: + pP->m_TeeInfos.m_ColorBody = 0x44FF00; + break; + case 4: + pP->m_TeeInfos.m_ColorBody = 0x33FF00; + break; + case 3: + pP->m_TeeInfos.m_ColorBody = 0x22FF00; + break; + case 2: + pP->m_TeeInfos.m_ColorBody = 0x11FF00; + break; + case 1: + pP->m_TeeInfos.m_ColorBody = 0x00FF00; + break; + default: + pP->m_TeeInfos.m_ColorBody = 0x000000; + break; + } + pP->m_TeeInfos.m_ColorFeet = 0x11FF00 + pP->m_TeeInfos.m_ColorFeet; + pP->m_TeeInfos.m_UseCustomColor = 1; + } +// if(g_Config.m_SvColorIndicator){ +// if(pP->m_zCatchNumKillsInARow > 1 || pP->m_zCatchNumKillsInARow < 16) +// { +// pP->m_TeeInfos.m_ColorBody = 0x11FF00 + pP->m_TeeInfos.m_ColorBody; +// } +// else +// { +// pP->m_TeeInfos.m_ColorBody = 0x11FF00; +// } +// pP->m_TeeInfos.m_ColorFeet = pP->m_TeeInfos.m_ColorBody; +// pP->m_TeeInfos.m_UseCustomColor = 1; +// } } void CGameController_zCatch::StartRound() diff --git a/src/game/server/player.h b/src/game/server/player.h index 97fb299c..7189d7e2 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -113,6 +113,8 @@ public: int m_CampTick; vec2 m_CampPos; + int m_RespawnProtection; + // zCatch/TeeVi enum { -- cgit 1.4.1