mirror of
https://github.com/ddnet/ddnet.git
synced 2024-09-19 09:12: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.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
|
||||||
|
@ -2500,8 +2501,13 @@ if(CLIENT)
|
||||||
mapitems/sound.cpp
|
mapitems/sound.cpp
|
||||||
mapitems/sound.h
|
mapitems/sound.h
|
||||||
popups.cpp
|
popups.cpp
|
||||||
|
prompt.cpp
|
||||||
|
prompt.h
|
||||||
proof_mode.cpp
|
proof_mode.cpp
|
||||||
proof_mode.h
|
proof_mode.h
|
||||||
|
quick_action.h
|
||||||
|
quick_actions.cpp
|
||||||
|
quick_actions.h
|
||||||
smooth_value.cpp
|
smooth_value.cpp
|
||||||
smooth_value.h
|
smooth_value.h
|
||||||
tileart.cpp
|
tileart.cpp
|
||||||
|
|
|
@ -631,7 +631,7 @@ Loading DDNet Client
|
||||||
== Загрузка DDNet Client
|
== Загрузка DDNet Client
|
||||||
|
|
||||||
Normal message
|
Normal message
|
||||||
== Обычное с.
|
== Обычное
|
||||||
|
|
||||||
Connecting dummy
|
Connecting dummy
|
||||||
== Подключение дамми
|
== Подключение дамми
|
||||||
|
@ -643,10 +643,10 @@ Save ghost
|
||||||
== Сохранять тень
|
== Сохранять тень
|
||||||
|
|
||||||
DDNet Client updated!
|
DDNet Client updated!
|
||||||
== DDNet Client обновлён!
|
== DDNet клиент обновлён!
|
||||||
|
|
||||||
Highlighted message
|
Highlighted message
|
||||||
== Выделенное с.
|
== Выделенное
|
||||||
|
|
||||||
Demo
|
Demo
|
||||||
== Демо
|
== Демо
|
||||||
|
@ -724,7 +724,7 @@ Downloading %s:
|
||||||
== Скачивание %s:
|
== Скачивание %s:
|
||||||
|
|
||||||
Update failed! Check log…
|
Update failed! Check log…
|
||||||
== Ошибка. Проверьте логи…
|
== Не удалось обновиться! Подробности в логах…
|
||||||
|
|
||||||
Restart
|
Restart
|
||||||
== Рестарт
|
== Рестарт
|
||||||
|
@ -844,7 +844,7 @@ DDNet
|
||||||
== DDNet
|
== DDNet
|
||||||
|
|
||||||
Friend message
|
Friend message
|
||||||
== Дружеское с.
|
== Дружеское
|
||||||
|
|
||||||
Save the best demo of each race
|
Save the best demo of each race
|
||||||
== Сохранять лучшее демо каждой карты
|
== Сохранять лучшее демо каждой карты
|
||||||
|
@ -916,10 +916,10 @@ Ratio
|
||||||
== Соотношение
|
== Соотношение
|
||||||
|
|
||||||
Net
|
Net
|
||||||
== Сеть
|
== Сальдо
|
||||||
|
|
||||||
FPM
|
FPM
|
||||||
== FPM
|
== У/мин
|
||||||
|
|
||||||
Spree
|
Spree
|
||||||
== Серия
|
== Серия
|
||||||
|
@ -940,7 +940,7 @@ Grabs
|
||||||
== 9+ упоминаний
|
== 9+ упоминаний
|
||||||
|
|
||||||
Client message
|
Client message
|
||||||
== Клиентское с.
|
== Клиентское
|
||||||
|
|
||||||
Warning
|
Warning
|
||||||
== Предупреждение
|
== Предупреждение
|
||||||
|
@ -973,7 +973,7 @@ Run server
|
||||||
== Запустить сервер
|
== Запустить сервер
|
||||||
|
|
||||||
Server executable not found, can't run server
|
Server executable not found, can't run server
|
||||||
== Файл сервера не найден, невозможно запустить
|
== Файл сервера не найден, не удалось запустить сервер
|
||||||
|
|
||||||
Editor
|
Editor
|
||||||
== Редактор
|
== Редактор
|
||||||
|
@ -1883,7 +1883,7 @@ Could not resolve connect address '%s'. See local console for details.
|
||||||
== Не удалось определить адрес подключения '%s'. Подробности в локальной консоли.
|
== Не удалось определить адрес подключения '%s'. Подробности в локальной консоли.
|
||||||
|
|
||||||
Connect address error
|
Connect address error
|
||||||
== Ошибка подключения сервера
|
== Ошибка адреса подключения
|
||||||
|
|
||||||
Could not connect dummy
|
Could not connect dummy
|
||||||
== Невозможно подключить дамми
|
== Невозможно подключить дамми
|
||||||
|
@ -1892,34 +1892,34 @@ Dummy is not allowed on this server
|
||||||
== Дамми не разрешен на этом сервере
|
== Дамми не разрешен на этом сервере
|
||||||
|
|
||||||
Please wait…
|
Please wait…
|
||||||
== Пожалуйста подождите…
|
== Пожалуйста, подождите…
|
||||||
|
|
||||||
Show client IDs (scoreboard, chat, spectator)
|
Show client IDs (scoreboard, chat, spectator)
|
||||||
== Показывать ID клиента (Табло, чат, наблюдатель)
|
== Показывать ID клиента (табло, чат, наблюдатель)
|
||||||
|
|
||||||
Normal:
|
Normal:
|
||||||
== Обычный:
|
== Обычный:
|
||||||
|
|
||||||
Team:
|
Team:
|
||||||
== Команда:
|
== В команде:
|
||||||
|
|
||||||
Dummy settings
|
Dummy settings
|
||||||
== Настройки дамми
|
== Настройки дамми
|
||||||
|
|
||||||
Toggle to edit your dummy settings
|
Toggle to edit your dummy settings
|
||||||
== Нажмите чтоб изменить настройки дамми
|
== Нажмите, чтобы изменить настройки дамми
|
||||||
|
|
||||||
Randomize
|
Randomize
|
||||||
== Перемешать
|
== Случайный
|
||||||
|
|
||||||
Are you sure that you want to delete '%s'?
|
Are you sure that you want to delete '%s'?
|
||||||
== Вы уверены что хотите удалить '%s'?
|
== Вы уверены, что хотите удалить '%s'?
|
||||||
|
|
||||||
Delete skin
|
Delete skin
|
||||||
== Удалить скин
|
== Удалить скин
|
||||||
|
|
||||||
Basic
|
Basic
|
||||||
== Базовый
|
== Пресеты
|
||||||
|
|
||||||
Custom
|
Custom
|
||||||
== Кастомизация
|
== Кастомизация
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
# 3edcxzaq1 2020-06-25 00:00:00
|
# 3edcxzaq1 2020-06-25 00:00:00
|
||||||
# cur.ie 2020-09-28 00:00:00
|
# cur.ie 2020-09-28 00:00:00
|
||||||
# simpygirl 2022-02-20 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 #####
|
##### /authors #####
|
||||||
|
|
||||||
##### translated strings #####
|
##### translated strings #####
|
||||||
|
@ -1868,52 +1868,52 @@ https://wiki.ddnet.org/wiki/Mapping
|
||||||
== https://wiki.ddnet.org/wiki/Mapping
|
== https://wiki.ddnet.org/wiki/Mapping
|
||||||
|
|
||||||
Could not resolve connect address '%s'. See local console for details.
|
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
|
Connect address error
|
||||||
==
|
== Anslutnings problem
|
||||||
|
|
||||||
Could not connect dummy
|
Could not connect dummy
|
||||||
==
|
== Kunde inte ansluta dummy
|
||||||
|
|
||||||
Dummy is not allowed on this server
|
Dummy is not allowed on this server
|
||||||
==
|
== Dummy är inte tillåten på denna server
|
||||||
|
|
||||||
Please wait…
|
Please wait…
|
||||||
==
|
== Vänligen vänta…
|
||||||
|
|
||||||
Show client IDs (scoreboard, chat, spectator)
|
Show client IDs (scoreboard, chat, spectator)
|
||||||
==
|
== Visa klient IDen (poänglistan, chatt, åskadarmeny)
|
||||||
|
|
||||||
Normal:
|
Normal:
|
||||||
==
|
== Normal:
|
||||||
|
|
||||||
Team:
|
Team:
|
||||||
==
|
== Lag:
|
||||||
|
|
||||||
Dummy settings
|
Dummy settings
|
||||||
==
|
== Dummy inställningar
|
||||||
|
|
||||||
Toggle to edit your dummy settings
|
Toggle to edit your dummy settings
|
||||||
==
|
== Växla för att ändra dina dummy inställningar
|
||||||
|
|
||||||
Randomize
|
Randomize
|
||||||
==
|
== Slumpa
|
||||||
|
|
||||||
Are you sure that you want to delete '%s'?
|
Are you sure that you want to delete '%s'?
|
||||||
==
|
== Är du säker att du vill ta bort '%s'?
|
||||||
|
|
||||||
Delete skin
|
Delete skin
|
||||||
==
|
== Ta bort skin
|
||||||
|
|
||||||
Basic
|
Basic
|
||||||
==
|
== Enkel
|
||||||
|
|
||||||
Custom
|
Custom
|
||||||
==
|
== Anpassa
|
||||||
|
|
||||||
Unable to delete skin
|
Unable to delete skin
|
||||||
==
|
== Kunde inte ta bort skin
|
||||||
|
|
||||||
Customize
|
Customize
|
||||||
==
|
== Ändra
|
||||||
|
|
|
@ -228,10 +228,8 @@ int CSound::Init()
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_MixingRate = g_Config.m_SndRate;
|
|
||||||
|
|
||||||
SDL_AudioSpec Format, FormatOut;
|
SDL_AudioSpec Format, FormatOut;
|
||||||
Format.freq = m_MixingRate;
|
Format.freq = g_Config.m_SndRate;
|
||||||
Format.format = AUDIO_S16;
|
Format.format = AUDIO_S16;
|
||||||
Format.channels = 2;
|
Format.channels = 2;
|
||||||
Format.samples = g_Config.m_SndBufferSize;
|
Format.samples = g_Config.m_SndBufferSize;
|
||||||
|
@ -239,7 +237,7 @@ int CSound::Init()
|
||||||
Format.userdata = this;
|
Format.userdata = this;
|
||||||
|
|
||||||
// Open the audio device and start playing sound!
|
// 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)
|
if(m_Device == 0)
|
||||||
{
|
{
|
||||||
dbg_msg("sound", "unable to open audio: %s", SDL_GetError());
|
dbg_msg("sound", "unable to open audio: %s", SDL_GetError());
|
||||||
|
@ -248,6 +246,7 @@ int CSound::Init()
|
||||||
else
|
else
|
||||||
dbg_msg("sound", "sound init successful using audio driver '%s'", SDL_GetCurrentAudioDriver());
|
dbg_msg("sound", "sound init successful using audio driver '%s'", SDL_GetCurrentAudioDriver());
|
||||||
|
|
||||||
|
m_MixingRate = FormatOut.freq;
|
||||||
m_MaxFrames = FormatOut.samples * 2;
|
m_MaxFrames = FormatOut.samples * 2;
|
||||||
#if defined(CONF_VIDEORECORDER)
|
#if defined(CONF_VIDEORECORDER)
|
||||||
m_MaxFrames = maximum<uint32_t>(m_MaxFrames, 1024 * 2); // make the buffer bigger just in case
|
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 int GetInteger(unsigned Index) const = 0;
|
||||||
virtual float GetFloat(unsigned Index) const = 0;
|
virtual float GetFloat(unsigned Index) const = 0;
|
||||||
virtual const char *GetString(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;
|
virtual void RemoveArgument(unsigned Index) = 0;
|
||||||
|
|
||||||
|
|
|
@ -111,22 +111,29 @@ void SIntConfigVariable::ResetToOld()
|
||||||
void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUserData)
|
void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
SColorConfigVariable *pData = static_cast<SColorConfigVariable *>(pUserData);
|
SColorConfigVariable *pData = static_cast<SColorConfigVariable *>(pUserData);
|
||||||
|
char aBuf[IConsole::CMDLINE_LENGTH + 64];
|
||||||
if(pResult->NumArguments())
|
if(pResult->NumArguments())
|
||||||
{
|
{
|
||||||
if(pData->CheckReadOnly())
|
if(pData->CheckReadOnly())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ColorHSLA Color = pResult->GetColor(0, pData->m_Light);
|
const auto Color = pResult->GetColor(0, pData->m_Light);
|
||||||
const unsigned Value = Color.Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
|
if(Color)
|
||||||
|
{
|
||||||
|
const unsigned Value = Color->Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
|
||||||
|
|
||||||
*pData->m_pVariable = Value;
|
*pData->m_pVariable = Value;
|
||||||
if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME)
|
if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME)
|
||||||
pData->m_OldValue = Value;
|
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
|
else
|
||||||
{
|
{
|
||||||
char aBuf[256];
|
|
||||||
str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable);
|
str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable);
|
||||||
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
|
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);
|
SColorConfigVariable *pColorVariable = static_cast<SColorConfigVariable *>(pVariable);
|
||||||
const float Darkest = pColorVariable->m_Light ? 0.5f : 0.0f;
|
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);
|
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.Pack(Darkest, pColorVariable->m_Alpha));
|
pColorVariable->SetValue(Value.value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha));
|
||||||
}
|
}
|
||||||
else if(pVariable->m_Type == SConfigVariable::VAR_STRING)
|
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]);
|
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)
|
if(Index >= m_NumArgs)
|
||||||
return ColorHSLA(0, 0, 0);
|
return std::nullopt;
|
||||||
|
|
||||||
const char *pStr = m_apArgs[Index];
|
const char *pStr = m_apArgs[Index];
|
||||||
if(str_isallnum(pStr) || ((pStr[0] == '-' || pStr[0] == '+') && str_isallnum(pStr + 1))) // Teeworlds Color (Packed HSL)
|
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)
|
if(Light)
|
||||||
return Hsla.UnclampLighting();
|
return Hsla.UnclampLighting();
|
||||||
return Hsla;
|
return Hsla;
|
||||||
}
|
}
|
||||||
else if(*pStr == '$') // Hex RGB/RGBA
|
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"))
|
else if(!str_comp_nocase(pStr, "red"))
|
||||||
return ColorHSLA(0.0f / 6.0f, 1, .5f);
|
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"))
|
else if(!str_comp_nocase(pStr, "black"))
|
||||||
return ColorHSLA(0, 0, 0);
|
return ColorHSLA(0, 0, 0);
|
||||||
|
|
||||||
return ColorHSLA(0, 0, 0);
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
int CConsole::ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback)
|
||||||
{
|
{
|
||||||
char Command = *pFormat;
|
char Command = *pFormat;
|
||||||
char *pStr;
|
char *pStr;
|
||||||
int Optional = 0;
|
int Optional = 0;
|
||||||
int Error = 0;
|
int Error = PARSEARGS_OK;
|
||||||
|
|
||||||
pResult->ResetVictim();
|
pResult->ResetVictim();
|
||||||
|
|
||||||
|
@ -155,7 +162,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
{
|
{
|
||||||
if(!Optional)
|
if(!Optional)
|
||||||
{
|
{
|
||||||
Error = 1;
|
Error = PARSEARGS_MISSING_VALUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +198,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
pStr++; // skip due to escape
|
pStr++; // skip due to escape
|
||||||
}
|
}
|
||||||
else if(pStr[0] == 0)
|
else if(pStr[0] == 0)
|
||||||
return 1; // return error
|
return PARSEARGS_MISSING_VALUE; // return error
|
||||||
|
|
||||||
*pDst = *pStr;
|
*pDst = *pStr;
|
||||||
pDst++;
|
pDst++;
|
||||||
|
@ -215,13 +222,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
|
|
||||||
if(Command == 'r') // rest of the string
|
if(Command == 'r') // rest of the string
|
||||||
break;
|
break;
|
||||||
else if(Command == 'v') // validate victim
|
else if(Command == 'v' || Command == 'i' || Command == 'f' || Command == 's')
|
||||||
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
|
|
||||||
pStr = str_skip_to_whitespace(pStr);
|
pStr = str_skip_to_whitespace(pStr);
|
||||||
|
|
||||||
if(pStr[0] != 0) // check for end of string
|
if(pStr[0] != 0) // check for end of string
|
||||||
|
@ -230,6 +231,32 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
pStr++;
|
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)
|
if(pVictim)
|
||||||
{
|
{
|
||||||
pResult->SetVictim(pVictim);
|
pResult->SetVictim(pVictim);
|
||||||
|
@ -487,10 +514,15 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientId, bo
|
||||||
|
|
||||||
if(Stroke || IsStrokeCommand)
|
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];
|
char aBuf[CMDLINE_LENGTH + 64];
|
||||||
str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
|
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);
|
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
|
||||||
}
|
}
|
||||||
else if(m_StoreCommands && pCommand->m_Flags & CFGFLAG_STORE)
|
else if(m_StoreCommands && pCommand->m_Flags & CFGFLAG_STORE)
|
||||||
|
|
|
@ -115,7 +115,7 @@ class CConsole : public IConsole
|
||||||
const char *GetString(unsigned Index) const override;
|
const char *GetString(unsigned Index) const override;
|
||||||
int GetInteger(unsigned Index) const override;
|
int GetInteger(unsigned Index) const override;
|
||||||
float GetFloat(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
|
void RemoveArgument(unsigned Index) override
|
||||||
{
|
{
|
||||||
|
@ -144,7 +144,16 @@ class CConsole : public IConsole
|
||||||
};
|
};
|
||||||
|
|
||||||
int ParseStart(CResult *pResult, const char *pString, int Length);
|
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
|
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
|
// proof button
|
||||||
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
|
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
|
||||||
static int s_ProofButton = 0;
|
if(DoButton_Ex(&m_QuickActionProof, m_QuickActionProof.Label(), m_QuickActionProof.Active(), &Button, 0, m_QuickActionProof.Description(), IGraphics::CORNER_L))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
MapView()->ProofMode()->Toggle();
|
m_QuickActionProof.Call();
|
||||||
}
|
}
|
||||||
|
|
||||||
TB_Top.VSplitLeft(14.0f, &Button, &TB_Top);
|
TB_Top.VSplitLeft(14.0f, &Button, &TB_Top);
|
||||||
|
@ -1254,10 +1252,9 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar)
|
||||||
// refocus button
|
// refocus button
|
||||||
{
|
{
|
||||||
TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom);
|
TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom);
|
||||||
static int s_RefocusButton = 0;
|
|
||||||
int FocusButtonChecked = MapView()->IsFocused() ? -1 : 1;
|
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)))
|
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)))
|
||||||
MapView()->Focus();
|
m_QuickActionRefocus.Call();
|
||||||
TB_Bottom.VSplitLeft(5.0f, nullptr, &TB_Bottom);
|
TB_Bottom.VSplitLeft(5.0f, nullptr, &TB_Bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4302,12 +4299,9 @@ void CEditor::RenderLayers(CUIRect LayersBox)
|
||||||
if(s_ScrollRegion.AddRect(AddGroupButton))
|
if(s_ScrollRegion.AddRect(AddGroupButton))
|
||||||
{
|
{
|
||||||
AddGroupButton.HSplitTop(RowHeight, &AddGroupButton, 0);
|
AddGroupButton.HSplitTop(RowHeight, &AddGroupButton, 0);
|
||||||
static int s_AddGroupButton = 0;
|
if(DoButton_Editor(&m_QuickActionAddGroup, m_QuickActionAddGroup.Label(), 0, &AddGroupButton, IGraphics::CORNER_R, m_QuickActionAddGroup.Description()))
|
||||||
if(DoButton_Editor(&s_AddGroupButton, "Add group", 0, &AddGroupButton, IGraphics::CORNER_R, "Adds a new group"))
|
|
||||||
{
|
{
|
||||||
m_Map.NewGroup();
|
m_QuickActionAddGroup.Call();
|
||||||
m_SelectedGroup = m_Map.m_vpGroups.size() - 1;
|
|
||||||
m_EditorHistory.RecordAction(std::make_shared<CEditorActionGroup>(this, m_SelectedGroup, false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4806,8 +4800,8 @@ void CEditor::RenderImagesList(CUIRect ToolBox)
|
||||||
{
|
{
|
||||||
AddImageButton.HSplitTop(5.0f, nullptr, &AddImageButton);
|
AddImageButton.HSplitTop(5.0f, nullptr, &AddImageButton);
|
||||||
AddImageButton.HSplitTop(RowHeight, &AddImageButton, nullptr);
|
AddImageButton.HSplitTop(RowHeight, &AddImageButton, nullptr);
|
||||||
if(DoButton_Editor(&s_AddImageButton, "Add", 0, &AddImageButton, 0, "Load a new image to use in the map"))
|
if(DoButton_Editor(&s_AddImageButton, m_QuickActionAddImage.Label(), 0, &AddImageButton, 0, m_QuickActionAddImage.Description()))
|
||||||
InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", false, AddImage, this);
|
m_QuickActionAddImage.Call();
|
||||||
}
|
}
|
||||||
s_ScrollRegion.End();
|
s_ScrollRegion.End();
|
||||||
}
|
}
|
||||||
|
@ -5750,9 +5744,9 @@ void CEditor::RenderStatusbar(CUIRect View, CUIRect *pTooltipRect)
|
||||||
CUIRect Button;
|
CUIRect Button;
|
||||||
View.VSplitRight(100.0f, &View, &Button);
|
View.VSplitRight(100.0f, &View, &Button);
|
||||||
static int s_EnvelopeButton = 0;
|
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);
|
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);
|
InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CallbackSaveCopyMap, this);
|
||||||
// ctrl+shift+s to save as
|
// ctrl+shift+s to save as
|
||||||
else if(Input()->KeyPress(KEY_S) && ModPressed && ShiftPressed)
|
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
|
// ctrl+s to save
|
||||||
else if(Input()->KeyPress(KEY_S) && ModPressed)
|
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_MapView);
|
||||||
m_vComponents.emplace_back(m_MapSettingsBackend);
|
m_vComponents.emplace_back(m_MapSettingsBackend);
|
||||||
m_vComponents.emplace_back(m_LayerSelector);
|
m_vComponents.emplace_back(m_LayerSelector);
|
||||||
|
m_vComponents.emplace_back(m_Prompt);
|
||||||
for(CEditorComponent &Component : m_vComponents)
|
for(CEditorComponent &Component : m_vComponents)
|
||||||
Component.OnInit(this);
|
Component.OnInit(this);
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -38,6 +39,8 @@
|
||||||
#include "layer_selector.h"
|
#include "layer_selector.h"
|
||||||
#include "map_view.h"
|
#include "map_view.h"
|
||||||
#include "smooth_value.h"
|
#include "smooth_value.h"
|
||||||
|
#include <game/editor/prompt.h>
|
||||||
|
#include <game/editor/quick_action.h>
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -60,7 +63,8 @@ enum
|
||||||
|
|
||||||
DIALOG_NONE = 0,
|
DIALOG_NONE = 0,
|
||||||
DIALOG_FILE,
|
DIALOG_FILE,
|
||||||
DIALOG_MAPSETTINGS_ERROR
|
DIALOG_MAPSETTINGS_ERROR,
|
||||||
|
DIALOG_QUICK_PROMPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEditorImage;
|
class CEditorImage;
|
||||||
|
@ -278,6 +282,7 @@ class CEditor : public IEditor
|
||||||
std::vector<std::reference_wrapper<CEditorComponent>> m_vComponents;
|
std::vector<std::reference_wrapper<CEditorComponent>> m_vComponents;
|
||||||
CMapView m_MapView;
|
CMapView m_MapView;
|
||||||
CLayerSelector m_LayerSelector;
|
CLayerSelector m_LayerSelector;
|
||||||
|
CPrompt m_Prompt;
|
||||||
|
|
||||||
bool m_EditorWasUsedBefore = false;
|
bool m_EditorWasUsedBefore = false;
|
||||||
|
|
||||||
|
@ -319,7 +324,20 @@ 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 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() :
|
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_ZoomEnvelopeX(1.0f, 0.1f, 600.0f),
|
||||||
m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f),
|
m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f),
|
||||||
m_MapSettingsCommandContext(m_MapSettingsBackend.NewContext(&m_SettingsCommandInput))
|
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 <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;
|
||||||
|
|
|
@ -68,17 +68,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuFile(void *pContext, CUIRect Vie
|
||||||
|
|
||||||
View.HSplitTop(2.0f, nullptr, &View);
|
View.HSplitTop(2.0f, nullptr, &View);
|
||||||
View.HSplitTop(12.0f, &Slot, &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_QuickActionLoadCurrentMap.Call();
|
||||||
{
|
|
||||||
pEditor->m_PopupEventType = POPEVENT_LOADCURRENT;
|
|
||||||
pEditor->m_PopupEventActivated = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pEditor->LoadCurrentMap();
|
|
||||||
}
|
|
||||||
return CUi::POPUP_CLOSE_CURRENT;
|
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(2.0f, nullptr, &View);
|
||||||
View.HSplitTop(12.0f, &Slot, &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;
|
return CUi::POPUP_CLOSE_CURRENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,20 +306,20 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuSettings(void *pContext, CUIRect
|
||||||
static int s_ButtonOff = 0;
|
static int s_ButtonOff = 0;
|
||||||
static int s_ButtonDec = 0;
|
static int s_ButtonDec = 0;
|
||||||
static int s_ButtonHex = 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;
|
pAction->Call();
|
||||||
pEditor->m_ShowEnvelopePreview = SHOWENV_NONE;
|
|
||||||
}
|
}
|
||||||
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;
|
pAction->Call();
|
||||||
pEditor->m_ShowEnvelopePreview = SHOWENV_NONE;
|
|
||||||
}
|
}
|
||||||
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;
|
pAction->Call();
|
||||||
pEditor->m_ShowEnvelopePreview = SHOWENV_NONE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,16 +570,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View,
|
||||||
// new tile layer
|
// new tile layer
|
||||||
View.HSplitBottom(5.0f, &View, nullptr);
|
View.HSplitBottom(5.0f, &View, nullptr);
|
||||||
View.HSplitBottom(12.0f, &View, &Button);
|
View.HSplitBottom(12.0f, &View, &Button);
|
||||||
static int s_NewTileLayerButton = 0;
|
if(pEditor->DoButton_Editor(&pEditor->m_QuickActionAddTileLayer, pEditor->m_QuickActionAddTileLayer.Label(), 0, &Button, 0, pEditor->m_QuickActionAddTileLayer.Description()))
|
||||||
if(pEditor->DoButton_Editor(&s_NewTileLayerButton, "Add tile layer", 0, &Button, 0, "Creates a new tile layer"))
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<CLayer> pTileLayer = std::make_shared<CLayerTiles>(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height);
|
pEditor->m_QuickActionAddTileLayer.Call();
|
||||||
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));
|
|
||||||
return CUi::POPUP_CLOSE_CURRENT;
|
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));
|
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
|
// force ninja Weapon
|
||||||
SetWeapon(WEAPON_NINJA);
|
SetWeapon(WEAPON_NINJA);
|
||||||
|
@ -442,7 +442,7 @@ void CCharacter::FireWeapon()
|
||||||
if(m_PainSoundTimer <= 0 && !(m_LatestPrevInput.m_Fire & 1))
|
if(m_PainSoundTimer <= 0 && !(m_LatestPrevInput.m_Fire & 1))
|
||||||
{
|
{
|
||||||
m_PainSoundTimer = 1 * Server()->TickSpeed();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -459,7 +459,7 @@ void CCharacter::FireWeapon()
|
||||||
{
|
{
|
||||||
// reset objects Hit
|
// reset objects Hit
|
||||||
m_NumObjectsHit = 0;
|
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());
|
Antibot()->OnHammerFire(m_pPlayer->GetCid());
|
||||||
|
|
||||||
|
@ -567,7 +567,7 @@ void CCharacter::FireWeapon()
|
||||||
MouseTarget // MouseTarget
|
MouseTarget // MouseTarget
|
||||||
);
|
);
|
||||||
|
|
||||||
GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask());
|
GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc)
|
||||||
}
|
}
|
||||||
break;
|
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_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
|
||||||
m_Core.m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2055,7 +2055,7 @@ void CCharacter::ForceSetRescue(int RescueMode)
|
||||||
void CCharacter::DDRaceTick()
|
void CCharacter::DDRaceTick()
|
||||||
{
|
{
|
||||||
mem_copy(&m_Input, &m_SavedInput, sizeof(m_Input));
|
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)
|
if(m_Input.m_Direction != 0 || m_Input.m_Jump != 0)
|
||||||
m_LastMove = Server()->Tick();
|
m_LastMove = Server()->Tick();
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
|
||||||
{
|
{
|
||||||
pHit->UnFreeze();
|
pHit->UnFreeze();
|
||||||
}
|
}
|
||||||
|
pHit->TakeDamage(vec2(0, 0), 0, m_Owner, m_Type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,8 @@ void CProjectile::Tick()
|
||||||
pChr->Freeze();
|
pChr->Freeze();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(pTargetChr)
|
||||||
|
pTargetChr->TakeDamage(vec2(0, 0), 0, m_Owner, m_Type);
|
||||||
|
|
||||||
if(pOwnerChar && !GameLayerClipped(ColPos) &&
|
if(pOwnerChar && !GameLayerClipped(ColPos) &&
|
||||||
((m_Type == WEAPON_GRENADE && pOwnerChar->HasTelegunGrenade()) || (m_Type == WEAPON_GUN && pOwnerChar->HasTelegunGun())))
|
((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 OnCharacterSpawn(class CCharacter *pChr);
|
||||||
|
|
||||||
virtual void HandleCharacterTiles(class CCharacter *pChr, int MapIndex);
|
virtual void HandleCharacterTiles(class CCharacter *pChr, int MapIndex);
|
||||||
|
virtual void SetArmorProgress(CCharacter *pCharacer, int Progress){};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function: OnEntity
|
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)
|
void CGameControllerDDRace::OnPlayerConnect(CPlayer *pPlayer)
|
||||||
{
|
{
|
||||||
IGameController::OnPlayerConnect(pPlayer);
|
IGameController::OnPlayerConnect(pPlayer);
|
||||||
|
|
|
@ -13,6 +13,7 @@ public:
|
||||||
CScore *Score();
|
CScore *Score();
|
||||||
|
|
||||||
void HandleCharacterTiles(class CCharacter *pChr, int MapIndex) override;
|
void HandleCharacterTiles(class CCharacter *pChr, int MapIndex) override;
|
||||||
|
void SetArmorProgress(CCharacter *pCharacer, int Progress) override;
|
||||||
|
|
||||||
void OnPlayerConnect(class CPlayer *pPlayer) override;
|
void OnPlayerConnect(class CPlayer *pPlayer) override;
|
||||||
void OnPlayerDisconnect(class CPlayer *pPlayer, const char *pReason) 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 ColorBody = ColorHSLA(m_ColorBody).UnclampLighting().Pack(ms_DarkestLGT7);
|
||||||
int ColorFeet = ColorHSLA(m_ColorFeet).UnclampLighting().Pack(ms_DarkestLGT7);
|
int ColorFeet = ColorHSLA(m_ColorFeet).UnclampLighting().Pack(ms_DarkestLGT7);
|
||||||
m_aUseCustomColors[0] = true;
|
m_aUseCustomColors[protocol7::SKINPART_BODY] = true;
|
||||||
m_aUseCustomColors[1] = true;
|
m_aUseCustomColors[protocol7::SKINPART_MARKING] = true;
|
||||||
m_aUseCustomColors[2] = true;
|
m_aUseCustomColors[protocol7::SKINPART_DECORATION] = true;
|
||||||
m_aUseCustomColors[3] = true;
|
m_aUseCustomColors[protocol7::SKINPART_HANDS] = true;
|
||||||
m_aUseCustomColors[4] = true;
|
m_aUseCustomColors[protocol7::SKINPART_FEET] = true;
|
||||||
m_aSkinPartColors[0] = ColorBody;
|
m_aSkinPartColors[protocol7::SKINPART_BODY] = ColorBody;
|
||||||
m_aSkinPartColors[1] = 0x22FFFFFF;
|
m_aSkinPartColors[protocol7::SKINPART_MARKING] = 0x22FFFFFF;
|
||||||
m_aSkinPartColors[2] = ColorBody;
|
m_aSkinPartColors[protocol7::SKINPART_DECORATION] = ColorBody;
|
||||||
m_aSkinPartColors[3] = ColorBody;
|
m_aSkinPartColors[protocol7::SKINPART_HANDS] = ColorBody;
|
||||||
m_aSkinPartColors[4] = ColorFeet;
|
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));
|
str_copy(m_aSkinName, g_aStdSkins[BestSkin].m_aSkinName, sizeof(m_aSkinName));
|
||||||
m_UseCustomColor = true;
|
m_UseCustomColor = true;
|
||||||
m_ColorBody = ColorHSLA(m_aUseCustomColors[0] ? m_aSkinPartColors[0] : 255).UnclampLighting(ms_DarkestLGT7).Pack(ColorHSLA::DARKEST_LGT);
|
m_ColorBody = ColorHSLA(m_aUseCustomColors[protocol7::SKINPART_BODY] ? m_aSkinPartColors[protocol7::SKINPART_BODY] : 255)
|
||||||
m_ColorFeet = ColorHSLA(m_aUseCustomColors[4] ? m_aSkinPartColors[4] : 255).UnclampLighting(ms_DarkestLGT7).Pack(ColorHSLA::DARKEST_LGT);
|
.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 {
|
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;
|
std::optional<::ColorHSLA> (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor;
|
||||||
new (return$) ::ColorHSLA((self.*GetColor$)(Index, Light));
|
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 {
|
::std::int32_t cxxbridge1$IConsole_IResult$NumArguments(const ::IConsole_IResult &self) noexcept {
|
||||||
|
|
Loading…
Reference in a new issue