diff --git a/CREDITS.md b/CREDITS.md index 3ecead2d75..ded5242180 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -788,6 +788,7 @@ This page lists all the individual contributions to the project by their author. - Customize whether or not passenger can fire out when the transport is moving - Show game time - Fix a game crash when parsing string list with null entry + - `513` Set mission timer type - **NaotoYuuki** - Vertical & meteor trajectory projectile prototypes - **handama**: - AI script action to `16005 Jump Back To Previous Script` diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md index 074d3917e2..ee54363cb1 100644 --- a/docs/AI-Scripting-and-Mapping.md +++ b/docs/AI-Scripting-and-Mapping.md @@ -716,6 +716,32 @@ ID=ActionCount,[Action1],512,0,0,[FollowerIndex],0,0,0,A,[ActionX] ... ``` +### `513` Set mission timer properties + +- Set the method to display mission timer and whether the timer should be displayed reversedly based on given value. + - For behaviours `0`, `1`, and `2`, the second parameter decides the base value for percentage timer type or reversed timer that'll be used for calculation. + - For behaviours `3` and `4`, the second parameter decides the index of variable that'll be displayed. If the local/global variable does not exist, 0 will be displayed. + +In `mycampaign.map`: +```ini +[Actions] +... +ID=ActionCount,[Action1],521,0,0,[MissionTimerType],[BaseValue or VariableIndex],[ReverseTimer],0,A,[ActionX] +... +``` + +| *Behaviour* | *Description* | +| :---------: | :----------------------------------------- | +| 0 | Show normal timer | +| 1 | show percentage based on the given value | +| 2 | Show timer in digit form | +| 3 | Show value of the selected local variable | +| 4 | Show value of the selected global variable | + +```{note} +This won't affect how the global mission timer really ticks, so it'll still end after the mission tiemr expired. +``` + ### `600` Configure Drop Crate - Set or overwrite the `DropCrate` of the affected objects. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 68b6030d64..05cd94ed31 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -205,6 +205,9 @@ HideShakeEffects=false ; boolean 70=AITargetTypes index,0 71=AttachEffectType,0 72=DropCrate Behavior,0 + 73=Unit Index,0 + 74=Mission Timer Type,0 + 75=Reverse Mission Timer,0 101=BannerType,0 102=Horizontal position,0 103=Vertical position,0 @@ -263,20 +266,22 @@ HideShakeEffects=false ; boolean 502=Generate random number... (Phobos),0,56,57,58,54,0,0,0,0,[LONG DESC],0,1,502,1 503=Print variable value... (Phobos),0,56,54,0,0,0,0,0,0,[LONG DESC],0,1,503,0 504=Binary operation... (Phobos),0,56,55,60,54,59,0,0,0,[LONG DESC],0,1,504,1 - 505=Fire Super Weapon at specified location... (Phobos),0,0,20,2,21,22,0,0,0,Launch a Super Weapon from [SuperWeaponTypes] list at a specified location. House=-1 means random target that isn't neutral. House=-2 means the first neutral house. House=-3 means random human target. Coordinate X=-1 means random. Coordinate Y=-1 means random,0,1,505 - 506=Fire Super Weapon at specified waypoint... (Phobos),0,0,20,2,30,0,0,0,0,Launch a Super Weapon from [SuperWeaponTypes] list at a specified waypoint. House=-1 means random target that isn't neutral. House=-2 means the first neutral house. House=-3 means random human target. Coordinate X=-1 means random. Coordinate Y=-1 means random,0,1,506 - 510=Toggle MCV Redeployablility... (Phobos),0,0,15,0,0,0,0,0,0, Set MCVRedeploys to the given value,0,1,510 + 505=Fire Super Weapon at specified location... (Phobos),0,0,20,2,21,22,0,0,0,Launch a Super Weapon from [SuperWeaponTypes] list at a specified location. House=-1 means random target that isn't neutral. House=-2 means the first neutral house. House=-3 means random human target. Coordinate X=-1 means random. Coordinate Y=-1 means random.,0,1,505 + 506=Fire Super Weapon at specified waypoint... (Phobos),0,0,20,2,30,0,0,0,0,Launch a Super Weapon from [SuperWeaponTypes] list at a specified waypoint. House=-1 means random target that isn't neutral. House=-2 means the first neutral house. House=-3 means random human target. Coordinate X=-1 means random. Coordinate Y=-1 means random.,0,1,506 + 510=Toggle MCV Redeployablility... (Phobos),0,0,15,0,0,0,0,0,0,Set MCVRedeploys to the given value.,0,1,510 511=Building Type undeploy at... (Phobos),-10,47,2,0,0,0,1,0,0,Recycle the building type into a vehicle and move it to the specified waypoint. If the type is ``, recycle all buildings.,0,1,511 - 600=Configure dropped crate... (Phobos),0,72,31,0,0,0,0,0,0,Set or overwrite what crate is dropped when the attached object is destroyed. Only functions when used as attached triggers within objects. Behaviour -1=default. 1=Overwrites current crate. 0=Clear current crate,0,1,600 + 512=Set Follower for Associated Unit... (Phobos),0,0,73,0,0,0,0,0,0,Sets the follower for the associated object. The parameter is the index of the follower unit.,0,1,512 + 513=Set Mission Timer Properties... (Phobos),0,0,74,48,75,0,0,0,0,Set the method to display mission timer and whether the timer should be displayed reversedly based on given value. Method 0=default, 1=percentage based on given value, 2=digit, 3=local variable, 4=global variable.,0,1,521 + 600=Configure dropped crate... (Phobos),0,72,31,0,0,0,0,0,0,Set or overwrite what crate is dropped when the attached object is destroyed. Only functions when used as attached triggers within objects. Behaviour -1=default. 1=Overwrites current crate. 0=Clear current crate.,0,1,600 606=Edit hate-value... (Phobos),0,2,55,6,0,0,0,0,0, Edit the hate-value that trigger houses to other houses. -1 works for all houses.,0,1,606 607=Clear hate-value... (Phobos),0,2,0,0,0,0,0,0,0, Clear the hate-value that trigger houses to other houses. -1 works for all houses.,0,1,607 608=Set force enemy... (Phobos),0,0,2,0,0,0,0,0,0, Force an enemy, it will not change with the change of hate-value. -1 will remove the forced enemy, -2 will never have any enemies.,0,1,608 609=Set radar mode... (Phobos),0,0,15,0,0,0,0,0,0, Trigger's house can modify the current radar mode. 0 for requires full-power and building, 1 for free radar, 2 for forced enable, 3 for forced disable.,0,1,609 610=Set team delay... (Phobos),0,0,6,0,0,0,0,0,0, Trigger's house can customize TeamDelay. When the value is less than 0 in [General] ->TeamDelays.,0,1,610 611=Set next scenario... (Phobos),-4,105,0,0,0,0,0,0,0, Set the next campaign to load after winning the current one. Works only in Campaign Mode and requires setting [Basic] -> SkipMapSelect=yes.,0,1,611 - 800=Display banner and local variable... (Phobos),-4,101,104,102,103,3,0,0,0,Draw banner on screen and replace banner with same ID,0,1,800 - 801=Display banner and global variable... (Phobos),-4,101,104,102,103,35,0,0,0,Draw banner on screen and replace banner with same ID,0,1,801 - 802=Delete banner... (Phobos),0,104,0,0,0,0,0,0,0,Delete banner with ID,0,1,802 + 800=Display banner and local variable... (Phobos),-4,101,104,102,103,3,0,0,0,Draw banner on screen and replace banner with same ID.,0,1,800 + 801=Display banner and global variable... (Phobos),-4,101,104,102,103,35,0,0,0,Draw banner on screen and replace banner with same ID.,0,1,801 + 802=Delete banner... (Phobos),0,104,0,0,0,0,0,0,0,Delete banner with ID.,0,1,802 ; FOLLOWING ENTRIES REQUIRE FA2SP.DLL (by secsome) [ScriptTypeLists] @@ -427,6 +432,7 @@ HideShakeEffects=false ; boolean - [Customize whether the unit exits from the roof](Fixed-or-Improved-Logics.md#customize-whether-the-unit-exits-from-the-roof) (by Noble_Fish) - [Customize whether the unit can be detected by psychic detector](Fixed-or-Improved-Logics.md#customize-whether-the-unit-can-be-detected-by-psychic-detector) (by Noble_Fish) - Cloak Enhancement (by NetsuNegi) +- [`513` Set mission timer properties](AI-Scripting-and-Mapping.md#set-mission-timer-properties) (by Ollerus) #### Vanilla fixes: - Fixed the bug where a building with `Factory=BuildingType` owned by the AI did not play `ProductionAnim` when placing a produced building (by Noble_Fish) diff --git a/src/Ext/Scenario/Body.cpp b/src/Ext/Scenario/Body.cpp index b66a18b123..b82164cfbc 100644 --- a/src/Ext/Scenario/Body.cpp +++ b/src/Ext/Scenario/Body.cpp @@ -192,6 +192,9 @@ void ScenarioExt::ExtData::Serialize(T& Stm) .Process(this->FallingDownTracker) .Process(this->EVAIndex) .Process(this->FiringAnimUpdateCount) + .Process(this->MissionTimer_Type) + .Process(this->MissionTimer_Variable) + .Process(this->MissionTimer_Reverse) ; } diff --git a/src/Ext/Scenario/Body.h b/src/Ext/Scenario/Body.h index af5d345682..88a8ee2034 100644 --- a/src/Ext/Scenario/Body.h +++ b/src/Ext/Scenario/Body.h @@ -52,6 +52,10 @@ class ScenarioExt int FiringAnimUpdateCount; + int MissionTimer_Type; + int MissionTimer_Variable; + bool MissionTimer_Reverse; + ExtData(ScenarioClass* OwnerObject) : Extension(OwnerObject) , ShowBriefing { false } , BriefingTheme { -1 } @@ -71,6 +75,9 @@ class ScenarioExt , FallingDownTracker {} , EVAIndex { -2 } , FiringAnimUpdateCount { 0 } + , MissionTimer_Type { 0 } + , MissionTimer_Variable { 0 } + , MissionTimer_Reverse { false } { } static void SetVariableToByID(bool bIsGlobal, int nIndex, char bState); diff --git a/src/Ext/TAction/Body.cpp b/src/Ext/TAction/Body.cpp index 201e8dfef7..aeac5594dd 100644 --- a/src/Ext/TAction/Body.cpp +++ b/src/Ext/TAction/Body.cpp @@ -65,12 +65,15 @@ bool TActionExt::Execute(TActionClass* pThis, HouseClass* pHouse, ObjectClass* p case PhobosTriggerAction::ToggleMCVRedeploy: return TActionExt::ToggleMCVRedeploy(pThis, pHouse, pObject, pTrigger, location); - case PhobosTriggerAction::SetDropCrate: - return TActionExt::SetDropCrate(pThis, pHouse, pObject, pTrigger, location); case PhobosTriggerAction::UndeployToWaypoint: return TActionExt::UndeployToWaypoint(pThis, pHouse, pObject, pTrigger, location); case PhobosTriggerAction::SetFollowsIndexForVehicle: return TActionExt::SetFollowsIndexForVehicle(pThis, pHouse, pObject, pTrigger, location); + case PhobosTriggerAction::SetMissionTimer: + return TActionExt::SetMissionTimer(pThis, pHouse, pObject, pTrigger, location); + + case PhobosTriggerAction::SetDropCrate: + return TActionExt::SetDropCrate(pThis, pHouse, pObject, pTrigger, location); case PhobosTriggerAction::EditAngerNode: return TActionExt::EditAngerNode(pThis, pHouse, pObject, pTrigger, location); @@ -777,6 +780,21 @@ bool TActionExt::SetNextScanario(TActionClass* const pThis, HouseClass* const pH return true; } +bool TActionExt::SetMissionTimer(TActionClass* const pThis, HouseClass* const pHouse, ObjectClass* const pObject, TriggerClass* const pTrigger, const CellStruct& location) +{ + const int type = pThis->Param3; + const int reverse = pThis->Param5; + ScenarioExt::Global()->MissionTimer_Variable = pThis->Param4; + + if (0 <= type && 4 >= type) + ScenarioExt::Global()->MissionTimer_Type = type; + + if (0 <= reverse && 1 >= reverse) + ScenarioExt::Global()->MissionTimer_Reverse = (bool)reverse; + + return true; +} + static void CreateOrReplaceBanner(TActionClass* pTAction, bool isGlobal) { const auto pBannerType = BannerTypeClass::Find(pTAction->Text); diff --git a/src/Ext/TAction/Body.h b/src/Ext/TAction/Body.h index 03f956755d..c054bd67b0 100644 --- a/src/Ext/TAction/Body.h +++ b/src/Ext/TAction/Body.h @@ -17,9 +17,11 @@ enum class PhobosTriggerAction : unsigned int RunSuperWeaponAtLocation = 505, RunSuperWeaponAtWaypoint = 506, ToggleMCVRedeploy = 510, - SetDropCrate = 600, UndeployToWaypoint = 511, SetFollowsIndexForVehicle = 512, + SetMissionTimer = 513, + + SetDropCrate = 600, EditAngerNode = 606, ClearAngerNode = 607, @@ -81,9 +83,11 @@ class TActionExt final : public AbstractExt ACTION_FUNC(RunSuperWeaponAtLocation); ACTION_FUNC(RunSuperWeaponAtWaypoint); ACTION_FUNC(ToggleMCVRedeploy); - ACTION_FUNC(SetDropCrate); ACTION_FUNC(UndeployToWaypoint); ACTION_FUNC(SetFollowsIndexForVehicle); + ACTION_FUNC(SetMissionTimer); + + ACTION_FUNC(SetDropCrate); ACTION_FUNC(EditAngerNode); ACTION_FUNC(ClearAngerNode); diff --git a/src/Misc/Hooks.UI.cpp b/src/Misc/Hooks.UI.cpp index 4bd96e843f..901d1a4b82 100644 --- a/src/Misc/Hooks.UI.cpp +++ b/src/Misc/Hooks.UI.cpp @@ -537,6 +537,7 @@ namespace DrawTimerTemp { bool AdjustLocation = false; bool IsPercentage = false; + bool IsDigit = false; double Percentage = 0.0; int TimeLeft = 0; } @@ -546,12 +547,65 @@ DEFINE_HOOK(0x6D3D10, TacticalClass_Render_BeforeAll, 0x6) using namespace DrawTimerTemp; AdjustLocation = false; IsPercentage = false; + IsDigit = false; return 0; } DEFINE_HOOK(0x6D4992, TacticalClass_Render_DrawMissionTimer_TimeLeft, 0x6) { DrawTimerTemp::TimeLeft = R->EDX(); + DrawTimerTemp::IsPercentage = false; + DrawTimerTemp::IsDigit = false; + + switch (ScenarioExt::Global()->MissionTimer_Type) + { + case 1: + { + DrawTimerTemp::IsPercentage = true; + const int totalTime = ScenarioExt::Global()->MissionTimer_Variable; + if (ScenarioExt::Global()->MissionTimer_Reverse) + DrawTimerTemp::Percentage = totalTime > 0 ? static_cast(DrawTimerTemp::TimeLeft) / totalTime : 1.0; + else + DrawTimerTemp::Percentage = totalTime > 0 ? static_cast(totalTime - DrawTimerTemp::TimeLeft) / totalTime : 1.0; + break; + } + case 2: + { + if (ScenarioExt::Global()->MissionTimer_Reverse) + DrawTimerTemp::TimeLeft = ScenarioExt::Global()->MissionTimer_Variable - DrawTimerTemp::TimeLeft; + DrawTimerTemp::IsDigit = true; + break; + } + case 3: + { + DrawTimerTemp::IsDigit = true; + const auto& variables = ScenarioExt::Global()->Variables[0]; + const auto& it = variables.find(ScenarioExt::Global()->MissionTimer_Variable); + if (it != variables.end()) + DrawTimerTemp::TimeLeft = it->second.Value; + else + DrawTimerTemp::TimeLeft = 0; + break; + } + case 4: + { + DrawTimerTemp::IsDigit = true; + const auto& variables = ScenarioExt::Global()->Variables[1]; + const auto& it = variables.find(ScenarioExt::Global()->MissionTimer_Variable); + if (it != variables.end()) + DrawTimerTemp::TimeLeft = it->second.Value; + else + DrawTimerTemp::TimeLeft = 0; + break; + } + default: + { + if (ScenarioExt::Global()->MissionTimer_Reverse) + DrawTimerTemp::TimeLeft = ScenarioExt::Global()->MissionTimer_Variable - DrawTimerTemp::TimeLeft; + break; + } + } + return 0; } @@ -562,6 +616,7 @@ DEFINE_HOOK(0x6D4A10, TacticalClass_Render_DrawSuperTimer_PercentageTimer, 0x6) GET(SuperClass*, pSuper, ECX); DrawTimerTemp::IsPercentage = false; + DrawTimerTemp::IsDigit = false; const int timeLeft = pSuper->RechargeTimer.GetTimeLeft(); const auto pSWTypeExt = SWTypeExt::Fetch(pSuper->Type); @@ -593,6 +648,8 @@ static int __fastcall TacticalClass_DrawTimer_swprintf(wchar_t* pBuffer, size_t if (IsPercentage) return swprintf(pBuffer, bufferCount, L"%.2lf%s", Percentage * 100, L"%%"); + else if (IsDigit) + return swprintf(pBuffer, bufferCount, L"%d", TimeLeft); else return swprintf(pBuffer, bufferCount, L"%02d:%02d", TimeLeft / 60 % 60, TimeLeft % 60); }