[Scummvm-git-logs] scummvm master -> ea5029209929423eaeec402added5972e7c60a2f

mduggan noreply at scummvm.org
Sun Oct 27 07:27:40 UTC 2024


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
50cface678 DGDS: Implement Heart of China intro natives
ea50292099 DGDS: JANITORIAL: Fix whitespace


Commit: 50cface678ec6a0bacb5dc455ef1898965955378
    https://github.com/scummvm/scummvm/commit/50cface678ec6a0bacb5dc455ef1898965955378
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-10-27T18:25:47+11:00

Commit Message:
DGDS: Implement Heart of China intro natives

The full intro cinematic can now play correctly.

Changed paths:
  A engines/dgds/dragon_native.cpp
  A engines/dgds/dragon_native.h
  A engines/dgds/hoc_intro.cpp
  A engines/dgds/hoc_intro.h
    engines/dgds/dgds.cpp
    engines/dgds/dgds.h
    engines/dgds/globals.cpp
    engines/dgds/globals.h
    engines/dgds/menu.cpp
    engines/dgds/module.mk
    engines/dgds/scene.cpp
    engines/dgds/scene.h
    engines/dgds/shell_game.h
    engines/dgds/sound/drivers/midipatch.cpp
    engines/dgds/ttm.cpp


diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 86f29035f00..7e41e539f41 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -63,6 +63,7 @@
 #include "dgds/sound.h"
 #include "dgds/game_palettes.h"
 #include "dgds/dragon_arcade.h"
+#include "dgds/hoc_intro.h"
 
 // for frame contents debugging
 //#define DUMP_FRAME_DATA 1
@@ -81,7 +82,7 @@ const byte DgdsEngine::HOC_CHAR_SWAP_ICONS[] = { 0, 20, 21, 22 };
 DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
 	: Engine(syst), _fontManager(nullptr), _console(nullptr), _inventory(nullptr),
 	_soundPlayer(nullptr), _decompressor(nullptr), _scene(nullptr), _shellGame(nullptr),
-	_gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
+	_hocIntro(nullptr), _gdsScene(nullptr), _resource(nullptr), _gamePals(nullptr), _gameGlobals(nullptr),
 	_detailLevel(kDgdsDetailHigh), _textSpeed(1), _justChangedScene1(false), _justChangedScene2(false),
 	_random("dgds"), _currentCursor(-1), _menuToTrigger(kMenuNone), _isLoading(true), _flipMode(false),
 	_rstFileName(nullptr), _difficulty(1), _menu(nullptr), _adsInterp(nullptr), _isDemo(false),
@@ -129,6 +130,7 @@ DgdsEngine::~DgdsEngine() {
 	delete _menu;
 	delete _inventory;
 	delete _shellGame;
+	delete _hocIntro;
 	delete _dragonArcade;
 
 	_icons.reset();
@@ -323,10 +325,9 @@ void DgdsEngine::init(bool restarting) {
 		delete _menu;
 		delete _adsInterp;
 		delete _inventory;
-		if (_dragonArcade)
-			delete _dragonArcade;
-		if (_shellGame)
-			delete _shellGame;
+		delete _dragonArcade;
+		delete _shellGame;
+		delete _hocIntro;
 	}
 
 	_gamePals = new GamePalettes(_resource, _decompressor);
@@ -339,8 +340,10 @@ void DgdsEngine::init(bool restarting) {
 	_inventory = new Inventory();
 	if (_gameId == GID_DRAGON)
 		_dragonArcade = new DragonArcade();
-	else if (_gameId == GID_HOC)
+	else if (_gameId == GID_HOC) {
 		_shellGame = new ShellGame();
+		_hocIntro = new HocIntro();
+	}
 
 	_backgroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
 	_storedAreaBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index cfcef2f1cce..72fc40b2544 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -60,6 +60,7 @@ class ADSInterpreter;
 class Globals;
 class ShellGame;
 class DragonArcade;
+class HocIntro;
 
 const float MS_PER_FRAME = 16.6667f;
 
@@ -141,6 +142,7 @@ private:
 
 	// HoC only
 	ShellGame *_shellGame;
+	HocIntro *_hocIntro;
 
 	FontManager *_fontManager;
 	Common::SharedPtr<Image> _corners;
@@ -242,6 +244,7 @@ public:
 	void setMenuToTrigger(MenuId menu) { _menuToTrigger = menu; }
 	bool isInvButtonVisible() const;
 	ShellGame *getShellGame() { return _shellGame; }
+	HocIntro *getHocIntro() { return _hocIntro; }
 	DragonArcade *getDragonArcade() { return _dragonArcade; }
 	void setSkipNextFrame() { _skipNextFrame = true; }
 
diff --git a/engines/dgds/dragon_native.cpp b/engines/dgds/dragon_native.cpp
new file mode 100644
index 00000000000..f62aa2f5f12
--- /dev/null
+++ b/engines/dgds/dragon_native.cpp
@@ -0,0 +1,122 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dgds/dragon_native.h"
+#include "dgds/globals.h"
+#include "dgds/scene.h"
+
+namespace Dgds {
+
+
+/*static*/
+void DragonNative::drawCountdown(FontManager::FontType fontType, int16 x, int16 y) {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	int16 countdownEnd = engine->getGameGlobals()->getGlobal(0x22);
+	int16 currentMins = engine->getClock().getMins();
+	const DgdsFont *fnt = engine->getFontMan()->getFont(fontType);
+	Common::String str = Common::String::format("%d", countdownEnd - currentMins);
+	fnt->drawString(&engine->_compositionBuffer, str, x, y, 320 - x, 10);
+}
+
+
+// The first row of this array corresponds to the
+// positions of buttons in game passcode
+// RYP YWP YRPWRY PBW
+static const uint16 DRAGON_PASSCODE[] = {
+	1, 4, 3, 4, 0, 3, 4, 1, 3, 0, 1, 4, 3, 2, 0,
+	4, 4, 2, 3, 4, 0, 0, 4, 3, 2, 1, 1, 2, 4, 0,
+	4, 1, 3, 2, 0, 2, 1, 4, 3, 4, 1, 3, 2, 0, 1
+};
+
+static uint16 passcodeBlockNum = 0;
+static uint16 passcodeVal1 = 0;
+static uint16 passcodeVal2 = 0;
+static uint16 passcodeVal3 = 0;
+static uint16 passcodeVal4 = 0;
+
+/*static*/
+ void DragonNative::updatePasscodeGlobal() {
+	GDSScene *gdsScene = DgdsEngine::getInstance()->getGDSScene();
+	int16 globalval = gdsScene->getGlobal(0x20);
+
+	if (globalval > 34)
+		return;
+
+	if (globalval >= 30) {
+		// One of the keypad buttons
+		if (DRAGON_PASSCODE[passcodeVal4 + passcodeBlockNum * 15] == globalval - 30) {
+			debug("sceneOpUpdatePasscodeGlobal CORRECT: variables %d %d %d %d block %d, curval %d",
+				passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
+
+			// Correct entry! Increment the expected button
+			passcodeVal4++;
+			if (passcodeVal4 < passcodeVal3) {
+				globalval = 0;
+			} else if (passcodeVal3 < 15) {
+				globalval = 5;
+			} else {
+				// Finished!
+				globalval = 6;
+			}
+		} else {
+			// Mistake
+			debug("sceneOpUpdatePasscodeGlobal WRONG: variables %d %d %d %d block %d, curval %d",
+				passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
+			passcodeVal1 = 0;
+			passcodeVal2 = 5;
+			globalval = 7;
+		}
+	} else {
+		if (globalval > 4 || globalval == 0)
+			return;
+
+		debug("sceneOpUpdatePasscodeGlobal OTHER: variables %d %d %d %d block %d, curval %d",
+				passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
+
+		if (globalval < 4) {
+			passcodeBlockNum = globalval - 1; // expect block globalval-1
+			passcodeVal1 = 5;
+			passcodeVal2 = 0;
+			passcodeVal3 = 15;	// 15 buttons expected
+			passcodeVal4 = 0;
+			return;
+		} else if (passcodeVal2 > passcodeVal1) {
+			passcodeVal1++;
+			globalval = DRAGON_PASSCODE[passcodeVal1 + passcodeBlockNum * 15] + 20;
+		} else if (passcodeVal2 > 14) {
+			passcodeVal1 = 0;
+			passcodeVal3 = passcodeVal2;
+			passcodeVal4 = 0;
+			globalval = 8;
+		} else {
+			passcodeVal1 = 0;
+			passcodeVal2 += 5;
+			passcodeVal3 = passcodeVal1;
+			passcodeVal4 = 0;
+			globalval = 8;
+		}
+	}
+
+	gdsScene->setGlobal(0x20, globalval);
+}
+
+
+} // end namespace Dgds
diff --git a/engines/dgds/dragon_native.h b/engines/dgds/dragon_native.h
new file mode 100644
index 00000000000..a9a1bc0b542
--- /dev/null
+++ b/engines/dgds/dragon_native.h
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_DRAGON_NATIVE_H
+#define DGDS_DRAGON_NATIVE_H
+
+#include "dgds/font.h"
+
+namespace Dgds {
+
+/**
+ * Native scene ops for Rise of the Dragon.
+ *
+ * The arcade section is more complex, see `dragon_arcade.h`
+ */
+class DragonNative {
+public:
+	static void updatePasscodeGlobal();
+	static void drawCountdown(FontManager::FontType fontType, int16 x, int16 y);
+
+private:
+	DragonNative();  // only static ops, don't instantiate
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_DRAGON_NATIVE_H
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index fc7e23c40c8..35a67a0d7d2 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -233,52 +233,52 @@ public:
 };
 
 
-HocGlobals::HocGlobals(Clock &clock) : Globals(clock), _unk82(1), _unk55(0),
+HocGlobals::HocGlobals(Clock &clock) : Globals(clock), _difficultyLevel(1), _unk55(0),
 	_unkDlgFileNum(0), _unkDlgDlgNum(0),  _currentCharacter2(0), _currentCharacter(0),
-	_unk50(0), _nativeGameState(0), _unk48(0), _unk47(0), _unk46(0), _unk45(0x3f), _sheckels(0),
-	_shellBet(0), _shellPea(0), _unk41(0), _unk40(3), _unk39(0) {
+	_tankFinished(0), _nativeGameState(0), _tankState(0), _unk47(0), _unk46(0), _unk45(0x3f), _sheckels(0),
+	_shellBet(0), _shellPea(0), _trainState(0), _startScene(3), _introState(0) {
 	_globals.push_back(new DetailLevelROGlobal(0x53));
-	_globals.push_back(new RWI16Global(0x52, &_unk82));
-	_globals.push_back(new RWI16Global(0x37, &_unk55)); // TODO: Special update function FUN_1407_080d, sound init related
+	_globals.push_back(new RWI16Global(0x52, &_difficultyLevel)); // TODO: Sync with difficulty in menu
+	_globals.push_back(new RWI16Global(0x37, &_unk55)); // TODO: Special update function FUN_1407_080d, sound init related.. sound bank?
 	_globals.push_back(new RWI16Global(0x36, &_unkDlgFileNum));
 	_globals.push_back(new RWI16Global(0x35, &_unkDlgDlgNum));
 	_globals.push_back(new HocCharacterGlobal(0x34, &_currentCharacter));
 	_globals.push_back(new HocCharacterGlobal(0x33, &_currentCharacter2));
-	_globals.push_back(new RWI16Global(0x32, &_unk50));
+	_globals.push_back(new RWI16Global(0x32, &_tankFinished));
 	_globals.push_back(new RWI16Global(0x31, &_nativeGameState));
-	_globals.push_back(new RWI16Global(0x30, &_unk48));
-	_globals.push_back(new RWI16Global(0x2F, &_unk47));
-	_globals.push_back(new RWI16Global(0x2E, &_unk46));
+	_globals.push_back(new RWI16Global(0x30, &_tankState));
+	_globals.push_back(new RWI16Global(0x2F, &_unk47)); // tank related.. cows?
+	_globals.push_back(new RWI16Global(0x2E, &_unk46)); // tank related.. start point?
 	_globals.push_back(new RWI16Global(0x2D, &_unk45)); // TODO: Special update function FUN_1407_0784, palette related?
 	_globals.push_back(new RWI16Global(0x2C, &_sheckels));	// used as currency in Istanbul
 	_globals.push_back(new RWI16Global(0x2B, &_shellBet));
 	_globals.push_back(new RWI16Global(0x2A, &_shellPea));
-	_globals.push_back(new RWI16Global(0x29, &_unk41));
-	_globals.push_back(new RWI16Global(0x28, &_unk40));
-	_globals.push_back(new ROI16Global(0x27, &_unk39));
+	_globals.push_back(new RWI16Global(0x29, &_trainState));
+	_globals.push_back(new RWI16Global(0x28, &_startScene));
+	_globals.push_back(new ROI16Global(0x27, &_introState));
 }
 
 Common::Error HocGlobals::syncState(Common::Serializer &s) {
 	Globals::syncState(s);
 
-	s.syncAsSint16LE(_unk39);
-	s.syncAsSint16LE(_unk40);
-	s.syncAsSint16LE(_unk41);
+	s.syncAsSint16LE(_introState);
+	s.syncAsSint16LE(_startScene);
+	s.syncAsSint16LE(_trainState);
 	s.syncAsSint16LE(_shellPea);
 	s.syncAsSint16LE(_shellBet);
 	s.syncAsSint16LE(_sheckels);
 	s.syncAsSint16LE(_unk45);
 	s.syncAsSint16LE(_unk46);
 	s.syncAsSint16LE(_unk47);
-	s.syncAsSint16LE(_unk48);
+	s.syncAsSint16LE(_tankState);
 	s.syncAsSint16LE(_nativeGameState);
-	s.syncAsSint16LE(_unk50);
+	s.syncAsSint16LE(_tankFinished);
 	s.syncAsSint16LE(_currentCharacter);
 	s.syncAsSint16LE(_currentCharacter2);
 	s.syncAsSint16LE(_unkDlgDlgNum);
 	s.syncAsSint16LE(_unkDlgFileNum);
 	s.syncAsSint16LE(_unk55);
-	s.syncAsSint16LE(_unk82);
+	s.syncAsSint16LE(_difficultyLevel);
 
 	return Common::kNoError;
 }
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 30cae66926d..dd088737263 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -164,26 +164,29 @@ public:
 	int16 getNativeGameState() const { return _nativeGameState; }
 	void setNativeGameState(int16 state) { _nativeGameState = state; }
 
+	int16 getIntroState() const { return _introState; }
+	void setIntroState(int16 state) { _introState = state; }
+
 private:
 	// HoC-specific globals
-	int16 _unk39;
-	int16 _unk40;
-	int16 _unk41;
+	int16 _introState;
+	int16 _startScene;
+	int16 _trainState;
 	int16 _shellPea;
 	int16 _shellBet;
 	int16 _sheckels;
 	int16 _unk45;
 	int16 _unk46;
 	int16 _unk47;
-	int16 _unk48;
+	int16 _tankState;
 	int16 _nativeGameState; // state for the shell game, tank game, etc.
-	int16 _unk50;
+	int16 _tankFinished;
 	int16 _currentCharacter;
 	int16 _currentCharacter2;
 	int16 _unkDlgDlgNum;
 	int16 _unkDlgFileNum;
 	int16 _unk55;
-	int16 _unk82;
+	int16 _difficultyLevel;
 
 	Common::Error syncState(Common::Serializer &s) override;
 };
diff --git a/engines/dgds/hoc_intro.cpp b/engines/dgds/hoc_intro.cpp
new file mode 100644
index 00000000000..67fdc0adb13
--- /dev/null
+++ b/engines/dgds/hoc_intro.cpp
@@ -0,0 +1,212 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "dgds/hoc_intro.h"
+#include "dgds/dgds.h"
+#include "dgds/sound.h"
+#include "dgds/game_palettes.h"
+#include "dgds/image.h"
+#include "dgds/includes.h"
+#include "dgds/globals.h"
+
+namespace Dgds {
+
+HocIntro::HocIntro() :  _scrollCountdown1(0), _xOffset203e(0), _xOffset2042(0), _scrollCountdown2(0) {
+
+}
+
+void HocIntro::init() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	HocGlobals *globals = static_cast<HocGlobals *>(engine->getGameGlobals());
+
+	if (globals->getIntroState())
+		return;
+
+	_scrollCountdown2 = 137;
+	_xOffset2042 = 320;
+	_scrollCountdown1 = 150;
+	engine->_soundPlayer->loadMusic("INTRO1.SNG");
+	engine->_soundPlayer->playMusic(0);
+	engine->getGamePals()->loadPalette("xx.pal");
+	Image tmp(engine->getResourceManager(), engine->getDecompressor());
+	tmp.drawScreen("xx.scr", engine->getBackgroundBuffer());
+
+	_maskImg.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+	_noMaskImg.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+	_maskImg->loadBitmap("xx_mask.bmp");
+	_noMaskImg->loadBitmap("xx_nomas.bmp");
+
+	engine->_compositionBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 81);
+	globals->setIntroState(1);
+
+	// TODO: Is this the right variable?
+	globals->setNativeGameState(32);
+
+	engine->_soundPlayer->playSFX(35);
+}
+
+void HocIntro::tick() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	HocGlobals *globals = static_cast<HocGlobals *>(engine->getGameGlobals());
+	if (!globals->getIntroState())
+		return;
+
+	if (_scrollCountdown2 != 0)
+	  _scrollCountdown2--;
+
+	if (_xOffset2042 > -90)
+	  _xOffset2042 -= 3;
+
+	_scrollCountdown1--;
+
+	doScroll();
+
+	_drawWin.left = 0;
+}
+
+void HocIntro::doScroll() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	HocGlobals *globals = static_cast<HocGlobals *>(engine->getGameGlobals());
+	assert(globals->getIntroState());
+
+	if (_scrollCountdown1 == 0) {
+	  globals->setIntroState(2);
+	  _scrollCountdown1 = 1;
+	}
+
+	// For the start of the scroll, we want to blank out the background.
+	// The original does this differently but this will do.
+	if (_xOffset2042 > 0)
+		engine->_compositionBuffer.fillRect(Common::Rect(_xOffset2042, 200), 81);
+
+	// set clip window
+	_drawWin.top = 0;
+	_drawWin.left = MAX((int16)0, _xOffset2042);
+	_drawWin.right = 320;
+	_drawWin.bottom = 200;
+	clean1(_scrollCountdown2);
+	clean2(_xOffset2042);
+	draw1(_scrollCountdown2);
+	draw2(_xOffset2042);
+}
+
+static int16 _clipXOffset(int16 x1, int16 x2) {
+	if (x1 + x2 > 320)
+		x2 = 320 - x1;
+
+	if (x2 < 0)
+		x2 = 0;
+
+	return x2;
+}
+
+void HocIntro::leave() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	HocGlobals *globals = static_cast<HocGlobals *>(engine->getGameGlobals());
+	if (!globals->getIntroState())
+		return;
+
+	//engine->getGamePals()->freePal("xx.pal");
+
+	// Store the current frame in the background
+	engine->getBackgroundBuffer().blitFrom(engine->_compositionBuffer);
+
+	_maskImg.reset();
+	_noMaskImg.reset();
+
+	globals->setIntroState(0);
+	static_cast<HocGlobals *>(engine->getGameGlobals())->setNativeGameState(0);
+}
+
+void HocIntro::doCopy(int16 x1, int16 y1, int16 x2, int16 y2) {
+	int16 xx = _xOffset203e + x1;
+	if (xx < _drawWin.left)
+		xx = _drawWin.left;
+
+	if (xx < 320) {
+		DgdsEngine *engine = DgdsEngine::getInstance();
+		Graphics::ManagedSurface &bg = engine->getBackgroundBuffer();
+		Graphics::ManagedSurface &comp = engine->_compositionBuffer;
+		int16 xx2 = _clipXOffset(xx, x2);
+		Common::Rect copyRect(Common::Point(xx, y1), xx2, y2);
+		comp.blitFrom(bg, copyRect, copyRect);
+	}
+}
+
+void HocIntro::clean1(int16 xoff) {
+  _xOffset203e = xoff;
+  doCopy(0x6c, 0x58, 0x10, 0x1a);
+  doCopy(0x87, 0x38, 0x2b, 0x11);
+  doCopy(0xa4, 0x48, 0x1b, 0x1e);
+  doCopy(0xc0, 0x40, 0xd, 4);
+}
+
+void HocIntro::clean2(int16 xoff) {
+  _xOffset203e = xoff;
+  doCopy(0, 0x14, 0x46, 0x25);
+  doCopy(0x31, 0x39, 0x2b, 0x1a);
+  doCopy(0x5b, 0x52, 0x36, 0x1f);
+  doCopy(0x7d, 0x70, 0x1b, 6);
+}
+
+void HocIntro::draw1(int16 xoff) {
+	Graphics::ManagedSurface &dst = DgdsEngine::getInstance()->_compositionBuffer;
+	_noMaskImg->drawBitmap(1, xoff + 0xcc, 0x33, _drawWin, dst);
+	_noMaskImg->drawBitmap(0, xoff + 0xf8, 0x14, _drawWin, dst);
+	_noMaskImg->drawBitmap(2, xoff, 0x7a, _drawWin, dst);
+	_maskImg->drawBitmap(1, xoff + 0xcf, 0x15, _drawWin, dst);
+	_maskImg->drawBitmap(2, xoff + 0xbc, 0x35, _drawWin, dst);
+	_maskImg->drawBitmap(3, xoff + 0xb7, 99, _drawWin, dst);
+	_maskImg->drawBitmap(4, xoff + 0x79, 0x38, _drawWin, dst);
+	_maskImg->drawBitmap(5, xoff + 0x5d, 0x58, _drawWin, dst);
+	_maskImg->drawBitmap(0, xoff + 0x19, 0x72, _drawWin, dst);
+}
+
+void HocIntro::draw2(int16 xoff) {
+	Graphics::ManagedSurface &dst = DgdsEngine::getInstance()->_compositionBuffer;
+
+	if (8 < xoff)
+		dst.fillRect(Common::Rect(Common::Point(0, 0x14), 8, 0x88), 81);
+
+	if (_drawWin.left < 9) {
+		if (_drawWin.left > 0)
+			dst.fillRect(Common::Rect(Common::Point(0, 0x14), xoff, 100), 81);
+	} else {
+		dst.fillRect(Common::Rect(Common::Point(xoff - 8, 0x14), 8, 0x68), 81);
+		_drawWin.left = 8;
+	}
+
+	dst.fillRect(Common::Rect(Common::Point(xoff, 0x31), 0x29, 0x6b), 81);
+
+	_maskImg->drawBitmap(6, xoff, 0x14, _drawWin, dst);
+	_noMaskImg->drawBitmap(3, xoff + 0x29, 0x49, _drawWin, dst);
+	_noMaskImg->drawBitmap(4, xoff + 0x43, 0x53, _drawWin, dst);
+	_noMaskImg->drawBitmap(5, xoff + 0x57, 0x6d, _drawWin, dst);
+	_maskImg->drawBitmap(7, xoff + 0x29, 0x19, _drawWin, dst);
+	_maskImg->drawBitmap(8, xoff + 0x43, 0x3c, _drawWin, dst);
+	_maskImg->drawBitmap(9, xoff + 0x57, 0x52, _drawWin, dst);
+	_maskImg->drawBitmap(10, xoff + 0x7a, 0x5c, _drawWin, dst);
+	_maskImg->drawBitmap(11, xoff + 0x90, 0x8c, _drawWin, dst);
+	_maskImg->drawBitmap(11, xoff + 0x13b, 0x8c, _drawWin, dst);
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/hoc_intro.h b/engines/dgds/hoc_intro.h
new file mode 100644
index 00000000000..0f538f0d534
--- /dev/null
+++ b/engines/dgds/hoc_intro.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DGDS_HOC_INTRO_H
+#define DGDS_HOC_INTRO_H
+
+#include "common/ptr.h"
+#include "dgds/image.h"
+
+namespace Dgds {
+
+/**
+ * Native scene ops for Heart of China intro.
+ */
+class HocIntro {
+public:
+	HocIntro();
+	void init();
+	void tick();
+	void leave();
+
+private:
+	void clean1(int16 xoff);
+	void clean2(int16 xoff);
+	void draw1(int16 xoff);
+	void draw2(int16 xoff);
+
+	void doCopy(int16 x1, int16 y1, int16 x2, int16 y2);
+	void doScroll();
+
+	int16 _scrollCountdown1;
+	int16 _xOffset2042;
+	int16 _xOffset203e;
+	int16 _scrollCountdown2;
+	Common::SharedPtr<Image> _noMaskImg;
+	Common::SharedPtr<Image> _maskImg;
+	Common::Rect _drawWin;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_HOC_INTRO_H
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 565594df0e2..ba75de61e20 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -596,7 +596,7 @@ void Menu::handleClickSkipPlayIntroMenu(const Common::Point &mouse) {
 	case kMenuIntroJumpToIntroduction:
 		hideMenu();
 		if (engine->getGameId() == GID_HOC)
-			engine->changeScene(98);
+			engine->changeScene(100);
 		else if (engine->getGameId() == GID_WILLY)
 			engine->changeScene(24);
 		break;
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index 302680c9159..2d80da976ef 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -10,10 +10,12 @@ MODULE_OBJS := \
 	dialog.o \
 	dragon_arcade.o \
 	dragon_arcade_ttm.o \
+	dragon_native.o \
 	drawing.o \
 	font.o \
 	game_palettes.o \
 	globals.o \
+	hoc_intro.o \
 	image.o \
 	inventory.o \
 	menu.o \
@@ -21,12 +23,12 @@ MODULE_OBJS := \
 	parser.o \
 	request.o \
 	resource.o \
+	scene.o \
 	scripts.o \
 	shell_game.o \
+	sound.o \
 	sound_raw.o \
 	ttm.o \
-	scene.o \
-	sound.o \
 	sound/midiparser_sci.o \
 	sound/music.o \
 	sound/drivers/adlib.o \
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index bd172d507ae..ba1b52aff8e 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -43,6 +43,8 @@
 #include "dgds/image.h"
 #include "dgds/inventory.h"
 #include "dgds/dragon_arcade.h"
+#include "dgds/dragon_native.h"
+#include "dgds/hoc_intro.h"
 
 namespace Dgds {
 
@@ -164,9 +166,9 @@ static Common::String _sceneOpCodeName(SceneOpCode code) {
 		case kSceneOpOpenChinaTrainMenu:	return "trainMenu";
 		case kSceneOpOpenChinaOpenGameOverMenu: return "gameOverMenu";
 		case kSceneOpOpenChinaOpenSkipCreditsMenu: return "skipCreditsMenu";
-		case kSceneOpOpenChinaStartIntro:	return "startIntro";
-		case kSceneOpChina117:				return "hocSceneOp117";
-		case kSceneOpChina118:  			return "hocSceneOp118";
+		case kSceneOpChinaOnIntroInit:		return "chinaOnIntroInit";
+		case kSceneOpChinaOnIntroTick:		return "chinaOnIntroTick";
+		case kSceneOpChinaOnIntroLeave:  	return "chinaOnIntroLeave";
 		default:
 			break;
 		}
@@ -609,15 +611,6 @@ void Scene::segmentStateOps(const Common::Array<uint16> &args) {
 	}
 }
 
-static void _drawDragonCountdown(FontManager::FontType fontType, int16 x, int16 y) {
-	DgdsEngine *engine = DgdsEngine::getInstance();
-	int16 countdownEnd = engine->getGameGlobals()->getGlobal(0x22);
-	int16 currentMins = engine->getClock().getMins();
-	const DgdsFont *fnt = engine->getFontMan()->getFont(fontType);
-	Common::String str = Common::String::format("%d", countdownEnd - currentMins);
-	fnt->drawString(&engine->_compositionBuffer, str, x, y, 320 - x, 10);
-}
-
 
 bool Scene::runSceneOp(const SceneOp &op) {
 	DgdsEngine *engine = DgdsEngine::getInstance();
@@ -734,7 +727,7 @@ bool Scene::runDragonOp(const SceneOp &op) {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 	switch (op._opCode) {
 	case kSceneOpPasscode:
-		engine->getScene()->sceneOpUpdatePasscodeGlobal();
+		DragonNative::updatePasscodeGlobal();
 		break;
 	case kSceneOpMeanwhile:
 		// TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway.
@@ -755,10 +748,10 @@ bool Scene::runDragonOp(const SceneOp &op) {
 		engine->getDragonArcade()->arcadeTick();
 		break;
 	case kSceneOpDrawDragonCountdown1:
-		_drawDragonCountdown(FontManager::k4x5Font, 141, 56);
+		DragonNative::drawCountdown(FontManager::k4x5Font, 141, 56);
 		break;
 	case kSceneOpDrawDragonCountdown2:
-		_drawDragonCountdown(FontManager::k8x8Font, 250, 42);
+		DragonNative::drawCountdown(FontManager::k8x8Font, 250, 42);
 		break;
 	case kSceneOpOpenPlaySkipIntroMenu:
 		engine->setMenuToTrigger(kMenuSkipPlayIntro);
@@ -793,10 +786,15 @@ bool Scene::runChinaOp(const SceneOp &op) {
 	case kSceneOpShellGameEnd:
 		engine->getShellGame()->shellGameEnd();
 		break;
-	case kSceneOpOpenChinaStartIntro:
-		// The game first jumps to scene 100, and then to 98
-		engine->changeScene(98);
-		return true;
+	case kSceneOpChinaOnIntroInit:
+		engine->getHocIntro()->init();
+		break;
+	case kSceneOpChinaOnIntroTick:
+		engine->getHocIntro()->tick();
+		break;
+	case kSceneOpChinaOnIntroLeave:
+		engine->getHocIntro()->leave();
+		break;
 	default:
 		warning("TODO: Implement china-specific scene opcode %d", op._opCode);
 		break;
@@ -1403,86 +1401,6 @@ void SDSScene::addAndShowTiredDialog() {
 }
 
 
-// The first row of this array corresponds to the
-// positions of buttons in game passcode
-// RYP YWP YRPWRY PBW
-static const uint16 DRAGON_PASSCODE[] = {
-	1, 4, 3, 4, 0, 3, 4, 1, 3, 0, 1, 4, 3, 2, 0,
-	4, 4, 2, 3, 4, 0, 0, 4, 3, 2, 1, 1, 2, 4, 0,
-	4, 1, 3, 2, 0, 2, 1, 4, 3, 4, 1, 3, 2, 0, 1
-};
-
-static uint16 passcodeBlockNum = 0;
-static uint16 passcodeVal1 = 0;
-static uint16 passcodeVal2 = 0;
-static uint16 passcodeVal3 = 0;
-static uint16 passcodeVal4 = 0;
-
-void SDSScene::sceneOpUpdatePasscodeGlobal() {
-	GDSScene *gdsScene = DgdsEngine::getInstance()->getGDSScene();
-	int16 globalval = gdsScene->getGlobal(0x20);
-
-	if (globalval > 34)
-		return;
-
-	if (globalval >= 30) {
-		// One of the keypad buttons
-		if (DRAGON_PASSCODE[passcodeVal4 + passcodeBlockNum * 15] == globalval - 30) {
-			debug("sceneOpUpdatePasscodeGlobal CORRECT: variables %d %d %d %d block %d, curval %d",
-				passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
-
-			// Correct entry! Increment the expected button
-			passcodeVal4++;
-			if (passcodeVal4 < passcodeVal3) {
-				globalval = 0;
-			} else if (passcodeVal3 < 15) {
-				globalval = 5;
-			} else {
-				// Finished!
-				globalval = 6;
-			}
-		} else {
-			// Mistake
-			debug("sceneOpUpdatePasscodeGlobal WRONG: variables %d %d %d %d block %d, curval %d",
-				passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
-			passcodeVal1 = 0;
-			passcodeVal2 = 5;
-			globalval = 7;
-		}
-	} else {
-		if (globalval > 4 || globalval == 0)
-			return;
-
-		debug("sceneOpUpdatePasscodeGlobal OTHER: variables %d %d %d %d block %d, curval %d",
-				passcodeVal1, passcodeVal2, passcodeVal3, passcodeVal4, passcodeBlockNum, globalval);
-
-		if (globalval < 4) {
-			passcodeBlockNum = globalval - 1; // expect block globalval-1
-			passcodeVal1 = 5;
-			passcodeVal2 = 0;
-			passcodeVal3 = 15;	// 15 buttons expected
-			passcodeVal4 = 0;
-			return;
-		} else if (passcodeVal2 > passcodeVal1) {
-			passcodeVal1++;
-			globalval = DRAGON_PASSCODE[passcodeVal1 + passcodeBlockNum * 15] + 20;
-		} else if (passcodeVal2 > 14) {
-			passcodeVal1 = 0;
-			passcodeVal3 = passcodeVal2;
-			passcodeVal4 = 0;
-			globalval = 8;
-		} else {
-			passcodeVal1 = 0;
-			passcodeVal2 += 5;
-			passcodeVal3 = passcodeVal1;
-			passcodeVal4 = 0;
-			globalval = 8;
-		}
-	}
-
-	gdsScene->setGlobal(0x20, globalval);
-}
-
 void SDSScene::showDialog(uint16 fileNum, uint16 dlgNum) {
 	if (fileNum)
 		loadDialogData(fileNum);
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index daeffe7ce92..e7cefce500a 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -125,15 +125,17 @@ enum SceneOpCode {
 	kSceneOpOpenBetterSaveGameMenu = 108,			// args: none. DRAGON: Show menu 46, the "Before arcade maybe you better save your game" menu.
 
 	// China-specific opcodes
+	kSceneOpChinaTankInit = 100,
+	kSceneOpChinaTankExit = 101,
 	kSceneOpOpenChinaTankMenu = 102,
 	kSceneOpShellGameEnd = 109,
 	kSceneOpShellGameTick = 110,
 	kSceneOpOpenChinaTrainMenu = 113,
 	kSceneOpOpenChinaOpenGameOverMenu = 114,	// args: none.
 	kSceneOpOpenChinaOpenSkipCreditsMenu = 115,	// args: none.
-	kSceneOpOpenChinaStartIntro = 116,	// args: none.
-	kSceneOpChina117 = 117,	// args: none. ??
-	kSceneOpChina118 = 118,	// args: none. ??
+	kSceneOpChinaOnIntroTick = 116,	// args: none.
+	kSceneOpChinaOnIntroInit = 117,	// args: none.
+	kSceneOpChinaOnIntroLeave = 118,	// args: none.
 
 	// Beamish-specific opcodes
 	kSceneOpOpenBeamishGameOverMenu = 100,
diff --git a/engines/dgds/shell_game.h b/engines/dgds/shell_game.h
index be2285d13a0..a213dabec76 100644
--- a/engines/dgds/shell_game.h
+++ b/engines/dgds/shell_game.h
@@ -26,7 +26,7 @@
 
 namespace Dgds {
 
-/* Native code for the shell game from Heart of China. */
+/** Native code for the shell game from Heart of China. */
 class ShellGame {
 public:
 	ShellGame();
diff --git a/engines/dgds/sound/drivers/midipatch.cpp b/engines/dgds/sound/drivers/midipatch.cpp
index d88693db219..8c8d89838bb 100644
--- a/engines/dgds/sound/drivers/midipatch.cpp
+++ b/engines/dgds/sound/drivers/midipatch.cpp
@@ -39,7 +39,7 @@ namespace Dgds {
 
 static const char *PATCH_RESOURCES[] = {
 	"SXTITLE.OVL", // dragon
-	"SXCODE1.OVL", // china (TODO: when do we load SXCODE2??)
+	"SXCODE1.OVL", // hoc (TODO: when do we load SXCODE2 - maybe when global 0x37 changes)
 	"SX.OVL",      // newer games (beamish, sq5 demo)
 };
 
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index 176540ea5d4..c2a756bbdaa 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -1056,7 +1056,7 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 	case 0xf010: { // LOAD SCR:	filename:str
 		if (seq._executed) // this is a one-shot op
 			break;
-		Image tmp = Image(_vm->getResourceManager(), _vm->getDecompressor());
+		Image tmp(_vm->getResourceManager(), _vm->getDecompressor());
 		tmp.drawScreen(sval, _vm->getBackgroundBuffer());
 		_vm->_compositionBuffer.blitFrom(_vm->getBackgroundBuffer());
 		_vm->getStoredAreaBuffer().fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);


Commit: ea5029209929423eaeec402added5972e7c60a2f
    https://github.com/scummvm/scummvm/commit/ea5029209929423eaeec402added5972e7c60a2f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-10-27T18:25:47+11:00

Commit Message:
DGDS: JANITORIAL: Fix whitespace

Changed paths:
    engines/dgds/game_palettes.cpp
    engines/dgds/metaengine.cpp
    engines/dgds/request.cpp
    engines/dgds/ttm.cpp


diff --git a/engines/dgds/game_palettes.cpp b/engines/dgds/game_palettes.cpp
index eb64f937458..0771321040a 100644
--- a/engines/dgds/game_palettes.cpp
+++ b/engines/dgds/game_palettes.cpp
@@ -29,22 +29,22 @@
 namespace Dgds {
 
 static const byte EGA_COLORS[16][3] = {
-    { 0x00, 0x00, 0x00 },
-    { 0x00, 0x00, 0xAA },
-    { 0x00, 0xAA, 0x00 },
-    { 0x00, 0xAA, 0xAA },
-    { 0xAA, 0x00, 0x00 },
-    { 0xAA, 0x00, 0xAA },
-    { 0xAA, 0x55, 0x00 },
-    { 0xAA, 0xAA, 0xAA },
-    { 0x55, 0x55, 0x55 },
-    { 0x55, 0x55, 0xFF },
-    { 0x55, 0xFF, 0x55 },
-    { 0x55, 0xFF, 0xFF },
-    { 0xFF, 0x55, 0x55 },
-    { 0xFF, 0x55, 0xFF },
-    { 0xFF, 0xFF, 0x55 },
-    { 0xFF, 0xFF, 0xFF },
+	{ 0x00, 0x00, 0x00 },
+	{ 0x00, 0x00, 0xAA },
+	{ 0x00, 0xAA, 0x00 },
+	{ 0x00, 0xAA, 0xAA },
+	{ 0xAA, 0x00, 0x00 },
+	{ 0xAA, 0x00, 0xAA },
+	{ 0xAA, 0x55, 0x00 },
+	{ 0xAA, 0xAA, 0xAA },
+	{ 0x55, 0x55, 0x55 },
+	{ 0x55, 0x55, 0xFF },
+	{ 0x55, 0xFF, 0x55 },
+	{ 0x55, 0xFF, 0xFF },
+	{ 0xFF, 0x55, 0x55 },
+	{ 0xFF, 0x55, 0xFF },
+	{ 0xFF, 0xFF, 0x55 },
+	{ 0xFF, 0xFF, 0xFF },
 };
 
 DgdsPal::DgdsPal() : Palette(256) {
diff --git a/engines/dgds/metaengine.cpp b/engines/dgds/metaengine.cpp
index 5b4436db7e3..c4a2d1dae5f 100644
--- a/engines/dgds/metaengine.cpp
+++ b/engines/dgds/metaengine.cpp
@@ -61,11 +61,11 @@ Common::Error DgdsMetaEngine::createInstance(OSystem *syst, Engine **engine, con
 }
 
 struct KeybindingRecord {
-    Dgds::DgdsKeyEvent _action;
-    const char *_id;
-    const Common::U32String _desc;
-    const char *_key;
-    const char *_altKey;
+	Dgds::DgdsKeyEvent _action;
+	const char *_id;
+	const Common::U32String _desc;
+	const char *_key;
+	const char *_altKey;
 };
 
 Common::KeymapArray DgdsMetaEngine::initKeymaps(const char *target) const {
diff --git a/engines/dgds/request.cpp b/engines/dgds/request.cpp
index 3e3ac10b262..17b17a40024 100644
--- a/engines/dgds/request.cpp
+++ b/engines/dgds/request.cpp
@@ -416,8 +416,8 @@ byte ButtonGadget::drawChinaBg(Graphics::ManagedSurface *dst, bool enabled) cons
 			dst->drawLine(x + x2_, y + x2_, x + x2_, y2 - x2_, drawCol);
 			dst->drawLine(x + x2_, y2 - x2_, (x2 - x2_) + -1, y2 - x2_, drawCol);
 		}
-    }
-    return colors[7];
+	}
+	return colors[7];
 }
 
 byte ButtonGadget::drawWillyBg(Graphics::ManagedSurface *dst, bool enabled) const {
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index c2a756bbdaa..80e7831e1a4 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -513,8 +513,8 @@ int16 TTMInterpreter::doOpInitCreditScroll(const Image *img) {
 		y += ygap + height;
 		if (y > 200)
 			break;
-    }
-    return scrollFinished;
+	}
+	return scrollFinished;
 }
 
 void TTMInterpreter::doDrawDialogForStrings(TTMEnviro &env, TTMSeq &seq, int16 x, int16 y, int16 width, int16 height) {




More information about the Scummvm-git-logs mailing list