mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-09 09:38:19 +00:00
Add quick actions for game tiles
This commit is contained in:
parent
36f0bcc509
commit
e1cb617c42
|
@ -2462,6 +2462,7 @@ if(CLIENT)
|
||||||
editor_trackers.cpp
|
editor_trackers.cpp
|
||||||
editor_trackers.h
|
editor_trackers.h
|
||||||
editor_ui.h
|
editor_ui.h
|
||||||
|
enums.h
|
||||||
explanations.cpp
|
explanations.cpp
|
||||||
layer_selector.cpp
|
layer_selector.cpp
|
||||||
layer_selector.h
|
layer_selector.h
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <game/client/ui_listbox.h>
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/mapitems.h>
|
#include <game/mapitems.h>
|
||||||
|
|
||||||
|
#include <game/editor/enums.h>
|
||||||
#include <game/editor/mapitems/envelope.h>
|
#include <game/editor/mapitems/envelope.h>
|
||||||
#include <game/editor/mapitems/layer.h>
|
#include <game/editor/mapitems/layer.h>
|
||||||
#include <game/editor/mapitems/layer_front.h>
|
#include <game/editor/mapitems/layer_front.h>
|
||||||
|
@ -323,6 +324,8 @@ public:
|
||||||
const CMapView *MapView() const { return &m_MapView; }
|
const CMapView *MapView() const { return &m_MapView; }
|
||||||
CLayerSelector *LayerSelector() { return &m_LayerSelector; }
|
CLayerSelector *LayerSelector() { return &m_LayerSelector; }
|
||||||
|
|
||||||
|
void FillGameTiles(EGameTileOp FillTile) const;
|
||||||
|
bool CanFillGameTiles() const;
|
||||||
void AddGroup();
|
void AddGroup();
|
||||||
void AddTileLayer();
|
void AddTileLayer();
|
||||||
void LayerSelectImage();
|
void LayerSelectImage();
|
||||||
|
|
36
src/game/editor/enums.h
Normal file
36
src/game/editor/enums.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef GAME_EDITOR_ENUMS_H
|
||||||
|
#define GAME_EDITOR_ENUMS_H
|
||||||
|
|
||||||
|
constexpr const char *g_apGametileOpNames[] = {
|
||||||
|
"Air",
|
||||||
|
"Hookable",
|
||||||
|
"Death",
|
||||||
|
"Unhookable",
|
||||||
|
"Hookthrough",
|
||||||
|
"Freeze",
|
||||||
|
"Unfreeze",
|
||||||
|
"Deep Freeze",
|
||||||
|
"Deep Unfreeze",
|
||||||
|
"Blue Check-Tele",
|
||||||
|
"Red Check-Tele",
|
||||||
|
"Live Freeze",
|
||||||
|
"Live Unfreeze",
|
||||||
|
};
|
||||||
|
enum class EGameTileOp
|
||||||
|
{
|
||||||
|
AIR,
|
||||||
|
HOOKABLE,
|
||||||
|
DEATH,
|
||||||
|
UNHOOKABLE,
|
||||||
|
HOOKTHROUGH,
|
||||||
|
FREEZE,
|
||||||
|
UNFREEZE,
|
||||||
|
DEEP_FREEZE,
|
||||||
|
DEEP_UNFREEZE,
|
||||||
|
BLUE_CHECK_TELE,
|
||||||
|
RED_CHECK_TELE,
|
||||||
|
LIVE_FREEZE,
|
||||||
|
LIVE_UNFREEZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@
|
||||||
#include <engine/shared/map.h>
|
#include <engine/shared/map.h>
|
||||||
#include <game/editor/editor.h>
|
#include <game/editor/editor.h>
|
||||||
#include <game/editor/editor_actions.h>
|
#include <game/editor/editor_actions.h>
|
||||||
|
#include <game/editor/enums.h>
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
@ -693,93 +694,126 @@ void CLayerTiles::ShowInfo()
|
||||||
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
void CLayerTiles::FillGameTiles(EGameTileOp Fill)
|
||||||
{
|
{
|
||||||
CUIRect Button;
|
if(!CanFillGameTiles())
|
||||||
|
return;
|
||||||
const bool EntitiesLayer = IsEntitiesLayer();
|
|
||||||
|
|
||||||
std::shared_ptr<CLayerGroup> pGroup = m_pEditor->m_Map.m_vpGroups[m_pEditor->m_SelectedGroup];
|
std::shared_ptr<CLayerGroup> pGroup = m_pEditor->m_Map.m_vpGroups[m_pEditor->m_SelectedGroup];
|
||||||
|
|
||||||
// Game tiles can only be constructed if the layer is relative to the game layer
|
int Result = (int)Fill;
|
||||||
if(!EntitiesLayer && !(pGroup->m_OffsetX % 32) && !(pGroup->m_OffsetY % 32) && pGroup->m_ParallaxX == 100 && pGroup->m_ParallaxY == 100)
|
switch(Fill)
|
||||||
{
|
{
|
||||||
pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
|
case EGameTileOp::HOOKTHROUGH:
|
||||||
static int s_GameTilesButton = 0;
|
Result = TILE_THROUGH_CUT;
|
||||||
if(m_pEditor->DoButton_Editor(&s_GameTilesButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer"))
|
break;
|
||||||
m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->Ui()->MouseX(), m_pEditor->Ui()->MouseY());
|
case EGameTileOp::FREEZE:
|
||||||
const int Selected = m_pEditor->PopupSelectGameTileOpResult();
|
Result = TILE_FREEZE;
|
||||||
int Result = Selected;
|
break;
|
||||||
switch(Selected)
|
case EGameTileOp::UNFREEZE:
|
||||||
|
Result = TILE_UNFREEZE;
|
||||||
|
break;
|
||||||
|
case EGameTileOp::DEEP_FREEZE:
|
||||||
|
Result = TILE_DFREEZE;
|
||||||
|
break;
|
||||||
|
case EGameTileOp::DEEP_UNFREEZE:
|
||||||
|
Result = TILE_DUNFREEZE;
|
||||||
|
break;
|
||||||
|
case EGameTileOp::BLUE_CHECK_TELE:
|
||||||
|
Result = TILE_TELECHECKIN;
|
||||||
|
break;
|
||||||
|
case EGameTileOp::RED_CHECK_TELE:
|
||||||
|
Result = TILE_TELECHECKINEVIL;
|
||||||
|
break;
|
||||||
|
case EGameTileOp::LIVE_FREEZE:
|
||||||
|
Result = TILE_LFREEZE;
|
||||||
|
break;
|
||||||
|
case EGameTileOp::LIVE_UNFREEZE:
|
||||||
|
Result = TILE_LUNFREEZE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(Result > -1)
|
||||||
|
{
|
||||||
|
const int OffsetX = -pGroup->m_OffsetX / 32;
|
||||||
|
const int OffsetY = -pGroup->m_OffsetY / 32;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
||||||
|
std::shared_ptr<CLayerTiles> pGLayer = m_pEditor->m_Map.m_pGameLayer;
|
||||||
|
int GameLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pGLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin();
|
||||||
|
|
||||||
|
if(Result != TILE_TELECHECKIN && Result != TILE_TELECHECKINEVIL)
|
||||||
{
|
{
|
||||||
case 4:
|
if(pGLayer->m_Width < m_Width + OffsetX || pGLayer->m_Height < m_Height + OffsetY)
|
||||||
Result = TILE_THROUGH_CUT;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
Result = TILE_FREEZE;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
Result = TILE_UNFREEZE;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
Result = TILE_DFREEZE;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
Result = TILE_DUNFREEZE;
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
Result = TILE_TELECHECKIN;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
Result = TILE_TELECHECKINEVIL;
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
Result = TILE_LFREEZE;
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
Result = TILE_LUNFREEZE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(Result > -1)
|
|
||||||
{
|
|
||||||
const int OffsetX = -pGroup->m_OffsetX / 32;
|
|
||||||
const int OffsetY = -pGroup->m_OffsetY / 32;
|
|
||||||
|
|
||||||
static const char *s_apGametileOpNames[] = {
|
|
||||||
"Air",
|
|
||||||
"Hookable",
|
|
||||||
"Death",
|
|
||||||
"Unhookable",
|
|
||||||
"Hookthrough",
|
|
||||||
"Freeze",
|
|
||||||
"Unfreeze",
|
|
||||||
"Deep Freeze",
|
|
||||||
"Deep Unfreeze",
|
|
||||||
"Blue Check-Tele",
|
|
||||||
"Red Check-Tele",
|
|
||||||
"Live Freeze",
|
|
||||||
"Live Unfreeze",
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<IEditorAction>> vpActions;
|
|
||||||
std::shared_ptr<CLayerTiles> pGLayer = m_pEditor->m_Map.m_pGameLayer;
|
|
||||||
int GameLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pGLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin();
|
|
||||||
|
|
||||||
if(Result != TILE_TELECHECKIN && Result != TILE_TELECHECKINEVIL)
|
|
||||||
{
|
{
|
||||||
if(pGLayer->m_Width < m_Width + OffsetX || pGLayer->m_Height < m_Height + OffsetY)
|
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||||
|
savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate();
|
||||||
|
savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES];
|
||||||
|
|
||||||
|
int PrevW = pGLayer->m_Width;
|
||||||
|
int PrevH = pGLayer->m_Height;
|
||||||
|
const int NewW = pGLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pGLayer->m_Width;
|
||||||
|
const int NewH = pGLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pGLayer->m_Height;
|
||||||
|
pGLayer->Resize(NewW, NewH);
|
||||||
|
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
||||||
|
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action1 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||||
|
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
||||||
|
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action2 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||||
|
|
||||||
|
Action1->SetSavedLayers(savedLayers);
|
||||||
|
Action2->SetSavedLayers(savedLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Changes = 0;
|
||||||
|
for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++)
|
||||||
|
{
|
||||||
|
for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++)
|
||||||
|
{
|
||||||
|
if(GetTile(x, y).m_Index)
|
||||||
|
{
|
||||||
|
const CTile ResultTile = {(unsigned char)Result};
|
||||||
|
pGLayer->SetTile(x + OffsetX, y + OffsetY, ResultTile);
|
||||||
|
Changes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vpActions.push_back(std::make_shared<CEditorBrushDrawAction>(m_pEditor, m_pEditor->m_SelectedGroup));
|
||||||
|
char aDisplay[256];
|
||||||
|
str_format(aDisplay, sizeof(aDisplay), "Construct '%s' game tiles (x%d)", g_apGametileOpNames[(int)Fill], Changes);
|
||||||
|
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay, true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!m_pEditor->m_Map.m_pTeleLayer)
|
||||||
|
{
|
||||||
|
std::shared_ptr<CLayerTele> pLayer = std::make_shared<CLayerTele>(m_pEditor, m_Width, m_Height);
|
||||||
|
m_pEditor->m_Map.MakeTeleLayer(pLayer);
|
||||||
|
m_pEditor->m_Map.m_pGameGroup->AddLayer(pLayer);
|
||||||
|
|
||||||
|
vpActions.push_back(std::make_shared<CEditorActionAddLayer>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_Map.m_pGameGroup->m_vpLayers.size() - 1));
|
||||||
|
|
||||||
|
if(m_Width != pGLayer->m_Width || m_Height > pGLayer->m_Height)
|
||||||
{
|
{
|
||||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||||
savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate();
|
savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate();
|
||||||
savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES];
|
savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES];
|
||||||
|
|
||||||
|
int NewW = pGLayer->m_Width;
|
||||||
|
int NewH = pGLayer->m_Height;
|
||||||
|
if(m_Width > pGLayer->m_Width)
|
||||||
|
{
|
||||||
|
NewW = m_Width;
|
||||||
|
}
|
||||||
|
if(m_Height > pGLayer->m_Height)
|
||||||
|
{
|
||||||
|
NewH = m_Height;
|
||||||
|
}
|
||||||
|
|
||||||
int PrevW = pGLayer->m_Width;
|
int PrevW = pGLayer->m_Width;
|
||||||
int PrevH = pGLayer->m_Height;
|
int PrevH = pGLayer->m_Height;
|
||||||
const int NewW = pGLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pGLayer->m_Width;
|
pLayer->Resize(NewW, NewH);
|
||||||
const int NewH = pGLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pGLayer->m_Height;
|
|
||||||
pGLayer->Resize(NewW, NewH);
|
|
||||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
||||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action1 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action1 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
||||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
||||||
|
@ -788,124 +822,94 @@ CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
||||||
Action1->SetSavedLayers(savedLayers);
|
Action1->SetSavedLayers(savedLayers);
|
||||||
Action2->SetSavedLayers(savedLayers);
|
Action2->SetSavedLayers(savedLayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Changes = 0;
|
|
||||||
for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++)
|
|
||||||
{
|
|
||||||
for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++)
|
|
||||||
{
|
|
||||||
if(GetTile(x, y).m_Index)
|
|
||||||
{
|
|
||||||
const CTile ResultTile = {(unsigned char)Result};
|
|
||||||
pGLayer->SetTile(x + OffsetX, y + OffsetY, ResultTile);
|
|
||||||
Changes++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vpActions.push_back(std::make_shared<CEditorBrushDrawAction>(m_pEditor, m_pEditor->m_SelectedGroup));
|
|
||||||
char aDisplay[256];
|
|
||||||
str_format(aDisplay, sizeof(aDisplay), "Construct '%s' game tiles (x%d)", s_apGametileOpNames[Selected], Changes);
|
|
||||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay, true));
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
std::shared_ptr<CLayerTele> pTLayer = m_pEditor->m_Map.m_pTeleLayer;
|
||||||
|
int TeleLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pTLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin();
|
||||||
|
|
||||||
|
if(pTLayer->m_Width < m_Width + OffsetX || pTLayer->m_Height < m_Height + OffsetY)
|
||||||
{
|
{
|
||||||
if(!m_pEditor->m_Map.m_pTeleLayer)
|
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||||
{
|
savedLayers[LAYERTYPE_TILES] = pTLayer->Duplicate();
|
||||||
std::shared_ptr<CLayerTele> pLayer = std::make_shared<CLayerTele>(m_pEditor, m_Width, m_Height);
|
savedLayers[LAYERTYPE_TELE] = savedLayers[LAYERTYPE_TILES];
|
||||||
m_pEditor->m_Map.MakeTeleLayer(pLayer);
|
|
||||||
m_pEditor->m_Map.m_pGameGroup->AddLayer(pLayer);
|
|
||||||
|
|
||||||
vpActions.push_back(std::make_shared<CEditorActionAddLayer>(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_Map.m_pGameGroup->m_vpLayers.size() - 1));
|
int PrevW = pTLayer->m_Width;
|
||||||
|
int PrevH = pTLayer->m_Height;
|
||||||
|
int NewW = pTLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pTLayer->m_Width;
|
||||||
|
int NewH = pTLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pTLayer->m_Height;
|
||||||
|
pTLayer->Resize(NewW, NewH);
|
||||||
|
std::shared_ptr<CEditorActionEditLayerTilesProp> Action1, Action2;
|
||||||
|
vpActions.push_back(Action1 = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
||||||
|
vpActions.push_back(Action2 = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
||||||
|
|
||||||
if(m_Width != pGLayer->m_Width || m_Height > pGLayer->m_Height)
|
Action1->SetSavedLayers(savedLayers);
|
||||||
{
|
Action2->SetSavedLayers(savedLayers);
|
||||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
|
||||||
savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate();
|
|
||||||
savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES];
|
|
||||||
|
|
||||||
int NewW = pGLayer->m_Width;
|
|
||||||
int NewH = pGLayer->m_Height;
|
|
||||||
if(m_Width > pGLayer->m_Width)
|
|
||||||
{
|
|
||||||
NewW = m_Width;
|
|
||||||
}
|
|
||||||
if(m_Height > pGLayer->m_Height)
|
|
||||||
{
|
|
||||||
NewH = m_Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PrevW = pGLayer->m_Width;
|
|
||||||
int PrevH = pGLayer->m_Height;
|
|
||||||
pLayer->Resize(NewW, NewH);
|
|
||||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
|
||||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action1 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
|
||||||
vpActions.push_back(std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
|
||||||
const std::shared_ptr<CEditorActionEditLayerTilesProp> &Action2 = std::static_pointer_cast<CEditorActionEditLayerTilesProp>(vpActions[vpActions.size() - 1]);
|
|
||||||
|
|
||||||
Action1->SetSavedLayers(savedLayers);
|
|
||||||
Action2->SetSavedLayers(savedLayers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<CLayerTele> pTLayer = m_pEditor->m_Map.m_pTeleLayer;
|
|
||||||
int TeleLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pTLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin();
|
|
||||||
|
|
||||||
if(pTLayer->m_Width < m_Width + OffsetX || pTLayer->m_Height < m_Height + OffsetY)
|
|
||||||
{
|
|
||||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
|
||||||
savedLayers[LAYERTYPE_TILES] = pTLayer->Duplicate();
|
|
||||||
savedLayers[LAYERTYPE_TELE] = savedLayers[LAYERTYPE_TILES];
|
|
||||||
|
|
||||||
int PrevW = pTLayer->m_Width;
|
|
||||||
int PrevH = pTLayer->m_Height;
|
|
||||||
int NewW = pTLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pTLayer->m_Width;
|
|
||||||
int NewH = pTLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pTLayer->m_Height;
|
|
||||||
pTLayer->Resize(NewW, NewH);
|
|
||||||
std::shared_ptr<CEditorActionEditLayerTilesProp> Action1, Action2;
|
|
||||||
vpActions.push_back(Action1 = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW));
|
|
||||||
vpActions.push_back(Action2 = std::make_shared<CEditorActionEditLayerTilesProp>(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH));
|
|
||||||
|
|
||||||
Action1->SetSavedLayers(savedLayers);
|
|
||||||
Action2->SetSavedLayers(savedLayers);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Changes = 0;
|
|
||||||
for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++)
|
|
||||||
{
|
|
||||||
for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++)
|
|
||||||
{
|
|
||||||
if(GetTile(x, y).m_Index)
|
|
||||||
{
|
|
||||||
auto TileIndex = (y + OffsetY) * pTLayer->m_Width + x + OffsetX;
|
|
||||||
Changes++;
|
|
||||||
|
|
||||||
STeleTileStateChange::SData Previous{
|
|
||||||
pTLayer->m_pTeleTile[TileIndex].m_Number,
|
|
||||||
pTLayer->m_pTeleTile[TileIndex].m_Type,
|
|
||||||
pTLayer->m_pTiles[TileIndex].m_Index};
|
|
||||||
|
|
||||||
pTLayer->m_pTiles[TileIndex].m_Index = TILE_AIR + Result;
|
|
||||||
pTLayer->m_pTeleTile[TileIndex].m_Number = 1;
|
|
||||||
pTLayer->m_pTeleTile[TileIndex].m_Type = TILE_AIR + Result;
|
|
||||||
|
|
||||||
STeleTileStateChange::SData Current{
|
|
||||||
pTLayer->m_pTeleTile[TileIndex].m_Number,
|
|
||||||
pTLayer->m_pTeleTile[TileIndex].m_Type,
|
|
||||||
pTLayer->m_pTiles[TileIndex].m_Index};
|
|
||||||
|
|
||||||
pTLayer->RecordStateChange(x, y, Previous, Current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vpActions.push_back(std::make_shared<CEditorBrushDrawAction>(m_pEditor, m_pEditor->m_SelectedGroup));
|
|
||||||
char aDisplay[256];
|
|
||||||
str_format(aDisplay, sizeof(aDisplay), "Construct 'tele' game tiles (x%d)", Changes);
|
|
||||||
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Changes = 0;
|
||||||
|
for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++)
|
||||||
|
{
|
||||||
|
for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++)
|
||||||
|
{
|
||||||
|
if(GetTile(x, y).m_Index)
|
||||||
|
{
|
||||||
|
auto TileIndex = (y + OffsetY) * pTLayer->m_Width + x + OffsetX;
|
||||||
|
Changes++;
|
||||||
|
|
||||||
|
STeleTileStateChange::SData Previous{
|
||||||
|
pTLayer->m_pTeleTile[TileIndex].m_Number,
|
||||||
|
pTLayer->m_pTeleTile[TileIndex].m_Type,
|
||||||
|
pTLayer->m_pTiles[TileIndex].m_Index};
|
||||||
|
|
||||||
|
pTLayer->m_pTiles[TileIndex].m_Index = TILE_AIR + Result;
|
||||||
|
pTLayer->m_pTeleTile[TileIndex].m_Number = 1;
|
||||||
|
pTLayer->m_pTeleTile[TileIndex].m_Type = TILE_AIR + Result;
|
||||||
|
|
||||||
|
STeleTileStateChange::SData Current{
|
||||||
|
pTLayer->m_pTeleTile[TileIndex].m_Number,
|
||||||
|
pTLayer->m_pTeleTile[TileIndex].m_Type,
|
||||||
|
pTLayer->m_pTiles[TileIndex].m_Index};
|
||||||
|
|
||||||
|
pTLayer->RecordStateChange(x, y, Previous, Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vpActions.push_back(std::make_shared<CEditorBrushDrawAction>(m_pEditor, m_pEditor->m_SelectedGroup));
|
||||||
|
char aDisplay[256];
|
||||||
|
str_format(aDisplay, sizeof(aDisplay), "Construct 'tele' game tiles (x%d)", Changes);
|
||||||
|
m_pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionBulk>(m_pEditor, vpActions, aDisplay, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CLayerTiles::CanFillGameTiles() const
|
||||||
|
{
|
||||||
|
const bool EntitiesLayer = IsEntitiesLayer();
|
||||||
|
if(EntitiesLayer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::shared_ptr<CLayerGroup> pGroup = m_pEditor->m_Map.m_vpGroups[m_pEditor->m_SelectedGroup];
|
||||||
|
|
||||||
|
// Game tiles can only be constructed if the layer is relative to the game layer
|
||||||
|
return !(pGroup->m_OffsetX % 32) && !(pGroup->m_OffsetY % 32) && pGroup->m_ParallaxX == 100 && pGroup->m_ParallaxY == 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
||||||
|
{
|
||||||
|
CUIRect Button;
|
||||||
|
|
||||||
|
const bool EntitiesLayer = IsEntitiesLayer();
|
||||||
|
|
||||||
|
if(CanFillGameTiles())
|
||||||
|
{
|
||||||
|
pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
|
||||||
|
static int s_GameTilesButton = 0;
|
||||||
|
if(m_pEditor->DoButton_Editor(&s_GameTilesButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer"))
|
||||||
|
m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->Ui()->MouseX(), m_pEditor->Ui()->MouseY());
|
||||||
|
const int Selected = m_pEditor->PopupSelectGameTileOpResult();
|
||||||
|
FillGameTiles((EGameTileOp)Selected);
|
||||||
|
}
|
||||||
|
|
||||||
if(m_pEditor->m_Map.m_pGameLayer.get() != this)
|
if(m_pEditor->m_Map.m_pGameLayer.get() != this)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define GAME_EDITOR_MAPITEMS_LAYER_TILES_H
|
#define GAME_EDITOR_MAPITEMS_LAYER_TILES_H
|
||||||
|
|
||||||
#include <game/editor/editor_trackers.h>
|
#include <game/editor/editor_trackers.h>
|
||||||
|
#include <game/editor/enums.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "layer.h"
|
#include "layer.h"
|
||||||
|
@ -122,6 +123,8 @@ public:
|
||||||
void BrushSelecting(CUIRect Rect) override;
|
void BrushSelecting(CUIRect Rect) override;
|
||||||
int BrushGrab(std::shared_ptr<CLayerGroup> pBrush, CUIRect Rect) override;
|
int BrushGrab(std::shared_ptr<CLayerGroup> pBrush, CUIRect Rect) override;
|
||||||
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
|
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
|
||||||
|
void FillGameTiles(EGameTileOp Fill);
|
||||||
|
bool CanFillGameTiles() const;
|
||||||
void BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy) override;
|
void BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy) override;
|
||||||
void BrushFlipX() override;
|
void BrushFlipX() override;
|
||||||
void BrushFlipY() override;
|
void BrushFlipY() override;
|
||||||
|
|
|
@ -4,12 +4,28 @@
|
||||||
|
|
||||||
#include "editor_actions.h"
|
#include "editor_actions.h"
|
||||||
|
|
||||||
|
void CEditor::FillGameTiles(EGameTileOp FillTile) const
|
||||||
|
{
|
||||||
|
std::shared_ptr<CLayerTiles> pTileLayer = std::static_pointer_cast<CLayerTiles>(GetSelectedLayerType(0, LAYERTYPE_TILES));
|
||||||
|
if(pTileLayer)
|
||||||
|
pTileLayer->FillGameTiles(FillTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CEditor::CanFillGameTiles() const
|
||||||
|
{
|
||||||
|
std::shared_ptr<CLayerTiles> pTileLayer = std::static_pointer_cast<CLayerTiles>(GetSelectedLayerType(0, LAYERTYPE_TILES));
|
||||||
|
if(pTileLayer)
|
||||||
|
return pTileLayer->CanFillGameTiles();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CEditor::AddGroup()
|
void CEditor::AddGroup()
|
||||||
{
|
{
|
||||||
m_Map.NewGroup();
|
m_Map.NewGroup();
|
||||||
m_SelectedGroup = m_Map.m_vpGroups.size() - 1;
|
m_SelectedGroup = m_Map.m_vpGroups.size() - 1;
|
||||||
m_EditorHistory.RecordAction(std::make_shared<CEditorActionGroup>(this, m_SelectedGroup, false));
|
m_EditorHistory.RecordAction(std::make_shared<CEditorActionGroup>(this, m_SelectedGroup, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEditor::AddTileLayer()
|
void CEditor::AddTileLayer()
|
||||||
{
|
{
|
||||||
std::shared_ptr<CLayer> pTileLayer = std::make_shared<CLayerTiles>(this, m_Map.m_pGameLayer->m_Width, m_Map.m_pGameLayer->m_Height);
|
std::shared_ptr<CLayer> pTileLayer = std::make_shared<CLayerTiles>(this, m_Map.m_pGameLayer->m_Width, m_Map.m_pGameLayer->m_Height);
|
||||||
|
|
|
@ -7,6 +7,110 @@
|
||||||
#define ALWAYS_FALSE []() -> bool { return false; }
|
#define ALWAYS_FALSE []() -> bool { return false; }
|
||||||
#define DEFAULT_BTN []() -> int { return -1; }
|
#define DEFAULT_BTN []() -> int { return -1; }
|
||||||
|
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesAir,
|
||||||
|
"Game tiles: Air",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::AIR); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesHookable,
|
||||||
|
"Game tiles: Hookable",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::HOOKABLE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesDeath,
|
||||||
|
"Game tiles: Death",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::DEATH); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesUnhookable,
|
||||||
|
"Game tiles: Unhookable",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::UNHOOKABLE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesHookthrough,
|
||||||
|
"Game tiles: Hookthrough",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::HOOKTHROUGH); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesFreeze,
|
||||||
|
"Game tiles: Freeze",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::FREEZE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesUnfreeze,
|
||||||
|
"Game tiles: Unfreeze",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::UNFREEZE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesDeepFreeze,
|
||||||
|
"Game tiles: Deep Freeze",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::DEEP_FREEZE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesDeepUnfreeze,
|
||||||
|
"Game tiles: Deep Unfreeze",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::DEEP_UNFREEZE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesBlueCheckTele,
|
||||||
|
"Game tiles: Blue Check Tele",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::BLUE_CHECK_TELE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesRedCheckTele,
|
||||||
|
"Game tiles: Red Check Tele",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::RED_CHECK_TELE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesLiveFreeze,
|
||||||
|
"Game tiles: Live Freeze",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::LIVE_FREEZE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
|
REGISTER_QUICK_ACTION(
|
||||||
|
GameTilesLiveUnfreeze,
|
||||||
|
"Game tiles: Live Unfreeze",
|
||||||
|
[&]() { FillGameTiles(EGameTileOp::LIVE_UNFREEZE); },
|
||||||
|
[&]() -> bool { return !CanFillGameTiles(); },
|
||||||
|
ALWAYS_FALSE,
|
||||||
|
DEFAULT_BTN,
|
||||||
|
"")
|
||||||
REGISTER_QUICK_ACTION(
|
REGISTER_QUICK_ACTION(
|
||||||
AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group")
|
AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group")
|
||||||
REGISTER_QUICK_ACTION(
|
REGISTER_QUICK_ACTION(
|
||||||
|
|
Loading…
Reference in a new issue