Change editor teleport number behavior

This commit is contained in:
KebsCS 2024-09-16 03:15:41 +02:00
parent 0feee9aa3e
commit 5a49dcedbd
No known key found for this signature in database
GPG key ID: 5A8C0761A75E7309
6 changed files with 128 additions and 99 deletions

View file

@ -1290,7 +1290,7 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar)
{
pButtonName = "Tele";
pfnPopupFunc = PopupTele;
Rows = 3;
Rows = m_TeleNumbers.size() + 1;
}
if(pButtonName != nullptr)
@ -8050,7 +8050,7 @@ void CEditor::Render()
return pLayer->m_Type == LAYERTYPE_TILES && std::static_pointer_cast<CLayerTiles>(pLayer)->m_Tele;
});
if(HasTeleTiles)
str_copy(m_aTooltip, "Use shift+mousewheel up/down to adjust the tele numbers. Use ctrl+f to change all tele numbers to the first unused number.");
str_copy(m_aTooltip, "Use shift+mousewheel up/down to adjust the tele number. Use ctrl+f to change current tele number to the first unused number.");
if(Input()->ShiftIsPressed())
{
@ -8995,9 +8995,6 @@ void CEditor::AdjustBrushSpecialTiles(bool UseNextFree, int Adjust)
// Only handle tele, switch and tune layers
if(pLayerTiles->m_Tele)
{
int NextFreeTeleNumber = FindNextFreeTeleNumber();
int NextFreeCPNumber = FindNextFreeTeleNumber(true);
std::shared_ptr<CLayerTele> pTeleLayer = std::static_pointer_cast<CLayerTele>(pLayer);
for(int y = 0; y < pTeleLayer->m_Height; y++)
{
@ -9009,13 +9006,18 @@ void CEditor::AdjustBrushSpecialTiles(bool UseNextFree, int Adjust)
if(UseNextFree)
{
if(IsTeleTileCheckpoint(pTeleLayer->m_pTiles[i].m_Index))
pTeleLayer->m_pTeleTile[i].m_Number = NextFreeCPNumber;
else
pTeleLayer->m_pTeleTile[i].m_Number = NextFreeTeleNumber;
pTeleLayer->m_pTeleTile[i].m_Number = FindNextFreeTeleNumber(pTeleLayer->m_pTiles[i].m_Index);
}
else
AdjustNumber(pTeleLayer->m_pTeleTile[i].m_Number);
if(m_TeleNumbers[pTeleLayer->m_pTiles[i].m_Index] != pTeleLayer->m_pTeleTile[i].m_Number)
{
if(UseNextFree || Adjust != 0)
m_TeleNumbers[pTeleLayer->m_pTiles[i].m_Index] = pTeleLayer->m_pTeleTile[i].m_Number;
else if(!UseNextFree && Adjust == 0)
pTeleLayer->m_pTeleTile[i].m_Number = m_TeleNumbers[pTeleLayer->m_pTiles[i].m_Index];
}
}
}
}
@ -9075,12 +9077,12 @@ int CEditor::FindNextFreeSwitchNumber()
return Number;
}
int CEditor::FindNextFreeTeleNumber(bool IsCheckpoint)
int CEditor::FindNextFreeTeleNumber(int Index)
{
int Number = -1;
for(int i = 1; i <= 255; i++)
{
if(!m_Map.m_pTeleLayer->ContainsElementWithId(i, IsCheckpoint))
if(!m_Map.m_pTeleLayer->ContainsElementWithId(i, Index))
{
Number = i;
break;

View file

@ -218,8 +218,15 @@ public:
void MakeTuneLayer(const std::shared_ptr<CLayer> &pLayer);
};
struct CProperty
class CProperty
{
public:
CProperty(const char *name, int value, int type, int min, int max) :
m_pName(name), m_Value(value), m_Type(type), m_Min(min), m_Max(max) {}
CProperty(std::nullptr_t) :
m_pName(nullptr), m_Value(0), m_Type(0), m_Min(0), m_Max(0) {}
const char *m_pName;
int m_Value;
int m_Type;
@ -428,8 +435,15 @@ public:
// DDRace
m_TeleNumber = 1;
m_TeleCheckpointNumber = 1;
m_TeleNumbers = {
{TILE_TELEINEVIL, 1},
{TILE_TELEINWEAPON, 1},
{TILE_TELEINHOOK, 1},
{TILE_TELEIN, 1},
{TILE_TELEOUT, 1},
{TILE_TELECHECK, 1},
{TILE_TELECHECKOUT, 1}};
m_SwitchNum = 1;
m_TuningNum = 1;
m_SwitchDelay = 0;
@ -1127,9 +1141,8 @@ public:
IGraphics::CTextureHandle GetSwitchTexture();
IGraphics::CTextureHandle GetTuneTexture();
unsigned char m_TeleNumber;
unsigned char m_TeleCheckpointNumber;
unsigned char m_ViewTeleNumber;
std::map<int, unsigned char> m_TeleNumbers;
unsigned char m_TuningNum;
@ -1143,7 +1156,7 @@ public:
void AdjustBrushSpecialTiles(bool UseNextFree, int Adjust = 0);
int FindNextFreeSwitchNumber();
int FindNextFreeTeleNumber(bool IsCheckpoint = false);
int FindNextFreeTeleNumber(int Index);
// Undo/Redo
CEditorHistory m_EditorHistory;

View file

@ -77,7 +77,7 @@ void CLayerTele::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
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;
m_pEditor->m_TeleNumbers = pTeleLayer->m_TeleNumbers;
bool Destructive = m_pEditor->m_BrushDrawDestructive || IsEmpty(pTeleLayer);
@ -99,22 +99,19 @@ void CLayerTele::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
m_pTeleTile[Index].m_Type,
m_pTiles[Index].m_Index};
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)
unsigned char TgtIndex = pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index;
if((m_pEditor->m_AllowPlaceUnusedTiles || IsValidTeleTile(TgtIndex)) && TgtIndex != TILE_AIR)
{
bool IsCheckpoint = IsTeleTileCheckpoint(pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index);
if(!IsCheckpoint && !IsTeleTileNumberUsed(pTeleLayer->m_pTiles[y * pTeleLayer->m_Width + x].m_Index, false))
bool IsCheckpoint = IsTeleTileCheckpoint(TgtIndex);
if(!IsCheckpoint && !IsTeleTileNumberUsed(TgtIndex, false))
{
// 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[Index].m_Number = 255;
}
else if(!IsCheckpoint && m_pEditor->m_TeleNumber != pTeleLayer->m_TeleNum)
else if(m_pEditor->m_TeleNumbers[TgtIndex] != pTeleLayer->m_TeleNumbers[TgtIndex])
{
m_pTeleTile[Index].m_Number = m_pEditor->m_TeleNumber;
}
else if(IsCheckpoint && m_pEditor->m_TeleCheckpointNumber != pTeleLayer->m_TeleCheckpointNum)
{
m_pTeleTile[Index].m_Number = m_pEditor->m_TeleCheckpointNumber;
m_pTeleTile[Index].m_Number = m_pEditor->m_TeleNumbers[TgtIndex];
}
else if(pTeleLayer->m_pTeleTile[y * pTeleLayer->m_Width + x].m_Number)
{
@ -122,7 +119,7 @@ void CLayerTele::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
}
else
{
if((!IsCheckpoint && !m_pEditor->m_TeleNumber) || (IsCheckpoint && !m_pEditor->m_TeleCheckpointNumber))
if(!m_pEditor->m_TeleNumbers[TgtIndex])
{
m_pTeleTile[Index].m_Number = 0;
m_pTeleTile[Index].m_Type = 0;
@ -138,7 +135,7 @@ void CLayerTele::BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy)
}
else
{
m_pTeleTile[Index].m_Number = IsCheckpoint ? m_pEditor->m_TeleCheckpointNumber : m_pEditor->m_TeleNumber;
m_pTeleTile[Index].m_Number = m_pEditor->m_TeleNumbers[TgtIndex];
}
}
@ -283,10 +280,8 @@ void CLayerTele::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRe
// as tiles with number 0 would be ignored by previous versions.
m_pTeleTile[TgtIndex].m_Number = 255;
}
else if(!IsCheckpoint && ((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 if(IsCheckpoint && ((pLt->m_pTeleTile[SrcIndex].m_Number == 0 && m_pEditor->m_TeleCheckpointNumber) || m_pEditor->m_TeleCheckpointNumber != pLt->m_TeleCheckpointNum))
m_pTeleTile[TgtIndex].m_Number = m_pEditor->m_TeleCheckpointNumber;
else if((pLt->m_pTeleTile[SrcIndex].m_Number == 0 && m_pEditor->m_TeleNumbers[m_pTiles[TgtIndex].m_Index]) || m_pEditor->m_TeleNumbers[m_pTiles[TgtIndex].m_Index] != pLt->m_TeleNumbers[m_pTiles[TgtIndex].m_Index])
m_pTeleTile[TgtIndex].m_Number = m_pEditor->m_TeleNumbers[m_pTiles[TgtIndex].m_Index];
else
m_pTeleTile[TgtIndex].m_Number = pLt->m_pTeleTile[SrcIndex].m_Number;
}
@ -303,13 +298,13 @@ void CLayerTele::FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRe
FlagModified(sx, sy, w, h);
}
bool CLayerTele::ContainsElementWithId(int Id, bool Checkpoint)
bool CLayerTele::ContainsElementWithId(int Id, int Index)
{
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, Checkpoint) && m_pTeleTile[y * m_Width + x].m_Number == Id)
if(m_pTeleTile[y * m_Width + x].m_Type == Index && m_pTeleTile[y * m_Width + x].m_Number == Id)
{
return true;
}

View file

@ -22,8 +22,7 @@ public:
~CLayerTele();
CTeleTile *m_pTeleTile;
unsigned char m_TeleNum;
unsigned char m_TeleCheckpointNum;
std::map<int, unsigned char> m_TeleNumbers;
void Resize(int NewW, int NewH) override;
void Shift(int Direction) override;
@ -33,7 +32,7 @@ public:
void BrushFlipY() override;
void BrushRotate(float Amount) override;
void FillSelection(bool Empty, std::shared_ptr<CLayer> pBrush, CUIRect Rect) override;
virtual bool ContainsElementWithId(int Id, bool Checkpoint);
virtual bool ContainsElementWithId(int Id, int Index);
virtual void GetPos(int Number, int Offset, int &TeleX, int &TeleY);
int m_GotoTeleOffset;

View file

@ -310,17 +310,15 @@ int CLayerTiles::BrushGrab(std::shared_ptr<CLayerGroup> pBrush, CUIRect Rect)
for(int x = 0; x < r.w; x++)
{
pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x] = static_cast<CLayerTele *>(this)->m_pTeleTile[(r.y + y) * m_Width + (r.x + x)];
if(IsValidTeleTile(pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Type))
unsigned char TgtIndex = pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Type;
if(IsValidTeleTile(TgtIndex))
{
if(IsTeleTileNumberUsed(pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Type, false))
m_pEditor->m_TeleNumber = pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Number;
else if(IsTeleTileNumberUsed(pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Type, true))
m_pEditor->m_TeleCheckpointNumber = pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Number;
if(IsTeleTileNumberUsedAny(TgtIndex))
m_pEditor->m_TeleNumbers[TgtIndex] = pGrabbed->m_pTeleTile[y * pGrabbed->m_Width + x].m_Number;
}
}
pGrabbed->m_TeleNum = m_pEditor->m_TeleNumber;
pGrabbed->m_TeleCheckpointNum = m_pEditor->m_TeleCheckpointNumber;
pGrabbed->m_TeleNumbers = m_pEditor->m_TeleNumbers;
str_copy(pGrabbed->m_aFileName, m_pEditor->m_aFileName);
}

View file

@ -2433,23 +2433,29 @@ CUi::EPopupMenuFunctionResult CEditor::PopupTele(void *pContext, CUIRect View, b
{
CEditor *pEditor = static_cast<CEditor *>(pContext);
static int s_PreviousTeleNumber;
static int s_PreviousCheckpointNumber;
const size_t TeleNumbersSize = pEditor->m_TeleNumbers.size();
static std::vector<int> s_PreviousTeleNumbers;
if(s_PreviousTeleNumbers.size() != TeleNumbersSize)
s_PreviousTeleNumbers.resize(TeleNumbersSize);
static int s_PreviousViewTeleNumber;
CUIRect NumberPicker;
CUIRect FindEmptySlot;
CUIRect FindFreeTeleSlot, FindFreeCheckpointSlot, FindFreeViewSlot;
CUIRect FindFreeViewSlot;
std::vector<CUIRect> FindFreeTeleSlots;
if(FindFreeTeleSlots.size() != TeleNumbersSize)
FindFreeTeleSlots.resize(TeleNumbersSize);
View.VSplitRight(15.f, &NumberPicker, &FindEmptySlot);
NumberPicker.VSplitRight(2.f, &NumberPicker, nullptr);
FindEmptySlot.HSplitTop(13.0f, &FindFreeTeleSlot, &FindEmptySlot);
FindEmptySlot.HSplitTop(13.0f, &FindFreeCheckpointSlot, &FindEmptySlot);
for(auto &Slot : FindFreeTeleSlots)
FindEmptySlot.HSplitTop(13.0f, &Slot, &FindEmptySlot);
FindEmptySlot.HSplitTop(13.0f, &FindFreeViewSlot, &FindEmptySlot);
FindFreeTeleSlot.HMargin(1.0f, &FindFreeTeleSlot);
FindFreeCheckpointSlot.HMargin(1.0f, &FindFreeCheckpointSlot);
for(auto &Slot : FindFreeTeleSlots)
Slot.HMargin(1.0f, &Slot);
FindFreeViewSlot.HMargin(1.0f, &FindFreeViewSlot);
auto ViewTele = [](CEditor *pEd) -> bool {
@ -2465,79 +2471,95 @@ CUi::EPopupMenuFunctionResult CEditor::PopupTele(void *pContext, CUIRect View, b
return false;
};
static std::vector<ColorRGBA> s_vColors = {
ColorRGBA(0.5f, 1, 0.5f, 0.5f),
ColorRGBA(0.5f, 1, 0.5f, 0.5f),
ColorRGBA(0.5f, 1, 0.5f, 0.5f),
};
enum
static std::vector<ColorRGBA> s_vColors;
if(s_vColors.size() != TeleNumbersSize + 1)
{
PROP_TELE = 0,
PROP_TELE_CP,
PROP_TELE_VIEW,
NUM_PROPS,
};
s_vColors.resize(TeleNumbersSize + 1, ColorRGBA(0.5f, 1, 0.5f, 0.5f));
}
// find next free numbers buttons
{
// Pressing ctrl+f will find next free numbers for both tele and checkpoints
static int s_NextFreeTelePid = 0;
if(pEditor->DoButton_Editor(&s_NextFreeTelePid, "F", 0, &FindFreeTeleSlot, 0, "[ctrl+f] Find next free tele number") || (Active && pEditor->Input()->ModifierIsPressed() && pEditor->Input()->KeyPress(KEY_F)))
static std::vector<int> s_NextFreeTelePids;
if(s_NextFreeTelePids.size() != TeleNumbersSize)
s_NextFreeTelePids.resize(TeleNumbersSize, 0);
for(size_t i = 0; i < s_NextFreeTelePids.size(); i++)
{
int TeleNumber = pEditor->FindNextFreeTeleNumber();
if(pEditor->DoButton_Editor(&s_NextFreeTelePids[i], "F", 0, &FindFreeTeleSlots[i], 0, "[ctrl+f] Find next free tele number") || (Active && pEditor->Input()->ModifierIsPressed() && pEditor->Input()->KeyPress(KEY_F)))
{
int Tile = (*std::next(pEditor->m_TeleNumbers.begin(), i)).first;
int TeleNumber = pEditor->FindNextFreeTeleNumber(Tile);
if(TeleNumber != -1)
pEditor->m_TeleNumber = TeleNumber;
}
static int s_NextFreeCheckpointPid = 0;
if(pEditor->DoButton_Editor(&s_NextFreeCheckpointPid, "F", 0, &FindFreeCheckpointSlot, 0, "[ctrl+f] Find next free checkpoint number") || (Active && pEditor->Input()->ModifierIsPressed() && pEditor->Input()->KeyPress(KEY_F)))
{
int CPNumber = pEditor->FindNextFreeTeleNumber(true);
if(CPNumber != -1)
pEditor->m_TeleCheckpointNumber = CPNumber;
if(TeleNumber != -1)
{
pEditor->m_TeleNumbers[Tile] = TeleNumber;
pEditor->AdjustBrushSpecialTiles(false);
}
}
}
static int s_NextFreeViewPid = 0;
int btn = pEditor->DoButton_Editor(&s_NextFreeViewPid, "N", 0, &FindFreeViewSlot, 0, "[n] Show next tele with this number");
if(btn || (Active && pEditor->Input()->KeyPress(KEY_N)))
s_vColors[PROP_TELE_VIEW] = ViewTele(pEditor) ? ColorRGBA(0.5f, 1, 0.5f, 0.5f) : ColorRGBA(1, 0.5f, 0.5f, 0.5f);
s_vColors[TeleNumbersSize] = ViewTele(pEditor) ? ColorRGBA(0.5f, 1, 0.5f, 0.5f) : ColorRGBA(1, 0.5f, 0.5f, 0.5f);
}
// number picker
{
CProperty aProps[] = {
{"Number", pEditor->m_TeleNumber, PROPTYPE_INT, 1, 255},
{"Checkpoint", pEditor->m_TeleCheckpointNumber, PROPTYPE_INT, 1, 255},
{"View", pEditor->m_ViewTeleNumber, PROPTYPE_INT, 1, 255},
{nullptr},
};
static std::map<int, const char *> TeleText = {
{TILE_TELEINEVIL, "Red Tele"},
{TILE_TELEINWEAPON, "Weapon Tele"},
{TILE_TELEINHOOK, "Hook Tele"},
{TILE_TELEIN, "Blue Tele"},
{TILE_TELEOUT, "Tele To"},
{TILE_TELECHECK, "CP Tele"},
{TILE_TELECHECKOUT, "CP Tele To"}};
static int s_aIds[NUM_PROPS] = {0};
std::vector<CProperty> aProps;
for(size_t i = 0; i < TeleNumbersSize; i++)
{
auto Tele = (*std::next(pEditor->m_TeleNumbers.begin(), i));
aProps.emplace_back(CProperty{TeleText[Tele.first], Tele.second, PROPTYPE_INT, 1, 255});
}
aProps.emplace_back(CProperty{"View", pEditor->m_ViewTeleNumber, PROPTYPE_INT, 1, 255});
aProps.emplace_back(nullptr);
static std::vector<int> s_aIds;
if(s_aIds.size() != TeleNumbersSize + 2)
{
s_aIds.resize(TeleNumbersSize, 0);
s_aIds.emplace_back(0); // PROP_TELE_VIEW
s_aIds.emplace_back(0); // NUM_PROPS
}
int NewVal = 0;
int Prop = pEditor->DoProperties(&NumberPicker, aProps, s_aIds, &NewVal, s_vColors);
if(Prop == PROP_TELE)
pEditor->m_TeleNumber = (NewVal - 1 + 255) % 255 + 1;
else if(Prop == PROP_TELE_CP)
pEditor->m_TeleCheckpointNumber = (NewVal - 1 + 255) % 255 + 1;
else if(Prop == PROP_TELE_VIEW)
int Prop = pEditor->DoProperties(&NumberPicker, aProps.data(), s_aIds.data(), &NewVal, s_vColors);
if(Prop >= 0 && Prop < static_cast<int>(TeleNumbersSize))
{
auto Tele = (*std::next(pEditor->m_TeleNumbers.begin(), Prop));
pEditor->m_TeleNumbers[Tele.first] = (NewVal - 1 + 255) % 255 + 1;
pEditor->AdjustBrushSpecialTiles(false);
}
else if(Prop == static_cast<int>(TeleNumbersSize))
pEditor->m_ViewTeleNumber = (NewVal - 1 + 255) % 255 + 1;
if(s_PreviousTeleNumber == 1 || s_PreviousTeleNumber != pEditor->m_TeleNumber)
s_vColors[PROP_TELE] = pEditor->m_Map.m_pTeleLayer->ContainsElementWithId(pEditor->m_TeleNumber, false) ? ColorRGBA(1, 0.5f, 0.5f, 0.5f) : ColorRGBA(0.5f, 1, 0.5f, 0.5f);
if(s_PreviousCheckpointNumber == 1 || s_PreviousCheckpointNumber != pEditor->m_TeleCheckpointNumber)
s_vColors[PROP_TELE_CP] = pEditor->m_Map.m_pTeleLayer->ContainsElementWithId(pEditor->m_TeleCheckpointNumber, true) ? ColorRGBA(1, 0.5f, 0.5f, 0.5f) : ColorRGBA(0.5f, 1, 0.5f, 0.5f);
for(size_t i = 0; i < s_PreviousTeleNumbers.size(); i++)
{
auto Tele = (*std::next(pEditor->m_TeleNumbers.begin(), i));
if(s_PreviousTeleNumbers[i] == 1 || s_PreviousTeleNumbers[i] != Tele.second)
s_vColors[i] = pEditor->m_Map.m_pTeleLayer->ContainsElementWithId(Tele.second, Tele.first) ? ColorRGBA(1, 0.5f, 0.5f, 0.5f) : ColorRGBA(0.5f, 1, 0.5f, 0.5f);
}
if(s_PreviousViewTeleNumber != pEditor->m_ViewTeleNumber)
s_vColors[PROP_TELE_VIEW] = ViewTele(pEditor) ? ColorRGBA(0.5f, 1, 0.5f, 0.5f) : ColorRGBA(1, 0.5f, 0.5f, 0.5f);
s_vColors[TeleNumbersSize] = ViewTele(pEditor) ? ColorRGBA(0.5f, 1, 0.5f, 0.5f) : ColorRGBA(1, 0.5f, 0.5f, 0.5f);
}
s_PreviousTeleNumber = pEditor->m_TeleNumber;
s_PreviousCheckpointNumber = pEditor->m_TeleCheckpointNumber;
for(size_t i = 0; i < s_PreviousTeleNumbers.size(); i++)
{
s_PreviousTeleNumbers[i] = (*std::next(pEditor->m_TeleNumbers.begin(), i)).second;
}
s_PreviousViewTeleNumber = pEditor->m_ViewTeleNumber;
return CUi::POPUP_KEEP_OPEN;