From 085afa7483db6f379fe41dfbe085dd797768734a Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Wed, 9 Apr 2025 17:25:02 +0800 Subject: [PATCH 01/14] Fix the bug that `EnterGrinderSound` on technotype does not used --- CREDITS.md | 2 +- docs/Fixed-or-Improved-Logics.md | 2 +- docs/Whats-New.md | 2 +- src/Misc/Hooks.BugFixes.cpp | 23 +++++++++++++++++++---- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 91d8614057..ee53b1a5ca 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -366,7 +366,7 @@ This page lists all the individual contributions to the project by their author. - Allow voxel projectiles to use `AnimPalette` and `FirersPalette` - Customize damaged speed ratio of drive/ship loco - Customize overpower logic - - Fix the bug that `EnterBioReactorSound` and `LeaveBioReactorSound` on technotype does not used + - Fix the bug that `EnterBioReactorSound`, `LeaveBioReactorSound`, `EnterGrinderSound` on technotype does not used - Fix the bug that harvester dont stop unloading and cannot unload cargos anymore when lifting by `IsLocomotor=yes` warhead - **Apollo** - Translucent SHP drawing patches - **ststl**: diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index e0360b2de8..d111d17575 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -207,7 +207,7 @@ This page describes all ingame logics that are fixed or improved in Phobos witho - Fixed the bug that healing weapons could not automatically acquire aerial targets. - Allow voxel projectiles to use `AnimPalette` and `FirersPalette`. - Fixed an issue where AI would select unreachable buildings and get stuck when looking for buildings like tank bunkers, bio reactors, etc. -- Fix the bug that `EnterBioReactorSound` and `LeaveBioReactorSound` on technotype does not used. +- Fix the bug that `EnterBioReactorSound`, `LeaveBioReactorSound`, `EnterGrinderSound` on technotype does not used. - Fix the bug that harvester dont stop unloading and cannot unload cargos anymore when lifting by `IsLocomotor=yes` warhead. ## Fixes / interactions with other extensions diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 69d656a048..5bc1444752 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -356,7 +356,7 @@ New: - [Customize damaged speed ratio of drive/ship loco](Fixed-or-Improved-Logics.md#damaged-speed-customization) (by NetsuNegi) - [Customize overpower logic](Fixed-or-Improved-Logics.md#customize-overpower-logic) (by NetsuNegi) - Promotion animation deglobalization (by Ollerus) -- Fix the bug that `EnterBioReactorSound` and `LeaveBioReactorSound` on technotype does not used (by NetsuNegi) +- Fix the bug that `EnterBioReactorSound`, `LeaveBioReactorSound`, `EnterGrinderSound` on technotype does not used (by NetsuNegi) - Fix the bug that harvester dont stop unloading and cannot unload cargos anymore when lifting by `IsLocomotor=yes` warhead (by NetsuNegi) Vanilla fixes: diff --git a/src/Misc/Hooks.BugFixes.cpp b/src/Misc/Hooks.BugFixes.cpp index b803590b06..c83e116682 100644 --- a/src/Misc/Hooks.BugFixes.cpp +++ b/src/Misc/Hooks.BugFixes.cpp @@ -1764,12 +1764,27 @@ DEFINE_HOOK(0x4DFB28, FootClass_FindGrinder_CheckValid, 0x8) #pragma endregion +DEFINE_HOOK_AGAIN(0x73A1D3, FootClass_UpdatePosition_EnterGrinderSound, 0x6)// UnitClass +DEFINE_HOOK(0x5198C3, FootClass_UpdatePosition_EnterGrinderSound, 0x6)// InfantryClass +{ + GET(BuildingClass*, pGrinder, EBX); + const int enterSound = pGrinder->Type->EnterGrinderSound; + + if (enterSound >= 0) + { + R->ECX(enterSound); + return R->Origin() + 0x6; + } + + return 0; +} + DEFINE_HOOK(0x51A304, InfantryClass_UpdatePosition_EnterBioReactorSound, 0x6) { enum { SkipGameCode = 0x51A30A }; - GET(BuildingClass*, pThis, EDI); - const int enterSound = pThis->Type->EnterBioReactorSound; + GET(BuildingClass*, pReactor, EDI); + const int enterSound = pReactor->Type->EnterBioReactorSound; if (enterSound >= 0) { @@ -1784,8 +1799,8 @@ DEFINE_HOOK(0x44DBCF, BuildingClass_Mission_Unload_LeaveBioReactorSound, 0x6) { enum { SkipGameCode = 0x44DBD5 }; - GET(BuildingClass*, pThis, EBP); - const int leaveSound = pThis->Type->LeaveBioReactorSound; + GET(BuildingClass*, pReactor, EBP); + const int leaveSound = pReactor->Type->LeaveBioReactorSound; if (leaveSound >= 0) { From f501d7facbcca145b97d259fbb77e71352929e2e Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Wed, 9 Apr 2025 21:21:10 +0800 Subject: [PATCH 02/14] initial --- CREDITS.md | 1 + Phobos.vcxproj | 2 + docs/New-or-Enhanced-Logics.md | 24 +++++ docs/Whats-New.md | 1 + src/Ext/Techno/Body.Update.cpp | 93 +++++++++++++++++++ src/Ext/Techno/Body.cpp | 1 + src/Ext/Techno/Body.h | 3 + src/Ext/TechnoType/Body.cpp | 5 + src/Ext/TechnoType/Body.h | 3 + .../Affiliated/TiberiumEaterTypeClass.cpp | 51 ++++++++++ .../Type/Affiliated/TiberiumEaterTypeClass.h | 31 +++++++ 11 files changed, 215 insertions(+) create mode 100644 src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp create mode 100644 src/New/Type/Affiliated/TiberiumEaterTypeClass.h diff --git a/CREDITS.md b/CREDITS.md index ee53b1a5ca..c688fd4c2a 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -368,6 +368,7 @@ This page lists all the individual contributions to the project by their author. - Customize overpower logic - Fix the bug that `EnterBioReactorSound`, `LeaveBioReactorSound`, `EnterGrinderSound` on technotype does not used - Fix the bug that harvester dont stop unloading and cannot unload cargos anymore when lifting by `IsLocomotor=yes` warhead + - Tiberium eater logic - **Apollo** - Translucent SHP drawing patches - **ststl**: - Customizable `ShowTimer` priority of superweapons diff --git a/Phobos.vcxproj b/Phobos.vcxproj index 0364ffee4c..c31e0e9410 100644 --- a/Phobos.vcxproj +++ b/Phobos.vcxproj @@ -22,6 +22,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 53305db677..bd43023ada 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1698,6 +1698,30 @@ NoQueueUpToEnter= ; boolean NoQueueUpToUnload= ; boolean ``` +### Tiberium eater + +- Units can convert the ore underneath them into cash in real time, like GDI's EPIC unit MARV in Command & Conquer 3 Kane's Wrath, when `TiberiumEater.TransDelay` is 0 or larger. +- `TiberiumEater.TransDelay` specifies the interval in game frames between two mining "processes". +- `TiberiumEater.AmountPerCell` controls how many "bails" of ore can be mined at each cell at once. +- By default, ore mined this way is worth the same as if it was harvested and refined the normal way. This can be adjusted with `TiberiumEater.CashMultiplier`. +- `TiberiumEater.Display=true` will create a flying text displaying the total cash amount received each mining process. `TiberiumEater.Display.Houses` controlls who can see this text. +- An animation will be played at each interval at each mined cell. If `TiberiumEater.Anims` contains 8 entries, then an entry will be picked according to unit facing. Otherwise, an entry will be chosen at random. +- If `TiberiumEater.AnimMove=true`, the animations will move with the unit. + +In `rulesmd.ini`: +```ini +[SOMETECHNO] ; InfantryType, UnitType or AircraftType +TiberiumEater.TransDelay=-1 ; integer +TiberiumEater.CashMultiplier=1.0 ; float +TiberiumEater.AmountPerCell=0 ; integer +TiberiumEater.FrontOffset= ; list of integer, use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.LeftOffset= ; list of integer, use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.Display=true ; boolean +TiberiumEater.Display.Houses=all ; AffectedHouse enumeration +TiberiumEater.Anims= ; list of animations +TiberiumEater.AnimMove=true ; boolean +``` + ## Terrain ### Destroy animation & sound diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 5bc1444752..82a28f8a79 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -358,6 +358,7 @@ New: - Promotion animation deglobalization (by Ollerus) - Fix the bug that `EnterBioReactorSound`, `LeaveBioReactorSound`, `EnterGrinderSound` on technotype does not used (by NetsuNegi) - Fix the bug that harvester dont stop unloading and cannot unload cargos anymore when lifting by `IsLocomotor=yes` warhead (by NetsuNegi) +- Tiberium eater logic (by NetsuNegi) Vanilla fixes: - Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl) diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 6f9f1b1be6..22029e36e8 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -32,6 +33,7 @@ void TechnoExt::ExtData::OnEarlyUpdate() this->UpdateLaserTrails(); this->ApplyInterceptor(); this->EatPassengers(); + this->UpdateTiberiumEater(); this->ApplySpawnLimitRange(); this->ApplyMindControlRangeLimit(); this->UpdateRecountBurst(); @@ -338,6 +340,97 @@ void TechnoExt::ExtData::EatPassengers() } } +void TechnoExt::ExtData::UpdateTiberiumEater() +{ + const auto pThis = this->OwnerObject(); + const auto pEaterType = this->TypeExtData->TiberiumEaterType.get(); + + if (pEaterType->TransDelay < 0 || this->TiberiumEater_Timer.InProgress()) + return; + + const size_t frontSize = pEaterType->FrontOffset.size(); + const size_t leftSize = pEaterType->LeftOffset.size(); + size_t cellCount = std::max(frontSize, leftSize); + + if (!cellCount) + cellCount = 1; + + const auto pOwner = pThis->Owner; + CoordStruct flh {}; + bool active = false; + const bool displayCash = pEaterType->Display && pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer); + const int animCount = static_cast(pEaterType->Anims.size()); + int facing = pThis->PrimaryFacing.Current().GetFacing<8>(); + + if (facing >= 7) + facing = 0; + else + facing++; + + for (size_t idx = 0; idx < cellCount; idx++) + { + flh.X = frontSize > idx ? pEaterType->FrontOffset[idx] * Unsorted::LeptonsPerCell : 0; + flh.Y = leftSize > idx ? pEaterType->LeftOffset[idx] * Unsorted::LeptonsPerCell : 0; + const auto pos = TechnoExt::GetFLHAbsoluteCoords(pThis, flh, false); + const auto pCell = MapClass::Instance.TryGetCellAt(pos); + + if (!pCell) + continue; + + auto cellCoords = pCell->GetCoords(); + cellCoords.Z = std::max(pThis->Location.Z, cellCoords.Z); + + if (const int contained = pCell->GetContainedTiberiumValue()) + { + const int tiberiumValue = TiberiumClass::Array[pCell->GetContainedTiberiumIndex()]->Value; + const int tiberiumAmount = static_cast(static_cast(contained) / tiberiumValue); + const int amount = pEaterType->AmountPerCell ? std::min(pEaterType->AmountPerCell.Get(), tiberiumAmount) : tiberiumAmount; + pCell->ReduceTiberium(amount); + const float multiplier = pEaterType->CashMultiplier * (1.0f + pOwner->NumOrePurifiers * RulesClass::Instance->PurifierBonus); + const int value = static_cast(std::round(amount * tiberiumValue * multiplier)); + pOwner->TransactMoney(value); + active = true; + + if (displayCash) + FlyingStrings::AddMoneyString(value, pOwner, pEaterType->DisplayToHouse, cellCoords, pEaterType->DisplayOffset); + + if (animCount == 0) + continue; + + AnimTypeClass* pAnimType = nullptr; + + switch (animCount) + { + case 1: + pAnimType = pEaterType->Anims[0]; + break; + + case 8: + pAnimType = pEaterType->Anims[facing]; + break; + + default: + pAnimType = pEaterType->Anims[ScenarioClass::Instance->Random.RandomRanged(0, pEaterType->Anims.size() - 1)]; + break; + } + + if (pAnimType) + { + if (auto pAnim = GameCreate(pAnimType, pos)) + { + pAnim->Owner = pThis->Owner; + + if (pEaterType->AnimMove) + pAnim->SetOwnerObject(pThis); + } + } + } + } + + if (active) + this->TiberiumEater_Timer.Start(pEaterType->TransDelay); +} + void TechnoExt::ExtData::UpdateShield() { auto const pTypeExt = this->TypeExtData; diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 7f262d8fb8..af893248ec 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -591,6 +591,7 @@ void TechnoExt::ExtData::Serialize(T& Stm) .Process(this->IsBeingChronoSphered) .Process(this->KeepTargetOnMove) .Process(this->LastSensorsMapCoords) + .Process(this->TiberiumEater_Timer) ; } diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index a6f49c4fad..366a2bcd5d 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -68,6 +68,7 @@ class TechnoExt bool IsBeingChronoSphered; // Set to true on units currently being ChronoSphered, does not apply to Ares-ChronoSphere'd buildings or Chrono reinforcements. bool KeepTargetOnMove; CellStruct LastSensorsMapCoords; + CDTimerClass TiberiumEater_Timer; ExtData(TechnoClass* OwnerObject) : Extension(OwnerObject) , TypeExtData { nullptr } @@ -112,6 +113,7 @@ class TechnoExt , IsBeingChronoSphered { false } , KeepTargetOnMove { false } , LastSensorsMapCoords { CellStruct::Empty } + , TiberiumEater_Timer {} { } void OnEarlyUpdate(); @@ -120,6 +122,7 @@ class TechnoExt bool CheckDeathConditions(bool isInLimbo = false); void DepletedAmmoActions(); void EatPassengers(); + void UpdateTiberiumEater(); void UpdateShield(); void UpdateOnTunnelEnter(); void UpdateOnTunnelExit(); diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 7886a6e243..637f69cf69 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -19,6 +19,7 @@ TechnoTypeExt::ExtContainer TechnoTypeExt::ExtMap; void TechnoTypeExt::ExtData::Initialize() { this->ShieldType = ShieldTypeClass::FindOrAllocate(NONE_STR); + this->TiberiumEaterType = std::make_unique(); } void TechnoTypeExt::ExtData::ApplyTurretOffset(Matrix3D* mtx, double factor) @@ -673,6 +674,8 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->DroppodType.reset(); } + this->TiberiumEaterType->LoadFromINI(pINI, pSection); + if (GeneralUtils::IsValidString(pThis->PaletteFile) && !pThis->Palette) Debug::Log("[Developer warning] [%s] has Palette=%s set but no palette file was loaded (missing file or wrong filename). Missing palettes cause issues with lighting recalculations.\n", pArtSection, pThis->PaletteFile); } @@ -868,6 +871,8 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->LandingDir) .Process(this->DroppodType) + .Process(this->TiberiumEaterType) + .Process(this->Convert_HumanToComputer) .Process(this->Convert_ComputerToHuman) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 12f4ba32da..55c581f1e0 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -12,6 +12,7 @@ #include #include #include +#include class Matrix3D; @@ -59,6 +60,7 @@ class TechnoTypeExt Valueable ShieldType; std::unique_ptr PassengerDeletionType; std::unique_ptr DroppodType; + std::unique_ptr TiberiumEaterType; Valueable Ammo_AddOnDeploy; Valueable Ammo_AutoDeployMinimumAmount; @@ -492,6 +494,7 @@ class TechnoTypeExt , SpawnHeight {} , LandingDir {} , DroppodType {} + , TiberiumEaterType {} , Convert_HumanToComputer { } , Convert_ComputerToHuman { } diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp b/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp new file mode 100644 index 0000000000..019d63747b --- /dev/null +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp @@ -0,0 +1,51 @@ +#include "TiberiumEaterTypeClass.h" + +#include +#include + +void TiberiumEaterTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection) +{ + INI_EX exINI(pINI); + + this->TransDelay.Read(exINI, pSection, "TiberiumEater.TransDelay"); + this->CashMultiplier.Read(exINI, pSection, "TiberiumEater.CashMultiplier"); + this->AmountPerCell.Read(exINI, pSection, "TiberiumEater.AmountPerCell"); + this->FrontOffset.Read(exINI, pSection, "TiberiumEater.FrontOffset"); + this->LeftOffset.Read(exINI, pSection, "TiberiumEater.LeftOffset"); + this->Display.Read(exINI, pSection, "TiberiumEater.Display"); + this->DisplayToHouse.Read(exINI, pSection, "TiberiumEater.DisplayToHouse"); + this->DisplayOffset.Read(exINI, pSection, "TiberiumEater.DisplayOffset"); + this->Anims.Read(exINI, pSection, "TiberiumEater.Anims"); + this->AnimMove.Read(exINI, pSection, "TiberiumEater.AnimMove"); +} + +template +bool TiberiumEaterTypeClass::Serialize(T& stm) +{ + return stm + .Process(this->TransDelay) + .Process(this->CashMultiplier) + .Process(this->AmountPerCell) + .Process(this->FrontOffset) + .Process(this->LeftOffset) + .Process(this->Display) + .Process(this->DisplayToHouse) + .Process(this->DisplayOffset) + .Process(this->Anims) + .Process(this->AnimMove) + .Success(); +} + +#pragma region(save/load) + +bool TiberiumEaterTypeClass::Load(PhobosStreamReader& stm, bool registerForChange) +{ + return this->Serialize(stm); +} + +bool TiberiumEaterTypeClass::Save(PhobosStreamWriter& stm) const +{ + return const_cast(this)->Serialize(stm); +} + +#pragma endregion diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h new file mode 100644 index 0000000000..7610ea515d --- /dev/null +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +class TiberiumEaterTypeClass +{ +public: + Valueable TransDelay { -1 }; + Valueable CashMultiplier { 1.0 }; + Valueable AmountPerCell { 0 }; + ValueableVector FrontOffset {}; + ValueableVector LeftOffset {}; + Valueable Display { true }; + Valueable DisplayToHouse { AffectedHouse::All }; + Valueable DisplayOffset { Point2D::Empty }; + ValueableVector Anims {}; + Valueable AnimMove { true }; + + TiberiumEaterTypeClass() = default; + + void LoadFromINI(CCINIClass* pINI, const char* pSection); + bool Load(PhobosStreamReader& stm, bool registerForChange); + bool Save(PhobosStreamWriter& stm) const; + +private: + + template + bool Serialize(T& stm); +}; From a6cf09aaff768840e1021a6a5436383781edef58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=9D=E5=8D=83=E5=A4=A9=E5=8D=8E?= <1065703286@qq.com> Date: Wed, 9 Apr 2025 22:17:10 +0800 Subject: [PATCH 03/14] Synchronize and update the documentation format from previous PR#1111 mobile-refinery --- docs/New-or-Enhanced-Logics.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index bd43023ada..695a2b045e 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1710,15 +1710,15 @@ NoQueueUpToUnload= ; boolean In `rulesmd.ini`: ```ini -[SOMETECHNO] ; InfantryType, UnitType or AircraftType +[SOMETECHNO] ; InfantryType, UnitType or AircraftType TiberiumEater.TransDelay=-1 ; integer -TiberiumEater.CashMultiplier=1.0 ; float +TiberiumEater.CashMultiplier=1.0 ; floating point value TiberiumEater.AmountPerCell=0 ; integer -TiberiumEater.FrontOffset= ; list of integer, use cell as unit, multiple values mean that they are effective in multiple cells at the same time -TiberiumEater.LeftOffset= ; list of integer, use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.FrontOffset= ; List of integers, use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.LeftOffset= ; List of integers, use cell as unit, multiple values mean that they are effective in multiple cells at the same time TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration -TiberiumEater.Anims= ; list of animations +TiberiumEater.Anims= ; List of AnimationTypes TiberiumEater.AnimMove=true ; boolean ``` From a62e26edba047a0780eed2b62a6b2f3b4953e859 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Thu, 10 Apr 2025 23:08:36 +0800 Subject: [PATCH 04/14] update --- docs/New-or-Enhanced-Logics.md | 4 ++-- src/Ext/Techno/Body.Update.cpp | 27 +++++++++++++-------------- src/Ext/Techno/Hooks.cpp | 1 + 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 695a2b045e..692d9e364e 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1701,8 +1701,8 @@ NoQueueUpToUnload= ; boolean ### Tiberium eater - Units can convert the ore underneath them into cash in real time, like GDI's EPIC unit MARV in Command & Conquer 3 Kane's Wrath, when `TiberiumEater.TransDelay` is 0 or larger. -- `TiberiumEater.TransDelay` specifies the interval in game frames between two mining "processes". -- `TiberiumEater.AmountPerCell` controls how many "bails" of ore can be mined at each cell at once. +- `TiberiumEater.TransDelay` specifies the interval in game frames between two mining "processes", 0 means eat in every frame. +- `TiberiumEater.AmountPerCell` controls how many "bails" of ore can be mined at each cell at once, <= 0 means no limit. - By default, ore mined this way is worth the same as if it was harvested and refined the normal way. This can be adjusted with `TiberiumEater.CashMultiplier`. - `TiberiumEater.Display=true` will create a flying text displaying the total cash amount received each mining process. `TiberiumEater.Display.Houses` controlls who can see this text. - An animation will be played at each interval at each mined cell. If `TiberiumEater.Anims` contains 8 entries, then an entry will be picked according to unit facing. Otherwise, an entry will be chosen at random. diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 22029e36e8..f4193edfa8 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -33,7 +33,6 @@ void TechnoExt::ExtData::OnEarlyUpdate() this->UpdateLaserTrails(); this->ApplyInterceptor(); this->EatPassengers(); - this->UpdateTiberiumEater(); this->ApplySpawnLimitRange(); this->ApplyMindControlRangeLimit(); this->UpdateRecountBurst(); @@ -342,10 +341,10 @@ void TechnoExt::ExtData::EatPassengers() void TechnoExt::ExtData::UpdateTiberiumEater() { - const auto pThis = this->OwnerObject(); const auto pEaterType = this->TypeExtData->TiberiumEaterType.get(); + const int transDelay = pEaterType->TransDelay; - if (pEaterType->TransDelay < 0 || this->TiberiumEater_Timer.InProgress()) + if (transDelay < 0 || this->TiberiumEater_Timer.InProgress()) return; const size_t frontSize = pEaterType->FrontOffset.size(); @@ -355,6 +354,7 @@ void TechnoExt::ExtData::UpdateTiberiumEater() if (!cellCount) cellCount = 1; + const auto pThis = this->OwnerObject(); const auto pOwner = pThis->Owner; CoordStruct flh {}; bool active = false; @@ -377,14 +377,11 @@ void TechnoExt::ExtData::UpdateTiberiumEater() if (!pCell) continue; - auto cellCoords = pCell->GetCoords(); - cellCoords.Z = std::max(pThis->Location.Z, cellCoords.Z); - if (const int contained = pCell->GetContainedTiberiumValue()) { const int tiberiumValue = TiberiumClass::Array[pCell->GetContainedTiberiumIndex()]->Value; const int tiberiumAmount = static_cast(static_cast(contained) / tiberiumValue); - const int amount = pEaterType->AmountPerCell ? std::min(pEaterType->AmountPerCell.Get(), tiberiumAmount) : tiberiumAmount; + const int amount = pEaterType->AmountPerCell > 0 ? std::min(pEaterType->AmountPerCell.Get(), tiberiumAmount) : tiberiumAmount; pCell->ReduceTiberium(amount); const float multiplier = pEaterType->CashMultiplier * (1.0f + pOwner->NumOrePurifiers * RulesClass::Instance->PurifierBonus); const int value = static_cast(std::round(amount * tiberiumValue * multiplier)); @@ -392,7 +389,11 @@ void TechnoExt::ExtData::UpdateTiberiumEater() active = true; if (displayCash) + { + auto cellCoords = pCell->GetCoords(); + cellCoords.Z = std::max(pThis->Location.Z, cellCoords.Z); FlyingStrings::AddMoneyString(value, pOwner, pEaterType->DisplayToHouse, cellCoords, pEaterType->DisplayOffset); + } if (animCount == 0) continue; @@ -416,18 +417,16 @@ void TechnoExt::ExtData::UpdateTiberiumEater() if (pAnimType) { - if (auto pAnim = GameCreate(pAnimType, pos)) - { - pAnim->Owner = pThis->Owner; + const auto pAnim = GameCreate(pAnimType, pos); + AnimExt::SetAnimOwnerHouseKind(pAnim, pThis->Owner, nullptr, false, true); - if (pEaterType->AnimMove) - pAnim->SetOwnerObject(pThis); - } + if (pEaterType->AnimMove) + pAnim->SetOwnerObject(pThis); } } } - if (active) + if (active && transDelay > 0) this->TiberiumEater_Timer.Start(pEaterType->TransDelay); } diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 5128a2215b..22bd2f6afd 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -37,6 +37,7 @@ DEFINE_HOOK(0x4DA54E, FootClass_AI, 0x6) pExt->UpdateTypeData_Foot(); pExt->UpdateWarpInDelay(); + pExt->UpdateTiberiumEater(); return 0; } From eb35a2733f312d7ec8578c737e65fd2baeff6979 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Thu, 10 Apr 2025 23:47:55 +0800 Subject: [PATCH 05/14] update Body.Update.cpp --- src/Ext/Techno/Body.Update.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index f4193edfa8..99696ec242 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -344,7 +344,7 @@ void TechnoExt::ExtData::UpdateTiberiumEater() const auto pEaterType = this->TypeExtData->TiberiumEaterType.get(); const int transDelay = pEaterType->TransDelay; - if (transDelay < 0 || this->TiberiumEater_Timer.InProgress()) + if (transDelay < 0 || (transDelay && this->TiberiumEater_Timer.InProgress())) return; const size_t frontSize = pEaterType->FrontOffset.size(); From 54764f6b86f1d232ef270e2f2bc13edc4d1e11f4 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Fri, 11 Apr 2025 12:43:28 +0800 Subject: [PATCH 06/14] update for make_unique --- src/Ext/Techno/Body.Update.cpp | 8 ++++++-- src/Ext/TechnoType/Body.cpp | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 99696ec242..08efe91388 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -342,9 +342,13 @@ void TechnoExt::ExtData::EatPassengers() void TechnoExt::ExtData::UpdateTiberiumEater() { const auto pEaterType = this->TypeExtData->TiberiumEaterType.get(); + + if (!pEaterType) + return; + const int transDelay = pEaterType->TransDelay; - if (transDelay < 0 || (transDelay && this->TiberiumEater_Timer.InProgress())) + if (transDelay && this->TiberiumEater_Timer.InProgress()) return; const size_t frontSize = pEaterType->FrontOffset.size(); @@ -426,7 +430,7 @@ void TechnoExt::ExtData::UpdateTiberiumEater() } } - if (active && transDelay > 0) + if (active && transDelay) this->TiberiumEater_Timer.Start(pEaterType->TransDelay); } diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 637f69cf69..1abbf323b8 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -19,7 +19,6 @@ TechnoTypeExt::ExtContainer TechnoTypeExt::ExtMap; void TechnoTypeExt::ExtData::Initialize() { this->ShieldType = ShieldTypeClass::FindOrAllocate(NONE_STR); - this->TiberiumEaterType = std::make_unique(); } void TechnoTypeExt::ExtData::ApplyTurretOffset(Matrix3D* mtx, double factor) @@ -648,6 +647,20 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->PassengerDeletionType->LoadFromINI(pINI, pSection); } + Nullable transDelay; + transDelay.Read(exINI, pSection, "TiberiumEater.TransDelay"); + + if (transDelay.Get(-1) >= 0 && !this->TiberiumEaterType) + this->TiberiumEaterType = std::make_unique(); + + if (this->TiberiumEaterType) + { + if (transDelay.isset() && transDelay.Get() < 0) + this->TiberiumEaterType.reset(); + else + this->TiberiumEaterType->LoadFromINI(pINI, pSection); + } + Nullable isInterceptor; isInterceptor.Read(exINI, pSection, "Interceptor"); @@ -674,8 +687,6 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->DroppodType.reset(); } - this->TiberiumEaterType->LoadFromINI(pINI, pSection); - if (GeneralUtils::IsValidString(pThis->PaletteFile) && !pThis->Palette) Debug::Log("[Developer warning] [%s] has Palette=%s set but no palette file was loaded (missing file or wrong filename). Missing palettes cause issues with lighting recalculations.\n", pArtSection, pThis->PaletteFile); } From 694968739cf753a0515cce8e84f2005bb47fd740 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Mon, 21 Apr 2025 23:48:12 +0800 Subject: [PATCH 07/14] Add a list of segmented animations based on Tiberium types --- src/Ext/Techno/Body.Update.cpp | 13 ++++++++----- src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp | 9 +++++++++ src/New/Type/Affiliated/TiberiumEaterTypeClass.h | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 08efe91388..937ec85a23 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -363,7 +363,6 @@ void TechnoExt::ExtData::UpdateTiberiumEater() CoordStruct flh {}; bool active = false; const bool displayCash = pEaterType->Display && pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer); - const int animCount = static_cast(pEaterType->Anims.size()); int facing = pThis->PrimaryFacing.Current().GetFacing<8>(); if (facing >= 7) @@ -383,7 +382,8 @@ void TechnoExt::ExtData::UpdateTiberiumEater() if (const int contained = pCell->GetContainedTiberiumValue()) { - const int tiberiumValue = TiberiumClass::Array[pCell->GetContainedTiberiumIndex()]->Value; + const int tiberiumIdx = pCell->GetContainedTiberiumIndex(); + const int tiberiumValue = TiberiumClass::Array[tiberiumIdx]->Value; const int tiberiumAmount = static_cast(static_cast(contained) / tiberiumValue); const int amount = pEaterType->AmountPerCell > 0 ? std::min(pEaterType->AmountPerCell.Get(), tiberiumAmount) : tiberiumAmount; pCell->ReduceTiberium(amount); @@ -399,6 +399,9 @@ void TechnoExt::ExtData::UpdateTiberiumEater() FlyingStrings::AddMoneyString(value, pOwner, pEaterType->DisplayToHouse, cellCoords, pEaterType->DisplayOffset); } + const auto& anims = pEaterType->Anims_Tiberiums[tiberiumIdx].GetElements(pEaterType->Anims); + const int animCount = static_cast(anims.size()); + if (animCount == 0) continue; @@ -407,15 +410,15 @@ void TechnoExt::ExtData::UpdateTiberiumEater() switch (animCount) { case 1: - pAnimType = pEaterType->Anims[0]; + pAnimType = anims[0]; break; case 8: - pAnimType = pEaterType->Anims[facing]; + pAnimType = anims[facing]; break; default: - pAnimType = pEaterType->Anims[ScenarioClass::Instance->Random.RandomRanged(0, pEaterType->Anims.size() - 1)]; + pAnimType = anims[ScenarioClass::Instance->Random.RandomRanged(0, animCount - 1)]; break; } diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp b/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp index 019d63747b..135d92d67b 100644 --- a/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp @@ -6,6 +6,7 @@ void TiberiumEaterTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection) { INI_EX exINI(pINI); + char tempBuffer[32]; this->TransDelay.Read(exINI, pSection, "TiberiumEater.TransDelay"); this->CashMultiplier.Read(exINI, pSection, "TiberiumEater.CashMultiplier"); @@ -16,6 +17,13 @@ void TiberiumEaterTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection) this->DisplayToHouse.Read(exINI, pSection, "TiberiumEater.DisplayToHouse"); this->DisplayOffset.Read(exINI, pSection, "TiberiumEater.DisplayOffset"); this->Anims.Read(exINI, pSection, "TiberiumEater.Anims"); + + for (size_t idx = 0; idx < 4; ++idx) + { + _snprintf_s(tempBuffer, sizeof(tempBuffer), "TiberiumEater.Anims.Tiberium%d", idx); + this->Anims_Tiberiums[idx].Read(exINI, pSection, tempBuffer); + } + this->AnimMove.Read(exINI, pSection, "TiberiumEater.AnimMove"); } @@ -32,6 +40,7 @@ bool TiberiumEaterTypeClass::Serialize(T& stm) .Process(this->DisplayToHouse) .Process(this->DisplayOffset) .Process(this->Anims) + .Process(this->Anims_Tiberiums) .Process(this->AnimMove) .Success(); } diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h index 7610ea515d..d670f69394 100644 --- a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h @@ -16,6 +16,7 @@ class TiberiumEaterTypeClass Valueable DisplayToHouse { AffectedHouse::All }; Valueable DisplayOffset { Point2D::Empty }; ValueableVector Anims {}; + std::vector> Anims_Tiberiums {}; Valueable AnimMove { true }; TiberiumEaterTypeClass() = default; From 3cd319382414539857adec250361380ed7d8a667 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Mon, 21 Apr 2025 23:50:32 +0800 Subject: [PATCH 08/14] update docs --- docs/New-or-Enhanced-Logics.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index f5d05f2055..5b9a0186d3 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1729,6 +1729,10 @@ TiberiumEater.LeftOffset= ; List of integers, use cell as unit, multiple TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration TiberiumEater.Anims= ; List of AnimationTypes +TiberiumEater.Anims.Tiberium0= ; List of AnimationTypes +TiberiumEater.Anims.Tiberium1= ; List of AnimationTypes +TiberiumEater.Anims.Tiberium2= ; List of AnimationTypes +TiberiumEater.Anims.Tiberium3= ; List of AnimationTypes TiberiumEater.AnimMove=true ; boolean ``` From 0422b0082e343e2fb987b091af74ddc1a4092b98 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Tue, 22 Apr 2025 12:19:31 +0800 Subject: [PATCH 09/14] fix error --- src/New/Type/Affiliated/TiberiumEaterTypeClass.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h index d670f69394..ba311bc7e7 100644 --- a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h @@ -16,7 +16,7 @@ class TiberiumEaterTypeClass Valueable DisplayToHouse { AffectedHouse::All }; Valueable DisplayOffset { Point2D::Empty }; ValueableVector Anims {}; - std::vector> Anims_Tiberiums {}; + NullableVector Anims_Tiberiums[4] {}; Valueable AnimMove { true }; TiberiumEaterTypeClass() = default; From ca79cb14704ddf1c06cac3a0ed33f8ef3c62f58f Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Tue, 22 Apr 2025 19:53:11 +0800 Subject: [PATCH 10/14] change offset tags --- docs/New-or-Enhanced-Logics.md | 3 +- src/Ext/Techno/Body.Update.cpp | 17 ++++------- .../Affiliated/TiberiumEaterTypeClass.cpp | 28 ++++++++++++++++--- .../Type/Affiliated/TiberiumEaterTypeClass.h | 3 +- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index b7075baf95..3b72689982 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1753,8 +1753,7 @@ In `rulesmd.ini`: TiberiumEater.TransDelay=-1 ; integer TiberiumEater.CashMultiplier=1.0 ; floating point value TiberiumEater.AmountPerCell=0 ; integer -TiberiumEater.FrontOffset= ; List of integers, use cell as unit, multiple values mean that they are effective in multiple cells at the same time -TiberiumEater.LeftOffset= ; List of integers, use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.CellsN= ; List of integers, use cell as unit, multiple values mean that they are effective in multiple cells at the same time TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration TiberiumEater.Anims= ; List of AnimationTypes diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 7a3a648cd6..b907cc9091 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -351,16 +351,8 @@ void TechnoExt::ExtData::UpdateTiberiumEater() if (transDelay && this->TiberiumEater_Timer.InProgress()) return; - const size_t frontSize = pEaterType->FrontOffset.size(); - const size_t leftSize = pEaterType->LeftOffset.size(); - size_t cellCount = std::max(frontSize, leftSize); - - if (!cellCount) - cellCount = 1; - const auto pThis = this->OwnerObject(); const auto pOwner = pThis->Owner; - CoordStruct flh {}; bool active = false; const bool displayCash = pEaterType->Display && pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer); int facing = pThis->PrimaryFacing.Current().GetFacing<8>(); @@ -370,11 +362,12 @@ void TechnoExt::ExtData::UpdateTiberiumEater() else facing++; - for (size_t idx = 0; idx < cellCount; idx++) + const int cellCount = static_cast(pEaterType->Cells.size()); + + for (int idx = 0; idx < cellCount; idx++) { - flh.X = frontSize > idx ? pEaterType->FrontOffset[idx] * Unsorted::LeptonsPerCell : 0; - flh.Y = leftSize > idx ? pEaterType->LeftOffset[idx] * Unsorted::LeptonsPerCell : 0; - const auto pos = TechnoExt::GetFLHAbsoluteCoords(pThis, flh, false); + const auto& cellOffset = pEaterType->Cells[idx]; + const auto pos = TechnoExt::GetFLHAbsoluteCoords(pThis, CoordStruct { cellOffset.X, cellOffset.Y, 0 }, false); const auto pCell = MapClass::Instance.TryGetCellAt(pos); if (!pCell) diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp b/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp index 135d92d67b..9b988fff42 100644 --- a/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp @@ -11,8 +11,29 @@ void TiberiumEaterTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection) this->TransDelay.Read(exINI, pSection, "TiberiumEater.TransDelay"); this->CashMultiplier.Read(exINI, pSection, "TiberiumEater.CashMultiplier"); this->AmountPerCell.Read(exINI, pSection, "TiberiumEater.AmountPerCell"); - this->FrontOffset.Read(exINI, pSection, "TiberiumEater.FrontOffset"); - this->LeftOffset.Read(exINI, pSection, "TiberiumEater.LeftOffset"); + + for (size_t idx = 0; ; ++idx) + { + Nullable> cell; + _snprintf_s(tempBuffer, sizeof(tempBuffer), "TiberiumEater.Cell%d", idx); + cell.Read(exINI, pSection, tempBuffer); + + if (idx >= this->Cells.size()) + { + if (!cell.isset()) + break; + + this->Cells.emplace_back(cell.Get().X * Unsorted::LeptonsPerCell, cell.Get().Y * Unsorted::LeptonsPerCell); + } + else + { + if (!cell.isset()) + continue; + + this->Cells[idx] = Vector2D { cell.Get().X * Unsorted::LeptonsPerCell, cell.Get().Y * Unsorted::LeptonsPerCell }; + } + } + this->Display.Read(exINI, pSection, "TiberiumEater.Display"); this->DisplayToHouse.Read(exINI, pSection, "TiberiumEater.DisplayToHouse"); this->DisplayOffset.Read(exINI, pSection, "TiberiumEater.DisplayOffset"); @@ -34,8 +55,7 @@ bool TiberiumEaterTypeClass::Serialize(T& stm) .Process(this->TransDelay) .Process(this->CashMultiplier) .Process(this->AmountPerCell) - .Process(this->FrontOffset) - .Process(this->LeftOffset) + .Process(this->Cells) .Process(this->Display) .Process(this->DisplayToHouse) .Process(this->DisplayOffset) diff --git a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h index ba311bc7e7..6762eee9d9 100644 --- a/src/New/Type/Affiliated/TiberiumEaterTypeClass.h +++ b/src/New/Type/Affiliated/TiberiumEaterTypeClass.h @@ -10,8 +10,7 @@ class TiberiumEaterTypeClass Valueable TransDelay { -1 }; Valueable CashMultiplier { 1.0 }; Valueable AmountPerCell { 0 }; - ValueableVector FrontOffset {}; - ValueableVector LeftOffset {}; + std::vector> Cells { std::vector>(1) }; Valueable Display { true }; Valueable DisplayToHouse { AffectedHouse::All }; Valueable DisplayOffset { Point2D::Empty }; From 49732dfb2f77e23854f9c545747b4112c3eb02df Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Tue, 22 Apr 2025 19:57:04 +0800 Subject: [PATCH 11/14] update docs --- docs/New-or-Enhanced-Logics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 3b72689982..abd03658d5 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1753,7 +1753,7 @@ In `rulesmd.ini`: TiberiumEater.TransDelay=-1 ; integer TiberiumEater.CashMultiplier=1.0 ; floating point value TiberiumEater.AmountPerCell=0 ; integer -TiberiumEater.CellsN= ; List of integers, use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.CellsN= ; x, y , use cell as unit, multiple values mean that they are effective in multiple cells at the same time TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration TiberiumEater.Anims= ; List of AnimationTypes From 93c5654ee08a7a7778139aba99a315959e52252d Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Tue, 22 Apr 2025 22:26:02 +0800 Subject: [PATCH 12/14] fix doc --- docs/New-or-Enhanced-Logics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index abd03658d5..e71a1ce298 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1753,7 +1753,7 @@ In `rulesmd.ini`: TiberiumEater.TransDelay=-1 ; integer TiberiumEater.CashMultiplier=1.0 ; floating point value TiberiumEater.AmountPerCell=0 ; integer -TiberiumEater.CellsN= ; x, y , use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.CellN= ; x, y , use cell as unit, multiple values mean that they are effective in multiple cells at the same time TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration TiberiumEater.Anims= ; List of AnimationTypes From 432c7e39a3be6fbd7d62e7dca50c1a355cae0166 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Wed, 23 Apr 2025 08:01:22 +0800 Subject: [PATCH 13/14] update --- docs/New-or-Enhanced-Logics.md | 4 ++-- src/Ext/Techno/Body.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 230dd1d1fd..d4aaefbb19 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1780,11 +1780,11 @@ AmphibiousUnload= ; boolean In `rulesmd.ini`: ```ini -[SOMETECHNO] ; InfantryType, UnitType or AircraftType +[SOMETECHNO] ; InfantryType, VehicleType or AircraftType TiberiumEater.TransDelay=-1 ; integer TiberiumEater.CashMultiplier=1.0 ; floating point value TiberiumEater.AmountPerCell=0 ; integer -TiberiumEater.CellN= ; x, y , use cell as unit, multiple values mean that they are effective in multiple cells at the same time +TiberiumEater.CellN= ; x, y , use cell as unit, multiple values mean that they are effective in multiple cells at the same time. N is zero-based. TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration TiberiumEater.Anims= ; List of AnimationTypes diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 36f57e5846..77aabd7f64 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -589,7 +589,7 @@ void TechnoExt::ExtData::Serialize(T& Stm) .Process(this->IsBeingChronoSphered) .Process(this->KeepTargetOnMove) .Process(this->LastSensorsMapCoords) - .Process(this->TiberiumEater_Timer) + .Process(this->TiberiumEater_Timer) .Process(this->AirstrikeTargetingMe) ; } From 63843cd3604ae1fce885fc7d4a41331f44cdbf17 Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Tue, 6 May 2025 15:59:03 +0800 Subject: [PATCH 14/14] update doc --- docs/New-or-Enhanced-Logics.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 95962e86ed..9918cbbe54 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1726,22 +1726,23 @@ VoiceCreated= ; Sound entry ### Tiberium eater -- Units can convert the ore underneath them into cash in real time, like GDI's EPIC unit MARV in Command & Conquer 3 Kane's Wrath, when `TiberiumEater.TransDelay` is 0 or larger. -- `TiberiumEater.TransDelay` specifies the interval in game frames between two mining "processes", 0 means eat in every frame. -- `TiberiumEater.AmountPerCell` controls how many "bails" of ore can be mined at each cell at once, <= 0 means no limit. -- By default, ore mined this way is worth the same as if it was harvested and refined the normal way. This can be adjusted with `TiberiumEater.CashMultiplier`. -- `TiberiumEater.Display`, if set to true, will create a flying text displaying the total cash amount received each mining process. `TiberiumEater.Display.Houses` controlls who can see this text. -- An animation will be played at each interval at each mined cell. If `TiberiumEater.Anims` contains 8 entries, then an entry will be picked according to unit facing. Otherwise, an entry will be chosen at random. - - `TiberiumEater.Anims.TiberiumN`, if set, will override `TiberiumEater.Anims` when mining corresponding tiberium type. - - If `TiberiumEater.AnimMove` set to true, the animations will move with the unit. +- TechnoTypes can convert the ores underneath them into credits in real time, like GDI's MARV in Command & Conquer 3 Kane's Wrath. +- `TiberiumEater.TransDelay` specifies the interval frames between two eating processes, 0 means eat in every frame. When it's below 0, the logic will be turned off for this TechnoType. +- `TiberiumEater.CellN` set a list of cells that'll process tiberium eating, where `N` is 0-based and the values are offset related to the TechnoType's current cell. If not set, only the ores on the TechnoType's current cell will be eaten. +- `TiberiumEater.AmountPerCell` controls the amount of ores that can be eaten at each cell at once. No limit when it's below 0. +- By default, ores mined in this way worth the same as regular harvesting. This can be adjusted by `TiberiumEater.CashMultiplier`. +- `TiberiumEater.Display`, if set to true, will create a flying text to display the total credits received in each eating process. `TiberiumEater.Display.Houses` determines which houses can see the credits display. +- An animation will be played at each mined cell in an eating process. If `TiberiumEater.Anims` contains 8 entries, entry from position matching the TechnoType's current facing will be chosen. Otherwise, an entry will be chosen randomly. + - `TiberiumEater.Anims.TiberiumN`, if set, will override `TiberiumEater.Anims` when eating corresponding tiberium type. + - If `TiberiumEater.AnimMove` set to true, the animations will move with the TechnoType. In `rulesmd.ini`: ```ini [SOMETECHNO] ; InfantryType, VehicleType or AircraftType TiberiumEater.TransDelay=-1 ; integer +TiberiumEater.CellN= ; X,Y - cell offset TiberiumEater.CashMultiplier=1.0 ; floating point value TiberiumEater.AmountPerCell=0 ; integer -TiberiumEater.CellN= ; x, y , use cell as unit, multiple values mean that they are effective in multiple cells at the same time. N is zero-based. TiberiumEater.Display=true ; boolean TiberiumEater.Display.Houses=all ; AffectedHouse enumeration TiberiumEater.Anims= ; List of AnimationTypes