mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-17 21:48:19 +00:00
Merge branch 'ddnet:master' into patch-1
This commit is contained in:
commit
a8616ef2ab
|
@ -2462,6 +2462,7 @@ if(CLIENT)
|
|||
editor_trackers.cpp
|
||||
editor_trackers.h
|
||||
editor_ui.h
|
||||
enums.h
|
||||
explanations.cpp
|
||||
layer_selector.cpp
|
||||
layer_selector.h
|
||||
|
@ -2500,8 +2501,13 @@ if(CLIENT)
|
|||
mapitems/sound.cpp
|
||||
mapitems/sound.h
|
||||
popups.cpp
|
||||
prompt.cpp
|
||||
prompt.h
|
||||
proof_mode.cpp
|
||||
proof_mode.h
|
||||
quick_action.h
|
||||
quick_actions.cpp
|
||||
quick_actions.h
|
||||
smooth_value.cpp
|
||||
smooth_value.h
|
||||
tileart.cpp
|
||||
|
|
|
@ -631,7 +631,7 @@ Loading DDNet Client
|
|||
== Загрузка DDNet Client
|
||||
|
||||
Normal message
|
||||
== Обычное с.
|
||||
== Обычное
|
||||
|
||||
Connecting dummy
|
||||
== Подключение дамми
|
||||
|
@ -643,10 +643,10 @@ Save ghost
|
|||
== Сохранять тень
|
||||
|
||||
DDNet Client updated!
|
||||
== DDNet Client обновлён!
|
||||
== DDNet клиент обновлён!
|
||||
|
||||
Highlighted message
|
||||
== Выделенное с.
|
||||
== Выделенное
|
||||
|
||||
Demo
|
||||
== Демо
|
||||
|
@ -724,7 +724,7 @@ Downloading %s:
|
|||
== Скачивание %s:
|
||||
|
||||
Update failed! Check log…
|
||||
== Ошибка. Проверьте логи…
|
||||
== Не удалось обновиться! Подробности в логах…
|
||||
|
||||
Restart
|
||||
== Рестарт
|
||||
|
@ -844,7 +844,7 @@ DDNet
|
|||
== DDNet
|
||||
|
||||
Friend message
|
||||
== Дружеское с.
|
||||
== Дружеское
|
||||
|
||||
Save the best demo of each race
|
||||
== Сохранять лучшее демо каждой карты
|
||||
|
@ -916,10 +916,10 @@ Ratio
|
|||
== Соотношение
|
||||
|
||||
Net
|
||||
== Сеть
|
||||
== Сальдо
|
||||
|
||||
FPM
|
||||
== FPM
|
||||
== У/мин
|
||||
|
||||
Spree
|
||||
== Серия
|
||||
|
@ -940,7 +940,7 @@ Grabs
|
|||
== 9+ упоминаний
|
||||
|
||||
Client message
|
||||
== Клиентское с.
|
||||
== Клиентское
|
||||
|
||||
Warning
|
||||
== Предупреждение
|
||||
|
@ -973,7 +973,7 @@ Run server
|
|||
== Запустить сервер
|
||||
|
||||
Server executable not found, can't run server
|
||||
== Файл сервера не найден, невозможно запустить
|
||||
== Файл сервера не найден, не удалось запустить сервер
|
||||
|
||||
Editor
|
||||
== Редактор
|
||||
|
@ -1883,7 +1883,7 @@ Could not resolve connect address '%s'. See local console for details.
|
|||
== Не удалось определить адрес подключения '%s'. Подробности в локальной консоли.
|
||||
|
||||
Connect address error
|
||||
== Ошибка подключения сервера
|
||||
== Ошибка адреса подключения
|
||||
|
||||
Could not connect dummy
|
||||
== Невозможно подключить дамми
|
||||
|
@ -1892,34 +1892,34 @@ Dummy is not allowed on this server
|
|||
== Дамми не разрешен на этом сервере
|
||||
|
||||
Please wait…
|
||||
== Пожалуйста подождите…
|
||||
== Пожалуйста, подождите…
|
||||
|
||||
Show client IDs (scoreboard, chat, spectator)
|
||||
== Показывать ID клиента (Табло, чат, наблюдатель)
|
||||
== Показывать ID клиента (табло, чат, наблюдатель)
|
||||
|
||||
Normal:
|
||||
== Обычный:
|
||||
|
||||
Team:
|
||||
== Команда:
|
||||
== В команде:
|
||||
|
||||
Dummy settings
|
||||
== Настройки дамми
|
||||
|
||||
Toggle to edit your dummy settings
|
||||
== Нажмите чтоб изменить настройки дамми
|
||||
== Нажмите, чтобы изменить настройки дамми
|
||||
|
||||
Randomize
|
||||
== Перемешать
|
||||
== Случайный
|
||||
|
||||
Are you sure that you want to delete '%s'?
|
||||
== Вы уверены что хотите удалить '%s'?
|
||||
== Вы уверены, что хотите удалить '%s'?
|
||||
|
||||
Delete skin
|
||||
== Удалить скин
|
||||
|
||||
Basic
|
||||
== Базовый
|
||||
== Пресеты
|
||||
|
||||
Custom
|
||||
== Кастомизация
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# 3edcxzaq1 2020-06-25 00:00:00
|
||||
# cur.ie 2020-09-28 00:00:00
|
||||
# simpygirl 2022-02-20 00:00:00
|
||||
# furo 2024-07-17 00:00:00
|
||||
# furo 2024-08-29 00:00:00
|
||||
##### /authors #####
|
||||
|
||||
##### translated strings #####
|
||||
|
@ -1868,52 +1868,52 @@ https://wiki.ddnet.org/wiki/Mapping
|
|||
== https://wiki.ddnet.org/wiki/Mapping
|
||||
|
||||
Could not resolve connect address '%s'. See local console for details.
|
||||
==
|
||||
== Kunde inte förstå anslutnings adress '%s'. Se den lokala konsolen för detaljer.
|
||||
|
||||
Connect address error
|
||||
==
|
||||
== Anslutnings problem
|
||||
|
||||
Could not connect dummy
|
||||
==
|
||||
== Kunde inte ansluta dummy
|
||||
|
||||
Dummy is not allowed on this server
|
||||
==
|
||||
== Dummy är inte tillåten på denna server
|
||||
|
||||
Please wait…
|
||||
==
|
||||
== Vänligen vänta…
|
||||
|
||||
Show client IDs (scoreboard, chat, spectator)
|
||||
==
|
||||
== Visa klient IDen (poänglistan, chatt, åskadarmeny)
|
||||
|
||||
Normal:
|
||||
==
|
||||
== Normal:
|
||||
|
||||
Team:
|
||||
==
|
||||
== Lag:
|
||||
|
||||
Dummy settings
|
||||
==
|
||||
== Dummy inställningar
|
||||
|
||||
Toggle to edit your dummy settings
|
||||
==
|
||||
== Växla för att ändra dina dummy inställningar
|
||||
|
||||
Randomize
|
||||
==
|
||||
== Slumpa
|
||||
|
||||
Are you sure that you want to delete '%s'?
|
||||
==
|
||||
== Är du säker att du vill ta bort '%s'?
|
||||
|
||||
Delete skin
|
||||
==
|
||||
== Ta bort skin
|
||||
|
||||
Basic
|
||||
==
|
||||
== Enkel
|
||||
|
||||
Custom
|
||||
==
|
||||
== Anpassa
|
||||
|
||||
Unable to delete skin
|
||||
==
|
||||
== Kunde inte ta bort skin
|
||||
|
||||
Customize
|
||||
==
|
||||
== Ändra
|
||||
|
|
|
@ -228,10 +228,8 @@ int CSound::Init()
|
|||
return -1;
|
||||
}
|
||||
|
||||
m_MixingRate = g_Config.m_SndRate;
|
||||
|
||||
SDL_AudioSpec Format, FormatOut;
|
||||
Format.freq = m_MixingRate;
|
||||
Format.freq = g_Config.m_SndRate;
|
||||
Format.format = AUDIO_S16;
|
||||
Format.channels = 2;
|
||||
Format.samples = g_Config.m_SndBufferSize;
|
||||
|
@ -239,7 +237,7 @@ int CSound::Init()
|
|||
Format.userdata = this;
|
||||
|
||||
// Open the audio device and start playing sound!
|
||||
m_Device = SDL_OpenAudioDevice(nullptr, 0, &Format, &FormatOut, 0);
|
||||
m_Device = SDL_OpenAudioDevice(nullptr, 0, &Format, &FormatOut, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||
if(m_Device == 0)
|
||||
{
|
||||
dbg_msg("sound", "unable to open audio: %s", SDL_GetError());
|
||||
|
@ -248,6 +246,7 @@ int CSound::Init()
|
|||
else
|
||||
dbg_msg("sound", "sound init successful using audio driver '%s'", SDL_GetCurrentAudioDriver());
|
||||
|
||||
m_MixingRate = FormatOut.freq;
|
||||
m_MaxFrames = FormatOut.samples * 2;
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
m_MaxFrames = maximum<uint32_t>(m_MaxFrames, 1024 * 2); // make the buffer bigger just in case
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
virtual int GetInteger(unsigned Index) const = 0;
|
||||
virtual float GetFloat(unsigned Index) const = 0;
|
||||
virtual const char *GetString(unsigned Index) const = 0;
|
||||
virtual ColorHSLA GetColor(unsigned Index, bool Light) const = 0;
|
||||
virtual std::optional<ColorHSLA> GetColor(unsigned Index, bool Light) const = 0;
|
||||
|
||||
virtual void RemoveArgument(unsigned Index) = 0;
|
||||
|
||||
|
|
|
@ -111,22 +111,29 @@ void SIntConfigVariable::ResetToOld()
|
|||
void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
SColorConfigVariable *pData = static_cast<SColorConfigVariable *>(pUserData);
|
||||
|
||||
char aBuf[IConsole::CMDLINE_LENGTH + 64];
|
||||
if(pResult->NumArguments())
|
||||
{
|
||||
if(pData->CheckReadOnly())
|
||||
return;
|
||||
|
||||
const ColorHSLA Color = pResult->GetColor(0, pData->m_Light);
|
||||
const unsigned Value = Color.Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
|
||||
const auto Color = pResult->GetColor(0, pData->m_Light);
|
||||
if(Color)
|
||||
{
|
||||
const unsigned Value = Color->Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
|
||||
|
||||
*pData->m_pVariable = Value;
|
||||
if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME)
|
||||
pData->m_OldValue = Value;
|
||||
*pData->m_pVariable = Value;
|
||||
if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME)
|
||||
pData->m_OldValue = Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%s is not a valid color.", pResult->GetString(0));
|
||||
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable);
|
||||
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
|
||||
|
||||
|
@ -493,8 +500,8 @@ void CConfigManager::Con_Toggle(IConsole::IResult *pResult, void *pUserData)
|
|||
{
|
||||
SColorConfigVariable *pColorVariable = static_cast<SColorConfigVariable *>(pVariable);
|
||||
const float Darkest = pColorVariable->m_Light ? 0.5f : 0.0f;
|
||||
const ColorHSLA Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light);
|
||||
pColorVariable->SetValue(Value.Pack(Darkest, pColorVariable->m_Alpha));
|
||||
const std::optional<ColorHSLA> Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light);
|
||||
pColorVariable->SetValue(Value.value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha));
|
||||
}
|
||||
else if(pVariable->m_Type == SConfigVariable::VAR_STRING)
|
||||
{
|
||||
|
|
|
@ -40,22 +40,29 @@ float CConsole::CResult::GetFloat(unsigned Index) const
|
|||
return str_tofloat(m_apArgs[Index]);
|
||||
}
|
||||
|
||||
ColorHSLA CConsole::CResult::GetColor(unsigned Index, bool Light) const
|
||||
std::optional<ColorHSLA> CConsole::CResult::GetColor(unsigned Index, bool Light) const
|
||||
{
|
||||
if(Index >= m_NumArgs)
|
||||
return ColorHSLA(0, 0, 0);
|
||||
return std::nullopt;
|
||||
|
||||
const char *pStr = m_apArgs[Index];
|
||||
if(str_isallnum(pStr) || ((pStr[0] == '-' || pStr[0] == '+') && str_isallnum(pStr + 1))) // Teeworlds Color (Packed HSL)
|
||||
{
|
||||
const ColorHSLA Hsla = ColorHSLA(str_toulong_base(pStr, 10), true);
|
||||
unsigned long Value = str_toulong_base(pStr, 10);
|
||||
if(Value == std::numeric_limits<unsigned long>::max())
|
||||
return std::nullopt;
|
||||
const ColorHSLA Hsla = ColorHSLA(Value, true);
|
||||
if(Light)
|
||||
return Hsla.UnclampLighting();
|
||||
return Hsla;
|
||||
}
|
||||
else if(*pStr == '$') // Hex RGB/RGBA
|
||||
{
|
||||
return color_cast<ColorHSLA>(color_parse<ColorRGBA>(pStr + 1).value_or(ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
|
||||
auto ParsedColor = color_parse<ColorRGBA>(pStr + 1);
|
||||
if(ParsedColor)
|
||||
return color_cast<ColorHSLA>(ParsedColor.value());
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
else if(!str_comp_nocase(pStr, "red"))
|
||||
return ColorHSLA(0.0f / 6.0f, 1, .5f);
|
||||
|
@ -76,7 +83,7 @@ ColorHSLA CConsole::CResult::GetColor(unsigned Index, bool Light) const
|
|||
else if(!str_comp_nocase(pStr, "black"))
|
||||
return ColorHSLA(0, 0, 0);
|
||||
|
||||
return ColorHSLA(0, 0, 0);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const
|
||||
|
@ -129,12 +136,12 @@ int CConsole::ParseStart(CResult *pResult, const char *pString, int Length)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||
int CConsole::ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback)
|
||||
{
|
||||
char Command = *pFormat;
|
||||
char *pStr;
|
||||
int Optional = 0;
|
||||
int Error = 0;
|
||||
int Error = PARSEARGS_OK;
|
||||
|
||||
pResult->ResetVictim();
|
||||
|
||||
|
@ -155,7 +162,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
|||
{
|
||||
if(!Optional)
|
||||
{
|
||||
Error = 1;
|
||||
Error = PARSEARGS_MISSING_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -191,7 +198,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
|||
pStr++; // skip due to escape
|
||||
}
|
||||
else if(pStr[0] == 0)
|
||||
return 1; // return error
|
||||
return PARSEARGS_MISSING_VALUE; // return error
|
||||
|
||||
*pDst = *pStr;
|
||||
pDst++;
|
||||
|
@ -215,13 +222,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
|||
|
||||
if(Command == 'r') // rest of the string
|
||||
break;
|
||||
else if(Command == 'v') // validate victim
|
||||
pStr = str_skip_to_whitespace(pStr);
|
||||
else if(Command == 'i') // validate int
|
||||
pStr = str_skip_to_whitespace(pStr);
|
||||
else if(Command == 'f') // validate float
|
||||
pStr = str_skip_to_whitespace(pStr);
|
||||
else if(Command == 's') // validate string
|
||||
else if(Command == 'v' || Command == 'i' || Command == 'f' || Command == 's')
|
||||
pStr = str_skip_to_whitespace(pStr);
|
||||
|
||||
if(pStr[0] != 0) // check for end of string
|
||||
|
@ -230,6 +231,32 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
|||
pStr++;
|
||||
}
|
||||
|
||||
// validate args
|
||||
if(Command == 'i')
|
||||
{
|
||||
// don't validate colors here
|
||||
if(pfnCallback != &SColorConfigVariable::CommandCallback)
|
||||
{
|
||||
int Value;
|
||||
if(!str_toint(pResult->GetString(pResult->NumArguments() - 1), &Value) ||
|
||||
Value == std::numeric_limits<int>::max() || Value == std::numeric_limits<int>::min())
|
||||
{
|
||||
Error = PARSEARGS_INVALID_INTEGER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(Command == 'f')
|
||||
{
|
||||
float Value;
|
||||
if(!str_tofloat(pResult->GetString(pResult->NumArguments() - 1), &Value) ||
|
||||
Value == std::numeric_limits<float>::max() || Value == std::numeric_limits<float>::min())
|
||||
{
|
||||
Error = PARSEARGS_INVALID_FLOAT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pVictim)
|
||||
{
|
||||
pResult->SetVictim(pVictim);
|
||||
|
@ -487,10 +514,15 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientId, bo
|
|||
|
||||
if(Stroke || IsStrokeCommand)
|
||||
{
|
||||
if(ParseArgs(&Result, pCommand->m_pParams))
|
||||
if(int Error = ParseArgs(&Result, pCommand->m_pParams, pCommand->m_pfnCallback))
|
||||
{
|
||||
char aBuf[TEMPCMD_NAME_LENGTH + TEMPCMD_PARAMS_LENGTH + 32];
|
||||
str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
|
||||
char aBuf[CMDLINE_LENGTH + 64];
|
||||
if(Error == PARSEARGS_INVALID_INTEGER)
|
||||
str_format(aBuf, sizeof(aBuf), "%s is not a valid integer.", Result.GetString(Result.NumArguments() - 1));
|
||||
else if(Error == PARSEARGS_INVALID_FLOAT)
|
||||
str_format(aBuf, sizeof(aBuf), "%s is not a valid decimal number.", Result.GetString(Result.NumArguments() - 1));
|
||||
else
|
||||
str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
|
||||
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
|
||||
}
|
||||
else if(m_StoreCommands && pCommand->m_Flags & CFGFLAG_STORE)
|
||||
|
|
|
@ -115,7 +115,7 @@ class CConsole : public IConsole
|
|||
const char *GetString(unsigned Index) const override;
|
||||
int GetInteger(unsigned Index) const override;
|
||||
float GetFloat(unsigned Index) const override;
|
||||
ColorHSLA GetColor(unsigned Index, bool Light) const override;
|
||||
std::optional<ColorHSLA> GetColor(unsigned Index, bool Light) const override;
|
||||
|
||||
void RemoveArgument(unsigned Index) override
|
||||
{
|
||||
|
@ -144,7 +144,16 @@ class CConsole : public IConsole
|
|||
};
|
||||
|
||||
int ParseStart(CResult *pResult, const char *pString, int Length);
|
||||
int ParseArgs(CResult *pResult, const char *pFormat);
|
||||
|
||||
enum
|
||||
{
|
||||
PARSEARGS_OK = 0,
|
||||
PARSEARGS_MISSING_VALUE,
|
||||
PARSEARGS_INVALID_INTEGER,
|
||||
PARSEARGS_INVALID_FLOAT,
|
||||
};
|
||||
|
||||
int ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback = 0);
|
||||
|
||||
/*
|
||||
this function will set pFormat to the next parameter (i,s,r,v,?) it contains and
|
||||
|
|
|
@ -1074,11 +1074,9 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar)
|
|||
|
||||
// proof button
|
||||
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
|
||||
static int s_ProofButton = 0;
|
||||
if(DoButton_Ex(&s_ProofButton, "Proof", MapView()->ProofMode()->IsEnabled(), &Button, 0, "[ctrl+p] Toggles proof borders. These borders represent the area that a player can see with default zoom.", IGraphics::CORNER_L) ||
|
||||
(m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_P) && ModPressed))
|
||||
if(DoButton_Ex(&m_QuickActionProof, m_QuickActionProof.Label(), m_QuickActionProof.Active(), &Button, 0, m_QuickActionProof.Description(), IGraphics::CORNER_L))
|
||||
{
|
||||
MapView()->ProofMode()->Toggle();
|
||||
m_QuickActionProof.Call();
|
||||
}
|
||||
|
||||
TB_Top.VSplitLeft(14.0f, &Button, &TB_Top);
|
||||
|
@ -1254,10 +1252,9 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar)
|
|||
// refocus button
|
||||
{
|
||||
TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom);
|
||||
static int s_RefocusButton = 0;
|
||||
int FocusButtonChecked = MapView()->IsFocused() ? -1 : 1;
|
||||
if(DoButton_Editor(&s_RefocusButton, "Refocus", FocusButtonChecked, &Button, 0, "[HOME] Restore map focus") || (m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_HOME)))
|
||||
MapView()->Focus();
|
||||
if(DoButton_Editor(&m_QuickActionRefocus, m_QuickActionRefocus.Label(), FocusButtonChecked, &Button, 0, m_QuickActionRefocus.Description()) || (m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_HOME)))
|
||||
m_QuickActionRefocus.Call();
|
||||
TB_Bottom.VSplitLeft(5.0f, nullptr, &TB_Bottom);
|
||||
}
|
||||
|
||||
|
@ -4302,12 +4299,9 @@ void CEditor::RenderLayers(CUIRect LayersBox)
|
|||
if(s_ScrollRegion.AddRect(AddGroupButton))
|
||||
{
|
||||
AddGroupButton.HSplitTop(RowHeight, &AddGroupButton, 0);
|
||||
static int s_AddGroupButton = 0;
|
||||
if(DoButton_Editor(&s_AddGroupButton, "Add group", 0, &AddGroupButton, IGraphics::CORNER_R, "Adds a new group"))
|
||||
if(DoButton_Editor(&m_QuickActionAddGroup, m_QuickActionAddGroup.Label(), 0, &AddGroupButton, IGraphics::CORNER_R, m_QuickActionAddGroup.Description()))
|
||||
{
|
||||
m_Map.NewGroup();
|
||||
m_SelectedGroup = m_Map.m_vpGroups.size() - 1;
|
||||
m_EditorHistory.RecordAction(std::make_shared<CEditorActionGroup>(this, m_SelectedGroup, false));
|
||||
m_QuickActionAddGroup.Call();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4806,8 +4800,8 @@ void CEditor::RenderImagesList(CUIRect ToolBox)
|
|||
{
|
||||
AddImageButton.HSplitTop(5.0f, nullptr, &AddImageButton);
|
||||
AddImageButton.HSplitTop(RowHeight, &AddImageButton, nullptr);
|
||||
if(DoButton_Editor(&s_AddImageButton, "Add", 0, &AddImageButton, 0, "Load a new image to use in the map"))
|
||||
InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", false, AddImage, this);
|
||||
if(DoButton_Editor(&s_AddImageButton, m_QuickActionAddImage.Label(), 0, &AddImageButton, 0, m_QuickActionAddImage.Description()))
|
||||
m_QuickActionAddImage.Call();
|
||||
}
|
||||
s_ScrollRegion.End();
|
||||
}
|
||||
|
@ -5750,9 +5744,9 @@ void CEditor::RenderStatusbar(CUIRect View, CUIRect *pTooltipRect)
|
|||
CUIRect Button;
|
||||
View.VSplitRight(100.0f, &View, &Button);
|
||||
static int s_EnvelopeButton = 0;
|
||||
if(DoButton_Editor(&s_EnvelopeButton, "Envelopes", ButtonsDisabled ? -1 : m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES, &Button, 0, "Toggles the envelope editor.") == 1)
|
||||
if(DoButton_Editor(&s_EnvelopeButton, m_QuickActionEnvelopes.Label(), m_QuickActionEnvelopes.Color(), &Button, 0, m_QuickActionEnvelopes.Description()) == 1)
|
||||
{
|
||||
m_ActiveExtraEditor = m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES ? EXTRAEDITOR_NONE : EXTRAEDITOR_ENVELOPES;
|
||||
m_QuickActionEnvelopes.Call();
|
||||
}
|
||||
|
||||
View.VSplitRight(10.0f, &View, nullptr);
|
||||
|
@ -7919,7 +7913,7 @@ void CEditor::Render()
|
|||
InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CallbackSaveCopyMap, this);
|
||||
// ctrl+shift+s to save as
|
||||
else if(Input()->KeyPress(KEY_S) && ModPressed && ShiftPressed)
|
||||
InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CallbackSaveMap, this);
|
||||
m_QuickActionSaveAs.Call();
|
||||
// ctrl+s to save
|
||||
else if(Input()->KeyPress(KEY_S) && ModPressed)
|
||||
{
|
||||
|
@ -8362,6 +8356,7 @@ void CEditor::Init()
|
|||
m_vComponents.emplace_back(m_MapView);
|
||||
m_vComponents.emplace_back(m_MapSettingsBackend);
|
||||
m_vComponents.emplace_back(m_LayerSelector);
|
||||
m_vComponents.emplace_back(m_Prompt);
|
||||
for(CEditorComponent &Component : m_vComponents)
|
||||
Component.OnInit(this);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <game/client/ui_listbox.h>
|
||||
#include <game/mapitems.h>
|
||||
|
||||
#include <game/editor/enums.h>
|
||||
#include <game/editor/mapitems/envelope.h>
|
||||
#include <game/editor/mapitems/layer.h>
|
||||
#include <game/editor/mapitems/layer_front.h>
|
||||
|
@ -38,6 +39,8 @@
|
|||
#include "layer_selector.h"
|
||||
#include "map_view.h"
|
||||
#include "smooth_value.h"
|
||||
#include <game/editor/prompt.h>
|
||||
#include <game/editor/quick_action.h>
|
||||
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
|
@ -60,7 +63,8 @@ enum
|
|||
|
||||
DIALOG_NONE = 0,
|
||||
DIALOG_FILE,
|
||||
DIALOG_MAPSETTINGS_ERROR
|
||||
DIALOG_MAPSETTINGS_ERROR,
|
||||
DIALOG_QUICK_PROMPT,
|
||||
};
|
||||
|
||||
class CEditorImage;
|
||||
|
@ -278,6 +282,7 @@ class CEditor : public IEditor
|
|||
std::vector<std::reference_wrapper<CEditorComponent>> m_vComponents;
|
||||
CMapView m_MapView;
|
||||
CLayerSelector m_LayerSelector;
|
||||
CPrompt m_Prompt;
|
||||
|
||||
bool m_EditorWasUsedBefore = false;
|
||||
|
||||
|
@ -319,7 +324,20 @@ public:
|
|||
const CMapView *MapView() const { return &m_MapView; }
|
||||
CLayerSelector *LayerSelector() { return &m_LayerSelector; }
|
||||
|
||||
void FillGameTiles(EGameTileOp FillTile) const;
|
||||
bool CanFillGameTiles() const;
|
||||
void AddGroup();
|
||||
void AddTileLayer();
|
||||
void LayerSelectImage();
|
||||
bool IsNonGameTileLayerSelected() const;
|
||||
#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) CQuickAction m_QuickAction##name;
|
||||
#include <game/editor/quick_actions.h>
|
||||
#undef REGISTER_QUICK_ACTION
|
||||
|
||||
CEditor() :
|
||||
#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) m_QuickAction##name(text, description, callback, disabled, active, button_color),
|
||||
#include <game/editor/quick_actions.h>
|
||||
#undef REGISTER_QUICK_ACTION
|
||||
m_ZoomEnvelopeX(1.0f, 0.1f, 600.0f),
|
||||
m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f),
|
||||
m_MapSettingsCommandContext(m_MapSettingsBackend.NewContext(&m_SettingsCommandInput))
|
||||
|
|
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 <game/editor/editor.h>
|
||||
#include <game/editor/editor_actions.h>
|
||||
#include <game/editor/enums.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
@ -693,93 +694,126 @@ void CLayerTiles::ShowInfo()
|
|||
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
||||
}
|
||||
|
||||
CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
||||
void CLayerTiles::FillGameTiles(EGameTileOp Fill)
|
||||
{
|
||||
CUIRect Button;
|
||||
|
||||
const bool EntitiesLayer = IsEntitiesLayer();
|
||||
if(!CanFillGameTiles())
|
||||
return;
|
||||
|
||||
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
|
||||
if(!EntitiesLayer && !(pGroup->m_OffsetX % 32) && !(pGroup->m_OffsetY % 32) && pGroup->m_ParallaxX == 100 && pGroup->m_ParallaxY == 100)
|
||||
int Result = (int)Fill;
|
||||
switch(Fill)
|
||||
{
|
||||
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();
|
||||
int Result = Selected;
|
||||
switch(Selected)
|
||||
case EGameTileOp::HOOKTHROUGH:
|
||||
Result = TILE_THROUGH_CUT;
|
||||
break;
|
||||
case EGameTileOp::FREEZE:
|
||||
Result = TILE_FREEZE;
|
||||
break;
|
||||
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:
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
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));
|
||||
|
@ -788,124 +822,94 @@ CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox)
|
|||
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)", 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::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);
|
||||
std::map<int, std::shared_ptr<CLayer>> savedLayers;
|
||||
savedLayers[LAYERTYPE_TILES] = pTLayer->Duplicate();
|
||||
savedLayers[LAYERTYPE_TELE] = savedLayers[LAYERTYPE_TILES];
|
||||
|
||||
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)
|
||||
{
|
||||
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));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_EDITOR_MAPITEMS_LAYER_TILES_H
|
||||
|
||||
#include <game/editor/editor_trackers.h>
|
||||
#include <game/editor/enums.h>
|
||||
#include <map>
|
||||
|
||||
#include "layer.h"
|
||||
|
@ -122,6 +123,8 @@ public:
|
|||
void BrushSelecting(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 FillGameTiles(EGameTileOp Fill);
|
||||
bool CanFillGameTiles() const;
|
||||
void BrushDraw(std::shared_ptr<CLayer> pBrush, float wx, float wy) override;
|
||||
void BrushFlipX() override;
|
||||
void BrushFlipY() override;
|
||||
|
|
|
@ -68,17 +68,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuFile(void *pContext, CUIRect Vie
|
|||
|
||||
View.HSplitTop(2.0f, nullptr, &View);
|
||||
View.HSplitTop(12.0f, &Slot, &View);
|
||||
if(pEditor->DoButton_MenuItem(&s_OpenCurrentMapButton, "Load Current Map", 0, &Slot, 0, "Opens the current in game map for editing (ctrl+alt+l)"))
|
||||
if(pEditor->DoButton_MenuItem(&s_OpenCurrentMapButton, pEditor->m_QuickActionLoadCurrentMap.Label(), 0, &Slot, 0, pEditor->m_QuickActionLoadCurrentMap.Description()))
|
||||
{
|
||||
if(pEditor->HasUnsavedData())
|
||||
{
|
||||
pEditor->m_PopupEventType = POPEVENT_LOADCURRENT;
|
||||
pEditor->m_PopupEventActivated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEditor->LoadCurrentMap();
|
||||
}
|
||||
pEditor->m_QuickActionLoadCurrentMap.Call();
|
||||
return CUi::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -107,9 +99,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuFile(void *pContext, CUIRect Vie
|
|||
|
||||
View.HSplitTop(2.0f, nullptr, &View);
|
||||
View.HSplitTop(12.0f, &Slot, &View);
|
||||
if(pEditor->DoButton_MenuItem(&s_SaveAsButton, "Save As", 0, &Slot, 0, "Saves the current map under a new name (ctrl+shift+s)"))
|
||||
if(pEditor->DoButton_MenuItem(&s_SaveAsButton, pEditor->m_QuickActionSaveAs.Label(), 0, &Slot, 0, pEditor->m_QuickActionSaveAs.Description()))
|
||||
{
|
||||
pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CEditor::CallbackSaveMap, pEditor);
|
||||
pEditor->m_QuickActionSaveAs.Call();
|
||||
return CUi::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
@ -314,20 +306,20 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuSettings(void *pContext, CUIRect
|
|||
static int s_ButtonOff = 0;
|
||||
static int s_ButtonDec = 0;
|
||||
static int s_ButtonHex = 0;
|
||||
if(pEditor->DoButton_Ex(&s_ButtonOff, "Off", pEditor->m_ShowTileInfo == SHOW_TILE_OFF, &Off, 0, "Do not show tile information", IGraphics::CORNER_L))
|
||||
CQuickAction *pAction = &pEditor->m_QuickActionShowInfoOff;
|
||||
if(pEditor->DoButton_Ex(&s_ButtonOff, pAction->LabelShort(), pAction->Active(), &Off, 0, pAction->Description(), IGraphics::CORNER_L))
|
||||
{
|
||||
pEditor->m_ShowTileInfo = SHOW_TILE_OFF;
|
||||
pEditor->m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
pAction->Call();
|
||||
}
|
||||
if(pEditor->DoButton_Ex(&s_ButtonDec, "Dec", pEditor->m_ShowTileInfo == SHOW_TILE_DECIMAL, &Dec, 0, "[ctrl+i] Show tile information", IGraphics::CORNER_NONE))
|
||||
pAction = &pEditor->m_QuickActionShowInfoDec;
|
||||
if(pEditor->DoButton_Ex(&s_ButtonDec, pAction->LabelShort(), pAction->Active(), &Dec, 0, pAction->Description(), IGraphics::CORNER_NONE))
|
||||
{
|
||||
pEditor->m_ShowTileInfo = SHOW_TILE_DECIMAL;
|
||||
pEditor->m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
pAction->Call();
|
||||
}
|
||||
if(pEditor->DoButton_Ex(&s_ButtonHex, "Hex", pEditor->m_ShowTileInfo == SHOW_TILE_HEXADECIMAL, &Hex, 0, "[ctrl+shift+i] Show tile information in hexadecimal", IGraphics::CORNER_R))
|
||||
pAction = &pEditor->m_QuickActionShowInfoHex;
|
||||
if(pEditor->DoButton_Ex(&s_ButtonHex, pAction->LabelShort(), pAction->Active(), &Hex, 0, pAction->Description(), IGraphics::CORNER_R))
|
||||
{
|
||||
pEditor->m_ShowTileInfo = SHOW_TILE_HEXADECIMAL;
|
||||
pEditor->m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
pAction->Call();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,16 +570,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
|||
// new tile layer
|
||||
View.HSplitBottom(5.0f, &View, nullptr);
|
||||
View.HSplitBottom(12.0f, &View, &Button);
|
||||
static int s_NewTileLayerButton = 0;
|
||||
if(pEditor->DoButton_Editor(&s_NewTileLayerButton, "Add tile layer", 0, &Button, 0, "Creates a new tile layer"))
|
||||
if(pEditor->DoButton_Editor(&pEditor->m_QuickActionAddTileLayer, pEditor->m_QuickActionAddTileLayer.Label(), 0, &Button, 0, pEditor->m_QuickActionAddTileLayer.Description()))
|
||||
{
|
||||
std::shared_ptr<CLayer> pTileLayer = std::make_shared<CLayerTiles>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
||||
pTileLayer->m_pEditor = pEditor;
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pTileLayer);
|
||||
int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
pEditor->SelectLayer(LayerIndex);
|
||||
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_Collapse = false;
|
||||
pEditor->m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(pEditor, pEditor->m_SelectedGroup, LayerIndex));
|
||||
pEditor->m_QuickActionAddTileLayer.Call();
|
||||
return CUi::POPUP_CLOSE_CURRENT;
|
||||
}
|
||||
|
||||
|
|
169
src/game/editor/prompt.cpp
Normal file
169
src/game/editor/prompt.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include <engine/keys.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/editor/quick_action.h>
|
||||
|
||||
#include "editor.h"
|
||||
|
||||
#include "prompt.h"
|
||||
|
||||
bool FuzzyMatch(const char *pHaystack, const char *pNeedle)
|
||||
{
|
||||
if(!pNeedle || !pNeedle[0])
|
||||
return false;
|
||||
char aBuf[2] = {0};
|
||||
const char *pHit = pHaystack;
|
||||
int NeedleLen = str_length(pNeedle);
|
||||
for(int i = 0; i < NeedleLen; i++)
|
||||
{
|
||||
if(!pHit)
|
||||
return false;
|
||||
aBuf[0] = pNeedle[i];
|
||||
pHit = str_find_nocase(pHit, aBuf);
|
||||
if(pHit)
|
||||
pHit++;
|
||||
}
|
||||
return pHit;
|
||||
}
|
||||
|
||||
bool CPrompt::IsActive()
|
||||
{
|
||||
return CEditorComponent::IsActive() || Editor()->m_Dialog == DIALOG_QUICK_PROMPT;
|
||||
}
|
||||
|
||||
void CPrompt::SetActive()
|
||||
{
|
||||
Editor()->m_Dialog = DIALOG_QUICK_PROMPT;
|
||||
CEditorComponent::SetActive();
|
||||
|
||||
Ui()->SetActiveItem(&m_PromptInput);
|
||||
}
|
||||
|
||||
void CPrompt::SetInactive()
|
||||
{
|
||||
m_ResetFilterResults = true;
|
||||
m_PromptInput.Clear();
|
||||
if(Editor()->m_Dialog == DIALOG_QUICK_PROMPT)
|
||||
Editor()->m_Dialog = DIALOG_NONE;
|
||||
CEditorComponent::SetInactive();
|
||||
}
|
||||
|
||||
bool CPrompt::OnInput(const IInput::CEvent &Event)
|
||||
{
|
||||
if(Input()->ModifierIsPressed() && Input()->KeyIsPressed(KEY_P))
|
||||
{
|
||||
SetActive();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPrompt::OnInit(CEditor *pEditor)
|
||||
{
|
||||
CEditorComponent::OnInit(pEditor);
|
||||
|
||||
#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) m_vQuickActions.emplace_back(&Editor()->m_QuickAction##name);
|
||||
#include <game/editor/quick_actions.h>
|
||||
#undef REGISTER_QUICK_ACTION
|
||||
}
|
||||
|
||||
void CPrompt::OnRender(CUIRect _)
|
||||
{
|
||||
if(!IsActive())
|
||||
return;
|
||||
|
||||
if(Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE))
|
||||
{
|
||||
SetInactive();
|
||||
return;
|
||||
}
|
||||
|
||||
static CListBox s_ListBox;
|
||||
CUIRect Prompt, PromptBox;
|
||||
CUIRect Suggestions;
|
||||
|
||||
Ui()->MapScreen();
|
||||
CUIRect Overlay = *Ui()->Screen();
|
||||
|
||||
Overlay.Draw(ColorRGBA(0, 0, 0, 0.33f), IGraphics::CORNER_NONE, 0.0f);
|
||||
CUIRect Background;
|
||||
Overlay.VMargin(150.0f, &Background);
|
||||
Background.HMargin(50.0f, &Background);
|
||||
Background.Draw(ColorRGBA(0, 0, 0, 0.80f), IGraphics::CORNER_ALL, 5.0f);
|
||||
|
||||
Background.Margin(10.0f, &Prompt);
|
||||
|
||||
Prompt.VSplitMid(nullptr, &PromptBox);
|
||||
|
||||
Prompt.HSplitTop(16.0f, &PromptBox, &Suggestions);
|
||||
PromptBox.Draw(ColorRGBA(0, 0, 0, 0.75f), IGraphics::CORNER_ALL, 2.0f);
|
||||
Suggestions.y += 6.0f;
|
||||
|
||||
if(Ui()->DoClearableEditBox(&m_PromptInput, &PromptBox, 10.0f) || m_ResetFilterResults)
|
||||
{
|
||||
m_PromptSelectedIndex = 0;
|
||||
m_vpFilteredPromptList.clear();
|
||||
if(m_ResetFilterResults && m_pLastAction && !m_pLastAction->Disabled())
|
||||
{
|
||||
m_vpFilteredPromptList.push_back(m_pLastAction);
|
||||
}
|
||||
for(auto *pQuickAction : m_vQuickActions)
|
||||
{
|
||||
if(pQuickAction->Disabled())
|
||||
continue;
|
||||
|
||||
if(m_PromptInput.IsEmpty() || FuzzyMatch(pQuickAction->Label(), m_PromptInput.GetString()))
|
||||
{
|
||||
bool Skip = false;
|
||||
if(m_ResetFilterResults)
|
||||
if(pQuickAction == m_pLastAction)
|
||||
Skip = true;
|
||||
if(!Skip)
|
||||
m_vpFilteredPromptList.push_back(pQuickAction);
|
||||
}
|
||||
}
|
||||
m_ResetFilterResults = false;
|
||||
}
|
||||
|
||||
s_ListBox.SetActive(!Ui()->IsPopupOpen());
|
||||
s_ListBox.DoStart(15.0f, m_vpFilteredPromptList.size(), 1, 5, m_PromptSelectedIndex, &Suggestions, false);
|
||||
|
||||
for(size_t i = 0; i < m_vpFilteredPromptList.size(); i++)
|
||||
{
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(m_vpFilteredPromptList[i], m_PromptSelectedIndex >= 0 && (size_t)m_PromptSelectedIndex == i);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
CUIRect LabelColumn, DescColumn;
|
||||
Item.m_Rect.VSplitLeft(5.0f, nullptr, &LabelColumn);
|
||||
LabelColumn.VSplitLeft(100.0f, &LabelColumn, &DescColumn);
|
||||
LabelColumn.VSplitRight(5.0f, &LabelColumn, nullptr);
|
||||
|
||||
SLabelProperties Props;
|
||||
Props.m_MaxWidth = LabelColumn.w;
|
||||
Props.m_EllipsisAtEnd = true;
|
||||
Ui()->DoLabel(&LabelColumn, m_vpFilteredPromptList[i]->Label(), 10.0f, TEXTALIGN_ML, Props);
|
||||
|
||||
Props.m_MaxWidth = DescColumn.w;
|
||||
ColorRGBA DescColor = TextRender()->DefaultTextColor();
|
||||
DescColor.a = Item.m_Selected ? 1.0f : 0.8f;
|
||||
TextRender()->TextColor(DescColor);
|
||||
Ui()->DoLabel(&DescColumn, m_vpFilteredPromptList[i]->Description(), 10.0f, TEXTALIGN_MR, Props);
|
||||
TextRender()->TextColor(TextRender()->DefaultTextColor());
|
||||
}
|
||||
|
||||
const int NewSelected = s_ListBox.DoEnd();
|
||||
if(m_PromptSelectedIndex != NewSelected)
|
||||
{
|
||||
m_PromptSelectedIndex = NewSelected;
|
||||
}
|
||||
|
||||
if(s_ListBox.WasItemActivated())
|
||||
{
|
||||
if(m_PromptSelectedIndex >= 0)
|
||||
{
|
||||
CQuickAction *pBtn = m_vpFilteredPromptList[m_PromptSelectedIndex];
|
||||
SetInactive();
|
||||
pBtn->Call();
|
||||
m_pLastAction = pBtn;
|
||||
}
|
||||
}
|
||||
}
|
29
src/game/editor/prompt.h
Normal file
29
src/game/editor/prompt.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef GAME_EDITOR_PROMPT_H
|
||||
#define GAME_EDITOR_PROMPT_H
|
||||
|
||||
#include <game/client/lineinput.h>
|
||||
#include <game/client/ui_rect.h>
|
||||
#include <game/editor/quick_action.h>
|
||||
|
||||
#include "component.h"
|
||||
|
||||
class CPrompt : public CEditorComponent
|
||||
{
|
||||
bool m_ResetFilterResults = true;
|
||||
CQuickAction *m_pLastAction = nullptr;
|
||||
int m_PromptSelectedIndex = -1;
|
||||
|
||||
std::vector<CQuickAction *> m_vpFilteredPromptList;
|
||||
std::vector<CQuickAction *> m_vQuickActions;
|
||||
CLineInputBuffered<512> m_PromptInput;
|
||||
|
||||
public:
|
||||
void OnInit(CEditor *pEditor) override;
|
||||
bool OnInput(const IInput::CEvent &Event) override;
|
||||
void OnRender(CUIRect _) override;
|
||||
bool IsActive();
|
||||
void SetActive();
|
||||
void SetInactive();
|
||||
};
|
||||
|
||||
#endif
|
69
src/game/editor/quick_action.h
Normal file
69
src/game/editor/quick_action.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef GAME_EDITOR_QUICK_ACTION_H
|
||||
#define GAME_EDITOR_QUICK_ACTION_H
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
typedef std::function<void()> FButtonClickCallback;
|
||||
typedef std::function<bool()> FButtonDisabledCallback;
|
||||
typedef std::function<bool()> FButtonActiveCallback;
|
||||
typedef std::function<int()> FButtonColorCallback;
|
||||
|
||||
class CQuickAction
|
||||
{
|
||||
private:
|
||||
const char *m_pLabel;
|
||||
const char *m_pDescription;
|
||||
|
||||
FButtonClickCallback m_pfnCallback;
|
||||
FButtonDisabledCallback m_pfnDisabledCallback;
|
||||
FButtonActiveCallback m_pfnActiveCallback;
|
||||
FButtonColorCallback m_pfnColorCallback;
|
||||
|
||||
public:
|
||||
CQuickAction(
|
||||
const char *pLabel,
|
||||
const char *pDescription,
|
||||
FButtonClickCallback pfnCallback,
|
||||
FButtonDisabledCallback pfnDisabledCallback,
|
||||
FButtonActiveCallback pfnActiveCallback,
|
||||
FButtonColorCallback pfnColorCallback) :
|
||||
m_pLabel(pLabel),
|
||||
m_pDescription(pDescription),
|
||||
m_pfnCallback(std::move(pfnCallback)),
|
||||
m_pfnDisabledCallback(std::move(pfnDisabledCallback)),
|
||||
m_pfnActiveCallback(std::move(pfnActiveCallback)),
|
||||
m_pfnColorCallback(std::move(pfnColorCallback))
|
||||
{
|
||||
}
|
||||
|
||||
// code to run when the action is triggered
|
||||
void Call() const { m_pfnCallback(); }
|
||||
|
||||
// bool that indicates if the action can be performed not or not
|
||||
bool Disabled() { return m_pfnDisabledCallback(); }
|
||||
|
||||
// bool that indicates if the action is currently running
|
||||
// only applies to actions that can be turned on or off like proof borders
|
||||
bool Active() { return m_pfnActiveCallback(); }
|
||||
|
||||
// color "enum" that represents the state of the quick actions button
|
||||
// used as Checked argument for DoButton_Editor()
|
||||
int Color() { return m_pfnColorCallback(); }
|
||||
|
||||
const char *Label() const { return m_pLabel; }
|
||||
|
||||
// skips to the part of the label after the first colon
|
||||
// useful for buttons that only show the state
|
||||
const char *LabelShort() const
|
||||
{
|
||||
const char *pShort = str_find(m_pLabel, ": ");
|
||||
if(!pShort)
|
||||
return m_pLabel;
|
||||
return pShort + 2;
|
||||
}
|
||||
|
||||
const char *Description() const { return m_pDescription; }
|
||||
};
|
||||
|
||||
#endif
|
71
src/game/editor/quick_actions.cpp
Normal file
71
src/game/editor/quick_actions.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include <game/mapitems.h>
|
||||
|
||||
#include "editor.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()
|
||||
{
|
||||
m_Map.NewGroup();
|
||||
m_SelectedGroup = m_Map.m_vpGroups.size() - 1;
|
||||
m_EditorHistory.RecordAction(std::make_shared<CEditorActionGroup>(this, m_SelectedGroup, false));
|
||||
}
|
||||
|
||||
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);
|
||||
pTileLayer->m_pEditor = this;
|
||||
m_Map.m_vpGroups[m_SelectedGroup]->AddLayer(pTileLayer);
|
||||
int LayerIndex = m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers.size() - 1;
|
||||
SelectLayer(LayerIndex);
|
||||
m_Map.m_vpGroups[m_SelectedGroup]->m_Collapse = false;
|
||||
m_EditorHistory.RecordAction(std::make_shared<CEditorActionAddLayer>(this, m_SelectedGroup, LayerIndex));
|
||||
}
|
||||
|
||||
bool CEditor::IsNonGameTileLayerSelected() const
|
||||
{
|
||||
std::shared_ptr<CLayer> pLayer = GetSelectedLayer(0);
|
||||
if(!pLayer)
|
||||
return false;
|
||||
if(pLayer->m_Type != LAYERTYPE_TILES)
|
||||
return false;
|
||||
if(
|
||||
pLayer == m_Map.m_pGameLayer ||
|
||||
pLayer == m_Map.m_pFrontLayer ||
|
||||
pLayer == m_Map.m_pSwitchLayer ||
|
||||
pLayer == m_Map.m_pTeleLayer ||
|
||||
pLayer == m_Map.m_pSpeedupLayer ||
|
||||
pLayer == m_Map.m_pTuneLayer)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEditor::LayerSelectImage()
|
||||
{
|
||||
if(!IsNonGameTileLayerSelected())
|
||||
return;
|
||||
|
||||
std::shared_ptr<CLayer> pLayer = GetSelectedLayer(0);
|
||||
std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(pLayer);
|
||||
|
||||
static SLayerPopupContext s_LayerPopupContext = {};
|
||||
s_LayerPopupContext.m_pEditor = this;
|
||||
Ui()->DoPopupMenu(&s_LayerPopupContext, Ui()->MouseX(), Ui()->MouseY(), 120, 270, &s_LayerPopupContext, PopupLayer);
|
||||
PopupSelectImageInvoke(pTiles->m_Image, Ui()->MouseX(), Ui()->MouseY());
|
||||
}
|
213
src/game/editor/quick_actions.h
Normal file
213
src/game/editor/quick_actions.h
Normal file
|
@ -0,0 +1,213 @@
|
|||
// This file can be included several times.
|
||||
|
||||
#ifndef REGISTER_QUICK_ACTION
|
||||
#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description)
|
||||
#endif
|
||||
|
||||
#define ALWAYS_FALSE []() -> bool { return false; }
|
||||
#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(
|
||||
AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group")
|
||||
REGISTER_QUICK_ACTION(
|
||||
Refocus, "Refocus", [&]() { MapView()->Focus(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "[HOME] Restore map focus")
|
||||
REGISTER_QUICK_ACTION(
|
||||
Proof,
|
||||
"Proof",
|
||||
[&]() { MapView()->ProofMode()->Toggle(); },
|
||||
ALWAYS_FALSE,
|
||||
[&]() -> bool { return MapView()->ProofMode()->IsEnabled(); },
|
||||
DEFAULT_BTN,
|
||||
"Toggles proof borders. These borders represent the area that a player can see with default zoom.")
|
||||
REGISTER_QUICK_ACTION(
|
||||
AddTileLayer, "Add tile layer", [&]() { AddTileLayer(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Creates a new tile layer.")
|
||||
REGISTER_QUICK_ACTION(
|
||||
SaveAs,
|
||||
"Save As",
|
||||
[&]() { InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save As", "maps", true, CEditor::CallbackSaveMap, this); },
|
||||
ALWAYS_FALSE,
|
||||
ALWAYS_FALSE,
|
||||
DEFAULT_BTN,
|
||||
"Saves the current map under a new name (ctrl+shift+s)")
|
||||
REGISTER_QUICK_ACTION(
|
||||
LoadCurrentMap,
|
||||
"Load Current Map",
|
||||
[&]() {
|
||||
if(HasUnsavedData())
|
||||
{
|
||||
m_PopupEventType = POPEVENT_LOADCURRENT;
|
||||
m_PopupEventActivated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadCurrentMap();
|
||||
}
|
||||
},
|
||||
ALWAYS_FALSE,
|
||||
ALWAYS_FALSE,
|
||||
DEFAULT_BTN,
|
||||
"Opens the current in game map for editing (ctrl+alt+l)")
|
||||
REGISTER_QUICK_ACTION(
|
||||
Envelopes,
|
||||
"Envelopes",
|
||||
[&]() { m_ActiveExtraEditor = m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES ? EXTRAEDITOR_NONE : EXTRAEDITOR_ENVELOPES; },
|
||||
ALWAYS_FALSE,
|
||||
ALWAYS_FALSE,
|
||||
[&]() -> int { return m_ShowPicker ? -1 : m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES; },
|
||||
"Toggles the envelope editor.")
|
||||
REGISTER_QUICK_ACTION(
|
||||
AddImage,
|
||||
"Add Image",
|
||||
[&]() { InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", false, AddImage, this); },
|
||||
ALWAYS_FALSE,
|
||||
ALWAYS_FALSE,
|
||||
DEFAULT_BTN,
|
||||
"Load a new image to use in the map")
|
||||
REGISTER_QUICK_ACTION(
|
||||
LayerPropAddImage,
|
||||
"Layer: Add Image",
|
||||
[&]() { LayerSelectImage(); },
|
||||
[&]() -> bool { return !IsNonGameTileLayerSelected(); },
|
||||
ALWAYS_FALSE,
|
||||
DEFAULT_BTN,
|
||||
"Pick mapres image for currently selected layer")
|
||||
REGISTER_QUICK_ACTION(
|
||||
ShowInfoOff,
|
||||
"Show Info: Off",
|
||||
[&]() {
|
||||
m_ShowTileInfo = SHOW_TILE_OFF;
|
||||
m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
},
|
||||
ALWAYS_FALSE,
|
||||
[&]() -> bool { return m_ShowTileInfo == SHOW_TILE_OFF; },
|
||||
DEFAULT_BTN,
|
||||
"Do not show tile information")
|
||||
REGISTER_QUICK_ACTION(
|
||||
ShowInfoDec,
|
||||
"Show Info: Dec",
|
||||
[&]() {
|
||||
m_ShowTileInfo = SHOW_TILE_DECIMAL;
|
||||
m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
},
|
||||
ALWAYS_FALSE,
|
||||
[&]() -> bool { return m_ShowTileInfo == SHOW_TILE_DECIMAL; },
|
||||
DEFAULT_BTN,
|
||||
"[ctrl+i] Show tile information")
|
||||
REGISTER_QUICK_ACTION(
|
||||
ShowInfoHex,
|
||||
"Show Info: Hex",
|
||||
[&]() {
|
||||
m_ShowTileInfo = SHOW_TILE_HEXADECIMAL;
|
||||
m_ShowEnvelopePreview = SHOWENV_NONE;
|
||||
},
|
||||
ALWAYS_FALSE,
|
||||
[&]() -> bool { return m_ShowTileInfo == SHOW_TILE_HEXADECIMAL; },
|
||||
DEFAULT_BTN,
|
||||
"[ctrl+shift+i] Show tile information in hexadecimal")
|
||||
|
||||
#undef ALWAYS_FALSE
|
||||
#undef DEFAULT_BTN
|
|
@ -260,7 +260,7 @@ void CCharacter::HandleNinja()
|
|||
GameServer()->CreateDamageInd(m_Pos, 0, NinjaTime / Server()->TickSpeed(), TeamMask() & GameServer()->ClientsMaskExcludeClientVersionAndHigher(VERSION_DDNET_NEW_HUD));
|
||||
}
|
||||
|
||||
m_Armor = clamp(10 - (NinjaTime / 15), 0, 10);
|
||||
GameServer()->m_pController->SetArmorProgress(this, NinjaTime);
|
||||
|
||||
// force ninja Weapon
|
||||
SetWeapon(WEAPON_NINJA);
|
||||
|
@ -442,7 +442,7 @@ void CCharacter::FireWeapon()
|
|||
if(m_PainSoundTimer <= 0 && !(m_LatestPrevInput.m_Fire & 1))
|
||||
{
|
||||
m_PainSoundTimer = 1 * Server()->TickSpeed();
|
||||
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG, TeamMask());
|
||||
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ void CCharacter::FireWeapon()
|
|||
{
|
||||
// reset objects Hit
|
||||
m_NumObjectsHit = 0;
|
||||
GameServer()->CreateSound(m_Pos, SOUND_HAMMER_FIRE, TeamMask());
|
||||
GameServer()->CreateSound(m_Pos, SOUND_HAMMER_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc)
|
||||
|
||||
Antibot()->OnHammerFire(m_pPlayer->GetCid());
|
||||
|
||||
|
@ -567,7 +567,7 @@ void CCharacter::FireWeapon()
|
|||
MouseTarget // MouseTarget
|
||||
);
|
||||
|
||||
GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask());
|
||||
GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc)
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -589,7 +589,7 @@ void CCharacter::FireWeapon()
|
|||
m_Core.m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
|
||||
m_Core.m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
|
||||
|
||||
GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE, TeamMask());
|
||||
GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2055,7 +2055,7 @@ void CCharacter::ForceSetRescue(int RescueMode)
|
|||
void CCharacter::DDRaceTick()
|
||||
{
|
||||
mem_copy(&m_Input, &m_SavedInput, sizeof(m_Input));
|
||||
m_Armor = clamp(10 - (m_FreezeTime / 15), 0, 10);
|
||||
GameServer()->m_pController->SetArmorProgress(this, m_FreezeTime);
|
||||
if(m_Input.m_Direction != 0 || m_Input.m_Jump != 0)
|
||||
m_LastMove = Server()->Tick();
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
|
|||
{
|
||||
pHit->UnFreeze();
|
||||
}
|
||||
pHit->TakeDamage(vec2(0, 0), 0, m_Owner, m_Type);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,6 +177,8 @@ void CProjectile::Tick()
|
|||
pChr->Freeze();
|
||||
}
|
||||
}
|
||||
else if(pTargetChr)
|
||||
pTargetChr->TakeDamage(vec2(0, 0), 0, m_Owner, m_Type);
|
||||
|
||||
if(pOwnerChar && !GameLayerClipped(ColPos) &&
|
||||
((m_Type == WEAPON_GRENADE && pOwnerChar->HasTelegunGrenade()) || (m_Type == WEAPON_GUN && pOwnerChar->HasTelegunGun())))
|
||||
|
|
|
@ -95,6 +95,7 @@ public:
|
|||
virtual void OnCharacterSpawn(class CCharacter *pChr);
|
||||
|
||||
virtual void HandleCharacterTiles(class CCharacter *pChr, int MapIndex);
|
||||
virtual void SetArmorProgress(CCharacter *pCharacer, int Progress){};
|
||||
|
||||
/*
|
||||
Function: OnEntity
|
||||
|
|
|
@ -112,6 +112,11 @@ void CGameControllerDDRace::HandleCharacterTiles(CCharacter *pChr, int MapIndex)
|
|||
}
|
||||
}
|
||||
|
||||
void CGameControllerDDRace::SetArmorProgress(CCharacter *pCharacer, int Progress)
|
||||
{
|
||||
pCharacer->SetArmor(clamp(10 - (Progress / 15), 0, 10));
|
||||
}
|
||||
|
||||
void CGameControllerDDRace::OnPlayerConnect(CPlayer *pPlayer)
|
||||
{
|
||||
IGameController::OnPlayerConnect(pPlayer);
|
||||
|
|
|
@ -13,6 +13,7 @@ public:
|
|||
CScore *Score();
|
||||
|
||||
void HandleCharacterTiles(class CCharacter *pChr, int MapIndex) override;
|
||||
void SetArmorProgress(CCharacter *pCharacer, int Progress) override;
|
||||
|
||||
void OnPlayerConnect(class CPlayer *pPlayer) override;
|
||||
void OnPlayerDisconnect(class CPlayer *pPlayer, const char *pReason) override;
|
||||
|
|
|
@ -78,16 +78,16 @@ void CTeeInfo::ToSixup()
|
|||
{
|
||||
int ColorBody = ColorHSLA(m_ColorBody).UnclampLighting().Pack(ms_DarkestLGT7);
|
||||
int ColorFeet = ColorHSLA(m_ColorFeet).UnclampLighting().Pack(ms_DarkestLGT7);
|
||||
m_aUseCustomColors[0] = true;
|
||||
m_aUseCustomColors[1] = true;
|
||||
m_aUseCustomColors[2] = true;
|
||||
m_aUseCustomColors[3] = true;
|
||||
m_aUseCustomColors[4] = true;
|
||||
m_aSkinPartColors[0] = ColorBody;
|
||||
m_aSkinPartColors[1] = 0x22FFFFFF;
|
||||
m_aSkinPartColors[2] = ColorBody;
|
||||
m_aSkinPartColors[3] = ColorBody;
|
||||
m_aSkinPartColors[4] = ColorFeet;
|
||||
m_aUseCustomColors[protocol7::SKINPART_BODY] = true;
|
||||
m_aUseCustomColors[protocol7::SKINPART_MARKING] = true;
|
||||
m_aUseCustomColors[protocol7::SKINPART_DECORATION] = true;
|
||||
m_aUseCustomColors[protocol7::SKINPART_HANDS] = true;
|
||||
m_aUseCustomColors[protocol7::SKINPART_FEET] = true;
|
||||
m_aSkinPartColors[protocol7::SKINPART_BODY] = ColorBody;
|
||||
m_aSkinPartColors[protocol7::SKINPART_MARKING] = 0x22FFFFFF;
|
||||
m_aSkinPartColors[protocol7::SKINPART_DECORATION] = ColorBody;
|
||||
m_aSkinPartColors[protocol7::SKINPART_HANDS] = ColorBody;
|
||||
m_aSkinPartColors[protocol7::SKINPART_FEET] = ColorFeet;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,10 @@ void CTeeInfo::FromSixup()
|
|||
|
||||
str_copy(m_aSkinName, g_aStdSkins[BestSkin].m_aSkinName, sizeof(m_aSkinName));
|
||||
m_UseCustomColor = true;
|
||||
m_ColorBody = ColorHSLA(m_aUseCustomColors[0] ? m_aSkinPartColors[0] : 255).UnclampLighting(ms_DarkestLGT7).Pack(ColorHSLA::DARKEST_LGT);
|
||||
m_ColorFeet = ColorHSLA(m_aUseCustomColors[4] ? m_aSkinPartColors[4] : 255).UnclampLighting(ms_DarkestLGT7).Pack(ColorHSLA::DARKEST_LGT);
|
||||
m_ColorBody = ColorHSLA(m_aUseCustomColors[protocol7::SKINPART_BODY] ? m_aSkinPartColors[protocol7::SKINPART_BODY] : 255)
|
||||
.UnclampLighting(ms_DarkestLGT7)
|
||||
.Pack(ColorHSLA::DARKEST_LGT);
|
||||
m_ColorFeet = ColorHSLA(m_aUseCustomColors[protocol7::SKINPART_FEET] ? m_aSkinPartColors[protocol7::SKINPART_FEET] : 255)
|
||||
.UnclampLighting(ms_DarkestLGT7)
|
||||
.Pack(ColorHSLA::DARKEST_LGT);
|
||||
}
|
||||
|
|
|
@ -109,8 +109,8 @@ void cxxbridge1$IConsole_IResult$GetString(const ::IConsole_IResult &self, ::std
|
|||
}
|
||||
|
||||
void cxxbridge1$IConsole_IResult$GetColor(const ::IConsole_IResult &self, ::std::uint32_t Index, bool Light, ::ColorHSLA *return$) noexcept {
|
||||
::ColorHSLA (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor;
|
||||
new (return$) ::ColorHSLA((self.*GetColor$)(Index, Light));
|
||||
std::optional<::ColorHSLA> (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor;
|
||||
new(return$)::ColorHSLA((self.*GetColor$)(Index, Light).value_or(::ColorHSLA(0, 0, 0)));
|
||||
}
|
||||
|
||||
::std::int32_t cxxbridge1$IConsole_IResult$NumArguments(const ::IConsole_IResult &self) noexcept {
|
||||
|
|
Loading…
Reference in a new issue