diff --git a/CREDITS.md b/CREDITS.md
index 6a2035cd83..293b8fa316 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -153,6 +153,7 @@ This page lists all the individual contributions to the project by their author.
- Event 606: AttachEffect is attaching to a Techno
- Linked superweapons
- Unit & infantry auto-conversion on ammo change
+ - Force the check of events in sequential order
- **Starkku**:
- Misc. minor bugfixes & improvements
- AI script actions:
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index 2def0db9a8..0b20114b16 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -23,6 +23,7 @@
+
@@ -218,6 +219,7 @@
+
diff --git a/YRpp b/YRpp
index 5af96790ce..beb80e8fbd 160000
--- a/YRpp
+++ b/YRpp
@@ -1 +1 @@
-Subproject commit 5af96790ce73e4ea068a390c60c124dccbc220e1
+Subproject commit beb80e8fbd48cd2d016ffaccb7f2c3476ef728d5
diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md
index 4e31d7e494..bdc0d975c0 100644
--- a/docs/AI-Scripting-and-Mapping.md
+++ b/docs/AI-Scripting-and-Mapping.md
@@ -881,3 +881,18 @@ In `mycampaign.map`:
ID=EventCount,...,606,2,0,[AttachEffectType],...
...
```
+
+### `1000` Force the check of events in sequential order
+
+- By default, the game evaluates all map triggers in parallel. Adding this map event forces short-circuit evaluation as soon as any subsequent event returns `false`.
+- This only affects evaluation from this control event (inclusive) to the last event in the list.
+- All events placed before this control event still work in a non-short-circuiting manner.
+- Sequential events will not begin evaluation until all preceding events have successfully completed.
+
+In `mycampaign.map`:
+```ini
+[Events]
+...
+ID=EventCount,...,1000,0,0,0,...
+...
+```
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index f550b9df7d..bb9543c9e5 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -464,6 +464,7 @@ New:
- [Customize if cloning need power](Fixed-or-Improved-Logics.md#customize-if-cloning-need-power) (by NetsuNegi)
- [Added Target Filtering Options to AttachEffect System](New-or-Enhanced-Logics.md#attached-effects) (by Flactine)
- [Customize type selection for IFV](Fixed-or-Improved-Logics.md#customize-type-selection-for-ifv) (by NetsuNegi)
+- Force the check of events in sequential order (by FS-21)
- CellSpread in cylinder shape (by TaranDahl)
- CellSpread damage check if victim is in air or on floor (by TaranDahl)
diff --git a/src/Ext/TEvent/Body.h b/src/Ext/TEvent/Body.h
index 553494e697..994286c564 100644
--- a/src/Ext/TEvent/Body.h
+++ b/src/Ext/TEvent/Body.h
@@ -56,6 +56,8 @@ enum PhobosTriggerEvent
CellHasAnyTechnoTypeFromList = 605,
AttachedIsUnderAttachedEffect = 606,
+ ForceSequentialEvents = 1000,
+
_DummyMaximum,
};
diff --git a/src/Ext/Trigger/Body.cpp b/src/Ext/Trigger/Body.cpp
new file mode 100644
index 0000000000..2b66f83dbd
--- /dev/null
+++ b/src/Ext/Trigger/Body.cpp
@@ -0,0 +1,101 @@
+#include "Body.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+//Static init
+TriggerExt::ExtContainer TriggerExt::ExtMap;
+
+// =============================
+// load / save
+
+template
+void TriggerExt::ExtData::Serialize(T& Stm)
+{
+ Stm
+ .Process(this->SortedEventsList)
+ .Process(this->SequentialTimers)
+ .Process(this->SequentialTimersOriginalValue)
+ .Process(this->ParallelTimers)
+ .Process(this->ParallelTimersOriginalValue)
+ .Process(this->SequentialSwitchModeIndex)
+ ;
+}
+
+void TriggerExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
+{
+ Extension::LoadFromStream(Stm);
+ this->Serialize(Stm);
+}
+
+void TriggerExt::ExtData::SaveToStream(PhobosStreamWriter& Stm)
+{
+ Extension::SaveToStream(Stm);
+ this->Serialize(Stm);
+}
+
+DEFINE_HOOK(0x7260C8, TriggerClass_CTOR, 0x8)
+{
+ GET(TriggerClass*, pItem, ESI);
+
+ TriggerExt::ExtMap.Allocate(pItem);
+
+ return 0;
+}
+
+DEFINE_HOOK(0x72617D, TriggerClass_DTOR, 0xF)
+{
+ GET(TriggerClass*, pItem, ESI);
+
+ TriggerExt::ExtMap.Remove(pItem);
+
+ return 0;
+}
+
+DEFINE_HOOK(0x726860, TriggerClass_Load_Prefix, 0x5)
+{
+ GET_STACK(TriggerClass*, pItem, 0x4);
+ GET_STACK(IStream*, pStm, 0x8);
+
+ TriggerExt::ExtMap.PrepareStream(pItem, pStm);
+
+ return 0;
+}
+
+DEFINE_HOOK(0x7268CB, TriggerClass_Load_Suffix, 0x4)
+{
+ TriggerExt::ExtMap.LoadStatic();
+
+ return 0;
+}
+
+DEFINE_HOOK(0x7268D0, TriggerClass_Save_Prefix, 0x8)
+{
+ GET_STACK(TriggerClass*, pItem, 0x4);
+ GET_STACK(IStream*, pStm, 0x8);
+
+ TriggerExt::ExtMap.PrepareStream(pItem, pStm);
+
+ return 0;
+}
+
+DEFINE_HOOK(0x7268EA, TriggerClass_Save_Suffix, 0x5)
+{
+ TriggerExt::ExtMap.SaveStatic();
+
+ return 0;
+}
+
+// =============================
+// container
+
+TriggerExt::ExtContainer::ExtContainer() : Container("TriggerClass") { }
+
+TriggerExt::ExtContainer::~ExtContainer() = default;
+
+// =============================
+// container hooks
diff --git a/src/Ext/Trigger/Body.h b/src/Ext/Trigger/Body.h
new file mode 100644
index 0000000000..1cf57b8428
--- /dev/null
+++ b/src/Ext/Trigger/Body.h
@@ -0,0 +1,58 @@
+#pragma once
+#include
+#include
+
+#include