Merge branch 'master' of http://github.com/oy/teeworlds into master

Conflicts:
	src/engine/client/input.h
	src/engine/server/server.cpp
	src/engine/shared/config_variables.h
	src/engine/shared/network_server.cpp
	src/engine/storage.h
	src/game/client/components/chat.cpp
	src/game/client/gameclient.cpp
	src/game/client/gameclient.h
	src/game/collision.cpp
	src/game/editor/ed_editor.cpp
	src/game/editor/ed_editor.h
	src/game/server/gamecontext.cpp
	src/game/server/gamecontroller.cpp
	src/game/server/gamemodes/ctf.cpp
	src/game/server/player.cpp

Signed-off-by: GreYFoXGTi <GreYFoXGTi@GMaiL.CoM>
This commit is contained in:
GreYFoXGTi 2010-09-07 07:57:38 +02:00
commit 616498e7b1
18 changed files with 330 additions and 73 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 B

After

Width:  |  Height:  |  Size: 616 B

View file

@ -385,7 +385,7 @@ container.sprites.Add(Sprite("speedup_arrow", set_speedup_arrow, 0,0,1,1))
container.sprites.Add(Sprite("demobutton_play", set_demobuttons, 0,0,1,1))
container.sprites.Add(Sprite("demobutton_pause", set_demobuttons, 1,0,1,1))
container.sprites.Add(Sprite("demobutton_reset", set_demobuttons, 2,0,1,1))
container.sprites.Add(Sprite("demobutton_stop", set_demobuttons, 2,0,1,1))
container.sprites.Add(Sprite("demobutton_slower", set_demobuttons, 3,0,1,1))
container.sprites.Add(Sprite("demobutton_faster", set_demobuttons, 4,0,1,1))

View file

@ -291,7 +291,7 @@ unsigned io_read(IOHANDLE io, void *buffer, unsigned size)
return fread(buffer, 1, size, (FILE*)io);
}
unsigned io_skip(IOHANDLE io, unsigned size)
unsigned io_skip(IOHANDLE io, int size)
{
fseek((FILE*)io, size, SEEK_CUR);
return size;

View file

@ -242,7 +242,7 @@ unsigned io_read(IOHANDLE io, void *buffer, unsigned size);
Returns:
Number of bytes skipped.
*/
unsigned io_skip(IOHANDLE io, unsigned size);
unsigned io_skip(IOHANDLE io, int size);
/*
Function: io_write

View file

@ -387,13 +387,21 @@ int CGraphics_OpenGL::LoadPNG(CImageInfo *pImg, const char *pFilename)
IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, aCompleteFilename, sizeof(aCompleteFilename));
if(File)
io_close(File);
if(png_open_file(&Png, aCompleteFilename) != PNG_NO_ERROR) // ignore_convention
else
{
dbg_msg("game/png", "failed to open file. filename='%s'", aCompleteFilename);
return 0;
}
int Error = png_open_file(&Png, aCompleteFilename); // ignore_convention
if(Error != PNG_NO_ERROR)
{
dbg_msg("game/png", "failed to open file. filename='%s'", aCompleteFilename);
if(Error != PNG_FILE_ERROR)
png_close_file(&Png); // ignore_convention
return 0;
}
if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA)) // ignore_convention
{
dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename);

View file

@ -87,7 +87,13 @@ void CInput::MouseModeRelative()
int CInput::MouseDoubleClick()
{
return m_ReleaseDelta < (time_freq() >> 2);
if(m_ReleaseDelta >= 0 && m_ReleaseDelta < (time_freq() >> 2))
{
m_LastRelease = 0;
m_ReleaseDelta = -1;
return 1;
}
return 0;
}
void CInput::ClearKeyStates()

View file

@ -185,6 +185,7 @@ public:
void PumpNetwork();
char *GetMapName();
int LoadMap(const char *pMapName);
void InitEngine(const char *pAppname);

View file

@ -511,7 +511,7 @@ int CDataFileWriter::Finish()
// calculate the complete size
TypesSize = m_NumItemTypes*sizeof(CDatafileItemType);
HeaderSize = sizeof(CDatafileHeader);
OffsetSize = m_NumItems*sizeof(int) + m_NumDatas*sizeof(int);
OffsetSize = (m_NumItems + m_NumDatas + m_NumDatas) * sizeof(int); //ItemOffsets, DataOffsets, DataSizes
FileSize = HeaderSize + TypesSize + OffsetSize + ItemSize + DataSize;
SwapSize = FileSize - DataSize;

View file

@ -9,7 +9,10 @@
#include "network.h"
#include "engine.h"
static const unsigned char gs_aHeaderMarker[8] = {'T', 'W', 'D', 'E', 'M', 'O', 0, 1};
static const unsigned char gs_aHeaderMarker[8] = {'T', 'W', 'D', 'E', 'M', 'O', '1', 0};
static const unsigned char gs_aHeaderMarkerOld[8] = {'T', 'W', 'D', 'E', 'M', 'O', 0, 1}; // TODO: remove this later on
static const unsigned char gs_aMapMarker[8] = {'M', 'A', 'P', 'D', 'A', 'T', 'A', 0,};
CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta)
{
@ -50,6 +53,45 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
Header.m_aCrc[3] = (Crc)&0xff;
io_write(m_File, &Header, sizeof(Header));
// write map
char aMapFilename[128];
// try the normal maps folder
str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", pMap);
IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ);
if(!MapFile)
{
// try the downloaded maps
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", pMap, Crc);
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ);
}
if(MapFile)
{
// write map marker
io_write(m_File, &gs_aMapMarker, sizeof(gs_aMapMarker));
// write map size
int MapSize = io_length(MapFile);
unsigned char aBufMapSize[4];
aBufMapSize[0] = (MapSize>>24)&0xff;
aBufMapSize[1] = (MapSize>>16)&0xff;
aBufMapSize[2] = (MapSize>>8)&0xff;
aBufMapSize[3] = (MapSize)&0xff;
io_write(m_File, &aBufMapSize, sizeof(aBufMapSize));
// write map data
while(1)
{
unsigned char aChunk[1024*64];
int Bytes = io_read(MapFile, &aChunk, sizeof(aChunk));
if(Bytes <= 0)
break;
io_write(m_File, &aChunk, Bytes);
}
io_close(MapFile);
}
m_LastKeyFrame = -1;
m_LastTickMarker = -1;
@ -488,7 +530,8 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const
// read the header
io_read(m_File, &m_Info.m_Header, sizeof(m_Info.m_Header));
if(mem_comp(m_Info.m_Header.m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) != 0)
if(mem_comp(m_Info.m_Header.m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) != 0 &&
mem_comp(m_Info.m_Header.m_aMarker, gs_aHeaderMarkerOld, sizeof(gs_aHeaderMarkerOld)) != 0)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "'%s' is not a demo file", pFilename);
@ -498,6 +541,51 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const
return -1;
}
// check if the demo includes a map
unsigned char aMapMarker[8];
io_read(m_File, &aMapMarker, sizeof(aMapMarker));
if(mem_comp(aMapMarker, gs_aMapMarker, sizeof(gs_aMapMarker)) == 0)
{
// get map size
unsigned char aBufMapSize[4];
io_read(m_File, &aBufMapSize, sizeof(aBufMapSize));
int MapSize = (aBufMapSize[0]<<24) | (aBufMapSize[1]<<16) | (aBufMapSize[2]<<8) | (aBufMapSize[3]);
// check if we already have the map
// TODO: improve map checking
int Crc = (m_Info.m_Header.m_aCrc[0]<<24) | (m_Info.m_Header.m_aCrc[1]<<16) | (m_Info.m_Header.m_aCrc[2]<<8) | (m_Info.m_Header.m_aCrc[3]);
char aMapFilename[128];
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", m_Info.m_Header.m_aMap, Crc);
IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ);
if(MapFile)
{
io_skip(m_File, MapSize);
io_close(MapFile);
}
else if(MapSize > 0)
{
// get map data
unsigned char *pMapData = (unsigned char *)mem_alloc(MapSize, 1);
io_read(m_File, pMapData, MapSize);
// save map
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_WRITE);
io_write(MapFile, pMapData, MapSize);
io_close(MapFile);
// free data
mem_free(pMapData);
}
}
else // no map in the demo
{
io_skip(m_File, -sizeof(aMapMarker));
}
// scan the file for interessting points
ScanFile();

View file

@ -1,4 +1,5 @@
// copyright (c) 2007 magnus auvinen, see licence.txt for more info
#include <stdio.h> //remove()
#include <base/system.h>
#include <engine/storage.h>
#include "engine.h"
@ -194,6 +195,18 @@ public:
return 0;
}
virtual bool RemoveFile(const char *pFilename)
{
char aBuffer[1024];
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aApplicationSavePath, pFilename);
bool Fail = remove(aBuffer);
if(Fail)
Fail = remove(pFilename);
return !Fail;
}
virtual const char* SavePath(const char *pFilename, char *pBuffer, int Max)
{
str_format(pBuffer, Max, "%s/%s", m_aApplicationSavePath, pFilename);

View file

@ -1,7 +1,8 @@
#include <stdio.h>
#include <engine/graphics.h>
#include <engine/keys.h> //temp
#include <engine/keys.h>
#include <engine/serverbrowser.h>
#include <engine/shared/config.h>
#include <engine/storage.h>
#include <game/layers.h>
#include <game/client/gameclient.h>
@ -126,20 +127,30 @@ void CMapLayers::OnRender()
Render = true;
}
if(pLayer->m_Type == LAYERTYPE_TILES && Input()->KeyPressed(KEY_KP0))
if(Render && pLayer->m_Type == LAYERTYPE_TILES && Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_KP0))
{
CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer;
CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data);
char buf[256];
str_format(buf, sizeof(buf), "%d%d_%dx%d", g, l, pTMap->m_Width, pTMap->m_Height);
FILE *f = fopen(buf, "w");
CServerInfo CurrentServerInfo;
Client()->GetServerInfo(&CurrentServerInfo);
char aFilename[256];
str_format(aFilename, sizeof(aFilename), "dumps/tilelayer_dump_%s-%d-%d-%dx%d.txt", CurrentServerInfo.m_aMap, g, l, pTMap->m_Width, pTMap->m_Height);
IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE);
if(File)
{
#if defined(CONF_FAMILY_WINDOWS)
static const char Newline[] = "\r\n";
#else
static const char Newline[] = "\n";
#endif
for(int y = 0; y < pTMap->m_Height; y++)
{
for(int x = 0; x < pTMap->m_Width; x++)
fprintf(f, "%d,", pTiles[y*pTMap->m_Width + x].m_Index);
fprintf(f, "\n");
io_write(File, &(pTiles[y*pTMap->m_Width + x].m_Index), sizeof(pTiles[y*pTMap->m_Width + x].m_Index));
io_write(File, Newline, sizeof(Newline)-1);
}
io_close(File);
}
fclose(f);
}
if(Render && !IsGameLayer && !g_Config.m_GfxClearFull || (g_Config.m_GfxClearFull && IsGameLayer))

View file

@ -90,9 +90,11 @@ CMenus::CMenus()
m_NeedSendinfo = false;
m_MenuActive = true;
m_UseMouseButtons = true;
m_DemolistDelEntry = false;
m_EscapePressed = false;
m_EnterPressed = false;
m_DeletePressed = false;
m_NumInputEvents = 0;
m_LastInput = time_get();
@ -993,6 +995,12 @@ int CMenus::Render()
pButtonText = Localize("Ok");
ExtraAlign = -1;
}
else if(m_Popup == POPUP_DELETE_DEMO)
{
pTitle = Localize("Delete demo");
pExtraText = Localize("Are you sure that you want to delete the demo?");
ExtraAlign = -1;
}
else if(m_Popup == POPUP_PASSWORD)
{
pTitle = Localize("Password incorrect");
@ -1086,6 +1094,29 @@ int CMenus::Render()
static float Offset = 0.0f;
DoEditBox(&g_Config.m_Password, &TextBox, g_Config.m_Password, sizeof(g_Config.m_Password), 12.0f, &Offset, true);
}
else if(m_Popup == POPUP_DELETE_DEMO)
{
CUIRect Yes, No;
Box.HSplitBottom(20.f, &Box, &Part);
Box.HSplitBottom(24.f, &Box, &Part);
Part.VMargin(80.0f, &Part);
Part.VSplitMid(&No, &Yes);
Yes.VMargin(20.0f, &Yes);
No.VMargin(20.0f, &No);
static int s_ButtonAbort = 0;
if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed)
m_Popup = POPUP_NONE;
static int s_ButtonTryAgain = 0;
if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed)
{
m_Popup = POPUP_NONE;
m_DemolistDelEntry = true;
}
}
else if(m_Popup == POPUP_FIRST_LAUNCH)
{
CUIRect Label, TextBox;
@ -1177,10 +1208,15 @@ bool CMenus::OnInput(IInput::CEvent e)
}
if(IsActive())
{
if(e.m_Flags&IInput::FLAG_PRESS)
{
// special for popups
if(e.m_Flags&IInput::FLAG_PRESS && e.m_Key == KEY_RETURN)
if(e.m_Key == KEY_RETURN)
m_EnterPressed = true;
else if(e.m_Key == KEY_DELETE)
m_DeletePressed = true;
}
if(m_NumInputEvents < MAX_INPUTEVENTS)
m_aInputEvents[m_NumInputEvents++] = e;
@ -1265,6 +1301,7 @@ void CMenus::OnRender()
{
m_EscapePressed = false;
m_EnterPressed = false;
m_DeletePressed = false;
m_NumInputEvents = 0;
return;
}
@ -1332,6 +1369,7 @@ void CMenus::OnRender()
m_EscapePressed = false;
m_EnterPressed = false;
m_DeletePressed = false;
m_NumInputEvents = 0;
}

View file

@ -95,6 +95,7 @@ class CMenus : public CComponent
POPUP_MESSAGE,
POPUP_DISCONNECTED,
POPUP_PURE,
POPUP_DELETE_DEMO,
POPUP_PASSWORD,
POPUP_QUIT,
};
@ -147,6 +148,7 @@ class CMenus : public CComponent
//
bool m_EscapePressed;
bool m_EnterPressed;
bool m_DeletePressed;
// for call vote
int m_CallvoteSelectedOption;
@ -162,6 +164,7 @@ class CMenus : public CComponent
};
char m_aCurrentDemoFolder[256];
bool m_DemolistDelEntry;
static void DemolistCountCallback(const char *pName, int IsDir, void *pUser);
static void DemolistFetchCallback(const char *pName, int IsDir, void *pUser);

View file

@ -4,6 +4,7 @@
#include <engine/demo.h>
#include <engine/keys.h>
#include <engine/graphics.h>
#include <engine/storage.h>
#include <game/client/render.h>
#include <game/client/gameclient.h>
@ -59,6 +60,9 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
CUIRect SeekBar, ButtonBar;
int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick;
int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick;
if(m_MenuActive)
{
MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar);
@ -75,9 +79,6 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f);
int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick;
int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick;
float Amount = CurrentTick/(float)TotalTicks;
CUIRect FilledBar = SeekBar;
@ -121,6 +122,11 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
UI()->SetHotItem(id);
}
if(CurrentTick == TotalTicks)
{
DemoPlayer()->Pause();
DemoPlayer()->SetPos(0);
}
if(m_MenuActive)
{
@ -141,11 +147,14 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
DemoPlayer()->Unpause();
}
// stop button
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
static int s_ResetButton = 0;
if(DoButton_DemoPlayer_Sprite(&s_ResetButton, SPRITE_DEMOBUTTON_RESET, false, &Button))
if(DoButton_DemoPlayer_Sprite(&s_ResetButton, SPRITE_DEMOBUTTON_STOP, false, &Button))
{
DemoPlayer()->Pause();
DemoPlayer()->SetPos(0);
}
@ -334,6 +343,7 @@ CMenus::CListboxItem CMenus::UiDoListboxNextItem(void *pId, bool Selected)
if(m_EnterPressed || (Input()->MouseDoubleClick() && UI()->ActiveItem() == pId))
{
gs_ListBoxItemActivated = true;
UI()->SetActiveItem(0);
}
else
{
@ -390,7 +400,6 @@ struct FETCH_CALLBACKINFO
{
CMenus *m_pSelf;
const char *m_pPrefix;
int m_Count;
};
void CMenus::DemolistFetchCallback(const char *pName, int IsDir, void *pUser)
@ -411,7 +420,7 @@ void CMenus::DemolistPopulate()
m_lDemos.clear();
if(str_comp_num(m_aCurrentDemoFolder, "demos", 256)) //add parent folder
if(str_comp(m_aCurrentDemoFolder, "demos") != 0) //add parent folder
{
CDemoItem Item;
str_copy(Item.m_aName, "..", sizeof(Item.m_aName));
@ -423,7 +432,7 @@ void CMenus::DemolistPopulate()
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "%s/%s", Client()->UserDirectory(), m_aCurrentDemoFolder);
FETCH_CALLBACKINFO Info = {this, aBuf, m_aCurrentDemoFolder[6]}; //skip "demos/"
FETCH_CALLBACKINFO Info = {this, aBuf};
fs_listdir(aBuf, DemolistFetchCallback, &Info);
Info.m_pPrefix = m_aCurrentDemoFolder;
fs_listdir(m_aCurrentDemoFolder, DemolistFetchCallback, &Info);
@ -432,10 +441,34 @@ void CMenus::DemolistPopulate()
void CMenus::RenderDemoList(CUIRect MainView)
{
static int s_SelectedItem = -1;
static int s_Inited = 0;
if(!s_Inited)
{
DemolistPopulate();
s_Inited = 1;
if(m_lDemos.size() > 0)
s_SelectedItem = 0;
}
bool IsDir = false;
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size())
{
if(str_comp(m_lDemos[s_SelectedItem].m_aName, "..") == 0 || fs_is_dir(m_lDemos[s_SelectedItem].m_aFilename))
IsDir = true;
}
// delete demo
if(m_DemolistDelEntry)
{
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size() && !IsDir)
{
Storage()->RemoveFile(m_lDemos[s_SelectedItem].m_aFilename);
DemolistPopulate();
s_SelectedItem = s_SelectedItem-1 < 0 ? m_lDemos.size() > 0 ? 0 : -1 : s_SelectedItem-1;
}
m_DemolistDelEntry = false;
}
// render background
RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f);
@ -445,7 +478,6 @@ void CMenus::RenderDemoList(CUIRect MainView)
MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar);
ButtonBar.HSplitTop(5.0f, 0, &ButtonBar);
static int s_SelectedItem = -1;
static int s_DemoListId = 0;
static float s_ScrollValue = 0;
@ -460,18 +492,11 @@ void CMenus::RenderDemoList(CUIRect MainView)
bool Activated = false;
s_SelectedItem = UiDoListboxEnd(&s_ScrollValue, &Activated);
CUIRect RefreshRect, PlayRect;
ButtonBar.VSplitRight(250.0f, &ButtonBar, &RefreshRect);
RefreshRect.VSplitRight(130.0f, &RefreshRect, &PlayRect);
PlayRect.VSplitRight(120.0f, 0x0, &PlayRect);
bool IsDir = false;
if(!str_comp_num(m_lDemos[s_SelectedItem].m_aName, "..", 256)) //parent folder
IsDir = true;
else if(fs_is_dir(m_lDemos[s_SelectedItem].m_aFilename))
IsDir = true;
CUIRect RefreshRect, PlayRect, DeleteRect;
ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect);
ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, &DeleteRect, &ButtonBar);
ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar);
static int s_RefreshButton = 0;
if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect))
@ -490,19 +515,21 @@ void CMenus::RenderDemoList(CUIRect MainView)
{
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size())
{
if(!str_comp_num(m_lDemos[s_SelectedItem].m_aName, "..", 256))
if(str_comp(m_lDemos[s_SelectedItem].m_aName, "..") == 0) //parent folder
{
DemoSetParentDirectory();
DemolistPopulate();
s_SelectedItem = 0;
s_SelectedItem = m_lDemos.size() > 0 ? 0 : -1;
}
else if(IsDir)
else if(IsDir) //folder
{
str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", m_aCurrentDemoFolder, m_lDemos[s_SelectedItem].m_aName);
char aTemp[256];
str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp));
str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[s_SelectedItem].m_aName);
DemolistPopulate();
s_SelectedItem = 0;
s_SelectedItem = m_lDemos.size() > 0 ? 0 : -1;
}
else
else //file
{
const char *pError = Client()->DemoPlayer_Play(m_lDemos[s_SelectedItem].m_aFilename);
if(pError)
@ -511,24 +538,30 @@ void CMenus::RenderDemoList(CUIRect MainView)
}
}
if(!IsDir)
{
static int s_DeleteButton = 0;
if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed)
{
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size())
m_Popup = POPUP_DELETE_DEMO;
}
}
}
void CMenus::DemoSetParentDirectory()
{
int Stop = 0;
int i;
for(i = 0; i < 256; i++)
for(int i = 0; i < 256; i++)
{
if(m_aCurrentDemoFolder[i] == '/')
Stop = i;
}
//keeps chars which are before the last '/' and remove chars which are after
for(i = 0; i < 256; i++)
for(int i = 0; i < 256; i++)
{
if(i >= Stop)
m_aCurrentDemoFolder[i] = 0;
m_aCurrentDemoFolder[i] = '\0';
}
}

View file

@ -250,26 +250,46 @@ void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4
int Px1 = Px0+(1024/16)-1;
int Py1 = Py0+(1024/16)-1;
float u0 = Nudge + Px0/TexSize+Frac;
float v0 = Nudge + Py0/TexSize+Frac;
float u1 = Nudge + Px1/TexSize-Frac;
float v1 = Nudge + Py1/TexSize-Frac;
float x0 = Nudge + Px0/TexSize+Frac;
float y0 = Nudge + Py0/TexSize+Frac;
float x1 = Nudge + Px1/TexSize-Frac;
float y1 = Nudge + Py0/TexSize+Frac;
float x2 = Nudge + Px1/TexSize-Frac;
float y2 = Nudge + Py1/TexSize-Frac;
float x3 = Nudge + Px0/TexSize+Frac;
float y3 = Nudge + Py1/TexSize-Frac;
if(Flags&TILEFLAG_VFLIP)
{
float Tmp = u0;
u0 = u1;
u1 = Tmp;
x0 = x2;
x1 = x3;
x2 = x3;
x3 = x0;
}
if(Flags&TILEFLAG_HFLIP)
{
float Tmp = v0;
v0 = v1;
v1 = Tmp;
y0 = y3;
y2 = y1;
y3 = y1;
y1 = y0;
}
Graphics()->QuadsSetSubset(u0,v0,u1,v1);
if(Flags&TILEFLAG_ROTATE)
{
float Tmp = x0;
x0 = x3;
x3 = x2;
x2 = x1;
x1 = Tmp;
Tmp = y0;
y0 = y3;
y3 = y2;
y2 = y1;
y1 = Tmp;
}
Graphics()->QuadsSetSubsetFree(x0, y0, x1, y1, x2, y2, x3, y3);
IGraphics::CQuadItem QuadItem(x*Scale, y*Scale, Scale, Scale);
Graphics()->QuadsDrawTL(&QuadItem, 1);
}

View file

@ -377,6 +377,7 @@ public:
virtual void BrushDraw(CLayer *pBrush, float wx, float wy);
virtual void BrushFlipX();
virtual void BrushFlipY();
virtual void BrushRotate(float Amount);
virtual int RenderProperties(CUIRect *pToolbox);

View file

@ -38,7 +38,7 @@ void CLayerTiles::PrepareForSave()
{
for(int y = 0; y < m_Height; y++)
for(int x = 0; x < m_Width; x++)
m_pTiles[y*m_Width+x].m_Flags &= TILEFLAG_VFLIP|TILEFLAG_HFLIP;
m_pTiles[y*m_Width+x].m_Flags &= TILEFLAG_VFLIP|TILEFLAG_HFLIP|TILEFLAG_ROTATE;
if(m_Image != -1)
{
@ -296,7 +296,7 @@ void CLayerTiles::BrushFlipX()
for(int y = 0; y < m_Height; y++)
for(int x = 0; x < m_Width; x++)
m_pTiles[y*m_Width+x].m_Flags ^= TILEFLAG_VFLIP;
m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].m_Flags&TILEFLAG_ROTATE ? TILEFLAG_HFLIP : TILEFLAG_VFLIP;
}
void CLayerTiles::BrushFlipY()
@ -311,7 +311,41 @@ void CLayerTiles::BrushFlipY()
for(int y = 0; y < m_Height; y++)
for(int x = 0; x < m_Width; x++)
m_pTiles[y*m_Width+x].m_Flags ^= TILEFLAG_HFLIP;
m_pTiles[y*m_Width+x].m_Flags ^= m_pTiles[y*m_Width+x].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°
if(Rotation < 0)
Rotation +=4;
if(Rotation == 1 || Rotation == 3)
{
// 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;
for(int x = 0; x < m_Width; ++x)
for(int y = m_Height-1; y >= 0; --y, ++pDst)
{
*pDst = pTempData[y*m_Width+x];
if(pDst->m_Flags&TILEFLAG_ROTATE)
pDst->m_Flags ^= (TILEFLAG_HFLIP|TILEFLAG_VFLIP);
pDst->m_Flags ^= TILEFLAG_ROTATE;
}
int Temp = m_Width;
m_Width = m_Height;
m_Height = Temp;
delete[] pTempData;
}
if(Rotation == 2 || Rotation == 3)
{
BrushFlipX();
BrushFlipY();
}
}
void CLayerTiles::Resize(int NewW, int NewH)

View file

@ -137,6 +137,7 @@ enum
TILEFLAG_VFLIP=1,
TILEFLAG_HFLIP=2,
TILEFLAG_OPAQUE=4,
TILEFLAG_ROTATE=8,
LAYERFLAG_DETAIL=1,