Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -642,3 +642,4 @@ This page lists all the individual contributions to the project by their author.
- **Damfoos** - extensive and thorough testing
- **Dmitry Volkov** - extensive and thorough testing
- **Rise of the East community** - extensive playtesting of in-dev features
- **ahasasjeb** - Add music to super weapons
22 changes: 22 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,28 @@ Detonate.Damage= ; integer
Detonate.AtFirer=false ; boolean
```

### Superweapon music control

- Superweapons can now play a soundtrack theme when fired and optionally stop after a configurable duration.

In `rulesmd.ini`:
```ini
[SOMESW] ; SuperWeaponType
Music.Theme= ; Soundtrack theme ID from thememd.ini (such as GodsendOne)
Music.Duration=0 ; integer, game frames; 0 or below means do not auto-stop,with the game speed set to 4, 15 frames equal 1 second.
Music.AffectedHouses= ; owner|allies|enemies|all (default all)
```

- `Music.Theme` selects the soundtrack theme by its ID defined in `thememd.ini` (such as `GodsendOne`).
- `Music.Duration` sets how long to keep playing, in game frames. 0 or below means no auto-stop.
- If a different theme is already playing, it will be replaced when the superweapon fires.
- When the timer completes, the theme is stopped only if the currently playing theme still equals the configured `Music.Theme`; if music was changed during the countdown, it will not be altered.
- `Music.AffectedHouses` determines which houses will hear and be affected by the superweapon music on their client: `owner`, `allies`, `enemies`, or `all` (default). Playback and auto-stop are applied only for those houses.

```{note}
To loop the music correctly during this period, set `Repeat=yes` for the corresponding theme in `thememd.ini`. Otherwise, the track may stop at its end even if `Music.Duration` has not elapsed.
```

## Technos

### Aggressive attack move mission
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ HideLightFlashEffects=false ; boolean
:open:

New:
- [Superweapon music control](New-or-Enhanced-Logics.md#superweapon-music-control) (by ahasasjeb)
- [Allow using waypoints, area guard and attack move with aircraft](Fixed-or-Improved-Logics.md#extended-aircraft-missions) (by CrimRecya)
- [Enhanced Straight trajectory](New-or-Enhanced-Logics.md#straight-trajectory) (by CrimRecya)
- [Enable building production queue](User-Interface.md#building-production-queue) (by CrimRecya)
Expand Down
5 changes: 5 additions & 0 deletions src/Ext/House/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <Utilities/TemplateDef.h>

#include <Ext/Building/Body.h>
#include <Timer.h>

#include <map>

Expand Down Expand Up @@ -61,6 +62,10 @@ class HouseExt
struct SWExt
{
int ShotCount;
CDTimerClass MusicTimer;
bool MusicActive;

SWExt() : ShotCount(0), MusicTimer(), MusicActive(false) { }
};
std::vector<SWExt> SuperExts;

Expand Down
13 changes: 13 additions & 0 deletions src/Ext/SWType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ void SWTypeExt::ExtData::Initialize()
this->EVA_SelectTarget = VoxClass::FindIndex("EVA_SelectTarget");

this->Message_CannotFire = CSFText("MSG:CannotFire");

// defaults for music control
this->Music_Theme = -1;
this->Music_Duration = 0;
}

// =============================
Expand Down Expand Up @@ -58,6 +62,10 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->LimboKill_Affected)
.Process(this->LimboKill_IDs)
.Process(this->RandomBuffer)
// music control
.Process(this->Music_Theme)
.Process(this->Music_Duration)
.Process(this->Music_AffectedHouses)
.Process(this->Detonate_Warhead)
.Process(this->Detonate_Weapon)
.Process(this->Detonate_Damage)
Expand Down Expand Up @@ -131,6 +139,11 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_MaxCount.Read(exINI, pSection, "SW.MaxCount");
this->SW_Shots.Read(exINI, pSection, "SW.Shots");

// music control
this->Music_Theme = pINI->ReadTheme(pSection, "Music.Theme", this->Music_Theme);
this->Music_Duration.Read(exINI, pSection, "Music.Duration");
this->Music_AffectedHouses.Read(exINI, pSection, "Music.AffectedHouses");

this->Message_CannotFire.Read(exINI, pSection, "Message.CannotFire");
this->Message_InsufficientFunds.Read(exINI, pSection, "Message.InsufficientFunds");

Expand Down
4 changes: 4 additions & 0 deletions src/Ext/SWType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class SWTypeExt
Valueable<AffectedHouse> LimboKill_Affected;
ValueableVector<int> LimboKill_IDs;
Valueable<double> RandomBuffer;
Valueable<int> Music_Theme;
Valueable<int> Music_Duration;
Valueable<AffectedHouse> Music_AffectedHouses;
ValueableIdxVector<SuperWeaponTypeClass> SW_Next;
Valueable<bool> SW_Next_RealLaunch;
Valueable<bool> SW_Next_IgnoreInhibitors;
Expand Down Expand Up @@ -187,6 +190,7 @@ class SWTypeExt
, SW_Link_RandomWeightsData {}
, Message_LinkedSWAcquired {}
, EVA_LinkedSWAcquired {}
, Music_AffectedHouses { AffectedHouse::All }
{ }

// Ares 0.A functions
Expand Down
18 changes: 18 additions & 0 deletions src/Ext/SWType/FireSuperWeapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <HouseClass.h>
#include <ScenarioClass.h>
#include <MessageListClass.h>
#include <ThemeClass.h>

#include <Utilities/EnumFunctions.h>
#include <Utilities/GeneralUtils.h>
Expand Down Expand Up @@ -46,6 +47,23 @@ void SWTypeExt::FireSuperWeaponExt(SuperClass* pSW, const CellStruct& cell)
auto& sw_ext = HouseExt::ExtMap.Find(pHouse)->SuperExts[pType->ArrayIndex];
sw_ext.ShotCount++;

// Music: play theme and start timer if configured
if (pTypeExt->Music_Theme.Get() >= 0)
{
const auto affected = pTypeExt->Music_AffectedHouses.Get();
if (EnumFunctions::CanTargetHouse(affected, pHouse, HouseClass::CurrentPlayer))
{
ThemeClass::Instance.Play(pTypeExt->Music_Theme);
}

const int duration = pTypeExt->Music_Duration.Get();
if (duration > 0)
{
sw_ext.MusicTimer.Start(duration);
sw_ext.MusicActive = true;
}
}

const auto pTags = &pHouse->RelatedTags;
if (pTags->Count > 0)
{
Expand Down
45 changes: 45 additions & 0 deletions src/Ext/Scenario/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <SessionClass.h>
#include <VeinholeMonsterClass.h>
#include <HouseClass.h>
#include <ThemeClass.h>
#include <Ext/House/Body.h>
#include <Ext/SWType/Body.h>

std::unique_ptr<ScenarioExt::ExtData> ScenarioExt::Data = nullptr;

Expand Down Expand Up @@ -265,5 +269,46 @@ DEFINE_HOOK(0x55B4E1, LogicClass_Update_BeforeAll, 0x5)
ScenarioExt::Global()->UpdateAutoDeathObjectsInLimbo();
ScenarioExt::Global()->UpdateTransportReloaders();

// SW music timers: stop music when timer completes
for (auto const pHouse : HouseClass::Array)
{
if (!pHouse) { continue; }
auto& houseExt = *HouseExt::ExtMap.Find(pHouse);
for (size_t i = 0; i < houseExt.SuperExts.size(); ++i)
{
auto& swExt = houseExt.SuperExts[i];
if (swExt.MusicActive && swExt.MusicTimer.Completed())
{
int configuredTheme = -1;
SuperClass* pSuper = nullptr;
SWTypeExt::ExtData* pTypeExt = nullptr;
if (pHouse->Supers.Count > static_cast<int>(i))
{
pSuper = pHouse->Supers[static_cast<int>(i)];
if (pSuper && pSuper->Type)
{
pTypeExt = SWTypeExt::ExtMap.Find(pSuper->Type);
configuredTheme = pTypeExt->Music_Theme.Get();
}
}
if (configuredTheme >= 0 && ThemeClass::Instance.CurrentTheme == configuredTheme)
{
// stop only if same theme and local house is affected
AffectedHouse affected = AffectedHouse::All;
if (pTypeExt)
{
affected = pTypeExt->Music_AffectedHouses.Get();
}
if (EnumFunctions::CanTargetHouse(affected, pHouse, HouseClass::CurrentPlayer))
{
ThemeClass::Instance.Stop();
}
}
swExt.MusicTimer.Stop();
swExt.MusicActive = false;
}
}
}

return 0;
}
Loading