diff --git a/CREDITS.md b/CREDITS.md index bc89107783..d77469233c 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -861,3 +861,8 @@ This page lists all the individual contributions to the project by their author. - Revert Ares patch to allow OpenTopped transport customization - Fix for units with Fly, Jumpjet or Rocket locomotors crashing off-map not being cleaned up - Fix for mirage tanks (and other vehicles disguised as terrain) incorrectly displaying veterancy insignia to enemy players when not clearly visible +- **Chang_zhi**: + - Add `ClampToScreen` tag for `BannerType` to control whether banner position is clamped to the visible area + + + diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md index e507f70666..deded33e48 100644 --- a/docs/AI-Scripting-and-Mapping.md +++ b/docs/AI-Scripting-and-Mapping.md @@ -820,6 +820,7 @@ Team delay change will take effect for a house after its next AI team is created - `Duration` determines how long the banner will be displayed. Negative values mean the banner can always be displayed until being deleted. The banner itself won't be deleted when it's not displaying. - `Delay` determines when the banner will be displayed again after it stops displaying by a positive `Duration`. Neagtive values mean it can't be displayed again. - If an `SHP` banner displays again after the delay, it'll start from the frame when it's stopped last time. This can also be changed to its first frame if `SHP.RefreshAfterDelay` set to true. + - `ClampToScreen` controls whether the banner is clamped to stay within the visible area. When disabled, a PCX banner exceeding the top screen edge may crash the game. In `rulesmd.ini`: ```ini @@ -837,6 +838,7 @@ CSF.Background=false ; boolean CSF.VariableFormat=none ; List of Variable Format Enumeration (none|variable|prefix/prefixed|surfix/surfixed) Duration=-1 ; integer Delay=-1 ; integer +ClampToScreen=true ; boolean ``` In `mycampaign.map`: diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 3109f010ed..b7b95c3648 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -592,6 +592,7 @@ HideShakeEffects=false ; boolean - [Animation transparency customization settings](New-or-Enhanced-Logics.md#customizable-animation-transparency-settings) (by Starkku) - [Customize `Tiled` drawing interval and centering](Fixed-or-Improved-Logics.md#customize-the-drawing-interval-for-tiled) (by Noble_Fish) - [Customize whether technos with `Locomotor=Fly` wobble](Fixed-or-Improved-Logics.md#customize-whether-technos-with-locomotor-fly-wobble) (by Noble_Fish) +- Add `ClampToScreen` tag for `BannerType` (defaults to `true`) to control whether banner position is clamped to the visible area (by Chang_zhi) #### Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/docs/locale/zh_CN/LC_MESSAGES/AI-Scripting-and-Mapping.po b/docs/locale/zh_CN/LC_MESSAGES/AI-Scripting-and-Mapping.po index b4f9e6954f..e66a592071 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/AI-Scripting-and-Mapping.po +++ b/docs/locale/zh_CN/LC_MESSAGES/AI-Scripting-and-Mapping.po @@ -1559,6 +1559,14 @@ msgid "" "frame if `SHP.RefreshAfterDelay` set to true." msgstr "一个 `SHP` 横幅会在再次显示时从上次结束时的帧开始。这可以通过 `SHP.RefreshAfterDelay=true` 更改为从头开始。" +msgid "" +"`ClampToScreen` controls whether the banner is clamped to stay within the" +" visible area. When disabled, a PCX banner exceeding the top screen edge " +"may crash the game." +msgstr "" +"`ClampToScreen` 控制横幅是否被限制在可视区域内。禁用后,PCX " +"横幅超出屏幕上边缘时可能导致游戏崩溃。" + msgid "Trigger events" msgstr "触发条件" diff --git a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po index 2b6d6b15a9..58baacc56a 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po +++ b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po @@ -2928,3 +2928,11 @@ msgid "" " being cleaned up" msgstr "修复了 `Locomotor` 为 `Fly`、`Jumpjet` 或 `Rocket` 的单位在地图外坠毁时未能清除的问题" +msgid "**Chang_zhi**:" +msgstr "**Chang_zhi**:" + +msgid "" +"Add `ClampToScreen` tag for `BannerType` to control whether banner " +"position is clamped to the visible area" +msgstr "" +"为 `BannerType` 添加了 `ClampToScreen` 标签以控制横幅位置是否被限制在可视化区域内" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po index 046c3f4118..e1e58f8f6b 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po @@ -1981,6 +1981,12 @@ msgstr "" "[寄生击杀水上目标后刷出的自定义](Fixed-or-Improved-Logics.md#dehardcode-of-parasites-" "unlimboing-after-killing-naval-targets)(by Noble_Fish)" +msgid "" +"Add `ClampToScreen` tag for `BannerType` (defaults to `true`) to control " +"whether banner position is clamped to the visible area (by Chang_zhi)" +msgstr "" +"为 `BannerType` 添加了 `ClampToScreen` 标签(默认为 `true`),用于控制横幅位置是否被限制在可视区域内(by Chang_zhi)" + msgid "Vanilla fixes:" msgstr "原版问题修复:" diff --git a/src/New/Entity/BannerClass.cpp b/src/New/Entity/BannerClass.cpp index a1cf6d5b3e..fe18a815e7 100644 --- a/src/New/Entity/BannerClass.cpp +++ b/src/New/Entity/BannerClass.cpp @@ -1,7 +1,11 @@ #include "BannerClass.h" +#include + #include +#include + std::vector> BannerClass::Array; BannerClass::BannerClass @@ -61,9 +65,21 @@ void BannerClass::Render() void BannerClass::RenderPCX(Point2D position) { + auto const pType = this->Type; BSurface* pcx = this->Type->PCX.GetSurface(); position.X -= pcx->Width / 2; position.Y -= pcx->Height / 2; + + // Clamp the position to keep the PCX within the visible area, + // preventing it from being drawn partially off-screen. + if(pType->ClampToScreen) + { + int maxX = std::max(0, DSurface::ViewBounds.Width - pcx->Width); + int maxY = std::max(0, DSurface::ViewBounds.Height - pcx->Height); + position.X = std::clamp(position.X, 0, maxX); + position.Y = std::clamp(position.Y, 0, maxY); + } + RectangleStruct bounds(position.X, position.Y, pcx->Width, pcx->Height); PCX::Instance.BlitToSurface(&bounds, DSurface::Composite, pcx); } @@ -76,6 +92,16 @@ void BannerClass::RenderSHP(Point2D position) position.X -= shape->Width / 2; position.Y -= shape->Height / 2; + // Clamp the position to keep the SHP within the visible area, + // preventing it from being drawn partially off-screen. + if (pType->ClampToScreen) + { + int maxX = std::max(0, DSurface::ViewBounds.Width - shape->Width); + int maxY = std::max(0, DSurface::ViewBounds.Height - shape->Height); + position.X = std::clamp(position.X, 0, maxX); + position.Y = std::clamp(position.Y, 0, maxY); + } + DSurface::Composite->DrawSHP ( palette, @@ -134,11 +160,27 @@ void BannerClass::RenderCSF(Point2D position) } const TextPrintType textFlags = TextPrintType::UseGradPal - | TextPrintType::Center | TextPrintType::Metal12 | (pType->CSF_Background ? TextPrintType::Background - : TextPrintType::LASTPOINT); + : TextPrintType::LASTPOINT) + | (pType->ClampToScreen + ? TextPrintType::LASTPOINT + : TextPrintType::Center); + + + // Measure the text, manually center, then clamp to screen bounds. + if (pType->ClampToScreen) + { + RectangleStruct textRect = Drawing::GetTextDimensions( + text.c_str(), position, static_cast(textFlags)); + position.X -= textRect.Width / 2; + position.Y -= textRect.Height / 2; + int maxX = std::max(0, DSurface::ViewBounds.Width - textRect.Width); + int maxY = std::max(0, DSurface::ViewBounds.Height - textRect.Height); + position.X = std::clamp(position.X, 0, maxX); + position.Y = std::clamp(position.Y, 0, maxY); + } DSurface::Composite->DrawText ( diff --git a/src/New/Type/BannerTypeClass.cpp b/src/New/Type/BannerTypeClass.cpp index 2950b344d2..595f323fc2 100644 --- a/src/New/Type/BannerTypeClass.cpp +++ b/src/New/Type/BannerTypeClass.cpp @@ -25,6 +25,7 @@ void BannerTypeClass::LoadFromINI(CCINIClass* pINI) this->Duration.Read(exINI, section, "Duration"); this->Delay.Read(exINI, section, "Delay"); this->Shape_RefreshAfterDelay.Read(exINI, section, "SHP.RefreshAfterDelay"); + this->ClampToScreen.Read(exINI, section, "ClampToScreen"); } template @@ -41,6 +42,7 @@ void BannerTypeClass::Serialize(T& stm) .Process(this->Duration) .Process(this->Delay) .Process(this->Shape_RefreshAfterDelay) + .Process(this->ClampToScreen) ; } diff --git a/src/New/Type/BannerTypeClass.h b/src/New/Type/BannerTypeClass.h index 8aeb921668..bde68d2438 100644 --- a/src/New/Type/BannerTypeClass.h +++ b/src/New/Type/BannerTypeClass.h @@ -25,6 +25,9 @@ class BannerTypeClass final : public Enumerable Valueable Delay; Valueable Shape_RefreshAfterDelay; + //Clamp to screen + Valueable ClampToScreen; + BannerTypeClass(const char* const pTitle) : Enumerable(pTitle) , PCX { } , Shape { } @@ -36,6 +39,7 @@ class BannerTypeClass final : public Enumerable , Duration { -1 } , Delay { -1 } , Shape_RefreshAfterDelay { false } + , ClampToScreen { true } { } virtual void LoadFromINI(CCINIClass* pINI);