From 6da5e4aa3124bec2a1eba270e98bcba1bda190e2 Mon Sep 17 00:00:00 2001 From: Vladimir Menshakov Date: Thu, 22 Oct 2026 11:06:52 +0100 Subject: [PATCH] PHOENIXVR: Run Sherlock - The Mystery of Mummy Add enough commands to compile and run sherlock startup script. The game is not playable just yet. --- engines/phoenixvr/commands_v2.cpp | 102 ++++++++++++++++++++++++++++-- engines/phoenixvr/phoenixvr.cpp | 2 +- engines/phoenixvr/script_v2.cpp | 4 +- 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/engines/phoenixvr/commands_v2.cpp b/engines/phoenixvr/commands_v2.cpp index 5974a89c82b..5f0f1635989 100644 --- a/engines/phoenixvr/commands_v2.cpp +++ b/engines/phoenixvr/commands_v2.cpp @@ -51,6 +51,59 @@ struct Sub : public Command { } }; +struct Add_Item : public Command { + Common::String name; + Common::String index; + Add_Item(const Common::Array &args) : name(args[0]), index(args[1]) {} + void exec(ExecutionContext &ctx) const override { + auto idx = valueOf(index); + warning("add_item %s %d", name.c_str(), idx); + } +}; + +struct Use_Item : public Command { + Common::String name; + Use_Item(const Common::Array &args) : name(args[0]) {} + void exec(ExecutionContext &ctx) const override { + warning("use_item %s", name.c_str()); + } +}; + +struct Remove_Item : public Command { + Common::String name; + Remove_Item(const Common::Array &args) : name(args[0]) {} + void exec(ExecutionContext &ctx) const override { + warning("remove_item %s", name.c_str()); + } +}; + +struct Drop_Item : public Command { + Drop_Item(const Common::Array &args) {} + void exec(ExecutionContext &ctx) const override { + warning("drop_item"); + } +}; + +struct Display_Message : public Command { + Common::String message; + Common::String duration; + Display_Message(const Common::Array &args) : message(args[0]), duration(args[1]) {} + void exec(ExecutionContext &ctx) const override { + auto m = valueOf(message); + auto d = valueOf(duration); + warning("display_message %d %d", m, d); + } +}; + +struct Call : public Command { + int test; + Call(const Common::Array &args) : test(atoi(args[0].c_str())) {} + void exec(ExecutionContext &ctx) const override { + debug("call %d", test); + g_engine->executeTest(test); + } +}; + struct Go_Back : public Command { Go_Back(const Common::Array &args) {} void exec(ExecutionContext &ctx) const override { @@ -128,6 +181,18 @@ struct Play_Amb : public Command { } }; +struct Play_Music : public Command { + Common::String path; + Common::String volume; + int loops; + Play_Music(const Common::Array &args) : path(args[0]), + volume(args.size() > 1 ? args[1] : Common::String{}), loops(args.size() > 2 ? atoi(args[2].c_str()) : 0) {} + void exec(ExecutionContext &ctx) const override { + int v = !volume.empty() ? valueOf(volume) : 100; + g_engine->playSound(path, Audio::Mixer::kMusicSoundType, v, loops); + } +}; + struct Delay_Sound : public Command { Common::String path; float delay; @@ -188,6 +253,10 @@ struct Stop_Sound : public Command { } }; +struct Stop_Music : public Stop_Sound { + Stop_Music(const Common::Array &args) : Stop_Sound(args) {} +}; + struct Stop_All_Sounds : public Command { Stop_All_Sounds(const Common::Array &args) {} @@ -347,7 +416,7 @@ struct Set_Jump_Key : public Command { key = 0; else if (keyName == "_KEY_RIGHT_CLIC") key = 12; - else if (keyName == "_KEY_Q" || keyName == "_KEY_SPACE") + else if (keyName == "_KEY_Q" || keyName == "_KEY_SPACE" || keyName == "_KEY_A") warning("unhandled key name: %s", keyName.c_str()); else error("unhandled key name: %s", keyName.c_str()); @@ -381,6 +450,20 @@ struct Test_Slot : public Command { } }; +struct Load_Context : public Command { + Load_Context(const Common::Array &args) {} + void exec(ExecutionContext &ctx) const override { + debug("load_context"); + } +}; + +struct Save_Context : public Command { + Save_Context(const Common::Array &args) {} + void exec(ExecutionContext &ctx) const override { + debug("save_context"); + } +}; + struct Load_Slot : public Command { Common::String slot; Load_Slot(const Common::Array &args) : slot(args[0]) {} @@ -481,6 +564,7 @@ static const char *const kUnhandledV2Commands[] = { "CURSOR_SET", "CURSOR_SET_SPEED", "DELAY_3DSOUND", + "DISPLAY", "DIV", "END", "END_SCRIPT", @@ -488,10 +572,11 @@ static const char *const kUnhandledV2Commands[] = { "GET_MOUSE_BUTTON", "GOTO_REF", "INTERPOLATE_VIEW", + "LOAD_CURSORS", + "LOAD_LETTERS", "MUL", "NOT", "OR", - "PLAY_MUSIC", "QUIT_SCRIPT", "SET_EFFECTS_MODE", "SET_FILTER_KEY", @@ -505,7 +590,6 @@ static const char *const kUnhandledV2Commands[] = { "SPRITE_SCREEN_MODE", "SPRITE_WARP", "SPRITE_WARP_MODE", - "STOP_MUSIC", "UNDERWATER_EFFECT", "ZONES_CLICK_MODE"}; @@ -513,10 +597,14 @@ static const char *const kUnhandledV2Commands[] = { #define COMMAND_LIST(E) \ E(Add) \ + E(Add_Item) \ + E(Display_Message) \ + E(Call) \ E(Continue_Game) \ E(Cursor_Load) \ E(Cursor_Set) \ E(Delay_Sound) \ + E(Drop_Item) \ E(Enter_Level) \ E(Exit_Game) \ E(Fade) \ @@ -525,14 +613,18 @@ static const char *const kUnhandledV2Commands[] = { E(Goto_Warp) \ E(Leave_Save) \ E(Limit_View) \ + E(Load_Context) \ E(Load_Slot) \ E(Play_3DSound) \ E(Play_Amb) \ E(Play_AnimBloc) \ E(Play_Movie) \ + E(Play_Music) \ E(Play_Sound) \ E(Quit_URL) \ + E(Remove_Item) \ E(Retrieve_State) \ + E(Save_Context) \ E(Save_Slot) \ E(Set_Jump_Key) \ E(Set_Lens) \ @@ -546,11 +638,13 @@ static const char *const kUnhandledV2Commands[] = { E(Stop_AnimBloc) \ E(Stop_Delay) \ E(Stop_Light) \ + E(Stop_Music) \ E(Stop_Sound) \ E(Stop_Timer) \ E(Store_State) \ E(Sub) \ - E(Test_Slot) + E(Test_Slot) \ + E(Use_Item) #define ADD_COMMAND(NAME) \ if (cmd.equalsIgnoreCase(#NAME)) \ diff --git a/engines/phoenixvr/phoenixvr.cpp b/engines/phoenixvr/phoenixvr.cpp index 25b933309a2..aeee772f2a8 100644 --- a/engines/phoenixvr/phoenixvr.cpp +++ b/engines/phoenixvr/phoenixvr.cpp @@ -1258,7 +1258,7 @@ Graphics::ManagedSurface *PhoenixVREngine::loadSurface(const Common::String &pat dec.reset(new Image::PCXDecoder); } else if (filename.hasSuffixIgnoreCase(".gif")) { dec.reset(new Image::GIFDecoder); - } else if (filename.hasSuffixIgnoreCase(".cur") || filename.hasSuffixIgnoreCase(".spr")) { + } else if (filename.hasSuffixIgnoreCase(".cur") || filename.hasSuffixIgnoreCase(".spr") || filename.hasSuffixIgnoreCase(".tga")) { dec.reset(new Image::TGADecoder); } else { warning("can't find decoder for %s", filename.c_str()); diff --git a/engines/phoenixvr/script_v2.cpp b/engines/phoenixvr/script_v2.cpp index 6afae4bf6a5..8a79728efdb 100644 --- a/engines/phoenixvr/script_v2.cpp +++ b/engines/phoenixvr/script_v2.cpp @@ -179,7 +179,7 @@ void ScriptV2::parseLine(const Common::String &line, uint lineno) { _warpNames.push_back(vr); _currentTest.reset(); _currentTestScope = nullptr; - } else if (p.maybe("test]:")) { + } else if (p.maybe("test]:") || p.maybe("stest]:")) { if (!_currentWarp) error("test without warp"); auto idx = p.nextInt(); @@ -260,6 +260,8 @@ void ScriptV2::parseLine(const Common::String &line, uint lineno) { } else if (p.maybe('(')) { auto args = p.readStringList(); p.expect(')'); + if (name.hasPrefixIgnoreCase("sh_")) + name = name.substr(3); command = createV2Command(name, args, lineno); } else error("invalid syntax at %d", lineno);