extract code from editor mapitems into separate files

This commit is contained in:
marmare314 2023-08-27 11:18:10 +02:00
parent d11bbbc921
commit e19b1e4da6
15 changed files with 1429 additions and 1427 deletions

View file

@ -2303,7 +2303,7 @@ if(CLIENT)
ui_scrollregion.cpp
ui_scrollregion.h
)
set_src(GAME_EDITOR GLOB src/game/editor
set_src(GAME_EDITOR GLOB_RECURSE src/game/editor
auto_map.cpp
auto_map.h
component.cpp
@ -2312,14 +2312,23 @@ if(CLIENT)
editor.h
explanations.cpp
io.cpp
layer_game.cpp
layer_quads.cpp
layer_sounds.cpp
layer_tiles.cpp
map_grid.cpp
map_grid.h
map_view.cpp
map_view.h
mapitems/image.cpp
mapitems/layer_front.cpp
mapitems/layer_game.cpp
mapitems/layer_group.cpp
mapitems/layer_quads.cpp
mapitems/layer_sounds.cpp
mapitems/layer_speedup.cpp
mapitems/layer_switch.cpp
mapitems/layer_tele.cpp
mapitems/layer_tiles.cpp
mapitems/layer_tune.cpp
mapitems/map.cpp
mapitems/sound.cpp
popups.cpp
proof_mode.cpp
proof_mode.h

View file

@ -87,206 +87,6 @@ enum
BUTTON_CONTEXT = 1,
};
CEditorImage::~CEditorImage()
{
m_pEditor->Graphics()->UnloadTexture(&m_Texture);
free(m_pData);
m_pData = nullptr;
}
CEditorSound::~CEditorSound()
{
m_pEditor->Sound()->UnloadSample(m_SoundID);
free(m_pData);
m_pData = nullptr;
}
CLayerGroup::CLayerGroup()
{
m_vpLayers.clear();
m_aName[0] = 0;
m_Visible = true;
m_Collapse = false;
m_GameGroup = false;
m_OffsetX = 0;
m_OffsetY = 0;
m_ParallaxX = 100;
m_ParallaxY = 100;
m_CustomParallaxZoom = 0;
m_ParallaxZoom = 100;
m_UseClipping = 0;
m_ClipX = 0;
m_ClipY = 0;
m_ClipW = 0;
m_ClipH = 0;
}
CLayerGroup::~CLayerGroup()
{
m_vpLayers.clear();
}
void CLayerGroup::Convert(CUIRect *pRect)
{
pRect->x += m_OffsetX;
pRect->y += m_OffsetY;
}
void CLayerGroup::Mapping(float *pPoints)
{
float ParallaxZoom = m_pMap->m_pEditor->m_PreviewZoom ? m_ParallaxZoom : 100.0f;
m_pMap->m_pEditor->RenderTools()->MapScreenToWorld(
m_pMap->m_pEditor->MapView()->GetWorldOffset().x, m_pMap->m_pEditor->MapView()->GetWorldOffset().y,
m_ParallaxX, m_ParallaxY, ParallaxZoom, m_OffsetX, m_OffsetY,
m_pMap->m_pEditor->Graphics()->ScreenAspect(), m_pMap->m_pEditor->MapView()->GetWorldZoom(), pPoints);
pPoints[0] += m_pMap->m_pEditor->MapView()->GetEditorOffset().x;
pPoints[1] += m_pMap->m_pEditor->MapView()->GetEditorOffset().y;
pPoints[2] += m_pMap->m_pEditor->MapView()->GetEditorOffset().x;
pPoints[3] += m_pMap->m_pEditor->MapView()->GetEditorOffset().y;
}
void CLayerGroup::MapScreen()
{
float aPoints[4];
Mapping(aPoints);
m_pMap->m_pEditor->Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
}
void CLayerGroup::Render()
{
MapScreen();
IGraphics *pGraphics = m_pMap->m_pEditor->Graphics();
if(m_UseClipping)
{
float aPoints[4];
m_pMap->m_pGameGroup->Mapping(aPoints);
float x0 = (m_ClipX - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y0 = (m_ClipY - aPoints[1]) / (aPoints[3] - aPoints[1]);
float x1 = ((m_ClipX + m_ClipW) - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y1 = ((m_ClipY + m_ClipH) - aPoints[1]) / (aPoints[3] - aPoints[1]);
pGraphics->ClipEnable((int)(x0 * pGraphics->ScreenWidth()), (int)(y0 * pGraphics->ScreenHeight()),
(int)((x1 - x0) * pGraphics->ScreenWidth()), (int)((y1 - y0) * pGraphics->ScreenHeight()));
}
for(auto &pLayer : m_vpLayers)
{
if(pLayer->m_Visible)
{
if(pLayer->m_Type == LAYERTYPE_TILES)
{
std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
if(pTiles->m_Game || pTiles->m_Front || pTiles->m_Tele || pTiles->m_Speedup || pTiles->m_Tune || pTiles->m_Switch)
continue;
}
if(m_pMap->m_pEditor->m_ShowDetail || !(pLayer->m_Flags & LAYERFLAG_DETAIL))
pLayer->Render();
}
}
for(auto &pLayer : m_vpLayers)
{
if(pLayer->m_Visible && pLayer->m_Type == LAYERTYPE_TILES && pLayer != m_pMap->m_pGameLayer && pLayer != m_pMap->m_pFrontLayer && pLayer != m_pMap->m_pTeleLayer && pLayer != m_pMap->m_pSpeedupLayer && pLayer != m_pMap->m_pSwitchLayer && pLayer != m_pMap->m_pTuneLayer)
{
std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
if(pTiles->m_Game || pTiles->m_Front || pTiles->m_Tele || pTiles->m_Speedup || pTiles->m_Tune || pTiles->m_Switch)
{
pLayer->Render();
}
}
}
if(m_UseClipping)
pGraphics->ClipDisable();
}
void CLayerGroup::AddLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pMap->OnModify();
m_vpLayers.push_back(pLayer);
}
void CLayerGroup::DeleteLayer(int Index)
{
if(Index < 0 || Index >= (int)m_vpLayers.size())
return;
m_vpLayers.erase(m_vpLayers.begin() + Index);
m_pMap->OnModify();
}
void CLayerGroup::DuplicateLayer(int Index)
{
if(Index < 0 || Index >= (int)m_vpLayers.size())
return;
std::shared_ptr<CLayer> pDup = m_vpLayers[Index]->Duplicate();
m_vpLayers.insert(m_vpLayers.begin() + Index + 1, pDup);
m_pMap->OnModify();
}
void CLayerGroup::GetSize(float *pWidth, float *pHeight) const
{
*pWidth = 0;
*pHeight = 0;
for(const auto &pLayer : m_vpLayers)
{
float lw, lh;
pLayer->GetSize(&lw, &lh);
*pWidth = maximum(*pWidth, lw);
*pHeight = maximum(*pHeight, lh);
}
}
int CLayerGroup::SwapLayers(int Index0, int Index1)
{
if(Index0 < 0 || Index0 >= (int)m_vpLayers.size())
return Index0;
if(Index1 < 0 || Index1 >= (int)m_vpLayers.size())
return Index0;
if(Index0 == Index1)
return Index0;
m_pMap->OnModify();
std::swap(m_vpLayers[Index0], m_vpLayers[Index1]);
return Index1;
}
void CEditorImage::AnalyseTileFlags()
{
mem_zero(m_aTileFlags, sizeof(m_aTileFlags));
int tw = m_Width / 16; // tilesizes
int th = m_Height / 16;
if(tw == th && m_Format == CImageInfo::FORMAT_RGBA)
{
unsigned char *pPixelData = (unsigned char *)m_pData;
int TileID = 0;
for(int ty = 0; ty < 16; ty++)
for(int tx = 0; tx < 16; tx++, TileID++)
{
bool Opaque = true;
for(int x = 0; x < tw; x++)
for(int y = 0; y < th; y++)
{
int p = (ty * tw + y) * m_Width + tx * tw + x;
if(pPixelData[p * 4 + 3] < 250)
{
Opaque = false;
break;
}
}
if(Opaque)
m_aTileFlags[TileID] |= TILEFLAG_OPAQUE;
}
}
}
void CEditor::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser)
{
CEditor *pThis = (CEditor *)pUser;
@ -7625,154 +7425,6 @@ void CEditor::Reset(bool CreateDefault)
m_SettingsCommandInput.Clear();
}
void CEditorMap::OnModify()
{
m_Modified = true;
m_ModifiedAuto = true;
m_LastModifiedTime = m_pEditor->Client()->GlobalTime();
}
void CEditorMap::DeleteEnvelope(int Index)
{
if(Index < 0 || Index >= (int)m_vpEnvelopes.size())
return;
OnModify();
VisitEnvelopeReferences([Index](int &ElementIndex) {
if(ElementIndex == Index)
ElementIndex = -1;
else if(ElementIndex > Index)
ElementIndex--;
});
m_vpEnvelopes.erase(m_vpEnvelopes.begin() + Index);
}
void CEditorMap::SwapEnvelopes(int Index0, int Index1)
{
if(Index0 < 0 || Index0 >= (int)m_vpEnvelopes.size())
return;
if(Index1 < 0 || Index1 >= (int)m_vpEnvelopes.size())
return;
if(Index0 == Index1)
return;
OnModify();
VisitEnvelopeReferences([Index0, Index1](int &ElementIndex) {
if(ElementIndex == Index0)
ElementIndex = Index1;
else if(ElementIndex == Index1)
ElementIndex = Index0;
});
std::swap(m_vpEnvelopes[Index0], m_vpEnvelopes[Index1]);
}
template<typename F>
void CEditorMap::VisitEnvelopeReferences(F &&Visitor)
{
for(auto &pGroup : m_vpGroups)
{
for(auto &pLayer : pGroup->m_vpLayers)
{
if(pLayer->m_Type == LAYERTYPE_QUADS)
{
std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(pLayer);
for(auto &Quad : pLayerQuads->m_vQuads)
{
Visitor(Quad.m_PosEnv);
Visitor(Quad.m_ColorEnv);
}
}
else if(pLayer->m_Type == LAYERTYPE_TILES)
{
std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
Visitor(pLayerTiles->m_ColorEnv);
}
else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(pLayer);
for(auto &Source : pLayerSounds->m_vSources)
{
Visitor(Source.m_PosEnv);
Visitor(Source.m_SoundEnv);
}
}
}
}
}
void CEditorMap::MakeGameLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pGameLayer = std::static_pointer_cast<CLayerGame>(pLayer);
m_pGameLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeGameGroup(std::shared_ptr<CLayerGroup> pGroup)
{
m_pGameGroup = std::move(pGroup);
m_pGameGroup->m_GameGroup = true;
str_copy(m_pGameGroup->m_aName, "Game");
}
void CEditorMap::Clean()
{
m_vpGroups.clear();
m_vpEnvelopes.clear();
m_vpImages.clear();
m_vpSounds.clear();
m_MapInfo.Reset();
m_MapInfoTmp.Reset();
m_vSettings.clear();
m_pGameLayer = nullptr;
m_pGameGroup = nullptr;
m_Modified = false;
m_ModifiedAuto = false;
m_pTeleLayer = nullptr;
m_pSpeedupLayer = nullptr;
m_pFrontLayer = nullptr;
m_pSwitchLayer = nullptr;
m_pTuneLayer = nullptr;
}
void CEditorMap::CreateDefault(IGraphics::CTextureHandle EntitiesTexture)
{
// add background
std::shared_ptr<CLayerGroup> pGroup = NewGroup();
pGroup->m_ParallaxX = 0;
pGroup->m_ParallaxY = 0;
pGroup->m_CustomParallaxZoom = 0;
pGroup->m_ParallaxZoom = 0;
std::shared_ptr<CLayerQuads> pLayer = std::make_shared<CLayerQuads>();
pLayer->m_pEditor = m_pEditor;
CQuad *pQuad = pLayer->NewQuad(0, 0, 1600, 1200);
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;
pQuad->m_aColors[2].r = pQuad->m_aColors[3].r = 204;
pQuad->m_aColors[2].g = pQuad->m_aColors[3].g = 232;
pQuad->m_aColors[2].b = pQuad->m_aColors[3].b = 255;
pGroup->AddLayer(pLayer);
// add game layer and reset front, tele, speedup, tune and switch layer pointers
MakeGameGroup(NewGroup());
MakeGameLayer(std::make_shared<CLayerGame>(50, 50));
m_pGameGroup->AddLayer(m_pGameLayer);
m_pFrontLayer = nullptr;
m_pTeleLayer = nullptr;
m_pSpeedupLayer = nullptr;
m_pSwitchLayer = nullptr;
m_pTuneLayer = nullptr;
}
int CEditor::GetTextureUsageFlag()
{
return Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
@ -8173,35 +7825,3 @@ void CEditor::LoadCurrentMap()
}
IEditor *CreateEditor() { return new CEditor; }
// DDRace
void CEditorMap::MakeTeleLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pTeleLayer = std::static_pointer_cast<CLayerTele>(pLayer);
m_pTeleLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeSpeedupLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pSpeedupLayer = std::static_pointer_cast<CLayerSpeedup>(pLayer);
m_pSpeedupLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeFrontLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pFrontLayer = std::static_pointer_cast<CLayerFront>(pLayer);
m_pFrontLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeSwitchLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pSwitchLayer = std::static_pointer_cast<CLayerSwitch>(pLayer);
m_pSwitchLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeTuneLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pTuneLayer = std::static_pointer_cast<CLayerTune>(pLayer);
m_pTuneLayer->m_pEditor = m_pEditor;
}

View file

@ -0,0 +1,40 @@
#include <game/editor/editor.h>
CEditorImage::~CEditorImage()
{
m_pEditor->Graphics()->UnloadTexture(&m_Texture);
free(m_pData);
m_pData = nullptr;
}
void CEditorImage::AnalyseTileFlags()
{
mem_zero(m_aTileFlags, sizeof(m_aTileFlags));
int tw = m_Width / 16; // tilesizes
int th = m_Height / 16;
if(tw == th && m_Format == CImageInfo::FORMAT_RGBA)
{
unsigned char *pPixelData = (unsigned char *)m_pData;
int TileID = 0;
for(int ty = 0; ty < 16; ty++)
for(int tx = 0; tx < 16; tx++, TileID++)
{
bool Opaque = true;
for(int x = 0; x < tw; x++)
for(int y = 0; y < th; y++)
{
int p = (ty * tw + y) * m_Width + tx * tw + x;
if(pPixelData[p * 4 + 3] < 250)
{
Opaque = false;
break;
}
}
if(Opaque)
m_aTileFlags[TileID] |= TILEFLAG_OPAQUE;
}
}
}

View file

@ -0,0 +1,47 @@
#include <game/editor/editor.h>
CLayerFront::CLayerFront(int w, int h) :
CLayerTiles(w, h)
{
str_copy(m_aName, "Front");
m_Front = 1;
}
void CLayerFront::SetTile(int x, int y, CTile Tile)
{
if(Tile.m_Index == TILE_THROUGH_CUT)
{
CTile nohook = {TILE_NOHOOK};
m_pEditor->m_Map.m_pGameLayer->CLayerTiles::SetTile(x, y, nohook); // NOLINT(bugprone-parent-virtual-call)
}
else if(Tile.m_Index == TILE_AIR && CLayerTiles::GetTile(x, y).m_Index == TILE_THROUGH_CUT)
{
CTile air = {TILE_AIR};
m_pEditor->m_Map.m_pGameLayer->CLayerTiles::SetTile(x, y, air); // NOLINT(bugprone-parent-virtual-call)
}
if(m_pEditor->m_AllowPlaceUnusedTiles || IsValidFrontTile(Tile.m_Index))
{
CLayerTiles::SetTile(x, y, Tile);
}
else
{
CTile air = {TILE_AIR};
CLayerTiles::SetTile(x, y, air);
if(!m_pEditor->m_PreventUnusedTilesWasWarned)
{
m_pEditor->m_PopupEventType = CEditor::POPEVENT_PREVENTUNUSEDTILES;
m_pEditor->m_PopupEventActivated = true;
m_pEditor->m_PreventUnusedTilesWasWarned = true;
}
}
}
void CLayerFront::Resize(int NewW, int NewH)
{
// resize tile data
CLayerTiles::Resize(NewW, NewH);
// resize gamelayer too
if(m_pEditor->m_Map.m_pGameLayer->m_Width != NewW || m_pEditor->m_Map.m_pGameLayer->m_Height != NewH)
m_pEditor->m_Map.m_pGameLayer->Resize(NewW, NewH);
}

View file

@ -1,6 +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 "editor.h"
#include <game/editor/editor.h>
CLayerGame::CLayerGame(int w, int h) :
CLayerTiles(w, h)

View file

@ -0,0 +1,155 @@
#include <game/editor/editor.h>
CLayerGroup::CLayerGroup()
{
m_vpLayers.clear();
m_aName[0] = 0;
m_Visible = true;
m_Collapse = false;
m_GameGroup = false;
m_OffsetX = 0;
m_OffsetY = 0;
m_ParallaxX = 100;
m_ParallaxY = 100;
m_CustomParallaxZoom = 0;
m_ParallaxZoom = 100;
m_UseClipping = 0;
m_ClipX = 0;
m_ClipY = 0;
m_ClipW = 0;
m_ClipH = 0;
}
CLayerGroup::~CLayerGroup()
{
m_vpLayers.clear();
}
void CLayerGroup::Convert(CUIRect *pRect)
{
pRect->x += m_OffsetX;
pRect->y += m_OffsetY;
}
void CLayerGroup::Mapping(float *pPoints)
{
float ParallaxZoom = m_pMap->m_pEditor->m_PreviewZoom ? m_ParallaxZoom : 100.0f;
m_pMap->m_pEditor->RenderTools()->MapScreenToWorld(
m_pMap->m_pEditor->MapView()->GetWorldOffset().x, m_pMap->m_pEditor->MapView()->GetWorldOffset().y,
m_ParallaxX, m_ParallaxY, ParallaxZoom, m_OffsetX, m_OffsetY,
m_pMap->m_pEditor->Graphics()->ScreenAspect(), m_pMap->m_pEditor->MapView()->GetWorldZoom(), pPoints);
pPoints[0] += m_pMap->m_pEditor->MapView()->GetEditorOffset().x;
pPoints[1] += m_pMap->m_pEditor->MapView()->GetEditorOffset().y;
pPoints[2] += m_pMap->m_pEditor->MapView()->GetEditorOffset().x;
pPoints[3] += m_pMap->m_pEditor->MapView()->GetEditorOffset().y;
}
void CLayerGroup::MapScreen()
{
float aPoints[4];
Mapping(aPoints);
m_pMap->m_pEditor->Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
}
void CLayerGroup::Render()
{
MapScreen();
IGraphics *pGraphics = m_pMap->m_pEditor->Graphics();
if(m_UseClipping)
{
float aPoints[4];
m_pMap->m_pGameGroup->Mapping(aPoints);
float x0 = (m_ClipX - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y0 = (m_ClipY - aPoints[1]) / (aPoints[3] - aPoints[1]);
float x1 = ((m_ClipX + m_ClipW) - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y1 = ((m_ClipY + m_ClipH) - aPoints[1]) / (aPoints[3] - aPoints[1]);
pGraphics->ClipEnable((int)(x0 * pGraphics->ScreenWidth()), (int)(y0 * pGraphics->ScreenHeight()),
(int)((x1 - x0) * pGraphics->ScreenWidth()), (int)((y1 - y0) * pGraphics->ScreenHeight()));
}
for(auto &pLayer : m_vpLayers)
{
if(pLayer->m_Visible)
{
if(pLayer->m_Type == LAYERTYPE_TILES)
{
std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
if(pTiles->m_Game || pTiles->m_Front || pTiles->m_Tele || pTiles->m_Speedup || pTiles->m_Tune || pTiles->m_Switch)
continue;
}
if(m_pMap->m_pEditor->m_ShowDetail || !(pLayer->m_Flags & LAYERFLAG_DETAIL))
pLayer->Render();
}
}
for(auto &pLayer : m_vpLayers)
{
if(pLayer->m_Visible && pLayer->m_Type == LAYERTYPE_TILES && pLayer != m_pMap->m_pGameLayer && pLayer != m_pMap->m_pFrontLayer && pLayer != m_pMap->m_pTeleLayer && pLayer != m_pMap->m_pSpeedupLayer && pLayer != m_pMap->m_pSwitchLayer && pLayer != m_pMap->m_pTuneLayer)
{
std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
if(pTiles->m_Game || pTiles->m_Front || pTiles->m_Tele || pTiles->m_Speedup || pTiles->m_Tune || pTiles->m_Switch)
{
pLayer->Render();
}
}
}
if(m_UseClipping)
pGraphics->ClipDisable();
}
void CLayerGroup::AddLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pMap->OnModify();
m_vpLayers.push_back(pLayer);
}
void CLayerGroup::DeleteLayer(int Index)
{
if(Index < 0 || Index >= (int)m_vpLayers.size())
return;
m_vpLayers.erase(m_vpLayers.begin() + Index);
m_pMap->OnModify();
}
void CLayerGroup::DuplicateLayer(int Index)
{
if(Index < 0 || Index >= (int)m_vpLayers.size())
return;
std::shared_ptr<CLayer> pDup = m_vpLayers[Index]->Duplicate();
m_vpLayers.insert(m_vpLayers.begin() + Index + 1, pDup);
m_pMap->OnModify();
}
void CLayerGroup::GetSize(float *pWidth, float *pHeight) const
{
*pWidth = 0;
*pHeight = 0;
for(const auto &pLayer : m_vpLayers)
{
float lw, lh;
pLayer->GetSize(&lw, &lh);
*pWidth = maximum(*pWidth, lw);
*pHeight = maximum(*pHeight, lh);
}
}
int CLayerGroup::SwapLayers(int Index0, int Index1)
{
if(Index0 < 0 || Index0 >= (int)m_vpLayers.size())
return Index0;
if(Index1 < 0 || Index1 >= (int)m_vpLayers.size())
return Index0;
if(Index0 == Index1)
return Index0;
m_pMap->OnModify();
std::swap(m_vpLayers[Index0], m_vpLayers[Index1]);
return Index1;
}

View file

@ -1,11 +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 <base/math.h>
#include <engine/graphics.h>
#include "editor.h"
#include <game/client/render.h>
#include <game/editor/editor.h>
CLayerQuads::CLayerQuads()
{

View file

@ -1,8 +1,7 @@
#include <game/editor/editor.h>
#include <game/generated/client_data.h>
#include "editor.h"
static const float s_SourceVisualSize = 32.0f;
CLayerSounds::CLayerSounds()

View file

@ -0,0 +1,244 @@
#include <game/editor/editor.h>
CLayerSpeedup::CLayerSpeedup(int w, int h) :
CLayerTiles(w, h)
{
str_copy(m_aName, "Speedup");
m_Speedup = 1;
m_pSpeedupTile = new CSpeedupTile[w * h];
mem_zero(m_pSpeedupTile, (size_t)w * h * sizeof(CSpeedupTile));
}
CLayerSpeedup::~CLayerSpeedup()
{
delete[] m_pSpeedupTile;
}
void CLayerSpeedup::Resize(int NewW, int NewH)
{
// resize speedup data
CSpeedupTile *pNewSpeedupData = new CSpeedupTile[NewW * NewH];
mem_zero(pNewSpeedupData, (size_t)NewW * NewH * sizeof(CSpeedupTile));
// copy old data
for(int y = 0; y < minimum(NewH, m_Height); y++)
mem_copy(&pNewSpeedupData[y * NewW], &m_pSpeedupTile[y * m_Width], minimum(m_Width, NewW) * sizeof(CSpeedupTile));
// replace old
delete[] m_pSpeedupTile;
m_pSpeedupTile = pNewSpeedupData;
// resize tile data
CLayerTiles::Resize(NewW, NewH);
// resize gamelayer too
if(m_pEditor->m_Map.m_pGameLayer->m_Width != NewW || m_pEditor->m_Map.m_pGameLayer->m_Height != NewH)
m_pEditor->m_Map.m_pGameLayer->Resize(NewW, NewH);
}
void CLayerSpeedup::Shift(int Direction)
{
CLayerTiles::Shift(Direction);
ShiftImpl(m_pSpeedupTile, Direction, m_pEditor->m_ShiftBy);
}
bool CLayerSpeedup::IsEmpty(const std::shared_ptr<CLayerTiles> &pLayer)
{
for(int y = 0; y < pLayer->m_Height; y++)
for(int x = 0; x < pLayer->m_Width; x++)
if(m_pEditor->m_AllowPlaceUnusedTiles || IsValidSpeedupTile(pLayer->GetTile(x, y).m_Index))
return false;
return true;
}
void CLayerSpeedup::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
{
if(m_Readonly)
return;
std::shared_ptr<CLayerSpeedup> pSpeedupLayer = std::static_pointer_cast<CLayerSpeedup>(pBrush);
int sx = ConvertX(wx);
int sy = ConvertY(wy);
if(str_comp(pSpeedupLayer->m_aFileName, m_pEditor->m_aFileName))
{
m_pEditor->m_SpeedupAngle = pSpeedupLayer->m_SpeedupAngle;
m_pEditor->m_SpeedupForce = pSpeedupLayer->m_SpeedupForce;
m_pEditor->m_SpeedupMaxSpeed = pSpeedupLayer->m_SpeedupMaxSpeed;
}
bool Destructive = m_pEditor->m_BrushDrawDestructive || IsEmpty(pSpeedupLayer);
for(int y = 0; y < pSpeedupLayer->m_Height; y++)
for(int x = 0; x < pSpeedupLayer->m_Width; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidSpeedupTile(pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index)) && pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index != TILE_AIR)
{
if(m_pEditor->m_SpeedupAngle != pSpeedupLayer->m_SpeedupAngle || m_pEditor->m_SpeedupForce != pSpeedupLayer->m_SpeedupForce || m_pEditor->m_SpeedupMaxSpeed != pSpeedupLayer->m_SpeedupMaxSpeed)
{
m_pSpeedupTile[fy * m_Width + fx].m_Force = m_pEditor->m_SpeedupForce;
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
m_pSpeedupTile[fy * m_Width + fx].m_Angle = m_pEditor->m_SpeedupAngle;
m_pSpeedupTile[fy * m_Width + fx].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
m_pTiles[fy * m_Width + fx].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
}
else if(pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Force)
{
m_pSpeedupTile[fy * m_Width + fx].m_Force = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Force;
m_pSpeedupTile[fy * m_Width + fx].m_Angle = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_Angle;
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = pSpeedupLayer->m_pSpeedupTile[y * pSpeedupLayer->m_Width + x].m_MaxSpeed;
m_pSpeedupTile[fy * m_Width + fx].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
m_pTiles[fy * m_Width + fx].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
}
else if(m_pEditor->m_SpeedupForce)
{
m_pSpeedupTile[fy * m_Width + fx].m_Force = m_pEditor->m_SpeedupForce;
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
m_pSpeedupTile[fy * m_Width + fx].m_Angle = m_pEditor->m_SpeedupAngle;
m_pSpeedupTile[fy * m_Width + fx].m_Type = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
m_pTiles[fy * m_Width + fx].m_Index = pSpeedupLayer->m_pTiles[y * pSpeedupLayer->m_Width + x].m_Index;
}
else
{
m_pSpeedupTile[fy * m_Width + fx].m_Force = 0;
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = 0;
m_pSpeedupTile[fy * m_Width + fx].m_Angle = 0;
m_pSpeedupTile[fy * m_Width + fx].m_Type = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
}
}
else
{
m_pSpeedupTile[fy * m_Width + fx].m_Force = 0;
m_pSpeedupTile[fy * m_Width + fx].m_MaxSpeed = 0;
m_pSpeedupTile[fy * m_Width + fx].m_Angle = 0;
m_pSpeedupTile[fy * m_Width + fx].m_Type = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
}
}
FlagModified(sx, sy, pSpeedupLayer->m_Width, pSpeedupLayer->m_Height);
}
void CLayerSpeedup::BrushFlipX()
{
CLayerTiles::BrushFlipX();
BrushFlipXImpl(m_pSpeedupTile);
}
void CLayerSpeedup::BrushFlipY()
{
CLayerTiles::BrushFlipY();
BrushFlipYImpl(m_pSpeedupTile);
}
void CLayerSpeedup::BrushRotate(float Amount)
{
int Rotation = (round_to_int(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
CSpeedupTile *pTempData1 = new CSpeedupTile[m_Width * m_Height];
CTile *pTempData2 = new CTile[m_Width * m_Height];
mem_copy(pTempData1, m_pSpeedupTile, (size_t)m_Width * m_Height * sizeof(CSpeedupTile));
mem_copy(pTempData2, m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
CSpeedupTile *pDst1 = m_pSpeedupTile;
CTile *pDst2 = m_pTiles;
for(int x = 0; x < m_Width; ++x)
for(int y = m_Height - 1; y >= 0; --y, ++pDst1, ++pDst2)
{
*pDst1 = pTempData1[y * m_Width + x];
*pDst2 = pTempData2[y * m_Width + x];
}
std::swap(m_Width, m_Height);
delete[] pTempData1;
delete[] pTempData2;
}
if(Rotation == 2 || Rotation == 3)
{
BrushFlipX();
BrushFlipY();
}
}
void CLayerSpeedup::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect)
{
if(m_Readonly || (!Empty && pBrush->m_Type != LAYERTYPE_TILES))
return;
Snap(&Rect); // corrects Rect; no need of <=
Snap(&Rect);
int sx = ConvertX(Rect.x);
int sy = ConvertY(Rect.y);
int w = ConvertX(Rect.w);
int h = ConvertY(Rect.h);
std::shared_ptr<CLayerSpeedup> pLt = std::static_pointer_cast<CLayerSpeedup>(pBrush);
bool Destructive = m_pEditor->m_BrushDrawDestructive || Empty || IsEmpty(pLt);
for(int y = 0; y < h; y++)
{
for(int x = 0; x < w; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
const int TgtIndex = fy * m_Width + fx;
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidSpeedupTile((pLt->m_pTiles[SrcIndex]).m_Index))) // no speed up tile chosen: reset
{
m_pTiles[TgtIndex].m_Index = 0;
m_pSpeedupTile[TgtIndex].m_Force = 0;
m_pSpeedupTile[TgtIndex].m_Angle = 0;
}
else
{
m_pTiles[TgtIndex] = pLt->m_pTiles[SrcIndex];
if(pLt->m_Speedup && m_pTiles[TgtIndex].m_Index > 0)
{
m_pSpeedupTile[TgtIndex].m_Type = m_pTiles[TgtIndex].m_Index;
if((pLt->m_pSpeedupTile[SrcIndex].m_Force == 0 && m_pEditor->m_SpeedupForce) || m_pEditor->m_SpeedupForce != pLt->m_SpeedupForce)
m_pSpeedupTile[TgtIndex].m_Force = m_pEditor->m_SpeedupForce;
else
m_pSpeedupTile[TgtIndex].m_Force = pLt->m_pSpeedupTile[SrcIndex].m_Force;
if((pLt->m_pSpeedupTile[SrcIndex].m_Angle == 0 && m_pEditor->m_SpeedupAngle) || m_pEditor->m_SpeedupAngle != pLt->m_SpeedupAngle)
m_pSpeedupTile[TgtIndex].m_Angle = m_pEditor->m_SpeedupAngle;
else
m_pSpeedupTile[TgtIndex].m_Angle = pLt->m_pSpeedupTile[SrcIndex].m_Angle;
if((pLt->m_pSpeedupTile[SrcIndex].m_MaxSpeed == 0 && m_pEditor->m_SpeedupMaxSpeed) || m_pEditor->m_SpeedupMaxSpeed != pLt->m_SpeedupMaxSpeed)
m_pSpeedupTile[TgtIndex].m_MaxSpeed = m_pEditor->m_SpeedupMaxSpeed;
else
m_pSpeedupTile[TgtIndex].m_MaxSpeed = pLt->m_pSpeedupTile[SrcIndex].m_MaxSpeed;
}
}
}
}
FlagModified(sx, sy, w, h);
}

View file

@ -0,0 +1,270 @@
#include <game/editor/editor.h>
CLayerSwitch::CLayerSwitch(int w, int h) :
CLayerTiles(w, h)
{
str_copy(m_aName, "Switch");
m_Switch = 1;
m_pSwitchTile = new CSwitchTile[w * h];
mem_zero(m_pSwitchTile, (size_t)w * h * sizeof(CSwitchTile));
}
CLayerSwitch::~CLayerSwitch()
{
delete[] m_pSwitchTile;
}
void CLayerSwitch::Resize(int NewW, int NewH)
{
// resize switch data
CSwitchTile *pNewSwitchData = new CSwitchTile[NewW * NewH];
mem_zero(pNewSwitchData, (size_t)NewW * NewH * sizeof(CSwitchTile));
// copy old data
for(int y = 0; y < minimum(NewH, m_Height); y++)
mem_copy(&pNewSwitchData[y * NewW], &m_pSwitchTile[y * m_Width], minimum(m_Width, NewW) * sizeof(CSwitchTile));
// replace old
delete[] m_pSwitchTile;
m_pSwitchTile = pNewSwitchData;
// resize tile data
CLayerTiles::Resize(NewW, NewH);
// resize gamelayer too
if(m_pEditor->m_Map.m_pGameLayer->m_Width != NewW || m_pEditor->m_Map.m_pGameLayer->m_Height != NewH)
m_pEditor->m_Map.m_pGameLayer->Resize(NewW, NewH);
}
void CLayerSwitch::Shift(int Direction)
{
CLayerTiles::Shift(Direction);
ShiftImpl(m_pSwitchTile, Direction, m_pEditor->m_ShiftBy);
}
bool CLayerSwitch::IsEmpty(const std::shared_ptr<CLayerTiles> &pLayer)
{
for(int y = 0; y < pLayer->m_Height; y++)
for(int x = 0; x < pLayer->m_Width; x++)
if(m_pEditor->m_AllowPlaceUnusedTiles || IsValidSwitchTile(pLayer->GetTile(x, y).m_Index))
return false;
return true;
}
void CLayerSwitch::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
{
if(m_Readonly)
return;
std::shared_ptr<CLayerSwitch> pSwitchLayer = std::static_pointer_cast<CLayerSwitch>(pBrush);
int sx = ConvertX(wx);
int sy = ConvertY(wy);
if(str_comp(pSwitchLayer->m_aFileName, m_pEditor->m_aFileName))
{
m_pEditor->m_SwitchNum = pSwitchLayer->m_SwitchNumber;
m_pEditor->m_SwitchDelay = pSwitchLayer->m_SwitchDelay;
}
bool Destructive = m_pEditor->m_BrushDrawDestructive || IsEmpty(pSwitchLayer);
for(int y = 0; y < pSwitchLayer->m_Height; y++)
for(int x = 0; x < pSwitchLayer->m_Width; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidSwitchTile(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index)) && pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index != TILE_AIR)
{
if(m_pEditor->m_SwitchNum != pSwitchLayer->m_SwitchNumber || m_pEditor->m_SwitchDelay != pSwitchLayer->m_SwitchDelay)
{
m_pSwitchTile[fy * m_Width + fx].m_Number = m_pEditor->m_SwitchNum;
m_pSwitchTile[fy * m_Width + fx].m_Delay = m_pEditor->m_SwitchDelay;
}
else if(pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Number)
{
m_pSwitchTile[fy * m_Width + fx].m_Number = pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Number;
m_pSwitchTile[fy * m_Width + fx].m_Delay = pSwitchLayer->m_pSwitchTile[y * pSwitchLayer->m_Width + x].m_Delay;
}
else
{
m_pSwitchTile[fy * m_Width + fx].m_Number = m_pEditor->m_SwitchNum;
m_pSwitchTile[fy * m_Width + fx].m_Delay = m_pEditor->m_SwitchDelay;
}
m_pSwitchTile[fy * m_Width + fx].m_Type = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index;
m_pSwitchTile[fy * m_Width + fx].m_Flags = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Flags;
m_pTiles[fy * m_Width + fx].m_Index = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index;
m_pTiles[fy * m_Width + fx].m_Flags = pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Flags;
if(!IsSwitchTileFlagsUsed(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index))
{
m_pSwitchTile[fy * m_Width + fx].m_Flags = 0;
}
if(!IsSwitchTileNumberUsed(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index))
{
m_pSwitchTile[fy * m_Width + fx].m_Number = 0;
}
if(!IsSwitchTileDelayUsed(pSwitchLayer->m_pTiles[y * pSwitchLayer->m_Width + x].m_Index))
{
m_pSwitchTile[fy * m_Width + fx].m_Delay = 0;
}
}
else
{
m_pSwitchTile[fy * m_Width + fx].m_Number = 0;
m_pSwitchTile[fy * m_Width + fx].m_Type = 0;
m_pSwitchTile[fy * m_Width + fx].m_Flags = 0;
m_pSwitchTile[fy * m_Width + fx].m_Delay = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
}
}
FlagModified(sx, sy, pSwitchLayer->m_Width, pSwitchLayer->m_Height);
}
void CLayerSwitch::BrushFlipX()
{
CLayerTiles::BrushFlipX();
BrushFlipXImpl(m_pSwitchTile);
}
void CLayerSwitch::BrushFlipY()
{
CLayerTiles::BrushFlipY();
BrushFlipYImpl(m_pSwitchTile);
}
void CLayerSwitch::BrushRotate(float Amount)
{
int Rotation = (round_to_int(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
CSwitchTile *pTempData1 = new CSwitchTile[m_Width * m_Height];
CTile *pTempData2 = new CTile[m_Width * m_Height];
mem_copy(pTempData1, m_pSwitchTile, (size_t)m_Width * m_Height * sizeof(CSwitchTile));
mem_copy(pTempData2, m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
CSwitchTile *pDst1 = m_pSwitchTile;
CTile *pDst2 = m_pTiles;
for(int x = 0; x < m_Width; ++x)
for(int y = m_Height - 1; y >= 0; --y, ++pDst1, ++pDst2)
{
*pDst1 = pTempData1[y * m_Width + x];
*pDst2 = pTempData2[y * m_Width + x];
if(IsRotatableTile(pDst2->m_Index))
{
if(pDst2->m_Flags & TILEFLAG_ROTATE)
pDst2->m_Flags ^= (TILEFLAG_YFLIP | TILEFLAG_XFLIP);
pDst2->m_Flags ^= TILEFLAG_ROTATE;
}
}
std::swap(m_Width, m_Height);
delete[] pTempData1;
delete[] pTempData2;
}
if(Rotation == 2 || Rotation == 3)
{
BrushFlipX();
BrushFlipY();
}
}
void CLayerSwitch::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect)
{
if(m_Readonly || (!Empty && pBrush->m_Type != LAYERTYPE_TILES))
return;
Snap(&Rect); // corrects Rect; no need of <=
Snap(&Rect);
int sx = ConvertX(Rect.x);
int sy = ConvertY(Rect.y);
int w = ConvertX(Rect.w);
int h = ConvertY(Rect.h);
std::shared_ptr<CLayerSwitch> pLt = std::static_pointer_cast<CLayerSwitch>(pBrush);
bool Destructive = m_pEditor->m_BrushDrawDestructive || Empty || IsEmpty(pLt);
for(int y = 0; y < h; y++)
{
for(int x = 0; x < w; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
const int TgtIndex = fy * m_Width + fx;
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidSwitchTile((pLt->m_pTiles[SrcIndex]).m_Index)))
{
m_pTiles[TgtIndex].m_Index = 0;
m_pSwitchTile[TgtIndex].m_Type = 0;
m_pSwitchTile[TgtIndex].m_Number = 0;
m_pSwitchTile[TgtIndex].m_Delay = 0;
}
else
{
m_pTiles[TgtIndex] = pLt->m_pTiles[SrcIndex];
m_pSwitchTile[TgtIndex].m_Type = m_pTiles[TgtIndex].m_Index;
if(pLt->m_Switch && m_pTiles[TgtIndex].m_Index > 0)
{
if(!IsSwitchTileNumberUsed(m_pSwitchTile[TgtIndex].m_Type))
m_pSwitchTile[TgtIndex].m_Number = 0;
else if(pLt->m_pSwitchTile[SrcIndex].m_Number == 0 || m_pEditor->m_SwitchNum != pLt->m_SwitchNumber)
m_pSwitchTile[TgtIndex].m_Number = m_pEditor->m_SwitchNum;
else
m_pSwitchTile[TgtIndex].m_Number = pLt->m_pSwitchTile[SrcIndex].m_Number;
if(!IsSwitchTileDelayUsed(m_pSwitchTile[TgtIndex].m_Type))
m_pSwitchTile[TgtIndex].m_Delay = 0;
else if(pLt->m_pSwitchTile[SrcIndex].m_Delay == 0 || m_pEditor->m_SwitchDelay != pLt->m_SwitchDelay)
m_pSwitchTile[TgtIndex].m_Delay = m_pEditor->m_SwitchDelay;
else
m_pSwitchTile[TgtIndex].m_Delay = pLt->m_pSwitchTile[SrcIndex].m_Delay;
if(!IsSwitchTileFlagsUsed(m_pSwitchTile[TgtIndex].m_Type))
m_pSwitchTile[TgtIndex].m_Flags = 0;
else
m_pSwitchTile[TgtIndex].m_Flags = pLt->m_pSwitchTile[SrcIndex].m_Flags;
}
}
}
}
FlagModified(sx, sy, w, h);
}
bool CLayerSwitch::ContainsElementWithId(int Id)
{
for(int y = 0; y < m_Height; ++y)
{
for(int x = 0; x < m_Width; ++x)
{
if(IsSwitchTileNumberUsed(m_pSwitchTile[y * m_Width + x].m_Type) && m_pSwitchTile[y * m_Width + x].m_Number == Id)
{
return true;
}
}
}
return false;
}

View file

@ -0,0 +1,247 @@
#include <game/editor/editor.h>
CLayerTele::CLayerTele(int w, int h) :
CLayerTiles(w, h)
{
str_copy(m_aName, "Tele");
m_Tele = 1;
m_pTeleTile = new CTeleTile[w * h];
mem_zero(m_pTeleTile, (size_t)w * h * sizeof(CTeleTile));
}
CLayerTele::~CLayerTele()
{
delete[] m_pTeleTile;
}
void CLayerTele::Resize(int NewW, int NewH)
{
// resize tele data
CTeleTile *pNewTeleData = new CTeleTile[NewW * NewH];
mem_zero(pNewTeleData, (size_t)NewW * NewH * sizeof(CTeleTile));
// copy old data
for(int y = 0; y < minimum(NewH, m_Height); y++)
mem_copy(&pNewTeleData[y * NewW], &m_pTeleTile[y * m_Width], minimum(m_Width, NewW) * sizeof(CTeleTile));
// replace old
delete[] m_pTeleTile;
m_pTeleTile = pNewTeleData;
// resize tile data
CLayerTiles::Resize(NewW, NewH);
// resize gamelayer too
if(m_pEditor->m_Map.m_pGameLayer->m_Width != NewW || m_pEditor->m_Map.m_pGameLayer->m_Height != NewH)
m_pEditor->m_Map.m_pGameLayer->Resize(NewW, NewH);
}
void CLayerTele::Shift(int Direction)
{
CLayerTiles::Shift(Direction);
ShiftImpl(m_pTeleTile, Direction, m_pEditor->m_ShiftBy);
}
bool CLayerTele::IsEmpty(const std::shared_ptr<CLayerTiles> &pLayer)
{
for(int y = 0; y < pLayer->m_Height; y++)
for(int x = 0; x < pLayer->m_Width; x++)
if(m_pEditor->m_AllowPlaceUnusedTiles || IsValidTeleTile(pLayer->GetTile(x, y).m_Index))
return false;
return true;
}
void CLayerTele::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
{
if(m_Readonly)
return;
std::shared_ptr<CLayerTele> pTeleLayer = std::static_pointer_cast<CLayerTele>(pBrush);
int sx = ConvertX(wx);
int sy = ConvertY(wy);
if(str_comp(pTeleLayer->m_aFileName, m_pEditor->m_aFileName))
m_pEditor->m_TeleNumber = pTeleLayer->m_TeleNum;
bool Destructive = m_pEditor->m_BrushDrawDestructive || IsEmpty(pTeleLayer);
for(int y = 0; y < pTeleLayer->m_Height; y++)
for(int x = 0; x < pTeleLayer->m_Width; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidTeleTile(pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index)) && pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index != TILE_AIR)
{
if(!IsTeleTileNumberUsed(pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index))
{
// Tele tile number is unused. Set a known value which is not 0,
// as tiles with number 0 would be ignored by previous versions.
m_pTeleTile[fy * m_Width + fx].m_Number = 255;
}
else if(m_pEditor->m_TeleNumber != pTeleLayer->m_TeleNum)
{
m_pTeleTile[fy * m_Width + fx].m_Number = m_pEditor->m_TeleNumber;
}
else if(pTeleLayer->m_pTeleTile[y * pTeleLayer->m_Width + x].m_Number)
{
m_pTeleTile[fy * m_Width + fx].m_Number = pTeleLayer->m_pTeleTile[y * pTeleLayer->m_Width + x].m_Number;
}
else
{
if(!m_pEditor->m_TeleNumber)
{
m_pTeleTile[fy * m_Width + fx].m_Number = 0;
m_pTeleTile[fy * m_Width + fx].m_Type = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
continue;
}
else
m_pTeleTile[fy * m_Width + fx].m_Number = m_pEditor->m_TeleNumber;
}
m_pTeleTile[fy * m_Width + fx].m_Type = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
m_pTiles[fy * m_Width + fx].m_Index = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
}
else
{
m_pTeleTile[fy * m_Width + fx].m_Number = 0;
m_pTeleTile[fy * m_Width + fx].m_Type = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
}
}
FlagModified(sx, sy, pTeleLayer->m_Width, pTeleLayer->m_Height);
}
void CLayerTele::BrushFlipX()
{
CLayerTiles::BrushFlipX();
BrushFlipXImpl(m_pTeleTile);
}
void CLayerTele::BrushFlipY()
{
CLayerTiles::BrushFlipY();
BrushFlipYImpl(m_pTeleTile);
}
void CLayerTele::BrushRotate(float Amount)
{
int Rotation = (round_to_int(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
CTeleTile *pTempData1 = new CTeleTile[m_Width * m_Height];
CTile *pTempData2 = new CTile[m_Width * m_Height];
mem_copy(pTempData1, m_pTeleTile, (size_t)m_Width * m_Height * sizeof(CTeleTile));
mem_copy(pTempData2, m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
CTeleTile *pDst1 = m_pTeleTile;
CTile *pDst2 = m_pTiles;
for(int x = 0; x < m_Width; ++x)
for(int y = m_Height - 1; y >= 0; --y, ++pDst1, ++pDst2)
{
*pDst1 = pTempData1[y * m_Width + x];
*pDst2 = pTempData2[y * m_Width + x];
}
std::swap(m_Width, m_Height);
delete[] pTempData1;
delete[] pTempData2;
}
if(Rotation == 2 || Rotation == 3)
{
BrushFlipX();
BrushFlipY();
}
}
void CLayerTele::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect)
{
if(m_Readonly || (!Empty && pBrush->m_Type != LAYERTYPE_TILES))
return;
Snap(&Rect); // corrects Rect; no need of <=
Snap(&Rect);
int sx = ConvertX(Rect.x);
int sy = ConvertY(Rect.y);
int w = ConvertX(Rect.w);
int h = ConvertY(Rect.h);
std::shared_ptr<CLayerTele> pLt = std::static_pointer_cast<CLayerTele>(pBrush);
bool Destructive = m_pEditor->m_BrushDrawDestructive || Empty || IsEmpty(pLt);
for(int y = 0; y < h; y++)
{
for(int x = 0; x < w; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
const int TgtIndex = fy * m_Width + fx;
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidTeleTile((pLt->m_pTiles[SrcIndex]).m_Index)))
{
m_pTiles[TgtIndex].m_Index = 0;
m_pTeleTile[TgtIndex].m_Type = 0;
m_pTeleTile[TgtIndex].m_Number = 0;
}
else
{
m_pTiles[TgtIndex] = pLt->m_pTiles[SrcIndex];
if(pLt->m_Tele && m_pTiles[TgtIndex].m_Index > 0)
{
m_pTeleTile[TgtIndex].m_Type = m_pTiles[TgtIndex].m_Index;
if(!IsTeleTileNumberUsed(m_pTeleTile[TgtIndex].m_Type))
{
// Tele tile number is unused. Set a known value which is not 0,
// as tiles with number 0 would be ignored by previous versions.
m_pTeleTile[TgtIndex].m_Number = 255;
}
else if((pLt->m_pTeleTile[SrcIndex].m_Number == 0 && m_pEditor->m_TeleNumber) || m_pEditor->m_TeleNumber != pLt->m_TeleNum)
m_pTeleTile[TgtIndex].m_Number = m_pEditor->m_TeleNumber;
else
m_pTeleTile[TgtIndex].m_Number = pLt->m_pTeleTile[SrcIndex].m_Number;
}
}
}
}
FlagModified(sx, sy, w, h);
}
bool CLayerTele::ContainsElementWithId(int Id)
{
for(int y = 0; y < m_Height; ++y)
{
for(int x = 0; x < m_Width; ++x)
{
if(IsTeleTileNumberUsed(m_pTeleTile[y * m_Width + x].m_Type) && m_pTeleTile[y * m_Width + x].m_Number == Id)
{
return true;
}
}
}
return false;
}

View file

@ -0,0 +1,218 @@
#include <game/editor/editor.h>
CLayerTune::CLayerTune(int w, int h) :
CLayerTiles(w, h)
{
str_copy(m_aName, "Tune");
m_Tune = 1;
m_pTuneTile = new CTuneTile[w * h];
mem_zero(m_pTuneTile, (size_t)w * h * sizeof(CTuneTile));
}
CLayerTune::~CLayerTune()
{
delete[] m_pTuneTile;
}
void CLayerTune::Resize(int NewW, int NewH)
{
// resize Tune data
CTuneTile *pNewTuneData = new CTuneTile[NewW * NewH];
mem_zero(pNewTuneData, (size_t)NewW * NewH * sizeof(CTuneTile));
// copy old data
for(int y = 0; y < minimum(NewH, m_Height); y++)
mem_copy(&pNewTuneData[y * NewW], &m_pTuneTile[y * m_Width], minimum(m_Width, NewW) * sizeof(CTuneTile));
// replace old
delete[] m_pTuneTile;
m_pTuneTile = pNewTuneData;
// resize tile data
CLayerTiles::Resize(NewW, NewH);
// resize gamelayer too
if(m_pEditor->m_Map.m_pGameLayer->m_Width != NewW || m_pEditor->m_Map.m_pGameLayer->m_Height != NewH)
m_pEditor->m_Map.m_pGameLayer->Resize(NewW, NewH);
}
void CLayerTune::Shift(int Direction)
{
CLayerTiles::Shift(Direction);
ShiftImpl(m_pTuneTile, Direction, m_pEditor->m_ShiftBy);
}
bool CLayerTune::IsEmpty(const std::shared_ptr<CLayerTiles> &pLayer)
{
for(int y = 0; y < pLayer->m_Height; y++)
for(int x = 0; x < pLayer->m_Width; x++)
if(m_pEditor->m_AllowPlaceUnusedTiles || IsValidTuneTile(pLayer->GetTile(x, y).m_Index))
return false;
return true;
}
void CLayerTune::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
{
if(m_Readonly)
return;
std::shared_ptr<CLayerTune> pTuneLayer = std::static_pointer_cast<CLayerTune>(pBrush);
int sx = ConvertX(wx);
int sy = ConvertY(wy);
if(str_comp(pTuneLayer->m_aFileName, m_pEditor->m_aFileName))
{
m_pEditor->m_TuningNum = pTuneLayer->m_TuningNumber;
}
bool Destructive = m_pEditor->m_BrushDrawDestructive || IsEmpty(pTuneLayer);
for(int y = 0; y < pTuneLayer->m_Height; y++)
for(int x = 0; x < pTuneLayer->m_Width; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidTuneTile(pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index)) && pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index != TILE_AIR)
{
if(m_pEditor->m_TuningNum != pTuneLayer->m_TuningNumber)
{
m_pTuneTile[fy * m_Width + fx].m_Number = m_pEditor->m_TuningNum;
}
else if(pTuneLayer->m_pTuneTile[y * pTuneLayer->m_Width + x].m_Number)
m_pTuneTile[fy * m_Width + fx].m_Number = pTuneLayer->m_pTuneTile[y * pTuneLayer->m_Width + x].m_Number;
else
{
if(!m_pEditor->m_TuningNum)
{
m_pTuneTile[fy * m_Width + fx].m_Number = 0;
m_pTuneTile[fy * m_Width + fx].m_Type = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
continue;
}
else
m_pTuneTile[fy * m_Width + fx].m_Number = m_pEditor->m_TuningNum;
}
m_pTuneTile[fy * m_Width + fx].m_Type = pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index;
m_pTiles[fy * m_Width + fx].m_Index = pTuneLayer->m_pTiles[y * pTuneLayer->m_Width + x].m_Index;
}
else
{
m_pTuneTile[fy * m_Width + fx].m_Number = 0;
m_pTuneTile[fy * m_Width + fx].m_Type = 0;
m_pTiles[fy * m_Width + fx].m_Index = 0;
}
}
FlagModified(sx, sy, pTuneLayer->m_Width, pTuneLayer->m_Height);
}
void CLayerTune::BrushFlipX()
{
CLayerTiles::BrushFlipX();
BrushFlipXImpl(m_pTuneTile);
}
void CLayerTune::BrushFlipY()
{
CLayerTiles::BrushFlipY();
BrushFlipYImpl(m_pTuneTile);
}
void CLayerTune::BrushRotate(float Amount)
{
int Rotation = (round_to_int(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
CTuneTile *pTempData1 = new CTuneTile[m_Width * m_Height];
CTile *pTempData2 = new CTile[m_Width * m_Height];
mem_copy(pTempData1, m_pTuneTile, (size_t)m_Width * m_Height * sizeof(CTuneTile));
mem_copy(pTempData2, m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
CTuneTile *pDst1 = m_pTuneTile;
CTile *pDst2 = m_pTiles;
for(int x = 0; x < m_Width; ++x)
for(int y = m_Height - 1; y >= 0; --y, ++pDst1, ++pDst2)
{
*pDst1 = pTempData1[y * m_Width + x];
*pDst2 = pTempData2[y * m_Width + x];
}
std::swap(m_Width, m_Height);
delete[] pTempData1;
delete[] pTempData2;
}
if(Rotation == 2 || Rotation == 3)
{
BrushFlipX();
BrushFlipY();
}
}
void CLayerTune::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect)
{
if(m_Readonly || (!Empty && pBrush->m_Type != LAYERTYPE_TILES))
return;
Snap(&Rect); // corrects Rect; no need of <=
int sx = ConvertX(Rect.x);
int sy = ConvertY(Rect.y);
int w = ConvertX(Rect.w);
int h = ConvertY(Rect.h);
std::shared_ptr<CLayerTune> pLt = std::static_pointer_cast<CLayerTune>(pBrush);
bool Destructive = m_pEditor->m_BrushDrawDestructive || Empty || IsEmpty(pLt);
for(int y = 0; y < h; y++)
{
for(int x = 0; x < w; x++)
{
int fx = x + sx;
int fy = y + sy;
if(fx < 0 || fx >= m_Width || fy < 0 || fy >= m_Height)
continue;
if(!Destructive && GetTile(fx, fy).m_Index)
continue;
const int SrcIndex = Empty ? 0 : (y * pLt->m_Width + x % pLt->m_Width) % (pLt->m_Width * pLt->m_Height);
const int TgtIndex = fy * m_Width + fx;
if(Empty || (!m_pEditor->m_AllowPlaceUnusedTiles && !IsValidTuneTile((pLt->m_pTiles[SrcIndex]).m_Index)))
{
m_pTiles[TgtIndex].m_Index = 0;
m_pTuneTile[TgtIndex].m_Type = 0;
m_pTuneTile[TgtIndex].m_Number = 0;
}
else
{
m_pTiles[TgtIndex] = pLt->m_pTiles[SrcIndex];
if(pLt->m_Tune && m_pTiles[TgtIndex].m_Index > 0)
{
m_pTuneTile[TgtIndex].m_Type = m_pTiles[fy * m_Width + fx].m_Index;
if((pLt->m_pTuneTile[SrcIndex].m_Number == 0 && m_pEditor->m_TuningNum) || m_pEditor->m_TuningNum != pLt->m_TuningNumber)
m_pTuneTile[TgtIndex].m_Number = m_pEditor->m_TuningNum;
else
m_pTuneTile[TgtIndex].m_Number = pLt->m_pTuneTile[SrcIndex].m_Number;
}
}
}
}
FlagModified(sx, sy, w, h);
}

View file

@ -0,0 +1,179 @@
#include <game/editor/editor.h>
void CEditorMap::OnModify()
{
m_Modified = true;
m_ModifiedAuto = true;
m_LastModifiedTime = m_pEditor->Client()->GlobalTime();
}
void CEditorMap::DeleteEnvelope(int Index)
{
if(Index < 0 || Index >= (int)m_vpEnvelopes.size())
return;
OnModify();
VisitEnvelopeReferences([Index](int &ElementIndex) {
if(ElementIndex == Index)
ElementIndex = -1;
else if(ElementIndex > Index)
ElementIndex--;
});
m_vpEnvelopes.erase(m_vpEnvelopes.begin() + Index);
}
void CEditorMap::SwapEnvelopes(int Index0, int Index1)
{
if(Index0 < 0 || Index0 >= (int)m_vpEnvelopes.size())
return;
if(Index1 < 0 || Index1 >= (int)m_vpEnvelopes.size())
return;
if(Index0 == Index1)
return;
OnModify();
VisitEnvelopeReferences([Index0, Index1](int &ElementIndex) {
if(ElementIndex == Index0)
ElementIndex = Index1;
else if(ElementIndex == Index1)
ElementIndex = Index0;
});
std::swap(m_vpEnvelopes[Index0], m_vpEnvelopes[Index1]);
}
template<typename F>
void CEditorMap::VisitEnvelopeReferences(F &&Visitor)
{
for(auto &pGroup : m_vpGroups)
{
for(auto &pLayer : pGroup->m_vpLayers)
{
if(pLayer->m_Type == LAYERTYPE_QUADS)
{
std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(pLayer);
for(auto &Quad : pLayerQuads->m_vQuads)
{
Visitor(Quad.m_PosEnv);
Visitor(Quad.m_ColorEnv);
}
}
else if(pLayer->m_Type == LAYERTYPE_TILES)
{
std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
Visitor(pLayerTiles->m_ColorEnv);
}
else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(pLayer);
for(auto &Source : pLayerSounds->m_vSources)
{
Visitor(Source.m_PosEnv);
Visitor(Source.m_SoundEnv);
}
}
}
}
}
void CEditorMap::MakeGameLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pGameLayer = std::static_pointer_cast<CLayerGame>(pLayer);
m_pGameLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeGameGroup(std::shared_ptr<CLayerGroup> pGroup)
{
m_pGameGroup = std::move(pGroup);
m_pGameGroup->m_GameGroup = true;
str_copy(m_pGameGroup->m_aName, "Game");
}
void CEditorMap::Clean()
{
m_vpGroups.clear();
m_vpEnvelopes.clear();
m_vpImages.clear();
m_vpSounds.clear();
m_MapInfo.Reset();
m_MapInfoTmp.Reset();
m_vSettings.clear();
m_pGameLayer = nullptr;
m_pGameGroup = nullptr;
m_Modified = false;
m_ModifiedAuto = false;
m_pTeleLayer = nullptr;
m_pSpeedupLayer = nullptr;
m_pFrontLayer = nullptr;
m_pSwitchLayer = nullptr;
m_pTuneLayer = nullptr;
}
void CEditorMap::CreateDefault(IGraphics::CTextureHandle EntitiesTexture)
{
// add background
std::shared_ptr<CLayerGroup> pGroup = NewGroup();
pGroup->m_ParallaxX = 0;
pGroup->m_ParallaxY = 0;
pGroup->m_CustomParallaxZoom = 0;
pGroup->m_ParallaxZoom = 0;
std::shared_ptr<CLayerQuads> pLayer = std::make_shared<CLayerQuads>();
pLayer->m_pEditor = m_pEditor;
CQuad *pQuad = pLayer->NewQuad(0, 0, 1600, 1200);
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;
pQuad->m_aColors[2].r = pQuad->m_aColors[3].r = 204;
pQuad->m_aColors[2].g = pQuad->m_aColors[3].g = 232;
pQuad->m_aColors[2].b = pQuad->m_aColors[3].b = 255;
pGroup->AddLayer(pLayer);
// add game layer and reset front, tele, speedup, tune and switch layer pointers
MakeGameGroup(NewGroup());
MakeGameLayer(std::make_shared<CLayerGame>(50, 50));
m_pGameGroup->AddLayer(m_pGameLayer);
m_pFrontLayer = nullptr;
m_pTeleLayer = nullptr;
m_pSpeedupLayer = nullptr;
m_pSwitchLayer = nullptr;
m_pTuneLayer = nullptr;
}
void CEditorMap::MakeTeleLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pTeleLayer = std::static_pointer_cast<CLayerTele>(pLayer);
m_pTeleLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeSpeedupLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pSpeedupLayer = std::static_pointer_cast<CLayerSpeedup>(pLayer);
m_pSpeedupLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeFrontLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pFrontLayer = std::static_pointer_cast<CLayerFront>(pLayer);
m_pFrontLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeSwitchLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pSwitchLayer = std::static_pointer_cast<CLayerSwitch>(pLayer);
m_pSwitchLayer->m_pEditor = m_pEditor;
}
void CEditorMap::MakeTuneLayer(const std::shared_ptr<CLayer> &pLayer)
{
m_pTuneLayer = std::static_pointer_cast<CLayerTune>(pLayer);
m_pTuneLayer->m_pEditor = m_pEditor;
}

View file

@ -0,0 +1,10 @@
#include <game/editor/editor.h>
#include <engine/sound.h>
CEditorSound::~CEditorSound()
{
m_pEditor->Sound()->UnloadSample(m_SoundID);
free(m_pData);
m_pData = nullptr;
}