diff -Naur /home/toil/teeworlds/src/engine/client/backend_sdl.cpp src/engine/client/backend_sdl.cpp --- /home/toil/teeworlds/src/engine/client/backend_sdl.cpp 2012-06-26 16:53:53.284860687 +1000 +++ src/engine/client/backend_sdl.cpp 2012-07-07 23:49:37.485176348 +1000 @@ -427,6 +427,13 @@ 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; @@ -443,7 +450,7 @@ } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&CCommandBuffer::INITFLAG_VSYNC ? 1 : 0); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, Flags&IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0); // set caption SDL_WM_SetCaption(pName, pName); diff -Naur /home/toil/teeworlds/src/engine/client/graphics.cpp src/engine/client/graphics.cpp --- /home/toil/teeworlds/src/engine/client/graphics.cpp 2012-06-26 16:53:53.292861564 +1000 +++ src/engine/client/graphics.cpp 2012-07-07 23:49:37.861176855 +1000 @@ -801,7 +801,15 @@ if(pInfo->blit_hw) // ignore_convention Flags |= SDL_HWACCEL; - if(g_Config.m_GfxFullscreen) + 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) Flags |= SDL_FULLSCREEN; // set gl attributes diff -Naur /home/toil/teeworlds/src/engine/client/graphics_threaded.cpp src/engine/client/graphics_threaded.cpp --- /home/toil/teeworlds/src/engine/client/graphics_threaded.cpp 2012-06-26 16:53:53.292861564 +1000 +++ src/engine/client/graphics_threaded.cpp 2012-07-07 23:49:37.489176297 +1000 @@ -712,7 +712,14 @@ int CGraphics_Threaded::IssueInit() { int Flags = 0; - if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN; + 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_GfxVsync) Flags |= IGraphicsBackend::INITFLAG_VSYNC; if(g_Config.m_DbgResizable) Flags |= IGraphicsBackend::INITFLAG_RESIZABLE; diff -Naur /home/toil/teeworlds/src/engine/client/graphics_threaded.h src/engine/client/graphics_threaded.h --- /home/toil/teeworlds/src/engine/client/graphics_threaded.h 2012-06-26 16:53:53.292861564 +1000 +++ src/engine/client/graphics_threaded.h 2012-07-07 23:49:37.489176297 +1000 @@ -98,13 +98,6 @@ enum { - INITFLAG_FULLSCREEN = 1, - INITFLAG_VSYNC = 2, - INITFLAG_RESIZABLE = 4, - }; - - enum - { // PRIMTYPE_INVALID = 0, PRIMTYPE_LINES, @@ -300,6 +293,7 @@ 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; diff -Naur /home/toil/teeworlds/src/engine/client/input.cpp src/engine/client/input.cpp --- /home/toil/teeworlds/src/engine/client/input.cpp 2012-06-26 16:53:53.292861564 +1000 +++ src/engine/client/input.cpp 2012-07-07 23:49:37.865176246 +1000 @@ -35,6 +35,7 @@ m_InputCurrent = 0; m_InputGrabbed = 0; + m_InputDispatched = false; m_LastRelease = 0; m_ReleaseDelta = -1; @@ -116,10 +117,14 @@ /*if(!input_grabbed && Graphics()->WindowActive()) Input()->MouseModeRelative();*/ - // 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])); + 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; + } { int i; diff -Naur /home/toil/teeworlds/src/engine/client/serverbrowser.cpp src/engine/client/serverbrowser.cpp --- /home/toil/teeworlds/src/engine/client/serverbrowser.cpp 2012-06-26 16:53:53.292861564 +1000 +++ src/engine/client/serverbrowser.cpp 2012-07-07 23:49:37.653176620 +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(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_nocase(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(a->m_Info.m_aMap, b->m_Info.m_aMap) < 0; + return str_comp_nocase(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(a->m_Info.m_aGameType, b->m_Info.m_aGameType) < 0; + return str_comp_nocase(a->m_Info.m_aGameType, b->m_Info.m_aGameType) < 0; } bool CServerBrowser::SortCompareNumPlayers(int Index1, int Index2) const diff -Naur /home/toil/teeworlds/src/engine/input.h src/engine/input.h --- /home/toil/teeworlds/src/engine/input.h 2012-06-26 16:53:53.328861462 +1000 +++ src/engine/input.h 2012-07-07 23:49:37.893182739 +1000 @@ -38,6 +38,7 @@ unsigned char m_aInputState[2][1024]; int m_InputCurrent; + bool m_InputDispatched; int KeyWasPressed(int Key) { return m_aInputState[m_InputCurrent^1][Key]; } @@ -51,7 +52,11 @@ // events int NumEvents() const { return m_NumEvents; } - void ClearEvents() { m_NumEvents = 0; } + void ClearEvents() + { + m_NumEvents = 0; + m_InputDispatched = true; + } CEvent GetEvent(int Index) const { if(Index < 0 || Index >= m_NumEvents) diff -Naur /home/toil/teeworlds/src/engine/shared/config_variables.h src/engine/shared/config_variables.h --- /home/toil/teeworlds/src/engine/shared/config_variables.h 2012-06-26 16:53:53.332860923 +1000 +++ src/engine/shared/config_variables.h 2012-07-07 23:49:37.901191509 +1000 @@ -59,6 +59,7 @@ 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(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)") diff -Naur /home/toil/teeworlds/src/engine/shared/memheap.cpp src/engine/shared/memheap.cpp --- /home/toil/teeworlds/src/engine/shared/memheap.cpp 2012-06-26 16:53:53.340861242 +1000 +++ src/engine/shared/memheap.cpp 2012-07-07 23:49:37.909190850 +1000 @@ -3,7 +3,6 @@ #include #include "memheap.h" -static const int CHUNK_SIZE = 1024*64; // allocates a new chunk to be used void CHeap::NewChunk() diff -Naur /home/toil/teeworlds/src/engine/shared/memheap.h src/engine/shared/memheap.h --- /home/toil/teeworlds/src/engine/shared/memheap.h 2012-06-26 16:53:53.340861242 +1000 +++ src/engine/shared/memheap.h 2012-07-07 23:49:37.909190850 +1000 @@ -15,7 +15,7 @@ enum { // how large each chunk should be - CHUNK_SIZE = 1025*64, + CHUNK_SIZE = 1024*64, }; CChunk *m_pCurrent; diff -Naur /home/toil/teeworlds/src/game/client/components/menus.h src/game/client/components/menus.h --- /home/toil/teeworlds/src/game/client/components/menus.h 2012-06-26 16:53:53.360863645 +1000 +++ src/game/client/components/menus.h 2012-07-07 23:49:37.929676066 +1000 @@ -218,11 +218,11 @@ return false; else { - int Result = str_comp(m_pFriendInfo->m_aName, Other.m_pFriendInfo->m_aName); + int Result = str_comp_nocase(m_pFriendInfo->m_aName, Other.m_pFriendInfo->m_aName); if(Result) return Result < 0; else - return str_comp(m_pFriendInfo->m_aClan, Other.m_pFriendInfo->m_aClan) < 0; + return str_comp_nocase(m_pFriendInfo->m_aClan, Other.m_pFriendInfo->m_aClan) < 0; } } }; diff -Naur /home/toil/teeworlds/src/game/client/components/menus_settings.cpp src/game/client/components/menus_settings.cpp --- /home/toil/teeworlds/src/game/client/components/menus_settings.cpp 2012-06-26 16:53:53.364862128 +1000 +++ src/game/client/components/menus_settings.cpp 2012-07-07 23:49:37.937676315 +1000 @@ -615,6 +615,7 @@ 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; @@ -670,9 +671,20 @@ // 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; } @@ -715,6 +727,7 @@ 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 && diff -Naur /home/toil/teeworlds/src/game/client/components/players.cpp src/game/client/components/players.cpp --- /home/toil/teeworlds/src/game/client/components/players.cpp 2012-06-26 16:53:53.368860821 +1000 +++ src/game/client/components/players.cpp 2012-07-07 23:49:37.941683878 +1000 @@ -272,7 +272,7 @@ } bool Stationary = Player.m_VelX <= 1 && Player.m_VelX >= -1; - bool InAir = !Collision()->CheckPoint(Player.m_X, Player.m_Y+16); + bool InAir = !(Collision()->CheckPoint(Player.m_X-14, Player.m_Y+16) || Collision()->CheckPoint(Player.m_X+14, Player.m_Y+16)); bool WantOtherDir = (Player.m_Direction == -1 && Vel.x > 0) || (Player.m_Direction == 1 && Vel.x < 0); // evaluate animation diff -Naur /home/toil/teeworlds/src/game/client/components/skins.h src/game/client/components/skins.h --- /home/toil/teeworlds/src/game/client/components/skins.h 2012-06-26 16:53:53.368860821 +1000 +++ src/game/client/components/skins.h 2012-07-07 23:49:37.945691580 +1000 @@ -17,7 +17,7 @@ char m_aName[24]; vec3 m_BloodColor; - bool operator<(const CSkin &Other) { return str_comp(m_aName, Other.m_aName) < 0; } + bool operator<(const CSkin &Other) { return str_comp_nocase(m_aName, Other.m_aName) < 0; } }; void OnInit(); diff -Naur /home/toil/teeworlds/src/game/collision.cpp src/game/collision.cpp --- /home/toil/teeworlds/src/game/collision.cpp 2012-06-26 16:53:53.376860790 +1000 +++ src/game/collision.cpp 2012-07-08 00:01:43.141676413 +1000 @@ -26,14 +26,14 @@ 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)); - + for(int i = 0; i < m_Width*m_Height; i++) { int Index = m_pTiles[i].m_Index; - + if(Index > 128) continue; - + switch(Index) { case TILE_DEATH: @@ -45,35 +45,64 @@ case TILE_NOHOOK: m_pTiles[i].m_Index = COLFLAG_SOLID|COLFLAG_NOHOOK; break; + case TILE_SLOPE: + { + m_pTiles[i].m_Index = COLFLAG_SLOPE; + m_pTiles[i].m_Flags = OrientationTile(m_pTiles[i].m_Flags, 1); + } + break; + case TILE_SLOPE_NH: + { + m_pTiles[i].m_Index = COLFLAG_SLOPE|COLFLAG_NOHOOK; + m_pTiles[i].m_Flags = OrientationTile(m_pTiles[i].m_Flags, 1); + } + break; default: m_pTiles[i].m_Index = 0; } } } -int CCollision::GetTile(int x, int y) +int CCollision::GetTile(int x, int y, int *pFlags, int *pDx, int *pDy) { - int Nx = clamp(x/32, 0, m_Width-1); - int Ny = clamp(y/32, 0, m_Height-1); + int Address = clamp(y/32, 0, m_Height-1)*m_Width + clamp(x/32, 0, m_Width-1); + int Index = m_pTiles[Address].m_Index; + + if(Index&COLFLAG_SLOPE) + { + int Flags = m_pTiles[Address].m_Flags; + int Dx = x < 0 ? 31-abs(x)%32 : x%32; + int Dy = y < 0 ? 31-abs(y)%32 : y%32; + + if((Flags == 1 && Dy >= Dx) || (Flags == 3 && Dy+Dx <= 31) || (Flags == 5 && Dy <= Dx) || (Flags == 7 && Dy+Dx >= 31)) + Index |= COLFLAG_SOLID; + else if(Index&COLFLAG_NOHOOK) + Index ^= COLFLAG_NOHOOK; + + if(pDx) *pDx = Dx; + if(pDy) *pDy = Dy; + if(pFlags) *pFlags = Flags; +} + +return Index > 128 ? 0 : 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; + return GetTile(x,y)&COLFLAG_SOLID; } // TODO: rewrite this smarter! int CCollision::IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision) { - float Distance = distance(Pos0, Pos1); - int End(Distance+1); + float d = distance(Pos0, Pos1); + int End(d+1); vec2 Last = Pos0; - + for(int i = 0; i < End; i++) { - float a = i/Distance; + float a = i/d; vec2 Pos = mix(Pos0, Pos1, a); if(CheckPoint(Pos.x, Pos.y)) { @@ -97,52 +126,112 @@ { if(pBounces) *pBounces = 0; - + vec2 Pos = *pInoutPos; - vec2 Vel = *pInoutVel; - if(CheckPoint(Pos + Vel)) + vec2 NewPos = Pos + *pInoutVel; + int Flags, Index = GetTile(round(NewPos.x), round(NewPos.y), &Flags); + + if(Index&COLFLAG_SOLID) { int Affected = 0; - if(CheckPoint(Pos.x + Vel.x, Pos.y)) + + if(Index&COLFLAG_SLOPE) + { + if(round(NewPos.x)/32 == round(Pos.x)/32 && round(NewPos.y)/32 == round(Pos.y)/32)//not correct, only approximative + { + vec2 Reflex = vec2(pInoutVel->y, pInoutVel->x); //inverting axisses values + if(Flags == 3 || Flags == 7) + Reflex *= -1; //inverting sings + + *pInoutVel = Elasticity? Reflex*Elasticity : (*pInoutVel+Reflex)*0.5f; + if(pBounces) + (*pBounces)++; + Affected++; + + return; + } + } + + if(CheckPoint(NewPos.x, Pos.y)) { pInoutVel->x *= -Elasticity; if(pBounces) - (*pBounces)++; + (*pBounces)++; Affected++; } - if(CheckPoint(Pos.x, Pos.y + Vel.y)) + if(CheckPoint(Pos.x, NewPos.y)) { pInoutVel->y *= -Elasticity; if(pBounces) - (*pBounces)++; + (*pBounces)++; Affected++; } - + if(Affected == 0) - { - pInoutVel->x *= -Elasticity; - pInoutVel->y *= -Elasticity; - } + *pInoutVel *= -Elasticity; } else { - *pInoutPos = Pos + Vel; + *pInoutPos = NewPos; } } -bool CCollision::TestBox(vec2 Pos, vec2 Size) +int CCollision::TestBox(vec2 Pos, vec2 Size) +{// not formatted, sorry :) +Pos -= Size*0.5f; +int Flags, Dx, Dy, Index = GetTile(round(Pos.x), round(Pos.y), &Flags, &Dx, &Dy); +if(Index&COLFLAG_SOLID) { - Size *= 0.5f; - if(CheckPoint(Pos.x-Size.x, Pos.y-Size.y)) - return true; - if(CheckPoint(Pos.x+Size.x, Pos.y-Size.y)) - return true; - if(CheckPoint(Pos.x-Size.x, Pos.y+Size.y)) - return true; - if(CheckPoint(Pos.x+Size.x, Pos.y+Size.y)) - return true; - return false; +if(Index&COLFLAG_SLOPE && Flags == 3) return 3; +else return 64; +} +else if(Index&COLFLAG_SLOPE) +{ +if(Flags == 1 && Dy+Size.y > Dx) return 64; //16|8 +else if(Flags == 5 && Dy < Dx+Size.x) return 64; //32|2 +} + +Pos.x += Size.x; +Index = GetTile(round(Pos.x), round(Pos.y), &Flags, &Dx, &Dy); +if(Index&COLFLAG_SOLID) +{ +if(Index&COLFLAG_SLOPE && Flags == 5) return 5; +else return 64; +} +else if(Index&COLFLAG_SLOPE) +{ +if(Flags == 3 && Dy+Dx < 31+Size.x) return 64; // 32|1 +else if(Flags == 7 && Dy+Size.y+Dx > 31) return 64; // 16|4 +} + +Pos.y += Size.y; +Index = GetTile(round(Pos.x), round(Pos.y), &Flags, &Dx, &Dy); +if(Index&COLFLAG_SOLID) +{ +if(Index&COLFLAG_SLOPE && Flags == 7) return 7; +else return 64; +} +else if(Index&COLFLAG_SLOPE) +{ +if(Flags == 1 && Dy+Size.x > Dx) return 64; // 32|8 +else if(Flags == 5 && Dy-Size.y < Dx) return 64; // 16|2 +} + +Pos.x -= Size.x; +Index = GetTile(round(Pos.x), round(Pos.y), &Flags, &Dx, &Dy); +if(Index&COLFLAG_SOLID) +{ +if(Index&COLFLAG_SLOPE && Flags == 1) return 1; +else return 64; +} +else if(Index&COLFLAG_SLOPE) +{ +if(Flags == 3 && Dy+Dx-Size.y < 31) return 64; // 16|1 +else if(Flags == 7 && Dy+Dx > 31-Size.x) return 64; // 32|4 +} + +return 0; } void CCollision::MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity) @@ -150,10 +239,10 @@ // do the move vec2 Pos = *pInoutPos; vec2 Vel = *pInoutVel; - + float Distance = length(Vel); int Max = (int)Distance; - + if(Distance > 0.00001f) { //vec2 old_pos = pos; @@ -163,42 +252,107 @@ //float amount = i/(float)max; //if(max == 0) //amount = 0; - + vec2 NewPos = Pos + Vel*Fraction; // TODO: this row is not nice - - if(TestBox(vec2(NewPos.x, NewPos.y), Size)) + + if(TestBox(NewPos, Size)) { int Hits = 0; - if(TestBox(vec2(Pos.x, NewPos.y), Size)) + int Colliding = TestBox(vec2(NewPos.x, Pos.y), Size); + if(Colliding) { - NewPos.y = Pos.y; - Vel.y *= -Elasticity; + if(Colliding == 64) + Vel.x *= -Elasticity; + else if(IntersectSlope(Colliding, &Vel, Elasticity)) + Pos = vec2(round(Pos.x), round(Pos.y)); + Hits++; } - - if(TestBox(vec2(NewPos.x, Pos.y), Size)) + + Colliding = TestBox(vec2(Pos.x, NewPos.y), Size); + if(Colliding) { - NewPos.x = Pos.x; - Vel.x *= -Elasticity; + if(Colliding == 64) + Vel.y *= -Elasticity; + else if(IntersectSlope(Colliding, &Vel, Elasticity)) + Pos = vec2(round(Pos.x), round(Pos.y)); + Hits++; } - + // neither of the tests got a collision. // this is a real _corner case_! if(Hits == 0) - { - NewPos.y = Pos.y; - Vel.y *= -Elasticity; - NewPos.x = Pos.x; - Vel.x *= -Elasticity; - } - } + Vel *= -Elasticity; - Pos = NewPos; + } + else + Pos = NewPos; } } - + *pInoutPos = Pos; *pInoutVel = Vel; } + +int CCollision::OrientationTile(int Flags, int Dir) +{ //Converts tiles flags to get effective direction drawn in the map editor + // Examples Dir(values)[axisses reference]: (0)=to down[x=0:y=1]; (1)=to bottom-right[x=1:y=1]; (2)=to right[x=1:y=0];... + if(Dir == 1) + { + if(Flags&TILEFLAG_ROTATE) + { + if(Flags&TILEFLAG_HFLIP) + Dir = Flags&TILEFLAG_VFLIP? 7 : 5; + else + Dir = Flags&TILEFLAG_VFLIP? 1 : 3; + } + else + { + if(Flags&TILEFLAG_HFLIP) + Dir = Flags&TILEFLAG_VFLIP? 5 : 3; + else + Dir = Flags&TILEFLAG_VFLIP? 7 : 1; + } + } + else if(Dir == 4)//this variant is useless now, but in future coulbe be used + { + if(Flags&TILEFLAG_ROTATE) + Dir = Flags&TILEFLAG_HFLIP? 6 : 2; + else + Dir = Flags&TILEFLAG_HFLIP? 0 : 4; + } + + return Dir; +} + +bool CCollision::IntersectSlope(int Flags, vec2 *pVel, int Elasticity) +{ + vec2 Vel = *pVel; + if((Flags==1 && Vel.y > Vel.x) || (Flags==3 && Vel.y+Vel.x < 0) || (Flags==5 && Vel.y < Vel.x) || (Flags==7 && Vel.y+Vel.x > 0)) + { + vec2 Reaction = vec2(Vel.y, Vel.x); //inverting axisses values + if(Flags == 3 || Flags == 7) + Reaction *= -1; //inverting sings + + *pVel = Elasticity? Reaction*Elasticity : (Vel+Reaction)*0.5f; + return true; + } + else + return false; + +//more general intersection function: maybe useful in future (not formatted) +/* //equation of the line(AB) in implicit form (ax+by+c=0) analytic geometry +float a1= Vel.y-Corner.y, b1= Corner.x-Vel.x, c1= -Corner.x*Vel.y; //1 first line: player movement +float a2= B.y-A.y, b2= A.x-B.x, c2= -A.x*B.y; //2 second line: slope segment + +float d = a1*b2-a2*b1; + +if(d)//lines are not parallel +{ +vec2 HitPoint = vec2((b1*c2-b2*c1)/d, (a2*c1-a1*c2)/d); +} +else +return false*/ +} \ No newline at end of file diff -Naur /home/toil/teeworlds/src/game/collision.h src/game/collision.h --- /home/toil/teeworlds/src/game/collision.h 2012-06-26 16:53:53.376860790 +1000 +++ src/game/collision.h 2012-07-07 23:49:37.953689524 +1000 @@ -13,14 +13,16 @@ class CLayers *m_pLayers; bool IsTileSolid(int x, int y); - int GetTile(int x, int y); - + int GetTile(int x, int y, int *pFlags=0, int *pDx=0, int *pDy=0); + int OrientationTile(int Flags, int Dir); + bool IntersectSlope(int Flags, vec2 *pVel, int Elasticity); public: enum { COLFLAG_SOLID=1, COLFLAG_DEATH=2, COLFLAG_NOHOOK=4, + COLFLAG_SLOPE=8, }; CCollision(); @@ -33,7 +35,7 @@ int IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision); 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); + int TestBox(vec2 Pos, vec2 Size); }; #endif diff -Naur /home/toil/teeworlds/src/game/editor/layer_tiles.cpp src/game/editor/layer_tiles.cpp --- /home/toil/teeworlds/src/game/editor/layer_tiles.cpp 2012-06-26 16:53:53.380861019 +1000 +++ src/game/editor/layer_tiles.cpp 2012-07-07 23:49:37.665176329 +1000 @@ -220,10 +220,13 @@ m_pTiles[y*m_Width+m_Width-1-x] = Tmp; } - if(!m_Game) - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_HFLIP : TILEFLAG_VFLIP; + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + { + int N = y*m_Width+x; + if(!m_Game || m_pTiles[N].m_Index == TILE_SLOPE || m_pTiles[N].m_Index == TILE_SLOPE_NH) + m_pTiles[N].m_Flags ^= m_pTiles[N].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_HFLIP : TILEFLAG_VFLIP; + } } void CLayerTiles::BrushFlipY() @@ -236,21 +239,24 @@ m_pTiles[(m_Height-1-y)*m_Width+x] = Tmp; } - if(!m_Game) - for(int y = 0; y < m_Height; y++) - for(int x = 0; x < m_Width; x++) - m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_VFLIP : TILEFLAG_HFLIP; + for(int y = 0; y < m_Height; y++) + for(int x = 0; x < m_Width; x++) + { + int N = y*m_Width+x; + if(!m_Game || m_pTiles[N].m_Index == TILE_SLOPE || m_pTiles[N].m_Index == TILE_SLOPE_NH) + m_pTiles[N].m_Flags ^= m_pTiles[N].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_VFLIP : TILEFLAG_HFLIP; + } } void CLayerTiles::BrushRotate(float Amount) { - int Rotation = (round(360.0f*Amount/(pi*2))/90)%4; // 0=0�, 1=90�, 2=180�, 3=270� + int Rotation = (round(360.0f*Amount/(pi*2))/90)%4; // 0=0�, 1=90�, 2=180�, 3=270� if(Rotation < 0) Rotation +=4; if(Rotation == 1 || Rotation == 3) { - // 90� rotation + // 90� rotation CTile *pTempData = new CTile[m_Width*m_Height]; mem_copy(pTempData, m_pTiles, m_Width*m_Height*sizeof(CTile)); CTile *pDst = m_pTiles; @@ -258,7 +264,7 @@ for(int y = m_Height-1; y >= 0; --y, ++pDst) { *pDst = pTempData[y*m_Width+x]; - if(!m_Game) + if(!m_Game || pDst->m_Index == TILE_SLOPE || pDst->m_Index == TILE_SLOPE_NH) { if(pDst->m_Flags&TILEFLAG_ROTATE) pDst->m_Flags ^= (TILEFLAG_HFLIP|TILEFLAG_VFLIP); diff -Naur /home/toil/teeworlds/src/game/generated/nethash.c src/game/generated/nethash.c --- /home/toil/teeworlds/src/game/generated/nethash.c 1970-01-01 10:00:00.000000000 +1000 +++ src/game/generated/nethash.c 2012-07-07 23:45:54.225177199 +1000 @@ -0,0 +1 @@ +#define GAME_NETVERSION_HASH "b67d1f1a1eea234e" diff -Naur /home/toil/teeworlds/src/game/mapitems.h src/game/mapitems.h --- /home/toil/teeworlds/src/game/mapitems.h 2012-06-26 16:53:53.384860969 +1000 +++ src/game/mapitems.h 2012-07-07 23:53:46.241689194 +1000 @@ -46,7 +46,8 @@ TILE_SOLID, TILE_DEATH, TILE_NOHOOK, - + TILE_SLOPE=17, + TILE_SLOPE_NH, TILEFLAG_VFLIP=1, TILEFLAG_HFLIP=2, TILEFLAG_OPAQUE=4, diff -Naur /home/toil/teeworlds/src/game/server/gamecontext.cpp src/game/server/gamecontext.cpp --- /home/toil/teeworlds/src/game/server/gamecontext.cpp 2012-06-26 16:53:53.392865827 +1000 +++ src/game/server/gamecontext.cpp 2012-07-07 23:49:37.965178275 +1000 @@ -1120,39 +1120,29 @@ if(!pSelf->m_pController->IsTeamplay()) return; - int CounterRed = 0; - int CounterBlue = 0; + int rnd = 0; int PlayerTeam = 0; - for(int i = 0; i < MAX_CLIENTS; ++i) + int aPlayer[MAX_CLIENTS]; + + for(int i = 0; i < MAX_CLIENTS; i++) if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) - ++PlayerTeam; - PlayerTeam = (PlayerTeam+1)/2; - + aPlayer[PlayerTeam++]=i; + pSelf->SendChat(-1, CGameContext::CHAT_ALL, "Teams were shuffled"); - for(int i = 0; i < MAX_CLIENTS; ++i) + //creating random permutation + for(int i = PlayerTeam; i > 1; i--) { - if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) - { - if(CounterRed == PlayerTeam) - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[i], TEAM_BLUE, false); - else if(CounterBlue == PlayerTeam) - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[i], TEAM_RED, false); - else - { - if(rand() % 2) - { - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[i], TEAM_BLUE, false); - ++CounterBlue; - } - else - { - pSelf->m_pController->DoTeamChange(pSelf->m_apPlayers[i], TEAM_RED, false); - ++CounterRed; - } - } - } + rnd = rand() % i; + int tmp = aPlayer[rnd]; + aPlayer[rnd] = aPlayer[i-1]; + aPlayer[i-1] = tmp; } + //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 CGameContext::ConLockTeams(IConsole::IResult *pResult, void *pUserData) @@ -1458,15 +1448,15 @@ m_Collision.Init(&m_Layers); // select gametype - if(str_comp(g_Config.m_SvGametype, "mod") == 0) + if(str_comp_nocase(g_Config.m_SvGametype, "mod") == 0) m_pController = new CGameControllerMOD(this); - else if(str_comp(g_Config.m_SvGametype, "ctf") == 0) + else if(str_comp_nocase(g_Config.m_SvGametype, "ctf") == 0) m_pController = new CGameControllerCTF(this); - else if(str_comp(g_Config.m_SvGametype, "lms") == 0) + else if(str_comp_nocase(g_Config.m_SvGametype, "lms") == 0) m_pController = new CGameControllerLMS(this); - else if(str_comp(g_Config.m_SvGametype, "sur") == 0) + else if(str_comp_nocase(g_Config.m_SvGametype, "sur") == 0) m_pController = new CGameControllerSUR(this); - else if(str_comp(g_Config.m_SvGametype, "tdm") == 0) + else if(str_comp_nocase(g_Config.m_SvGametype, "tdm") == 0) m_pController = new CGameControllerTDM(this); else m_pController = new CGameControllerDM(this); diff -Naur /home/toil/teeworlds/src/game/server/gamemodes/ctf.cpp src/game/server/gamemodes/ctf.cpp --- /home/toil/teeworlds/src/game/server/gamemodes/ctf.cpp 2012-06-26 16:53:53.396862075 +1000 +++ src/game/server/gamemodes/ctf.cpp 2012-07-07 23:49:37.969176549 +1000 @@ -287,6 +287,9 @@ { F->m_Vel.y += GameServer()->m_World.m_Core.m_Tuning.m_Gravity; GameServer()->Collision()->MoveBox(&F->m_Pos, &F->m_Vel, vec2(F->ms_PhysSize, F->ms_PhysSize), 0.5f); + + if(GameServer()->Collision()->CheckPoint(F->m_Pos.x, F->m_Pos.y+F->ms_PhysSize/2+5)) + F->m_Vel.x *= GameServer()->m_World.m_Core.m_Tuning.m_GroundFriction; } } }