diff --git a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp index 6b847211..b51011b5 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp @@ -2,6 +2,7 @@ #include "act3.h" #include "credits_actions.h" +#include "extensions/siloader.h" #include "helicopter.h" #include "infomain_actions.h" #include "intro_actions.h" @@ -36,6 +37,8 @@ DECOMP_SIZE_ASSERT(Infocenter, 0x1d8) DECOMP_SIZE_ASSERT(InfocenterMapEntry, 0x18) DECOMP_SIZE_ASSERT(InfocenterState, 0x94) +using namespace Extensions; + // GLOBAL: LEGO1 0x100f76a0 const char* g_object2x4red = "2x4red"; @@ -339,7 +342,8 @@ MxLong Infocenter::HandleEndAction(MxEndActionNotificationParam& p_param) MxLong result = m_radio.Notify(p_param); - if (result || (action->GetAtomId() != m_atomId && action->GetAtomId() != *g_introScript)) { + if (result || (action->GetAtomId() != m_atomId && action->GetAtomId() != *g_introScript && + !Extension::Call(ReplacedIn, *action, m_atomId, *g_introScript).value_or(false))) { return result; } diff --git a/assets/badend/BadEnd_Smk.smk b/assets/badend/BadEnd_Smk.smk new file mode 100644 index 00000000..401a7e6d Binary files /dev/null and b/assets/badend/BadEnd_Smk.smk differ diff --git a/assets/badend/BadEnd_Wav.wav b/assets/badend/BadEnd_Wav.wav new file mode 100644 index 00000000..33d0d207 Binary files /dev/null and b/assets/badend/BadEnd_Wav.wav differ diff --git a/assets/main.cpp b/assets/main.cpp index ef269e97..3557d3e2 100644 --- a/assets/main.cpp +++ b/assets/main.cpp @@ -200,6 +200,71 @@ void CreateHDMusic() si.Write(result.c_str()); } +void CreateBadEnd() +{ + std::string result = out + "/badend.si"; + + si::Interleaf si; + mxHd.seek(0, si::MemoryBuffer::SeekStart); + si.Read(&mxHd); + + si::Object* composite = new si::Object; + std::string extra = "Replace:\\lego\\scripts\\intro:4"; + composite->id_ = 0; + composite->type_ = si::MxOb::Presenter; + composite->flags_ = MxDSAction::c_enabled; + composite->duration_ = 0; + composite->loops_ = 1; + composite->extra_ = si::bytearray(extra.c_str(), extra.length() + 1); + composite->presenter_ = "MxCompositeMediaPresenter"; + composite->name_ = "BadEnd_Movie"; + si.AppendChild(composite); + + si::Object* smk = new si::Object; + std::string file = std::string("badend/BadEnd_Smk.smk"); + smk->id_ = 1; + smk->type_ = si::MxOb::Video; + smk->flags_ = MxDSAction::c_enabled; + smk->duration_ = 75100; + smk->loops_ = 1; + smk->presenter_ = "MxSmkPresenter"; + smk->name_ = "BadEnd_Smk"; + smk->filetype_ = si::MxOb::SMK; + smk->location_ = si::Vector3(0, 0, -10000); + smk->direction_ = si::Vector3(0, 0, 1); + smk->up_ = si::Vector3(0, 1, 0); + smk->unknown29_ = 1; // Palette management = yes + if (!smk->ReplaceWithFile(file.c_str())) { + abort(); + } + + composite->AppendChild(smk); + depfile << result << ": " << (std::filesystem::current_path() / file).string() << std::endl; + + si::Object* wav = new si::Object; + file = std::string("badend/BadEnd_Wav.wav"); + wav->id_ = 2; + wav->type_ = si::MxOb::Sound; + wav->flags_ = MxDSAction::c_enabled; + wav->duration_ = 77800; + wav->loops_ = 1; + wav->presenter_ = "MxWavePresenter"; + wav->name_ = "BadEnd_Wav"; + wav->filetype_ = si::MxOb::WAV; + wav->location_ = si::Vector3(0, 0, 0); + wav->direction_ = si::Vector3(0, 0, 1); + wav->up_ = si::Vector3(0, 1, 0); + wav->volume_ = 79; + if (!wav->ReplaceWithFile(file.c_str())) { + abort(); + } + + composite->AppendChild(wav); + depfile << result << ": " << (std::filesystem::current_path() / file).string() << std::endl; + + si.Write(result.c_str()); +} + int main(int argc, char* argv[]) { out = argv[1]; @@ -213,5 +278,6 @@ int main(int argc, char* argv[]) CreateWidescreen(); CreateHDMusic(); + CreateBadEnd(); return 0; } diff --git a/extensions/include/extensions/siloader.h b/extensions/include/extensions/siloader.h index 3f50d08a..2a82bd3b 100644 --- a/extensions/include/extensions/siloader.h +++ b/extensions/include/extensions/siloader.h @@ -27,6 +27,9 @@ class SiLoader { static std::optional HandleDelete(MxDSAction& p_action); static MxBool HandleEndAction(MxEndActionNotificationParam& p_param); + template + static bool ReplacedIn(MxDSAction& p_action, Args... p_args); + static std::map options; static std::vector files; static std::vector directives; @@ -47,12 +50,30 @@ class SiLoader { }; #ifdef EXTENSIONS +template +bool SiLoader::ReplacedIn(MxDSAction& p_action, Args... p_args) +{ + StreamObject object{p_action.GetAtomId(), p_action.GetObjectId()}; + auto checkAtomId = [&p_action, &object](const auto& p_atomId) -> bool { + for (const auto& key : replace) { + if (key.second == object && key.first.first == p_atomId) { + return true; + } + } + + return false; + }; + + return (checkAtomId(p_args) || ...); +} + constexpr auto Load = &SiLoader::Load; constexpr auto HandleFind = &SiLoader::HandleFind; constexpr auto HandleStart = &SiLoader::HandleStart; constexpr auto HandleRemove = &SiLoader::HandleRemove; constexpr auto HandleDelete = &SiLoader::HandleDelete; constexpr auto HandleEndAction = &SiLoader::HandleEndAction; +constexpr auto ReplacedIn = [](auto&&... args) { return SiLoader::ReplacedIn(std::forward(args)...); }; #else constexpr decltype(&SiLoader::Load) Load = nullptr; constexpr decltype(&SiLoader::HandleFind) HandleFind = nullptr; @@ -60,5 +81,9 @@ constexpr decltype(&SiLoader::HandleStart) HandleStart = nullptr; constexpr decltype(&SiLoader::HandleRemove) HandleRemove = nullptr; constexpr decltype(&SiLoader::HandleDelete) HandleDelete = nullptr; constexpr decltype(&SiLoader::HandleEndAction) HandleEndAction = nullptr; +constexpr auto ReplacedIn = [](auto&&... args) { + ((void) args, ...); + return false; +}; #endif }; // namespace Extensions