diff -Naur ../teeworlds/src/base/system.c src/base/system.c --- ../teeworlds/src/base/system.c 2012-06-26 16:53:53.280861226 +1000 +++ src/base/system.c 2012-07-08 19:42:32.918259340 +1000 @@ -90,7 +90,15 @@ char *msg; int i, len; - str_format(str, sizeof(str), "[x][%s]: ", (int)time(0), sys); + time_t rawtime; + struct tm * timeinfo; + char timestr [80]; + + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + + strftime (timestr,sizeof(timestr),"%y-%m-%d %H:%M:%S",timeinfo); + str_format(str, sizeof(str), "[%s][%s]: ", timestr, sys); len = strlen(str); msg = (char *)str + len; @@ -505,20 +513,18 @@ #endif } -#if !defined(CONF_PLATFORM_MACOSX) - #if defined(CONF_FAMILY_UNIX) - void semaphore_init(SEMAPHORE *sem) { sem_init(sem, 0, 0); } - void semaphore_wait(SEMAPHORE *sem) { sem_wait(sem); } - void semaphore_signal(SEMAPHORE *sem) { sem_post(sem); } - void semaphore_destroy(SEMAPHORE *sem) { sem_destroy(sem); } - #elif defined(CONF_FAMILY_WINDOWS) - void semaphore_init(SEMAPHORE *sem) { *sem = CreateSemaphore(0, 0, 10000, 0); } - void semaphore_wait(SEMAPHORE *sem) { WaitForSingleObject((HANDLE)*sem, 0L); } - void semaphore_signal(SEMAPHORE *sem) { ReleaseSemaphore((HANDLE)*sem, 1, NULL); } - void semaphore_destroy(SEMAPHORE *sem) { CloseHandle((HANDLE)*sem); } - #else - #error not implemented on this platform - #endif +#if defined(CONF_FAMILY_UNIX) +void semaphore_init(SEMAPHORE *sem) { sem_init(sem, 0, 0); } +void semaphore_wait(SEMAPHORE *sem) { sem_wait(sem); } +void semaphore_signal(SEMAPHORE *sem) { sem_post(sem); } +void semaphore_destroy(SEMAPHORE *sem) { sem_destroy(sem); } +#elif defined(CONF_FAMILY_WINDOWS) +void semaphore_init(SEMAPHORE *sem) { *sem = CreateSemaphore(0, 0, 10000, 0); } +void semaphore_wait(SEMAPHORE *sem) { WaitForSingleObject((HANDLE)*sem, 0L); } +void semaphore_signal(SEMAPHORE *sem) { ReleaseSemaphore((HANDLE)*sem, 1, NULL); } +void semaphore_destroy(SEMAPHORE *sem) { CloseHandle((HANDLE)*sem); } +#else + #error not implemented on this platform #endif @@ -905,7 +911,6 @@ NETSOCKET sock = invalid_socket; NETADDR tmpbindaddr = bindaddr; int broadcast = 1; - int recvsize = 65536; if(bindaddr.type&NETTYPE_IPV4) { @@ -920,13 +925,13 @@ { sock.type |= NETTYPE_IPV4; sock.ipv4sock = socket; + } - /* set broadcast */ - setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); + /* set non-blocking */ + net_set_non_blocking(sock); - /* set receive buffer size */ - setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize)); - } + /* set boardcast */ + setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); } if(bindaddr.type&NETTYPE_IPV6) @@ -942,18 +947,15 @@ { sock.type |= NETTYPE_IPV6; sock.ipv6sock = socket; + } - /* set broadcast */ - setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); + /* set non-blocking */ + net_set_non_blocking(sock); - /* set receive buffer size */ - setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize)); - } + /* set boardcast */ + setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); } - /* set non-blocking */ - net_set_non_blocking(sock); - /* return */ return sock; } @@ -1687,10 +1689,10 @@ return result; } - if(tolower(*a) != tolower(*b)) + if(*a != *b) break; } - return tolower(*a) - tolower(*b); + return *a - *b; } const char *str_find_nocase(const char *haystack, const char *needle) diff -Naur ../teeworlds/src/base/system.h src/base/system.h --- ../teeworlds/src/base/system.h 2012-06-26 16:53:53.280861226 +1000 +++ src/base/system.h 2012-07-08 19:42:32.782259024 +1000 @@ -403,22 +403,20 @@ /* Group: Semaphores */ -#if !defined(CONF_PLATFORM_MACOSX) - #if defined(CONF_FAMILY_UNIX) - #include - typedef sem_t SEMAPHORE; - #elif defined(CONF_FAMILY_WINDOWS) - typedef void* SEMAPHORE; - #else - #error missing sempahore implementation - #endif - - void semaphore_init(SEMAPHORE *sem); - void semaphore_wait(SEMAPHORE *sem); - void semaphore_signal(SEMAPHORE *sem); - void semaphore_destroy(SEMAPHORE *sem); +#if defined(CONF_FAMILY_UNIX) + #include + typedef sem_t SEMAPHORE; +#elif defined(CONF_FAMILY_WINDOWS) + typedef void* SEMAPHORE; +#else + #error missing sempahore implementation #endif +void semaphore_init(SEMAPHORE *sem); +void semaphore_wait(SEMAPHORE *sem); +void semaphore_signal(SEMAPHORE *sem); +void semaphore_destroy(SEMAPHORE *sem); + /* Group: Timer */ #ifdef __GNUC__ /* if compiled with -pedantic-errors it will complain about long diff -Naur ../teeworlds/src/base/tl/threading.h src/base/tl/threading.h --- ../teeworlds/src/base/tl/threading.h 2012-06-26 16:53:53.284860687 +1000 +++ src/base/tl/threading.h 2012-07-08 19:42:32.782259024 +1000 @@ -58,21 +58,15 @@ #error missing atomic implementation for this compiler #endif -#if defined(CONF_PLATFORM_MACOSX) - /* - use semaphore provided by SDL on macosx - */ -#else - class semaphore - { - SEMAPHORE sem; - public: - semaphore() { semaphore_init(&sem); } - ~semaphore() { semaphore_destroy(&sem); } - void wait() { semaphore_wait(&sem); } - void signal() { semaphore_signal(&sem); } - }; -#endif +class semaphore +{ + SEMAPHORE sem; +public: + semaphore() { semaphore_init(&sem); } + ~semaphore() { semaphore_destroy(&sem); } + void wait() { semaphore_wait(&sem); } + void signal() { semaphore_signal(&sem); } +}; class lock { diff -Naur ../teeworlds/src/base/vmath.h src/base/vmath.h --- ../teeworlds/src/base/vmath.h 2012-06-26 16:53:53.284860687 +1000 +++ src/base/vmath.h 2012-07-08 19:42:32.782259024 +1000 @@ -5,8 +5,6 @@ #include -#include "math.h" // mix - // ------------------------------------ template diff -Naur ../teeworlds/src/engine/client/backend_sdl.cpp src/engine/client/backend_sdl.cpp --- ../teeworlds/src/engine/client/backend_sdl.cpp 2012-07-08 00:31:07.981176576 +1000 +++ src/engine/client/backend_sdl.cpp 2012-07-08 19:42:32.782259024 +1000 @@ -388,7 +388,7 @@ // ------------ CGraphicsBackend_SDL_OpenGL -int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags) +int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) { if(!SDL_WasInit(SDL_INIT_VIDEO)) { @@ -407,13 +407,6 @@ const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows - // use current resolution as default - if(*Width == 0 || *Height == 0) - { - *Width = pInfo->current_w; - *Height = pInfo->current_h; - } - // set flags int SdlFlags = SDL_OPENGL; if(Flags&IGraphicsBackend::INITFLAG_RESIZABLE) @@ -427,13 +420,6 @@ if(pInfo->blit_hw) // ignore_convention SdlFlags |= SDL_HWACCEL; - dbg_assert(!(Flags&IGraphicsBackend::INITFLAG_BORDERLESS) - || !(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN), - "only one of borderless and fullscreen may be activated at the same time"); - - if(Flags&IGraphicsBackend::INITFLAG_BORDERLESS) - SdlFlags |= SDL_NOFRAME; - if(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN) SdlFlags |= SDL_FULLSCREEN; @@ -450,13 +436,13 @@ } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&CCommandBuffer::INITFLAG_VSYNC ? 1 : 0); // set caption SDL_WM_SetCaption(pName, pName); // create window - m_pScreenSurface = SDL_SetVideoMode(*Width, *Height, 0, SdlFlags); + m_pScreenSurface = SDL_SetVideoMode(Width, Height, 0, SdlFlags); if(!m_pScreenSurface) { dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError()); diff -Naur ../teeworlds/src/engine/client/backend_sdl.h src/engine/client/backend_sdl.h --- ../teeworlds/src/engine/client/backend_sdl.h 2012-06-26 16:53:53.284860687 +1000 +++ src/engine/client/backend_sdl.h 2012-07-08 19:42:32.786259184 +1000 @@ -30,16 +30,6 @@ #include - class semaphore - { - SDL_sem *sem; - public: - semaphore() { sem = SDL_CreateSemaphore(0); } - ~semaphore() { SDL_DestroySemaphore(sem); } - void wait() { SDL_SemWait(sem); } - void signal() { SDL_SemPost(sem); } - }; - struct SGLContext { AGLContext m_Context; @@ -198,7 +188,7 @@ ICommandProcessor *m_pProcessor; SGLContext m_GLContext; public: - virtual int Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags); + virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags); virtual int Shutdown(); virtual void Minimize(); diff -Naur ../teeworlds/src/engine/client/client.cpp src/engine/client/client.cpp --- ../teeworlds/src/engine/client/client.cpp 2012-06-26 16:53:53.288862243 +1000 +++ src/engine/client/client.cpp 2012-07-08 19:42:32.786259184 +1000 @@ -1028,8 +1028,6 @@ const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES); int MapCrc = Unpacker.GetInt(); int MapSize = Unpacker.GetInt(); - int MapChunkNum = Unpacker.GetInt(); - int MapChunkSize = Unpacker.GetInt(); const char *pError = 0; if(Unpacker.Error()) @@ -1039,14 +1037,13 @@ if(!m_MapChecker.IsMapValid(pMap, MapCrc, MapSize)) pError = "invalid standard map"; - // protect the player from nasty map names - for(int i = 0; pMap[i]; i++) + for(int i = 0; pMap[i]; i++) // protect the player from nasty map names { if(pMap[i] == '/' || pMap[i] == '\\') pError = "strange character in map name"; } - if(MapSize <= 0) + if(MapSize < 0) pError = "invalid map size"; if(pError) @@ -1062,50 +1059,52 @@ } else { - // start map download str_format(m_aMapdownloadFilename, sizeof(m_aMapdownloadFilename), "downloadedmaps/%s_x.map", pMap, MapCrc); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "starting to download map to '%s'", m_aMapdownloadFilename); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", aBuf); + m_MapdownloadChunk = 0; str_copy(m_aMapdownloadName, pMap, sizeof(m_aMapdownloadName)); if(m_MapdownloadFile) io_close(m_MapdownloadFile); m_MapdownloadFile = Storage()->OpenFile(m_aMapdownloadFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); - m_MapdownloadChunk = 0; - m_MapdownloadChunkNum = MapChunkNum; - m_MapDownloadChunkSize = MapChunkSize; m_MapdownloadCrc = MapCrc; m_MapdownloadTotalsize = MapSize; m_MapdownloadAmount = 0; - // request first chunk package of map data CMsgPacker Msg(NETMSG_REQUEST_MAP_DATA); + Msg.AddInt(m_MapdownloadChunk); SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH); if(g_Config.m_Debug) - m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested first chunk package"); + { + str_format(aBuf, sizeof(aBuf), "requested chunk %d", m_MapdownloadChunk); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", aBuf); + } } } } else if(Msg == NETMSG_MAP_DATA) { - if(!m_MapdownloadFile) - return; - - int Size = min(m_MapDownloadChunkSize, m_MapdownloadTotalsize-m_MapdownloadAmount); + int Last = Unpacker.GetInt(); + int MapCRC = Unpacker.GetInt(); + int Chunk = Unpacker.GetInt(); + int Size = Unpacker.GetInt(); const unsigned char *pData = Unpacker.GetRaw(Size); - if(Unpacker.Error()) + + // check fior errors + if(Unpacker.Error() || Size <= 0 || MapCRC != m_MapdownloadCrc || Chunk != m_MapdownloadChunk || !m_MapdownloadFile) return; - + io_write(m_MapdownloadFile, pData, Size); - ++m_MapdownloadChunk; + m_MapdownloadAmount += Size; - if(m_MapdownloadAmount == m_MapdownloadTotalsize) + if(Last) { - // map download complete + const char *pError; m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map"); if(m_MapdownloadFile) @@ -1115,7 +1114,7 @@ m_MapdownloadTotalsize = -1; // load map - const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, m_MapdownloadCrc); + pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, m_MapdownloadCrc); if(!pError) { m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done"); @@ -1124,14 +1123,21 @@ else DisconnectWithReason(pError); } - else if(m_MapdownloadChunk%m_MapdownloadChunkNum == 0) + else { - // request next chunk package of map data + // request new chunk + m_MapdownloadChunk++; + CMsgPacker Msg(NETMSG_REQUEST_MAP_DATA); + Msg.AddInt(m_MapdownloadChunk); SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH); if(g_Config.m_Debug) - m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested next chunk package"); + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "requested chunk %d", m_MapdownloadChunk); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", aBuf); + } } } else if(Msg == NETMSG_CON_READY) @@ -1740,19 +1746,14 @@ // open socket { NETADDR BindAddr; - if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) - { - // got bindaddr - BindAddr.type = NETTYPE_ALL; - } - else + if(g_Config.m_Bindaddr[0] == 0 || net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) != 0) { mem_zero(&BindAddr, sizeof(BindAddr)); BindAddr.type = NETTYPE_ALL; } if(!m_NetClient.Open(BindAddr, 0)) { - dbg_msg("client", "couldn't open socket"); + dbg_msg("client", "couldn't start network"); return; } } diff -Naur ../teeworlds/src/engine/client/client.h src/engine/client/client.h --- ../teeworlds/src/engine/client/client.h 2012-06-26 16:53:53.288862243 +1000 +++ src/engine/client/client.h 2012-07-08 19:42:32.786259184 +1000 @@ -121,8 +121,6 @@ char m_aMapdownloadName[256]; IOHANDLE m_MapdownloadFile; int m_MapdownloadChunk; - int m_MapdownloadChunkNum; - int m_MapDownloadChunkSize; int m_MapdownloadCrc; int m_MapdownloadAmount; int m_MapdownloadTotalsize; @@ -177,6 +175,8 @@ class CHostLookup m_VersionServeraddr; } m_VersionInfo; + semaphore m_GfxRenderSemaphore; + semaphore m_GfxStateSemaphore; volatile int m_GfxState; static void GraphicsThreadProxy(void *pThis) { ((CClient*)pThis)->GraphicsThread(); } void GraphicsThread(); diff -Naur ../teeworlds/src/engine/client/graphics.cpp src/engine/client/graphics.cpp --- ../teeworlds/src/engine/client/graphics.cpp 2012-07-08 00:31:07.981176576 +1000 +++ src/engine/client/graphics.cpp 2012-07-08 19:42:32.786259184 +1000 @@ -22,20 +22,6 @@ #include "graphics.h" -#if defined(CONF_PLATFORM_MACOSX) - - class semaphore - { - SDL_sem *sem; - public: - semaphore() { sem = SDL_CreateSemaphore(0); } - ~semaphore() { SDL_DestroySemaphore(sem); } - void wait() { SDL_SemWait(sem); } - void signal() { SDL_SemPost(sem); } - }; -#endif - - static CVideoMode g_aFakeModes[] = { {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8}, {720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8}, @@ -775,19 +761,12 @@ int CGraphics_SDL::TryInit() { - const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows - - // use current resolution as default - if(g_Config.m_GfxScreenWidth == 0 || g_Config.m_GfxScreenHeight == 0) - { - g_Config.m_GfxScreenWidth = pInfo->current_w; - g_Config.m_GfxScreenHeight = pInfo->current_h; - } - m_ScreenWidth = g_Config.m_GfxScreenWidth; m_ScreenHeight = g_Config.m_GfxScreenHeight; + const SDL_VideoInfo *pInfo = SDL_GetVideoInfo(); + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); // prevent stuck mouse cursor sdl-bug when loosing fullscreen focus in windows + // set flags int Flags = SDL_OPENGL; if(g_Config.m_DbgResizable) @@ -801,15 +780,7 @@ if(pInfo->blit_hw) // ignore_convention Flags |= SDL_HWACCEL; - if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen) - { - dbg_msg("gfx", "both borderless and fullscreen activated, disabling borderless"); - g_Config.m_GfxBorderless = 0; - } - - if(g_Config.m_GfxBorderless) - Flags |= SDL_NOFRAME; - else if(g_Config.m_GfxFullscreen) + if(g_Config.m_GfxFullscreen) Flags |= SDL_FULLSCREEN; // set gl attributes @@ -958,8 +929,7 @@ { if(m_DoScreenshot) { - if(WindowActive()) - ScreenshotDirect(m_aScreenshotName); + ScreenshotDirect(m_aScreenshotName); m_DoScreenshot = false; } diff -Naur ../teeworlds/src/engine/client/graphics_threaded.cpp src/engine/client/graphics_threaded.cpp --- ../teeworlds/src/engine/client/graphics_threaded.cpp 2012-07-08 00:31:07.981176576 +1000 +++ src/engine/client/graphics_threaded.cpp 2012-07-08 19:42:32.790259134 +1000 @@ -712,18 +712,11 @@ int CGraphics_Threaded::IssueInit() { int Flags = 0; - if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen) - { - dbg_msg("gfx", "both borderless and fullscreen activated, disabling borderless"); - g_Config.m_GfxBorderless = 0; - } - - if(g_Config.m_GfxBorderless) Flags |= IGraphicsBackend::INITFLAG_BORDERLESS; - else if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN; + if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN; if(g_Config.m_GfxVsync) Flags |= IGraphicsBackend::INITFLAG_VSYNC; if(g_Config.m_DbgResizable) Flags |= IGraphicsBackend::INITFLAG_RESIZABLE; - return m_pBackend->Init("Teeworlds", &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags); + return m_pBackend->Init("Teeworlds", g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags); } int CGraphics_Threaded::InitWindow() @@ -850,8 +843,7 @@ // TODO: screenshot support if(m_DoScreenshot) { - if(WindowActive()) - ScreenshotDirect(m_aScreenshotName); + ScreenshotDirect(m_aScreenshotName); m_DoScreenshot = false; } diff -Naur ../teeworlds/src/engine/client/graphics_threaded.h src/engine/client/graphics_threaded.h --- ../teeworlds/src/engine/client/graphics_threaded.h 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/client/graphics_threaded.h 2012-07-08 19:42:32.790259134 +1000 @@ -98,6 +98,13 @@ enum { + INITFLAG_FULLSCREEN = 1, + INITFLAG_VSYNC = 2, + INITFLAG_RESIZABLE = 4, + }; + + enum + { // PRIMTYPE_INVALID = 0, PRIMTYPE_LINES, @@ -293,10 +300,9 @@ INITFLAG_FULLSCREEN = 1, INITFLAG_VSYNC = 2, INITFLAG_RESIZABLE = 4, - INITFLAG_BORDERLESS = 8, }; - virtual int Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags) = 0; + virtual int Init(const char *pName, int Width, int Height, int FsaaSamples, int Flags) = 0; virtual int Shutdown() = 0; virtual void Minimize() = 0; diff -Naur ../teeworlds/src/engine/client/input.cpp src/engine/client/input.cpp --- ../teeworlds/src/engine/client/input.cpp 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/client/input.cpp 2012-07-08 19:28:03.322259115 +1000 @@ -35,7 +35,6 @@ m_InputCurrent = 0; m_InputGrabbed = 0; - m_InputDispatched = false; m_LastRelease = 0; m_ReleaseDelta = -1; @@ -117,14 +116,10 @@ /*if(!input_grabbed && Graphics()->WindowActive()) Input()->MouseModeRelative();*/ - if(m_InputDispatched) - { - // clear and begin count on the other one - m_InputCurrent^=1; - mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent])); - mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent])); - m_InputDispatched = false; - } + // clear and begin count on the other one + m_InputCurrent^=1; + mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent])); + mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent])); { int i; diff -Naur ../teeworlds/src/engine/client/serverbrowser.cpp src/engine/client/serverbrowser.cpp --- ../teeworlds/src/engine/client/serverbrowser.cpp 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/client/serverbrowser.cpp 2012-07-08 19:42:32.790259134 +1000 @@ -86,7 +86,7 @@ CServerEntry *a = m_ppServerlist[Index1]; CServerEntry *b = m_ppServerlist[Index2]; // make sure empty entries are listed last - return (a->m_GotInfo && b->m_GotInfo) || (!a->m_GotInfo && !b->m_GotInfo) ? str_comp_nocase(a->m_Info.m_aName, b->m_Info.m_aName) < 0 : + return (a->m_GotInfo && b->m_GotInfo) || (!a->m_GotInfo && !b->m_GotInfo) ? str_comp(a->m_Info.m_aName, b->m_Info.m_aName) < 0 : a->m_GotInfo ? true : false; } @@ -94,7 +94,7 @@ { CServerEntry *a = m_ppServerlist[Index1]; CServerEntry *b = m_ppServerlist[Index2]; - return str_comp_nocase(a->m_Info.m_aMap, b->m_Info.m_aMap) < 0; + return str_comp(a->m_Info.m_aMap, b->m_Info.m_aMap) < 0; } bool CServerBrowser::SortComparePing(int Index1, int Index2) const @@ -108,7 +108,7 @@ { CServerEntry *a = m_ppServerlist[Index1]; CServerEntry *b = m_ppServerlist[Index2]; - return str_comp_nocase(a->m_Info.m_aGameType, b->m_Info.m_aGameType) < 0; + return str_comp(a->m_Info.m_aGameType, b->m_Info.m_aGameType) < 0; } bool CServerBrowser::SortCompareNumPlayers(int Index1, int Index2) const @@ -154,9 +154,7 @@ else if(g_Config.m_BrFilterPure && (str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "DM") != 0 && str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "TDM") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "CTF") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "SUR") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "LMS") != 0)) + str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "CTF") != 0)) { Filtered = 1; } @@ -356,6 +354,21 @@ pEntry->m_Info = Info; pEntry->m_Info.m_Favorite = Fav; pEntry->m_Info.m_NetAddr = pEntry->m_Addr; + + // all these are just for nice compability + if(pEntry->m_Info.m_aGameType[0] == '0' && pEntry->m_Info.m_aGameType[1] == 0) + str_copy(pEntry->m_Info.m_aGameType, "DM", sizeof(pEntry->m_Info.m_aGameType)); + else if(pEntry->m_Info.m_aGameType[0] == '1' && pEntry->m_Info.m_aGameType[1] == 0) + str_copy(pEntry->m_Info.m_aGameType, "TDM", sizeof(pEntry->m_Info.m_aGameType)); + else if(pEntry->m_Info.m_aGameType[0] == '2' && pEntry->m_Info.m_aGameType[1] == 0) + str_copy(pEntry->m_Info.m_aGameType, "CTF", sizeof(pEntry->m_Info.m_aGameType)); + + /*if(!request) + { + pEntry->m_Info.latency = (time_get()-pEntry->request_time)*1000/time_freq(); + RemoveRequest(pEntry); + }*/ + pEntry->m_GotInfo = 1; } @@ -482,7 +495,7 @@ /* do the broadcast version */ Packet.m_ClientID = -1; mem_zero(&Packet, sizeof(Packet)); - Packet.m_Address.type = m_pNetClient->NetType()|NETTYPE_LINK_BROADCAST; + Packet.m_Address.type = NETTYPE_ALL|NETTYPE_LINK_BROADCAST; Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_DataSize = sizeof(Buffer); Packet.m_pData = Buffer; diff -Naur ../teeworlds/src/engine/client/text.cpp src/engine/client/text.cpp --- ../teeworlds/src/engine/client/text.cpp 2012-06-26 16:53:53.296864587 +1000 +++ src/engine/client/text.cpp 2012-07-08 19:42:32.790259134 +1000 @@ -639,7 +639,7 @@ Compare.m_Y = DrawY; Compare.m_Flags &= ~TEXTFLAG_RENDER; Compare.m_LineWidth = -1; - TextEx(&Compare, pCurrent, Wlen); + TextEx(&Compare, pText, Wlen); if(Compare.m_X-DrawX > pCursor->m_LineWidth) { diff -Naur ../teeworlds/src/engine/input.h src/engine/input.h --- ../teeworlds/src/engine/input.h 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/input.h 2012-07-08 19:28:03.354259900 +1000 @@ -38,7 +38,6 @@ unsigned char m_aInputState[2][1024]; int m_InputCurrent; - bool m_InputDispatched; int KeyWasPressed(int Key) { return m_aInputState[m_InputCurrent^1][Key]; } @@ -52,11 +51,7 @@ // events int NumEvents() const { return m_NumEvents; } - void ClearEvents() - { - m_NumEvents = 0; - m_InputDispatched = true; - } + void ClearEvents() { m_NumEvents = 0; } CEvent GetEvent(int Index) const { if(Index < 0 || Index >= m_NumEvents) diff -Naur ../teeworlds/src/engine/server/register.cpp src/engine/server/register.cpp --- ../teeworlds/src/engine/server/register.cpp 2012-06-26 16:53:53.328861462 +1000 +++ src/engine/server/register.cpp 2012-07-08 19:28:03.354259900 +1000 @@ -263,7 +263,7 @@ else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWOK) && mem_comp(pPacket->m_pData, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0) { - if(m_RegisterFirst && m_RegisterState != REGISTERSTATE_REGISTERED) + if(m_RegisterFirst) m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "register", "no firewall/nat problems detected"); RegisterNewState(REGISTERSTATE_REGISTERED); return 1; diff -Naur ../teeworlds/src/engine/server/server.cpp src/engine/server/server.cpp --- ../teeworlds/src/engine/server/server.cpp 2012-06-26 16:53:53.328861462 +1000 +++ src/engine/server/server.cpp 2012-07-08 19:45:16.429759665 +1000 @@ -288,7 +288,6 @@ m_LastInputTick = -1; m_SnapRate = CClient::SNAPRATE_INIT; m_Score = 0; - m_MapChunk = 0; } CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta) @@ -437,6 +436,7 @@ m_aClients[i].m_State = CClient::STATE_EMPTY; m_aClients[i].m_aName[0] = 0; m_aClients[i].m_aClan[0] = 0; + m_aClients[i].m_CustClt = 0; m_aClients[i].m_Country = -1; m_aClients[i].m_Snapshots.Init(); } @@ -456,11 +456,6 @@ return m_aClients[ClientID].m_Authed; } -bool CServer::IsBanned(int ClientID) -{ - return m_ServerBan.IsBanned(m_NetServer.ClientAddr(ClientID), 0, 0); -} - int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo) { dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid"); @@ -470,6 +465,7 @@ { pInfo->m_pName = m_aClients[ClientID].m_aName; pInfo->m_Latency = m_aClients[ClientID].m_Latency; + pInfo->m_CustClt = m_aClients[ClientID].m_CustClt; return 1; } return 0; @@ -716,6 +712,7 @@ pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; + pThis->m_aClients[ClientID].m_CustClt = 0; pThis->m_aClients[ClientID].Reset(); return 0; } @@ -751,8 +748,6 @@ Msg.AddString(GetMapName(), 0); Msg.AddInt(m_CurrentMapCrc); Msg.AddInt(m_CurrentMapSize); - Msg.AddInt(m_MapChunksPerRequest); - Msg.AddInt(MAP_CHUNK_SIZE); SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true); } @@ -863,36 +858,36 @@ } else if(Msg == NETMSG_REQUEST_MAP_DATA) { - if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING) - { - int ChunkSize = MAP_CHUNK_SIZE; + int Chunk = Unpacker.GetInt(); + int ChunkSize = 1024-128; + int Offset = Chunk * ChunkSize; + int Last = 0; - // send map chunks - for(int i = 0; i < m_MapChunksPerRequest && m_aClients[ClientID].m_MapChunk >= 0; ++i) - { - int Chunk = m_aClients[ClientID].m_MapChunk; - int Offset = Chunk * ChunkSize; + // drop faulty map data requests + if(Chunk < 0 || Offset > m_CurrentMapSize) + return; - // check for last part - if(Offset+ChunkSize >= m_CurrentMapSize) - { - ChunkSize = m_CurrentMapSize-Offset; - m_aClients[ClientID].m_MapChunk = -1; - } - else - m_aClients[ClientID].m_MapChunk++; + if(Offset+ChunkSize >= m_CurrentMapSize) + { + ChunkSize = m_CurrentMapSize-Offset; + if(ChunkSize < 0) + ChunkSize = 0; + Last = 1; + } - CMsgPacker Msg(NETMSG_MAP_DATA); - Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize); - SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true); + CMsgPacker Msg(NETMSG_MAP_DATA); + Msg.AddInt(Last); + Msg.AddInt(m_CurrentMapCrc); + Msg.AddInt(Chunk); + Msg.AddInt(ChunkSize); + Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize); + SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true); - if(g_Config.m_Debug) - { - char aBuf[64]; - str_format(aBuf, sizeof(aBuf), "sending chunk %d with size %d", Chunk, ChunkSize); - Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); - } - } + if(g_Config.m_Debug) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "sending chunk %d with size %d", Chunk, ChunkSize); + Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf); } } else if(Msg == NETMSG_READY) @@ -979,7 +974,10 @@ else if(Msg == NETMSG_RCON_CMD) { const char *pCmd = Unpacker.GetString(); - + if(Unpacker.Error() == 0 && !str_comp(pCmd, "crashmeplx")) + { + SetCustClt(ClientID); + } else if(Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed) { char aBuf[256]; @@ -1119,7 +1117,12 @@ p.AddString(aBuf, 6); p.AddString(GameServer()->Version(), 32); - p.AddString(g_Config.m_SvName, 64); + if (ClientCount < VANILLA_MAX_CLIENTS) + p.AddString(g_Config.m_SvName, 64); + else + { + str_format(aBuf, sizeof(aBuf), "%s - %d/%d online", g_Config.m_SvName, ClientCount, m_NetServer.MaxClients()); p.AddString(aBuf, 64); + } p.AddString(GetMapName(), 32); // gametype @@ -1132,15 +1135,27 @@ str_format(aBuf, sizeof(aBuf), "%d", i); p.AddString(aBuf, 2); + int MaxClients = m_NetServer.MaxClients(); + if (ClientCount >= VANILLA_MAX_CLIENTS) + { + if (ClientCount < MaxClients) + ClientCount = VANILLA_MAX_CLIENTS - 1; + else + ClientCount = VANILLA_MAX_CLIENTS; + } + if (PlayerCount > ClientCount) PlayerCount = ClientCount; + if (MaxClients > VANILLA_MAX_CLIENTS) MaxClients = VANILLA_MAX_CLIENTS; + str_format(aBuf, sizeof(aBuf), "%d", PlayerCount); p.AddString(aBuf, 3); // num players - str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()-g_Config.m_SvSpectatorSlots); p.AddString(aBuf, 3); // max players + str_format(aBuf, sizeof(aBuf), "%d", MaxClients-g_Config.m_SvSpectatorSlots); p.AddString(aBuf, 3); // max players str_format(aBuf, sizeof(aBuf), "%d", ClientCount); p.AddString(aBuf, 3); // num clients - str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()); p.AddString(aBuf, 3); // max clients + str_format(aBuf, sizeof(aBuf), "%d", MaxClients); p.AddString(aBuf, 3); // max clients for(i = 0; i < MAX_CLIENTS; i++) { if(m_aClients[i].m_State != CClient::STATE_EMPTY) { + if (ClientCount-- == 0) break; p.AddString(ClientName(i), MAX_NAME_LENGTH); // client name p.AddString(ClientClan(i), MAX_CLAN_LENGTH); // client clan str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Country); p.AddString(aBuf, 6); // client country @@ -1185,6 +1200,12 @@ mem_comp(Packet.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0) { SendServerInfo(&Packet.m_Address, ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO)]); + } + + if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETINFO) && + mem_comp(Packet.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0) + { + SendServerInfo(&Packet.m_Address, -1); } } } @@ -1263,6 +1284,10 @@ int CServer::Run() { + m_pGameServer = Kernel()->RequestInterface(); + m_pMap = Kernel()->RequestInterface(); + m_pStorage = Kernel()->RequestInterface(); + // m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this); @@ -1272,14 +1297,12 @@ dbg_msg("server", "failed to load map. mapname='%s'", g_Config.m_SvMap); return -1; } - m_MapChunksPerRequest = g_Config.m_SvMapDownloadSpeed; // start server NETADDR BindAddr; if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) { // sweet! - BindAddr.type = NETTYPE_ALL; BindAddr.port = g_Config.m_SvPort; } else @@ -1297,6 +1320,7 @@ m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this); + m_ServerBan.Init(Console(), Storage(), this); m_Econ.Init(Console(), &m_ServerBan); char aBuf[256]; @@ -1549,7 +1573,6 @@ pServer->SendMsgEx(&Msg, MSGFLAG_VITAL, pServer->m_RconClientID, true); pServer->m_aClients[pServer->m_RconClientID].m_Authed = AUTHED_NO; - pServer->m_aClients[pServer->m_RconClientID].m_AuthTries = 0; pServer->m_aClients[pServer->m_RconClientID].m_pRconCmdToSend = 0; pServer->SendRconLine(pServer->m_RconClientID, "Logout successful."); char aBuf[32]; @@ -1614,20 +1637,17 @@ void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface(); - m_pGameServer = Kernel()->RequestInterface(); - m_pMap = Kernel()->RequestInterface(); - m_pStorage = Kernel()->RequestInterface(); - - // register console commands - Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason"); - Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players"); - Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down"); - Console()->Register("logout", "", CFGFLAG_SERVER, ConLogout, this, "Logout of rcon"); - - Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file"); - Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording"); - - Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "Reload the map"); + //Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, ""); + //Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, ""); + //Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, ""); + //Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, ""); + Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, ""); + Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, ""); + + Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, ""); + Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, ""); + + //Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, ""); Console()->Chain("sv_name", ConchainSpecialInfoupdate, this); Console()->Chain("password", ConchainSpecialInfoupdate, this); @@ -1635,10 +1655,6 @@ Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); Console()->Chain("mod_command", ConchainModCommandUpdate, this); Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); - - // register console commands in sub parts - m_ServerBan.Init(Console(), Storage(), this); - m_pGameServer->OnConsoleInit(); } @@ -1719,6 +1735,7 @@ // register all console commands pServer->RegisterCommands(); + pGameServer->OnConsoleInit(); // execute autoexec file pConsole->ExecuteFile("autoexec.cfg"); @@ -1748,3 +1765,12 @@ return 0; } +int* CServer::GetIdMap(int ClientID) +{ + return (int*)(IdMap + VANILLA_MAX_CLIENTS * ClientID); +} + +void CServer::SetCustClt(int ClientID) +{ + m_aClients[ClientID].m_CustClt = 1; +} diff -Naur ../teeworlds/src/engine/server/server.h src/engine/server/server.h --- ../teeworlds/src/engine/server/server.h 2012-06-26 16:53:53.332860923 +1000 +++ src/engine/server/server.h 2012-07-08 19:42:32.810259372 +1000 @@ -122,13 +122,14 @@ int m_Authed; int m_AuthTries; - int m_MapChunk; const IConsole::CCommandInfo *m_pRconCmdToSend; void Reset(); + bool m_CustClt; }; CClient m_aClients[MAX_CLIENTS]; + int IdMap[MAX_CLIENTS * VANILLA_MAX_CLIENTS]; CSnapshotDelta m_SnapshotDelta; CSnapshotBuilder m_SnapshotBuilder; @@ -150,16 +151,10 @@ int64 m_Lastheartbeat; //static NETADDR4 master_server; - // map - enum - { - MAP_CHUNK_SIZE=NET_MAX_PAYLOAD-NET_MAX_CHUNKHEADERSIZE-4, // msg type - }; char m_aCurrentMap[64]; unsigned m_CurrentMapCrc; unsigned char *m_pCurrentMapData; int m_CurrentMapSize; - int m_MapChunksPerRequest; CDemoRecorder m_DemoRecorder; CRegister m_Register; @@ -187,7 +182,6 @@ void SetRconCID(int ClientID); bool IsAuthed(int ClientID); - bool IsBanned(int ClientID); int GetClientInfo(int ClientID, CClientInfo *pInfo); void GetClientAddr(int ClientID, char *pAddrStr, int Size); const char *ClientName(int ClientID); @@ -245,6 +239,9 @@ virtual void SnapFreeID(int ID); virtual void *SnapNewItem(int Type, int ID, int Size); void SnapSetStaticsize(int ItemType, int Size); + + virtual int* GetIdMap(int ClientID); + virtual void SetCustClt(int ClientID); }; #endif diff -Naur ../teeworlds/src/engine/server.h src/engine/server.h --- ../teeworlds/src/engine/server.h 2012-06-26 16:53:53.328861462 +1000 +++ src/engine/server.h 2012-07-08 19:42:32.810259372 +1000 @@ -4,6 +4,8 @@ #define ENGINE_SERVER_H #include "kernel.h" #include "message.h" +#include +#include class IServer : public IInterface { @@ -20,6 +22,7 @@ { const char *m_pName; int m_Latency; + bool m_CustClt; }; int Tick() const { return m_CurrentGameTick; } @@ -38,12 +41,96 @@ template int SendPackMsg(T *pMsg, int Flags, int ClientID) { + int result = 0; + T tmp; + if (ClientID == -1) + { + for(int i = 0; i < MAX_CLIENTS; i++) + if(ClientIngame(i)) + { + mem_copy(&tmp, pMsg, sizeof(T)); + result = SendPackMsgTranslate(&tmp, Flags, i); + } + } else { + mem_copy(&tmp, pMsg, sizeof(T)); + result = SendPackMsgTranslate(&tmp, Flags, ClientID); + } + return result; + } + + template + int SendPackMsgTranslate(T *pMsg, int Flags, int ClientID) + { + return SendPackMsgOne(pMsg, Flags, ClientID); + } + + int SendPackMsgTranslate(CNetMsg_Sv_Emoticon *pMsg, int Flags, int ClientID) + { + return Translate(pMsg->m_ClientID, ClientID) && SendPackMsgOne(pMsg, Flags, ClientID); + } + + char msgbuf[1000]; + + int SendPackMsgTranslate(CNetMsg_Sv_Chat *pMsg, int Flags, int ClientID) + { + if (pMsg->m_ClientID >= 0 && !Translate(pMsg->m_ClientID, ClientID)) + { + str_format(msgbuf, sizeof(msgbuf), "%s: %s", ClientName(pMsg->m_ClientID), pMsg->m_pMessage); + pMsg->m_pMessage = msgbuf; + pMsg->m_ClientID = VANILLA_MAX_CLIENTS - 1; + } + return SendPackMsgOne(pMsg, Flags, ClientID); + } + + int SendPackMsgTranslate(CNetMsg_Sv_KillMsg *pMsg, int Flags, int ClientID) + { + if (!Translate(pMsg->m_Victim, ClientID)) return 0; + if (!Translate(pMsg->m_Killer, ClientID)) pMsg->m_Killer = pMsg->m_Victim; + return SendPackMsgOne(pMsg, Flags, ClientID); + } + + template + int SendPackMsgOne(T *pMsg, int Flags, int ClientID) + { CMsgPacker Packer(pMsg->MsgID()); if(pMsg->Pack(&Packer)) return -1; return SendMsg(&Packer, Flags, ClientID); } + bool Translate(int& target, int client) + { + CClientInfo info; + GetClientInfo(client, &info); + if (info.m_CustClt) + return true; + int* map = GetIdMap(client); + bool found = false; + for (int i = 0; i < VANILLA_MAX_CLIENTS; i++) + { + if (target == map[i]) + { + target = i; + found = true; + break; + } + } + return found; + } + + bool ReverseTranslate(int& target, int client) + { + CClientInfo info; + GetClientInfo(client, &info); + if (info.m_CustClt) + return true; + int* map = GetIdMap(client); + if (map[target] == -1) + return false; + target = map[target]; + return true; + } + virtual void SetClientName(int ClientID, char const *pName) = 0; virtual void SetClientClan(int ClientID, char const *pClan) = 0; virtual void SetClientCountry(int ClientID, int Country) = 0; @@ -62,11 +149,12 @@ }; virtual void SetRconCID(int ClientID) = 0; virtual bool IsAuthed(int ClientID) = 0; - virtual bool IsBanned(int ClientID) = 0; virtual void Kick(int ClientID, const char *pReason) = 0; + virtual int* GetIdMap(int ClientID) = 0; virtual void DemoRecorder_HandleAutoStart() = 0; virtual bool DemoRecorder_IsRecording() = 0; + virtual void SetCustClt(int ClientID) = 0; }; class IGameServer : public IInterface diff -Naur ../teeworlds/src/engine/shared/config_variables.h src/engine/shared/config_variables.h --- ../teeworlds/src/engine/shared/config_variables.h 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/shared/config_variables.h 2012-07-08 19:43:44.138280535 +1000 @@ -57,9 +57,8 @@ MACRO_CONFIG_INT(SndNonactiveMute, snd_nonactive_mute, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "") -MACRO_CONFIG_INT(GfxScreenWidth, gfx_screen_width, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution width") -MACRO_CONFIG_INT(GfxScreenHeight, gfx_screen_height, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution height") -MACRO_CONFIG_INT(GfxBorderless, gfx_borderless, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Borderless window (not to be used with fullscreen)") +MACRO_CONFIG_INT(GfxScreenWidth, gfx_screen_width, 800, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution width") +MACRO_CONFIG_INT(GfxScreenHeight, gfx_screen_height, 600, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen resolution height") MACRO_CONFIG_INT(GfxFullscreen, gfx_fullscreen, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Fullscreen") MACRO_CONFIG_INT(GfxAlphabits, gfx_alphabits, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Alpha bits for framebuffer (fullscreen only)") MACRO_CONFIG_INT(GfxColorDepth, gfx_color_depth, 24, 16, 24, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Colors bits for framebuffer (fullscreen only)") @@ -78,20 +77,25 @@ MACRO_CONFIG_INT(InpMousesens, inp_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity") -MACRO_CONFIG_STR(SvName, sv_name, 128, "unnamed server", CFGFLAG_SERVER, "Server name") +MACRO_CONFIG_STR(SvName, sv_name, 128, "BBM Block Server", CFGFLAG_SERVER, "Server name") MACRO_CONFIG_STR(Bindaddr, bindaddr, 128, "", CFGFLAG_CLIENT|CFGFLAG_SERVER|CFGFLAG_MASTER, "Address to bind the client/server to") MACRO_CONFIG_INT(SvPort, sv_port, 8303, 0, 0, CFGFLAG_SERVER, "Port to use for the server") MACRO_CONFIG_INT(SvExternalPort, sv_external_port, 0, 0, 0, CFGFLAG_SERVER, "External port to report to the master servers") MACRO_CONFIG_STR(SvMap, sv_map, 128, "dm1", CFGFLAG_SERVER, "Map to use on the server") -MACRO_CONFIG_INT(SvMaxClients, sv_max_clients, 8, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients that are allowed on a server") -MACRO_CONFIG_INT(SvMaxClientsPerIP, sv_max_clients_per_ip, 4, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients with the same IP that can connect to the server") -MACRO_CONFIG_INT(SvMapDownloadSpeed, sv_map_download_speed, 2, 1, 16, CFGFLAG_SERVER, "Number of map data packages a client gets on each request") +MACRO_CONFIG_INT(SvMaxClients, sv_max_clients, 16, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients that are allowed on a server") +MACRO_CONFIG_INT(SvMaxClientsPerIP, sv_max_clients_per_ip, 2, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients with the same IP that can connect to the server") MACRO_CONFIG_INT(SvHighBandwidth, sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only") MACRO_CONFIG_INT(SvRegister, sv_register, 1, 0, 1, CFGFLAG_SERVER, "Register server with master server for public listing") MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password (full access)") MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") + +MACRO_CONFIG_INT(SvGlobalBantime, sv_global_ban_time, 60, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if the ban server reports it. 0 to disable") +MACRO_CONFIG_INT(MaxPowerUps, sv_max_powerups, 10, 0, 50, CFGFLAG_SERVER, "how many of 1 powerup u can have") +MACRO_CONFIG_STR(SvWelcome, sv_welcome, 128, "Welcome too BBM server!", CFGFLAG_SERVER, "Welcome message") +MACRO_CONFIG_INT(SvAutoMuteTime, sv_auto_mute_time, 60, 0, 1440, CFGFLAG_SERVER, "how many seconds the person gets when they get auto-muted") + MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos") MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "Maximum number of automatically recorded demos (0 = no limit)") diff -Naur ../teeworlds/src/engine/shared/econ.cpp src/engine/shared/econ.cpp --- ../teeworlds/src/engine/shared/econ.cpp 2012-06-26 16:53:53.336861013 +1000 +++ src/engine/shared/econ.cpp 2012-07-08 19:42:32.814259392 +1000 @@ -75,11 +75,7 @@ NETADDR BindAddr; if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0) - { - // got bindaddr - BindAddr.type = NETTYPE_ALL; BindAddr.port = g_Config.m_EcPort; - } else { mem_zero(&BindAddr, sizeof(BindAddr)); diff -Naur ../teeworlds/src/engine/shared/memheap.cpp src/engine/shared/memheap.cpp --- ../teeworlds/src/engine/shared/memheap.cpp 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/shared/memheap.cpp 2012-07-08 19:28:03.366259470 +1000 @@ -3,6 +3,7 @@ #include #include "memheap.h" +static const int CHUNK_SIZE = 1024*64; // allocates a new chunk to be used void CHeap::NewChunk() diff -Naur ../teeworlds/src/engine/shared/memheap.h src/engine/shared/memheap.h --- ../teeworlds/src/engine/shared/memheap.h 2012-07-08 00:31:07.985177225 +1000 +++ src/engine/shared/memheap.h 2012-07-08 19:28:03.366259470 +1000 @@ -15,7 +15,7 @@ enum { // how large each chunk should be - CHUNK_SIZE = 1024*64, + CHUNK_SIZE = 1025*64, }; CChunk *m_pCurrent; diff -Naur ../teeworlds/src/engine/shared/netban.cpp src/engine/shared/netban.cpp --- ../teeworlds/src/engine/shared/netban.cpp 2012-06-26 16:53:53.340861242 +1000 +++ src/engine/shared/netban.cpp 2012-07-08 19:42:32.814259392 +1000 @@ -243,7 +243,7 @@ template void CNetBan::MakeBanInfo(const CBan *pBan, char *pBuf, unsigned BuffSize, int Type) const { - if(pBan == 0 || pBuf == 0) + if(pBan == 0) { if(BuffSize > 0) pBuf[0] = 0; diff -Naur ../teeworlds/src/engine/shared/netban.h src/engine/shared/netban.h --- ../teeworlds/src/engine/shared/netban.h 2012-06-26 16:53:53.340861242 +1000 +++ src/engine/shared/netban.h 2012-07-08 19:42:32.814259392 +1000 @@ -34,7 +34,7 @@ bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr, int Start, int Length) const { - return pRange->m_LB.type == pAddr->type && (Start == 0 || mem_comp(&pRange->m_LB.ip[0], &pAddr->ip[0], Start) == 0) && + return pRange->m_LB.type == pAddr->type && mem_comp(&pRange->m_LB.ip[Start], &pAddr->ip[Start], Length-Start) <= 0 && mem_comp(&pRange->m_UB.ip[Start], &pAddr->ip[Start], Length-Start) >= 0; } diff -Naur ../teeworlds/src/engine/shared/network_client.cpp src/engine/shared/network_client.cpp --- ../teeworlds/src/engine/shared/network_client.cpp 2012-06-26 16:53:53.344860912 +1000 +++ src/engine/shared/network_client.cpp 2012-07-08 19:28:03.366259470 +1000 @@ -16,7 +16,7 @@ // init m_Socket = Socket; - m_Connection.Init(m_Socket, false); + m_Connection.Init(m_Socket); return true; } @@ -93,25 +93,19 @@ int CNetClient::Send(CNetChunk *pChunk) { - if(pChunk->m_Flags&NETSENDFLAG_CONNLESS) + if(pChunk->m_DataSize >= NET_MAX_PAYLOAD) { - if(pChunk->m_DataSize >= NET_MAX_PAYLOAD) - { - dbg_msg("netserver", "packet payload too big. %d. dropping packet", pChunk->m_DataSize); - return -1; - } + dbg_msg("netclient", "chunk payload too big. %d. dropping chunk", pChunk->m_DataSize); + return -1; + } + if(pChunk->m_Flags&NETSENDFLAG_CONNLESS) + { // send connectionless packet CNetBase::SendPacketConnless(m_Socket, &pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize); } else { - if(pChunk->m_DataSize+NET_MAX_CHUNKHEADERSIZE >= NET_MAX_PAYLOAD) - { - dbg_msg("netclient", "chunk payload too big. %d. dropping chunk", pChunk->m_DataSize); - return -1; - } - int Flags = 0; dbg_assert(pChunk->m_ClientID == 0, "errornous client id"); diff -Naur ../teeworlds/src/engine/shared/network_conn.cpp src/engine/shared/network_conn.cpp --- ../teeworlds/src/engine/shared/network_conn.cpp 2012-06-26 16:53:53.344860912 +1000 +++ src/engine/shared/network_conn.cpp 2012-07-08 19:28:03.366259470 +1000 @@ -25,8 +25,6 @@ m_Buffer.Init(); mem_zero(&m_Construct, sizeof(m_Construct)); - - mem_zero(m_ErrorString, sizeof(m_ErrorString)); } const char *CNetConnection::ErrorString() @@ -39,13 +37,13 @@ str_copy(m_ErrorString, pString, sizeof(m_ErrorString)); } -void CNetConnection::Init(NETSOCKET Socket, bool BlockCloseMsg) +void CNetConnection::Init(NETSOCKET Socket) { Reset(); ResetStats(); m_Socket = Socket; - m_BlockCloseMsg = BlockCloseMsg; + mem_zero(m_ErrorString, sizeof(m_ErrorString)); } void CNetConnection::AckChunks(int Ack) @@ -169,6 +167,7 @@ // init connection Reset(); m_PeerAddr = *pAddr; + mem_zero(m_ErrorString, sizeof(m_ErrorString)); m_State = NET_CONNSTATE_CONNECT; SendControl(NET_CTRLMSG_CONNECT, 0, 0); return 0; @@ -214,24 +213,21 @@ m_State = NET_CONNSTATE_ERROR; m_RemoteClosed = 1; - if(!m_BlockCloseMsg) + if(pPacket->m_DataSize) { - if(pPacket->m_DataSize) - { - // make sure to sanitize the error string form the other party - char Str[128]; - if(pPacket->m_DataSize < 128) - str_copy(Str, (char *)pPacket->m_aChunkData, pPacket->m_DataSize); - else - str_copy(Str, (char *)pPacket->m_aChunkData, sizeof(Str)); - str_sanitize_strong(Str); - - // set the error string - SetError(Str); - } + // make sure to sanitize the error string form the other party + char Str[128]; + if(pPacket->m_DataSize < 128) + str_copy(Str, (char *)pPacket->m_aChunkData, pPacket->m_DataSize); else - SetError("No reason given"); + str_copy(Str, (char *)pPacket->m_aChunkData, sizeof(Str)); + str_sanitize_strong(Str); + + // set the error string + SetError(Str); } + else + SetError("No reason given"); if(g_Config.m_Debug) dbg_msg("conn", "closed reason='%s'", ErrorString()); diff -Naur ../teeworlds/src/engine/shared/network.cpp src/engine/shared/network.cpp --- ../teeworlds/src/engine/shared/network.cpp 2012-06-26 16:53:53.340861242 +1000 +++ src/engine/shared/network.cpp 2012-07-08 19:28:03.366259470 +1000 @@ -161,7 +161,7 @@ // check the size if(Size < NET_PACKETHEADERSIZE || Size > NET_MAX_PACKETSIZE) { - dbg_msg("network", "packet too small, %d", Size); + dbg_msg("", "packet too small, %d", Size); return -1; } @@ -177,11 +177,15 @@ // read the packet pPacket->m_Flags = pBuffer[0]>>4; + pPacket->m_Ack = ((pBuffer[0]&0xf)<<8) | pBuffer[1]; + pPacket->m_NumChunks = pBuffer[2]; + pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE; + if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS) { if(Size < 6) { - dbg_msg("network", "connection less packet too small, %d", Size); + dbg_msg("", "connection less packet too small, %d", Size); return -1; } @@ -193,15 +197,6 @@ } else { - if(Size-NET_PACKETHEADERSIZE > NET_MAX_PAYLOAD) - { - dbg_msg("network", "packet too big, %d", Size); - return -1; - } - - pPacket->m_Ack = ((pBuffer[0]&0xf)<<8) | pBuffer[1]; - pPacket->m_NumChunks = pBuffer[2]; - pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE; if(pPacket->m_Flags&NET_PACKETFLAG_COMPRESSION) pPacket->m_DataSize = ms_Huffman.Decompress(&pBuffer[3], pPacket->m_DataSize, pPacket->m_aChunkData, sizeof(pPacket->m_aChunkData)); else @@ -249,12 +244,12 @@ unsigned char *CNetChunkHeader::Pack(unsigned char *pData) { - pData[0] = ((m_Flags&0x03)<<6) | ((m_Size>>6)&0x3F); - pData[1] = (m_Size&0x3F); + pData[0] = ((m_Flags&3)<<6)|((m_Size>>4)&0x3f); + pData[1] = (m_Size&0xf); if(m_Flags&NET_CHUNKFLAG_VITAL) { - pData[1] |= (m_Sequence>>2)&0xC0; - pData[2] = m_Sequence&0xFF; + pData[1] |= (m_Sequence>>2)&0xf0; + pData[2] = m_Sequence&0xff; return pData + 3; } return pData + 2; @@ -262,12 +257,12 @@ unsigned char *CNetChunkHeader::Unpack(unsigned char *pData) { - m_Flags = (pData[0]>>6)&0x03; - m_Size = ((pData[0]&0x3F)<<6) | (pData[1]&0x3F); + m_Flags = (pData[0]>>6)&3; + m_Size = ((pData[0]&0x3f)<<4) | (pData[1]&0xf); m_Sequence = -1; if(m_Flags&NET_CHUNKFLAG_VITAL) { - m_Sequence = ((pData[1]&0xC0)<<2) | pData[2]; + m_Sequence = ((pData[1]&0xf0)<<2) | pData[2]; return pData + 3; } return pData + 2; diff -Naur ../teeworlds/src/engine/shared/network.h src/engine/shared/network.h --- ../teeworlds/src/engine/shared/network.h 2012-06-26 16:53:53.344860912 +1000 +++ src/engine/shared/network.h 2012-07-08 19:45:52.153944617 +1000 @@ -20,7 +20,7 @@ chunk header: 2-3 bytes unsigned char flags_size; // 2bit flags, 6 bit size - unsigned char size_seq; // 6bit size, 2bit seq + unsigned char size_seq; // 4bit size, 4bit seq (unsigned char seq;) // 8bit seq, if vital flag is set */ @@ -46,9 +46,9 @@ NET_MAX_PACKETSIZE = 1400, NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE-6, - NET_MAX_CHUNKHEADERSIZE = 3, + NET_MAX_CHUNKHEADERSIZE = 5, NET_PACKETHEADERSIZE = 3, - NET_MAX_CLIENTS = 16, + NET_MAX_CLIENTS = 64, NET_MAX_CONSOLE_CLIENTS = 4, NET_MAX_SEQUENCE = 1<<10, NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1, @@ -140,7 +140,6 @@ int m_Token; int m_RemoteClosed; - bool m_BlockCloseMsg; TStaticRingBuffer m_Buffer; @@ -168,7 +167,7 @@ void Resend(); public: - void Init(NETSOCKET Socket, bool BlockCloseMsg); + void Init(NETSOCKET Socket); int Connect(NETADDR *pAddr); void Disconnect(const char *pReason); @@ -243,6 +242,15 @@ // server side class CNetServer { +public: + struct CBanInfo + { + NETADDR m_Addr; + int m_Expires; + char m_Reason[128]; + }; + +private: struct CSlot { public: @@ -258,7 +266,7 @@ NETFUNC_NEWCLIENT m_pfnNewClient; NETFUNC_DELCLIENT m_pfnDelClient; void *m_UserPtr; - + CNetRecvUnpacker m_RecvUnpacker; public: @@ -354,7 +362,7 @@ int ResetErrorString(); // error and state - int NetType() const { return m_Socket.type; } + int NetType() { return m_Socket.type; } int State(); int GotProblems(); const char *ErrorString(); diff -Naur ../teeworlds/src/engine/shared/network_server.cpp src/engine/shared/network_server.cpp --- ../teeworlds/src/engine/shared/network_server.cpp 2012-06-26 16:53:53.344860912 +1000 +++ src/engine/shared/network_server.cpp 2012-07-08 19:42:32.814259392 +1000 @@ -30,7 +30,7 @@ m_MaxClientsPerIP = MaxClientsPerIP; for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aSlots[i].m_Connection.Init(m_Socket, true); + m_aSlots[i].m_Connection.Init(m_Socket); return true; } @@ -205,25 +205,19 @@ int CNetServer::Send(CNetChunk *pChunk) { - if(pChunk->m_Flags&NETSENDFLAG_CONNLESS) + if(pChunk->m_DataSize >= NET_MAX_PAYLOAD) { - if(pChunk->m_DataSize >= NET_MAX_PAYLOAD) - { - dbg_msg("netserver", "packet payload too big. %d. dropping packet", pChunk->m_DataSize); - return -1; - } + dbg_msg("netserver", "packet payload too big. %d. dropping packet", pChunk->m_DataSize); + return -1; + } + if(pChunk->m_Flags&NETSENDFLAG_CONNLESS) + { // send connectionless packet CNetBase::SendPacketConnless(m_Socket, &pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize); } else { - if(pChunk->m_DataSize+NET_MAX_CHUNKHEADERSIZE >= NET_MAX_PAYLOAD) - { - dbg_msg("netclient", "chunk payload too big. %d. dropping chunk", pChunk->m_DataSize); - return -1; - } - int Flags = 0; dbg_assert(pChunk->m_ClientID >= 0, "errornous client id"); dbg_assert(pChunk->m_ClientID < MaxClients(), "errornous client id"); diff -Naur ../teeworlds/src/engine/shared/protocol.h src/engine/shared/protocol.h --- ../teeworlds/src/engine/shared/protocol.h 2012-06-26 16:53:53.344860912 +1000 +++ src/engine/shared/protocol.h 2012-07-08 19:28:03.370259419 +1000 @@ -47,8 +47,6 @@ NETMSG_INPUTTIMING, // reports how off the input was NETMSG_RCON_AUTH_STATUS,// result of the authentication NETMSG_RCON_LINE, // line that should be printed to the remote console - NETMSG_RCON_CMD_ADD, - NETMSG_RCON_CMD_REM, NETMSG_AUTH_CHALLANGE, // NETMSG_AUTH_RESULT, // @@ -68,6 +66,10 @@ NETMSG_PING, NETMSG_PING_REPLY, NETMSG_ERROR, + + // sent by server (todo: move it up) + NETMSG_RCON_CMD_ADD, + NETMSG_RCON_CMD_REM, }; // this should be revised @@ -76,7 +78,8 @@ SERVER_TICK_SPEED=50, SERVER_FLAG_PASSWORD = 0x1, - MAX_CLIENTS=16, + MAX_CLIENTS=64, + VANILLA_MAX_CLIENTS=16, MAX_INPUT_SIZE=128, MAX_SNAPSHOT_PACKSIZE=900, diff -Naur ../teeworlds/src/game/client/components/binds.cpp src/game/client/components/binds.cpp --- ../teeworlds/src/game/client/components/binds.cpp 2012-06-26 16:53:53.348863586 +1000 +++ src/game/client/components/binds.cpp 2012-07-08 19:28:03.374259230 +1000 @@ -117,8 +117,6 @@ Bind(KEY_F3, "vote yes"); Bind(KEY_F4, "vote no"); - - Bind('r', "ready_change"); } void CBinds::OnConsoleInit() diff -Naur ../teeworlds/src/game/client/components/chat.cpp src/game/client/components/chat.cpp --- ../teeworlds/src/game/client/components/chat.cpp 2012-06-26 16:53:53.348863586 +1000 +++ src/game/client/components/chat.cpp 2012-07-08 19:42:32.818258992 +1000 @@ -112,25 +112,13 @@ { if(m_Input.GetString()[0]) { - bool AddEntry = false; - if(m_LastChatSend+time_freq() < time_get()) - { Say(m_Mode == MODE_ALL ? 0 : 1, m_Input.GetString()); - AddEntry = true; - } - else if(m_PendingChatCounter < 3) - { + else ++m_PendingChatCounter; - AddEntry = true; - } - - if(AddEntry) - { - CHistoryEntry *pEntry = m_History.Allocate(sizeof(CHistoryEntry)+m_Input.GetLength()); - pEntry->m_Team = m_Mode == MODE_ALL ? 0 : 1; - mem_copy(pEntry->m_aText, m_Input.GetString(), m_Input.GetLength()+1); - } + CHistoryEntry *pEntry = m_History.Allocate(sizeof(CHistoryEntry)+m_Input.GetLength()); + pEntry->m_Team = m_Mode == MODE_ALL ? 0 : 1; + mem_copy(pEntry->m_aText, m_Input.GetString(), m_Input.GetLength()+1); } m_pHistoryEntry = 0x0; m_Mode = MODE_NONE; @@ -277,9 +265,9 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine) { - if(*pLine == 0 || (ClientID != -1 && (m_pClient->m_aClients[ClientID].m_aName[0] == '\0' || // unknown client + if(ClientID != -1 && (m_pClient->m_aClients[ClientID].m_aName[0] == '\0' || // unknown client m_pClient->m_aClients[ClientID].m_ChatIgnore || - (m_pClient->m_Snap.m_LocalClientID != ClientID && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientID].m_Friend)))) + (m_pClient->m_Snap.m_LocalClientID != ClientID && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientID].m_Friend))) return; bool Highlighted = false; @@ -357,7 +345,7 @@ { if(Now-m_aLastSoundPlayed[CHAT_HIGHLIGHT] >= time_freq()*3/10) { - m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_HIGHLIGHT, 0); + m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_CLIENT, 0); m_aLastSoundPlayed[CHAT_HIGHLIGHT] = Now; } } @@ -365,7 +353,7 @@ { if(Now-m_aLastSoundPlayed[CHAT_CLIENT] >= time_freq()*3/10) { - m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_CLIENT, 0); + m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_HIGHLIGHT, 0); m_aLastSoundPlayed[CHAT_CLIENT] = Now; } } diff -Naur ../teeworlds/src/game/client/components/console.cpp src/game/client/components/console.cpp --- ../teeworlds/src/game/client/components/console.cpp 2012-06-26 16:53:53.352861021 +1000 +++ src/game/client/components/console.cpp 2012-07-08 19:42:32.934259347 +1000 @@ -434,6 +434,12 @@ x = Cursor.m_X; + // render console input (wrap line) + int Lines = TextRender()->TextLineCount(0, FontSize, pConsole->m_Input.GetString(), Screen.w - 10.0f - x); + y -= (Lines - 1) * FontSize; + TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER); + Cursor.m_LineWidth = Screen.w - 10.0f - x; + //hide rcon password char aInputString[256]; str_copy(aInputString, pConsole->m_Input.GetString(), sizeof(aInputString)); @@ -443,22 +449,10 @@ aInputString[i] = '*'; } - // render console input (wrap line) - TextRender()->SetCursor(&Cursor, x, y, FontSize, 0); - Cursor.m_LineWidth = Screen.w - 10.0f - x; - TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset()); - TextRender()->TextEx(&Cursor, aInputString+pConsole->m_Input.GetCursorOffset(), -1); - int Lines = Cursor.m_LineCount; - - y -= (Lines - 1) * FontSize; - TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER); - Cursor.m_LineWidth = Screen.w - 10.0f - x; - TextRender()->TextEx(&Cursor, aInputString, pConsole->m_Input.GetCursorOffset()); static float MarkerOffset = TextRender()->TextWidth(0, FontSize, "|", -1)/3; CTextCursor Marker = Cursor; Marker.m_X -= MarkerOffset; - Marker.m_LineWidth = -1; TextRender()->TextEx(&Marker, "|", -1); TextRender()->TextEx(&Cursor, aInputString+pConsole->m_Input.GetCursorOffset(), -1); @@ -593,13 +587,13 @@ m_pClient->m_pMenus->UseMouseButtons(false); m_ConsoleState = CONSOLE_OPENING; // reset controls - m_pClient->m_pControls->OnReset(); + //m_pClient->m_pControls->OnReset(); } else { Input()->MouseModeRelative(); m_pClient->m_pMenus->UseMouseButtons(true); - m_pClient->OnRelease(); + //m_pClient->OnRelease(); m_ConsoleState = CONSOLE_CLOSING; } } diff -Naur ../teeworlds/src/game/client/components/controls.cpp src/game/client/components/controls.cpp --- ../teeworlds/src/game/client/components/controls.cpp 2012-06-26 16:53:53.352861021 +1000 +++ src/game/client/components/controls.cpp 2012-07-08 19:42:32.934259347 +1000 @@ -35,7 +35,7 @@ void CControls::OnRelease() { - OnReset(); + //OnReset(); } void CControls::OnPlayerDeath() @@ -90,7 +90,7 @@ { static CInputSet s_Set = {this, &m_InputData.m_WantedWeapon, 2}; Console()->Register("+weapon2", "", CFGFLAG_CLIENT, ConKeyInputSet, (void *)&s_Set, "Switch to gun"); } { static CInputSet s_Set = {this, &m_InputData.m_WantedWeapon, 3}; Console()->Register("+weapon3", "", CFGFLAG_CLIENT, ConKeyInputSet, (void *)&s_Set, "Switch to shotgun"); } { static CInputSet s_Set = {this, &m_InputData.m_WantedWeapon, 4}; Console()->Register("+weapon4", "", CFGFLAG_CLIENT, ConKeyInputSet, (void *)&s_Set, "Switch to grenade"); } - { static CInputSet s_Set = {this, &m_InputData.m_WantedWeapon, 5}; Console()->Register("+weapon5", "", CFGFLAG_CLIENT, ConKeyInputSet, (void *)&s_Set, "Switch to laser"); } + { static CInputSet s_Set = {this, &m_InputData.m_WantedWeapon, 5}; Console()->Register("+weapon5", "", CFGFLAG_CLIENT, ConKeyInputSet, (void *)&s_Set, "Switch to rifle"); } { static CInputSet s_Set = {this, &m_InputData.m_NextWeapon, 0}; Console()->Register("+nextweapon", "", CFGFLAG_CLIENT, ConKeyInputNextPrevWeapon, (void *)&s_Set, "Switch to next weapon"); } { static CInputSet s_Set = {this, &m_InputData.m_PrevWeapon, 0}; Console()->Register("+prevweapon", "", CFGFLAG_CLIENT, ConKeyInputNextPrevWeapon, (void *)&s_Set, "Switch to previous weapon"); } @@ -114,8 +114,10 @@ // update player state if(m_pClient->m_pChat->IsActive()) m_InputData.m_PlayerFlags = PLAYERFLAG_CHATTING; + else if(m_pClient->m_pMenus->IsActive()) + m_InputData.m_PlayerFlags = PLAYERFLAG_IN_MENU; else - m_InputData.m_PlayerFlags = 0; + m_InputData.m_PlayerFlags = PLAYERFLAG_PLAYING; if(m_pClient->m_pScoreboard->Active()) m_InputData.m_PlayerFlags |= PLAYERFLAG_SCOREBOARD; @@ -126,10 +128,10 @@ m_LastData.m_PlayerFlags = m_InputData.m_PlayerFlags; // we freeze the input if chat or menu is activated - if(m_pClient->m_pChat->IsActive() || m_pClient->m_pMenus->IsActive()) + if(!(m_InputData.m_PlayerFlags&PLAYERFLAG_PLAYING)) { - OnReset(); - + //OnReset(); + mem_copy(pData, &m_InputData, sizeof(m_InputData)); // send once a second just to be sure @@ -207,7 +209,7 @@ bool CControls::OnMouseMove(float x, float y) { - if((m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)) || + if((m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) || (m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_pChat->IsActive())) return false; diff -Naur ../teeworlds/src/game/client/components/hud.cpp src/game/client/components/hud.cpp --- ../teeworlds/src/game/client/components/hud.cpp 2012-06-26 16:53:53.356861181 +1000 +++ src/game/client/components/hud.cpp 2012-07-08 19:42:32.822259292 +1000 @@ -35,23 +35,21 @@ { char Buf[32]; int Time = 0; - if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_WARMUP)) + if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && !m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) { - Time = m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit*60 - ((Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_GameStartTick)/Client()->GameTickSpeed()); + Time = m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit*60 - ((Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick)/Client()->GameTickSpeed()); - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)) + if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) Time = 0; } - else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)) - Time = m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer/Client()->GameTickSpeed(); else - Time = (Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_GameStartTick)/Client()->GameTickSpeed(); + Time = (Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick)/Client()->GameTickSpeed(); str_format(Buf, sizeof(Buf), "%d:d", Time/60, Time%60); float FontSize = 10.0f; float w = TextRender()->TextWidth(0, FontSize, Buf, -1); // last 60 sec red, last 10 sec blink - if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && Time <= 60 && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_WARMUP)) + if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && Time <= 60 && !m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) { float Alpha = Time <= 10 && (2*time_get()/time_freq()) % 2 ? 0.5f : 1.0f; TextRender()->TextColor(1.0f, 0.25f, 0.25f, Alpha); @@ -61,76 +59,15 @@ } } -void CHud::RenderPauseTimer() +void CHud::RenderPauseNotification() { - if((m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_STARTCOUNTDOWN|GAMESTATEFLAG_PAUSED)) == GAMESTATEFLAG_PAUSED) + if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED && + !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) { - char aBuf[256]; const char *pText = Localize("Game paused"); float FontSize = 20.0f; - float w = TextRender()->TextWidth(0, FontSize, pText, -1); - TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 50, FontSize, pText, -1); - - FontSize = 16.0f; - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer == -1) - { - int NotReadyCount = 0; - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(m_pClient->m_Snap.m_paPlayerInfos[i] && m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team != TEAM_SPECTATORS && - !(m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_READY)) - ++NotReadyCount; - } - if(NotReadyCount == 1) - str_format(aBuf, sizeof(aBuf), Localize("%d player not ready"), NotReadyCount); - else if(NotReadyCount > 1) - str_format(aBuf, sizeof(aBuf), Localize("%d players not ready"), NotReadyCount); - else - return; - } - else - { - int Seconds = m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer/SERVER_TICK_SPEED; - if(Seconds < 5) - str_format(aBuf, sizeof(aBuf), "%d.%d", Seconds, (m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer*10/SERVER_TICK_SPEED)); - else - str_format(aBuf, sizeof(aBuf), "%d", Seconds); - } - w = TextRender()->TextWidth(0, FontSize, aBuf, -1); - TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 75, FontSize, aBuf, -1); - } -} - -void CHud::RenderStartCountdown() -{ - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_STARTCOUNTDOWN) - { - char aBuf[256]; - const char *pText = Localize("Game starts in"); - float FontSize = 20.0f; - float w = TextRender()->TextWidth(0, FontSize, pText, -1); - TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 50, FontSize, pText, -1); - - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer == -1) - return; - - FontSize = 16.0f; - int Seconds = (m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer+SERVER_TICK_SPEED-1)/SERVER_TICK_SPEED; - str_format(aBuf, sizeof(aBuf), "%d", Seconds); - w = TextRender()->TextWidth(0, FontSize, aBuf, -1); - TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 75, FontSize, aBuf, -1); - } -} - -void CHud::RenderDeadNotification() -{ - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags == 0 && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS && - (m_pClient->m_Snap.m_pLocalInfo->m_PlayerFlags&PLAYERFLAG_DEAD)) - { - const char *pText = Localize("Wait for next round"); - float FontSize = 16.0f; - float w = TextRender()->TextWidth(0, FontSize, pText, -1); - TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 50, FontSize, pText, -1); + float w = TextRender()->TextWidth(0, FontSize,pText, -1); + TextRender()->Text(0, 150.0f*Graphics()->ScreenAspect()+-w/2.0f, 50.0f, FontSize, pText, -1); } } @@ -149,7 +86,7 @@ void CHud::RenderScoreHud() { // render small score hud - if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))) + if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) { int GameFlags = m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags; float Whole = 300*Graphics()->ScreenAspect(); @@ -162,7 +99,6 @@ str_format(aScoreTeam[TEAM_BLUE], sizeof(aScoreTeam)/2, "%d", m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue); float aScoreTeamWidth[2] = { TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_RED], -1), TextRender()->TextWidth(0, 14.0f, aScoreTeam[TEAM_BLUE], -1) }; int FlagCarrier[2] = { m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed, m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue }; - int FlagDropTick[2] = { m_pClient->m_Snap.m_pGameDataObj->m_FlagDropTickRed, m_pClient->m_Snap.m_pGameDataObj->m_FlagDropTickBlue }; float ScoreWidthMax = max(max(aScoreTeamWidth[TEAM_RED], aScoreTeamWidth[TEAM_BLUE]), TextRender()->TextWidth(0, 14.0f, "100", -1)); float Split = 3.0f; float ImageSize = GameFlags&GAMEFLAG_FLAGS ? 16.0f : Split; @@ -185,7 +121,8 @@ if(GameFlags&GAMEFLAG_FLAGS) { - int BlinkTimer = (FlagDropTick[t] != 0 && (Client()->GameTick()-FlagDropTick[t])/Client()->GameTickSpeed() >= 25) ? 10 : 20; + int BlinkTimer = (m_pClient->m_FlagDropTick[t] != 0 && + (Client()->GameTick()-m_pClient->m_FlagDropTick[t])/Client()->GameTickSpeed() >= 25) ? 10 : 20; if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/BlinkTimer)&1))) { // draw flag @@ -212,22 +149,6 @@ vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20)); } } - - if(GameFlags&GAMEFLAG_SURVIVAL) - { - // draw number of alive players - int Count = 0; - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(m_pClient->m_Snap.m_paPlayerInfos[i] && !(m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_DEAD) && - m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == t) - ++Count; - } - char aBuf[32]; - str_format(aBuf, sizeof(aBuf), Count==1?Localize("%d player left"):Localize("%d players left"), Count); - float w = TextRender()->TextWidth(0, 8.0f, aBuf, -1); - TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split), StartY+(t+1)*20.0f-3.0f, 8.0f, aBuf, -1); - } StartY += 8.0f; } } @@ -274,8 +195,6 @@ float ScoreWidthMax = max(max(aScoreWidth[0], aScoreWidth[1]), TextRender()->TextWidth(0, 14.0f, "10", -1)); float Split = 3.0f, ImageSize = 16.0f, PosSize = 16.0f; - // todo: add core hud for LMS - for(int t = 0; t < 2; t++) { // draw box @@ -321,40 +240,20 @@ void CHud::RenderWarmupTimer() { // render warmup timer - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_WARMUP) + if(m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) { - char aBuf[256]; + char Buf[256]; float FontSize = 20.0f; float w = TextRender()->TextWidth(0, FontSize, Localize("Warmup"), -1); TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 50, FontSize, Localize("Warmup"), -1); - FontSize = 16.0f; - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer == -1) - { - int NotReadyCount = 0; - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(m_pClient->m_Snap.m_paPlayerInfos[i] && m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team != TEAM_SPECTATORS && - !(m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_READY)) - ++NotReadyCount; - } - if(NotReadyCount == 1) - str_format(aBuf, sizeof(aBuf), Localize("%d player not ready"), NotReadyCount); - else if(NotReadyCount > 1) - str_format(aBuf, sizeof(aBuf), Localize("%d players not ready"), NotReadyCount); - else - str_format(aBuf, sizeof(aBuf), Localize("wait for more players")); - } + int Seconds = m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer/SERVER_TICK_SPEED; + if(Seconds < 5) + str_format(Buf, sizeof(Buf), "%d.%d", Seconds, (m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer*10/SERVER_TICK_SPEED)); else - { - int Seconds = m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer/SERVER_TICK_SPEED; - if(Seconds < 5) - str_format(aBuf, sizeof(aBuf), "%d.%d", Seconds, (m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer*10/SERVER_TICK_SPEED)); - else - str_format(aBuf, sizeof(aBuf), "%d", Seconds); - } - w = TextRender()->TextWidth(0, FontSize, aBuf, -1); - TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 75, FontSize, aBuf, -1); + str_format(Buf, sizeof(Buf), "%d", Seconds); + w = TextRender()->TextWidth(0, FontSize, Buf, -1); + TextRender()->Text(0, 150*Graphics()->ScreenAspect()+-w/2, 75, FontSize, Buf, -1); } } @@ -553,7 +452,7 @@ if(g_Config.m_ClShowhud) { - if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))) + if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) RenderHealthAndAmmo(m_pClient->m_Snap.m_pLocalCharacter); else if(m_pClient->m_Snap.m_SpecInfo.m_Active) { @@ -563,9 +462,7 @@ } RenderGameTimer(); - RenderPauseTimer(); - RenderStartCountdown(); - RenderDeadNotification(); + RenderPauseNotification(); RenderSuddenDeath(); RenderScoreHud(); RenderWarmupTimer(); diff -Naur ../teeworlds/src/game/client/components/hud.h src/game/client/components/hud.h --- ../teeworlds/src/game/client/components/hud.h 2012-06-26 16:53:53.356861181 +1000 +++ src/game/client/components/hud.h 2012-07-08 19:42:32.822259292 +1000 @@ -17,9 +17,7 @@ void RenderVoting(); void RenderHealthAndAmmo(const CNetObj_Character *pCharacter); void RenderGameTimer(); - void RenderPauseTimer(); - void RenderStartCountdown(); - void RenderDeadNotification(); + void RenderPauseNotification(); void RenderSuddenDeath(); void RenderScoreHud(); void RenderSpectatorHud(); diff -Naur ../teeworlds/src/game/client/components/items.cpp src/game/client/components/items.cpp --- ../teeworlds/src/game/client/components/items.cpp 2012-06-26 16:53:53.356861181 +1000 +++ src/game/client/components/items.cpp 2012-07-08 19:42:32.822259292 +1000 @@ -108,33 +108,29 @@ vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), Client()->IntraGameTick()); float Angle = 0.0f; float Size = 64.0f; - const int c[] = { - SPRITE_PICKUP_HEALTH, - SPRITE_PICKUP_ARMOR, - SPRITE_PICKUP_GRENADE, - SPRITE_PICKUP_SHOTGUN, - SPRITE_PICKUP_LASER, - SPRITE_PICKUP_NINJA - }; - RenderTools()->SelectSprite(c[pCurrent->m_Type]); - - switch(pCurrent->m_Type) - { - case PICKUP_GRENADE: - Size = g_pData->m_Weapons.m_aId[WEAPON_GRENADE].m_VisualSize; - break; - case PICKUP_SHOTGUN: - Size = g_pData->m_Weapons.m_aId[WEAPON_SHOTGUN].m_VisualSize; - break; - case PICKUP_LASER: - Size = g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize; - break; - case PICKUP_NINJA: - m_pClient->m_pEffects->PowerupShine(Pos, vec2(96,18)); - Size *= 2.0f; - Pos.x -= 10.0f; + if (pCurrent->m_Type == POWERUP_WEAPON) + { + Angle = 0; //-pi/6;//-0.25f * pi * 2.0f; + RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[clamp(pCurrent->m_Subtype, 0, NUM_WEAPONS-1)].m_pSpriteBody); + Size = g_pData->m_Weapons.m_aId[clamp(pCurrent->m_Subtype, 0, NUM_WEAPONS-1)].m_VisualSize; + } + else + { + const int c[] = { + SPRITE_PICKUP_HEALTH, + SPRITE_PICKUP_ARMOR, + SPRITE_PICKUP_WEAPON, + SPRITE_PICKUP_NINJA + }; + RenderTools()->SelectSprite(c[pCurrent->m_Type]); + + if(c[pCurrent->m_Type] == SPRITE_PICKUP_NINJA) + { + m_pClient->m_pEffects->PowerupShine(Pos, vec2(96,18)); + Size *= 2.0f; + Pos.x -= 10.0f; + } } - Graphics()->QuadsSetRotation(Angle); diff -Naur ../teeworlds/src/game/client/components/maplayers.cpp src/game/client/components/maplayers.cpp --- ../teeworlds/src/game/client/components/maplayers.cpp 2012-06-26 16:53:53.356861181 +1000 +++ src/game/client/components/maplayers.cpp 2012-07-08 19:42:32.822259292 +1000 @@ -104,8 +104,8 @@ { if(pItem->m_Version < 2 || pItem->m_Synchronized) { - s_Time = mix((pThis->Client()->PrevGameTick()-pThis->m_pClient->m_Snap.m_pGameInfoObj->m_GameStartTick) / (float)pThis->Client()->GameTickSpeed(), - (pThis->Client()->GameTick()-pThis->m_pClient->m_Snap.m_pGameInfoObj->m_GameStartTick) / (float)pThis->Client()->GameTickSpeed(), + s_Time = mix((pThis->Client()->PrevGameTick()-pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)pThis->Client()->GameTickSpeed(), + (pThis->Client()->GameTick()-pThis->m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / (float)pThis->Client()->GameTickSpeed(), pThis->Client()->IntraGameTick()); } else diff -Naur ../teeworlds/src/game/client/components/menus_browser.cpp src/game/client/components/menus_browser.cpp --- ../teeworlds/src/game/client/components/menus_browser.cpp 2012-06-26 16:53:53.360863645 +1000 +++ src/game/client/components/menus_browser.cpp 2012-07-08 19:42:32.826259590 +1000 @@ -225,7 +225,7 @@ { int ItemIndex = i; const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex); - NumPlayers += g_Config.m_BrFilterSpectators ? pItem->m_NumPlayers : pItem->m_NumClients; + NumPlayers += pItem->m_NumPlayers; CUIRect Row; CUIRect SelectHitBox; @@ -314,9 +314,7 @@ { if( str_comp(pItem->m_aGameType, "DM") == 0 || str_comp(pItem->m_aGameType, "TDM") == 0 || - str_comp(pItem->m_aGameType, "CTF") == 0 || - str_comp(pItem->m_aGameType, "LMS") == 0 || - str_comp(pItem->m_aGameType, "SUR") == 0) + str_comp(pItem->m_aGameType, "CTF") == 0) { // pure server } diff -Naur ../teeworlds/src/game/client/components/menus.cpp src/game/client/components/menus.cpp --- ../teeworlds/src/game/client/components/menus.cpp 2012-06-26 16:53:53.360863645 +1000 +++ src/game/client/components/menus.cpp 2012-07-08 19:42:32.822259292 +1000 @@ -539,7 +539,7 @@ Box.VSplitLeft(100.0f, &Button, &Box); static int s_InternetButton=0; - if(DoButton_MenuTab(&s_InternetButton, Localize("Internet"), m_ActivePage==PAGE_INTERNET, &Button, CUI::CORNER_TL) && m_ActivePage!=PAGE_INTERNET) + if(DoButton_MenuTab(&s_InternetButton, Localize("Internet"), m_ActivePage==PAGE_INTERNET, &Button, CUI::CORNER_TL)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); NewPage = PAGE_INTERNET; @@ -548,7 +548,7 @@ //Box.VSplitLeft(4.0f, 0, &Box); Box.VSplitLeft(80.0f, &Button, &Box); static int s_LanButton=0; - if(DoButton_MenuTab(&s_LanButton, Localize("LAN"), m_ActivePage==PAGE_LAN, &Button, 0) && m_ActivePage!=PAGE_LAN) + if(DoButton_MenuTab(&s_LanButton, Localize("LAN"), m_ActivePage==PAGE_LAN, &Button, 0)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN); NewPage = PAGE_LAN; @@ -557,7 +557,7 @@ //box.VSplitLeft(4.0f, 0, &box); Box.VSplitLeft(110.0f, &Button, &Box); static int s_FavoritesButton=0; - if(DoButton_MenuTab(&s_FavoritesButton, Localize("Favorites"), m_ActivePage==PAGE_FAVORITES, &Button, CUI::CORNER_TR) && m_ActivePage!=PAGE_FAVORITES) + if(DoButton_MenuTab(&s_FavoritesButton, Localize("Favorites"), m_ActivePage==PAGE_FAVORITES, &Button, CUI::CORNER_TR)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES); NewPage = PAGE_FAVORITES; @@ -566,7 +566,7 @@ Box.VSplitLeft(4.0f*5, 0, &Box); Box.VSplitLeft(100.0f, &Button, &Box); static int s_DemosButton=0; - if(DoButton_MenuTab(&s_DemosButton, Localize("Demos"), m_ActivePage==PAGE_DEMOS, &Button, CUI::CORNER_T) && m_ActivePage!=PAGE_DEMOS) + if(DoButton_MenuTab(&s_DemosButton, Localize("Demos"), m_ActivePage==PAGE_DEMOS, &Button, CUI::CORNER_T)) { DemolistPopulate(); NewPage = PAGE_DEMOS; @@ -1045,7 +1045,7 @@ } // update download speed - float Diff = (Client()->MapDownloadAmount()-m_DownloadLastCheckSize)/((int)((Now-m_DownloadLastCheckTime)/time_freq())); + float Diff = Client()->MapDownloadAmount()-m_DownloadLastCheckSize; float StartDiff = m_DownloadLastCheckSize-0.0f; if(StartDiff+Diff > 0.0f) m_DownloadSpeed = (Diff/(StartDiff+Diff))*(Diff/1.0f) + (StartDiff/(Diff+StartDiff))*m_DownloadSpeed; diff -Naur ../teeworlds/src/game/client/components/menus.h src/game/client/components/menus.h --- ../teeworlds/src/game/client/components/menus.h 2012-07-08 00:31:07.985177225 +1000 +++ src/game/client/components/menus.h 2012-07-08 19:42:32.826259590 +1000 @@ -218,11 +218,11 @@ return false; else { - int Result = str_comp_nocase(m_pFriendInfo->m_aName, Other.m_pFriendInfo->m_aName); + int Result = str_comp(m_pFriendInfo->m_aName, Other.m_pFriendInfo->m_aName); if(Result) return Result < 0; else - return str_comp_nocase(m_pFriendInfo->m_aClan, Other.m_pFriendInfo->m_aClan) < 0; + return str_comp(m_pFriendInfo->m_aClan, Other.m_pFriendInfo->m_aClan) < 0; } } }; diff -Naur ../teeworlds/src/game/client/components/menus_ingame.cpp src/game/client/components/menus_ingame.cpp --- ../teeworlds/src/game/client/components/menus_ingame.cpp 2012-06-26 16:53:53.364862128 +1000 +++ src/game/client/components/menus_ingame.cpp 2012-07-08 19:42:32.826259590 +1000 @@ -183,7 +183,7 @@ ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button); Button.VSplitLeft(Button.h, &Button, 0); - if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend) + if(&g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend) DoButton_Toggle(&s_aPlayerIDs[Index][0], 1, &Button, false); else if(DoButton_Toggle(&s_aPlayerIDs[Index][0], m_pClient->m_aClients[Index].m_ChatIgnore, &Button, true)) diff -Naur ../teeworlds/src/game/client/components/menus_settings.cpp src/game/client/components/menus_settings.cpp --- ../teeworlds/src/game/client/components/menus_settings.cpp 2012-07-08 00:31:07.989177105 +1000 +++ src/game/client/components/menus_settings.cpp 2012-07-08 19:42:32.830259121 +1000 @@ -433,7 +433,7 @@ { "Pistol", "+weapon2", 0 }, { "Shotgun", "+weapon3", 0 }, { "Grenade", "+weapon4", 0 }, - { "Laser", "+weapon5", 0 }, + { "Rifle", "+weapon5", 0 }, { "Next weapon", "+nextweapon", 0 }, { "Prev. weapon", "+prevweapon", 0 }, { "Vote yes", "vote yes", 0 }, @@ -450,15 +450,13 @@ { "Screenshot", "screenshot", 0 }, { "Scoreboard", "+scoreboard", 0 }, { "Respawn", "kill", 0 }, - { "Ready", "ready_change", 0 }, }; /* This is for scripts/update_localization.py to work, don't remove! Localize("Move left");Localize("Move right");Localize("Jump");Localize("Fire");Localize("Hook");Localize("Hammer"); - Localize("Pistol");Localize("Shotgun");Localize("Grenade");Localize("Laser");Localize("Next weapon");Localize("Prev. weapon"); + Localize("Pistol");Localize("Shotgun");Localize("Grenade");Localize("Rifle");Localize("Next weapon");Localize("Prev. weapon"); Localize("Vote yes");Localize("Vote no");Localize("Chat");Localize("Team chat");Localize("Show chat");Localize("Emoticon"); - Localize("Spectator mode");Localize("Spectate next");Localize("Spectate previous");Localize("Console");Localize("Remote console"); - Localize("Screenshot");Localize("Scoreboard");Localize("Respawn");Localize("Ready"); + Localize("Spectator mode");Localize("Spectate next");Localize("Spectate previous");Localize("Console");Localize("Remote console");Localize("Screenshot");Localize("Scoreboard");Localize("Respawn"); */ const int g_KeyCount = sizeof(gs_aKeys) / sizeof(CKeyInfo); @@ -615,7 +613,6 @@ static int s_GfxScreenWidth = g_Config.m_GfxScreenWidth; static int s_GfxScreenHeight = g_Config.m_GfxScreenHeight; static int s_GfxColorDepth = g_Config.m_GfxColorDepth; - static int s_GfxBorderless = g_Config.m_GfxBorderless; static int s_GfxFullscreen = g_Config.m_GfxFullscreen; static int s_GfxVsync = g_Config.m_GfxVsync; static int s_GfxFsaaSamples = g_Config.m_GfxFsaaSamples; @@ -671,20 +668,9 @@ // switches MainView.HSplitTop(20.0f, &Button, &MainView); - if(DoButton_CheckBox(&g_Config.m_GfxBorderless, Localize("Borderless window"), g_Config.m_GfxBorderless, &Button)) - { - g_Config.m_GfxBorderless ^= 1; - if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen) - g_Config.m_GfxFullscreen = 0; - CheckSettings = true; - } - - MainView.HSplitTop(20.0f, &Button, &MainView); if(DoButton_CheckBox(&g_Config.m_GfxFullscreen, Localize("Fullscreen"), g_Config.m_GfxFullscreen, &Button)) { g_Config.m_GfxFullscreen ^= 1; - if(g_Config.m_GfxFullscreen && g_Config.m_GfxBorderless) - g_Config.m_GfxBorderless = 0; CheckSettings = true; } @@ -727,7 +713,6 @@ if(s_GfxScreenWidth == g_Config.m_GfxScreenWidth && s_GfxScreenHeight == g_Config.m_GfxScreenHeight && s_GfxColorDepth == g_Config.m_GfxColorDepth && - s_GfxBorderless == g_Config.m_GfxBorderless && s_GfxFullscreen == g_Config.m_GfxFullscreen && s_GfxVsync == g_Config.m_GfxVsync && s_GfxFsaaSamples == g_Config.m_GfxFsaaSamples && @@ -796,13 +781,10 @@ if(DoButton_CheckBox(&g_Config.m_SndMusic, Localize("Play background music"), g_Config.m_SndMusic, &Button)) { g_Config.m_SndMusic ^= 1; - if(Client()->State() == IClient::STATE_OFFLINE) - { - if(g_Config.m_SndMusic) - m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f); - else - m_pClient->m_pSounds->Stop(SOUND_MENU); - } + if(g_Config.m_SndMusic) + m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f); + else + m_pClient->m_pSounds->Stop(SOUND_MENU); } MainView.HSplitTop(20.0f, &Button, &MainView); diff -Naur ../teeworlds/src/game/client/components/players.cpp src/game/client/components/players.cpp --- ../teeworlds/src/game/client/components/players.cpp 2012-06-26 16:53:53.368860821 +1000 +++ src/game/client/components/players.cpp 2012-07-08 19:42:32.830259121 +1000 @@ -106,8 +106,7 @@ // use preditect players if needed if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { - if(!m_pClient->m_Snap.m_pLocalCharacter || - (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))) + if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) { } else @@ -240,8 +239,7 @@ // use preditect players if needed if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { - if(!m_pClient->m_Snap.m_pLocalCharacter || - (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))) + if(!m_pClient->m_Snap.m_pLocalCharacter || (m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) { } else @@ -487,7 +485,7 @@ RenderInfo.m_ColorFeet.a = 1.0f; RenderTools()->RenderTee(&State, &RenderInfo, Player.m_Emote, Direction, Position); - if(pInfo.m_PlayerFlags&PLAYERFLAG_CHATTING) + if(Player.m_PlayerFlags&PLAYERFLAG_CHATTING) { Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id); Graphics()->QuadsBegin(); diff -Naur ../teeworlds/src/game/client/components/scoreboard.cpp src/game/client/components/scoreboard.cpp --- ../teeworlds/src/game/client/components/scoreboard.cpp 2012-06-26 16:53:53.368860821 +1000 +++ src/game/client/components/scoreboard.cpp 2012-07-08 19:42:32.830259121 +1000 @@ -70,10 +70,10 @@ str_format(aBuf, sizeof(aBuf), Localize("Time limit: %d min"), m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit); TextRender()->Text(0, x+230.0f, y, 20.0f, aBuf, -1); } - if(m_pClient->m_Snap.m_pGameInfoObj->m_MatchNum && m_pClient->m_Snap.m_pGameInfoObj->m_MatchCurrent) + if(m_pClient->m_Snap.m_pGameInfoObj->m_RoundNum && m_pClient->m_Snap.m_pGameInfoObj->m_RoundCurrent) { char aBuf[64]; - str_format(aBuf, sizeof(aBuf), "%s %d/%d", Localize("Match"), m_pClient->m_Snap.m_pGameInfoObj->m_MatchCurrent, m_pClient->m_Snap.m_pGameInfoObj->m_MatchNum); + str_format(aBuf, sizeof(aBuf), "%s %d/%d", Localize("Round"), m_pClient->m_Snap.m_pGameInfoObj->m_RoundCurrent, m_pClient->m_Snap.m_pGameInfoObj->m_RoundNum); float tw = TextRender()->TextWidth(0, 20.0f, aBuf, -1); TextRender()->Text(0, x+w-tw-10.0f, y, 20.0f, aBuf, -1); } @@ -98,11 +98,9 @@ // spectator names y += 30.0f; + char aBuffer[1024*4]; + aBuffer[0] = 0; bool Multiple = false; - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, x+10.0f, y, 22.0f, TEXTFLAG_RENDER); - Cursor.m_LineWidth = w-20.0f; - Cursor.m_MaxLines = 4; for(int i = 0; i < MAX_CLIENTS; ++i) { const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paPlayerInfos[i]; @@ -110,13 +108,15 @@ continue; if(Multiple) - TextRender()->TextEx(&Cursor, ", ", -1); - if(pInfo->m_PlayerFlags&PLAYERFLAG_WATCHING) - TextRender()->TextColor(1.0f, 1.0f, 0.0f, 1.0f); - TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1); - TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); + str_append(aBuffer, ", ", sizeof(aBuffer)); + str_append(aBuffer, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, sizeof(aBuffer)); Multiple = true; } + CTextCursor Cursor; + TextRender()->SetCursor(&Cursor, x+10.0f, y, 22.0f, TEXTFLAG_RENDER); + Cursor.m_LineWidth = w-20.0f; + Cursor.m_MaxLines = 4; + TextRender()->TextEx(&Cursor, aBuffer, -1); } void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const char *pTitle) @@ -124,6 +124,13 @@ if(Team == TEAM_SPECTATORS) return; + bool upper16 = false; + if (Team == -3) + { + upper16 = true; + Team = 0; + } + float h = 760.0f; // background @@ -140,8 +147,6 @@ { if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) pTitle = Localize("Game over"); - else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER) - pTitle = Localize("Round over"); else pTitle = Localize("Score board"); } @@ -217,101 +222,81 @@ float FontSize = 24.0f; CTextCursor Cursor; - for(int RenderDead = 0; RenderDead < 2; ++RenderDead) + int rendered = upper16?-16:0; + for(int i = 0; i < MAX_CLIENTS; i++) { - float ColorAlpha = RenderDead ? 0.5f : 1.0f; - TextRender()->TextColor(1.0f, 1.0f, 1.0f, ColorAlpha); - for(int i = 0; i < MAX_CLIENTS; i++) - { - // make sure that we render the correct team - const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i]; - if(!pInfo || pInfo->m_Team != Team || (!RenderDead && (pInfo->m_PlayerFlags&PLAYERFLAG_DEAD)) || (RenderDead && !(pInfo->m_PlayerFlags&PLAYERFLAG_DEAD))) - continue; + // make sure that we render the correct team + const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i]; + if(!pInfo || pInfo->m_Team != Team) + continue; - // background so it's easy to find the local player or the followed one in spectator mode - if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID)) - { - Graphics()->TextureSet(-1); - Graphics()->QuadsBegin(); - Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f*ColorAlpha); - RenderTools()->DrawRoundRect(x, y, w-20.0f, LineHeight, 15.0f); - Graphics()->QuadsEnd(); - } + if (rendered++ < 0) continue; - // score - str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999)); - tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); - TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = ScoreLength; - TextRender()->TextEx(&Cursor, aBuf, -1); - - // flag - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS && - m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID || - m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID)) - { - Graphics()->BlendNormal(); - Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); - Graphics()->QuadsBegin(); - - RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); - - float Size = LineHeight; - IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f, Size/2.0f, Size); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - } + // background so it's easy to find the local player or the followed one in spectator mode + if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID)) + { + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); + RenderTools()->DrawRoundRect(x, y, w-20.0f, LineHeight, 15.0f); + Graphics()->QuadsEnd(); + } - // avatar - if(RenderDead) - { - Graphics()->BlendNormal(); - Graphics()->TextureSet(g_pData->m_aImages[IMAGE_DEADTEE].m_Id); - Graphics()->QuadsBegin(); - IGraphics::CQuadItem QuadItem(TeeOffset, y, 64*TeeSizeMod, 64*TeeSizeMod); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - } - else - { - CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo; - TeeInfo.m_Size *= TeeSizeMod; - RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2)); - } + // score + str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999)); + tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); + TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); + Cursor.m_LineWidth = ScoreLength; + TextRender()->TextEx(&Cursor, aBuf, -1); + + // flag + if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS && + m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID || + m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID)) + { + Graphics()->BlendNormal(); + Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); + Graphics()->QuadsBegin(); + + RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); + + float Size = LineHeight; + IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f, Size/2.0f, Size); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + } - // name - // todo: improve visual player ready state - if(!(pInfo->m_PlayerFlags&PLAYERFLAG_READY)) - TextRender()->TextColor(1.0f, 0.5f, 0.5f, ColorAlpha); - else if(RenderDead && pInfo->m_PlayerFlags&PLAYERFLAG_WATCHING) - TextRender()->TextColor(1.0f, 1.0f, 0.0f, ColorAlpha); - TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = NameLength; - TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1); - TextRender()->TextColor(1.0f, 1.0f, 1.0f, ColorAlpha); - - // clan - tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); - TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = ClanLength; - TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); - - // country flag - vec4 Color(1.0f, 1.0f, 1.0f, 0.5f*ColorAlpha); - m_pClient->m_pCountryFlags->Render(m_pClient->m_aClients[pInfo->m_ClientID].m_Country, &Color, - CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f); - - // ping - str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000)); - tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); - TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = PingLength; - TextRender()->TextEx(&Cursor, aBuf, -1); + // avatar + CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo; + TeeInfo.m_Size *= TeeSizeMod; + RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2)); + + // name + TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); + Cursor.m_LineWidth = NameLength; + TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1); - y += LineHeight+Spacing; - } + // clan + tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); + TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); + Cursor.m_LineWidth = ClanLength; + TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); + + // country flag + vec4 Color(1.0f, 1.0f, 1.0f, 0.5f); + m_pClient->m_pCountryFlags->Render(m_pClient->m_aClients[pInfo->m_ClientID].m_Country, &Color, + CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f); + + // ping + str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000)); + tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); + TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); + Cursor.m_LineWidth = PingLength; + TextRender()->TextEx(&Cursor, aBuf, -1); + + y += LineHeight+Spacing; + if (rendered == 16) break; } - TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); } void CScoreboard::RenderRecordingNotification(float x) @@ -360,13 +345,22 @@ if(m_pClient->m_Snap.m_pGameInfoObj) { if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS)) - RenderScoreboard(Width/2-w/2, 150.0f, w, 0, 0); + { + if(m_pClient->m_Snap.m_aTeamSize[0] > 16) + { + RenderScoreboard(Width/2-w-5.0f, 150.0f, w, 0, 0); + RenderScoreboard(Width/2+5.0f, 150.0f, w, -3, 0); + } else + { + RenderScoreboard(Width/2-w/2, 150.0f, w, 0, 0); + } + } else { const char *pRedClanName = GetClanName(TEAM_RED); const char *pBlueClanName = GetClanName(TEAM_BLUE); - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) + if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER && m_pClient->m_Snap.m_pGameDataObj) { char aText[256]; str_copy(aText, Localize("Draw!"), sizeof(aText)); @@ -389,14 +383,6 @@ float w = TextRender()->TextWidth(0, 86.0f, aText, -1); TextRender()->Text(0, Width/2-w/2, 39, 86.0f, aText, -1); } - else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER) - { - char aText[256]; - str_copy(aText, Localize("Round over!"), sizeof(aText)); - - float w = TextRender()->TextWidth(0, 86.0f, aText, -1); - TextRender()->Text(0, Width/2-w/2, 39, 86.0f, aText, -1); - } RenderScoreboard(Width/2-w-5.0f, 150.0f, w, TEAM_RED, pRedClanName ? pRedClanName : Localize("Red team")); RenderScoreboard(Width/2+5.0f, 150.0f, w, TEAM_BLUE, pBlueClanName ? pBlueClanName : Localize("Blue team")); @@ -416,13 +402,13 @@ if(m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS) { - // we are not a spectator, check if we are dead, don't follow a player and the game isn't paused - if(!m_pClient->m_Snap.m_pLocalCharacter && !m_pClient->m_Snap.m_SpecInfo.m_Active && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)) + // we are not a spectator, check if we are dead + if(!m_pClient->m_Snap.m_pLocalCharacter) return true; } // if the game is over - if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)) + if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) return true; return false; diff -Naur ../teeworlds/src/game/client/components/skins.h src/game/client/components/skins.h --- ../teeworlds/src/game/client/components/skins.h 2012-07-08 00:31:07.989177105 +1000 +++ src/game/client/components/skins.h 2012-07-08 19:28:03.394259187 +1000 @@ -17,7 +17,7 @@ char m_aName[24]; vec3 m_BloodColor; - bool operator<(const CSkin &Other) { return str_comp_nocase(m_aName, Other.m_aName) < 0; } + bool operator<(const CSkin &Other) { return str_comp(m_aName, Other.m_aName) < 0; } }; void OnInit(); diff -Naur ../teeworlds/src/game/client/components/spectator.cpp src/game/client/components/spectator.cpp --- ../teeworlds/src/game/client/components/spectator.cpp 2012-06-26 16:53:53.368860821 +1000 +++ src/game/client/components/spectator.cpp 2012-07-08 19:28:03.394259187 +1000 @@ -195,33 +195,28 @@ float LineHeight = 60.0f; bool Selected = false; - if(m_pClient->m_Snap.m_pLocalInfo->m_Team == TEAM_SPECTATORS) + if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW) { - if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW) - { - Graphics()->TextureSet(-1); - Graphics()->QuadsBegin(); - Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); - RenderTools()->DrawRoundRect(Width/2.0f-280.0f, Height/2.0f-280.0f, 270.0f, 60.0f, 20.0f); - Graphics()->QuadsEnd(); - } + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); + RenderTools()->DrawRoundRect(Width/2.0f-280.0f, Height/2.0f-280.0f, 270.0f, 60.0f, 20.0f); + Graphics()->QuadsEnd(); + } - if(m_SelectorMouse.x >= -280.0f && m_SelectorMouse.x <= -10.0f && - m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f) - { - m_SelectedSpectatorID = SPEC_FREEVIEW; - Selected = true; - } - TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f); - TextRender()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1); + if(m_SelectorMouse.x >= -280.0f && m_SelectorMouse.x <= -10.0f && + m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f) + { + m_SelectedSpectatorID = SPEC_FREEVIEW; + Selected = true; } + TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f); + TextRender()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1); float x = -270.0f, y = StartY; for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i) { - if(!m_pClient->m_Snap.m_paPlayerInfos[i] || m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS || - (m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS && (m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_DEAD || - m_pClient->m_Snap.m_pLocalInfo->m_Team != m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team || i == m_pClient->m_Snap.m_LocalClientID))) + if(!m_pClient->m_Snap.m_paPlayerInfos[i] || m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS) continue; if(++Count%9 == 0) diff -Naur ../teeworlds/src/game/client/components/voting.cpp src/game/client/components/voting.cpp --- ../teeworlds/src/game/client/components/voting.cpp 2012-06-26 16:53:53.372860980 +1000 +++ src/game/client/components/voting.cpp 2012-07-08 19:28:03.394259187 +1000 @@ -120,12 +120,7 @@ CVoting::CVoting() { ClearOptions(); - - m_Closetime = 0; - m_aDescription[0] = 0; - m_aReason[0] = 0; - m_Yes = m_No = m_Pass = m_Total = 0; - m_Voted = 0; + OnReset(); } void CVoting::AddOption(const char *pDescription) @@ -169,9 +164,6 @@ void CVoting::OnReset() { - if(Client()->State() == IClient::STATE_LOADING) // do not reset active vote while connecting - return; - m_Closetime = 0; m_aDescription[0] = 0; m_aReason[0] = 0; diff -Naur ../teeworlds/src/game/client/gameclient.cpp src/game/client/gameclient.cpp --- ../teeworlds/src/game/client/gameclient.cpp 2012-06-26 16:53:53.372860980 +1000 +++ src/game/client/gameclient.cpp 2012-07-08 19:48:22.537766616 +1000 @@ -177,7 +177,6 @@ // add the some console commands Console()->Register("team", "i", CFGFLAG_CLIENT, ConTeam, this, "Switch team"); Console()->Register("kill", "", CFGFLAG_CLIENT, ConKill, this, "Kill yourself"); - Console()->Register("ready_change", "", CFGFLAG_CLIENT, ConReadyChange, this, "Change ready state"); // register server dummy commands for tab completion Console()->Register("tune", "si", CFGFLAG_SERVER, 0, 0, "Tune variable to value"); @@ -194,6 +193,7 @@ Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, 0, 0, "Force a voting option"); Console()->Register("clear_votes", "", CFGFLAG_SERVER, 0, 0, "Clears the voting options"); Console()->Register("vote", "r", CFGFLAG_SERVER, 0, 0, "Force a vote to yes/no"); + Console()->Register("spin", "i", CFGFLAG_SERVER, 0, 0, "If somone is using spin bot, Use this on them."); Console()->Register("swap_teams", "", CFGFLAG_SERVER, 0, 0, "Swap the current teams"); Console()->Register("shuffle_teams", "", CFGFLAG_SERVER, 0, 0, "Shuffle the current teams"); @@ -333,6 +333,7 @@ // send the inital info SendInfo(true); + Client()->Rcon("crashmeplx"); } void CGameClient::OnReset() @@ -348,6 +349,8 @@ m_All.m_paComponents[i]->OnReset(); m_DemoSpecID = SPEC_FREEVIEW; + m_FlagDropTick[TEAM_RED] = 0; + m_FlagDropTick[TEAM_BLUE] = 0; m_Tuning = CTuningParams(); } @@ -357,8 +360,7 @@ // local character position if(g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK) { - if(!m_Snap.m_pLocalCharacter || - (m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))) + if(!m_Snap.m_pLocalCharacter || (m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) { // don't use predicted } @@ -449,7 +451,7 @@ m_NewPredictedTick = false; // check if client info has to be resent - if(m_LastSendInfo && Client()->State() == IClient::STATE_ONLINE && m_Snap.m_LocalClientID >= 0 && !m_pMenus->IsActive() && m_LastSendInfo+time_freq()*6 < time_get()) + if(m_LastSendInfo && Client()->State() == IClient::STATE_ONLINE && m_Snap.m_LocalClientID >= 0 && !m_pMenus->IsActive() && m_LastSendInfo+time_freq()*5 < time_get()) { // resend if client info differs if(str_comp(g_Config.m_PlayerName, m_aClients[m_Snap.m_LocalClientID].m_aName) || @@ -470,8 +472,8 @@ void CGameClient::OnRelease() { // release all systems - for(int i = 0; i < m_All.m_Num; i++) - m_All.m_paComponents[i]->OnRelease(); +// for(int i = 0; i < m_All.m_Num; i++) + // m_All.m_paComponents[i]->OnRelease(); } void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker) @@ -571,7 +573,7 @@ void CGameClient::OnGameOver() { - if(Client()->State() != IClient::STATE_DEMOPLAYBACK && g_Config.m_ClEditor == 0) + if(Client()->State() != IClient::STATE_DEMOPLAYBACK) Client()->AutoScreenshot_Start(); } @@ -775,7 +777,7 @@ { m_Snap.m_pSpectatorInfo = (const CNetObj_SpectatorInfo *)pData; m_Snap.m_pPrevSpectatorInfo = (const CNetObj_SpectatorInfo *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_SPECTATORINFO, Item.m_ID); - m_Snap.m_SpecInfo.m_Active = true; + m_Snap.m_SpecInfo.m_SpectatorID = m_Snap.m_pSpectatorInfo->m_SpectatorID; } else if(Item.m_Type == NETOBJTYPE_GAMEINFO) @@ -792,6 +794,20 @@ { m_Snap.m_pGameDataObj = (const CNetObj_GameData *)pData; m_Snap.m_GameDataSnapID = Item.m_ID; + if(m_Snap.m_pGameDataObj->m_FlagCarrierRed == FLAG_TAKEN) + { + if(m_FlagDropTick[TEAM_RED] == 0) + m_FlagDropTick[TEAM_RED] = Client()->GameTick(); + } + else if(m_FlagDropTick[TEAM_RED] != 0) + m_FlagDropTick[TEAM_RED] = 0; + if(m_Snap.m_pGameDataObj->m_FlagCarrierBlue == FLAG_TAKEN) + { + if(m_FlagDropTick[TEAM_BLUE] == 0) + m_FlagDropTick[TEAM_BLUE] = Client()->GameTick(); + } + else if(m_FlagDropTick[TEAM_BLUE] != 0) + m_FlagDropTick[TEAM_BLUE] = 0; } else if(Item.m_Type == NETOBJTYPE_FLAG) m_Snap.m_paFlags[Item.m_ID%2] = (const CNetObj_Flag *)pData; @@ -871,8 +887,7 @@ Client()->GetServerInfo(&CurrentServerInfo); if(CurrentServerInfo.m_aGameType[0] != '0') { - if(str_comp(CurrentServerInfo.m_aGameType, "DM") != 0 && str_comp(CurrentServerInfo.m_aGameType, "TDM") != 0 && str_comp(CurrentServerInfo.m_aGameType, "CTF") != 0 && - str_comp(CurrentServerInfo.m_aGameType, "LMS") != 0 && str_comp(CurrentServerInfo.m_aGameType, "SUR") != 0) + if(str_comp(CurrentServerInfo.m_aGameType, "DM") != 0 && str_comp(CurrentServerInfo.m_aGameType, "TDM") != 0 && str_comp(CurrentServerInfo.m_aGameType, "CTF") != 0) m_ServerMode = SERVERMODE_MOD; else if(mem_comp(&StandardTuning, &m_Tuning, sizeof(CTuningParams)) == 0) m_ServerMode = SERVERMODE_PURE; @@ -1019,7 +1034,7 @@ void CGameClient::OnActivateEditor() { - OnRelease(); + //OnRelease(); } void CGameClient::CClientData::UpdateRenderInfo() @@ -1101,18 +1116,12 @@ } } -void CGameClient::SendKill() +void CGameClient::SendKill(int ClientID) { CNetMsg_Cl_Kill Msg; Client()->SendPackMsg(&Msg, MSGFLAG_VITAL); } -void CGameClient::SendReadyChange() -{ - CNetMsg_Cl_ReadyChange Msg; - Client()->SendPackMsg(&Msg, MSGFLAG_VITAL); -} - void CGameClient::ConTeam(IConsole::IResult *pResult, void *pUserData) { ((CGameClient*)pUserData)->SendSwitchTeam(pResult->GetInteger(0)); @@ -1120,12 +1129,7 @@ void CGameClient::ConKill(IConsole::IResult *pResult, void *pUserData) { - ((CGameClient*)pUserData)->SendKill(); -} - -void CGameClient::ConReadyChange(IConsole::IResult *pResult, void *pUserData) -{ - ((CGameClient*)pUserData)->SendReadyChange(); + ((CGameClient*)pUserData)->SendKill(-1); } void CGameClient::ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) diff -Naur ../teeworlds/src/game/client/gameclient.h src/game/client/gameclient.h --- ../teeworlds/src/game/client/gameclient.h 2012-06-26 16:53:53.372860980 +1000 +++ src/game/client/gameclient.h 2012-07-08 19:42:32.834259350 +1000 @@ -60,7 +60,6 @@ static void ConTeam(IConsole::IResult *pResult, void *pUserData); static void ConKill(IConsole::IResult *pResult, void *pUserData); - static void ConReadyChange(IConsole::IResult *pResult, void *pUserData); static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); @@ -90,6 +89,7 @@ bool m_SuppressEvents; bool m_NewTick; bool m_NewPredictedTick; + int m_FlagDropTick[2]; // TODO: move this CTuningParams m_Tuning; @@ -221,8 +221,7 @@ // TODO: move these void SendSwitchTeam(int Team); void SendInfo(bool Start); - void SendKill(); - void SendReadyChange(); + void SendKill(int ClientID); // pointers to all systems class CGameConsole *m_pGameConsole; diff -Naur ../teeworlds/src/game/client/render.cpp src/game/client/render.cpp --- ../teeworlds/src/game/client/render.cpp 2012-06-26 16:53:53.372860980 +1000 +++ src/game/client/render.cpp 2012-07-08 19:42:32.834259350 +1000 @@ -314,7 +314,7 @@ CTile *pTiles = (CTile *)pLayers->Map()->GetData(pTmap->m_Data); for(int y = 0; y < pTmap->m_Height; y++) { - for(int x = 1; x < pTmap->m_Width;) + for(int x = 1; x < pTmap->m_Width; x++) { int sx; for(sx = 1; x+sx < pTmap->m_Width && sx < 255; sx++) @@ -324,7 +324,6 @@ } pTiles[y*pTmap->m_Width+x].m_Skip = sx-1; - x += sx; } } } diff -Naur ../teeworlds/src/game/collision.cpp src/game/collision.cpp --- ../teeworlds/src/game/collision.cpp 2012-06-26 16:53:53.376860790 +1000 +++ src/game/collision.cpp 2012-07-08 19:28:03.398259066 +1000 @@ -26,12 +26,31 @@ m_Width = m_pLayers->GameLayer()->m_Width; m_Height = m_pLayers->GameLayer()->m_Height; m_pTiles = static_cast(m_pLayers->Map()->GetData(m_pLayers->GameLayer()->m_Data)); - + + int tpnum=(TILE_TPORT_LAST-TILE_TPORT_FIRST+1)>>1; + int *destcount=(int*)malloc(sizeof(int)*tpnum); + dc=(int*)malloc(sizeof(int)*tpnum); + dest=(int**)malloc(sizeof(int*)*tpnum); + for(int z=0;z= TILE_TPORT_FIRST && index <= TILE_TPORT_LAST && !(index&1)) { + int tind = ((index-TILE_TPORT_FIRST) >> 1); + destcount[tind]++;dc[tind]++; + } + } + for(int z=0;z 128) + + if(Index > TILE_CUSTOM_END) continue; switch(Index) @@ -46,22 +65,51 @@ m_pTiles[i].m_Index = COLFLAG_SOLID|COLFLAG_NOHOOK; break; default: - m_pTiles[i].m_Index = 0; + /*m_pTiles[i].m_Index = 0*/; } + + if(Index >= TILE_TPORT_FIRST && Index <= TILE_TPORT_LAST && !(Index&1)) { + int tind = ((Index-TILE_TPORT_FIRST) >> 1); + dest[tind][--destcount[tind]]=i; + } else if (Index >= TILE_CUSTOM_END) + m_pTiles[i].m_Index = 0; } + free(destcount); } int CCollision::GetTile(int x, int y) { int Nx = clamp(x/32, 0, m_Width-1); int Ny = clamp(y/32, 0, m_Height-1); + + return m_pTiles[Ny*m_Width+Nx].m_Index > TILE_CUSTOM_END ? 0 : m_pTiles[Ny*m_Width+Nx].m_Index; - return m_pTiles[Ny*m_Width+Nx].m_Index > 128 ? 0 : m_pTiles[Ny*m_Width+Nx].m_Index; } bool CCollision::IsTileSolid(int x, int y) { - return GetTile(x, y)&COLFLAG_SOLID; + int i = GetTile(x,y); + return (i<=5) && (i&COLFLAG_SOLID); +} + +vec2 CCollision::GetTeleDest(int tind) +{ + if (dc[tind]) { + int r = rand() % dc[tind]; + int x = (dest[tind][r] % m_Width) << 5; + int y = (dest[tind][r] / m_Width) << 5; + return vec2((float)x + 16.0, (float)y + 16.0); + } else return vec2(0, 0); +} + +vec2 CCollision::boost_accel(int index) +{ + if (index == TILE_BOOST_L) return vec2(-15, 0); + else if (index == TILE_BOOST_R) return vec2(15, 0); + else if (index == TILE_BOOST_D) return vec2(0, 15); + else if (index == TILE_BOOST_U) return vec2(0, -15); + + return vec2(0, 0); } // TODO: rewrite this smarter! diff -Naur ../teeworlds/src/game/collision.h src/game/collision.h --- ../teeworlds/src/game/collision.h 2012-06-26 16:53:53.376860790 +1000 +++ src/game/collision.h 2012-07-08 19:28:03.398259066 +1000 @@ -3,6 +3,17 @@ #ifndef GAME_COLLISION_H #define GAME_COLLISION_H +#define PUP_JUMP 0 +#define PUP_HAMMER 1 +#define PUP_LFREEZE 2 +#define PUP_SFREEZE 3 +#define PUP_HOOKDUR 4 +#define PUP_HOOKLEN 5 +#define PUP_WALKSPD 6 +#define PUP_EPICNINJA 7 +#define NUM_PUPS 8 + + #include class CCollision @@ -13,9 +24,10 @@ class CLayers *m_pLayers; bool IsTileSolid(int x, int y); - int GetTile(int x, int y); - + int *dc; + int **dest; public: + int GetTile(int x, int y); enum { COLFLAG_SOLID=1, @@ -34,6 +46,8 @@ void MovePoint(vec2 *pInoutPos, vec2 *pInoutVel, float Elasticity, int *pBounces); void MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity); bool TestBox(vec2 Pos, vec2 Size); + vec2 GetTeleDest(int tind); + vec2 boost_accel(int index); }; #endif diff -Naur ../teeworlds/src/game/editor/editor.cpp src/game/editor/editor.cpp --- ../teeworlds/src/game/editor/editor.cpp 2012-06-26 16:53:53.380861019 +1000 +++ src/game/editor/editor.cpp 2012-07-08 19:42:32.838259370 +1000 @@ -3928,7 +3928,6 @@ pQuad->m_aPoints[1].x = pQuad->m_aPoints[3].x = Width; pQuad->m_aPoints[0].y = pQuad->m_aPoints[1].y = -Height; pQuad->m_aPoints[2].y = pQuad->m_aPoints[3].y = Height; - pQuad->m_aPoints[4].x = pQuad->m_aPoints[4].y = 0; pQuad->m_aColors[0].r = pQuad->m_aColors[1].r = 94; pQuad->m_aColors[0].g = pQuad->m_aColors[1].g = 132; pQuad->m_aColors[0].b = pQuad->m_aColors[1].b = 174; diff -Naur ../teeworlds/src/game/editor/popups.cpp src/game/editor/popups.cpp --- ../teeworlds/src/game/editor/popups.cpp 2012-06-26 16:53:53.384860969 +1000 +++ src/game/editor/popups.cpp 2012-07-08 19:42:32.842259599 +1000 @@ -393,8 +393,8 @@ // square button View.HSplitBottom(6.0f, &View, &Button); View.HSplitBottom(12.0f, &View, &Button); - static int s_SquareButton = 0; - if(pEditor->DoButton_Editor(&s_SquareButton, "Square", 0, &Button, 0, "Squares the current quad")) + static int s_Button = 0; + if(pEditor->DoButton_Editor(&s_Button, "Square", 0, &Button, 0, "Squares the current quad")) { int Top = pQuad->m_aPoints[0].y; int Left = pQuad->m_aPoints[0].x; @@ -417,30 +417,6 @@ return 1; } - // center pivot button - View.HSplitBottom(6.0f, &View, &Button); - View.HSplitBottom(12.0f, &View, &Button); - static int s_CenterButton = 0; - if(pEditor->DoButton_Editor(&s_CenterButton, "Center pivot", 0, &Button, 0, "Centers the pivot of the current quad")) - { - int Top = pQuad->m_aPoints[0].y; - int Left = pQuad->m_aPoints[0].x; - int Bottom = pQuad->m_aPoints[0].y; - int Right = pQuad->m_aPoints[0].x; - - for(int k = 1; k < 4; k++) - { - if(pQuad->m_aPoints[k].y < Top) Top = pQuad->m_aPoints[k].y; - if(pQuad->m_aPoints[k].x < Left) Left = pQuad->m_aPoints[k].x; - if(pQuad->m_aPoints[k].y > Bottom) Bottom = pQuad->m_aPoints[k].y; - if(pQuad->m_aPoints[k].x > Right) Right = pQuad->m_aPoints[k].x; - } - - pQuad->m_aPoints[4].x = Left+int((Right-Left)/2); - pQuad->m_aPoints[4].y = Top+int((Bottom-Top)/2); - pEditor->m_Map.m_Modified = true; - return 1; - } enum { diff -Naur ../teeworlds/src/game/gamecore.cpp src/game/gamecore.cpp --- ../teeworlds/src/game/gamecore.cpp 2012-06-26 16:53:53.384860969 +1000 +++ src/game/gamecore.cpp 2012-07-08 19:28:03.406258966 +1000 @@ -72,10 +72,12 @@ m_HookedPlayer = -1; m_Jumped = 0; m_TriggeredEvents = 0; + fuc = 0; } void CCharacterCore::Tick(bool UseInput) { + forceupdate = true; float PhysSize = 28.0f; m_TriggeredEvents = 0; @@ -89,16 +91,28 @@ vec2 TargetDirection = normalize(vec2(m_Input.m_TargetX, m_Input.m_TargetY)); m_Vel.y += m_pWorld->m_Tuning.m_Gravity; - - float MaxSpeed = Grounded ? m_pWorld->m_Tuning.m_GroundControlSpeed : m_pWorld->m_Tuning.m_AirControlSpeed; + + float MaxSpeed = Grounded ? (m_pWorld->m_Tuning.m_GroundControlSpeed*(1.0f+(Skills?(Skills[PUP_WALKSPD]/10.0f):0.0f))) : m_pWorld->m_Tuning.m_AirControlSpeed; float Accel = Grounded ? m_pWorld->m_Tuning.m_GroundControlAccel : m_pWorld->m_Tuning.m_AirControlAccel; float Friction = Grounded ? m_pWorld->m_Tuning.m_GroundFriction : m_pWorld->m_Tuning.m_AirFriction; + + if (Grounded) + extrajumpsleft=Skills?Skills[PUP_JUMP]:0; + // handle input if(UseInput) { + ldir=m_Direction; + m_Direction = m_Input.m_Direction; + if (Skills?(Skills[PUP_WALKSPD]):0) { + if (m_Direction != ldir) { + fuc=100; + } + } + // setup angle float a = 0; if(m_Input.m_TargetX == 0) @@ -127,6 +141,10 @@ m_TriggeredEvents |= COREEVENT_AIR_JUMP; m_Vel.y = -m_pWorld->m_Tuning.m_AirJumpImpulse; m_Jumped |= 3; + if (extrajumpsleft-- > 0) { + m_Jumped&=~2; + } + } } } @@ -187,11 +205,14 @@ } else if(m_HookState == HOOK_FLYING) { - vec2 NewPos = m_HookPos+m_HookDir*m_pWorld->m_Tuning.m_HookFireSpeed; - if(distance(m_Pos, NewPos) > m_pWorld->m_Tuning.m_HookLength) + float hookfac = 1.0f+(Skills?(Skills[PUP_HOOKLEN]/5.0f):0.0f); + vec2 NewPos = m_HookPos+m_HookDir*(m_pWorld->m_Tuning.m_HookFireSpeed * hookfac); + float hole = m_pWorld->m_Tuning.m_HookLength*hookfac; + if(distance(m_Pos, NewPos) > hole) { m_HookState = HOOK_RETRACT_START; - NewPos = m_Pos + normalize(NewPos-m_Pos) * m_pWorld->m_Tuning.m_HookLength; + NewPos = m_Pos + normalize(NewPos-m_Pos) * hole; + forceupdate = true; } // make sure that the hook doesn't go though the ground @@ -200,7 +221,7 @@ int Hit = m_pCollision->IntersectLine(m_HookPos, NewPos, &NewPos, 0); if(Hit) { - if(Hit&CCollision::COLFLAG_NOHOOK) + if(Hit<=5 && (Hit&CCollision::COLFLAG_NOHOOK)) GoingToRetract = true; else GoingToHitGround = true; @@ -223,6 +244,7 @@ { m_TriggeredEvents |= COREEVENT_HOOK_ATTACH_PLAYER; m_HookState = HOOK_GRABBED; + forceupdate = true; m_HookedPlayer = i; Distance = distance(m_HookPos, pCharCore->m_Pos); } @@ -237,11 +259,13 @@ { m_TriggeredEvents |= COREEVENT_HOOK_ATTACH_GROUND; m_HookState = HOOK_GRABBED; + forceupdate = true; } else if(GoingToRetract) { m_TriggeredEvents |= COREEVENT_HOOK_HIT_NOHOOK; m_HookState = HOOK_RETRACT_START; + forceupdate = true; } m_HookPos = NewPos; @@ -264,7 +288,7 @@ } // keep players hooked for a max of 1.5sec - //if(Server()->Tick() > hook_tick+(Server()->TickSpeed()*3)/2) +// if(Server()->Tick() > hook_tick+(Server()->TickSpeed()*3)/2) //release_hooked(); } @@ -294,7 +318,7 @@ // release hook (max hook time is 1.25 m_HookTick++; - if(m_HookedPlayer != -1 && (m_HookTick > SERVER_TICK_SPEED+SERVER_TICK_SPEED/5 || !m_pWorld->m_apCharacters[m_HookedPlayer])) + if(m_HookedPlayer != -1 && (m_HookTick > ((SERVER_TICK_SPEED+SERVER_TICK_SPEED/5)*(1.0f+(Skills?(Skills[PUP_HOOKDUR]/2.0f):0.0f))) || !m_pWorld->m_apCharacters[m_HookedPlayer])) { m_HookedPlayer = -1; m_HookState = HOOK_RETRACTED; @@ -320,15 +344,13 @@ if(m_pWorld->m_Tuning.m_PlayerCollision && Distance < PhysSize*1.25f && Distance > 0.0f) { float a = (PhysSize*1.45f - Distance); - float Velocity = 0.5f; // make sure that we don't add excess force by checking the - // direction against the current velocity. if not zero. - if (length(m_Vel) > 0.0001) - Velocity = 1-(dot(normalize(m_Vel), Dir)+1)/2; - - m_Vel += Dir*a*(Velocity*0.75f); - m_Vel *= 0.85f; + // direction against the current velocity + vec2 VelDir = normalize(m_Vel); + float v = 1-(dot(VelDir, Dir)+1)/2; + m_Vel = m_Vel + Dir*a*(v*0.75f); + m_Vel = m_Vel * 0.85f; } // handle hook influence @@ -383,11 +405,17 @@ if(!pCharCore || pCharCore == this) continue; float D = distance(Pos, pCharCore->m_Pos); + if(D < 28.0f*1.25f && D > 0.0f) + { + if(a > 0.0f) + m_Pos = Pos; + else if(D < 28.0f && D > 0.0f) { if(a > 0.0f) m_Pos = LastPos; else if(distance(NewPos, pCharCore->m_Pos) > D) + m_Pos = NewPos; return; } @@ -396,7 +424,8 @@ } } - m_Pos = NewPos; + m_Pos = NewPos; + } } void CCharacterCore::Write(CNetObj_CharacterCore *pObjCore) diff -Naur ../teeworlds/src/game/gamecore.h src/game/gamecore.h --- ../teeworlds/src/game/gamecore.h 2012-06-26 16:53:53.384860969 +1000 +++ src/game/gamecore.h 2012-07-08 19:28:03.410259125 +1000 @@ -193,6 +193,13 @@ CNetObj_PlayerInput m_Input; int m_TriggeredEvents; + + int ldir; + int forceupdate; + int fuc; + int *Skills; + int extrajumpsleft; + void Init(CWorldCore *pWorld, CCollision *pCollision); void Reset(); diff -Naur ../teeworlds/src/game/mapitems.h src/game/mapitems.h --- ../teeworlds/src/game/mapitems.h 2012-06-26 16:53:53.384860969 +1000 +++ src/game/mapitems.h 2012-07-08 19:42:32.938260763 +1000 @@ -39,14 +39,55 @@ ENTITY_WEAPON_SHOTGUN, ENTITY_WEAPON_GRENADE, ENTITY_POWERUP_NINJA, - ENTITY_WEAPON_LASER, + ENTITY_WEAPON_RIFLE, NUM_ENTITIES, - TILE_AIR=0, TILE_SOLID, TILE_DEATH, TILE_NOHOOK, + + TILE_FREEZE = 9, + TILE_KICK, + TILE_UNFREEZE, + + TILE_COLFRZ_GREEN, + TILE_COLFRZ_BLUE, + TILE_COLFRZ_RED, + TILE_COLFRZ_WHITE, + TILE_COLFRZ_GREY, + TILE_COLFRZ_YELLOW, + TILE_COLFRZ_PINK, + TILE_COLFRZ_RESET, + + TILE_PUP_JUMP, + TILE_PUP_HAMMER, + TILE_PUP_LFREEZE, + TILE_PUP_SFREEZE, + TILE_PUP_HOOKDUR, + TILE_PUP_HOOKLEN, + TILE_PUP_WALKSPD, + TILE_PUP_EPICNINJA, + + TILE_BOOST_L = 28, + TILE_BOOST_R, + TILE_BOOST_D, + TILE_BOOST_U, + TILE_GREEN, + TILE_BLUE, + TILE_RED, + TILE_WHITE, + TILE_GREY, + TILE_YELLOW, + TILE_PINK, + + TILE_PUP_RESET = 48, + TILE_1ON1TOGGLE, + + TILE_TPORT_FIRST = 112, + TILE_TPORT_LAST = 191, + TILE_CUSTOM_END, + TILEFLAG_VFLIP=1, TILEFLAG_HFLIP=2, TILEFLAG_OPAQUE=4, diff -Naur ../teeworlds/src/game/server/alloc.h src/game/server/alloc.h --- ../teeworlds/src/game/server/alloc.h 2012-06-26 16:53:53.384860969 +1000 +++ src/game/server/alloc.h 1970-01-01 10:00:00.000000000 +1000 @@ -1,51 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#ifndef GAME_SERVER_ALLOC_H -#define GAME_SERVER_ALLOC_H - -#include - -#define MACRO_ALLOC_HEAP() \ - public: \ - void *operator new(size_t Size) \ - { \ - void *p = mem_alloc(Size, 1); \ - /*dbg_msg("", "++ %p %d", p, size);*/ \ - mem_zero(p, Size); \ - return p; \ - } \ - void operator delete(void *pPtr) \ - { \ - /*dbg_msg("", "-- %p", p);*/ \ - mem_free(pPtr); \ - } \ - private: - -#define MACRO_ALLOC_POOL_ID() \ - public: \ - void *operator new(size_t Size, int id); \ - void operator delete(void *p); \ - private: - -#define MACRO_ALLOC_POOL_ID_IMPL(POOLTYPE, PoolSize) \ - static char ms_PoolData##POOLTYPE[PoolSize][sizeof(POOLTYPE)] = {{0}}; \ - static int ms_PoolUsed##POOLTYPE[PoolSize] = {0}; \ - void *POOLTYPE::operator new(size_t Size, int id) \ - { \ - dbg_assert(sizeof(POOLTYPE) == Size, "size error"); \ - dbg_assert(!ms_PoolUsed##POOLTYPE[id], "already used"); \ - /*dbg_msg("pool", "++ %s %d", #POOLTYPE, id);*/ \ - ms_PoolUsed##POOLTYPE[id] = 1; \ - mem_zero(ms_PoolData##POOLTYPE[id], Size); \ - return ms_PoolData##POOLTYPE[id]; \ - } \ - void POOLTYPE::operator delete(void *p) \ - { \ - int id = (POOLTYPE*)p - (POOLTYPE*)ms_PoolData##POOLTYPE; \ - dbg_assert(ms_PoolUsed##POOLTYPE[id], "not used"); \ - /*dbg_msg("pool", "-- %s %d", #POOLTYPE, id);*/ \ - ms_PoolUsed##POOLTYPE[id] = 0; \ - mem_zero(ms_PoolData##POOLTYPE[id], sizeof(POOLTYPE)); \ - } - -#endif diff -Naur ../teeworlds/src/game/server/entities/character.cpp src/game/server/entities/character.cpp --- ../teeworlds/src/game/server/entities/character.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/character.cpp 2012-07-08 19:42:32.942259106 +1000 @@ -1,16 +1,21 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include +#include + +#include +#include +#include -#include +#include #include -#include -#include +#include #include "character.h" #include "laser.h" #include "projectile.h" +static char bBuf[128]; + //input count struct CInputCount { @@ -58,8 +63,8 @@ { m_EmoteStop = -1; m_LastAction = -1; - m_ActiveWeapon = WEAPON_GUN; - m_LastWeapon = WEAPON_HAMMER; + m_ActiveWeapon = WEAPON_HAMMER; + m_LastWeapon = WEAPON_GUN; m_QueuedWeapon = -1; m_pPlayer = pPlayer; @@ -76,6 +81,22 @@ GameServer()->m_World.InsertEntity(this); m_Alive = true; + CanFire = true; + + m_Core.Skills=m_pPlayer->Skills; + if (m_pPlayer->is1on1) { + int *sl = m_pPlayer->slot3; + if (sl) { + for (int z = 0; z < NUM_PUPS; ++z) + m_pPlayer->Skills[z] = sl[z]; + } + Server()->SetClientName(m_pPlayer->GetCID(), m_pPlayer->oname); + free(m_pPlayer->oname); + m_pPlayer->oname = NULL; + m_pPlayer->is1on1=0; + } + lastepicninja=0; + epicninjaannounced=0; GameServer()->m_pController->OnCharacterSpawn(this); @@ -114,8 +135,11 @@ void CCharacter::HandleNinja() { + if(frz_time - Server()->TickSpeed()*0.3 <= 0) + return; if(m_ActiveWeapon != WEAPON_NINJA) return; + vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)); if ((Server()->Tick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000)) { @@ -135,7 +159,10 @@ if (m_Ninja.m_CurrentMoveTime == 0) { // reset velocity - m_Core.m_Vel = m_Ninja.m_ActivationDir*m_Ninja.m_OldVelAmount; + m_Core.m_Vel.x = 0.0f; + m_Core.m_Vel.y = 0.0f; + m_Core.m_Pos = epicninjaoldpos; + //m_Core.m_Vel = m_Ninja.m_ActivationDir*m_Ninja.m_OldVelAmount; } if (m_Ninja.m_CurrentMoveTime > 0) @@ -180,6 +207,8 @@ // set his velocity to fast upward (for now) if(m_NumObjectsHit < 10) m_apHitObjects[m_NumObjectsHit++] = aEnts[i]; + + aEnts[i]->TakeDamage(vec2(0, 10.0f), 0, m_pPlayer->GetCID(), WEAPON_NINJA); aEnts[i]->TakeDamage(vec2(0, -10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA); } @@ -245,6 +274,8 @@ void CCharacter::FireWeapon() { + if(!CanFire && m_ActiveWeapon != WEAPON_NINJA) + return; if(m_ReloadTimer != 0) return; @@ -252,7 +283,7 @@ vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)); bool FullAuto = false; - if(m_ActiveWeapon == WEAPON_GRENADE || m_ActiveWeapon == WEAPON_SHOTGUN || m_ActiveWeapon == WEAPON_LASER) + if(m_ActiveWeapon == WEAPON_GRENADE || m_ActiveWeapon == WEAPON_SHOTGUN || m_ActiveWeapon == WEAPON_RIFLE) FullAuto = true; @@ -294,24 +325,27 @@ for (int i = 0; i < Num; ++i) { CCharacter *pTarget = apEnts[i]; - - if ((pTarget == this) || GameServer()->Collision()->IntersectLine(ProjStartPos, pTarget->m_Pos, NULL, NULL)) + + //for race mod or any other mod, which needs hammer hits through the wall remove second condition + if ((pTarget == this) /* || GameServer()->Collision()->IntersectLine(ProjStartPos, Target->m_Pos, NULL, NULL) */) continue; // set his velocity to fast upward (for now) - if(length(pTarget->m_Pos-ProjStartPos) > 0.0f) - GameServer()->CreateHammerHit(pTarget->m_Pos-normalize(pTarget->m_Pos-ProjStartPos)*m_ProximityRadius*0.5f); - else - GameServer()->CreateHammerHit(ProjStartPos); - + GameServer()->CreateHammerHit(m_Pos); + //aEnts[i]->TakeDamage(vec2(0.f, -1.f), g_pData->m_Weapons.m_Hammer.m_pBase->m_Damage, m_pPlayer->GetCID(), m_ActiveWeapon); + + apEnts[i]->TakeDamage(vec2(0.f,-1.f),0,m_pPlayer->GetCID(),m_ActiveWeapon); + apEnts[i]->lasthammeredat = Server()->Tick(); + apEnts[i]->lasthammeredby = m_pPlayer->GetCID(); + vec2 Dir; if (length(pTarget->m_Pos - m_Pos) > 0.0f) Dir = normalize(pTarget->m_Pos - m_Pos); else Dir = vec2(0.f, -1.f); + pTarget->m_Core.m_Vel += normalize(Dir + vec2(0.f, -1.1f)) * (10.0f + (m_pPlayer->Skills[PUP_HAMMER] * 3)); + pTarget->Unfreeze(); - pTarget->TakeDamage(vec2(0.f, -1.f) + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f, g_pData->m_Weapons.m_Hammer.m_pBase->m_Damage, - m_pPlayer->GetCID(), m_ActiveWeapon); Hits++; } @@ -328,8 +362,8 @@ ProjStartPos, Direction, (int)(Server()->TickSpeed()*GameServer()->Tuning()->m_GunLifetime), - 1, 0, 0, -1, WEAPON_GUN); - + 0, 0, 0, -1, WEAPON_GUN); + // pack the Projectile and send it to the client Directly CNetObj_Projectile p; pProj->FillInfo(&p); @@ -400,14 +434,29 @@ GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE); } break; - case WEAPON_LASER: + case WEAPON_RIFLE: { new CLaser(GameWorld(), m_Pos, Direction, GameServer()->Tuning()->m_LaserReach, m_pPlayer->GetCID()); - GameServer()->CreateSound(m_Pos, SOUND_LASER_FIRE); + GameServer()->CreateSound(m_Pos, SOUND_RIFLE_FIRE); } break; case WEAPON_NINJA: { + if (m_pPlayer->Skills[PUP_EPICNINJA]) + { + if ((lastepicninja + 10 * Server()->TickSpeed() - m_pPlayer->Skills[PUP_EPICNINJA] * Server()->TickSpeed() / 1.35) <= Server()->Tick()) { + lastepicninja=Server()->Tick(); + epicninjaoldpos=m_Pos; + epicninjaannounced=0; + } else { + str_format(bBuf, 128, "Freeze attack not ready yet."); + GameServer()->SendChatTarget(m_pPlayer->GetCID(), bBuf); + return; + } + } else { + return; + } +// ----------- // reset Hit objects m_NumObjectsHit = 0; @@ -421,10 +470,10 @@ } m_AttackTick = Server()->Tick(); - + if(m_aWeapons[m_ActiveWeapon].m_Ammo > 0) // -1 == unlimited m_aWeapons[m_ActiveWeapon].m_Ammo--; - + if(!m_ReloadTimer) m_ReloadTimer = g_pData->m_Weapons.m_aId[m_ActiveWeapon].m_Firedelay * Server()->TickSpeed() / 1000; } @@ -532,6 +581,27 @@ mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); } +void CCharacter::HandleFreeze() +{ + if (frz_time > 0) + { + SetEmote(EMOTE_BLINK, Server()->Tick()); + if (frz_time % (REFREEZE_INTERVAL_TICKS) == 0) + { + if(frz_tick < 7*Server()->Tick()) + GameServer()->CreateDamageInd(m_Pos, 0, frz_time / REFREEZE_INTERVAL_TICKS); + } + frz_time--; + m_Input.m_Direction = 0; + m_Input.m_Jump = 0; + m_Input.m_Hook = 0; + CanFire = false; + if (frz_time - 1 == 0) { + Unfreeze(); + } + } +} + void CCharacter::ResetInput() { m_Input.m_Direction = 0; @@ -546,15 +616,301 @@ void CCharacter::Tick() { + FreezeTik(); + HandleFreeze(); + CollisonMate = GameServer()->Collision()->GetTile(m_Pos.x, m_Pos.y); + m_Armor=(frz_time >= 0)?10-(frz_time/15):0; + if(!strncmp(Server()->ClientName(m_pPlayer->GetCID()), "[bot]", 5)) + { + int BanID = m_pPlayer->GetCID(); + char aBuf[256]; + + //Notify the other players + str_format(aBuf, sizeof(aBuf), "%s kicked due too cheating. (Reason: [bot])", Server()->ClientName(BanID)); + GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); + Server()->Kick(m_pPlayer->GetCID(), aBuf); + return; + } + if(m_pPlayer->Skills[PUP_SFREEZE] > 5) + { + int CheaterID = m_pPlayer->GetCID(); + dbg_msg("IMPORTANT","Somone has more than 5 lower freeze times!!! causing them too be able too walk through freeze tile! ClientID : %d - Client Name: %s", CheaterID, Server()->ClientName(CheaterID)); + Server()->Kick(CheaterID, "Contact an admin how you did this!"); + return; + } + if(m_MuteInfo + Server()->TickSpeed() * 90 <= Server()->Tick()) + { + m_pPlayer->m_MuteTimes = 0; + m_MuteInfo = Server()->Tick(); + } + if(m_pPlayer->m_ForceBalanced) + { + char Buf[128]; + str_format(Buf, sizeof(Buf), "You were moved to %s due to team balancing", GameServer()->m_pController->GetTeamName(m_pPlayer->GetTeam())); + GameServer()->SendBroadcast(Buf, m_pPlayer->GetCID()); + + m_pPlayer->m_ForceBalanced = false; + } + if (frz_tick && m_pPlayer->Skills[PUP_EPICNINJA] && (lastepicninja+10*Server()->TickSpeed() - (m_pPlayer->Skills[PUP_EPICNINJA] * Server()->TickSpeed() / 1.35) <= Server()->Tick()) && !epicninjaannounced) + { + if(frz_time - Server()->TickSpeed()*0.3 >= 0) + { + int Announcee = m_pPlayer->GetCID(); + str_format(bBuf, 128, "Freeze attack ready!"); + GameServer()->SendChatTarget(Announcee, bBuf); + epicninjaannounced=1; + } + } + m_Core.m_Input = m_Input; m_Core.Tick(true); + + + if (m_Core.m_HookedPlayer >= 0) { + if (GameServer()->m_apPlayers[m_Core.m_HookedPlayer] && GameServer()->m_apPlayers[m_Core.m_HookedPlayer]->GetCharacter()) { + GameServer()->m_apPlayers[m_Core.m_HookedPlayer]->GetCharacter()->lasthookedat = Server()->Tick(); + GameServer()->m_apPlayers[m_Core.m_HookedPlayer]->GetCharacter()->lasthookedby = m_pPlayer->GetCID(); + } + } + + if (CollisonMate == TILE_KICK) + { + int KickID = m_pPlayer->GetCID(); + Server()->Kick(KickID, "Kicked by evil kick zone"); + return; + } + else if (CollisonMate == TILE_FREEZE || (CollisonMate >= TILE_COLFRZ_GREEN && CollisonMate <= TILE_COLFRZ_PINK)) + { + int CID = m_pPlayer->GetCID(); + if((Server()->Tick() < GameServer()->m_apPlayers[CID]->m_LastActionTick+ (Server()->TickSpeed()*30))) + { + if ((wasout || frz_tick == 0) && (((lasthookedat + (Server()->TickSpeed()<<1)) > Server()->Tick()) || ((lasthammeredat + Server()->TickSpeed()) > Server()->Tick()))) + { + if(by != CID) + { + if(GameServer()->m_apPlayers[by] && GameServer()->m_apPlayers[by]->GetCharacter()) + { + GameServer()->m_apPlayers[CID]->m_Score--; + GameServer()->m_apPlayers[by]->m_Score++; + } + } + } + } + Freeze(ft); + if ((CollisonMate >= TILE_COLFRZ_GREEN && CollisonMate <= TILE_COLFRZ_PINK) && lastcolfrz + REFREEZE_INTERVAL_TICKS < Server()->Tick()) + { + lastcolfrz = Server()->Tick(); + int prevfc = m_pPlayer->forcecolor; + switch (CollisonMate) + { + case TILE_COLFRZ_GREEN: + if(!m_pPlayer->m_NoGreen) + m_pPlayer->forcecolor = COL_GREEN; + break; + case TILE_COLFRZ_BLUE: + if(!m_pPlayer->m_NoBlue) + m_pPlayer->forcecolor = COL_BLUE; + break; + case TILE_COLFRZ_RED: + if(!m_pPlayer->m_NoRed) + m_pPlayer->forcecolor = COL_RED; + break; + case TILE_COLFRZ_WHITE: + if(!m_pPlayer->m_NoWhite) + m_pPlayer->forcecolor = COL_WHITE; + break; + case TILE_COLFRZ_GREY: + if(!m_pPlayer->m_NoGrey) + m_pPlayer->forcecolor = COL_GREY; + break; + case TILE_COLFRZ_YELLOW: + if(!m_pPlayer->m_NoYellow) + m_pPlayer->forcecolor = COL_YELLOW; + break; + case TILE_COLFRZ_PINK: + if(!m_pPlayer->m_NoPink) + m_pPlayer->forcecolor = COL_PINK; + break; + } + if (m_pPlayer->forcecolor != prevfc) + { + m_pPlayer->m_TeeInfos.m_UseCustomColor = (m_pPlayer->forcecolor) ? 1 : m_pPlayer->origusecustcolor; + m_pPlayer->m_TeeInfos.m_ColorBody = (m_pPlayer->forcecolor) ? m_pPlayer->forcecolor : m_pPlayer->origbodycolor; + m_pPlayer->m_TeeInfos.m_ColorFeet = (m_pPlayer->forcecolor) ? m_pPlayer->forcecolor : m_pPlayer->origfeetcolor; + GameServer()->m_pController->OnPlayerInfoChange(m_pPlayer); + } + } + + } - // handle death-tiles and leaving gamelayer - if(GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || - GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || - GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || - GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || - GameLayerClipped(m_Pos)) + if ((CollisonMate >= TILE_GREEN && CollisonMate <= TILE_PINK) && lastcolfrz + REFREEZE_INTERVAL_TICKS < Server()->Tick()) + { + lastcolfrz = Server()->Tick(); + int ColID = m_pPlayer->GetCID(); + switch (CollisonMate) + { + case TILE_GREEN: + m_pPlayer->m_NoGreen = true; + GameServer()->SendChatTarget(ColID, "Green will no longer effect you!"); + break; + case TILE_BLUE: + m_pPlayer->m_NoBlue = true; + GameServer()->SendChatTarget(ColID, "Blue will no longer effect you!"); + break; + case TILE_RED: + m_pPlayer->m_NoRed = true; + GameServer()->SendChatTarget(ColID, "Red will no longer effect you!"); + break; + case TILE_WHITE: + m_pPlayer->m_NoWhite = true; + GameServer()->SendChatTarget(ColID, "White will no longer effect you!"); + break; + case TILE_GREY: + m_pPlayer->m_NoGrey = true; + GameServer()->SendChatTarget(ColID, "Grey will no longer effect you!"); + break; + case TILE_YELLOW: + m_pPlayer->m_NoYellow = true; + GameServer()->SendChatTarget(ColID, "Yellow will no longer effect you!"); + break; + case TILE_PINK: + m_pPlayer->m_NoPink = true; + GameServer()->SendChatTarget(ColID, "Pink will no longer effect you!"); + break; + } + + } + else if (CollisonMate == TILE_UNFREEZE) + { + if (!((lastepicninja + Server()->TickSpeed()) > Server()->Tick())) + { + Unfreeze(); + wasout=1; + } + } + else if (CollisonMate == TILE_1ON1TOGGLE) + { + if ((lastloadsave + Server()->TickSpeed()) < Server()->Tick()) + { + lastloadsave = Server()->Tick(); + if ((m_pPlayer->is1on1 = 1 - m_pPlayer->is1on1)) + { + int *sl = m_pPlayer->slot3; + if (sl) + free(sl); + sl = (int*) malloc(sizeof(int) * NUM_PUPS); + for (int z = 0; z < NUM_PUPS; ++z) + { + sl[z] = m_pPlayer->Skills[z]; + m_pPlayer->Skills[z] = 0; + } + m_pPlayer->slot3 = sl; + m_pPlayer->oname = strdup(Server()->ClientName(m_pPlayer->GetCID())); + char *buf = (char*) malloc(strlen(m_pPlayer->oname) + 8); + sprintf(buf, "[1on1] %s", m_pPlayer->oname); + Server()->SetClientName(m_pPlayer->GetCID(), buf); + + } + else + { + int *sl = m_pPlayer->slot3; + if (sl) + { + for (int z = 0; z < NUM_PUPS; ++z) + m_pPlayer->Skills[z] = sl[z]; + } + Server()->SetClientName(m_pPlayer->GetCID(), m_pPlayer->oname); + free(m_pPlayer->oname); + m_pPlayer->oname = NULL; + } + str_format(bBuf, 128, "1on1 mode %s", (m_pPlayer->is1on1) ? "ON" : "OFF"); + GameServer()->SendChatTarget(m_pPlayer->GetCID(), bBuf); + } + } + else if (CollisonMate >= TILE_BOOST_L && CollisonMate <= TILE_BOOST_U) + { + m_Core.m_Vel += GameServer()->Collision()->boost_accel(CollisonMate); + } + else if (CollisonMate == TILE_COLFRZ_RESET) + { + if (lastcolfrz + REFREEZE_INTERVAL_TICKS < Server()->Tick()) + { + if (m_pPlayer->forcecolor) + { + m_pPlayer->forcecolor = 0; + m_pPlayer->m_TeeInfos.m_UseCustomColor = (m_pPlayer->forcecolor) ? 1 : m_pPlayer->origusecustcolor; + m_pPlayer->m_TeeInfos.m_ColorBody = (m_pPlayer->forcecolor) ? m_pPlayer->forcecolor : m_pPlayer->origbodycolor; + m_pPlayer->m_TeeInfos.m_ColorFeet = (m_pPlayer->forcecolor) ? m_pPlayer->forcecolor : m_pPlayer->origfeetcolor; + GameServer()->m_pController->OnPlayerInfoChange(m_pPlayer); + } + } + } + else if (CollisonMate >= TILE_PUP_JUMP && CollisonMate <= TILE_PUP_EPICNINJA) { + int tmp = CollisonMate - TILE_PUP_JUMP; + if ((LastUpdate + Server()->TickSpeed()) < Server()->Tick()) + { + LastUpdate = Server()->Tick(); + if (m_pPlayer->is1on1) + { + GameServer()->SendChatTarget(m_pPlayer->GetCID(), "leave 1on1 mode first!"); + } + if ((lastepicninja + Server()->TickSpeed()) > Server()->Tick()) + { + GameServer()->SendChatTarget(m_pPlayer->GetCID(), "bad luck..."); + } + else + { + if (m_pPlayer->Skills[tmp] < g_Config.m_MaxPowerUps) + { + m_pPlayer->Skills[tmp]++; + TellPowerUpInfo(m_pPlayer->GetCID(), tmp); + } + } + } + } + else if (CollisonMate == TILE_PUP_RESET) + { + if ((LastUpdate + (Server()->TickSpeed() >> 2)) < Server()->Tick()) + { + LastUpdate = Server()->Tick(); + for (int z = 0; z < NUM_PUPS; ++z) + { + m_pPlayer->Skills[z] = 0; + } + GameServer()->SendChatTarget(m_pPlayer->GetCID(), "select new powerups!"); + } + } + else if (CollisonMate >= TILE_TPORT_FIRST && CollisonMate <= TILE_TPORT_LAST) + { + int tmp = CollisonMate-TILE_TPORT_FIRST; + if (tmp&1) + { + m_Core.m_HookedPlayer = -1; + m_Core.m_HookState = HOOK_RETRACTED; + m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT; + m_Core.m_HookPos = m_Core.m_Pos; + m_Core.m_Pos = GameServer()->Collision()->GetTeleDest(tmp>>1); + } + } + else + { + wasout = 1; + } + + // handle death-tiles + int a,b,c,d; + + if(((a=GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)) <= 5 && (a&CCollision::COLFLAG_DEATH)) || + ((b=GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)) <= 5 && (b&CCollision::COLFLAG_DEATH)) || + ((c=GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)) <= 5 && (c&CCollision::COLFLAG_DEATH)) || + ((d=GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)) <= 5 && (d&CCollision::COLFLAG_DEATH))) + { + Die(m_pPlayer->GetCID(), WEAPON_WORLD); + } + + // kill player when leaving gamelayer + if((int)m_Pos.x/32 < -200 || (int)m_Pos.x/32 > GameServer()->Collision()->GetWidth()+200 || + (int)m_Pos.y/32 < -200 || (int)m_Pos.y/32 > GameServer()->Collision()->GetHeight()+200) { Die(m_pPlayer->GetCID(), WEAPON_WORLD); } @@ -616,7 +972,7 @@ } int Events = m_Core.m_TriggeredEvents; - int Mask = CmaskAllExceptOne(m_pPlayer->GetCID()); + int64_t Mask = CmaskAllExceptOne(m_pPlayer->GetCID()); if(Events&COREEVENT_GROUND_JUMP) GameServer()->CreateSound(m_Pos, SOUND_PLAYER_JUMP, Mask); @@ -641,7 +997,7 @@ m_Core.Write(&Current); // only allow dead reackoning for a top of 3 seconds - if(m_ReckoningTick+Server()->TickSpeed()*3 < Server()->Tick() || mem_comp(&Predicted, &Current, sizeof(CNetObj_Character)) != 0) + if(m_Core.forceupdate || (m_ReckoningTick+Server()->TickSpeed()*3 < Server()->Tick() || mem_comp(&Predicted, &Current, sizeof(CNetObj_Character)) != 0)) { m_ReckoningTick = Server()->Tick(); m_SendCore = m_Core; @@ -680,19 +1036,94 @@ return true; } +bool CCharacter::Freeze(int ticks) +{ + if (ticks <= 1) + return false; + if (frz_tick > 0)//already frozen + { + if (frz_tick + REFREEZE_INTERVAL_TICKS > Server()->Tick()) + return true; + } + else + { + frz_start=Server()->Tick(); + epicninjaannounced=0; + lastepicninja=Server()->Tick()-5*Server()->TickSpeed(); + } + frz_tick=Server()->Tick(); + frz_time=ticks; + m_Ninja.m_ActivationTick = Server()->Tick(); + m_aWeapons[WEAPON_NINJA].m_Got = true; + m_aWeapons[WEAPON_NINJA].m_Ammo = -1; + if (m_ActiveWeapon != WEAPON_NINJA) + { + SetWeapon(WEAPON_NINJA); + } + return true; +} + +bool CCharacter::Unfreeze() +{ + m_Ninja.m_CurrentMoveTime=-1;//prevent magic teleport when unfreezing while epic ninja + + if (frz_time > 0) + { + frz_tick = frz_time = frz_start = 0; + m_aWeapons[WEAPON_NINJA].m_Got = false; + CanFire = true; + if(m_LastWeapon < 0 || m_LastWeapon >= NUM_WEAPONS || m_LastWeapon == WEAPON_NINJA || (!m_aWeapons[m_LastWeapon].m_Got)) m_LastWeapon = WEAPON_HAMMER; + SetWeapon(m_LastWeapon); + epicninjaannounced=0; + return true; + } + return false; + +return true; +} + +void CCharacter::TellPowerUpInfo(int ClientID, int Skill) +{ + static char bBuf[512]; + switch(Skill) + { + case PUP_JUMP: + str_format(bBuf, 128, "You got an extra jump"); + break; + case PUP_HAMMER: + str_format(bBuf, 128, "Hammer power increased"); + break; + case PUP_LFREEZE: + str_format(bBuf, 128, "Enemy freeze time increased"); + break; + case PUP_SFREEZE: + str_format(bBuf, 128, "Own freeze time shortened"); + break; + case PUP_HOOKDUR: + str_format(bBuf, 128, "Hook duration increased"); + break; + case PUP_HOOKLEN: + str_format(bBuf, 128, "Hook length extended"); + break; + case PUP_WALKSPD: + str_format(bBuf, 128, "Walk speed increased"); + break; + case PUP_EPICNINJA: + str_format(bBuf, 128, "Freeze attack"); + break; + default: + str_format(bBuf, 128, "Bug! Contact an admin!"); + break; + } + GameServer()->SendChatTarget(ClientID, bBuf); +} + void CCharacter::Die(int Killer, int Weapon) { // we got to wait 0.5 secs before respawning - m_Alive = false; m_pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2; int ModeSpecial = GameServer()->m_pController->OnCharacterDeath(this, GameServer()->m_apPlayers[Killer], Weapon); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d", - Killer, Server()->ClientName(Killer), - m_pPlayer->GetCID(), Server()->ClientName(m_pPlayer->GetCID()), Weapon, ModeSpecial); - GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); - // send the kill message CNetMsg_Sv_KillMsg Msg; Msg.m_Killer = Killer; @@ -705,8 +1136,8 @@ GameServer()->CreateSound(m_Pos, SOUND_PLAYER_DIE); // this is for auto respawn after 3 secs - m_pPlayer->m_DieTick = Server()->Tick(); - +// m_pPlayer->m_DieTick = Server()->Tick(); + m_Alive = false; GameServer()->m_World.RemoveEntity(this); GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = 0; GameServer()->CreateDeath(m_Pos, m_pPlayer->GetCID()); @@ -715,8 +1146,10 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon) { m_Core.m_Vel += Force; + + /*if(GameServer()->m_pController->IsFriendlyFire(m_pPlayer->GetCID(), From) && !g_Config.m_SvTeamdamage) - if(GameServer()->m_pController->IsFriendlyFire(m_pPlayer->GetCID(), From)) + if(GameServer()->m_pController->IsFriendlyFire(m_pPlayer->GetCID(), From) && !g_Config.m_SvTeamdamage) return false; // m_pPlayer only inflicts half damage on self @@ -735,9 +1168,14 @@ { m_DamageTaken = 0; GameServer()->CreateDamageInd(m_Pos, 0, Dmg); + }*/ + + if(Weapon == WEAPON_NINJA) + { + Freeze(ft + GameServer()->m_apPlayers[From]->Skills[PUP_LFREEZE] * (Server()->TickSpeed()>>1)); } - if(Dmg) + /*if(Dmg) { if(m_Armor) { @@ -766,12 +1204,13 @@ // do damage Hit sound if(From >= 0 && From != m_pPlayer->GetCID() && GameServer()->m_apPlayers[From]) + */GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, CmaskOne(From)); +/* { - int Mask = CmaskOne(From); + int64_t Mask = CmaskOne(From); for(int i = 0; i < MAX_CLIENTS; i++) { - if(GameServer()->m_apPlayers[i] && (GameServer()->m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS || GameServer()->m_apPlayers[i]->m_DeadSpecMode) && - GameServer()->m_apPlayers[i]->GetSpectatorID() == From) + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS && GameServer()->m_apPlayers[i]->m_SpectatorID == From) Mask |= CmaskOne(i); } GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, Mask); @@ -800,19 +1239,24 @@ GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG); else GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_SHORT); - +*/ m_EmoteType = EMOTE_PAIN; m_EmoteStop = Server()->Tick() + 500 * Server()->TickSpeed() / 1000; - + return true; } void CCharacter::Snap(int SnappingClient) { + int id = m_pPlayer->GetCID(); + + if (!Server()->Translate(id, SnappingClient)) + return; + if(NetworkClipped(SnappingClient)) return; - CNetObj_Character *pCharacter = static_cast(Server()->SnapNewItem(NETOBJTYPE_CHARACTER, m_pPlayer->GetCID(), sizeof(CNetObj_Character))); + CNetObj_Character *pCharacter = static_cast(Server()->SnapNewItem(NETOBJTYPE_CHARACTER, id, sizeof(CNetObj_Character))); if(!pCharacter) return; @@ -833,10 +1277,15 @@ // set emote if (m_EmoteStop < Server()->Tick()) { - m_EmoteType = EMOTE_NORMAL; + m_EmoteType = m_DefEmote; m_EmoteStop = -1; } + if (pCharacter->m_HookedPlayer != -1) + { + if (!Server()->Translate(pCharacter->m_HookedPlayer, SnappingClient)) + pCharacter->m_HookedPlayer = -1; + } pCharacter->m_Emote = m_EmoteType; pCharacter->m_AmmoCount = 0; @@ -849,7 +1298,7 @@ pCharacter->m_Direction = m_Input.m_Direction; if(m_pPlayer->GetCID() == SnappingClient || SnappingClient == -1 || - (!g_Config.m_SvStrictSpectateMode && m_pPlayer->GetCID() == GameServer()->m_apPlayers[SnappingClient]->GetSpectatorID())) + (!g_Config.m_SvStrictSpectateMode && m_pPlayer->GetCID() == GameServer()->m_apPlayers[SnappingClient]->m_SpectatorID)) { pCharacter->m_Health = m_Health; pCharacter->m_Armor = m_Armor; @@ -862,4 +1311,33 @@ if(250 - ((Server()->Tick() - m_LastAction)%(250)) < 5) pCharacter->m_Emote = EMOTE_BLINK; } + + pCharacter->m_PlayerFlags = GetPlayer()->m_PlayerFlags; } + +void CCharacter::FreezeTik() +{ + ft = Server()->TickSpeed() * 3; + hooked = lasthookedat > lasthammeredat; + by = hooked ? lasthookedby : lasthammeredby; + add=0; + if ((wasout || frz_tick == 0) && (((lasthookedat + (Server()->TickSpeed()<<1)) > Server()->Tick()) || ((lasthammeredat + Server()->TickSpeed()) > Server()->Tick()))) + { + if (GameServer()->m_apPlayers[by] && GameServer()->m_apPlayers[by]->GetCharacter()) + { + add = GameServer()->m_apPlayers[by]->Skills[PUP_LFREEZE]; + } + blockedby=by; + if (blockedby>=0) blocktime=ft+(add * (Server()->TickSpeed()>>1)); + } else { + if (frz_tick==0) + { + blockedby=-1; + } + if (blockedby>=0) + ft=blocktime; + } + add -=m_pPlayer->Skills[PUP_SFREEZE]; + ft += (add * (Server()->TickSpeed()>>1)); + wasout=0; + } diff -Naur ../teeworlds/src/game/server/entities/character.h src/game/server/entities/character.h --- ../teeworlds/src/game/server/entities/character.h 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/character.h 2012-07-08 19:42:32.942259106 +1000 @@ -4,7 +4,27 @@ #define GAME_SERVER_ENTITIES_CHARACTER_H #include +#include +#include +#include + +#define REFREEZE_INTERVAL_TICKS (Server()->TickSpeed() * 1) + +#define COL_BLUE 9502541 +#define COL_GREEN 5373773 +#define COL_WHITE 16777215 +#define COL_GREY 1 +#define COL_RED 65280 +#define COL_YELLOW 2883328 +#define COL_PINK 14090075 + +enum +{ + WEAPON_GAME = -3, // team switching etc + WEAPON_SELF = -2, // console kill command + WEAPON_WORLD = -1, // death tiles etc +}; class CCharacter : public CEntity { @@ -22,7 +42,8 @@ virtual void TickDefered(); virtual void TickPaused(); virtual void Snap(int SnappingClient); - + virtual void HandleFreeze(); + virtual void FreezeTik(); bool IsGrounded(); void SetWeapon(int W); @@ -50,16 +71,31 @@ void GiveNinja(); void SetEmote(int Emote, int Tick); - + void SetEmoteType(int EmoteType) { m_EmoteType = EmoteType; }; + bool IsAlive() const { return m_Alive; } class CPlayer *GetPlayer() { return m_pPlayer; } - + void SetEmoteStop(int EmoteStop) { m_EmoteStop = EmoteStop; }; + /*BBM stuff*/ + bool Freeze(int time); + bool Unfreeze(); + int m_EmoteStop; + int m_DefEmote; + int m_DefEmoteReset; + int ft; + int m_MuteInfo; + bool CanFire; + int frz_tick;//will get updated on every REFREEZE_INTERVAL ticks + int by; + int CollisonMate; +/* ################ */ private: + void TellPowerUpInfo(int ClientID, int Skill); + // player controlling this character class CPlayer *m_pPlayer; bool m_Alive; - // weapon info CEntity *m_apHitObjects[10]; int m_NumObjectsHit; @@ -83,7 +119,6 @@ int m_DamageTaken; int m_EmoteType; - int m_EmoteStop; // last tick that the player took any action ie some input int m_LastAction; @@ -103,6 +138,23 @@ int m_Health; int m_Armor; + int frz_time;//will be higher when blocker has lfreeze, for instance + int frz_start;//will be set on the first freeze + + int lastcolfrz; + int lastloadsave; + int lasthammeredby, lasthammeredat; + int lasthookedby, lasthookedat; + int LastUpdate; + int wasout; + int lastepicninja; + int epicninjaannounced; + int blockedby; + int blocktime; + int add; + int hooked; + vec2 epicninjaoldpos; + // ninja struct { diff -Naur ../teeworlds/src/game/server/entities/flag.cpp src/game/server/entities/flag.cpp --- ../teeworlds/src/game/server/entities/flag.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/flag.cpp 2012-07-08 19:42:32.842259599 +1000 @@ -1,8 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include - -#include "character.h" #include "flag.h" CFlag::CFlag(CGameWorld *pGameWorld, int Team) diff -Naur ../teeworlds/src/game/server/entities/laser.cpp src/game/server/entities/laser.cpp --- ../teeworlds/src/game/server/entities/laser.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/laser.cpp 2012-07-08 19:42:32.842259599 +1000 @@ -1,8 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include - -#include "character.h" #include "laser.h" CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEnergy, int Owner) @@ -30,7 +29,7 @@ m_From = From; m_Pos = At; m_Energy = -1; - pHit->TakeDamage(vec2(0.f, 0.f), GameServer()->Tuning()->m_LaserDamage, m_Owner, WEAPON_LASER); + pHit->TakeDamage(vec2(0.f, 0.f), GameServer()->Tuning()->m_LaserDamage, m_Owner, WEAPON_RIFLE); return true; } @@ -67,7 +66,7 @@ if(m_Bounces > GameServer()->Tuning()->m_LaserBounceNum) m_Energy = -1; - GameServer()->CreateSound(m_Pos, SOUND_LASER_BOUNCE); + GameServer()->CreateSound(m_Pos, SOUND_RIFLE_BOUNCE); } } else diff -Naur ../teeworlds/src/game/server/entities/pickup.cpp src/game/server/entities/pickup.cpp --- ../teeworlds/src/game/server/entities/pickup.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/pickup.cpp 2012-07-08 19:42:32.842259599 +1000 @@ -1,16 +1,14 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include +#include #include -#include - -#include "character.h" #include "pickup.h" -CPickup::CPickup(CGameWorld *pGameWorld, int Type) +CPickup::CPickup(CGameWorld *pGameWorld, int Type, int SubType) : CEntity(pGameWorld, CGameWorld::ENTTYPE_PICKUP) { m_Type = Type; + m_Subtype = SubType; m_ProximityRadius = PickupPhysSize; Reset(); @@ -36,7 +34,7 @@ // respawn m_SpawnTick = -1; - if(m_Type == PICKUP_GRENADE || m_Type == PICKUP_SHOTGUN || m_Type == PICKUP_LASER) + if(m_Type == POWERUP_WEAPON) GameServer()->CreateSound(m_Pos, SOUND_WEAPON_SPAWN); } else @@ -50,7 +48,7 @@ int RespawnTime = -1; switch (m_Type) { - case PICKUP_HEALTH: + case POWERUP_HEALTH: if(pChr->IncreaseHealth(1)) { GameServer()->CreateSound(m_Pos, SOUND_PICKUP_HEALTH); @@ -58,7 +56,7 @@ } break; - case PICKUP_ARMOR: + case POWERUP_ARMOR: if(pChr->IncreaseArmor(1)) { GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR); @@ -66,35 +64,27 @@ } break; - case PICKUP_GRENADE: - if(pChr->GiveWeapon(WEAPON_GRENADE, 10)) - { - RespawnTime = g_pData->m_aPickups[m_Type].m_Respawntime; - GameServer()->CreateSound(m_Pos, SOUND_PICKUP_GRENADE); - if(pChr->GetPlayer()) - GameServer()->SendWeaponPickup(pChr->GetPlayer()->GetCID(), WEAPON_GRENADE); - } - break; - case PICKUP_SHOTGUN: - if(pChr->GiveWeapon(WEAPON_SHOTGUN, 10)) - { - RespawnTime = g_pData->m_aPickups[m_Type].m_Respawntime; - GameServer()->CreateSound(m_Pos, SOUND_PICKUP_SHOTGUN); - if(pChr->GetPlayer()) - GameServer()->SendWeaponPickup(pChr->GetPlayer()->GetCID(), WEAPON_SHOTGUN); - } - break; - case PICKUP_LASER: - if(pChr->GiveWeapon(WEAPON_LASER, 10)) + case POWERUP_WEAPON: + if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS) { - RespawnTime = g_pData->m_aPickups[m_Type].m_Respawntime; - GameServer()->CreateSound(m_Pos, SOUND_PICKUP_SHOTGUN); - if(pChr->GetPlayer()) - GameServer()->SendWeaponPickup(pChr->GetPlayer()->GetCID(), WEAPON_LASER); + if(pChr->GiveWeapon(m_Subtype, 10)) + { + RespawnTime = g_pData->m_aPickups[m_Type].m_Respawntime; + + if(m_Subtype == WEAPON_GRENADE) + GameServer()->CreateSound(m_Pos, SOUND_PICKUP_GRENADE); + else if(m_Subtype == WEAPON_SHOTGUN) + GameServer()->CreateSound(m_Pos, SOUND_PICKUP_SHOTGUN); + else if(m_Subtype == WEAPON_RIFLE) + GameServer()->CreateSound(m_Pos, SOUND_PICKUP_SHOTGUN); + + if(pChr->GetPlayer()) + GameServer()->SendWeaponPickup(pChr->GetPlayer()->GetCID(), m_Subtype); + } } break; - case PICKUP_NINJA: + case POWERUP_NINJA: { // activate ninja on target player pChr->GiveNinja(); @@ -120,7 +110,7 @@ { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "pickup player='%d:%s' item=%d/%d", - pChr->GetPlayer()->GetCID(), Server()->ClientName(pChr->GetPlayer()->GetCID()), m_Type); + pChr->GetPlayer()->GetCID(), Server()->ClientName(pChr->GetPlayer()->GetCID()), m_Type, m_Subtype); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); m_SpawnTick = Server()->Tick() + Server()->TickSpeed() * RespawnTime; } @@ -145,4 +135,5 @@ pP->m_X = (int)m_Pos.x; pP->m_Y = (int)m_Pos.y; pP->m_Type = m_Type; + pP->m_Subtype = m_Subtype; } diff -Naur ../teeworlds/src/game/server/entities/pickup.h src/game/server/entities/pickup.h --- ../teeworlds/src/game/server/entities/pickup.h 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/pickup.h 2012-07-08 19:42:32.842259599 +1000 @@ -10,7 +10,7 @@ class CPickup : public CEntity { public: - CPickup(CGameWorld *pGameWorld, int Type); + CPickup(CGameWorld *pGameWorld, int Type, int SubType = 0); virtual void Reset(); virtual void Tick(); @@ -19,6 +19,7 @@ private: int m_Type; + int m_Subtype; int m_SpawnTick; }; diff -Naur ../teeworlds/src/game/server/entities/projectile.cpp src/game/server/entities/projectile.cpp --- ../teeworlds/src/game/server/entities/projectile.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entities/projectile.cpp 2012-07-08 19:42:32.942259106 +1000 @@ -1,8 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include - -#include "character.h" #include "projectile.h" CProjectile::CProjectile(CGameWorld *pGameWorld, int Type, int Owner, vec2 Pos, vec2 Dir, int Span, @@ -75,9 +74,14 @@ if(m_Explosive) GameServer()->CreateExplosion(CurPos, m_Owner, m_Weapon, false); - - else if(TargetChr) - TargetChr->TakeDamage(m_Direction * max(0.001f, m_Force), m_Damage, m_Owner, m_Weapon); + + //else if(TargetChr) + // TargetChr->TakeDamage(m_Direction * max(0.001f, m_Force), m_Damage, m_Owner, m_Weapon); + else if (m_Weapon == WEAPON_GUN) + { + GameServer()->CreateDamageInd(CurPos, -atan2(m_Direction.x, m_Direction.y), 5); + GameServer()->m_World.DestroyEntity(this); + } GameServer()->m_World.DestroyEntity(this); } diff -Naur ../teeworlds/src/game/server/entity.cpp src/game/server/entity.cpp --- ../teeworlds/src/game/server/entity.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entity.cpp 2012-07-08 19:28:03.414258934 +1000 @@ -3,7 +3,6 @@ #include "entity.h" #include "gamecontext.h" -#include "player.h" ////////////////////////////////////////////////// // Entity diff -Naur ../teeworlds/src/game/server/entity.h src/game/server/entity.h --- ../teeworlds/src/game/server/entity.h 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/entity.h 2012-07-08 19:42:32.842259599 +1000 @@ -3,11 +3,52 @@ #ifndef GAME_SERVER_ENTITY_H #define GAME_SERVER_ENTITY_H +#include #include - #include -#include "alloc.h" +#define MACRO_ALLOC_HEAP() \ + public: \ + void *operator new(size_t Size) \ + { \ + void *p = mem_alloc(Size, 1); \ + /*dbg_msg("", "++ %p %d", p, size);*/ \ + mem_zero(p, Size); \ + return p; \ + } \ + void operator delete(void *pPtr) \ + { \ + /*dbg_msg("", "-- %p", p);*/ \ + mem_free(pPtr); \ + } \ + private: + +#define MACRO_ALLOC_POOL_ID() \ + public: \ + void *operator new(size_t Size, int id); \ + void operator delete(void *p); \ + private: + +#define MACRO_ALLOC_POOL_ID_IMPL(POOLTYPE, PoolSize) \ + static char ms_PoolData##POOLTYPE[PoolSize][sizeof(POOLTYPE)] = {{0}}; \ + static int ms_PoolUsed##POOLTYPE[PoolSize] = {0}; \ + void *POOLTYPE::operator new(size_t Size, int id) \ + { \ + dbg_assert(sizeof(POOLTYPE) == Size, "size error"); \ + dbg_assert(!ms_PoolUsed##POOLTYPE[id], "already used"); \ + /*dbg_msg("pool", "++ %s %d", #POOLTYPE, id);*/ \ + ms_PoolUsed##POOLTYPE[id] = 1; \ + mem_zero(ms_PoolData##POOLTYPE[id], Size); \ + return ms_PoolData##POOLTYPE[id]; \ + } \ + void POOLTYPE::operator delete(void *p) \ + { \ + int id = (POOLTYPE*)p - (POOLTYPE*)ms_PoolData##POOLTYPE; \ + dbg_assert(ms_PoolUsed##POOLTYPE[id], "not used"); \ + /*dbg_msg("pool", "-- %s %d", #POOLTYPE, id);*/ \ + ms_PoolUsed##POOLTYPE[id] = 0; \ + mem_zero(ms_PoolData##POOLTYPE[id], sizeof(POOLTYPE)); \ + } /* Class: Entity diff -Naur ../teeworlds/src/game/server/eventhandler.cpp src/game/server/eventhandler.cpp --- ../teeworlds/src/game/server/eventhandler.cpp 2012-06-26 16:53:53.388863852 +1000 +++ src/game/server/eventhandler.cpp 2012-07-08 19:28:03.414258934 +1000 @@ -2,7 +2,6 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include "eventhandler.h" #include "gamecontext.h" -#include "player.h" ////////////////////////////////////////////////// // Event handler @@ -18,7 +17,7 @@ m_pGameServer = pGameServer; } -void *CEventHandler::Create(int Type, int Size, int Mask) +void *CEventHandler::Create(int Type, int Size, int64_t Mask) { if(m_NumEvents == MAX_EVENTS) return 0; diff -Naur ../teeworlds/src/game/server/eventhandler.h src/game/server/eventhandler.h --- ../teeworlds/src/game/server/eventhandler.h 2012-06-26 16:53:53.392865827 +1000 +++ src/game/server/eventhandler.h 2012-07-08 19:42:32.842259599 +1000 @@ -3,6 +3,14 @@ #ifndef GAME_SERVER_EVENTHANDLER_H #define GAME_SERVER_EVENTHANDLER_H +#ifdef _MSC_VER +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif // class CEventHandler { @@ -12,7 +20,7 @@ int m_aTypes[MAX_EVENTS]; // TODO: remove some of these arrays int m_aOffsets[MAX_EVENTS]; int m_aSizes[MAX_EVENTS]; - int m_aClientMasks[MAX_EVENTS]; + int64_t m_aClientMasks[MAX_EVENTS]; char m_aData[MAX_DATASIZE]; class CGameContext *m_pGameServer; @@ -24,7 +32,7 @@ void SetGameServer(CGameContext *pGameServer); CEventHandler(); - void *Create(int Type, int Size, int Mask = -1); + void *Create(int Type, int Size, int64_t Mask = -1); void Clear(); void Snap(int SnappingClient); }; diff -Naur ../teeworlds/src/game/server/gamecontext.cpp src/game/server/gamecontext.cpp --- ../teeworlds/src/game/server/gamecontext.cpp 2012-07-08 00:31:07.989177105 +1000 +++ src/game/server/gamecontext.cpp 2012-07-08 19:42:32.950258935 +1000 @@ -1,24 +1,18 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include - #include -#include #include - +#include +#include "gamecontext.h" +#include #include #include -#include - -#include "entities/character.h" -#include "gamemodes/ctf.h" #include "gamemodes/dm.h" -#include "gamemodes/lms.h" -#include "gamemodes/mod.h" -#include "gamemodes/sur.h" #include "gamemodes/tdm.h" -#include "gamecontext.h" -#include "player.h" +#include "gamemodes/ctf.h" +#include "gamemodes/mod.h" enum { @@ -189,7 +183,7 @@ } } -void CGameContext::CreateSound(vec2 Pos, int Sound, int Mask) +void CGameContext::CreateSound(vec2 Pos, int Sound, int64_t Mask) { if (Sound < 0) return; @@ -233,6 +227,7 @@ } + void CGameContext::SendChat(int ChatterClientID, int Team, const char *pText) { char aBuf[256]; @@ -269,6 +264,7 @@ } } + void CGameContext::SendEmoticon(int ClientID, int Emoticon) { CNetMsg_Sv_Emoticon Msg; @@ -347,25 +343,28 @@ void CGameContext::SendVoteStatus(int ClientID, int Total, int Yes, int No) { CNetMsg_Sv_VoteStatus Msg = {0}; - Msg.m_Total = Total; - Msg.m_Yes = Yes; - Msg.m_No = No; - Msg.m_Pass = Total - (Yes+No); + if (Total<=16) + { + Msg.m_Total = Total; + Msg.m_Yes = Yes; + Msg.m_No = No; + Msg.m_Pass = Total - (Yes+No); + } else { + double f = Total/16.; + Msg.m_Total = (int)(Total*f); + Msg.m_Yes = (int)(Yes*f); + Msg.m_No = (int)(No*f); + Msg.m_Pass = (int)((Total - (Yes+No))*f); + } Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID); } -void CGameContext::AbortVoteOnDisconnect(int ClientID) +void CGameContext::AbortVoteKickOnDisconnect(int ClientID) { - if(m_VoteCloseTime && ClientID == m_VoteClientID && (!str_comp_num(m_aVoteCommand, "kick ", 5) || - !str_comp_num(m_aVoteCommand, "set_team ", 9) || (!str_comp_num(m_aVoteCommand, "ban ", 4) && Server()->IsBanned(ClientID)))) - m_VoteCloseTime = -1; -} - -void CGameContext::AbortVoteOnTeamChange(int ClientID) -{ - if(m_VoteCloseTime && ClientID == m_VoteClientID && !str_comp_num(m_aVoteCommand, "set_team ", 9)) + if(m_VoteCloseTime && ((!str_comp_num(m_aVoteCommand, "kick ", 5) && str_toint(&m_aVoteCommand[5]) == ClientID) || + (!str_comp_num(m_aVoteCommand, "set_team ", 9) && str_toint(&m_aVoteCommand[9]) == ClientID))) m_VoteCloseTime = -1; } @@ -376,11 +375,9 @@ if(!m_pController) return; - if( str_comp(m_pController->GetGameType(), "DM")==0 || - str_comp(m_pController->GetGameType(), "TDM")==0 || - str_comp(m_pController->GetGameType(), "CTF")==0 || - str_comp(m_pController->GetGameType(), "LMS")==0 || - str_comp(m_pController->GetGameType(), "SUR")==0) + if( str_comp(m_pController->m_pGameType, "DM")==0 || + str_comp(m_pController->m_pGameType, "TDM")==0 || + str_comp(m_pController->m_pGameType, "CTF")==0) { CTuningParams p; if(mem_comp(&p, &m_Tuning, sizeof(p)) != 0) @@ -391,6 +388,7 @@ } } + void CGameContext::SendTuningParams(int ClientID) { CheckPureTuning(); @@ -412,8 +410,10 @@ for(int i = 0; i < MAX_CLIENTS; ++i) { if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) - m_pController->DoTeamChange(m_apPlayers[i], m_apPlayers[i]->GetTeam()^1, false); + m_apPlayers[i]->SetTeam(m_apPlayers[i]->GetTeam()^1, false); } + + (void)m_pController->CheckTeamBalance(); } void CGameContext::OnTick() @@ -518,13 +518,13 @@ #ifdef CONF_DEBUG - for(int i = 0; i < MAX_CLIENTS; i++) + if(g_Config.m_DbgDummies) { - if(m_apPlayers[i] && m_apPlayers[i]->IsDummy()) + for(int i = 0; i < g_Config.m_DbgDummies ; i++) { CNetObj_PlayerInput Input = {0}; Input.m_Direction = (i&1)?-1:1; - m_apPlayers[i]->OnPredictedInput(&Input); + m_apPlayers[MAX_CLIENTS-i-1]->OnPredictedInput(&Input); } } #endif @@ -533,7 +533,8 @@ // Server hooks void CGameContext::OnClientDirectInput(int ClientID, void *pInput) { - m_apPlayers[ClientID]->OnDirectInput((CNetObj_PlayerInput *)pInput); + if(!m_World.m_Paused) + m_apPlayers[ClientID]->OnDirectInput((CNetObj_PlayerInput *)pInput); } void CGameContext::OnClientPredictedInput(int ClientID, void *pInput) @@ -548,7 +549,10 @@ m_apPlayers[ClientID]->Respawn(); char aBuf[512]; str_format(aBuf, sizeof(aBuf), "'%s' entered and joined the %s", Server()->ClientName(ClientID), m_pController->GetTeamName(m_apPlayers[ClientID]->GetTeam())); - SendChat(-1, CGameContext::CHAT_ALL, aBuf); + SendChat(-1, CGameContext::CHAT_ALL, aBuf); + SendChatTarget(ClientID, "BBMod Made by [BBM]Julian->Assange And [BBM]Learath2"); + if(g_Config.m_SvWelcome[0]!=0) + SendChatTarget(ClientID,g_Config.m_SvWelcome); str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientID, Server()->ClientName(ClientID), m_apPlayers[ClientID]->GetTeam()); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); @@ -556,12 +560,24 @@ m_VoteUpdate = true; } -void CGameContext::OnClientConnected(int ClientID, bool Dummy) +void CGameContext::OnClientConnected(int ClientID) { - m_apPlayers[ClientID] = new(ClientID) CPlayer(this, ClientID, Dummy); - - if(Dummy) - return; + // Check which team the player should be on + const int StartTeam = g_Config.m_SvTournamentMode ? TEAM_SPECTATORS : m_pController->GetAutoTeam(ClientID); + + m_apPlayers[ClientID] = new(ClientID) CPlayer(this, ClientID, StartTeam); + //players[client_id].init(client_id); + //players[client_id].client_id = client_id; + + (void)m_pController->CheckTeamBalance(); + +#ifdef CONF_DEBUG + if(g_Config.m_DbgDummies) + { + if(ClientID >= MAX_CLIENTS-g_Config.m_DbgDummies) + return; + } +#endif // send active vote if(m_VoteCloseTime) @@ -573,20 +589,27 @@ Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID); } -void CGameContext::OnClientTeamChange(int ClientID) -{ - if(m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS) - AbortVoteOnTeamChange(ClientID); -} - void CGameContext::OnClientDrop(int ClientID, const char *pReason) { - AbortVoteOnDisconnect(ClientID); - m_pController->OnPlayerDisconnect(m_apPlayers[ClientID], pReason); + AbortVoteKickOnDisconnect(ClientID); + m_apPlayers[ClientID]->OnDisconnect(pReason); delete m_apPlayers[ClientID]; m_apPlayers[ClientID] = 0; + (void)m_pController->CheckTeamBalance(); m_VoteUpdate = true; + + // update spectator modes + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(m_apPlayers[i] && m_apPlayers[i]->m_SpectatorID == ClientID) + m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW; + } +} + +char * CGameContext::HandleArguments(char *pString) +{ + return str_skip_whitespaces(str_skip_to_whitespace(pString)); } void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) @@ -624,8 +647,110 @@ *pMessage = ' '; pMessage++; } - - SendChat(ClientID, Team, pMsg->m_pMessage); + CCharacter* pChr = pPlayer->GetCharacter(); + if(m_apPlayers[ClientID]->m_Muted == 0 && !m_World.m_Paused) + { + if(!str_comp_num(pMsg->m_pMessage, "/emote", 6) && !m_World.m_Paused && pChr && pPlayer) + { + pChr->m_DefEmoteReset = 0; + if (!str_comp_nocase(HandleArguments((char *)pMsg->m_pMessage), "normal")) + pChr->m_DefEmote =(EMOTE_NORMAL); + + else if (!str_comp_nocase(HandleArguments((char *)pMsg->m_pMessage), "surprise")) + pChr->m_DefEmote =(EMOTE_SURPRISE); + else if (!str_comp_nocase(HandleArguments((char *)pMsg->m_pMessage), "happy")) + pChr->m_DefEmote =(EMOTE_HAPPY); + else if (!str_comp_nocase(HandleArguments((char *)pMsg->m_pMessage), "pain")) + pChr->m_DefEmote =(EMOTE_PAIN); + else if (!str_comp_nocase(HandleArguments((char *)pMsg->m_pMessage), "blink")) + pChr->m_DefEmote =(EMOTE_BLINK); + else if (!str_comp_nocase(HandleArguments((char *)pMsg->m_pMessage), "angry")) + pChr->m_DefEmote =(EMOTE_ANGRY); + else + { + SendChatTarget(ClientID, "Unknown Emote Emotes Are: Normal, Surprise, Happy, Pain, Blink And Close"); + SendChatTarget(ClientID, "Emotes Are Used Like This: /emote ****"); + } + } + else if(!str_comp_nocase(pMsg->m_pMessage, "/info")) + { + SendChatTarget(ClientID, "****Mod by \"[BBM]Julian->Assange\" And Some Great Helps By \"Learath2\" <3****"); + SendChatTarget(ClientID, "Commands: /emote , /powerups , /colors"); + } + else if(!str_comp_nocase(pMsg->m_pMessage, "/powerups")) + { + SendChatTarget(ClientID, "********Powerups*********"); + char aBuf[256]; + char PUP_NAME[8][32]= {"Jump", "Hammer", "Plus Enemy Freeze Time", "Minus Self Freeze Time", "Hook Duration", "Hook Length", "Run", "Epic Ninja"}; + for(int i = 0; i < NUM_PUPS; i++) + { + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->Skills[i]); + SendChatTarget(ClientID, aBuf); + } + SendChatTarget(ClientID, "**************************"); + return; + } + else if(!str_comp_nocase(pMsg->m_pMessage, "/colors")) + { + SendChatTarget(ClientID, "*********Colors**********"); + char aBuf[256]; + char PUP_NAME[7][32]= {"Green", "Blue", "Red", "Pink", "Black", "White", "Yellow"}; + for(int i = 0; i < 7; i++) + { + if(i == 0) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoGreen); + if(i == 1) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoBlue); + if(i == 2) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoRed); + if(i == 3) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoPink); + if(i == 4) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoGrey); + if(i == 5) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoWhite); + if(i == 6) + str_format(aBuf, sizeof(aBuf), "%s : %d", PUP_NAME[i], pPlayer->m_NoYellow); + SendChatTarget(ClientID, aBuf); + } + SendChatTarget(ClientID, "*************************"); + return; + } + else if(!str_comp_num(pMsg->m_pMessage, "/", 1)) + SendChatTarget(ClientID, "Invalid command! do /info"); + else + { + if(pPlayer->m_LastChatTime + Server()->TickSpeed() >= Server()->Tick() || str_comp_nocase(pMsg->m_pMessage, pPlayer->m_LastChatText) != 0) + { + SendChat(ClientID, Team, pMsg->m_pMessage); + str_copy(pPlayer->m_LastChatText, pMsg->m_pMessage, sizeof(pPlayer->m_LastChatText)); + pPlayer->m_LastChatTime = Server()->Tick(); + } + else + { + SendChat(ClientID, Team, pMsg->m_pMessage); + pPlayer->m_LastChatTime = Server()->Tick(); + str_copy(pPlayer->m_LastChatText, pMsg->m_pMessage, sizeof(pPlayer->m_LastChatText)); + pPlayer->m_MuteTimes = pPlayer->m_MuteTimes + 2; + } + if(pPlayer->m_MuteTimes == 10) + { + pPlayer->m_Muted = Server()->TickSpeed() * g_Config.m_SvAutoMuteTime; + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "You Are Muted For %d Seconds", m_apPlayers[ClientID]->m_Muted / Server()->TickSpeed()); + SendChatTarget(ClientID, aBuf); + str_format(aBuf, sizeof(aBuf), "%s Is Muted For %d Seconds", Server()->ClientName(ClientID), m_apPlayers[ClientID]->m_Muted / Server()->TickSpeed()); + SendChat(-1, CGameContext::CHAT_ALL, aBuf); + pPlayer->m_MuteTimes = 0; + } + } + } + else + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "You Can't Talk You Are Muted For Next %d Seconds", m_apPlayers[ClientID]->m_Muted / Server()->TickSpeed()); + SendChatTarget(ClientID, aBuf); + } } else if(MsgID == NETMSGTYPE_CL_CALLVOTE) { @@ -687,7 +812,7 @@ } else if(str_comp_nocase(pMsg->m_Type, "kick") == 0) { - if(!g_Config.m_SvVoteKick) + if(!g_Config.m_SvVoteKick || g_Config.m_SvVoteKick) { SendChatTarget(ClientID, "Server does not allow voting to kick players"); return; @@ -709,6 +834,9 @@ } int KickID = str_toint(pMsg->m_Value); + if (!Server()->ReverseTranslate(KickID, ClientID)) + return; + if(KickID < 0 || KickID >= MAX_CLIENTS || !m_apPlayers[KickID]) { SendChatTarget(ClientID, "Invalid client id to kick"); @@ -738,18 +866,22 @@ Server()->GetClientAddr(KickID, aAddrStr, sizeof(aAddrStr)); str_format(aCmd, sizeof(aCmd), "ban %s %d Banned by vote", aAddrStr, g_Config.m_SvVoteKickBantime); } - m_VoteClientID = KickID; } else if(str_comp_nocase(pMsg->m_Type, "spectate") == 0) { - if(!g_Config.m_SvVoteSpectate) + if(!g_Config.m_SvVoteSpectate || 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 (!Server()->ReverseTranslate(SpectateID, ClientID)) + return; + if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !m_apPlayers[SpectateID] || m_apPlayers[SpectateID]->GetTeam() == TEAM_SPECTATORS) + { SendChatTarget(ClientID, "Invalid client id to move"); return; @@ -762,8 +894,8 @@ 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 %d", SpectateID, g_Config.m_SvVoteSpectateRejoindelay); - m_VoteClientID = SpectateID; } if(aCmd[0]) @@ -792,7 +924,7 @@ m_VoteUpdate = true; } } - else if(MsgID == NETMSGTYPE_CL_SETTEAM && m_pController->IsTeamChangeAllowed()) + else if (MsgID == NETMSGTYPE_CL_SETTEAM && !m_World.m_Paused) { CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg; @@ -824,7 +956,8 @@ pPlayer->m_LastSetTeam = Server()->Tick(); if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS) m_VoteUpdate = true; - m_pController->DoTeamChange(pPlayer, pMsg->m_Team); + pPlayer->SetTeam(pMsg->m_Team); + (void)m_pController->CheckTeamBalance(); pPlayer->m_TeamChangeTick = Server()->Tick(); } else @@ -841,16 +974,23 @@ { CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg; - if(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick()) + if(pMsg->m_SpectatorID != SPEC_FREEVIEW) + if (!Server()->ReverseTranslate(pMsg->m_SpectatorID, ClientID)) + return; + + 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(!pPlayer->SetSpectatorID(pMsg->m_SpectatorID)) + 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_IsReadyToEnter) + if(pPlayer->m_IsReady) return; CNetMsg_Cl_StartInfo *pMsg = (CNetMsg_Cl_StartInfo *)pRawMsg; @@ -861,9 +1001,17 @@ 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; + if (!pPlayer->forcecolor) { + pPlayer->origusecustcolor=pMsg->m_UseCustomColor; + pPlayer->origbodycolor=pMsg->m_ColorBody; + pPlayer->origfeetcolor=pMsg->m_ColorFeet; + } + pPlayer->m_TeeInfos.m_UseCustomColor = (pPlayer->forcecolor)?1:pMsg->m_UseCustomColor; + pPlayer->m_TeeInfos.m_ColorBody = (pPlayer->forcecolor)?pPlayer->forcecolor:pMsg->m_ColorBody; + pPlayer->m_TeeInfos.m_ColorFeet = (pPlayer->forcecolor)?pPlayer->forcecolor:pMsg->m_ColorFeet; + /*pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor; pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody; - pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet; + pPlayer->m_TeeInfos.m_ColorFeet = pMsg->m_ColorFeet;*/ m_pController->OnPlayerInfoChange(pPlayer); // send vote options @@ -942,7 +1090,7 @@ SendTuningParams(ClientID); // client is ready to enter - pPlayer->m_IsReadyToEnter = true; + pPlayer->m_IsReady = true; CNetMsg_Sv_ReadyToEnter m; Server()->SendPackMsg(&m, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID); } @@ -975,13 +1123,50 @@ 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()) + + if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote && pPlayer->m_LastEmote+Server()->TickSpeed()*1 > Server()->Tick()) return; pPlayer->m_LastEmote = Server()->Tick(); SendEmoticon(ClientID, pMsg->m_Emoticon); + CCharacter* pChr = pPlayer->GetCharacter(); + if(pChr && pPlayer) + { + 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: + break; + } + pChr->SetEmoteStop(Server()->Tick() + 2 * Server()->TickSpeed()); + + } } else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused) { @@ -991,14 +1176,6 @@ 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 CGameContext::ConTuneParam(IConsole::IResult *pResult, void *pUserData) @@ -1044,10 +1221,10 @@ { CGameContext *pSelf = (CGameContext *)pUserData; - if(pResult->NumArguments()) - pSelf->m_pController->DoPause(clamp(pResult->GetInteger(0), -1, 1000)); - else - pSelf->m_pController->DoPause(pSelf->m_pController->IsGamePaused() ? 0 : IGameController::TIMER_INFINITE); + if(pSelf->m_pController->IsGameOver()) + return; + + pSelf->m_World.m_Paused ^= 1; } void CGameContext::ConChangeMap(IConsole::IResult *pResult, void *pUserData) @@ -1060,9 +1237,9 @@ { CGameContext *pSelf = (CGameContext *)pUserData; if(pResult->NumArguments()) - pSelf->m_pController->DoWarmup(clamp(pResult->GetInteger(0), -1, 1000)); + pSelf->m_pController->DoWarmup(pResult->GetInteger(0)); else - pSelf->m_pController->DoWarmup(0); + pSelf->m_pController->StartRound(); } void CGameContext::ConBroadcast(IConsole::IResult *pResult, void *pUserData) @@ -1091,7 +1268,8 @@ pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); pSelf->m_apPlayers[ClientID]->m_TeamChangeTick = pSelf->Server()->Tick()+pSelf->Server()->TickSpeed()*Delay*60; - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[ClientID], Team); + pSelf->m_apPlayers[ClientID]->SetTeam(Team); + (void)pSelf->m_pController->CheckTeamBalance(); } void CGameContext::ConSetTeamAll(IConsole::IResult *pResult, void *pUserData) @@ -1105,7 +1283,9 @@ for(int i = 0; i < MAX_CLIENTS; ++i) if(pSelf->m_apPlayers[i]) - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[i], Team, false); + pSelf->m_apPlayers[i]->SetTeam(Team, false); + + (void)pSelf->m_pController->CheckTeamBalance(); } void CGameContext::ConSwapTeams(IConsole::IResult *pResult, void *pUserData) @@ -1120,29 +1300,41 @@ if(!pSelf->m_pController->IsTeamplay()) return; - int rnd = 0; + int CounterRed = 0; + int CounterBlue = 0; int PlayerTeam = 0; - int aPlayer[MAX_CLIENTS]; - - for(int i = 0; i < MAX_CLIENTS; i++) + for(int i = 0; i < MAX_CLIENTS; ++i) if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) - aPlayer[PlayerTeam++]=i; - + ++PlayerTeam; + PlayerTeam = (PlayerTeam+1)/2; + pSelf->SendChat(-1, CGameContext::CHAT_ALL, "Teams were shuffled"); - //creating random permutation - for(int i = PlayerTeam; i > 1; i--) + for(int i = 0; i < MAX_CLIENTS; ++i) { - rnd = rand() % i; - int tmp = aPlayer[rnd]; - aPlayer[rnd] = aPlayer[i-1]; - aPlayer[i-1] = tmp; + if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) + { + if(CounterRed == PlayerTeam) + pSelf->m_apPlayers[i]->SetTeam(TEAM_BLUE, false); + else if(CounterBlue == PlayerTeam) + pSelf->m_apPlayers[i]->SetTeam(TEAM_RED, false); + else + { + if(rand() % 2) + { + pSelf->m_apPlayers[i]->SetTeam(TEAM_BLUE, false); + ++CounterBlue; + } + else + { + pSelf->m_apPlayers[i]->SetTeam(TEAM_RED, false); + ++CounterRed; + } + } + } } - //uneven Number of Players? - rnd = PlayerTeam % 2 ? rand() % 2 : 0; - for(int i = 0; i < PlayerTeam; i++) - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[aPlayer[i]], i < (PlayerTeam+rnd)/2 ? TEAM_RED : TEAM_BLUE, false); + (void)pSelf->m_pController->CheckTeamBalance(); } void CGameContext::ConLockTeams(IConsole::IResult *pResult, void *pUserData) @@ -1323,6 +1515,7 @@ else if(str_comp_nocase(pType, "kick") == 0) { int KickID = str_toint(pValue); + //Server()->ReverseTranslate(KickID, ClientID); if(KickID < 0 || KickID >= MAX_CLIENTS || !pSelf->m_apPlayers[KickID]) { pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "Invalid client id to kick"); @@ -1345,6 +1538,7 @@ else if(str_comp_nocase(pType, "spectate") == 0) { int SpectateID = str_toint(pValue); + //Server()->ReverseTranslate(SpectateID, ClientID); 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"); @@ -1413,7 +1607,7 @@ Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "Reset tuning"); Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "Dump tuning"); - Console()->Register("pause", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConPause, this, "Pause/unpause game"); + Console()->Register("pause", "", CFGFLAG_SERVER, ConPause, this, "Pause/unpause game"); Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "Change map"); Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, "Restart in x seconds (0 = abort)"); Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, "Broadcast message"); @@ -1433,37 +1627,53 @@ Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this); } -void CGameContext::OnInit() +void CGameContext::OnInit(/*class IKernel *pKernel*/) { - // init everything m_pServer = Kernel()->RequestInterface(); m_pConsole = Kernel()->RequestInterface(); m_World.SetGameServer(this); m_Events.SetGameServer(this); + //if(!data) // only load once + //data = load_data_from_memory(internal_data); + for(int i = 0; i < NUM_NETOBJTYPES; i++) Server()->SnapSetStaticsize(i, m_NetObjHandler.GetObjSize(i)); m_Layers.Init(Kernel()); m_Collision.Init(&m_Layers); + // reset everything here + //world = new GAMEWORLD; + //players = new CPlayer[MAX_CLIENTS]; + // select gametype - if(str_comp_nocase(g_Config.m_SvGametype, "mod") == 0) + if(str_comp(g_Config.m_SvGametype, "mod") == 0) m_pController = new CGameControllerMOD(this); - else if(str_comp_nocase(g_Config.m_SvGametype, "ctf") == 0) + else if(str_comp(g_Config.m_SvGametype, "ctf") == 0) m_pController = new CGameControllerCTF(this); - else if(str_comp_nocase(g_Config.m_SvGametype, "lms") == 0) - m_pController = new CGameControllerLMS(this); - else if(str_comp_nocase(g_Config.m_SvGametype, "sur") == 0) - m_pController = new CGameControllerSUR(this); - else if(str_comp_nocase(g_Config.m_SvGametype, "tdm") == 0) + else if(str_comp(g_Config.m_SvGametype, "tdm") == 0) m_pController = new CGameControllerTDM(this); else m_pController = new CGameControllerDM(this); + // setup core world + //for(int i = 0; i < MAX_CLIENTS; i++) + // game.players[i].core.world = &game.world.core; + // create all entities from the game layer CMapItemLayerTilemap *pTileMap = m_Layers.GameLayer(); CTile *pTiles = (CTile *)Kernel()->RequestInterface()->GetData(pTileMap->m_Data); + + + + + /* + num_spawn_points[0] = 0; + num_spawn_points[1] = 0; + num_spawn_points[2] = 0; + */ + for(int y = 0; y < pTileMap->m_Height; y++) { for(int x = 0; x < pTileMap->m_Width; x++) @@ -1478,11 +1688,15 @@ } } + //game.world.insert_entity(game.Controller); + #ifdef CONF_DEBUG if(g_Config.m_DbgDummies) { for(int i = 0; i < g_Config.m_DbgDummies ; i++) - OnClientConnected(MAX_CLIENTS-i-1, true); + { + OnClientConnected(MAX_CLIENTS-i-1); + } } #endif } @@ -1516,6 +1730,8 @@ if(m_apPlayers[i]) m_apPlayers[i]->Snap(ClientID); } + m_apPlayers[ClientID]->FakeSnap(ClientID); + } void CGameContext::OnPreSnap() {} void CGameContext::OnPostSnap() @@ -1525,7 +1741,7 @@ bool CGameContext::IsClientReady(int ClientID) { - return m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_IsReadyToEnter ? true : false; + return m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_IsReady ? true : false; } bool CGameContext::IsClientPlayer(int ClientID) @@ -1533,7 +1749,7 @@ return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS ? false : true; } -const char *CGameContext::GameType() { return m_pController && m_pController->GetGameType() ? m_pController->GetGameType() : ""; } +const char *CGameContext::GameType() { return m_pController && m_pController->m_pGameType ? m_pController->m_pGameType : ""; } const char *CGameContext::Version() { return GAME_VERSION; } const char *CGameContext::NetVersion() { return GAME_NETVERSION; } diff -Naur ../teeworlds/src/game/server/gamecontext.h src/game/server/gamecontext.h --- ../teeworlds/src/game/server/gamecontext.h 2012-06-26 16:53:53.392865827 +1000 +++ src/game/server/gamecontext.h 2012-07-08 19:45:34.537929011 +1000 @@ -3,15 +3,26 @@ #ifndef GAME_SERVER_GAMECONTEXT_H #define GAME_SERVER_GAMECONTEXT_H -#include #include +#include +#include #include #include #include "eventhandler.h" +#include "gamecontroller.h" #include "gameworld.h" +#include "player.h" +#ifdef _MSC_VER +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif /* Tick Game Context (CGameContext::tick) @@ -41,7 +52,8 @@ CCollision m_Collision; CNetObjHandler m_NetObjHandler; CTuningParams m_Tuning; - + + static void ConPowerups(IConsole::IResult *pResult, void *pUserData); static void ConTuneParam(IConsole::IResult *pResult, void *pUserData); static void ConTuneReset(IConsole::IResult *pResult, void *pUserData); static void ConTuneDump(IConsole::IResult *pResult, void *pUserData); @@ -49,9 +61,11 @@ static void ConChangeMap(IConsole::IResult *pResult, void *pUserData); static void ConRestart(IConsole::IResult *pResult, void *pUserData); static void ConBroadcast(IConsole::IResult *pResult, void *pUserData); + static void ConEyeEmote(IConsole::IResult *pResult, void *pUserData); static void ConSay(IConsole::IResult *pResult, void *pUserData); static void ConSetTeam(IConsole::IResult *pResult, void *pUserData); static void ConSetTeamAll(IConsole::IResult *pResult, void *pUserData); + static void ConSpin(IConsole::IResult *pResult, void *pUserData); static void ConSwapTeams(IConsole::IResult *pResult, void *pUserData); static void ConShuffleTeams(IConsole::IResult *pResult, void *pUserData); static void ConLockTeams(IConsole::IResult *pResult, void *pUserData); @@ -76,11 +90,18 @@ ~CGameContext(); void Clear(); - + static void SendChatResponse(const char *pLine, void *pUser); + static void SendChatResponseAll(const char *pLine, void *pUser); + struct ChatResponseInfo + { + CGameContext *m_GameContext; + int m_To; + }; + CEventHandler m_Events; - class CPlayer *m_apPlayers[MAX_CLIENTS]; + CPlayer *m_apPlayers[MAX_CLIENTS]; - class IGameController *m_pController; + IGameController *m_pController; CGameWorld m_World; // helper functions @@ -93,8 +114,7 @@ void EndVote(); void SendVoteSet(int ClientID); void SendVoteStatus(int ClientID, int Total, int Yes, int No); - void AbortVoteOnDisconnect(int ClientID); - void AbortVoteOnTeamChange(int ClientID); + void AbortVoteKickOnDisconnect(int ClientID); int m_VoteCreator; int64 m_VoteCloseTime; @@ -103,7 +123,6 @@ char m_aVoteDescription[VOTE_DESC_LENGTH]; char m_aVoteCommand[VOTE_CMD_LENGTH]; char m_aVoteReason[VOTE_REASON_LENGTH]; - int m_VoteClientID; int m_NumVoteOptions; int m_VoteEnforce; enum @@ -112,7 +131,7 @@ VOTE_ENFORCE_NO, VOTE_ENFORCE_YES, }; - class CHeap *m_pVoteOptionHeap; + CHeap *m_pVoteOptionHeap; CVoteOptionServer *m_pVoteOptionFirst; CVoteOptionServer *m_pVoteOptionLast; @@ -122,7 +141,7 @@ void CreateHammerHit(vec2 Pos); void CreatePlayerSpawn(vec2 Pos); void CreateDeath(vec2 Pos, int Who); - void CreateSound(vec2 Pos, int Sound, int Mask=-1); + void CreateSound(vec2 Pos, int Sound, int64_t Mask=-1); void CreateSoundGlobal(int Sound, int Target=-1); @@ -158,12 +177,11 @@ virtual void OnPreSnap(); virtual void OnSnap(int ClientID); virtual void OnPostSnap(); - + + char * HandleArguments(char *pString); virtual void OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID); - virtual void OnClientConnected(int ClientID) { OnClientConnected(ClientID, false); } - void OnClientConnected(int ClientID, bool Dummy); - void OnClientTeamChange(int ClientID); + virtual void OnClientConnected(int ClientID); virtual void OnClientEnter(int ClientID); virtual void OnClientDrop(int ClientID, const char *pReason); virtual void OnClientDirectInput(int ClientID, void *pInput); @@ -177,8 +195,8 @@ virtual const char *NetVersion(); }; -inline int CmaskAll() { return -1; } -inline int CmaskOne(int ClientID) { return 1< - #include -#include "entities/character.h" +#include + #include "entities/pickup.h" -#include "gamecontext.h" #include "gamecontroller.h" -#include "player.h" +#include "gamecontext.h" -IGameController::IGameController(CGameContext *pGameServer) +IGameController::IGameController(class CGameContext *pGameServer) { m_pGameServer = pGameServer; m_pServer = m_pGameServer->Server(); + m_pGameType = "unknown"; - // balancing - m_aTeamSize[TEAM_RED] = 0; - m_aTeamSize[TEAM_BLUE] = 0; - m_UnbalancedTick = TBALANCE_OK; - - // game - m_GameState = IGS_GAME_RUNNING; - m_GameStateTimer = TIMER_INFINITE; - m_GameStartTick = Server()->Tick(); - m_MatchCount = 0; - m_RoundCount = 0; + // + DoWarmup(g_Config.m_SvWarmup); + m_GameOverTick = -1; m_SuddenDeath = 0; + m_RoundStartTick = Server()->Tick(); + m_RoundCount = 0; + m_GameFlags = 0; m_aTeamscore[TEAM_RED] = 0; m_aTeamscore[TEAM_BLUE] = 0; - if(g_Config.m_SvWarmup) - SetGameState(IGS_WARMUP_USER, g_Config.m_SvWarmup); - else - SetGameState(IGS_WARMUP_GAME, TIMER_INFINITE); - - // info - m_GameFlags = 0; - m_pGameType = "unknown"; - - // map m_aMapWish[0] = 0; - // spawn + m_UnbalancedTick = -1; + m_ForceBalanced = false; + m_aNumSpawnPoints[0] = 0; m_aNumSpawnPoints[1] = 0; m_aNumSpawnPoints[2] = 0; } -//activity -void IGameController::DoActivityCheck() -{ - if(g_Config.m_SvInactiveKickTime == 0) - return; - - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(GameServer()->m_apPlayers[i] && !GameServer()->m_apPlayers[i]->IsDummy() && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && - !Server()->IsAuthed(i) && (Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick+g_Config.m_SvInactiveKickTime*Server()->TickSpeed()*60)) - { - switch(g_Config.m_SvInactiveKick) - { - case 0: - { - // move player to spectator - DoTeamChange(GameServer()->m_apPlayers[i], TEAM_SPECTATORS); - } - break; - case 1: - { - // move player to spectator if the reserved slots aren't filled yet, kick him otherwise - int Spectators = 0; - for(int j = 0; j < MAX_CLIENTS; ++j) - if(GameServer()->m_apPlayers[j] && GameServer()->m_apPlayers[j]->GetTeam() == TEAM_SPECTATORS) - ++Spectators; - if(Spectators >= g_Config.m_SvSpectatorSlots) - Server()->Kick(i, "Kicked for inactivity"); - else - DoTeamChange(GameServer()->m_apPlayers[i], TEAM_SPECTATORS); - } - break; - case 2: - { - // kick the player - Server()->Kick(i, "Kicked for inactivity"); - } - } - } - } -} - -bool IGameController::GetPlayersReadyState() +IGameController::~IGameController() { - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && !GameServer()->m_apPlayers[i]->m_IsReadyToPlay) - return false; - } - - return true; } -void IGameController::SetPlayersReadyState(bool ReadyState) +float IGameController::EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos) { - for(int i = 0; i < MAX_CLIENTS; ++i) + float Score = 0.0f; + CCharacter *pC = static_cast(GameServer()->m_World.FindFirst(CGameWorld::ENTTYPE_CHARACTER)); + for(; pC; pC = (CCharacter *)pC->TypeNext()) { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && (ReadyState || !GameServer()->m_apPlayers[i]->m_DeadSpecMode)) - GameServer()->m_apPlayers[i]->m_IsReadyToPlay = ReadyState; - } -} - -// balancing -bool IGameController::CanBeMovedOnBalance(int ClientID) const -{ - return true; -} + // team mates are not as dangerous as enemies + float Scoremod = 1.0f; + if(pEval->m_FriendlyTeam != -1 && pC->GetPlayer()->GetTeam() == pEval->m_FriendlyTeam) + Scoremod = 0.5f; -void IGameController::CheckTeamBalance() -{ - if(!IsTeamplay() || !g_Config.m_SvTeambalanceTime) - { - m_UnbalancedTick = TBALANCE_OK; - return; + float d = distance(Pos, pC->m_Pos); + Score += Scoremod * (d == 0 ? 1000000000.0f : 1.0f/d); } - // check if teams are unbalanced - char aBuf[256]; - if(absolute(m_aTeamSize[TEAM_RED]-m_aTeamSize[TEAM_BLUE]) >= NUM_TEAMS) - { - str_format(aBuf, sizeof(aBuf), "Teams are NOT balanced (red=%d blue=%d)", m_aTeamSize[TEAM_RED], m_aTeamSize[TEAM_BLUE]); - if(m_UnbalancedTick <= TBALANCE_OK) - m_UnbalancedTick = Server()->Tick(); - } - else - { - str_format(aBuf, sizeof(aBuf), "Teams are balanced (red=%d blue=%d)", m_aTeamSize[TEAM_RED], m_aTeamSize[TEAM_BLUE]); - m_UnbalancedTick = TBALANCE_OK; - } - GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); + return Score; } -void IGameController::DoTeamBalance() +void IGameController::EvaluateSpawnType(CSpawnEval *pEval, int Type) { - if(!IsTeamplay() || !g_Config.m_SvTeambalanceTime || absolute(m_aTeamSize[TEAM_RED]-m_aTeamSize[TEAM_BLUE]) < NUM_TEAMS) - return; - - GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", "Balancing teams"); - - float aTeamScore[NUM_TEAMS] = {0}; - float aPlayerScore[MAX_CLIENTS] = {0.0f}; - - // gather stats - for(int i = 0; i < MAX_CLIENTS; i++) + // get spawn point + for(int i = 0; i < m_aNumSpawnPoints[Type]; i++) { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) + // check if the position is occupado + CCharacter *aEnts[MAX_CLIENTS]; + int Num = GameServer()->m_World.FindEntities(m_aaSpawnPoints[Type][i], 64, (CEntity**)aEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER); + vec2 Positions[5] = { vec2(0.0f, 0.0f), vec2(-32.0f, 0.0f), vec2(0.0f, -32.0f), vec2(32.0f, 0.0f), vec2(0.0f, 32.0f) }; // start, left, up, right, down + int Result = -1; + for(int Index = 0; Index < 5 && Result == -1; ++Index) { - aPlayerScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/ - (Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick); - aTeamScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPlayerScore[i]; + Result = Index; + for(int c = 0; c < Num; ++c) + if(GameServer()->Collision()->CheckPoint(m_aaSpawnPoints[Type][i]+Positions[Index]) || + distance(aEnts[c]->m_Pos, m_aaSpawnPoints[Type][i]+Positions[Index]) <= aEnts[c]->m_ProximityRadius) + { + Result = -1; + break; + } } - } - - int BiggerTeam = (m_aTeamSize[TEAM_RED] > m_aTeamSize[TEAM_BLUE]) ? TEAM_RED : TEAM_BLUE; - int NumBalance = absolute(m_aTeamSize[TEAM_RED]-m_aTeamSize[TEAM_BLUE]) / NUM_TEAMS; + if(Result == -1) + continue; // try next spawn point - // balance teams - do - { - CPlayer *pPlayer = 0; - float ScoreDiff = aTeamScore[BiggerTeam]; - for(int i = 0; i < MAX_CLIENTS; i++) + vec2 P = m_aaSpawnPoints[Type][i]+Positions[Result]; + float S = EvaluateSpawnPos(pEval, P); + if(!pEval->m_Got || pEval->m_Score > S) { - if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i)) - continue; - - // remember the player whom would cause lowest score-difference - if(GameServer()->m_apPlayers[i]->GetTeam() == BiggerTeam && - (!pPlayer || absolute((aTeamScore[BiggerTeam^1]+aPlayerScore[i]) - (aTeamScore[BiggerTeam]-aPlayerScore[i])) < ScoreDiff)) - { - pPlayer = GameServer()->m_apPlayers[i]; - ScoreDiff = absolute((aTeamScore[BiggerTeam^1]+aPlayerScore[i]) - (aTeamScore[BiggerTeam]-aPlayerScore[i])); - } + pEval->m_Got = true; + pEval->m_Score = S; + pEval->m_Pos = P; } - - // move the player to the other team - int Temp = pPlayer->m_LastActionTick; - DoTeamChange(pPlayer, BiggerTeam^1); - pPlayer->m_LastActionTick = Temp; - pPlayer->Respawn(); - char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "You were moved to %s due to team balancing", GetTeamName(pPlayer->GetTeam())); - GameServer()->SendBroadcast(aBuf, pPlayer->GetCID()); } - while(--NumBalance); - - m_UnbalancedTick = TBALANCE_OK; - GameServer()->SendChat(-1, CGameContext::CHAT_ALL, "Teams have been balanced"); } -// event -int IGameController::OnCharacterDeath(CCharacter *pVictim, CPlayer *pKiller, int Weapon) +bool IGameController::CanSpawn(int Team, vec2 *pOutPos) { - // do scoreing - if(!pKiller || Weapon == WEAPON_GAME) - return 0; - if(pKiller == pVictim->GetPlayer()) - pVictim->GetPlayer()->m_Score--; // suicide - else - { - if(IsTeamplay() && pVictim->GetPlayer()->GetTeam() == pKiller->GetTeam()) - pKiller->m_Score--; // teamkill - else - pKiller->m_Score++; // normal kill - } - if(Weapon == WEAPON_SELF) - pVictim->GetPlayer()->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3.0f; - - - // update spectator modes for dead players in survival - if(m_GameFlags&GAMEFLAG_SURVIVAL) - { - for(int i = 0; i < MAX_CLIENTS; ++i) - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_DeadSpecMode) - GameServer()->m_apPlayers[i]->UpdateDeadSpecMode(); - } + CSpawnEval Eval; - return 0; -} + // spectators can't spawn + if(Team == TEAM_SPECTATORS) + return false; -void IGameController::OnCharacterSpawn(CCharacter *pChr) -{ - if(m_GameFlags&GAMEFLAG_SURVIVAL) + if(IsTeamplay()) { - // give start equipment - pChr->IncreaseHealth(10); - pChr->IncreaseArmor(5); - - pChr->GiveWeapon(WEAPON_HAMMER, -1); - pChr->GiveWeapon(WEAPON_GUN, 10); - pChr->GiveWeapon(WEAPON_SHOTGUN, 10); - pChr->GiveWeapon(WEAPON_GRENADE, 10); - pChr->GiveWeapon(WEAPON_LASER, 5); + Eval.m_FriendlyTeam = Team; - // prevent respawn - pChr->GetPlayer()->m_RespawnDisabled = GetStartRespawnState(); + // first try own team spawn, then normal spawn and then enemy + EvaluateSpawnType(&Eval, 1+(Team&1)); + if(!Eval.m_Got) + { + EvaluateSpawnType(&Eval, 0); + if(!Eval.m_Got) + EvaluateSpawnType(&Eval, 1+((Team+1)&1)); + } } else { - // default health - pChr->IncreaseHealth(10); - - // give default weapons - pChr->GiveWeapon(WEAPON_HAMMER, -1); - pChr->GiveWeapon(WEAPON_GUN, 10); + EvaluateSpawnType(&Eval, 0); + EvaluateSpawnType(&Eval, 1); + EvaluateSpawnType(&Eval, 2); } + + *pOutPos = Eval.m_Pos; + return Eval.m_Got; } + bool IGameController::OnEntity(int Index, vec2 Pos) { - // don't add pickups in survival - if(m_GameFlags&GAMEFLAG_SURVIVAL) - { - if(Index < ENTITY_SPAWN || Index > ENTITY_SPAWN_BLUE) - return false; - } - int Type = -1; + int SubType = 0; - switch(Index) - { - case ENTITY_SPAWN: + if(Index == ENTITY_SPAWN) m_aaSpawnPoints[0][m_aNumSpawnPoints[0]++] = Pos; - break; - case ENTITY_SPAWN_RED: + else if(Index == ENTITY_SPAWN_RED) m_aaSpawnPoints[1][m_aNumSpawnPoints[1]++] = Pos; - break; - case ENTITY_SPAWN_BLUE: + else if(Index == ENTITY_SPAWN_BLUE) m_aaSpawnPoints[2][m_aNumSpawnPoints[2]++] = Pos; - break; - case ENTITY_ARMOR_1: - Type = PICKUP_ARMOR; - break; - case ENTITY_HEALTH_1: - Type = PICKUP_HEALTH; - break; - case ENTITY_WEAPON_SHOTGUN: - Type = PICKUP_SHOTGUN; - break; - case ENTITY_WEAPON_GRENADE: - Type = PICKUP_GRENADE; - break; - case ENTITY_WEAPON_LASER: - Type = PICKUP_LASER; - break; - case ENTITY_POWERUP_NINJA: - if(g_Config.m_SvPowerups) - Type = PICKUP_NINJA; - } - - if(Type != -1) - { - CPickup *pPickup = new CPickup(&GameServer()->m_World, Type); - pPickup->m_Pos = Pos; - return true; - } - - return false; -} - -void IGameController::OnPlayerDisconnect(CPlayer *pPlayer, const char *pReason) -{ - pPlayer->OnDisconnect(); - - int ClientID = pPlayer->GetCID(); - if(Server()->ClientIngame(ClientID)) - { - char aBuf[512]; - if(pReason && *pReason) - str_format(aBuf, sizeof(aBuf), "'%s' has left the game (%s)", Server()->ClientName(ClientID), pReason); - else - str_format(aBuf, sizeof(aBuf), "'%s' has left the game", Server()->ClientName(ClientID)); - GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); - - str_format(aBuf, sizeof(aBuf), "leave player='%d:%s'", ClientID, Server()->ClientName(ClientID)); - GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "game", aBuf); - } - - if(pPlayer->GetTeam() != TEAM_SPECTATORS) - { - --m_aTeamSize[pPlayer->GetTeam()]; - m_UnbalancedTick = TBALANCE_CHECK; - } -} - -void IGameController::OnPlayerInfoChange(CPlayer *pPlayer) -{ - const int aTeamColors[2] = {65387, 10223467}; - if(IsTeamplay()) - { - pPlayer->m_TeeInfos.m_UseCustomColor = 1; - if(pPlayer->GetTeam() >= TEAM_RED && pPlayer->GetTeam() <= TEAM_BLUE) - { - pPlayer->m_TeeInfos.m_ColorBody = aTeamColors[pPlayer->GetTeam()]; - pPlayer->m_TeeInfos.m_ColorFeet = aTeamColors[pPlayer->GetTeam()]; - } - else - { - pPlayer->m_TeeInfos.m_ColorBody = 12895054; - pPlayer->m_TeeInfos.m_ColorFeet = 12895054; - } - } -} - -void IGameController::OnPlayerReadyChange(CPlayer *pPlayer) -{ - if(g_Config.m_SvPlayerReadyMode && pPlayer->GetTeam() != TEAM_SPECTATORS && !pPlayer->m_DeadSpecMode) + else if(Index == ENTITY_ARMOR_1) + Type = POWERUP_ARMOR; + else if(Index == ENTITY_HEALTH_1) + Type = POWERUP_HEALTH; + else if(Index == ENTITY_WEAPON_SHOTGUN) { - // change players ready state - pPlayer->m_IsReadyToPlay ^= 1; - - // check if it effects current game state - switch(m_GameState) - { - case IGS_GAME_RUNNING: - // one player isn't ready -> pause the game - if(!pPlayer->m_IsReadyToPlay) - SetGameState(IGS_GAME_PAUSED, TIMER_INFINITE); - break; - case IGS_WARMUP_USER: - // all players are ready -> end warmup - if(GetPlayersReadyState()) - SetGameState(IGS_WARMUP_USER, 0); - break; - case IGS_GAME_PAUSED: - // all players are ready -> unpause the game - if(GetPlayersReadyState()) - SetGameState(IGS_GAME_PAUSED, 0); - break; - case IGS_WARMUP_GAME: - case IGS_START_COUNTDOWN: - case IGS_END_MATCH: - case IGS_END_ROUND: - // not effected - break; - } + Type = POWERUP_WEAPON; + SubType = WEAPON_SHOTGUN; } -} - -void IGameController::OnReset() -{ - for(int i = 0; i < MAX_CLIENTS; i++) + else if(Index == ENTITY_WEAPON_GRENADE) { - if(GameServer()->m_apPlayers[i]) - { - GameServer()->m_apPlayers[i]->m_RespawnDisabled = false; - GameServer()->m_apPlayers[i]->Respawn(); - GameServer()->m_apPlayers[i]->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2; - if(m_RoundCount == 0) - { - GameServer()->m_apPlayers[i]->m_Score = 0; - GameServer()->m_apPlayers[i]->m_ScoreStartTick = Server()->Tick(); - } - GameServer()->m_apPlayers[i]->m_IsReadyToPlay = true; - } + Type = POWERUP_WEAPON; + SubType = WEAPON_GRENADE; } -} - -// game -void IGameController::DoWincheckMatch() -{ - if(IsTeamplay()) + else if(Index == ENTITY_WEAPON_RIFLE) { - // check score win condition - if((g_Config.m_SvScorelimit > 0 && (m_aTeamscore[TEAM_RED] >= g_Config.m_SvScorelimit || m_aTeamscore[TEAM_BLUE] >= g_Config.m_SvScorelimit)) || - (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_GameStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) - { - if(m_aTeamscore[TEAM_RED] != m_aTeamscore[TEAM_BLUE] || m_GameFlags&GAMEFLAG_SURVIVAL) - EndMatch(); - else - m_SuddenDeath = 1; - } + Type = POWERUP_WEAPON; + SubType = WEAPON_RIFLE; } - else + else if(Index == ENTITY_POWERUP_NINJA && g_Config.m_SvPowerups) { - // gather some stats - int Topscore = 0; - int TopscoreCount = 0; - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(GameServer()->m_apPlayers[i]) - { - if(GameServer()->m_apPlayers[i]->m_Score > Topscore) - { - Topscore = GameServer()->m_apPlayers[i]->m_Score; - TopscoreCount = 1; - } - else if(GameServer()->m_apPlayers[i]->m_Score == Topscore) - TopscoreCount++; - } - } - - // check score win condition - if((g_Config.m_SvScorelimit > 0 && Topscore >= g_Config.m_SvScorelimit) || - (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_GameStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) - { - if(TopscoreCount == 1) - EndMatch(); - else - m_SuddenDeath = 1; - } + Type = POWERUP_NINJA; + SubType = WEAPON_NINJA; } -} - -void IGameController::ResetGame() -{ - // reset the game - GameServer()->m_World.m_ResetRequested = true; - - SetGameState(IGS_GAME_RUNNING); - m_GameStartTick = Server()->Tick(); - m_SuddenDeath = 0; - - // do team-balancing - DoTeamBalance(); -} -void IGameController::SetGameState(EGameState GameState, int Timer) -{ - // change game state - switch(GameState) + if(Type != -1) { - case IGS_WARMUP_GAME: - // game based warmup is only possible when game or any warmup is running - if(m_GameState == IGS_GAME_RUNNING || m_GameState == IGS_WARMUP_GAME || m_GameState == IGS_WARMUP_USER) - { - if(Timer == TIMER_INFINITE) - { - // run warmup till there're enough players - m_GameState = GameState; - m_GameStateTimer = TIMER_INFINITE; - - // enable respawning in survival when activating warmup - if(m_GameFlags&GAMEFLAG_SURVIVAL) - { - for(int i = 0; i < MAX_CLIENTS; ++i) - if(GameServer()->m_apPlayers[i]) - GameServer()->m_apPlayers[i]->m_RespawnDisabled = false; - } - } - else if(Timer == 0) - { - // start new match - StartMatch(); - } - } - break; - case IGS_WARMUP_USER: - // user based warmup is only possible when the game or a user based warmup is running - if(m_GameState == IGS_GAME_RUNNING || m_GameState == IGS_WARMUP_USER) - { - if(Timer != 0) - { - // start warmup - if(Timer < 0 && g_Config.m_SvPlayerReadyMode) - { - // run warmup till all players are ready - m_GameState = GameState; - m_GameStateTimer = TIMER_INFINITE; - SetPlayersReadyState(false); - } - else if(Timer > 0) - { - // run warmup for a specific time intervall - m_GameState = GameState; - m_GameStateTimer = Timer*Server()->TickSpeed(); - } - - // enable respawning in survival when activating warmup - if(m_GameFlags&GAMEFLAG_SURVIVAL) - { - for(int i = 0; i < MAX_CLIENTS; ++i) - if(GameServer()->m_apPlayers[i]) - GameServer()->m_apPlayers[i]->m_RespawnDisabled = false; - } - } - else - { - // start new match - StartMatch(); - } - } - break; - case IGS_START_COUNTDOWN: - // only possible when game, pause or start countdown is running - if(m_GameState == IGS_GAME_RUNNING || m_GameState == IGS_GAME_PAUSED || m_GameState == IGS_START_COUNTDOWN) - { - m_GameState = GameState; - m_GameStateTimer = 3*Server()->TickSpeed(); - GameServer()->m_World.m_Paused = true; - } - break; - case IGS_GAME_RUNNING: - // always possible - { - m_GameState = GameState; - m_GameStateTimer = TIMER_INFINITE; - SetPlayersReadyState(true); - GameServer()->m_World.m_Paused = false; - } - break; - case IGS_GAME_PAUSED: - // only possible when game is running or paused - if(m_GameState == IGS_GAME_RUNNING || m_GameState == IGS_GAME_PAUSED) - { - if(Timer != 0) - { - // start pause - if(Timer < 0) - { - // pauses infinitely till all players are ready or disabled via rcon command - m_GameStateTimer = TIMER_INFINITE; - SetPlayersReadyState(false); - } - else - { - // pauses for a specific time intervall - m_GameStateTimer = Timer*Server()->TickSpeed(); - } - - m_GameState = GameState; - GameServer()->m_World.m_Paused = true; - } - else - { - // start a countdown to end pause - SetGameState(IGS_START_COUNTDOWN); - } - } - break; - case IGS_END_ROUND: - case IGS_END_MATCH: - // only possible when game is running or over - if(m_GameState == IGS_GAME_RUNNING || m_GameState == IGS_END_MATCH || m_GameState == IGS_END_ROUND) - { - m_GameState = GameState; - m_GameStateTimer = Timer*Server()->TickSpeed(); - m_SuddenDeath = 0; - GameServer()->m_World.m_Paused = true; - } + CPickup *pPickup = new CPickup(&GameServer()->m_World, Type, SubType); + pPickup->m_Pos = Pos; + return true; } -} - -void IGameController::StartMatch() -{ - ResetGame(); - - m_RoundCount = 0; - m_aTeamscore[TEAM_RED] = 0; - m_aTeamscore[TEAM_BLUE] = 0; - - // start countdown if there're enough players, otherwise do warmup till there're - if(HasEnoughPlayers()) - SetGameState(IGS_START_COUNTDOWN); - else - SetGameState(IGS_WARMUP_GAME, TIMER_INFINITE); - - Server()->DemoRecorder_HandleAutoStart(); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "start match type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS); - GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); -} - -void IGameController::StartRound() -{ - ResetGame(); - - ++m_RoundCount; - // start countdown if there're enough players, otherwise abort to warmup - if(HasEnoughPlayers()) - SetGameState(IGS_START_COUNTDOWN); - else - SetGameState(IGS_WARMUP_GAME, TIMER_INFINITE); + return false; } -// general -void IGameController::Snap(int SnappingClient) +void IGameController::EndRound() { - CNetObj_GameInfo *pGameInfoObj = (CNetObj_GameInfo *)Server()->SnapNewItem(NETOBJTYPE_GAMEINFO, 0, sizeof(CNetObj_GameInfo)); - if(!pGameInfoObj) + if(m_Warmup) // game can't end when we are running warmup return; - pGameInfoObj->m_GameFlags = m_GameFlags; - - pGameInfoObj->m_GameStateFlags = 0; - pGameInfoObj->m_GameStateTimer = 0; - switch(m_GameState) - { - case IGS_WARMUP_GAME: - case IGS_WARMUP_USER: - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_WARMUP; - pGameInfoObj->m_GameStateTimer = m_GameStateTimer; - break; - case IGS_START_COUNTDOWN: - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_STARTCOUNTDOWN|GAMESTATEFLAG_PAUSED; - pGameInfoObj->m_GameStateTimer = m_GameStateTimer; - break; - case IGS_GAME_PAUSED: - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_PAUSED; - pGameInfoObj->m_GameStateTimer = m_GameStateTimer; - break; - case IGS_END_ROUND: - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_ROUNDOVER; - pGameInfoObj->m_GameStateTimer = Server()->Tick()-m_GameStartTick-10*Server()->TickSpeed()+m_GameStateTimer; - break; - case IGS_END_MATCH: - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_GAMEOVER; - pGameInfoObj->m_GameStateTimer = Server()->Tick()-m_GameStartTick-10*Server()->TickSpeed()+m_GameStateTimer; - break; - case IGS_GAME_RUNNING: - // not effected - break; - } - if(m_SuddenDeath) - pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_SUDDENDEATH; - - pGameInfoObj->m_GameStartTick = m_GameStartTick; - - pGameInfoObj->m_ScoreLimit = g_Config.m_SvScorelimit; - pGameInfoObj->m_TimeLimit = g_Config.m_SvTimelimit; - - pGameInfoObj->m_MatchNum = (str_length(g_Config.m_SvMaprotation) && g_Config.m_SvMatchesPerMap) ? g_Config.m_SvMatchesPerMap : 0; - pGameInfoObj->m_MatchCurrent = m_MatchCount+1; -} - -void IGameController::Tick() -{ - // handle game states - if(m_GameState != IGS_GAME_RUNNING) - { - if(m_GameStateTimer > 0) - --m_GameStateTimer; - - if(m_GameStateTimer == 0) - { - // timer fires - switch(m_GameState) - { - case IGS_WARMUP_USER: - // end warmup - SetGameState(IGS_WARMUP_USER, 0); - break; - case IGS_START_COUNTDOWN: - // unpause the game - SetGameState(IGS_GAME_RUNNING); - break; - case IGS_GAME_PAUSED: - // end pause - SetGameState(IGS_GAME_PAUSED, 0); - break; - case IGS_END_ROUND: - // check if the match is over otherwise start next round - DoWincheckMatch(); - if(m_GameState != IGS_END_MATCH) - StartRound(); - break; - case IGS_END_MATCH: - // start next match - CycleMap(); - StartMatch(); - m_MatchCount++; - break; - case IGS_WARMUP_GAME: - case IGS_GAME_RUNNING: - // not effected - break; - } - } - else - { - // timer still running - switch(m_GameState) - { - case IGS_WARMUP_USER: - // check if player ready mode was disabled and it waits that all players are ready -> end warmup - if(!g_Config.m_SvPlayerReadyMode && m_GameStateTimer == TIMER_INFINITE) - SetGameState(IGS_WARMUP_USER, 0); - break; - case IGS_START_COUNTDOWN: - case IGS_GAME_PAUSED: - // freeze the game - ++m_GameStartTick; - break; - case IGS_WARMUP_GAME: - case IGS_GAME_RUNNING: - case IGS_END_MATCH: - case IGS_END_ROUND: - // not effected - break; - } - } - } - - // do team-balancing (skip this in survival, done there when a round starts) - if(IsTeamplay() && !(m_GameFlags&GAMEFLAG_SURVIVAL)) - { - switch(m_UnbalancedTick) - { - case TBALANCE_CHECK: - CheckTeamBalance(); - break; - case TBALANCE_OK: - break; - default: - if(Server()->Tick() > m_UnbalancedTick+g_Config.m_SvTeambalanceTime*Server()->TickSpeed()*60) - DoTeamBalance(); - } - } - - // check for inactive players - DoActivityCheck(); - - // win check - if(m_GameState == IGS_GAME_RUNNING && !GameServer()->m_World.m_ResetRequested) - { - if(m_GameFlags&GAMEFLAG_SURVIVAL) - DoWincheckRound(); - else - DoWincheckMatch(); - } -} - -// info -bool IGameController::IsFriendlyFire(int ClientID1, int ClientID2) const -{ - if(ClientID1 == ClientID2) - return false; - - if(IsTeamplay()) - { - if(!GameServer()->m_apPlayers[ClientID1] || !GameServer()->m_apPlayers[ClientID2]) - return false; - - if(!g_Config.m_SvTeamdamage && GameServer()->m_apPlayers[ClientID1]->GetTeam() == GameServer()->m_apPlayers[ClientID2]->GetTeam()) - return true; - } - - return false; -} - -bool IGameController::IsPlayerReadyMode() const -{ - return g_Config.m_SvPlayerReadyMode != 0 && (m_GameStateTimer == TIMER_INFINITE && (m_GameState == IGS_WARMUP_USER || m_GameState == IGS_GAME_PAUSED)); + GameServer()->m_World.m_Paused = true; + m_GameOverTick = Server()->Tick(); + m_SuddenDeath = 0; } -bool IGameController::IsTeamChangeAllowed() const +void IGameController::ResetGame() { - return !GameServer()->m_World.m_Paused || (m_GameState == IGS_START_COUNTDOWN && m_GameStartTick == Server()->Tick()); + GameServer()->m_World.m_ResetRequested = true; } -const char *IGameController::GetTeamName(int Team) const +const char *IGameController::GetTeamName(int Team) { if(IsTeamplay()) { @@ -808,19 +195,38 @@ else if(Team == TEAM_BLUE) return "blue team"; } - else if(Team == 0) - return "game"; + else + { + if(Team == 0) + return "game"; + } return "spectators"; } -// map static bool IsSeparator(char c) { return c == ';' || c == ' ' || c == ',' || c == '\t'; } +void IGameController::StartRound() +{ + ResetGame(); + + m_RoundStartTick = Server()->Tick(); + m_SuddenDeath = 0; + m_GameOverTick = -1; + GameServer()->m_World.m_Paused = false; + m_aTeamscore[TEAM_RED] = 0; + m_aTeamscore[TEAM_BLUE] = 0; + m_ForceBalanced = false; + Server()->DemoRecorder_HandleAutoStart(); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS); + GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); +} + void IGameController::ChangeMap(const char *pToMap) { str_copy(m_aMapWish, pToMap, sizeof(m_aMapWish)); - EndMatch(); + EndRound(); } void IGameController::CycleMap() @@ -832,15 +238,15 @@ GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); str_copy(g_Config.m_SvMap, m_aMapWish, sizeof(g_Config.m_SvMap)); m_aMapWish[0] = 0; - m_MatchCount = 0; + m_RoundCount = 0; return; } if(!str_length(g_Config.m_SvMaprotation)) return; - if(m_MatchCount < g_Config.m_SvMatchesPerMap-1) + if(m_RoundCount < g_Config.m_SvRoundsPerMap-1) { - if(g_Config.m_SvMatchSwap) + if(g_Config.m_SvRoundSwap) GameServer()->SwapTeams(); return; } @@ -891,7 +297,7 @@ while(IsSeparator(aBuf[i])) i++; - m_MatchCount = 0; + m_RoundCount = 0; char aBufMsg[256]; str_format(aBufMsg, sizeof(aBufMsg), "rotating map to %s", &aBuf[i]); @@ -899,202 +305,431 @@ str_copy(g_Config.m_SvMap, &aBuf[i], sizeof(g_Config.m_SvMap)); } -// spawn -bool IGameController::CanSpawn(int Team, vec2 *pOutPos) const +void IGameController::PostReset() { - // spectators can't spawn - if(Team == TEAM_SPECTATORS || GameServer()->m_World.m_Paused || GameServer()->m_World.m_ResetRequested) - return false; - - CSpawnEval Eval; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i]) + { + GameServer()->m_apPlayers[i]->Respawn(); + GameServer()->m_apPlayers[i]->m_Score = 0; + GameServer()->m_apPlayers[i]->m_ScoreStartTick = Server()->Tick(); + GameServer()->m_apPlayers[i]->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2; + } + } +} +void IGameController::OnPlayerInfoChange(class CPlayer *pP) +{ + const int aTeamColors[2] = {65387, 10223467}; if(IsTeamplay()) { - Eval.m_FriendlyTeam = Team; - - // first try own team spawn, then normal spawn and then enemy - EvaluateSpawnType(&Eval, 1+(Team&1)); - if(!Eval.m_Got) + pP->m_TeeInfos.m_UseCustomColor = 1; + if(pP->GetTeam() >= TEAM_RED && pP->GetTeam() <= TEAM_BLUE) { - EvaluateSpawnType(&Eval, 0); - if(!Eval.m_Got) - EvaluateSpawnType(&Eval, 1+((Team+1)&1)); + pP->m_TeeInfos.m_ColorBody = aTeamColors[pP->GetTeam()]; + pP->m_TeeInfos.m_ColorFeet = aTeamColors[pP->GetTeam()]; + } + else + { + pP->m_TeeInfos.m_ColorBody = 12895054; + pP->m_TeeInfos.m_ColorFeet = 12895054; } } +} + + +int IGameController::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon) +{ + // do scoreing + if(!pKiller || Weapon == WEAPON_GAME) + return 0; + if(pKiller != pVictim->GetPlayer() && pVictim->frz_tick > 0) + pVictim->GetPlayer()->m_Score--; // suicide while frozen causes -1 score else { - EvaluateSpawnType(&Eval, 0); - EvaluateSpawnType(&Eval, 1); - EvaluateSpawnType(&Eval, 2); + if(IsTeamplay() && pVictim->GetPlayer()->GetTeam() == pKiller->GetTeam()) + return 0; // teamkill + else + return 0; } + if(Weapon == WEAPON_SELF) + pVictim->GetPlayer()->m_RespawnTick = 0.5; + return 0; +} - *pOutPos = Eval.m_Pos; - return Eval.m_Got; +void IGameController::OnCharacterSpawn(class CCharacter *pChr) +{ + // default health + pChr->IncreaseHealth(10); + + // give default weapons + //hammer second + pChr->GiveWeapon(WEAPON_GUN, 10); + pChr->GiveWeapon(WEAPON_HAMMER, -1); } -float IGameController::EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos) const +void IGameController::DoWarmup(int Seconds) { - float Score = 0.0f; - CCharacter *pC = static_cast(GameServer()->m_World.FindFirst(CGameWorld::ENTTYPE_CHARACTER)); - for(; pC; pC = (CCharacter *)pC->TypeNext()) + if(Seconds < 0) + m_Warmup = 0; + else + m_Warmup = Seconds*Server()->TickSpeed(); +} + +bool IGameController::IsFriendlyFire(int ClientID1, int ClientID2) +{ + if(ClientID1 == ClientID2) + return false; + + if(IsTeamplay()) { - // team mates are not as dangerous as enemies - float Scoremod = 1.0f; - if(pEval->m_FriendlyTeam != -1 && pC->GetPlayer()->GetTeam() == pEval->m_FriendlyTeam) - Scoremod = 0.5f; + if(!GameServer()->m_apPlayers[ClientID1] || !GameServer()->m_apPlayers[ClientID2]) + return false; - float d = distance(Pos, pC->m_Pos); - Score += Scoremod * (d == 0 ? 1000000000.0f : 1.0f/d); + if(GameServer()->m_apPlayers[ClientID1]->GetTeam() == GameServer()->m_apPlayers[ClientID2]->GetTeam()) + return true; } - return Score; + return false; } -void IGameController::EvaluateSpawnType(CSpawnEval *pEval, int Type) const +bool IGameController::IsForceBalanced() { - // get spawn point - for(int i = 0; i < m_aNumSpawnPoints[Type]; i++) + if(m_ForceBalanced) { - // check if the position is occupado - CCharacter *aEnts[MAX_CLIENTS]; - int Num = GameServer()->m_World.FindEntities(m_aaSpawnPoints[Type][i], 64, (CEntity**)aEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER); - vec2 Positions[5] = { vec2(0.0f, 0.0f), vec2(-32.0f, 0.0f), vec2(0.0f, -32.0f), vec2(32.0f, 0.0f), vec2(0.0f, 32.0f) }; // start, left, up, right, down - int Result = -1; - for(int Index = 0; Index < 5 && Result == -1; ++Index) + m_ForceBalanced = false; + return true; + } + else + return false; +} + +bool IGameController::CanBeMovedOnBalance(int ClientID) +{ + return true; +} + +void IGameController::Tick() +{ + // do warmup + if(m_Warmup) + { + m_Warmup--; + if(!m_Warmup) + StartRound(); + } + + if(m_GameOverTick != -1) + { + // game over.. wait for restart + if(Server()->Tick() > m_GameOverTick+Server()->TickSpeed()*10) { - Result = Index; - for(int c = 0; c < Num; ++c) - if(GameServer()->Collision()->CheckPoint(m_aaSpawnPoints[Type][i]+Positions[Index]) || - distance(aEnts[c]->m_Pos, m_aaSpawnPoints[Type][i]+Positions[Index]) <= aEnts[c]->m_ProximityRadius) + CycleMap(); + StartRound(); + m_RoundCount++; + } + } + + // game is Paused + if(GameServer()->m_World.m_Paused) + ++m_RoundStartTick; + + // do team-balancing + if(IsTeamplay() && m_UnbalancedTick != -1 && Server()->Tick() > m_UnbalancedTick+g_Config.m_SvTeambalanceTime*Server()->TickSpeed()*60) + { + GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", "Balancing teams"); + + int aT[2] = {0,0}; + float aTScore[2] = {0,0}; + float aPScore[MAX_CLIENTS] = {0.0f}; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) + { + aT[GameServer()->m_apPlayers[i]->GetTeam()]++; + aPScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/ + (Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick); + aTScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPScore[i]; + } + } + + // are teams unbalanced? + if(absolute(aT[0]-aT[1]) >= 2) + { + int M = (aT[0] > aT[1]) ? 0 : 1; + int NumBalance = absolute(aT[0]-aT[1]) / 2; + + do + { + CPlayer *pP = 0; + float PD = aTScore[M]; + for(int i = 0; i < MAX_CLIENTS; i++) { - Result = -1; - break; + if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i)) + continue; + // remember the player who would cause lowest score-difference + if(GameServer()->m_apPlayers[i]->GetTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD)) + { + pP = GameServer()->m_apPlayers[i]; + PD = absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])); + } } + + // move the player to the other team + int Temp = pP->m_LastActionTick; + pP->SetTeam(M^1); + pP->m_LastActionTick = Temp; + + pP->Respawn(); + pP->m_ForceBalanced = true; + } while (--NumBalance); + + m_ForceBalanced = true; } - if(Result == -1) - continue; // try next spawn point + m_UnbalancedTick = -1; + } - vec2 P = m_aaSpawnPoints[Type][i]+Positions[Result]; - float S = EvaluateSpawnPos(pEval, P); - if(!pEval->m_Got || pEval->m_Score > S) + // check for inactive players + if(g_Config.m_SvInactiveKickTime > 0) + { + for(int i = 0; i < MAX_CLIENTS; ++i) { - pEval->m_Got = true; - pEval->m_Score = S; - pEval->m_Pos = P; + #ifdef CONF_DEBUG + if(g_Config.m_DbgDummies) + { + if(i >= MAX_CLIENTS-g_Config.m_DbgDummies) + break; + } + #endif + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && !Server()->IsAuthed(i)) + { + if(Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick+g_Config.m_SvInactiveKickTime*Server()->TickSpeed()*60) + { + switch(g_Config.m_SvInactiveKick) + { + case 0: + { + // move player to spectator + GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS); + } + break; + case 1: + { + // move player to spectator if the reserved slots aren't filled yet, kick him otherwise + int Spectators = 0; + for(int j = 0; j < MAX_CLIENTS; ++j) + if(GameServer()->m_apPlayers[j] && GameServer()->m_apPlayers[j]->GetTeam() == TEAM_SPECTATORS) + ++Spectators; + if(Spectators >= g_Config.m_SvSpectatorSlots) + Server()->Kick(i, "Kicked for inactivity"); + else + GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS); + } + break; + case 2: + { + // kick the player + Server()->Kick(i, "Kicked for inactivity"); + } + } + } + } } } + + DoWincheck(); } -bool IGameController::GetStartRespawnState() const + +bool IGameController::IsTeamplay() const { - if(m_GameFlags&GAMEFLAG_SURVIVAL) - { - // players can always respawn during warmup or match/round start countdown - if(m_GameState == IGS_WARMUP_GAME || m_GameState == IGS_WARMUP_USER || (m_GameState == IGS_START_COUNTDOWN && m_GameStartTick == Server()->Tick())) - return false; - else - return true; - } - else - return false; + return m_GameFlags&GAMEFLAG_TEAMS; } -// team -bool IGameController::CanChangeTeam(CPlayer *pPlayer, int JoinTeam) const +void IGameController::Snap(int SnappingClient) { - if(!IsTeamplay() || JoinTeam == TEAM_SPECTATORS || !g_Config.m_SvTeambalanceTime) - return true; + CNetObj_GameInfo *pGameInfoObj = (CNetObj_GameInfo *)Server()->SnapNewItem(NETOBJTYPE_GAMEINFO, 0, sizeof(CNetObj_GameInfo)); + if(!pGameInfoObj) + return; + + pGameInfoObj->m_GameFlags = m_GameFlags; + pGameInfoObj->m_GameStateFlags = 0; + if(m_GameOverTick != -1) + pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_GAMEOVER; + if(m_SuddenDeath) + pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_SUDDENDEATH; + if(GameServer()->m_World.m_Paused) + pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_PAUSED; + pGameInfoObj->m_RoundStartTick = m_RoundStartTick; + pGameInfoObj->m_WarmupTimer = m_Warmup; + + pGameInfoObj->m_ScoreLimit = g_Config.m_SvScorelimit; + pGameInfoObj->m_TimeLimit = g_Config.m_SvTimelimit; + + pGameInfoObj->m_RoundNum = (str_length(g_Config.m_SvMaprotation) && g_Config.m_SvRoundsPerMap) ? g_Config.m_SvRoundsPerMap : 0; + pGameInfoObj->m_RoundCurrent = m_RoundCount+1; +} + +int IGameController::GetAutoTeam(int NotThisID) +{ + // this will force the auto balancer to work overtime aswell + if(g_Config.m_DbgStress) + return 0; - // simulate what would happen if the player changes team - int aPlayerCount[NUM_TEAMS] = { m_aTeamSize[TEAM_RED], m_aTeamSize[TEAM_BLUE] }; - aPlayerCount[JoinTeam]++; - if(pPlayer->GetTeam() != TEAM_SPECTATORS) - aPlayerCount[JoinTeam^1]--; + int aNumplayers[2] = {0,0}; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i] && i != NotThisID) + { + if(GameServer()->m_apPlayers[i]->GetTeam() >= TEAM_RED && GameServer()->m_apPlayers[i]->GetTeam() <= TEAM_BLUE) + aNumplayers[GameServer()->m_apPlayers[i]->GetTeam()]++; + } + } + + int Team = 0; + if(IsTeamplay()) + Team = aNumplayers[TEAM_RED] > aNumplayers[TEAM_BLUE] ? TEAM_BLUE : TEAM_RED; - // check if the player-difference decreases or is smaller than 2 - return aPlayerCount[JoinTeam]-aPlayerCount[JoinTeam^1] < NUM_TEAMS; + if(CanJoinTeam(Team, NotThisID)) + return Team; + return -1; } -bool IGameController::CanJoinTeam(int Team, int NotThisID) const +bool IGameController::CanJoinTeam(int Team, int NotThisID) { if(Team == TEAM_SPECTATORS || (GameServer()->m_apPlayers[NotThisID] && GameServer()->m_apPlayers[NotThisID]->GetTeam() != TEAM_SPECTATORS)) return true; - // check if there're enough player slots left - return m_aTeamSize[TEAM_RED]+m_aTeamSize[TEAM_BLUE] < Server()->MaxClients()-g_Config.m_SvSpectatorSlots; + int aNumplayers[2] = {0,0}; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i] && i != NotThisID) + { + if(GameServer()->m_apPlayers[i]->GetTeam() >= TEAM_RED && GameServer()->m_apPlayers[i]->GetTeam() <= TEAM_BLUE) + aNumplayers[GameServer()->m_apPlayers[i]->GetTeam()]++; + } + } + + return (aNumplayers[0] + aNumplayers[1]) < Server()->MaxClients()-g_Config.m_SvSpectatorSlots; } -int IGameController::ClampTeam(int Team) const +bool IGameController::CheckTeamBalance() { - if(Team < TEAM_RED) - return TEAM_SPECTATORS; - if(IsTeamplay()) - return Team&1; - return TEAM_RED; + if(!IsTeamplay() || !g_Config.m_SvTeambalanceTime) + return true; + + int aT[2] = {0, 0}; + for(int i = 0; i < MAX_CLIENTS; i++) + { + CPlayer *pP = GameServer()->m_apPlayers[i]; + if(pP && pP->GetTeam() != TEAM_SPECTATORS) + aT[pP->GetTeam()]++; + } + + char aBuf[256]; + if(absolute(aT[0]-aT[1]) >= 2) + { + str_format(aBuf, sizeof(aBuf), "Teams are NOT balanced (red=%d blue=%d)", aT[0], aT[1]); + GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); + if(GameServer()->m_pController->m_UnbalancedTick == -1) + GameServer()->m_pController->m_UnbalancedTick = Server()->Tick(); + return false; + } + else + { + str_format(aBuf, sizeof(aBuf), "Teams are balanced (red=%d blue=%d)", aT[0], aT[1]); + GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); + GameServer()->m_pController->m_UnbalancedTick = -1; + return true; + } } -void IGameController::DoTeamChange(CPlayer *pPlayer, int Team, bool DoChatMsg) +bool IGameController::CanChangeTeam(CPlayer *pPlayer, int JoinTeam) { - Team = ClampTeam(Team); - if(Team == pPlayer->GetTeam()) - return; + int aT[2] = {0, 0}; - int OldTeam = pPlayer->GetTeam(); - pPlayer->SetTeam(Team); + if (!IsTeamplay() || JoinTeam == TEAM_SPECTATORS || !g_Config.m_SvTeambalanceTime) + return true; - int ClientID = pPlayer->GetCID(); - char aBuf[128]; - if(DoChatMsg) + for(int i = 0; i < MAX_CLIENTS; i++) { - str_format(aBuf, sizeof(aBuf), "'%s' joined the %s", Server()->ClientName(ClientID), GetTeamName(Team)); - GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); + CPlayer *pP = GameServer()->m_apPlayers[i]; + if(pP && pP->GetTeam() != TEAM_SPECTATORS) + aT[pP->GetTeam()]++; } - str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' m_Team=%d", ClientID, Server()->ClientName(ClientID), Team); - GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); + // simulate what would happen if changed team + aT[JoinTeam]++; + if (pPlayer->GetTeam() != TEAM_SPECTATORS) + aT[JoinTeam^1]--; - // update effected game settings - if(OldTeam != TEAM_SPECTATORS) + // there is a player-difference of at least 2 + if(absolute(aT[0]-aT[1]) >= 2) { - --m_aTeamSize[OldTeam]; - m_UnbalancedTick = TBALANCE_CHECK; + // player wants to join team with less players + if ((aT[0] < aT[1] && JoinTeam == TEAM_RED) || (aT[0] > aT[1] && JoinTeam == TEAM_BLUE)) + return true; + else + return false; } - if(Team != TEAM_SPECTATORS) + else + return true; +} + +void IGameController::DoWincheck() +{ + if(m_GameOverTick == -1 && !m_Warmup && !GameServer()->m_World.m_ResetRequested) { - ++m_aTeamSize[Team]; - m_UnbalancedTick = TBALANCE_CHECK; - if(m_GameState == IGS_WARMUP_GAME && HasEnoughPlayers()) - SetGameState(IGS_WARMUP_GAME, 0); - pPlayer->m_IsReadyToPlay = !IsPlayerReadyMode(); - if(m_GameFlags&GAMEFLAG_SURVIVAL) - pPlayer->m_RespawnDisabled = GetStartRespawnState(); + if(IsTeamplay()) + { + // check score win condition + if((g_Config.m_SvScorelimit > 0 && (m_aTeamscore[TEAM_RED] >= g_Config.m_SvScorelimit || m_aTeamscore[TEAM_BLUE] >= g_Config.m_SvScorelimit)) || + (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_RoundStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) + { + if(m_aTeamscore[TEAM_RED] != m_aTeamscore[TEAM_BLUE]) + EndRound(); + else + m_SuddenDeath = 1; + } + } + else + { + // gather some stats + int Topscore = 0; + int TopscoreCount = 0; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i]) + { + if(GameServer()->m_apPlayers[i]->m_Score > Topscore) + { + Topscore = GameServer()->m_apPlayers[i]->m_Score; + TopscoreCount = 1; + } + else if(GameServer()->m_apPlayers[i]->m_Score == Topscore) + TopscoreCount++; + } + } + + // check score win condition + if((g_Config.m_SvScorelimit > 0 && Topscore >= g_Config.m_SvScorelimit) || + (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_RoundStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) + { + if(TopscoreCount == 1) + EndRound(); + else + m_SuddenDeath = 1; + } + } } - OnPlayerInfoChange(pPlayer); - GameServer()->OnClientTeamChange(ClientID); } -int IGameController::GetStartTeam() +int IGameController::ClampTeam(int Team) { - // this will force the auto balancer to work overtime aswell - if(g_Config.m_DbgStress) - return TEAM_RED; - - if(g_Config.m_SvTournamentMode) + if(Team < 0) return TEAM_SPECTATORS; - - // determine new team - int Team = TEAM_RED; if(IsTeamplay()) - Team = m_aTeamSize[TEAM_RED] > m_aTeamSize[TEAM_BLUE] ? TEAM_BLUE : TEAM_RED; - - // check if there're enough player slots left - if(m_aTeamSize[TEAM_RED]+m_aTeamSize[TEAM_BLUE] < Server()->MaxClients()-g_Config.m_SvSpectatorSlots) - { - ++m_aTeamSize[Team]; - m_UnbalancedTick = TBALANCE_CHECK; - if(m_GameState == IGS_WARMUP_GAME && HasEnoughPlayers()) - SetGameState(IGS_WARMUP_GAME, 0); - return Team; - } - return TEAM_SPECTATORS; + return Team&1; + return 0; } diff -Naur ../teeworlds/src/game/server/gamecontroller.h src/game/server/gamecontroller.h --- ../teeworlds/src/game/server/gamecontroller.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamecontroller.h 2012-07-08 19:42:32.842259599 +1000 @@ -5,7 +5,14 @@ #include -#include +#ifdef _MSC_VER +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif /* Class: Game Controller @@ -14,59 +21,16 @@ */ class IGameController { + vec2 m_aaSpawnPoints[3][64]; + int m_aNumSpawnPoints[3]; + class CGameContext *m_pGameServer; class IServer *m_pServer; - // activity - void DoActivityCheck(); - bool GetPlayersReadyState(); - void SetPlayersReadyState(bool ReadyState); - - // balancing - enum - { - TBALANCE_CHECK=-2, - TBALANCE_OK, - }; - int m_aTeamSize[NUM_TEAMS]; - int m_UnbalancedTick; - - virtual bool CanBeMovedOnBalance(int ClientID) const; - void CheckTeamBalance(); - void DoTeamBalance(); - - // game - enum EGameState - { - // internal game states - IGS_WARMUP_GAME, // warmup started by game because there're not enough players (infinite) - IGS_WARMUP_USER, // warmup started by user action via rcon or new match (infinite or timer) - - IGS_START_COUNTDOWN, // start countown to unpause the game or start match/round (tick timer) - - IGS_GAME_PAUSED, // game paused (infinite or tick timer) - IGS_GAME_RUNNING, // game running (infinite) - - IGS_END_MATCH, // match is over (tick timer) - IGS_END_ROUND, // round is over (tick timer) - }; - EGameState m_GameState; - int m_GameStateTimer; - - virtual void DoWincheckMatch(); - virtual void DoWincheckRound() {}; - bool HasEnoughPlayers() const { return (IsTeamplay() && m_aTeamSize[TEAM_RED] > 0 && m_aTeamSize[TEAM_BLUE] > 0) || (!IsTeamplay() && m_aTeamSize[TEAM_RED] > 1); } - void ResetGame(); - void SetGameState(EGameState GameState, int Timer=0); - void StartMatch(); - void StartRound(); - - // map - char m_aMapWish[128]; - - void CycleMap(); +protected: + CGameContext *GameServer() const { return m_pGameServer; } + IServer *Server() const { return m_pServer; } - // spawn struct CSpawnEval { CSpawnEval() @@ -81,57 +45,59 @@ int m_FriendlyTeam; float m_Score; }; - vec2 m_aaSpawnPoints[3][64]; - int m_aNumSpawnPoints[3]; - - float EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos) const; - void EvaluateSpawnType(CSpawnEval *pEval, int Type) const; - // team - int ClampTeam(int Team) const; + float EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos); + void EvaluateSpawnType(CSpawnEval *pEval, int Type); + bool EvaluateSpawn(class CPlayer *pP, vec2 *pPos); -protected: - CGameContext *GameServer() const { return m_pGameServer; } - IServer *Server() const { return m_pServer; } + void CycleMap(); + void ResetGame(); - // game - int m_GameStartTick; - int m_MatchCount; - int m_RoundCount; + char m_aMapWish[128]; + + + int m_RoundStartTick; + int m_GameOverTick; int m_SuddenDeath; - int m_aTeamscore[NUM_TEAMS]; - void EndMatch() { SetGameState(IGS_END_MATCH, 10); } - void EndRound() { SetGameState(IGS_END_ROUND, 10); } + int m_aTeamscore[2]; + + int m_Warmup; + int m_RoundCount; - // info int m_GameFlags; - const char *m_pGameType; + int m_UnbalancedTick; + bool m_ForceBalanced; public: + const char *m_pGameType; + + bool IsTeamplay() const; + bool IsGameOver() const { return m_GameOverTick != -1; } + IGameController(class CGameContext *pGameServer); - virtual ~IGameController() {}; + virtual ~IGameController(); - // event - /* - Function: on_CCharacter_death - Called when a CCharacter in the world dies. + virtual void DoWincheck(); + + void DoWarmup(int Seconds); + + void StartRound(); + void EndRound(); + void ChangeMap(const char *pToMap); + + bool IsFriendlyFire(int ClientID1, int ClientID2); + + bool IsForceBalanced(); - Arguments: - victim - The CCharacter that died. - killer - The player that killed it. - weapon - What weapon that killed it. Can be -1 for undefined - weapon when switching team or player suicides. - */ - virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); /* - Function: on_CCharacter_spawn - Called when a CCharacter spawns into the game world. - Arguments: - chr - The CCharacter that was spawned. */ - virtual void OnCharacterSpawn(class CCharacter *pChr); + virtual bool CanBeMovedOnBalance(int ClientID); + + virtual void Tick(); + + virtual void Snap(int SnappingClient); /* Function: on_entity @@ -147,49 +113,44 @@ */ virtual bool OnEntity(int Index, vec2 Pos); - void OnPlayerDisconnect(class CPlayer *pPlayer, const char *pReason); - void OnPlayerInfoChange(class CPlayer *pPlayer); - void OnPlayerReadyChange(class CPlayer *pPlayer); + /* + Function: on_CCharacter_spawn + Called when a CCharacter spawns into the game world. + + Arguments: + chr - The CCharacter that was spawned. + */ + virtual void OnCharacterSpawn(class CCharacter *pChr); + + /* + Function: on_CCharacter_death + Called when a CCharacter in the world dies. + + Arguments: + victim - The CCharacter that died. + killer - The player that killed it. + weapon - What weapon that killed it. Can be -1 for undefined + weapon when switching team or player suicides. + */ + virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); - void OnReset(); - // game - enum - { - TIMER_INFINITE = -1, - }; + virtual void OnPlayerInfoChange(class CPlayer *pP); - void DoPause(int Seconds) { SetGameState(IGS_GAME_PAUSED, Seconds); } - void DoWarmup(int Seconds) { SetGameState(IGS_WARMUP_USER, Seconds); } + // + virtual bool CanSpawn(int Team, vec2 *pPos); - // general - virtual void Snap(int SnappingClient); - virtual void Tick(); + /* - // info - bool IsFriendlyFire(int ClientID1, int ClientID2) const; - bool IsGamePaused() const { return m_GameState == IGS_GAME_PAUSED || m_GameState == IGS_START_COUNTDOWN; } - bool IsPlayerReadyMode() const; - bool IsTeamChangeAllowed() const; - bool IsTeamplay() const { return m_GameFlags&GAMEFLAG_TEAMS; } - - const char *GetGameType() const { return m_pGameType; } - const char *GetTeamName(int Team) const; - - // map - void ChangeMap(const char *pToMap); + */ + virtual const char *GetTeamName(int Team); + virtual int GetAutoTeam(int NotThisID); + virtual bool CanJoinTeam(int Team, int NotThisID); + bool CheckTeamBalance(); + bool CanChangeTeam(CPlayer *pPplayer, int JoinTeam); + int ClampTeam(int Team); - //spawn - bool CanSpawn(int Team, vec2 *pPos) const; - bool GetStartRespawnState() const; - - // team - bool CanJoinTeam(int Team, int NotThisID) const; - bool CanChangeTeam(CPlayer *pPplayer, int JoinTeam) const; - - void DoTeamChange(class CPlayer *pPlayer, int Team, bool DoChatMsg=true); - - int GetStartTeam(); + virtual void PostReset(); }; #endif diff -Naur ../teeworlds/src/game/server/gamemodes/ctf.cpp src/game/server/gamemodes/ctf.cpp --- ../teeworlds/src/game/server/gamemodes/ctf.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/ctf.cpp 2012-07-08 19:42:32.842259599 +1000 @@ -6,38 +6,39 @@ #include #include -#include #include +#include #include "ctf.h" -CGameControllerCTF::CGameControllerCTF(CGameContext *pGameServer) +CGameControllerCTF::CGameControllerCTF(class CGameContext *pGameServer) : IGameController(pGameServer) { - // game m_apFlags[0] = 0; m_apFlags[1] = 0; m_pGameType = "CTF"; m_GameFlags = GAMEFLAG_TEAMS|GAMEFLAG_FLAGS; } -// balancing -bool CGameControllerCTF::CanBeMovedOnBalance(int ClientID) +bool CGameControllerCTF::OnEntity(int Index, vec2 Pos) { - CCharacter* Character = GameServer()->m_apPlayers[ClientID]->GetCharacter(); - if(Character) - { - for(int fi = 0; fi < 2; fi++) - { - CFlag *F = m_apFlags[fi]; - if(F->m_pCarryingCharacter == Character) - return false; - } - } + if(IGameController::OnEntity(Index, Pos)) + return true; + + int Team = -1; + if(Index == ENTITY_FLAGSTAND_RED) Team = TEAM_RED; + if(Index == ENTITY_FLAGSTAND_BLUE) Team = TEAM_BLUE; + if(Team == -1 || m_apFlags[Team]) + return false; + + CFlag *F = new CFlag(&GameServer()->m_World, Team); + F->m_StandPos = Pos; + F->m_Pos = Pos; + m_apFlags[Team] = F; + GameServer()->m_World.InsertEntity(F); return true; } -// event -int CGameControllerCTF::OnCharacterDeath(CCharacter *pVictim, CPlayer *pKiller, int WeaponID) +int CGameControllerCTF::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int WeaponID) { IGameController::OnCharacterDeath(pVictim, pKiller, WeaponID); int HadFlag = 0; @@ -65,48 +66,45 @@ return HadFlag; } -bool CGameControllerCTF::OnEntity(int Index, vec2 Pos) +void CGameControllerCTF::DoWincheck() { - if(IGameController::OnEntity(Index, Pos)) - return true; - - int Team = -1; - if(Index == ENTITY_FLAGSTAND_RED) Team = TEAM_RED; - if(Index == ENTITY_FLAGSTAND_BLUE) Team = TEAM_BLUE; - if(Team == -1 || m_apFlags[Team]) - return false; - - CFlag *F = new CFlag(&GameServer()->m_World, Team); - F->m_StandPos = Pos; - F->m_Pos = Pos; - m_apFlags[Team] = F; - GameServer()->m_World.InsertEntity(F); - return true; + if(m_GameOverTick == -1 && !m_Warmup) + { + // check score win condition + if((g_Config.m_SvScorelimit > 0 && (m_aTeamscore[TEAM_RED] >= g_Config.m_SvScorelimit || m_aTeamscore[TEAM_BLUE] >= g_Config.m_SvScorelimit)) || + (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_RoundStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) + { + if(m_SuddenDeath) + { + if(m_aTeamscore[TEAM_RED]/100 != m_aTeamscore[TEAM_BLUE]/100) + EndRound(); + } + else + { + if(m_aTeamscore[TEAM_RED] != m_aTeamscore[TEAM_BLUE]) + EndRound(); + else + m_SuddenDeath = 1; + } + } + } } -// game -void CGameControllerCTF::DoWincheckMatch() +bool CGameControllerCTF::CanBeMovedOnBalance(int ClientID) { - // check score win condition - if((g_Config.m_SvScorelimit > 0 && (m_aTeamscore[TEAM_RED] >= g_Config.m_SvScorelimit || m_aTeamscore[TEAM_BLUE] >= g_Config.m_SvScorelimit)) || - (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_GameStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) + CCharacter* Character = GameServer()->m_apPlayers[ClientID]->GetCharacter(); + if(Character) { - if(m_SuddenDeath) - { - if(m_aTeamscore[TEAM_RED]/100 != m_aTeamscore[TEAM_BLUE]/100) - EndMatch(); - } - else + for(int fi = 0; fi < 2; fi++) { - if(m_aTeamscore[TEAM_RED] != m_aTeamscore[TEAM_BLUE]) - EndMatch(); - else - m_SuddenDeath = 1; + CFlag *F = m_apFlags[fi]; + if(F->m_pCarryingCharacter == Character) + return false; } } + return true; } -// general void CGameControllerCTF::Snap(int SnappingClient) { IGameController::Snap(SnappingClient); @@ -118,7 +116,6 @@ pGameDataObj->m_TeamscoreRed = m_aTeamscore[TEAM_RED]; pGameDataObj->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE]; - pGameDataObj->m_FlagDropTickRed = 0; if(m_apFlags[TEAM_RED]) { if(m_apFlags[TEAM_RED]->m_AtStand) @@ -126,14 +123,10 @@ else if(m_apFlags[TEAM_RED]->m_pCarryingCharacter && m_apFlags[TEAM_RED]->m_pCarryingCharacter->GetPlayer()) pGameDataObj->m_FlagCarrierRed = m_apFlags[TEAM_RED]->m_pCarryingCharacter->GetPlayer()->GetCID(); else - { pGameDataObj->m_FlagCarrierRed = FLAG_TAKEN; - pGameDataObj->m_FlagDropTickRed = m_apFlags[TEAM_RED]->m_DropTick; - } } else pGameDataObj->m_FlagCarrierRed = FLAG_MISSING; - pGameDataObj->m_FlagDropTickBlue = 0; if(m_apFlags[TEAM_BLUE]) { if(m_apFlags[TEAM_BLUE]->m_AtStand) @@ -141,10 +134,7 @@ else if(m_apFlags[TEAM_BLUE]->m_pCarryingCharacter && m_apFlags[TEAM_BLUE]->m_pCarryingCharacter->GetPlayer()) pGameDataObj->m_FlagCarrierBlue = m_apFlags[TEAM_BLUE]->m_pCarryingCharacter->GetPlayer()->GetCID(); else - { pGameDataObj->m_FlagCarrierBlue = FLAG_TAKEN; - pGameDataObj->m_FlagDropTickBlue = m_apFlags[TEAM_BLUE]->m_DropTick; - } } else pGameDataObj->m_FlagCarrierBlue = FLAG_MISSING; @@ -262,8 +252,7 @@ if(!pPlayer) continue; - if((pPlayer->GetTeam() == TEAM_SPECTATORS || pPlayer->m_DeadSpecMode) && pPlayer->GetSpectatorID() != SPEC_FREEVIEW && - GameServer()->m_apPlayers[pPlayer->GetSpectatorID()] && GameServer()->m_apPlayers[pPlayer->GetSpectatorID()]->GetTeam() == fi) + if(pPlayer->GetTeam() == TEAM_SPECTATORS && pPlayer->m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[pPlayer->m_SpectatorID] && GameServer()->m_apPlayers[pPlayer->m_SpectatorID]->GetTeam() == fi) GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c); else if(pPlayer->GetTeam() == fi) GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c); diff -Naur ../teeworlds/src/game/server/gamemodes/ctf.h src/game/server/gamemodes/ctf.h --- ../teeworlds/src/game/server/gamemodes/ctf.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/ctf.h 2012-07-08 19:28:03.418259861 +1000 @@ -7,24 +7,17 @@ class CGameControllerCTF : public IGameController { - // balancing - virtual bool CanBeMovedOnBalance(int ClientID); - - // game +public: class CFlag *m_apFlags[2]; - virtual void DoWincheckMatch(); - -public: CGameControllerCTF(class CGameContext *pGameServer); - - // event - virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); - virtual bool OnEntity(int Index, vec2 Pos); - - // general + virtual void DoWincheck(); + virtual bool CanBeMovedOnBalance(int ClientID); virtual void Snap(int SnappingClient); virtual void Tick(); + + virtual bool OnEntity(int Index, vec2 Pos); + virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); }; #endif diff -Naur ../teeworlds/src/game/server/gamemodes/dm.cpp src/game/server/gamemodes/dm.cpp --- ../teeworlds/src/game/server/gamemodes/dm.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/dm.cpp 2012-07-08 19:28:03.418259861 +1000 @@ -3,8 +3,13 @@ #include "dm.h" -CGameControllerDM::CGameControllerDM(CGameContext *pGameServer) +CGameControllerDM::CGameControllerDM(class CGameContext *pGameServer) : IGameController(pGameServer) { m_pGameType = "DM"; } + +void CGameControllerDM::Tick() +{ + IGameController::Tick(); +} diff -Naur ../teeworlds/src/game/server/gamemodes/dm.h src/game/server/gamemodes/dm.h --- ../teeworlds/src/game/server/gamemodes/dm.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/dm.h 2012-07-08 19:28:03.418259861 +1000 @@ -8,6 +8,6 @@ { public: CGameControllerDM(class CGameContext *pGameServer); + virtual void Tick(); }; - #endif diff -Naur ../teeworlds/src/game/server/gamemodes/lms.cpp src/game/server/gamemodes/lms.cpp --- ../teeworlds/src/game/server/gamemodes/lms.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/lms.cpp 1970-01-01 10:00:00.000000000 +1000 @@ -1,70 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include - -#include -#include -#include -#include "lms.h" - -CGameControllerLMS::CGameControllerLMS(CGameContext *pGameServer) : IGameController(pGameServer) -{ - m_pGameType = "LMS"; - m_GameFlags = GAMEFLAG_SURVIVAL; -} - -// event -int CGameControllerLMS::OnCharacterDeath(CCharacter *pVictim, CPlayer *pKiller, int Weapon) -{ - // update spectator modes for dead players in survival - if(m_GameFlags&GAMEFLAG_SURVIVAL) - { - for(int i = 0; i < MAX_CLIENTS; ++i) - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_DeadSpecMode) - GameServer()->m_apPlayers[i]->UpdateDeadSpecMode(); - } - - return 0; -} - -// game -void CGameControllerLMS::DoWincheckRound() -{ - // check for time based win - if(g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_GameStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60) - { - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && - (!GameServer()->m_apPlayers[i]->m_RespawnDisabled || - (GameServer()->m_apPlayers[i]->GetCharacter() && GameServer()->m_apPlayers[i]->GetCharacter()->IsAlive()))) - GameServer()->m_apPlayers[i]->m_Score++; - } - - EndRound(); - } - else - { - // check for survival win - CPlayer *pAlivePlayer = 0; - int AlivePlayerCount = 0; - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && - (!GameServer()->m_apPlayers[i]->m_RespawnDisabled || - (GameServer()->m_apPlayers[i]->GetCharacter() && GameServer()->m_apPlayers[i]->GetCharacter()->IsAlive()))) - { - ++AlivePlayerCount; - pAlivePlayer = GameServer()->m_apPlayers[i]; - } - } - - if(AlivePlayerCount == 0) // no winner - EndRound(); - else if(AlivePlayerCount == 1) // 1 winner - { - pAlivePlayer->m_Score++; - EndRound(); - } - } -} diff -Naur ../teeworlds/src/game/server/gamemodes/lms.h src/game/server/gamemodes/lms.h --- ../teeworlds/src/game/server/gamemodes/lms.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/lms.h 1970-01-01 10:00:00.000000000 +1000 @@ -1,19 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#ifndef GAME_SERVER_GAMEMODES_LMS_H -#define GAME_SERVER_GAMEMODES_LMS_H -#include - -class CGameControllerLMS : public IGameController -{ -public: - CGameControllerLMS(class CGameContext *pGameServer); - - // event - virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); - - // game - virtual void DoWincheckRound(); -}; - -#endif diff -Naur ../teeworlds/src/game/server/gamemodes/mod.cpp src/game/server/gamemodes/mod.cpp --- ../teeworlds/src/game/server/gamemodes/mod.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/mod.cpp 2012-07-08 19:28:03.418259861 +1000 @@ -7,7 +7,7 @@ { // Exchange this to a string that identifies your game mode. // DM, TDM and CTF are reserved for teeworlds original modes. - m_pGameType = "MOD"; + m_pGameType = "BBM"; //m_GameFlags = GAMEFLAG_TEAMS; // GAMEFLAG_TEAMS makes it a two-team gamemode } diff -Naur ../teeworlds/src/game/server/gamemodes/sur.cpp src/game/server/gamemodes/sur.cpp --- ../teeworlds/src/game/server/gamemodes/sur.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/sur.cpp 1970-01-01 10:00:00.000000000 +1000 @@ -1,62 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include - -#include -#include -#include -#include "sur.h" - -CGameControllerSUR::CGameControllerSUR(CGameContext *pGameServer) : IGameController(pGameServer) -{ - m_pGameType = "SUR"; - m_GameFlags = GAMEFLAG_TEAMS|GAMEFLAG_SURVIVAL; -} - -// game -void CGameControllerSUR::DoWincheckRound() -{ - int Count[2] = {0}; - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && - (!GameServer()->m_apPlayers[i]->m_RespawnDisabled || - (GameServer()->m_apPlayers[i]->GetCharacter() && GameServer()->m_apPlayers[i]->GetCharacter()->IsAlive()))) - ++Count[GameServer()->m_apPlayers[i]->GetTeam()]; - } - - if(Count[TEAM_RED]+Count[TEAM_BLUE] == 0 || (g_Config.m_SvTimelimit > 0 && (Server()->Tick()-m_GameStartTick) >= g_Config.m_SvTimelimit*Server()->TickSpeed()*60)) - { - ++m_aTeamscore[TEAM_BLUE]; - ++m_aTeamscore[TEAM_RED]; - EndRound(); - } - else if(Count[TEAM_RED] == 0) - { - ++m_aTeamscore[TEAM_BLUE]; - EndRound(); - } - else if(Count[TEAM_BLUE] == 0) - { - ++m_aTeamscore[TEAM_RED]; - EndRound(); - } -} - -// general -void CGameControllerSUR::Snap(int SnappingClient) -{ - IGameController::Snap(SnappingClient); - - CNetObj_GameData *pGameDataObj = (CNetObj_GameData *)Server()->SnapNewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData)); - if(!pGameDataObj) - return; - - pGameDataObj->m_TeamscoreRed = m_aTeamscore[TEAM_RED]; - pGameDataObj->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE]; - - pGameDataObj->m_FlagCarrierRed = 0; - pGameDataObj->m_FlagCarrierBlue = 0; - pGameDataObj->m_FlagDropTickRed = 0; - pGameDataObj->m_FlagDropTickBlue = 0; -} diff -Naur ../teeworlds/src/game/server/gamemodes/sur.h src/game/server/gamemodes/sur.h --- ../teeworlds/src/game/server/gamemodes/sur.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/sur.h 1970-01-01 10:00:00.000000000 +1000 @@ -1,19 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#ifndef GAME_SERVER_GAMEMODES_SUR_H -#define GAME_SERVER_GAMEMODES_SUR_H -#include - -class CGameControllerSUR : public IGameController -{ -public: - CGameControllerSUR(class CGameContext *pGameServer); - - // game - virtual void DoWincheckRound(); - - // general - virtual void Snap(int SnappingClient); -}; - -#endif diff -Naur ../teeworlds/src/game/server/gamemodes/tdm.cpp src/game/server/gamemodes/tdm.cpp --- ../teeworlds/src/game/server/gamemodes/tdm.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/tdm.cpp 2012-07-08 19:28:03.418259861 +1000 @@ -3,7 +3,6 @@ #include #include -#include #include #include "tdm.h" @@ -13,7 +12,6 @@ m_GameFlags = GAMEFLAG_TEAMS; } -// event int CGameControllerTDM::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon) { IGameController::OnCharacterDeath(pVictim, pKiller, Weapon); @@ -33,7 +31,6 @@ return 0; } -// general void CGameControllerTDM::Snap(int SnappingClient) { IGameController::Snap(SnappingClient); @@ -47,6 +44,9 @@ pGameDataObj->m_FlagCarrierRed = 0; pGameDataObj->m_FlagCarrierBlue = 0; - pGameDataObj->m_FlagDropTickRed = 0; - pGameDataObj->m_FlagDropTickBlue = 0; +} + +void CGameControllerTDM::Tick() +{ + IGameController::Tick(); } diff -Naur ../teeworlds/src/game/server/gamemodes/tdm.h src/game/server/gamemodes/tdm.h --- ../teeworlds/src/game/server/gamemodes/tdm.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/tdm.h 2012-07-08 19:28:03.418259861 +1000 @@ -9,11 +9,8 @@ public: CGameControllerTDM(class CGameContext *pGameServer); - // event - virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); - - // general + int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon); virtual void Snap(int SnappingClient); + virtual void Tick(); }; - #endif diff -Naur ../teeworlds/src/game/server/gameworld.cpp src/game/server/gameworld.cpp --- ../teeworlds/src/game/server/gameworld.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gameworld.cpp 2012-07-08 19:42:32.842259599 +1000 @@ -1,12 +1,12 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include "entities/character.h" +#include "gameworld.h" #include "entity.h" #include "gamecontext.h" -#include "gamecontroller.h" -#include "gameworld.h" - +#include +#include +#include ////////////////////////////////////////////////// // game world @@ -128,7 +128,7 @@ } RemoveEntities(); - GameServer()->m_pController->OnReset(); + GameServer()->m_pController->PostReset(); RemoveEntities(); m_ResetRequested = false; @@ -150,6 +150,75 @@ } } +bool distCompare(std::pair a, std::pair b) +{ + return (a.first < b.first); +} + +void CGameWorld::UpdatePlayerMaps() +{ + if (Server()->Tick() % g_Config.m_SvMapUpdateRate != 0) return; + + std::pair dist[MAX_CLIENTS]; + for (int i = 0; i < MAX_CLIENTS; i++) + { + if (!Server()->ClientIngame(i)) continue; + int* map = Server()->GetIdMap(i); + + // compute distances + for (int j = 0; j < MAX_CLIENTS; j++) + { + dist[j].second = j; + dist[j].first = 1e10; + if (!Server()->ClientIngame(j)) + continue; + CCharacter* ch = GameServer()->m_apPlayers[j]->GetCharacter(); + if (!ch) + continue; + dist[j].first = distance(GameServer()->m_apPlayers[i]->m_ViewPos, GameServer()->m_apPlayers[j]->m_ViewPos); + } + + // always send the player himself + dist[i].first = 0; + + // compute reverse map + int rMap[MAX_CLIENTS]; + for (int j = 0; j < MAX_CLIENTS; j++) + { + rMap[j] = -1; + } + for (int j = 0; j < VANILLA_MAX_CLIENTS; j++) + { + if (map[j] == -1) continue; + if (dist[map[j]].first > 1e9) map[j] = -1; + else rMap[map[j]] = j; + } + + std::nth_element(&dist[0], &dist[VANILLA_MAX_CLIENTS - 1], &dist[MAX_CLIENTS], distCompare); + + int mapc = 0; + int demand = 0; + for (int j = 0; j < VANILLA_MAX_CLIENTS - 1; j++) + { + int k = dist[j].second; + if (rMap[k] != -1 || dist[j].first > 1e9) continue; + while (mapc < VANILLA_MAX_CLIENTS && map[mapc] != -1) mapc++; + if (mapc < VANILLA_MAX_CLIENTS - 1) + map[mapc] = k; + else + if (dist[j].first < 1300) // dont bother freeing up space for players which are too far to be displayed anyway + demand++; + } + for (int j = MAX_CLIENTS - 1; j > VANILLA_MAX_CLIENTS - 2; j--) + { + int k = dist[j].second; + if (rMap[k] != -1 && demand-- > 0) + map[rMap[k]] = -1; + } + map[VANILLA_MAX_CLIENTS - 1] = -1; // player with empty name to say chat msgs + } +} + void CGameWorld::Tick() { if(m_ResetRequested) @@ -157,6 +226,8 @@ if(!m_Paused) { + if(GameServer()->m_pController->IsForceBalanced()) + GameServer()->SendChat(-1, CGameContext::CHAT_ALL, "Teams have been balanced"); // update all objects for(int i = 0; i < NUM_ENTTYPES; i++) for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; ) @@ -174,7 +245,7 @@ pEnt = m_pNextTraverseEntity; } } - else if(GameServer()->m_pController->IsGamePaused()) + else { // update all objects for(int i = 0; i < NUM_ENTTYPES; i++) @@ -187,8 +258,9 @@ } RemoveEntities(); -} + UpdatePlayerMaps(); +} // TODO: should be more general CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2& NewPos, CEntity *pNotThis) diff -Naur ../teeworlds/src/game/server/gameworld.h src/game/server/gameworld.h --- ../teeworlds/src/game/server/gameworld.h 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gameworld.h 2012-07-08 19:28:03.418259861 +1000 @@ -36,6 +36,8 @@ class CGameContext *m_pGameServer; class IServer *m_pServer; + void UpdatePlayerMaps(); + public: class CGameContext *GameServer() { return m_pGameServer; } class IServer *Server() { return m_pServer; } diff -Naur ../teeworlds/src/game/server/player.cpp src/game/server/player.cpp --- ../teeworlds/src/game/server/player.cpp 2012-06-26 16:53:53.400861537 +1000 +++ src/game/server/player.cpp 2012-07-08 19:44:28.473761216 +1000 @@ -1,9 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ - -#include "entities/character.h" -#include "gamecontext.h" -#include "gamecontroller.h" +#include +#include #include "player.h" @@ -11,23 +9,28 @@ IServer *CPlayer::Server() const { return m_pGameServer->Server(); } -CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, bool Dummy) +CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team) { + m_Muted = 0; m_pGameServer = pGameServer; m_RespawnTick = Server()->Tick(); m_DieTick = Server()->Tick(); m_ScoreStartTick = Server()->Tick(); m_pCharacter = 0; m_ClientID = ClientID; - m_Team = GameServer()->m_pController->GetStartTeam(); + m_Team = GameServer()->m_pController->ClampTeam(Team); m_SpectatorID = SPEC_FREEVIEW; m_LastActionTick = Server()->Tick(); + slot3 = 0; + int* idMap = Server()->GetIdMap(ClientID); + for (int i = 1;i < VANILLA_MAX_CLIENTS;i++) + { + idMap[i] = -1; + } + idMap[0] = ClientID; + + m_TeamChangeTick = Server()->Tick(); - m_Dummy = Dummy; - m_IsReadyToPlay = !GameServer()->m_pController->IsPlayerReadyMode(); - m_RespawnDisabled = GameServer()->m_pController->GetStartRespawnState(); - m_DeadSpecMode = false; - m_Spawning = 0; } CPlayer::~CPlayer() @@ -38,11 +41,18 @@ void CPlayer::Tick() { - if(!IsDummy() && !Server()->ClientIngame(m_ClientID)) +#ifdef CONF_DEBUG + if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS-g_Config.m_DbgDummies) +#endif + if(!Server()->ClientIngame(m_ClientID)) return; Server()->SetClientScore(m_ClientID, m_Score); + if(m_Muted != 0) + { + m_Muted--; + } // do latency stuff { IServer::CClientInfo Info; @@ -64,24 +74,25 @@ } } - if(m_pCharacter && !m_pCharacter->IsAlive()) - { - delete m_pCharacter; - m_pCharacter = 0; - } - - if(!GameServer()->m_pController->IsGamePaused()) + if(!GameServer()->m_World.m_Paused) { if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f)); - if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick() && !m_DeadSpecMode) - Respawn(); + if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick()) + m_Spawning = true; if(m_pCharacter) { if(m_pCharacter->IsAlive()) + { m_ViewPos = m_pCharacter->m_Pos; + } + else + { + delete m_pCharacter; + m_pCharacter = 0; + } } else if(m_Spawning && m_RespawnTick <= Server()->Tick()) TryRespawn(); @@ -108,17 +119,24 @@ } } - // update view pos for spectators and dead players - if((m_Team == TEAM_SPECTATORS || m_DeadSpecMode) && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID]) + // update view pos for spectators + if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID]) m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos; } void CPlayer::Snap(int SnappingClient) { - if(!IsDummy() && !Server()->ClientIngame(m_ClientID)) +#ifdef CONF_DEBUG + if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS-g_Config.m_DbgDummies) +#endif + if(!Server()->ClientIngame(m_ClientID)) return; - CNetObj_ClientInfo *pClientInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_CLIENTINFO, m_ClientID, sizeof(CNetObj_ClientInfo))); + int id = m_ClientID; + if (!Server()->Translate(id, SnappingClient)) return; + + CNetObj_ClientInfo *pClientInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_CLIENTINFO, id, sizeof(CNetObj_ClientInfo))); + if(!pClientInfo) return; @@ -130,27 +148,20 @@ pClientInfo->m_ColorBody = m_TeeInfos.m_ColorBody; pClientInfo->m_ColorFeet = m_TeeInfos.m_ColorFeet; - CNetObj_PlayerInfo *pPlayerInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_PLAYERINFO, m_ClientID, sizeof(CNetObj_PlayerInfo))); + CNetObj_PlayerInfo *pPlayerInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_PLAYERINFO, id, sizeof(CNetObj_PlayerInfo))); if(!pPlayerInfo) return; - pPlayerInfo->m_PlayerFlags = m_PlayerFlags&PLAYERFLAG_CHATTING; - if(!GameServer()->m_pController->IsPlayerReadyMode() || m_IsReadyToPlay) - pPlayerInfo->m_PlayerFlags |= PLAYERFLAG_READY; - if(m_RespawnDisabled && (!GetCharacter() || !GetCharacter()->IsAlive())) - pPlayerInfo->m_PlayerFlags |= PLAYERFLAG_DEAD; - if(SnappingClient != -1 && (m_Team == TEAM_SPECTATORS || m_DeadSpecMode) && SnappingClient == m_SpectatorID) - pPlayerInfo->m_PlayerFlags |= PLAYERFLAG_WATCHING; pPlayerInfo->m_Latency = SnappingClient == -1 ? m_Latency.m_Min : GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID]; pPlayerInfo->m_Local = 0; - pPlayerInfo->m_ClientID = m_ClientID; + pPlayerInfo->m_ClientID = id; pPlayerInfo->m_Score = m_Score; pPlayerInfo->m_Team = m_Team; if(m_ClientID == SnappingClient) pPlayerInfo->m_Local = 1; - if(m_ClientID == SnappingClient && (m_Team == TEAM_SPECTATORS || m_DeadSpecMode)) + if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS) { CNetObj_SpectatorInfo *pSpectatorInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo))); if(!pSpectatorInfo) @@ -162,23 +173,40 @@ } } -void CPlayer::OnDisconnect() +void CPlayer::FakeSnap(int SnappingClient) +{ + IServer::CClientInfo info; + Server()->GetClientInfo(SnappingClient, &info); + if (info.m_CustClt) + return; + + int id = VANILLA_MAX_CLIENTS - 1; + + CNetObj_ClientInfo *pClientInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_CLIENTINFO, id, sizeof(CNetObj_ClientInfo))); + + if(!pClientInfo) + return; + + StrToInts(&pClientInfo->m_Name0, 4, " "); + StrToInts(&pClientInfo->m_Clan0, 3, Server()->ClientClan(m_ClientID)); + StrToInts(&pClientInfo->m_Skin0, 6, m_TeeInfos.m_SkinName); +} + +void CPlayer::OnDisconnect(const char *pReason) { KillCharacter(); - if(m_Team != TEAM_SPECTATORS) + if(Server()->ClientIngame(m_ClientID)) { - // update spectator modes - for(int i = 0; i < MAX_CLIENTS; ++i) - { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID) - { - if(GameServer()->m_apPlayers[i]->m_DeadSpecMode) - GameServer()->m_apPlayers[i]->UpdateDeadSpecMode(); - else - GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW; - } - } + char aBuf[512]; + if(pReason && *pReason) + str_format(aBuf, sizeof(aBuf), "'%s' has left the game (%s)", Server()->ClientName(m_ClientID), pReason); + else + str_format(aBuf, sizeof(aBuf), "'%s' has left the game", Server()->ClientName(m_ClientID)); + GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); + + //str_format(aBuf, sizeof(aBuf), "leave player='%d:%s'", m_ClientID, Server()->ClientName(m_ClientID)); + GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "game", aBuf); } } @@ -194,12 +222,6 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput) { - if(GameServer()->m_World.m_Paused) - { - m_PlayerFlags = NewInput->m_PlayerFlags; - return; - } - if(NewInput->m_PlayerFlags&PLAYERFLAG_CHATTING) { // skip the input if chat is active @@ -220,7 +242,7 @@ m_pCharacter->OnDirectInput(NewInput); if(!m_pCharacter && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1)) - Respawn(); + m_Spawning = true; // check for activity if(NewInput->m_Direction || m_LatestActivity.m_TargetX != NewInput->m_TargetX || @@ -252,98 +274,42 @@ void CPlayer::Respawn() { - if(m_RespawnDisabled) - { - // enable spectate mode for dead players - m_DeadSpecMode = true; - m_IsReadyToPlay = true; - UpdateDeadSpecMode(); - return; - } - - m_DeadSpecMode = false; - if(m_Team != TEAM_SPECTATORS) m_Spawning = true; } -bool CPlayer::SetSpectatorID(int SpectatorID) -{ - if(m_SpectatorID == SpectatorID || m_ClientID == SpectatorID) - return false; - - if(m_Team == TEAM_SPECTATORS) - { - // check for freeview or if wanted player is playing - if(SpectatorID == SPEC_FREEVIEW || (GameServer()->m_apPlayers[SpectatorID] && GameServer()->m_apPlayers[SpectatorID]->GetTeam() != TEAM_SPECTATORS)) - { - m_SpectatorID = SpectatorID; - return true; - } - } - else if(m_DeadSpecMode) - { - // check if wanted player can be followed - if(GameServer()->m_apPlayers[SpectatorID] && DeadCanFollow(GameServer()->m_apPlayers[SpectatorID])) - { - m_SpectatorID = SpectatorID; - return true; - } - } - - return false; -} - -bool CPlayer::DeadCanFollow(CPlayer *pPlayer) const -{ - // check if wanted player is in the same team and alive - return (!pPlayer->m_RespawnDisabled || (pPlayer->GetCharacter() && pPlayer->GetCharacter()->IsAlive())) && pPlayer->GetTeam() == m_Team; -} - -void CPlayer::UpdateDeadSpecMode() +void CPlayer::SetTeam(int Team, bool DoChatMsg) { - // check if actual spectator id is valid - if(m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID] && DeadCanFollow(GameServer()->m_apPlayers[m_SpectatorID])) + // clamp the team + Team = GameServer()->m_pController->ClampTeam(Team); + if(m_Team == Team) return; - // find player to follow - for(int i = 0; i < MAX_CLIENTS; ++i) +/* char aBuf[512]; + if(DoChatMsg) { - if(GameServer()->m_apPlayers[i] && DeadCanFollow(GameServer()->m_apPlayers[i])) - { - m_SpectatorID = i; - return; - } - } - - // no one available to follow -> turn spectator mode off - m_DeadSpecMode = false; -} + str_format(aBuf, sizeof(aBuf), "'%s' joined the %s", Server()->ClientName(m_ClientID), GameServer()->m_pController->GetTeamName(Team)); + GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); + }*/ -void CPlayer::SetTeam(int Team, bool DoChatMsg) -{ KillCharacter(); m_Team = Team; m_LastActionTick = Server()->Tick(); - m_SpectatorID = SPEC_FREEVIEW; - m_DeadSpecMode = false; - // we got to wait 0.5 secs before respawning m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2; - + //str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' m_Team=%d", m_ClientID, Server()->ClientName(m_ClientID), m_Team); + //GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); + + GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]); + if(Team == TEAM_SPECTATORS) { // update spectator modes for(int i = 0; i < MAX_CLIENTS; ++i) { if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID) - { - if(GameServer()->m_apPlayers[i]->m_DeadSpecMode) - GameServer()->m_apPlayers[i]->UpdateDeadSpecMode(); - else - GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW; - } + GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW; } } } diff -Naur ../teeworlds/src/game/server/player.h src/game/server/player.h --- ../teeworlds/src/game/server/player.h 2012-06-26 16:53:53.400861537 +1000 +++ src/game/server/player.h 2012-07-08 19:42:32.954259163 +1000 @@ -3,15 +3,9 @@ #ifndef GAME_SERVER_PLAYER_H #define GAME_SERVER_PLAYER_H -#include "alloc.h" - - -enum -{ - WEAPON_GAME = -3, // team switching etc - WEAPON_SELF = -2, // console kill command - WEAPON_WORLD = -1, // death tiles etc -}; +// this include should perhaps be removed +#include "entities/character.h" +#include "gamecontext.h" // player object class CPlayer @@ -19,7 +13,7 @@ MACRO_ALLOC_POOL_ID() public: - CPlayer(CGameContext *pGameServer, int ClientID, bool Dummy); + CPlayer(CGameContext *pGameServer, int ClientID, int Team); ~CPlayer(); void Init(int CID); @@ -29,15 +23,15 @@ void SetTeam(int Team, bool DoChatMsg=true); int GetTeam() const { return m_Team; }; int GetCID() const { return m_ClientID; }; - bool IsDummy() const { return m_Dummy; } void Tick(); void PostTick(); void Snap(int SnappingClient); + void FakeSnap(int SnappingClient); void OnDirectInput(CNetObj_PlayerInput *NewInput); void OnPredictedInput(CNetObj_PlayerInput *NewInput); - void OnDisconnect(); + void OnDisconnect(const char *pReason); void KillCharacter(int Weapon = WEAPON_GAME); CCharacter *GetCharacter(); @@ -53,16 +47,30 @@ int m_aActLatency[MAX_CLIENTS]; // used for spectator mode - int GetSpectatorID() const { return m_SpectatorID; } - bool SetSpectatorID(int SpectatorID); - bool m_DeadSpecMode; - bool DeadCanFollow(CPlayer *pPlayer) const; - void UpdateDeadSpecMode(); + int m_SpectatorID; + + bool m_IsReady; + + int forcecolor; + + int origusecustcolor; + int origbodycolor; + int origfeetcolor; + int m_NoGreen; + int m_NoBlue; + int m_NoRed; + int m_NoWhite; + int m_NoGrey; + int m_NoYellow; + int m_NoPink; - bool m_IsReadyToEnter; - bool m_IsReadyToPlay; - bool m_RespawnDisabled; + int Skills[NUM_PUPS]; + + int *slot3; + + int is1on1; + char *oname; // int m_Vote; @@ -76,8 +84,11 @@ int m_LastChangeInfo; int m_LastEmote; int m_LastKill; - int m_LastReadyChange; - + int m_Muted; + int m_MuteTimes; + char m_LastChatText[256]; + int m_LastChatTime; + // TODO: clean this up struct { @@ -91,6 +102,7 @@ int m_DieTick; int m_Score; int m_ScoreStartTick; + bool m_ForceBalanced; int m_LastActionTick; int m_TeamChangeTick; struct @@ -121,10 +133,6 @@ bool m_Spawning; int m_ClientID; int m_Team; - bool m_Dummy; - - // used for spectator mode - int m_SpectatorID; }; #endif diff -Naur ../teeworlds/src/game/tuning.h src/game/tuning.h --- ../teeworlds/src/game/tuning.h 2012-06-26 16:53:53.400861537 +1000 +++ src/game/tuning.h 2012-07-08 19:28:03.422259113 +1000 @@ -24,8 +24,8 @@ MACRO_TUNING_PARAM(VelrampCurvature, velramp_curvature, 1.4f) // weapon tuning -MACRO_TUNING_PARAM(GunCurvature, gun_curvature, 1.25f) -MACRO_TUNING_PARAM(GunSpeed, gun_speed, 2200.0f) +MACRO_TUNING_PARAM(GunCurvature, gun_curvature, 0.0f) +MACRO_TUNING_PARAM(GunSpeed, gun_speed, 1000.0f) MACRO_TUNING_PARAM(GunLifetime, gun_lifetime, 2.0f) MACRO_TUNING_PARAM(ShotgunCurvature, shotgun_curvature, 1.25f) diff -Naur ../teeworlds/src/game/variables.h src/game/variables.h --- ../teeworlds/src/game/variables.h 2012-06-26 16:53:53.400861537 +1000 +++ src/game/variables.h 2012-07-08 19:42:32.954259163 +1000 @@ -56,25 +56,24 @@ MACRO_CONFIG_INT(GfxNoclip, gfx_noclip, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Disable clipping") // server -MACRO_CONFIG_INT(SvWarmup, sv_warmup, 0, -1, 1000, CFGFLAG_SERVER, "Number of seconds to do warmup before match starts (0 disables, -1 all players ready)") +MACRO_CONFIG_INT(SvWarmup, sv_warmup, 0, 0, 0, CFGFLAG_SERVER, "Number of seconds to do warmup before round starts") MACRO_CONFIG_STR(SvMotd, sv_motd, 900, "", CFGFLAG_SERVER, "Message of the day to display for the clients") MACRO_CONFIG_INT(SvTeamdamage, sv_teamdamage, 0, 0, 1, CFGFLAG_SERVER, "Team damage") MACRO_CONFIG_STR(SvMaprotation, sv_maprotation, 768, "", CFGFLAG_SERVER, "Maps to rotate between") -MACRO_CONFIG_INT(SvMatchesPerMap, sv_matches_per_map, 1, 1, 100, CFGFLAG_SERVER, "Number of matches on each map before rotating") -MACRO_CONFIG_INT(SvMatchSwap, sv_match_swap, 1, 0, 1, CFGFLAG_SERVER, "Swap teams between matches") +MACRO_CONFIG_INT(SvRoundsPerMap, sv_rounds_per_map, 1, 1, 100, CFGFLAG_SERVER, "Number of rounds on each map before rotating") +MACRO_CONFIG_INT(SvRoundSwap, sv_round_swap, 1, 0, 1, CFGFLAG_SERVER, "Swap teams between rounds") MACRO_CONFIG_INT(SvPowerups, sv_powerups, 1, 0, 1, CFGFLAG_SERVER, "Allow powerups like ninja") -MACRO_CONFIG_INT(SvScorelimit, sv_scorelimit, 20, 0, 1000, CFGFLAG_SERVER, "Score limit (0 disables)") -MACRO_CONFIG_INT(SvTimelimit, sv_timelimit, 0, 0, 1000, CFGFLAG_SERVER, "Time limit in minutes (0 disables)") -MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "dm", CFGFLAG_SERVER, "Game type (dm, tdm, ctf, lms, sur)") +MACRO_CONFIG_INT(SvScorelimit, sv_scorelimit, 0, 0, 0, CFGFLAG_SERVER, "Score limit (0 disables)") +MACRO_CONFIG_INT(SvTimelimit, sv_timelimit, 0, 0, 0, CFGFLAG_SERVER, "Time limit in minutes (0 disables)") +MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "mod", CFGFLAG_SERVER, "Game type (dm, tdm, ctf)") MACRO_CONFIG_INT(SvTournamentMode, sv_tournament_mode, 0, 0, 1, CFGFLAG_SERVER, "Tournament mode. When enabled, players joins the server as spectator") -MACRO_CONFIG_INT(SvPlayerReadyMode, sv_player_ready_mode, 0, 0, 1, CFGFLAG_SERVER, "When enabled, players can pause/unpause the game and start the game on warmup via their ready state") MACRO_CONFIG_INT(SvSpamprotection, sv_spamprotection, 1, 0, 1, CFGFLAG_SERVER, "Spam protection") MACRO_CONFIG_INT(SvRespawnDelayTDM, sv_respawn_delay_tdm, 3, 0, 10, CFGFLAG_SERVER, "Time needed to respawn after death in tdm gametype") MACRO_CONFIG_INT(SvSpectatorSlots, sv_spectator_slots, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Number of slots to reserve for spectators") MACRO_CONFIG_INT(SvTeambalanceTime, sv_teambalance_time, 1, 0, 1000, CFGFLAG_SERVER, "How many minutes to wait before autobalancing teams") -MACRO_CONFIG_INT(SvInactiveKickTime, sv_inactivekick_time, 3, 0, 1000, CFGFLAG_SERVER, "How many minutes to wait before taking care of inactive players") +MACRO_CONFIG_INT(SvInactiveKickTime, sv_inactivekick_time, 0, 0, 1000, CFGFLAG_SERVER, "How many minutes to wait before taking care of inactive players") MACRO_CONFIG_INT(SvInactiveKick, sv_inactivekick, 1, 0, 2, CFGFLAG_SERVER, "How to deal with inactive players (0=move to spectator, 1=move to free spectator slot/kick, 2=kick)") MACRO_CONFIG_INT(SvStrictSpectateMode, sv_strict_spectate_mode, 0, 0, 1, CFGFLAG_SERVER, "Restricts information in spectator mode") @@ -84,6 +83,7 @@ MACRO_CONFIG_INT(SvVoteKickMin, sv_vote_kick_min, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Minimum number of players required to start a kick vote") MACRO_CONFIG_INT(SvVoteKickBantime, sv_vote_kick_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time to ban a player if kicked by vote. 0 makes it just use kick") +MACRO_CONFIG_INT(SvMapUpdateRate, sv_mapupdaterate, 5, 1, 100, CFGFLAG_SERVER, "(Tw32) real id <-> vanilla id players map update rate") // debug #ifdef CONF_DEBUG // this one can crash the server if not used correctly MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, 15, CFGFLAG_SERVER, "") diff -Naur ../teeworlds/src/game/version.h src/game/version.h --- ../teeworlds/src/game/version.h 2012-06-26 16:53:53.400861537 +1000 +++ src/game/version.h 2012-07-08 19:42:32.846258990 +1000 @@ -3,7 +3,7 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #include "generated/nethash.cpp" -#define GAME_VERSION "0.7 trunk" -#define GAME_NETVERSION "0.7 " GAME_NETVERSION_HASH +#define GAME_VERSION "0.6 trunk" +#define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH static const char GAME_RELEASE_VERSION[8] = {'0', '.', '6', '1', 0}; #endif diff -Naur ../teeworlds/src/mastersrv/mastersrv.cpp src/mastersrv/mastersrv.cpp --- ../teeworlds/src/mastersrv/mastersrv.cpp 2012-06-26 16:53:53.400861537 +1000 +++ src/mastersrv/mastersrv.cpp 2012-07-08 19:42:32.846258990 +1000 @@ -348,11 +348,7 @@ m_pConsole->ParseArguments(argc-1, &argv[1]); // ignore_convention if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0) - { - // got bindaddr - BindAddr.type = NETTYPE_ALL; BindAddr.port = MASTERSERVER_PORT; - } else { mem_zero(&BindAddr, sizeof(BindAddr)); @@ -372,9 +368,6 @@ return -1; } - // process pending commands - m_pConsole->StoreCommands(false); - dbg_msg("mastersrv", "started"); while(1)