/
dieoska
/
ddnet
Обзор
Документация
Войти
/
dieoska
/
ddnet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/game/editor/mapitems/layer_tune.cpp
380 строк
9 KB
Robert Müller
Move editor shift-by property to map
13 дек 2025, 13:21
13 дек 2025, 13:21
bfdd661
Код
Авторство
О чём код?
#include "layer_tune.h" #include <game/editor/editor.h> CLayerTune::CLayerTune(CEditorMap *pMap, int w, int h) : CLayerTiles(pMap, w, h) { str_copy(m_aName, "Tune"); m_HasTune = true; m_pTuneTile = new CTuneTile[w * h]; mem_zero(m_pTuneTile, (size_t)w * h * sizeof(CTuneTile)); m_GotoTuneOffset = 0; m_GotoTuneLastPos = ivec2(-1, -1); } CLayerTune::CLayerTune(const CLayerTune &Other) : CLayerTiles(Other) { str_copy(m_aName, "Tune copy"); m_HasTune = true; m_pTuneTile = new CTuneTile[m_Width * m_Height]; mem_copy(m_pTuneTile, Other.m_pTuneTile, (size_t)m_Width * m_Height * 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(Map()->m_pGameLayer->m_Width != NewW || Map()->m_pGameLayer->m_Height != NewH) Map()->m_pGameLayer->Resize(NewW, NewH); } void CLayerTune::Shift(EShiftDirection Direction) { CLayerTiles::Shift(Direction); ShiftImpl(m_pTuneTile, Direction, Map()->m_ShiftBy); } bool CLayerTune::IsEmpty() const { for(int y = 0; y < m_Height; y++) { for(int x = 0; x < m_Width; x++) { const int Index = GetTile(x, y).m_Index; if(Index == 0) { continue; } if(Editor()->IsAllowPlaceUnusedTiles() || IsValidTuneTile(Index)) { return false; } } } return true; } void CLayerTune::BrushDraw(CLayer *pBrush, vec2 WorldPos) { if(m_Readonly) return; CLayerTune *pTuneLayer = static_cast<CLayerTune *>(pBrush); int sx = ConvertX(WorldPos.x); int sy = ConvertY(WorldPos.y); if(str_comp(pTuneLayer->m_aFilename, pTuneLayer->Map()->m_aFilename)) { Editor()->m_TuningNumber = pTuneLayer->m_TuningNumber; } bool Destructive = Editor()->m_BrushDrawDestructive || pTuneLayer->IsEmpty(); 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; const int SrcIndex = y * pTuneLayer->m_Width + x; const int TgtIndex = fy * m_Width + fx; STuneTileStateChange::SData Previous{ m_pTuneTile[TgtIndex].m_Number, m_pTuneTile[TgtIndex].m_Type, m_pTiles[TgtIndex].m_Index}; if((Editor()->IsAllowPlaceUnusedTiles() || IsValidTuneTile(pTuneLayer->m_pTiles[SrcIndex].m_Index)) && pTuneLayer->m_pTiles[SrcIndex].m_Index != TILE_AIR) { if(Editor()->m_TuningNumber != pTuneLayer->m_TuningNumber) { m_pTuneTile[TgtIndex].m_Number = Editor()->m_TuningNumber; } else if(pTuneLayer->m_pTuneTile[SrcIndex].m_Number) m_pTuneTile[TgtIndex].m_Number = pTuneLayer->m_pTuneTile[SrcIndex].m_Number; else { if(!Editor()->m_TuningNumber) { m_pTuneTile[TgtIndex].m_Number = 0; m_pTuneTile[TgtIndex].m_Type = 0; m_pTiles[TgtIndex].m_Index = 0; continue; } else m_pTuneTile[TgtIndex].m_Number = Editor()->m_TuningNumber; } m_pTuneTile[TgtIndex].m_Type = pTuneLayer->m_pTiles[SrcIndex].m_Index; m_pTiles[TgtIndex].m_Index = pTuneLayer->m_pTiles[SrcIndex].m_Index; } else { m_pTuneTile[TgtIndex].m_Number = 0; m_pTuneTile[TgtIndex].m_Type = 0; m_pTiles[TgtIndex].m_Index = 0; if(pTuneLayer->m_pTiles[SrcIndex].m_Index != TILE_AIR) ShowPreventUnusedTilesWarning(); } STuneTileStateChange::SData Current{ m_pTuneTile[TgtIndex].m_Number, m_pTuneTile[TgtIndex].m_Type, m_pTiles[TgtIndex].m_Index}; RecordStateChange(fx, fy, Previous, Current); } FlagModified(sx, sy, pTuneLayer->m_Width, pTuneLayer->m_Height); } void CLayerTune::RecordStateChange(int x, int y, STuneTileStateChange::SData Previous, STuneTileStateChange::SData Current) { if(!m_History[y][x].m_Changed) m_History[y][x] = STuneTileStateChange{true, Previous, Current}; else m_History[y][x].m_Current = Current; } 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, CLayer *pBrush, CUIRect Rect) { if(m_Readonly || (!Empty && pBrush->m_Type != LAYERTYPE_TILES)) return; Snap(&Rect); int sx = ConvertX(Rect.x); int sy = ConvertY(Rect.y); int w = ConvertX(Rect.w); int h = ConvertY(Rect.h); CLayerTune *pLt = static_cast<CLayerTune *>(pBrush); bool Destructive = Editor()->m_BrushDrawDestructive || Empty || pLt->IsEmpty(); 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; STuneTileStateChange::SData Previous{ m_pTuneTile[TgtIndex].m_Number, m_pTuneTile[TgtIndex].m_Type, m_pTiles[TgtIndex].m_Index}; if(Empty || (!Editor()->IsAllowPlaceUnusedTiles() && !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; if(!Empty) ShowPreventUnusedTilesWarning(); } else { m_pTiles[TgtIndex] = pLt->m_pTiles[SrcIndex]; if(pLt->m_HasTune && 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 && Editor()->m_TuningNumber) || Editor()->m_TuningNumber != pLt->m_TuningNumber) m_pTuneTile[TgtIndex].m_Number = Editor()->m_TuningNumber; else m_pTuneTile[TgtIndex].m_Number = pLt->m_pTuneTile[SrcIndex].m_Number; } else { m_pTiles[TgtIndex].m_Index = 0; m_pTuneTile[TgtIndex].m_Type = 0; m_pTuneTile[TgtIndex].m_Number = 0; } } STuneTileStateChange::SData Current{ m_pTuneTile[TgtIndex].m_Number, m_pTuneTile[TgtIndex].m_Type, m_pTiles[TgtIndex].m_Index}; RecordStateChange(fx, fy, Previous, Current); } } FlagModified(sx, sy, w, h); } int CLayerTune::FindNextFreeNumber() const { for(int i = 1; i <= 255; i++) { if(!ContainsElementWithId(i)) { return i; } } return -1; } bool CLayerTune::ContainsElementWithId(int Id) const { for(int y = 0; y < m_Height; ++y) { for(int x = 0; x < m_Width; ++x) { if(IsValidTuneTile(m_pTuneTile[y * m_Width + x].m_Type) && m_pTuneTile[y * m_Width + x].m_Number == Id) { return true; } } } return false; } void CLayerTune::GetPos(int Number, int Offset, ivec2 &Pos) { int Match = -1; ivec2 MatchPos = ivec2(-1, -1); Pos = ivec2(-1, -1); auto FindTile = [this, &Match, &MatchPos, &Number, &Offset]() { for(int x = 0; x < m_Width; x++) { for(int y = 0; y < m_Height; y++) { int i = y * m_Width + x; int Tune = m_pTuneTile[i].m_Number; if(Number == Tune) { Match++; if(Offset != -1) { if(Match == Offset) { MatchPos = ivec2(x, y); m_GotoTuneOffset = Match; return; } continue; } MatchPos = ivec2(x, y); if(m_GotoTuneLastPos != ivec2(-1, -1)) { if(distance(m_GotoTuneLastPos, MatchPos) < 10.0f) { m_GotoTuneOffset++; continue; } } m_GotoTuneLastPos = MatchPos; if(Match == m_GotoTuneOffset) return; } } } }; FindTile(); if(MatchPos == ivec2(-1, -1)) return; if(Match < m_GotoTuneOffset) m_GotoTuneOffset = -1; Pos = MatchPos; m_GotoTuneOffset++; } std::shared_ptr<CLayer> CLayerTune::Duplicate() const { return std::make_shared<CLayerTune>(*this); } const char *CLayerTune::TypeName() const { return "tune"; }