Skip to content

Commit 0f8b6d2

Browse files
committed
Merge branch 'development' into browncoat-mission
2 parents f1e2a94 + 9392f2c commit 0f8b6d2

21 files changed

+419
-107
lines changed

.github/workflows/nightly.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ jobs:
127127
- name: Update tag pointing to the previous nightly release
128128
if: steps.check_nightly.outputs.release_exists
129129
run: |
130-
curl -X PATCH \
130+
curl --fail-with-body -X PATCH \
131131
-H "Authorization: Bearer ${{ secrets.WORKFLOW_TOKEN }}" \
132132
-H "Accept: application/vnd.github.v3+json" \
133133
https://api.github.com/repos/${{ github.repository }}/git/refs/tags/${{ env.PREV_TAG }} \

CHANGELOG.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
88

99
<details><summary><b>Added</b></summary>
1010

11-
- New music system, including a dynamic horizontal sequencing system, under the new music manager `MusicMan`.
11+
- New music system, including a dynamic horizontal sequencing system, under the new music manager `MusicMan`.
1212
`PlayDynamicSong(string songName, string songSectionName, bool playImmediately, bool playTransition, bool smoothFade)` to play a new DynamicSong.
13-
`SetNextDynamicSongSection(string songSectionName, bool playImmediately, bool playTransition, bool smoothFade)` to queue a new DynamicSongSection for the currently playing song.
14-
`PlayInterruptingMusic(SoundContainer soundContainer)` to start an interrupting piece of music which will pause any playing DynamicSong. Note that pause menu music happily overrides this currently.
15-
`EndInterruptingMusic()` to end any playing interrupting music, and resume any paused DynamicSongs.
16-
`EndDynamicMusic(bool fadeOut)` to end any currently playing dynamic music, optionally immediately fading it out. If not fading it out, the currently playing piece will play to completion.
13+
`SetNextDynamicSongSection(string songSectionName, bool playImmediately, bool playTransition, bool smoothFade)` to queue a new DynamicSongSection for the currently playing song.
14+
`PlayInterruptingMusic(SoundContainer soundContainer)` to start an interrupting piece of music which will pause any playing DynamicSong. Note that pause menu music happily overrides this currently.
15+
`EndInterruptingMusic()` to end any playing interrupting music, and resume any paused DynamicSongs.
16+
`EndDynamicMusic(bool fadeOut)` to end any currently playing dynamic music, optionally immediately fading it out. If not fading it out, the currently playing piece will play to completion.
1717
`ResetMusicState()` to immediately end all music and return the MusicMan to a blank state.
1818

19-
- New entities `DynamicSongSection` and `DynamicSong` which are used for organizing music to play using the new system.
20-
`DynamicSongSection` is made up of TransitionSoundContainers, SoundContainers, a string SectionType, and either randomnorepeat or shuffle SoundContainerSelectionCycleMode.
19+
- New entities `DynamicSongSection` and `DynamicSong` which are used for organizing music to play using the new system.
20+
`DynamicSongSection` is made up of TransitionSoundContainers, SoundContainers, a string SectionType, and either randomnorepeat or shuffle SoundContainerSelectionCycleMode.
2121
`DynamicSong` is a simple container of DynamicSongSections. It can have one DefaultSongSection and as many added sections as needed.
2222

23-
- New `SoundContainer` features.
24-
Lua property `Paused` (R/W) to pause or unpause all sounds of a SoundContainer. Newly played sounds will not begin playback until unpaused.
25-
Lua function `GetAudibleVolume` to get the real audible volume of a SoundContainer's sounds as a float from 0 to 1. This accounts for literally everything, including game volume.
23+
- New `SoundContainer` features.
24+
Lua property `Paused` (R/W) to pause or unpause all sounds of a SoundContainer. Newly played sounds will not begin playback until unpaused.
25+
Lua function `GetAudibleVolume` to get the real audible volume of a SoundContainer's sounds as a float from 0 to 1. This accounts for literally everything, including game volume.
26+
27+
- Allow lua scripts to use LuaJIT's BitOp module (see https://bitop.luajit.org/api.html)
2628

2729
</details>
2830

@@ -33,18 +35,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3335
- All music-related functionality from AudioMan has been removed due to the addition of the MusicMan. Generic DynamicSongs have been put in to use instead.
3436
Mod activities that used to queue up all the vanilla music should now instead call, for example, `MusicMan:PlayDynamicSong("Generic Battle Music")`
3537

36-
- Increased fog of war resolution in all vanilla activities, and conquest, from 20x20 to 4x4.
37-
The Ronin Scrambler, the basic scanner, and `SceneMan:CastUnseenRay` have been changed to accomodate fog of war resolutions as fine as 1x1 and as course as 20x20.
38+
- Increased fog-of-war resolution in all vanilla activities, and conquest, from 20x20 to 4x4.
39+
The Ronin Scrambler, the basic scanner, and `SceneMan:CastUnseenRay` have been changed to accomodate fog-of-war resolutions as fine as 1x1 and as course as 20x20.
40+
The fog-of-war revealing code is now multithreaded to increase performance.
3841

3942
- All vanilla scenario activities have had their settings polished, respecting settings which make sense and disabling settings which don't.
4043
You can now have fog of war in the test scene, and can no longer require path to orbit in Zero-G Diggers-Only One Man Army.
4144

4245
- The Signal Hunt activity no longer has a preview image, as it was not formatted correctly and spoiled the interior structure of the cave.
4346

47+
- `MovableObject`'s `UniqueID` and `Age` fields are now persisted through game save/load.
48+
4449
</details>
4550

4651
<details><summary><b>Fixed</b></summary>
4752

53+
- Fixed a crash on launch that could occur depending on what Microsoft Visual C++ Redistributable the user has installed.
54+
4855
- Fixed an issue where palette index 255 was incorrectly showing as black.
4956

5057
- Fixed instances of `CameraMan:GetScrollTarget()` and `CameraMan:SetScrollTarget()` supplying a player index instead of a screen index. This could prevent the functions from working properly, or at all, when playing as a player other than 1, potentially screwing up camera effects.

Source/Entities/DynamicSong.cpp

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -128,77 +128,79 @@ SoundContainer& DynamicSongSection::SelectTransitionSoundContainer() {
128128
if (m_TransitionSoundContainers.empty()) {
129129
return SelectSoundContainer();
130130
}
131-
if (m_TransitionSoundContainers.size() == 1) {
132-
return m_TransitionSoundContainers[0];
133-
}
134131

135-
if (m_TransitionShuffleUnplayedIndices.empty()) {
136-
for (unsigned int i = 0; i < m_TransitionSoundContainers.size(); i++) {
137-
if (i != m_LastTransitionSoundContainerIndex) {
138-
m_TransitionShuffleUnplayedIndices.push_back(i);
139-
}
140-
}
141-
}
142-
143-
switch (m_SoundContainerSelectionCycleMode) {
144-
case RANDOMNOREPEAT: {
145-
std::vector<unsigned int> validIndices;
132+
// Shuffle between our options if we have multiple
133+
if (m_TransitionSoundContainers.size() > 1) {
134+
if (m_TransitionShuffleUnplayedIndices.empty()) {
146135
for (unsigned int i = 0; i < m_TransitionSoundContainers.size(); i++) {
147136
if (i != m_LastTransitionSoundContainerIndex) {
148-
validIndices.push_back(i);
137+
m_TransitionShuffleUnplayedIndices.push_back(i);
149138
}
150139
}
151-
152-
unsigned int randomIndex = validIndices[RandomNum(0, static_cast<int>(validIndices.size()) - 1)];
153-
m_LastTransitionSoundContainerIndex = randomIndex;
154-
return m_TransitionSoundContainers[randomIndex];
155-
}
156-
case SHUFFLE: {
157-
unsigned int randomSelection = RandomNum(0, static_cast<int>(m_TransitionShuffleUnplayedIndices.size() - 1));
158-
unsigned int selectedIndex = m_TransitionShuffleUnplayedIndices[randomSelection];
159-
m_TransitionShuffleUnplayedIndices.erase(m_TransitionShuffleUnplayedIndices.begin() + randomSelection);
160-
m_LastTransitionSoundContainerIndex = selectedIndex;
161-
return m_TransitionSoundContainers[selectedIndex];
162140
}
163-
}
164-
}
165-
166-
SoundContainer& DynamicSongSection::SelectSoundContainer() {
167-
RTEAssert(!m_SoundContainers.empty(), "Tried to get a SoundContainer from a DynamicSongSection with none to choose from!");
168141

169-
if (m_SoundContainers.size() == 1) {
170-
return m_SoundContainers[0];
171-
}
142+
switch (m_SoundContainerSelectionCycleMode) {
143+
case RANDOMNOREPEAT: {
144+
std::vector<unsigned int> validIndices;
145+
for (unsigned int i = 0; i < m_TransitionSoundContainers.size(); i++) {
146+
if (i != m_LastTransitionSoundContainerIndex) {
147+
validIndices.push_back(i);
148+
}
149+
}
172150

173-
if (m_ShuffleUnplayedIndices.empty()) {
174-
for (unsigned int i = 0; i < m_SoundContainers.size(); i++) {
175-
if (i != m_LastSoundContainerIndex) {
176-
m_ShuffleUnplayedIndices.push_back(i);
151+
unsigned int randomIndex = validIndices[RandomNum(0, static_cast<int>(validIndices.size()) - 1)];
152+
m_LastTransitionSoundContainerIndex = randomIndex;
153+
return m_TransitionSoundContainers[randomIndex];
154+
}
155+
case SHUFFLE: {
156+
unsigned int randomSelection = RandomNum(0, static_cast<int>(m_TransitionShuffleUnplayedIndices.size() - 1));
157+
unsigned int selectedIndex = m_TransitionShuffleUnplayedIndices[randomSelection];
158+
m_TransitionShuffleUnplayedIndices.erase(m_TransitionShuffleUnplayedIndices.begin() + randomSelection);
159+
m_LastTransitionSoundContainerIndex = selectedIndex;
160+
return m_TransitionSoundContainers[selectedIndex];
177161
}
178162
}
179163
}
180164

181-
switch (m_SoundContainerSelectionCycleMode) {
182-
case RANDOMNOREPEAT: {
183-
std::vector<unsigned int> validIndices;
165+
return m_TransitionSoundContainers[0];
166+
}
167+
168+
SoundContainer& DynamicSongSection::SelectSoundContainer() {
169+
// Shuffle between our options if we have multiple
170+
if (m_SoundContainers.size() != 1) {
171+
if (m_ShuffleUnplayedIndices.empty()) {
184172
for (unsigned int i = 0; i < m_SoundContainers.size(); i++) {
185173
if (i != m_LastSoundContainerIndex) {
186-
validIndices.push_back(i);
174+
m_ShuffleUnplayedIndices.push_back(i);
187175
}
188176
}
189-
190-
unsigned int randomIndex = validIndices[RandomNum(0, static_cast<int>(validIndices.size()) - 1)];
191-
m_LastSoundContainerIndex = randomIndex;
192-
return m_SoundContainers[randomIndex];
193177
}
194-
case SHUFFLE: {
195-
unsigned int randomSelection = RandomNum(0, static_cast<int>(m_ShuffleUnplayedIndices.size() - 1));
196-
unsigned int selectedIndex = m_ShuffleUnplayedIndices[randomSelection];
197-
m_ShuffleUnplayedIndices.erase(m_ShuffleUnplayedIndices.begin() + randomSelection);
198-
m_LastSoundContainerIndex = selectedIndex;
199-
return m_SoundContainers[selectedIndex];
178+
179+
switch (m_SoundContainerSelectionCycleMode) {
180+
case RANDOMNOREPEAT: {
181+
std::vector<unsigned int> validIndices;
182+
for (unsigned int i = 0; i < m_SoundContainers.size(); i++) {
183+
if (i != m_LastSoundContainerIndex) {
184+
validIndices.push_back(i);
185+
}
186+
}
187+
188+
unsigned int randomIndex = validIndices[RandomNum(0, static_cast<int>(validIndices.size()) - 1)];
189+
m_LastSoundContainerIndex = randomIndex;
190+
return m_SoundContainers[randomIndex];
191+
}
192+
case SHUFFLE: {
193+
unsigned int randomSelection = RandomNum(0, static_cast<int>(m_ShuffleUnplayedIndices.size() - 1));
194+
unsigned int selectedIndex = m_ShuffleUnplayedIndices[randomSelection];
195+
m_ShuffleUnplayedIndices.erase(m_ShuffleUnplayedIndices.begin() + randomSelection);
196+
m_LastSoundContainerIndex = selectedIndex;
197+
return m_SoundContainers[selectedIndex];
198+
}
200199
}
201200
}
201+
202+
RTEAssert(!m_SoundContainers.empty(), "Tried to get a SoundContainer from a DynamicSongSection with none to choose from!");
203+
return m_SoundContainers[0];
202204
}
203205

204206
DynamicSong::DynamicSong() {

Source/Entities/MovableObject.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ using namespace RTE;
2323

2424
AbstractClassInfo(MovableObject, SceneObject);
2525

26-
std::atomic<long> MovableObject::m_UniqueIDCounter = 1;
2726
std::string MovableObject::ms_EmptyString = "";
2827

2928
MovableObject::MovableObject() {
@@ -138,17 +137,21 @@ LuaStateWrapper& MovableObject::GetAndLockStateForScript(const std::string& scri
138137
}
139138

140139
int MovableObject::Create() {
141-
if (SceneObject::Create() < 0)
140+
if (SceneObject::Create() < 0) {
142141
return -1;
142+
}
143143

144-
m_AgeTimer.Reset();
145144
m_RestTimer.Reset();
146145

147146
// If the stop time hasn't been assigned, just make the same as the life time.
148-
if (m_EffectStopTime <= 0)
147+
if (m_EffectStopTime <= 0) {
149148
m_EffectStopTime = m_Lifetime;
149+
}
150150

151-
m_UniqueID = MovableObject::GetNextUniqueID();
151+
if (m_UniqueID == 0) {
152+
m_UniqueID = g_MovableMan.GetNextUniqueID();
153+
m_AgeTimer.Reset();
154+
}
152155

153156
m_MOIDHit = g_NoMOID;
154157
m_TerrainMatHit = g_MaterialAir;
@@ -177,7 +180,7 @@ int MovableObject::Create(const float mass,
177180
m_HitsMOs = hitMOs;
178181
m_GetsHitByMOs = getHitByMOs;
179182

180-
m_UniqueID = MovableObject::GetNextUniqueID();
183+
m_UniqueID = g_MovableMan.GetNextUniqueID();
181184

182185
m_MOIDHit = g_NoMOID;
183186
m_TerrainMatHit = g_MaterialAir;
@@ -203,9 +206,6 @@ int MovableObject::Create(const MovableObject& reference) {
203206
m_RestThreshold = reference.m_RestThreshold;
204207
// m_Force = reference.m_Force;
205208
// m_ImpulseForce = reference.m_ImpulseForce;
206-
// Should reset age instead??
207-
// m_AgeTimer = reference.m_AgeTimer;
208-
m_AgeTimer.Reset();
209209
m_RestTimer.Reset();
210210
m_Lifetime = reference.m_Lifetime;
211211
m_Sharpness = reference.m_Sharpness;
@@ -266,7 +266,17 @@ int MovableObject::Create(const MovableObject& reference) {
266266
m_NumberValueMap = reference.m_NumberValueMap;
267267
m_ObjectValueMap = reference.m_ObjectValueMap;
268268

269-
m_UniqueID = MovableObject::GetNextUniqueID();
269+
// If we have a -1 unique ID, then we're currently performing a game save or load
270+
// In this case, we actually want to persist our existing IDs
271+
if (g_MovableMan.ShouldPersistUniqueIDs()) {
272+
m_UniqueID = reference.m_UniqueID;
273+
m_AgeTimer = reference.m_AgeTimer;
274+
} else {
275+
// Otherwise we're copying from a preset normally and ought to create a new object
276+
m_UniqueID = g_MovableMan.GetNextUniqueID();
277+
m_AgeTimer.Reset();
278+
}
279+
270280
g_MovableMan.RegisterObject(this);
271281

272282
return 0;
@@ -374,6 +384,11 @@ int MovableObject::ReadProperty(const std::string_view& propName, Reader& reader
374384
MatchProperty("SimUpdatesBetweenScriptedUpdates", { reader >> m_SimUpdatesBetweenScriptedUpdates; });
375385
MatchProperty("AddCustomValue", { ReadCustomValueProperty(reader); });
376386
MatchProperty("ForceIntoMasterLuaState", { reader >> m_ForceIntoMasterLuaState; });
387+
MatchProperty("SpecialBehaviour_SetUniqueID", {
388+
long oldID = m_UniqueID;
389+
reader >> m_UniqueID;
390+
g_MovableMan.ReregisterObjectIfApplicable(this, oldID);
391+
});
377392

378393
EndPropertyList;
379394
}

Source/Entities/MovableObject.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -979,10 +979,6 @@ namespace RTE {
979979
/// @param newRestThreshold New rest threshold value
980980
void SetRestThreshold(int newRestThreshold) { m_RestThreshold = newRestThreshold; }
981981

982-
/// Returns the next unique id for MO's and increments unique ID counter
983-
/// @return Returns the next unique id.
984-
static long GetNextUniqueID() { return ++m_UniqueIDCounter; }
985-
986982
/// Returns this MO's unique persistent ID
987983
/// @return Returns this MO's unique persistent ID
988984
long GetUniqueID() const { return m_UniqueID; }
@@ -1139,8 +1135,7 @@ namespace RTE {
11391135
/// @param A MovableObject object which is passed in by reference.
11401136
// Member variables
11411137
static Entity::ClassInfo m_sClass;
1142-
// Global counter with unique ID's
1143-
static std::atomic<long> m_UniqueIDCounter;
1138+
11441139
// The type of MO this is, either Actor, Item, or Particle
11451140
int m_MOType;
11461141
float m_Mass; // In metric kilograms (kg).

Source/Entities/Scene.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,7 @@ void Scene::SaveSceneObject(Writer& writer, const SceneObject* sceneObjectToSave
11721172
writer.NewPropertyWithValue("LifeTime", movableObjectToSave->GetLifetime());
11731173
writer.NewPropertyWithValue("Age", movableObjectToSave->GetAge());
11741174
writer.NewPropertyWithValue("PinStrength", movableObjectToSave->GetPinStrength());
1175+
writer.NewPropertyWithValue("SpecialBehaviour_SetUniqueID", movableObjectToSave->GetUniqueID());
11751176
}
11761177

11771178
if (const MOSprite* moSpriteToSave = dynamic_cast<const MOSprite*>(sceneObjectToSave)) {

Source/GUI/GUIReader.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ GUIReader& GUIReader::operator>>(unsigned long& var) {
359359
return *this;
360360
}
361361

362+
GUIReader& GUIReader::operator>>(long long& var) {
363+
DiscardEmptySpace();
364+
*m_Stream >> var;
365+
return *this;
366+
}
367+
362368
// Yeah, this is dumb - read as double and cast.
363369
// This is because, for whatever fucking reason, iostream can save out floats at a precision that it's then unable to read...
364370
GUIReader& GUIReader::operator>>(float& var) {

Source/GUI/GUIReader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ namespace RTE {
9292
GUIReader& operator>>(unsigned int& var);
9393
GUIReader& operator>>(long& var);
9494
GUIReader& operator>>(unsigned long& var);
95+
GUIReader& operator>>(long long& var);
9596
GUIReader& operator>>(float& var);
9697
GUIReader& operator>>(double& var);
9798
GUIReader& operator>>(std::string& var);

Source/Main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ void PollSDLEvents() {
245245
void RunMenuLoop() {
246246
g_UInputMan.DisableKeys(false);
247247
g_UInputMan.TrapMousePos(false);
248+
g_TimerMan.PauseSim(true);
248249

249250
while (!System::IsSetToQuit()) {
250251
g_WindowMan.ClearRenderer();

0 commit comments

Comments
 (0)