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

bluegr noreply at scummvm.org
Sun Sep 22 07:01:34 UTC 2024


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

Summary:
74ebf32934 DGDS: WIP Rise of the Dragon arcade support
3e931be799 DGDS: Begin implementing Arcade TTM interpreter
3da5777112 DGDS: Implement Arcade TTM interpreter
bf0f312d5b DGDS: More WIP dragon arcade code
e131bbbe55 DGDS: Even more dragon arcade code
8f41c8d511 DGDS: Dragon arcade nearly complete
ce4c983b1c DGDS: Dragon arcade starting to work
e5aaf8d063 DGDS: Add keyboard and fix some bugs in Dragon arcade
7b353c0dda DGDS: Fix small dragon arcade bugs
836010fa7e DGDS: Clean up dragon arcade code slightly
2ec7643b44 DGDS: Improve dragon arcade var names
41b6df5a55 DGDS: Fix fight in dragon arcade 1
c80a5b4a28 DGDS: Dragon sequence almost complete
d7a6701a66 DGDS: Reduce unneeded hex numbers in dragon arcade code


Commit: 74ebf32934a0984a0fa5299c0f7e7ea58be0c6ab
    https://github.com/scummvm/scummvm/commit/74ebf32934a0984a0fa5299c0f7e7ea58be0c6ab
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: WIP Rise of the Dragon arcade support

Changed paths:
  A engines/dgds/dragon_arcade.cpp
  A engines/dgds/dragon_arcade.h
  A engines/dgds/dragon_arcade_ttm.cpp
  A engines/dgds/dragon_arcade_ttm.h
  A engines/dgds/drawing.cpp
  A engines/dgds/drawing.h
    engines/dgds/dialog.cpp
    engines/dgds/globals.cpp
    engines/dgds/globals.h
    engines/dgds/module.mk


diff --git a/engines/dgds/dialog.cpp b/engines/dgds/dialog.cpp
index 6b3100613c6..d9dbb306235 100644
--- a/engines/dgds/dialog.cpp
+++ b/engines/dgds/dialog.cpp
@@ -35,6 +35,7 @@
 #include "dgds/scripts.h"
 #include "dgds/scene.h"
 #include "dgds/font.h"
+#include "dgds/drawing.h"
 
 namespace Dgds {
 
@@ -76,13 +77,6 @@ void Dialog::draw(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
 	}
 }
 
-static void _drawPixel(int x, int y, int color, void *data) {
-	Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
-
-	if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
-		*((byte *)surface->getBasePtr(x, y)) = (byte)color;
-}
-
 
 const DgdsFont *Dialog::getDlgTextFont() const {
 	const FontManager *fontman = DgdsEngine::getInstance()->getFontMan();
@@ -223,11 +217,6 @@ void Dialog::drawType2(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
 	}
 }
 
-static void _filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol, byte bgcol) {
-	Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, bgcol, true, _drawPixel, dst);
-	Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, _drawPixel, dst);
-}
-
 // Find the last line that will be printed - we don't use empty lines
 static uint _countPrintedLines(const Common::Array<Common::String> &lines) {
 	uint nprinted = 0;
@@ -281,32 +270,32 @@ void Dialog::drawType3(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
 		}
 
 		for (int i = 1; i < circlesDown; i++) {
-			_filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+			Drawing::filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
 			y += yradius;
 		}
 		for (int i = 1; i < circlesAcross; i++) {
-			_filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+			Drawing::filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
 			x += xradius;
 		}
 		for (int i = 1; i < circlesDown; i++) {
-			_filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+			Drawing::filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
 			y -= yradius;
 		}
 		for (int i = 1; i < circlesAcross; i++) {
-			_filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
+			Drawing::filledCircle(x, y, xradius, yradius, dst, fgcol, bgcol);
 			x -= xradius;
 		}
 
 		uint16 smallCircleX;
 		if (isbig) {
-			_filledCircle((x - xradius) - 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
+			Drawing::filledCircle((x - xradius) - 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
 			smallCircleX = (x - xradius) - 20;
 		} else {
-			_filledCircle(x + circlesAcross * xradius + 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
+			Drawing::filledCircle(x + circlesAcross * xradius + 5, y + circlesDown * yradius + 5, 10, 8, dst, fgcol, bgcol);
 			smallCircleX = x + circlesAcross * xradius + 20;
 		}
 
-		_filledCircle(smallCircleX, y + circlesDown * yradius + 25, 5, 4, dst, fgcol, bgcol);
+		Drawing::filledCircle(smallCircleX, y + circlesDown * yradius + 25, 5, 4, dst, fgcol, bgcol);
 
 		int16 yoff = (yradius * 27) / 32;
 		dst->fillRect(Common::Rect(x, y - yoff,
@@ -357,8 +346,8 @@ void Dialog::drawType4(Graphics::ManagedSurface *dst, DialogDrawStage stage) {
 		// This is not exactly the same as the original - might need some work to get pixel-perfect
 		if (DgdsEngine::getInstance()->getGameId() != GID_HOC) {
 			Common::Rect drawRect(x, y, x + w, y + h);
-			Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, _drawPixel, dst);
-			Graphics::drawRoundRect(drawRect, midy, fillcolor, false, _drawPixel, dst);
+			Graphics::drawRoundRect(drawRect, midy, fillbgcolor, true, Drawing::drawPixel, dst);
+			Graphics::drawRoundRect(drawRect, midy, fillcolor, false, Drawing::drawPixel, dst);
 		}
 	} else if (stage == kDlgDrawFindSelectionPointXY) {
 		drawFindSelectionXY();
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
new file mode 100644
index 00000000000..335b3aa09e6
--- /dev/null
+++ b/engines/dgds/dragon_arcade.cpp
@@ -0,0 +1,497 @@
+/* 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/util.h"
+#include "dgds/dgds.h"
+#include "dgds/image.h"
+#include "dgds/includes.h"
+#include "dgds/dragon_arcade.h"
+#include "dgds/sound.h"
+#include "dgds/drawing.h"
+#include "dgds/globals.h"
+#include "dgds/game_palettes.h"
+#include "dgds/menu.h"
+#include "dgds/font.h"
+
+namespace Dgds {
+
+DragonArcade::DragonArcade() {
+}
+
+void DragonArcade::finish() {
+	_arcadeTTM._currentTTMNum = 0;
+	_arcadeTTM.freeShapes();
+	_arcadeTTM.freePages(0);
+	_arcadeTTM._currentTTMNum = 1;
+	_arcadeTTM.freeShapes();
+	_arcadeTTM.freePages(1);
+	_arcadeTTM._currentTTMNum = 2;
+	_arcadeTTM.freeShapes();
+	_arcadeTTM.freePages(2);
+	//DgdsEngine::getInstance()->getGamePals()->freePal(arcadePal);
+	_bulletImg.reset();
+	_arrowImg.reset();
+	_scrollImg.reset();
+	_loadedArcadeStage = -1;
+	_initFinished = false;
+	warning("TODO: DragonArcade::finish: copy/clear some vid buffers here?");
+}
+
+bool DragonArcade::doTickUpdate() {
+	// TODO: Copy video buffers here?
+
+	if (_finishCountdown == 0)
+		return 0;
+
+	// TODO: Set video mask here?
+
+	_nextRandomVal = DgdsEngine::getInstance()->getRandom().getRandomNumber(65535);
+
+	error("DragonArcade::doTickUpdate: finish me");
+	
+	return false;
+}
+
+void DragonArcade::initIfNeeded() {
+	if (_initFinished)
+		return;
+
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	const char *ttmName;
+	const char *scrollBmpName;
+	const char *songName;
+	if (_nextStage == 4) {
+		ttmName = "path2.ttm";
+		scrollBmpName = "scroll2.bmp";
+		songName = "sarcade.sng";
+	} else {
+		ttmName = "path1.ttm";
+		scrollBmpName = "scroll.bmp";
+		songName = "darcade.sng";
+	}
+
+	engine->getGamePals()->loadPalette("arcade.pal");
+	_scrollImg.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+	_scrollImg->loadBitmap(scrollBmpName);
+
+	_arcadeTTM.clearDataPtrs();
+	_arcadeTTM._currentTTMNum = 0;
+	_arcadeTTM.load(ttmName);
+	_arcadeTTM.finishTTMParse();
+	_arcadeTTM._doingInit = true;
+	for (int i = 0; i < 8; i++) {
+		_arcadeTTM.runNextPage(i + 1);
+	}
+	_arcadeTTM._doingInit = false;
+	_arcadeTTM.freePages(0);
+
+	_arcadeTTM.freeShapes();
+	_arcadeTTM._currentTTMNum = 0;
+
+	const char *bladeTTM = _haveBigGun ? "BIGUNBLA.TTM" : "BLADE.TTM";
+
+	_arcadeTTM.load(bladeTTM);
+	_arcadeTTM.finishTTMParse();
+	_arcadeTTM.runNextPage(0);
+
+	_bulletImg.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+	_bulletImg->loadBitmap("bullet.bmp");
+
+	_arrowImg.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+	_arrowImg->loadBitmap("arcade.bmp");
+
+	engine->_soundPlayer->loadMusic(songName);
+	// set font to 0?
+	// set text draw to 0xe?
+	drawBackgroundAndWeapons();
+	loadTTMScriptsForStage(_nextStage);
+	_initFinished = true;
+	_arcadeModeSomethingCounter = 0;
+	g_system->warpMouse(166, 158);
+	_dontRedrawBgndAndWeapons = true;
+	redraw();
+}
+
+
+void DragonArcade::resetStageState() {
+	clearAllNPCStates();
+	clearAllBulletStates();
+	_scrollXOffset = 0;
+	_nTickUpdates = 0;
+	//INT_39e5_0a34 = 0;
+	//BYTE_39e5_0a14 = 0;
+	//INT_39e5_3d18 = 0;
+	//UINT_39e5_0a17 = 0;
+	_shouldUpdateState = 0;
+	//INT_39e5_3fa8 = 0;
+	_npcState[0].byte12 = 1;
+	_npcState[0].byte14 = 0;
+	_npcState[0].health = (4 - _startDifficultyMaybe) * 3 + 20;
+	_npcState[0].npcState = 3;
+	_npcState[1].health = 0;
+	_lastDrawnBladeHealth = -1;
+	_lastDrawnBossHealth = -1;
+	_bladeState1 = 0;
+	_mouseButtonWentDown = 0;
+	_bladeMoveFlag = kBladeMoveNone;
+	// TODO: Work out what those commented out variables are..
+	error("DragonArcade::resetStageState: TODO: Finish me.");
+}
+
+void DragonArcade::initValuesForStage() {
+	error("DragonArcade::initValuesForStage: TODO: Implement me.");
+}
+
+void DragonArcade::setFinishCountdownIfLessThan0(int16 val) {
+	if (_finishCountdown < 0)
+		_finishCountdown = val;
+}
+
+void DragonArcade::arcadeTick() {
+	DragonGlobals *globals = static_cast<DragonGlobals *>(DgdsEngine::getInstance()->getGameGlobals());
+	int16 arcadeState = globals->getArcadeState();
+
+	switch (arcadeState) {
+	case 0:
+		return;
+	case 5: {
+		initIfNeeded();
+		if (doTickUpdate())
+			return;
+
+		if (_shouldUpdateState == 0) {
+			globals->setArcadeState(6);
+			return;
+		}
+		_arcadeModeSomethingCounter++;
+		checkToOpenMenu();
+		globals->setArcadeState(0);
+		return;
+	}
+	case 6:
+	case 7:
+	case 8:
+	case 9:
+		finish();
+		return;
+	case 10:
+		fadeInAndClearScreen();
+		finish();
+		globals->setArcadeState(_shouldUpdateState + 6);
+		return;
+	case 20:
+		globals->setArcadeState(30);
+		return;
+	case 30:
+        loadTTMScriptsForStage(_nextStage);
+        // These don't seem to ever be used?
+        // UINT_39e5_0d0e = 0;
+        // UINT_39e5_0d10 = 0;
+        globals->setArcadeState(5);
+        _arcadeNeedsBufferCopy = true;
+        _flagInventoryOpened = false;
+        return;
+	default:
+		_haveBomb = arcadeState > 20;
+		if (_haveBomb)
+		  globals->setArcadeState(arcadeState - 20);
+
+		_enemyHasSmallGun = arcadeState > 10;
+		if (_enemyHasSmallGun != 0)
+		  globals->setArcadeState(arcadeState - 10);
+
+		bool _haveBigGun = arcadeState > 2;
+		if (_haveBigGun != 0)
+		  globals->setArcadeState(arcadeState - 2);
+
+		_nextStage = (arcadeState & 1) ? 4 : 0;
+
+		globals->setArcadeState(5);
+		return;
+	}
+}
+
+void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
+	const char *ttm1;
+	const char *ttm2;
+
+	switch(stage) {
+    case 0:
+		resetStageState();
+		ttm1 = "STATIONA.TTM";
+		ttm2 = "FLAMDEAD.TTM";
+		_npcState[0].x = 160;
+		_npcState[0].val1 = 160;
+		_startYOffset = 0;
+		break;
+	case 3:
+		ttm1 = "DRAGON.TTM";
+		ttm2 = "GRENADE.TTM";
+		break;
+    case 4:
+		resetStageState();
+		ttm1 = "STATIONA.TTM";
+		ttm2 = "AARC.TTM";
+		_npcState[0].x = 140;
+		_npcState[0].val1 = 140;
+		_startYOffset = -43;
+		break;
+    case 6:
+		_currentNPCRunningTTM = 0;
+		_arcadeTTM.runNextPage(276);
+		ttm1 = "SNAKERUN.TTM";
+		if (_haveBigGun)
+			ttm2 = "BIGFIGHT.TTM";
+		else
+			ttm2 = "LITFIGHT.TTM";
+		break;
+    default:
+		return;
+    }
+
+	if (stage != _loadedArcadeStage) {
+		_currentArcadeTT3Num = 1;
+		_arcadeTTM.freeShapes();
+		_arcadeTTM.freePages(1);
+		//g_TT3ScriptDataPtrs[1][0] = nullptr;
+		//g_TT3ScriptDataPtrs[1][1] = nullptr;
+		_currentArcadeTT3Num = 2;
+		_arcadeTTM.freeShapes();
+		_arcadeTTM.freePages(2);
+		_currentArcadeTT3Num = 1;
+		_arcadeTTM.load(ttm1);
+		_arcadeTTM.finishTTMParse();
+		_arcadeTTM.runNextPage(0);
+		_currentArcadeTT3Num = 2;
+		//g_TT3ScriptDataPtrs[2][0] = nullptr;
+		//g_TT3ScriptDataPtrs[2][1] = nullptr;
+		_arcadeTTM.load(ttm2);
+		_arcadeTTM.finishTTMParse();
+		_arcadeTTM.runNextPage(0);
+	}
+	//INT_39e5_0b54 = _startYOffset;
+	_finishCountdown = -1;
+	//INT_39e5_0be4 = 0; // this only ever gets set 0?
+	_loadedArcadeStage = stage;
+	initValuesForStage();
+}
+
+void DragonArcade::fadeInAndClearScreen() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	for (int fade = 63; fade > 0; fade--) {
+		engine->getGamePals()->setFade(0, 255, 0, fade * 4);
+		g_system->updateScreen();
+		g_system->delayMillis(5);
+	}
+	Common::Rect screenRect(SCREEN_WIDTH, SCREEN_HEIGHT);
+	engine->getBackgroundBuffer().fillRect(screenRect, 0);
+	engine->_compositionBuffer.fillRect(screenRect, 0);
+}
+
+void DragonArcade::drawBackgroundAndWeapons() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	Image bg(engine->getResourceManager(), engine->getDecompressor());
+	bg.drawScreen("BGND.SCR", engine->getBackgroundBuffer());
+	
+	Image weapons(engine->getResourceManager(), engine->getDecompressor());
+	weapons.loadBitmap("W.BMP");
+	if (weapons.loadedFrameCount() < 3)
+		error("Dragon Arcade: Expect 3 frames in w.bmp");
+
+	// Offsets are customized and hard-coded depending on weapon combination
+	// Frames are 0 = big gun, 1 = pistol, 2 = bomb
+	Graphics::ManagedSurface &dst = engine->getBackgroundBuffer();
+	const Common::Rect screen(SCREEN_WIDTH, SCREEN_HEIGHT);
+	if (!_haveBigGun && !_haveBomb) {
+		weapons.drawBitmap(1, 267, 160, screen, dst);
+	} else if (_haveBigGun && !_haveBomb) {
+		weapons.drawBitmap(0, 249, 159, screen, dst);
+	} else if (!_haveBigGun && _haveBomb) {
+		weapons.drawBitmap(1, 258, 155, screen, dst);
+		weapons.drawBitmap(2, 289, 165, screen, dst);
+	} else {
+		// have big gun and have bomb
+		weapons.drawBitmap(0, 246, 153, screen, dst);
+		weapons.drawBitmap(2, 295, 166, screen, dst);
+	}
+}
+
+void DragonArcade::drawBulletHitCircles(uint16 x, uint16 y, bool flag) {
+	static const byte COLORS[2][3] = { {0, 1, 9}, {0, 4, 12} };
+
+	Graphics::ManagedSurface &dst = DgdsEngine::getInstance()->_compositionBuffer;
+	for (int i = 0; i < 3; i++) {
+		byte col = COLORS[flag][i];
+		Drawing::filledCircle(x, y, 4 - i, 4 - i, &dst, col, col);
+	}
+}
+
+void DragonArcade::checkToOpenMenu() {
+	if (_arcadeModeSomethingCounter < 5) {
+		// Open menu 45, hightlight widget 139
+		DgdsEngine::getInstance()->setMenuToTrigger(kMenuReplayArcade);
+	} else {
+		// Open menu 47, hightlight widget 148
+		DgdsEngine::getInstance()->setMenuToTrigger(kMenuArcadeFrustrated);
+	}
+}
+
+void DragonArcade::clearAllNPCStates() {
+	for (uint i = 1; i < ARRAYSIZE(_npcState); i++) {
+		_npcState[i].byte12 = 0;
+		_npcState[i].npcState = -1;
+	}
+}
+
+void DragonArcade::clearAllBulletStates() {
+	for (uint i = 0; i < ARRAYSIZE(_bullets); i++) {
+		_bullets[i]._state = kBulletInactive;
+	}
+}
+
+void DragonArcade::createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16 var1) {
+	for (uint i = 0; i < ARRAYSIZE(_bullets); i++) {
+		if (_bullets[i]._state == kBulletInactive) {
+			_bullets[i]._state = kBulletFlying;
+			_bullets[i]._x = x;
+			_bullets[i]._y = x;
+			_bullets[i]._flipMode = flipMode;
+			_bullets[i]._var1 = var1;
+			if (var1 == 3)
+				_bullets[i]._speed = _nextRandomVal & 3;
+			
+			break;
+		}
+	}
+}
+
+void DragonArcade::playSfx(int16 num) const {
+	DgdsEngine::getInstance()->_soundPlayer->playSFX(num);
+}
+
+void DragonArcade::bladeTakeHitAndCheck() {
+	if (_bladeHealth)
+		_bladeHealth--;
+	if (!_enemyHasSmallGun && _bladeHealth)
+		_bladeHealth--;
+	if (_bladeHealth <= 0) {
+		playSfx(75);
+		if ((_bladeState1 == 0 && _bladeStateOffset + 28 < _npcState[0].npcState && _npcState[0].npcState <= 35)
+			|| _bladeState1 == 4) {
+			_bladeState1 = 9;
+			_npcState[0].npcState = _bladeState1 + 103;
+		} else {
+			_bladeState1 = 8;
+			_npcState[0].npcState = _bladeState1 + 98;
+		}
+		setFinishCountdownIfLessThan0(15);
+		_npcState[0].byte14 = 0;
+		_mouseButtonWentDown = 0x80;
+	} else {
+		playSfx(41);
+	}
+}
+
+void DragonArcade::drawHealthBars() {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+
+	if (_bladeHealth != _lastDrawnBladeHealth) {
+		Common::Rect clearRect(Common::Point(10, 155), 64, 10);
+		engine->_compositionBuffer.fillRect(clearRect, 0);
+
+		for (int i = 1; i <= _bladeHealth; i++) {
+			int x = 8 + i * 2;
+			engine->_compositionBuffer.drawLine(x, 155, x, 162, 12);
+		}
+
+		_lastDrawnBladeHealth = _bladeHealth;
+	}
+
+	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) && (_bossHealth != _lastDrawnBossHealth)) {
+		Common::Rect clearRect(Common::Point(10, 167), 60, 8);
+		engine->_compositionBuffer.fillRect(clearRect, 0);
+
+		byte color = (_loadedArcadeStage == 3) ? 2 : 9;
+
+		for (int i = 1; i <= _bossHealth; i++) {
+			int x = 8 + i * 2;
+			engine->_compositionBuffer.drawLine(x, 167, x, 174, color);
+		}
+		_lastDrawnBossHealth = _bossHealth;
+	}
+}
+
+void DragonArcade::redraw() {
+	if (!_dontRedrawBgndAndWeapons)
+		drawBackgroundAndWeapons();
+
+	runThenDrawBulletsInFlight();
+	_lastDrawnBladeHealth = -1;
+	_lastDrawnBossHealth = -1;
+	drawHealthBars();
+	// TODO: What are these?
+	//UINT_39e5_0d10 = 0;
+	//UINT_39e5_0d0e = 0;
+	_dontRedrawBgndAndWeapons = 0;
+	g_system->warpMouse(166, 158);
+}
+
+void DragonArcade::runThenDrawBulletsInFlight() {
+	const Common::Rect screenWin(SCREEN_WIDTH, SCREEN_HEIGHT);
+	_arcadeTTM._currentTTMNum = _npcState[0].byte14;
+	_npcState[0].x_11 = 0;
+	_npcState[0].x_12 = 0;
+	_npcState[0].x_21 = 0;
+	_npcState[0].x_22 = 0;
+	_npcState[0].y_11 = 0;
+	_npcState[0].y_12 = 0;
+	_npcState[0].y_21 = 0;
+	_npcState[0].y_22 = 0;
+	_drawXOffset = _npcState[0].x - 152;
+	_drawYOffset = _startYOffset;
+	_currentNPCRunningTTM = 0;
+	if (-1 < _npcState[0].byte12) {
+		_arcadeTTM.runNextPage(_npcState[0].npcState);
+	}
+
+	for (int i = 0; i < ARRAYSIZE(_bullets); i++) {
+		int16 x = _bullets[i]._x;
+		int16 y = _bullets[i]._y;
+		if (_bullets[i]._state == kBulletHittingBlade) {
+			drawBulletHitCircles(x, y, false);
+		} else if (_bullets[i]._state == kBulletHittingBlade) {
+			drawBulletHitCircles(x, y, true);
+		} else if (_bullets[i]._state == kBulletFlying) {
+			int16 frameno;
+			if (_bullets[i]._var1 == 3) {
+				// FIXME: this is a bit weird?
+				frameno = (_nextRandomVal % 3);
+			} else {
+				frameno = 0;
+			}
+			_bulletImg->drawBitmap(frameno, x, y, screenWin, DgdsEngine::getInstance()->_compositionBuffer, _bullets[i]._flipMode);
+		}
+	}
+
+	error("DragonArcade::runThenDrawBulletsInFlight: TODO: implement the first half here.");
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
new file mode 100644
index 00000000000..1874a2e76c6
--- /dev/null
+++ b/engines/dgds/dragon_arcade.h
@@ -0,0 +1,149 @@
+/* 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_ARCADE_H
+#define DGDS_DRAGON_ARCADE_H
+
+#include "common/types.h"
+#include "engines/dgds/dragon_arcade_ttm.h"
+
+namespace Dgds {
+
+enum DragonBulletState {
+	kBulletInactive = 0,
+	kBulletFlying = 1,
+	kBulletHittingBlade = 2,
+	kBulletHittingEnemy = 3,
+};
+
+enum DragonBladeMoveFlag {
+	kBladeMoveNone = 0,
+	kBladeMoveUp = 1,
+	kBladeMoveDown = 2,
+	kBladeMoveRight = 4,
+	kBladeMoveLeft = 8,
+};
+
+struct ArcadeNPCState {
+    int16 val1;
+    int16 val2;
+    int16 x;
+    int16 val4;
+    int16 x_11;
+    int16 y_11;
+    int16 x_12;
+    int16 y_12;
+    int16 npcState;
+    int8 byte12;
+    int8 byte13;
+    int8 health;
+    int8 byte14; /* Set to 0, 1 or 2 */
+    int16 x_21;
+    int16 y_21;
+    int16 x_22;
+    int16 y_22;
+};
+
+
+class DragonArcadeBullet {
+public:
+	DragonArcadeBullet() : _x(0), _y(0), _state(kBulletInactive),
+		_flipMode(kImageFlipNone), _var1(0), _speed(0), _var2(0), _var3(0) {}
+
+	int16 _x;
+	int16 _y;
+	DragonBulletState _state;
+	ImageFlipMode _flipMode;
+	int16 _var1;
+	uint16 _speed;
+	int16 _var2;
+	int16 _var3;
+};
+
+class DragonArcade {
+public:
+	DragonArcade();
+
+	void arcadeTick();
+	
+private:
+	void initIfNeeded();
+	void drawBackgroundAndWeapons();
+	void checkToOpenMenu();
+	void clearAllBulletStates();
+	void clearAllNPCStates();
+	void createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16 var1);
+	void bladeTakeHitAndCheck();
+	void enemyTakeHit() { _bossHealth--; }
+	void enemyTakeHitAndCheck();
+	void playSfx(int16 num) const;
+	void drawBulletHitCircles(uint16 x, uint16 y, bool flag);
+	void drawHealthBars();
+	void runThenDrawBulletsInFlight();
+	void redraw();
+	void finish();
+	void loadTTMScriptsForStage(uint16 stage);
+	void fadeInAndClearScreen();
+	bool doTickUpdate();
+	void resetStageState();
+	void initValuesForStage();
+	void setFinishCountdownIfLessThan0(int16 val);
+
+	int16 _bladeHealth;
+	int16 _bossHealth;
+	int16 _lastDrawnBladeHealth;
+	int16 _lastDrawnBossHealth;
+	uint16 _nextRandomVal;
+	int16 _loadedArcadeStage;
+	int16 _nextStage;
+	int16 _arcadeModeSomethingCounter;
+	int16 _currentArcadeTT3Num;
+	int16 _shouldUpdateState;
+	int16 _finishCountdown;
+	int16 _bladeState1;
+	int16 _bladeStateOffset;
+	uint16 _mouseButtonWentDown;
+	int16 _drawXOffset;
+	int16 _drawYOffset;
+	int16 _startYOffset;
+	int16 _scrollXOffset;
+	int16 _currentNPCRunningTTM;
+	int16 _nTickUpdates;
+	int16 _startDifficultyMaybe;
+	bool _haveBigGun;
+	bool _haveBomb;
+	bool _enemyHasSmallGun;
+	bool _dontRedrawBgndAndWeapons;
+	bool _arcadeNeedsBufferCopy;
+	bool _flagInventoryOpened;
+	bool _initFinished;
+	DragonBladeMoveFlag _bladeMoveFlag;
+	DragonArcadeBullet _bullets[20];
+	ArcadeNPCState _npcState[10];
+	Common::SharedPtr<Image> _bulletImg;
+	Common::SharedPtr<Image> _arrowImg;
+	Common::SharedPtr<Image> _scrollImg;
+	DragonArcadeTTM _arcadeTTM;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_DRAGON_ARCADE_H
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
new file mode 100644
index 00000000000..2983f6a1b49
--- /dev/null
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -0,0 +1,53 @@
+/* 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_arcade_ttm.h"
+
+namespace Dgds {
+
+DragonArcadeTTM::DragonArcadeTTM() {
+}
+
+void DragonArcadeTTM::clearDataPtrs() {
+
+}
+
+void DragonArcadeTTM::load(const char *filename) {
+
+}
+
+void DragonArcadeTTM::finishTTMParse() {
+
+}
+
+void DragonArcadeTTM::runNextPage(uint16 num) {
+
+}
+
+void DragonArcadeTTM::freePages(uint16 num) {
+
+}
+
+void DragonArcadeTTM::freeShapes() {
+
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
new file mode 100644
index 00000000000..0363fb3477a
--- /dev/null
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -0,0 +1,47 @@
+/* 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_ARCADE_TTM_H
+#define DGDS_DRAGON_ARCADE_TTM_H
+
+#include "common/types.h"
+
+namespace Dgds {
+
+/** A TTM interpreter which is simpler than the main one and
+   specialized to the arcade sequences. */
+class DragonArcadeTTM {
+public:
+	DragonArcadeTTM();
+	void clearDataPtrs();
+	void load(const char *filename);
+	void finishTTMParse();
+	void runNextPage(uint16 num);
+	void freePages(uint16 num);
+	void freeShapes();
+
+	uint16 _currentTTMNum;
+	bool _doingInit;
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_DRAGON_ARCADE_TTM_H
diff --git a/engines/dgds/drawing.cpp b/engines/dgds/drawing.cpp
new file mode 100644
index 00000000000..bfab36279d2
--- /dev/null
+++ b/engines/dgds/drawing.cpp
@@ -0,0 +1,44 @@
+/* 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 "graphics/primitives.h"
+#include "graphics/managed_surface.h"
+#include "dgds/drawing.h"
+
+namespace Dgds {
+
+namespace Drawing {
+
+void drawPixel(int x, int y, int color, void *data) {
+	Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
+
+	if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
+		*((byte *)surface->getBasePtr(x, y)) = (byte)color;
+}
+
+void filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol, byte bgcol) {
+	Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, bgcol, true, drawPixel, dst);
+	Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, drawPixel, dst);
+}
+
+}
+
+} // end namespace Dgds
diff --git a/engines/dgds/drawing.h b/engines/dgds/drawing.h
new file mode 100644
index 00000000000..15dd41a2f99
--- /dev/null
+++ b/engines/dgds/drawing.h
@@ -0,0 +1,42 @@
+/* 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_DRAWING_H
+#define DGDS_DRAWING_H
+
+namespace Graphics {
+	class ManagedSurface;
+}
+
+namespace Dgds {
+
+namespace Drawing {
+
+	// A function that can be used as the callback for Graphics::Primitives functions.
+	void drawPixel(int x, int y, int color, void *data);
+
+	void filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol, byte bgcol);
+
+};
+
+} // end namespace Dgds
+
+#endif // DGDS_DRAWING_H
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 6b3d0164e46..760cdae9cc3 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -191,9 +191,9 @@ private:
 ////////////////////////////////
 
 DragonGlobals::DragonGlobals(Clock &clock) : Globals(clock),
- _sceneOpcode100Var(0), _arcadeModeState(0), _opcode106EndMinutes(0) {
+ _sceneOpcode100Var(0), _arcadeState(0), _opcode106EndMinutes(0) {
 	_globals.push_back(new RWI16Global(0x20, &_sceneOpcode100Var));
-	_globals.push_back(new RWI16Global(0x21, &_arcadeModeState));
+	_globals.push_back(new RWI16Global(0x21, &_arcadeState));
 	_globals.push_back(new RWI16Global(0x22, &_opcode106EndMinutes));
 	_globals.push_back(new RWI16Global(0x23, &_table._row));
 	_globals.push_back(new RWI16Global(0x24, &_table._col));
@@ -205,7 +205,7 @@ DragonGlobals::DragonGlobals(Clock &clock) : Globals(clock),
 Common::Error DragonGlobals::syncState(Common::Serializer &s) {
 	Globals::syncState(s);
 	s.syncAsSint16LE(_sceneOpcode100Var);
-	s.syncAsSint16LE(_arcadeModeState);
+	s.syncAsSint16LE(_arcadeState);
 	s.syncAsSint16LE(_opcode106EndMinutes);
 
 	s.syncAsSint16LE(_table._row);
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index 958aee29d35..f29d802da65 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -135,10 +135,13 @@ class DragonGlobals : public Globals {
 public:
 	DragonGlobals(Clock &clock);
 
+	int16 getArcadeState() const { return _arcadeState; }
+	void setArcadeState(int16 state) { _arcadeState = state; }
+
 private:
 	// Dragon-specific globals
 	int16 _sceneOpcode100Var;
-	int16 _arcadeModeState;
+	int16 _arcadeState;
 	int16 _opcode106EndMinutes;
 	DragonDataTable _table;
 
diff --git a/engines/dgds/module.mk b/engines/dgds/module.mk
index a0f4b7bde9d..ed239282b19 100644
--- a/engines/dgds/module.mk
+++ b/engines/dgds/module.mk
@@ -8,6 +8,9 @@ MODULE_OBJS := \
 	dgds.o \
 	dgds_rect.o \
 	dialog.o \
+	dragon_arcade.o \
+	dragon_arcade_ttm.o \
+	drawing.o \
 	font.o \
 	game_palettes.o \
 	globals.o \


Commit: 3e931be79923d46bec4ad5658ea216e78c25713e
    https://github.com/scummvm/scummvm/commit/3e931be79923d46bec4ad5658ea216e78c25713e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Begin implementing Arcade TTM interpreter

Changed paths:
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/dragon_arcade_ttm.h


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 335b3aa09e6..11e4eda38b0 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -93,9 +93,11 @@ void DragonArcade::initIfNeeded() {
 	_scrollImg->loadBitmap(scrollBmpName);
 
 	_arcadeTTM.clearDataPtrs();
+
+	int16 envNum;
 	_arcadeTTM._currentTTMNum = 0;
-	_arcadeTTM.load(ttmName);
-	_arcadeTTM.finishTTMParse();
+	envNum = _arcadeTTM.load(ttmName);
+	_arcadeTTM.finishTTMParse(envNum);
 	_arcadeTTM._doingInit = true;
 	for (int i = 0; i < 8; i++) {
 		_arcadeTTM.runNextPage(i + 1);
@@ -108,8 +110,8 @@ void DragonArcade::initIfNeeded() {
 
 	const char *bladeTTM = _haveBigGun ? "BIGUNBLA.TTM" : "BLADE.TTM";
 
-	_arcadeTTM.load(bladeTTM);
-	_arcadeTTM.finishTTMParse();
+	envNum = _arcadeTTM.load(bladeTTM);
+	_arcadeTTM.finishTTMParse(envNum);
 	_arcadeTTM.runNextPage(0);
 
 	_bulletImg.reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
@@ -277,14 +279,14 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		_arcadeTTM.freeShapes();
 		_arcadeTTM.freePages(2);
 		_currentArcadeTT3Num = 1;
-		_arcadeTTM.load(ttm1);
-		_arcadeTTM.finishTTMParse();
+		int16 envNum = _arcadeTTM.load(ttm1);
+		_arcadeTTM.finishTTMParse(envNum);
 		_arcadeTTM.runNextPage(0);
 		_currentArcadeTT3Num = 2;
 		//g_TT3ScriptDataPtrs[2][0] = nullptr;
 		//g_TT3ScriptDataPtrs[2][1] = nullptr;
-		_arcadeTTM.load(ttm2);
-		_arcadeTTM.finishTTMParse();
+		envNum = _arcadeTTM.load(ttm2);
+		_arcadeTTM.finishTTMParse(envNum);
 		_arcadeTTM.runNextPage(0);
 	}
 	//INT_39e5_0b54 = _startYOffset;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index 2983f6a1b49..d298410679c 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -27,27 +27,102 @@ DragonArcadeTTM::DragonArcadeTTM() {
 }
 
 void DragonArcadeTTM::clearDataPtrs() {
-
+	for (int i = 0; i < 5; i++) {
+		_ttmEnvs[i] = TTMEnviro();
+	}
+	// TODO: Is this used anywhere?
+	// INT_39e5_3cb8 = -1;
 }
 
-void DragonArcadeTTM::load(const char *filename) {
+int16 DragonArcadeTTM::load(const char *filename) {
+	TTMEnviro *env = nullptr;
+	int16 envNum;
+	for (envNum = 0; envNum < ARRAYSIZE(_ttmEnvs); envNum++) {
+		if (_ttmEnvs[envNum].scr == nullptr) {
+			env = &_ttmEnvs[envNum];
+		}
+	}
+	if (!env)
+		error("Trying to load too many TTMs in Dragon arcade");
+
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	TTMParser dgds(engine->getResourceManager(), engine->getDecompressor());
+	bool parseResult = dgds.parse(env, filename);
+	if (!parseResult)
+		error("Error loading dgds arcade script %s", filename);
+	
+	env->scr->seek(0);
+
+	return envNum;
+}
 
+void DragonArcadeTTM::finishTTMParse(int16 envNum) {
+	TTMEnviro &env = _ttmEnvs[envNum];
+
+	if (!env.scr)
+		error("DragonArcadeTTM::finishTTMParse: script env %d not loaded", envNum);
+
+	// Discover the frame offsets
+	uint16 op = 0;
+	for (uint frame = 0; frame < env._totalFrames; frame++) {
+		env._frameOffsets[frame] = env.scr->pos();
+		op = env.scr->readUint16LE();
+		while (op != 0x0ff0 && env.scr->pos() < env.scr->size()) {
+			switch (op & 0xf) {
+			case 0:
+				break;
+			case 0xf: {
+				byte ch[2];
+				do {
+					ch[0] = env.scr->readByte();
+					ch[1] = env.scr->readByte();
+				} while (ch[0] != 0 && ch[1] != 0);
+				break;
+			}
+			default:
+				env.scr->skip((op & 0xf) * 2);
+				break;
+			}
+			op = env.scr->readUint16LE();
+		}
+	}
+	env.scr->seek(0);
 }
 
-void DragonArcadeTTM::finishTTMParse() {
+int16 DragonArcadeTTM::runNextPage(int16 pageNum) {
+	_shapes2[_currentTTMNum] = _shapes[_currentTTMNum];
+	//UINT_39e5_3ca2 = 0;
 
+	if (pageNum < _ttmEnvs[_currentTTMNum]._totalFrames && pageNum > -1 &&
+	_ttmEnvs[_currentTTMNum]._frameOffsets[pageNum] > -1) {
+		return runScriptPage(pageNum);
+	} else {
+		return 0;
+	}
 }
 
-void DragonArcadeTTM::runNextPage(uint16 num) {
+int16 DragonArcadeTTM::runScriptPage(int16 pageNum) {
+	Common::SeekableReadStream *scr = _ttmEnvs[_currentTTMNum].scr;
+	scr->seek(_ttmEnvs[_currentTTMNum]._frameOffsets[pageNum]);
+
+	uint16 opcode = scr->readUint16LE();
+	if (opcode == 0x0ff0)
+		return 1;
 
+	error("DragonArcadeTTM::runScriptPage: TODO: Implement me");
 }
 
 void DragonArcadeTTM::freePages(uint16 num) {
-
+	delete _ttmEnvs[num].scr;
+	_ttmEnvs[num] = TTMEnviro();
 }
 
 void DragonArcadeTTM::freeShapes() {
-
+	_shapes3[_currentTTMNum].reset();
+	_shapes[_currentTTMNum].reset();
+	for (int i = 0; i < 6; i++) {
+		_allShapes[i * 5 + _currentTTMNum].reset();
+	}
 }
 
 } // end namespace Dgds
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
index 0363fb3477a..5814a02e701 100644
--- a/engines/dgds/dragon_arcade_ttm.h
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -23,6 +23,10 @@
 #define DGDS_DRAGON_ARCADE_TTM_H
 
 #include "common/types.h"
+#include "common/ptr.h"
+
+#include "dgds/image.h"
+#include "dgds/ttm.h"
 
 namespace Dgds {
 
@@ -32,14 +36,24 @@ class DragonArcadeTTM {
 public:
 	DragonArcadeTTM();
 	void clearDataPtrs();
-	void load(const char *filename);
-	void finishTTMParse();
-	void runNextPage(uint16 num);
+	int16 load(const char *filename);
+	void finishTTMParse(int16 envNum);
+	int16 runNextPage(int16 pageNum);
+	int16 runScriptPage(int16 pageNum);
 	void freePages(uint16 num);
 	void freeShapes();
 
 	uint16 _currentTTMNum;
 	bool _doingInit;
+	
+	Common::SharedPtr<Image> _shapes3[6];
+	Common::SharedPtr<Image> _shapes2[6];
+	Common::SharedPtr<Image> _shapes[6];
+	Common::SharedPtr<Image> _allShapes[30];
+	
+	// Note: only a subset of the enviro members get used, but
+	// use the same structure for simplicity.
+	TTMEnviro _ttmEnvs[5];
 };
 
 } // end namespace Dgds


Commit: 3da5777112f4b9e7518f3b4a07bde05131855e91
    https://github.com/scummvm/scummvm/commit/3da5777112f4b9e7518f3b4a07bde05131855e91
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Implement Arcade TTM interpreter

Changed paths:
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/dragon_arcade_ttm.h
    engines/dgds/drawing.cpp
    engines/dgds/drawing.h
    engines/dgds/ttm.cpp
    engines/dgds/ttm.h


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 11e4eda38b0..eb1f4838c4b 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -33,7 +33,7 @@
 
 namespace Dgds {
 
-DragonArcade::DragonArcade() {
+DragonArcade::DragonArcade() : _arcadeTTM(_npcState) {
 }
 
 void DragonArcade::finish() {
@@ -66,7 +66,7 @@ bool DragonArcade::doTickUpdate() {
 	_nextRandomVal = DgdsEngine::getInstance()->getRandom().getRandomNumber(65535);
 
 	error("DragonArcade::doTickUpdate: finish me");
-	
+
 	return false;
 }
 
@@ -242,7 +242,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		ttm2 = "FLAMDEAD.TTM";
 		_npcState[0].x = 160;
 		_npcState[0].val1 = 160;
-		_startYOffset = 0;
+		_arcadeTTM._startYOffset = 0;
 		break;
 	case 3:
 		ttm1 = "DRAGON.TTM";
@@ -254,10 +254,10 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		ttm2 = "AARC.TTM";
 		_npcState[0].x = 140;
 		_npcState[0].val1 = 140;
-		_startYOffset = -43;
+		_arcadeTTM._startYOffset = -43;
 		break;
     case 6:
-		_currentNPCRunningTTM = 0;
+		_arcadeTTM._currentNPCRunningTTM = 0;
 		_arcadeTTM.runNextPage(276);
 		ttm1 = "SNAKERUN.TTM";
 		if (_haveBigGun)
@@ -312,7 +312,7 @@ void DragonArcade::drawBackgroundAndWeapons() {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 	Image bg(engine->getResourceManager(), engine->getDecompressor());
 	bg.drawScreen("BGND.SCR", engine->getBackgroundBuffer());
-	
+
 	Image weapons(engine->getResourceManager(), engine->getDecompressor());
 	weapons.loadBitmap("W.BMP");
 	if (weapons.loadedFrameCount() < 3)
@@ -379,7 +379,7 @@ void DragonArcade::createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16
 			_bullets[i]._var1 = var1;
 			if (var1 == 3)
 				_bullets[i]._speed = _nextRandomVal & 3;
-			
+
 			break;
 		}
 	}
@@ -467,9 +467,9 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 	_npcState[0].y_12 = 0;
 	_npcState[0].y_21 = 0;
 	_npcState[0].y_22 = 0;
-	_drawXOffset = _npcState[0].x - 152;
-	_drawYOffset = _startYOffset;
-	_currentNPCRunningTTM = 0;
+	_arcadeTTM._drawXOffset = _npcState[0].x - 152;
+	_arcadeTTM._drawYOffset = _arcadeTTM._startYOffset;
+	_arcadeTTM._currentNPCRunningTTM = 0;
 	if (-1 < _npcState[0].byte12) {
 		_arcadeTTM.runNextPage(_npcState[0].npcState);
 	}
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index 1874a2e76c6..cbd13f26da0 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -46,7 +46,7 @@ struct ArcadeNPCState {
     int16 val1;
     int16 val2;
     int16 x;
-    int16 val4;
+    int16 y;
     int16 x_11;
     int16 y_11;
     int16 x_12;
@@ -83,7 +83,7 @@ public:
 	DragonArcade();
 
 	void arcadeTick();
-	
+
 private:
 	void initIfNeeded();
 	void drawBackgroundAndWeapons();
@@ -121,11 +121,7 @@ private:
 	int16 _bladeState1;
 	int16 _bladeStateOffset;
 	uint16 _mouseButtonWentDown;
-	int16 _drawXOffset;
-	int16 _drawYOffset;
-	int16 _startYOffset;
 	int16 _scrollXOffset;
-	int16 _currentNPCRunningTTM;
 	int16 _nTickUpdates;
 	int16 _startDifficultyMaybe;
 	bool _haveBigGun;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index d298410679c..3870fc4ddda 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -21,9 +21,15 @@
 
 #include "dgds/dragon_arcade_ttm.h"
 
+#include "dgds/dragon_arcade.h"
+#include "dgds/ads.h"
+#include "dgds/drawing.h"
+#include "dgds/sound.h"
+#include "dgds/includes.h"
+
 namespace Dgds {
 
-DragonArcadeTTM::DragonArcadeTTM() {
+DragonArcadeTTM::DragonArcadeTTM(ArcadeNPCState *npcState) : _npcState(npcState) {
 }
 
 void DragonArcadeTTM::clearDataPtrs() {
@@ -50,7 +56,7 @@ int16 DragonArcadeTTM::load(const char *filename) {
 	bool parseResult = dgds.parse(env, filename);
 	if (!parseResult)
 		error("Error loading dgds arcade script %s", filename);
-	
+
 	env->scr->seek(0);
 
 	return envNum;
@@ -72,11 +78,7 @@ void DragonArcadeTTM::finishTTMParse(int16 envNum) {
 			case 0:
 				break;
 			case 0xf: {
-				byte ch[2];
-				do {
-					ch[0] = env.scr->readByte();
-					ch[1] = env.scr->readByte();
-				} while (ch[0] != 0 && ch[1] != 0);
+				TTMInterpreter::readTTMStringVal(env.scr);
 				break;
 			}
 			default:
@@ -101,15 +103,184 @@ int16 DragonArcadeTTM::runNextPage(int16 pageNum) {
 	}
 }
 
+int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, byte count, const int16 *ivals, const Common::String &sval) {
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	Graphics::ManagedSurface &compBuffer = engine->_compositionBuffer;
+	switch (op) {
+	case 0x0070:
+		// Do nothing.
+		break;
+	case 0x0080: // FREE SHAPE
+		_allShapes[_shapes3[_currentTTMNum] * 5 + _currentTTMNum].reset();
+		_shapes[_currentTTMNum].reset();
+		break;
+	case 0x1021: // SET DELAY
+		engine->adsInterpreter()->setScriptDelay((int)(ivals[0] * MS_PER_FRAME));
+		break;
+	case 0x1031: // SET BRUSH
+		if (!_shapes2[_currentTTMNum]) {
+			_brushes[_currentTTMNum] = 0;
+		} else {
+			_brushes[_currentTTMNum] = ivals[0];
+		}
+		break;
+	case 0x1051: // SET SHAPE
+		_shapes3[_currentTTMNum] = ivals[0];
+		_shapes[_currentTTMNum] = _allShapes[ivals[0] * 5 + _currentTTMNum];
+		_shapes2[_currentTTMNum] = _allShapes[ivals[0] * 5 + _currentTTMNum];
+		break;
+	case 0x1061:
+		// Do nothing (ignore arg)
+		break;
+	case 0x1101:
+	case 0x1111:
+		// Do nothing (ignore arg)
+		break;
+	case 0x2002: // SET COLORS
+		_drawColFG = (byte)ivals[0];
+		_drawColBG = (byte)ivals[1];
+		break;
+	case 0x2012: { // PLAY SOUND
+		int16 sound;
+		if (ivals[0] == 0 || ivals[0] == 1) {
+			sound = 0x26;
+		} else if (ivals[0] == 2) {
+			sound = 0x4f;
+		} else {
+			break;
+		}
+		engine->_soundPlayer->playSFX(sound);
+		break;
+	}
+	case 0x4054: { // SET NPC POS 1
+		int16 x = _drawXOffset + ivals[0];
+		int16 y = _drawYOffset + ivals[1] + 2;
+		_npcState[_currentNPCRunningTTM].x_11 = x;
+		_npcState[_currentNPCRunningTTM].x_12 = x + ivals[2];
+		_npcState[_currentNPCRunningTTM].y_11 = y;
+		_npcState[_currentNPCRunningTTM].y_12 = y + ivals[3];
+		break;
+	}
+	case 0x4514: {// SET NPC POS 2
+		int16 x = _drawXOffset + ivals[0];
+		int16 y = _drawYOffset + ivals[1] + 2;
+		_npcState[_currentNPCRunningTTM].x_21 = x;
+		_npcState[_currentNPCRunningTTM].x_22 = x + ivals[2];
+		_npcState[_currentNPCRunningTTM].y_21 = y;
+		_npcState[_currentNPCRunningTTM].y_22 = y + ivals[3];
+		break;
+	}
+	case 0xA0A4: { // DRAW LINE
+		compBuffer.drawLine(_drawXOffset + ivals[0], _drawYOffset + ivals[1] + 2, _drawXOffset + ivals[2], _drawYOffset + ivals[3] + 2, _drawColFG);
+		break;
+	}
+	case 0xA104: // DRAW FILLED RECT
+		if (_doingInit) {
+			ArcadeLevelData data;
+			data.x = (page - 1) * 320 + ivals[0];
+			data.y = ivals[2];
+			data.data = (byte)ivals[1];
+			data.flag = false;
+			_levelData.push_back(data);
+		} else {
+			const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
+			compBuffer.fillRect(rect, _drawColFG);
+		}
+		break;
+	case 0xA114: // DRAW EMPTY RECT
+		if (_doingInit) {
+			ArcadeLevelData data;
+			data.x = (page - 1) * 320 + ivals[0];
+			data.y = ivals[2];
+			data.data = (byte)ivals[1];
+			data.flag = true;
+			_levelData.push_back(data);
+		} else {
+			const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2] - 1, ivals[3] - 1);
+			compBuffer.drawLine(r.left, r.top, r.right, r.top, _drawColFG);
+			compBuffer.drawLine(r.left, r.bottom, r.right, r.bottom, _drawColFG);
+			compBuffer.drawLine(r.left, r.top, r.left, r.bottom, _drawColFG);
+			compBuffer.drawLine(r.right, r.top, r.right, r.bottom, _drawColFG);
+		}
+		break;
+	case 0xA404: { // DRAW FILLED CIRCLE
+		int16 r = ivals[3] / 2;
+		Drawing::filledCircle(ivals[0], ivals[1], r, r, &compBuffer, _drawColFG, _drawColBG);
+		break;
+	}
+	case 0xA424: { // DRAW EMPTY CIRCLE
+		int16 r = ivals[3] / 2;
+		Drawing::emptyCircle(ivals[0], ivals[1], r, r, &compBuffer, _drawColFG);
+		break;
+	}
+	case 0xA502:
+	case 0xA512:
+	case 0xA522:
+	case 0xA532: { // DRAW SHAPE
+		if (_doingInit)
+			break;
+
+		ImageFlipMode flipMode = kImageFlipNone;
+		if (op == 0xa512)
+			flipMode = kImageFlipV;
+		else if (op == 0xa522)
+			flipMode = kImageFlipH;
+		else if (op == 0xa532)
+			flipMode = kImageFlipHV;
+
+		Common::Rect drawWin(SCREEN_WIDTH, SCREEN_HEIGHT);
+		if (_currentNPCRunningTTM == 0) {
+			int16 x = ivals[0] + _npcState[0].x - 152;
+			int16 y = ivals[1] + _startYOffset + 2;
+			_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
+			_npcState[0].y = ivals[1];
+		} else {
+			int16 x = ivals[0] + _drawXOffset;
+			int16 y = ivals[1] + _drawYOffset + 2;
+			_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
+			_npcState[_currentNPCRunningTTM].x = ivals[0];
+			_npcState[_currentNPCRunningTTM].y = ivals[1];
+		}
+		break;
+	}
+	case 0xF02F: {
+		_shapes[_currentTTMNum].reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
+		_shapes[_currentTTMNum]->loadBitmap(sval);
+		_shapes2[_currentTTMNum] = _shapes[_currentTTMNum];
+		_allShapes[_shapes3[_currentTTMNum] * 5 + _currentTTMNum] = _shapes[_currentTTMNum];
+		break;
+	}
+	case 0x505F:
+		// Do nothing (ignore arg)
+		break;
+	default:
+		error("Unsupported TTM opcode 0x%04x for Dragon arcade.", op);
+	}
+	return 0;
+}
+
 int16 DragonArcadeTTM::runScriptPage(int16 pageNum) {
 	Common::SeekableReadStream *scr = _ttmEnvs[_currentTTMNum].scr;
 	scr->seek(_ttmEnvs[_currentTTMNum]._frameOffsets[pageNum]);
 
 	uint16 opcode = scr->readUint16LE();
-	if (opcode == 0x0ff0)
-		return 1;
+	while (opcode != 0x0ff0 && opcode) {
+		int16 ivals[4];
+		Common::String sval;
+		byte count = (byte)(opcode & 0xf);
+		if (count <= 4) {
+			for (int i = 0; i < count; i++)
+				ivals[i] = scr->readUint16LE();
+		} else if (count == 0xf) {
+			sval = TTMInterpreter::readTTMStringVal(scr);
+		} else {
+			error("Unsupported TTM opcode 0x%04x with %d args for Dragon arcade.", opcode, count);
+		}
+
+		handleOperation(_ttmEnvs[_currentTTMNum], pageNum, opcode, count, ivals, sval);
+	}
+	return 1;
 
-	error("DragonArcadeTTM::runScriptPage: TODO: Implement me");
 }
 
 void DragonArcadeTTM::freePages(uint16 num) {
@@ -118,7 +289,7 @@ void DragonArcadeTTM::freePages(uint16 num) {
 }
 
 void DragonArcadeTTM::freeShapes() {
-	_shapes3[_currentTTMNum].reset();
+	_shapes3[_currentTTMNum] = 0;
 	_shapes[_currentTTMNum].reset();
 	for (int i = 0; i < 6; i++) {
 		_allShapes[i * 5 + _currentTTMNum].reset();
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
index 5814a02e701..bd2809f57c7 100644
--- a/engines/dgds/dragon_arcade_ttm.h
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -30,30 +30,54 @@
 
 namespace Dgds {
 
+struct ArcadeLevelData {
+	int16 x;
+	int16 y;
+	byte data;
+	bool flag;
+};
+
+struct ArcadeNPCState;
+
 /** A TTM interpreter which is simpler than the main one and
    specialized to the arcade sequences. */
 class DragonArcadeTTM {
 public:
-	DragonArcadeTTM();
+	DragonArcadeTTM(ArcadeNPCState *npcState);
 	void clearDataPtrs();
 	int16 load(const char *filename);
 	void finishTTMParse(int16 envNum);
 	int16 runNextPage(int16 pageNum);
-	int16 runScriptPage(int16 pageNum);
 	void freePages(uint16 num);
 	void freeShapes();
 
 	uint16 _currentTTMNum;
+	int16 _currentNPCRunningTTM;
+	int16 _drawXOffset;
+	int16 _drawYOffset;
+	int16 _startYOffset;
 	bool _doingInit;
-	
-	Common::SharedPtr<Image> _shapes3[6];
+
+private:
+	int16 runScriptPage(int16 pageNum);
+	int16 handleOperation(TTMEnviro &env, int16 page, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
+
+	int16 _shapes3[6];
 	Common::SharedPtr<Image> _shapes2[6];
 	Common::SharedPtr<Image> _shapes[6];
 	Common::SharedPtr<Image> _allShapes[30];
-	
+	int16 _brushes[6];
+
+	byte _drawColFG;
+	byte _drawColBG;
+	ArcadeNPCState *_npcState;
+	// int16 _numA1x4OpsInInit; // implicit by count of items in _levelData
+	Common::Array<ArcadeLevelData> _levelData;
+
 	// Note: only a subset of the enviro members get used, but
 	// use the same structure for simplicity.
 	TTMEnviro _ttmEnvs[5];
+
 };
 
 } // end namespace Dgds
diff --git a/engines/dgds/drawing.cpp b/engines/dgds/drawing.cpp
index bfab36279d2..d7146aee758 100644
--- a/engines/dgds/drawing.cpp
+++ b/engines/dgds/drawing.cpp
@@ -39,6 +39,10 @@ void filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, b
 	Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, drawPixel, dst);
 }
 
+void emptyCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol) {
+	Graphics::drawEllipse(x - xr, y - yr, x + xr, y + yr, fgcol, false, drawPixel, dst);
+}
+
 }
 
 } // end namespace Dgds
diff --git a/engines/dgds/drawing.h b/engines/dgds/drawing.h
index 15dd41a2f99..145ebc1f9b6 100644
--- a/engines/dgds/drawing.h
+++ b/engines/dgds/drawing.h
@@ -34,6 +34,7 @@ namespace Drawing {
 	void drawPixel(int x, int y, int color, void *data);
 
 	void filledCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol, byte bgcol);
+	void emptyCircle(int x, int y, int xr, int yr, Graphics::ManagedSurface *dst, byte fgcol);
 
 };
 
diff --git a/engines/dgds/ttm.cpp b/engines/dgds/ttm.cpp
index d0b5a11e3f9..9c3625dc0dc 100644
--- a/engines/dgds/ttm.cpp
+++ b/engines/dgds/ttm.cpp
@@ -1083,6 +1083,21 @@ void TTMInterpreter::handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byt
 	}
 }
 
+Common::String TTMInterpreter::readTTMStringVal(Common::SeekableReadStream *scr) {
+	Common::String sval;
+	byte ch[2];
+
+	do {
+		ch[0] = scr->readByte();
+		ch[1] = scr->readByte();
+		if (ch[0])
+			sval += ch[0];
+		if (ch[1])
+			sval += ch[1];
+	} while (ch[0] != 0 && ch[1] != 0);
+	return sval;
+}
+
 bool TTMInterpreter::run(TTMEnviro &env, TTMSeq &seq) {
 	Common::SeekableReadStream *scr = env.scr;
 	if (!scr || scr->pos() >= scr->size())
@@ -1120,16 +1135,7 @@ bool TTMInterpreter::run(TTMEnviro &env, TTMSeq &seq) {
 					debugN(10, "(%d,%d)", pts[i].x, pts[i].y);
 				debugN(10, "]");
 			} else {
-				byte ch[2];
-
-				do {
-					ch[0] = scr->readByte();
-					ch[1] = scr->readByte();
-					if (ch[0])
-						sval += ch[0];
-					if (ch[1])
-						sval += ch[1];
-				} while (ch[0] != 0 && ch[1] != 0);
+				sval = readTTMStringVal(scr);
 				debugN(10, "\"%s\"", sval.c_str());
 			}
 
@@ -1201,11 +1207,7 @@ void TTMInterpreter::findAndAddSequences(TTMEnviro &env, Common::Array<TTMSeq> &
 					int16 nbytes = env.scr->readUint16LE() * 4;
 					env.scr->skip(nbytes);
 				} else {
-					byte ch[2];
-					do {
-						ch[0] = env.scr->readByte();
-						ch[1] = env.scr->readByte();
-					} while (ch[0] != 0 && ch[1] != 0);
+					readTTMStringVal(env.scr);
 				}
 				break;
 			}
diff --git a/engines/dgds/ttm.h b/engines/dgds/ttm.h
index f1103d1ae4a..9436d063c7f 100644
--- a/engines/dgds/ttm.h
+++ b/engines/dgds/ttm.h
@@ -123,6 +123,8 @@ public:
 	bool run(TTMEnviro &env, TTMSeq &seq);
 	void findAndAddSequences(TTMEnviro &scriptData, Common::Array<TTMSeq> &seqArray);
 
+	static Common::String readTTMStringVal(Common::SeekableReadStream *scr);
+
 protected:
 	void handleOperation(TTMEnviro &env, TTMSeq &seq, uint16 op, byte count, const int16 *ivals, const Common::String &sval, const Common::Array<Common::Point> &pts);
 	int32 findGOTOTarget(TTMEnviro &env, TTMSeq &seq, int16 frame);


Commit: bf0f312d5b4fe35ea370bda59873b80d82935bab
    https://github.com/scummvm/scummvm/commit/bf0f312d5b4fe35ea370bda59873b80d82935bab
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: More WIP dragon arcade code

Changed paths:
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/dragon_arcade_ttm.h
    engines/dgds/scene.cpp
    engines/dgds/scene.h


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index eb1f4838c4b..aaa1e5a450b 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -20,11 +20,15 @@
  */
 
 #include "common/util.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+
 #include "dgds/dgds.h"
 #include "dgds/image.h"
 #include "dgds/includes.h"
 #include "dgds/dragon_arcade.h"
 #include "dgds/sound.h"
+#include "dgds/scene.h"
 #include "dgds/drawing.h"
 #include "dgds/globals.h"
 #include "dgds/game_palettes.h"
@@ -36,6 +40,10 @@ namespace Dgds {
 DragonArcade::DragonArcade() : _arcadeTTM(_npcState) {
 }
 
+static uint _getNextRandom() {
+	return DgdsEngine::getInstance()->getRandom().getRandomNumber(65535);
+}
+
 void DragonArcade::finish() {
 	_arcadeTTM._currentTTMNum = 0;
 	_arcadeTTM.freeShapes();
@@ -59,17 +67,902 @@ bool DragonArcade::doTickUpdate() {
 	// TODO: Copy video buffers here?
 
 	if (_finishCountdown == 0)
-		return 0;
+		return false;
 
 	// TODO: Set video mask here?
 
-	_nextRandomVal = DgdsEngine::getInstance()->getRandom().getRandomNumber(65535);
+	_nextRandomVal = _getNextRandom();
+
+	if (!_arcadeNeedsBufferCopy) {
+		updateMouseAndJoystickStates();
+		updateBladeWithInputs();
+	}
+
+	int16 findResult = findValuesIn3d30Array();
+	arcade2754(findResult);
+	
+	switch (_loadedArcadeStage) {
+	case 0:
+	case 1:
+	case 2:
+		updateBlade();
+		arcade3e96();
+		break;
+	case 3:
+		updateBoss();
+		break;
+	case 4:
+		updateBlade();
+		arcade4085();
+		break;
+	case 5:
+		arcade4085();
+		break;
+	case 6:
+		updateBoss2();
+		break;
+	}
+
+    updateBullets();
+    //setSomeVideoFlags();
+    runThenDrawBulletsInFlight();
+    checkBladeFireAllStages();
+	switch(_loadedArcadeStage) {
+      case 0:
+      case 1:
+      case 2:
+      case 4:
+        checkEnemyFireStage0124();
+        break;
+      case 3:
+        checkBossFireStage3();
+        break;
+      case 6:
+        checkBossFireStage6();
+        break;
+      default:
+		break;
+    }
+    drawHealthBars();
+    //do { } while (_arcadeTickDelay != 0);
+    //_arcadeTickDelay = 4;
+    _nTickUpdates++;
+    
+	return true;
+}
+
+void DragonArcade::updateBullets() {
+	for (int i = 19; i > 0; i++) {
+		if (_bullets[i]._state == 2 || _bullets[i]._state == 3) {
+			_bullets[i]._state = kBulletInactive;
+			continue;
+		}
+		
+		if (_bullets[i]._state == kBulletFlying) {
+			if (_bullets[i]._var1 == 3) {
+				_bullets[i]._y += _bullets[i]._speed;
+			}
+			if (_bullets[i]._flipMode == 0) {
+				_bullets[i]._x -= (_scrollXIncrement * 8 - 10);
+				if (_bullets[i]._x < 0x141) {
+					int iVar2 = checkBulletCollision(i);
+					if (iVar2 != 0) {
+						if (iVar2 < 1) {
+							_bullets[i]._state = kBulletHittingEnemy;
+						} else {
+							_bullets[i]._state = kBulletHittingBlade;
+						}
+					}
+					continue;
+				}
+			} else {
+				_bullets[i]._x -= (_scrollXIncrement * 8 + 10);
+				if (-0x29 < _bullets[i]._x) {
+					int iVar2 = checkBulletCollision(i);
+					if (iVar2 != 0) {
+						if (iVar2 < 1) {
+							_bullets[i]._state = kBulletHittingEnemy;
+						} else {
+							_bullets[i]._state = kBulletHittingBlade;
+						}
+					}
+					continue;
+				}
+			}
+			_bullets[i]._state = kBulletInactive;
+		}
+	}
+}
+
+int16 DragonArcade::checkBulletCollision(int16 num) {
+	error("TODO: Implement me");
+}
+
+
+static const int16 FIRE_ALLOWABLE_PAGES[] = {
+	0x1A, 0x26, 0x3E, 0x74, 0x94, 0xA0, 0xB8, 0xEE
+};
+
+static const int16 FIRE_Y_OFFSETS_SMALL_GUN[] = {
+	0x3A, 0x5A, 0x41, 0x4F, 0x37, 0x5A, 0x47, 0x4F
+};
+
+static const int16 FIRE_Y_OFFSETS_BIG_GUN[] = {
+	0x38, 0x5E, 0x3E, 0x52, 0x40, 0x5E, 0x3D, 0x52
+};
+
+static const int16 FIRE_X_OFFSETS[] = {
+	0xC4, 0xC8, 0xC8, 0xC2, 0x7A, 0x72, 0x69, 0x78
+};
+
+void DragonArcade::checkBladeFireAllStages() {
+	int16 yoff;
+	int16 sndno;
+	ImageFlipMode flipMode;
+	
+	_bladeHasFired = false;
+	if (_npcState[0].byte14 != 0)
+		return;
+
+	for (int i = 0; i < 8; i++) {
+		if (FIRE_ALLOWABLE_PAGES[i] == _npcState[0].ttmPage) {
+			if (_npcState[0].ttmPage < 0x7b) {
+				flipMode = kImageFlipNone;
+			} else {
+				flipMode = kImageFlipV;
+			}
+			if (_haveBigGun == 0) {
+				yoff = FIRE_Y_OFFSETS_SMALL_GUN[i];
+			} else {
+				yoff = FIRE_Y_OFFSETS_BIG_GUN[i];
+			}
+
+			createBullet(FIRE_X_OFFSETS[i] + _npcState[0].x - 0xa0,
+						 yoff + _arcadeTTM._startYOffset, flipMode, 0);
+
+			// is this always 0?
+			//if (INT_39e5_0c58 == 0) {
+			sndno = 0x2f;
+			//} else {
+			//sndno = 0x34;
+			//}
+			playSfx(sndno);
+			_bladeHasFired = true;
+			break;
+		}
+	}
+}
+
+
+static const int16 ENEMY_FIRE_ALLOWABLE_PAGES[] =  { 3, 0xC, 0x1F, 0x28 };
+static const int16 ENEMY_FIRE_X_OFFSETS[] = { 0xB1, 0xB3, 0x77, 0x75, };
+static const int16 ENEMY_FIRE_Y_OFFSETS[] = { 0x4E, 0x56, 0x4D, 0x55,};
+
+void DragonArcade::checkEnemyFireStage0124() {
+	for (int i = 9; i != 0; i--) {
+		if (_npcState[i].byte12 == 0)
+			continue;
+		for (int j = 0; j < 4; j++) {
+			if (_npcState[i].x < 0x154 && -20 < _npcState[i].x &&
+				ENEMY_FIRE_ALLOWABLE_PAGES[j] == _npcState[i].ttmPage) {
+				ImageFlipMode flipMode = (_npcState[i].ttmPage < 0x1d) ? kImageFlipNone : kImageFlipV;
+				createBullet(ENEMY_FIRE_X_OFFSETS[j] + _npcState[i].val1 - _scrollXOffset * 8 - 0xa0,
+							 ENEMY_FIRE_Y_OFFSETS[j] + _npcState[i].val2 + 3, flipMode, 1);
+				playSfx(0x25);
+			}
+		}
+	}
+}
+
+
+void DragonArcade::checkBossFireStage3() {
+	if (_npcState[1].x < 0x154 && -20 < _npcState[1].x && _npcState[1].ttmPage == 22) {
+		createBullet(_npcState[1].val1 - _scrollXOffset * 8 - 44,
+						_npcState[1].val2 + 70, kImageFlipH, 3);
+		playSfx(0x2a);
+	}
+}
+
+void DragonArcade::checkBossFireStage6() {
+	ImageFlipMode flipMode = (_npcState[1].ttmPage < 0x28) ? kImageFlipNone: kImageFlipV;
+
+	if (_npcState[1].x < 0x154 && -20 < _npcState[1].x &&
+		(_npcState[1].ttmPage == 9 || _npcState[1].ttmPage == 0x28)) {
+		createBullet(_npcState[1].val1 - _scrollXOffset * 8 - 19,
+						_npcState[1].val2 + 86, flipMode, 2);
+		playSfx(0x24);
+  }
+}
+
+void DragonArcade::limitToCenterOfScreenAndUpdateCursor() {
+	Common::Point lastMouse = DgdsEngine::getInstance()->getLastMouse();
+	/* limit mouse coords to (x = 144-190, y = 135-180) */
+	lastMouse.x = CLIP((int)lastMouse.x, 144, 190);
+	lastMouse.y = CLIP((int)lastMouse.y, 135, 180);
+	g_system->warpMouse(lastMouse.x, lastMouse.y);
+	
+	int16 arrowNum = (lastMouse.x - 144) / 16 + ((lastMouse.y - 136) / 16) * 3;
+
+    if (_currentArrowNum != arrowNum && arrowNum < 9) {
+		_currentArrowNum = arrowNum;
+		CursorMan.replaceCursor(*(_arrowImg->getSurface(arrowNum)->surfacePtr()), 0, 0, 0, 0);
+    }
+    //if (g_arcadeNeedsBufferCopy == 0) {
+    //  Arcade_MouseCursorDraw();
+    //}
+}
+
+void DragonArcade::keyboardUpdate() {
+	// TODO: Keyboard update.
+}
+
+void DragonArcade::mouseUpdate() {
+	limitToCenterOfScreenAndUpdateCursor();
+	_rMouseButtonState = DgdsEngine::getInstance()->getScene()->isRButtonDown();
+	_lMouseButtonState = DgdsEngine::getInstance()->getScene()->isLButtonDown();
+	int16 arrowRow = _currentArrowNum / 3;
+	if (arrowRow == 0) {
+		_keyStateFlags = kBladeMoveUp;
+	} else if (arrowRow == 1) {
+		_keyStateFlags = kBladeMoveNone;
+	} else if (arrowRow == 2) {
+		_keyStateFlags = kBladeMoveDown;
+	}
+	if (_currentArrowNum % 3 == 0) {
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveLeft);
+	} else if (_currentArrowNum % 3 == 2) {
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveRight);
+	}
+}
+
+void DragonArcade::updateMouseAndJoystickStates() {
+	_bladeXMove = 0;
+	_scrollXIncrement = 0;
+	_rMouseButtonState = 0;
+	_lMouseButtonState = 0;
+	if (!_mouseIsAvailable) {
+		//if (g_optionJoystickOnButtonState != 0) {
+		//	Joystick_ArcadeUpdate();
+		//}
+		keyboardUpdate();
+	} else {
+		mouseUpdate();
+	}
+
+	if (_mouseButtonWentDown != 0x80) {
+		_bladeMoveFlag = kBladeMoveNone;
+		if ((_keyStateFlags & kBladeMoveRight) == kBladeMoveNone) {
+			if ((_keyStateFlags & kBladeMoveLeft) != kBladeMoveNone) {
+				if (_arcadeNotMovingLeftFlag) {
+					_arcadeNotMovingLeftFlag = false;
+				}
+				_bladeMoveFlag = kBladeMoveLeft;
+				if (_bladeState1 == 0) {
+					_int0b5c = -1;
+					_bladeHorizMoveAttempt = 1;
+				}
+			}
+		} else {
+			_bladeMoveFlag = kBladeMoveRight;
+			if (_bladeState1 == 0) {
+				_int0b5c = 1;
+				_bladeHorizMoveAttempt = 2;
+			}
+		}
+		if ((_keyStateFlags & kBladeMoveUp) == kBladeMoveNone) {
+			if ((_keyStateFlags & kBladeMoveDown) != kBladeMoveNone) {
+				_bladeMoveFlag = static_cast<DragonBladeMoveFlag>(_bladeMoveFlag | kBladeMoveDown);
+			}
+		} else {
+			_bladeMoveFlag = static_cast<DragonBladeMoveFlag>(_bladeMoveFlag | kBladeMoveUp);
+		}
+		if ((_lMouseButtonState != 0) && (_lastLMouseButtonState == 0)) {
+			_mouseButtonWentDown = 1;
+		}
+		if (_rMouseButtonState != 0 && _lastRMouseButtonState == 0 && _bladeState1 != 2 && _bladeState1 != 1) {
+			_mouseButtonWentDown = 2;
+			_bladeMoveFlagBeforeRButton = _bladeMoveFlag;
+		}
+		_lastLMouseButtonState = _lMouseButtonState;
+		_lastRMouseButtonState = _rMouseButtonState;
+	}
+}
+
+int16 DragonArcade::findValuesIn3d30Array() {
+	error("DragonArcade::findValuesIn3d30Array: Implement me");
+}
+
+bool DragonArcade::isNpcInsideXRange(int16 num) {
+	return _npcState[num].x < 321 && _npcState[num].x > 1;
+}
+
+
+void DragonArcade::arcade4085() {
+	error("DragonArcade::arcade4085: implement me");
+}
+
+void DragonArcade::arcade2754(int16 findResult) {
+	error("DragonArcade::arcade2754: implement me");
+}
+
+
+static const int16 arrayC5A[4][7] {
+    { 0x8, 0x19, 0x5A, 0x78, 0x8C, 0xA5, 0xBE },
+    { 0x6, 0x28, 0x5A, 0x87, 0x96, 0xAA, 0xC0 },
+    { 0x4, 0x37, 0x69, 0x79, 0x91, 0xA0, 0xC2 },
+    { 0x2, 0x46, 0x69, 0x87, 0x9B, 0xAF, 0xC4 },
+};
+
+static const int16 arrayC92[4][7] {
+	{ 0xA, 0x37, 0x46, 0x55, 0x91, 0xAA, 0xC8 },
+	{ 0x19, 0x5F, 0x87, 0x9B, 0xB9, 0xD7, -0x1 },
+	{ 0x19, 0x23, 0x69, 0x7D, 0x9B, 0xB9, 0xD7 },
+	{ 0xA, 0x37, 0x46, 0x73,  0xAA, 0xC8,  -0x1 },
+};
+
+
+void DragonArcade::arcade3e96() {
+	for (int i = 0; i < 4; i++) {
+		for (int j = 0; j < 7; j++) {
+			if (_loadedArcadeStage == 0) {
+				if (_flag40ee && arrayC5A[i][j] == _someCounter40f0) {
+					_npcState[i].ttmPage = 1;
+				}
+			} else if (_loadedArcadeStage == 1) {
+				if (arrayC92[i][j] == _someCounter40f0) {
+					_npcState[4 + i].ttmPage = 1;
+				}
+				if (_flag40ee && arrayC5A[i][j] == _someCounter40f0) {
+					_npcState[i].ttmPage = 1;
+				}
+			} else if (_loadedArcadeStage == 2 && _flag40ef && arrayC92[i][j] == _someCounter40f0) {
+				_npcState[i].ttmPage = 1;
+			}
+		}
+	}
+
+
+	for (int i = 10; i < 18; i++) {
+		_npcState[i].ttmPage++;
+		if (_npcState[i].ttmPage < 2 || _npcState[i].ttmPage > 18) {
+			_npcState[i].byte12 = 0;
+		} else {
+			if (_npcState[i].ttmPage == 2 && isNpcInsideXRange(i)) {
+				playSfx(0x5a);
+			}
+			_npcState[i].byte12 = 0xfc;
+			if (_npcState[i].ttmPage < 0xf &&
+				_npcState[i].val1 - 16 <= _npcState[0].val1 &&
+				_npcState[0].val1 <= _npcState[i].val1 + 12 && _npcState[0].health != 0 &&
+				(_loadedArcadeStage != 1 || _arcadeTTM._startYOffset < -9 ||
+				 (_bladeMoveFlag & kBladeMoveRight) == kBladeMoveNone)) {
+				setFinishCountdownIfLessThan0(20);
+				_npcState[0].byte14 = 2;
+				_npcState[0].health = 0;
+				if (_haveBigGun == 0) {
+					_npcState[0].ttmPage = 0x22;
+				} else {
+					_npcState[0].ttmPage = 0x19;
+				}
+				_npcState[0].byte12 = 12;
+				_bladeState1 = 0xc;
+				_mouseButtonWentDown = 0x80;
+			}
+		}
+	}
+	_someCounter40f0++;
+	if (_someCounter40f0 == 221) {
+        _someCounter40f0 = 0;
+	}
+
+}
+
+void DragonArcade::updateBlade() {
+	int16 local_6 = 0;
+	
+	for (int i = 9; i > 0; i--) {
+		if (_npcState[i].byte12 == 0)
+			continue;
+
+		int16 startPage = (_npcState[i].ttmPage < 30) ? 0 : 28;
+
+		if (_npcState[i].byte13 == 0 &&
+			((startPage != 0 && _npcState[i].val1 < _npcState[0].val1) ||
+			 (startPage == 0 && _npcState[0].val1 < _npcState[i].val1))) {
+			
+			if (_npcState[i].byte12 == 4 || _npcState[i].byte12 == 5) {
+				if (_npcState[i].byte12 == 4) {
+					_npcState[i].byte13 = 5;
+					_npcState[i].byte12 = 7;
+					_npcState[i].ttmPage = startPage + 26;
+				} else if (_npcState[i].byte12 == 5) {
+					_npcState[i].byte13 = 7;
+					_npcState[i].byte12 = 8;
+					_npcState[i].ttmPage = startPage + 18;
+				}
+				local_6++;
+			}
+		}
+
+		if (local_6 != 0)
+			continue;
+		
+		switch (_npcState[i].byte12 - 1) {
+		case 5:
+			if ( _npcState[i].ttmPage < startPage + 11) {
+				_npcState[i].ttmPage++;
+				break;
+			}
+			_npcState[i].byte13 = 0;
+			_npcState[i].byte12 = 5;
+			_npcState[i].ttmPage = startPage + 11;
+			break;
+		case 6:
+			if (_npcState[i].ttmPage < startPage + 29) {
+				_npcState[i].ttmPage++;
+				break;
+			}
+			startPage = startPage ^ 28;
+			if (_npcState[i].byte13 == 7) {
+				_npcState[i].byte13 = 0;
+				_npcState[i].byte12 = 4;
+				_npcState[i].ttmPage = startPage + 2;
+				break;
+			}
+			_npcState[i].byte12 = 6;
+			_npcState[i].ttmPage = startPage + 9;
+			break;
+		case 7:
+			if (_npcState[i].ttmPage < startPage + 20) {
+				_npcState[i].ttmPage++;
+				break;
+			}
+			if (_npcState[i].byte13 == 4){
+				_npcState[i].byte13 = 0;
+				_npcState[i].byte12 = 4;
+				_npcState[i].ttmPage = startPage + 2;
+				break;
+			}
+			_npcState[i].byte12 = 7;
+			_npcState[i].ttmPage = startPage + 26;
+			break;
+		case 0:
+			if (_npcState[i].ttmPage < startPage + 23) {
+				_npcState[i].ttmPage++;
+			}
+			break;
+		case 3:
+			if ((0xf - i == (_nextRandomVal & 0xf)) &&
+				 abs(_npcState[i].y - _npcState[0].y) < 36 && _npcState[0].health != 0) {
+				_npcState[i].byte12 = 2;
+				_npcState[i].ttmPage = startPage + 3;
+			}
+			break;
+		case 4:
+			if ((0xf - i == (_nextRandomVal & 0xf)) &&
+				  abs(_npcState[i].y - _npcState[0].y) < 36 && _bladeState1 != 8 && _bladeState1 != 9) {
+				_npcState[i].byte12 = 3;
+				_npcState[i].ttmPage = startPage + 12;
+			}
+			break;
+		case 2:
+			if (_npcState[i].ttmPage < startPage + 17) {
+				_npcState[i].ttmPage++;
+				break;
+			}
+			_npcState[i].byte12 = 5;
+			_npcState[i].ttmPage = startPage + 11;
+			break;
+		case 1:
+			if (_npcState[i].ttmPage < startPage + 8) {
+				_npcState[i].ttmPage++;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+}
+
+
+void DragonArcade::updateBoss() {
+	_npcState[2].ttmPage = _npcState[2].ttmPage + 1;
+	if (29 < _npcState[2].ttmPage) {
+		_npcState[2].ttmPage = 23;
+	}
+
+	int16 distToBoss = _npcState[1].x - _npcState[0].x;
+	int16 absDistToBoss = abs(distToBoss);
+	bool bossIsClose = absDistToBoss < 20;
+	uint16 uVar4 = _nextRandomVal & 0xf;
+
+	switch(_npcState[1].byte12) {
+	case 0:
+		if (bossIsClose && absDistToBoss < 45) {
+			if (_bladeState1 != 8 && _bladeState1 != 9) {
+				_npcState[1].byte12 = 5;
+				_npcState[1].ttmPage = 30;
+			}
+		} else if (distToBoss < 0 || (_bossStateUpdateCounter < 0 && uVar4 == 7)) {
+			_npcState[1].byte12 = 3;
+			_npcState[1].ttmPage = 10;
+			_bossStateUpdateCounter++;
+		} else if ((bossIsClose && distToBoss < 70 && 0 < distToBoss && uVar4 == 0xf) || (0 < _bossStateUpdateCounter && uVar4 == 7)) {
+			_npcState[1].byte12 = 2;
+			_npcState[1].ttmPage = 3;
+			_bossStateUpdateCounter--;
+		} else if (_bossStateUpdateCounter == 0 && uVar4 == 0xf) {
+			_npcState[1].byte12 = 4;
+			_npcState[1].ttmPage = 17;
+		}
+		break;
+	case 7:
+		if (_npcState[1].ttmPage < 89) {
+			_npcState[1].ttmPage++;
+		} else {
+			_npcState[1].byte12 = 9;
+			_npcState[1].ttmPage = 67;
+		}
+		break;
+	case 9:
+		if (0x37 < _npcState[1].ttmPage) {
+			decBossHealth();
+		}
+		if ((_npcState[1].ttmPage != 67 || (_nTickUpdates & 0x1fU) == 0) && _npcState[1].ttmPage < 74) {
+			if (_npcState[1].ttmPage < 68) {
+				_npcState[1].ttmPage++;
+			} else if (!(_nTickUpdates & 1)) {
+				setFinishCountdownIfLessThan0(15);
+			} else {
+				_npcState[1].ttmPage++;
+			}
+		}
+		break;
+	case 8:
+		if ((_npcState[1].ttmPage != 67 || (_nTickUpdates & 0x1fU) == 0) && _npcState[1].ttmPage < 74) {
+			playSfx(75);
+			setFinishCountdownIfLessThan0(20);
+			if (_npcState[1].ttmPage == 67) {
+				_npcState[1].ttmPage = 68;
+			} else if (_nTickUpdates & 1) {
+				_npcState[1].ttmPage++;
+			}
+		}
+		break;
+	case 6:
+		if (_npcState[1].ttmPage < 78) {
+			_npcState[1].ttmPage++;
+			break;
+		}
+		// FALL THROUGH
+	case 3:
+		if (_npcState[1].ttmPage < 22) {
+			_npcState[1].ttmPage++;
+		} else {
+			_npcState[1].byte12 = 1;
+			_npcState[1].ttmPage = 2;
+		}
+		break;
+	case 2:
+		if (_npcState[1].ttmPage < 16) {
+			_npcState[1].ttmPage++;
+			_npcState[1].val1 += 6;
+		} else {
+			_npcState[1].byte12 = 1;
+			_npcState[1].ttmPage = 2;
+		}
+		break;
+	case 1:
+		if (_npcState[1].ttmPage < 9) {
+			_npcState[1].ttmPage++;
+			_npcState[1].val1 -= 6;
+		} else {
+			_npcState[1].byte12 = 5;
+			_npcState[1].ttmPage = 30;
+		}
+		break;
+	case 4:
+		if (_npcState[1].ttmPage < 37) {
+			_npcState[1].ttmPage++;
+			// TODO: does UINT_39e5_0a17 ever get modified? It's set 0 in resetStageState
+			if (bossIsClose && absDistToBoss < 50 && /*UINT_39e5_0a17 == 0 &&*/ 33 < _npcState[1].ttmPage && _npcState[1].ttmPage < 37) {
+				_npcState[0].byte12 = 10;
+				_bladeState1 = 10;
+				_npcState[0].ttmPage = 76;
+				bladeTakeHit();
+				if (_npcState[0].health == 0) {
+					_shouldUpdateState = 3;
+				}
+			}
+		} else {
+			_npcState[1].byte12 = 1;
+			_npcState[1].ttmPage = 2;
+		}
+		break;
+	default:
+		break;
+	}
+
+	// TODO: Is this supposed to be just be case 5 or apply to all cases?
+	if (_npcState[3].byte12 == -2) {
+		_npcState[3].health--;
+		if (_npcState[3].health == 6) {
+			_npcState[1].ttmPage = 49;
+			_npcState[1].byte12 = 10;
+		}
+		if (_npcState[3].health == 0) {
+			_npcState[3].byte12 = -3;
+			_npcState[3].ttmPage = 39;
+			_npcState[3].byte14 = 1;
+		}
+	} else if (_npcState[3].byte12 == -3) {
+		_npcState[3].ttmPage++;
+		if (48 < _npcState[3].ttmPage)
+			_npcState[3].byte12 = 0;
+	}
+}
+
+
+// FIXME: remove this
+uint16 UINT_39e5_0be6 = 0;
+
+static const int16 BOSS_2_PAGE_OFFSETS[] = { 2, 2, 0xe, 0x1b, 0x21, 0x2a, 0x34, 0x3b };
+
+void DragonArcade::updateBoss2() {
+	if (_arcadeNotMovingLeftFlag && 269 < _scrollXOffset + _npcState[0].x / 8 && _scrollXOffset < 282) {
+		_int0b5c = 1;
+		_scrollXOffset++;
+		_npcState[0].x -= 8;
+	}
+	
+	if (_bladeState1 == 5) {
+		return;
+	}
+	
+	int distToBoss = _npcState[1].x - _npcState[0].x;
+	int absDistToBoss = abs(distToBoss);
+	
+	switch (_npcState[1].byte12 - 1) {
+	case 0:
+		if (_npcState[1].x - _npcState[0].x < 1) {
+			UINT_39e5_0be6 = 0;
+		} else {
+			UINT_39e5_0be6 = 31;
+		}
+		if ((_nextRandomVal & 0xfU) == 0xf) {
+			if (abs(_npcState[1].y - _npcState[0].y) > 35)
+				return;
+			
+			_npcState[1].byte12 = 4;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 9;
+		}
+		if ((_nextRandomVal & 0xfU) == 7 && absDistToBoss > 20 && _npcState[1].val1 < 0x938) {
+			_npcState[1].byte12 = 2;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 2;
+		}
+		else if (_bladeHasFired == 0 || _npcState[1].val1 < 0x939) {
+			if (absDistToBoss < 0x1e) {
+				arcade34b4();
+			}
+		}
+		else {
+			_npcState[1].byte12 = 6;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 13;
+		}
+		break;
+	case 4:
+		if (_npcState[1].ttmPage < (UINT_39e5_0be6 + 0x1f)) {
+			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		}
+		break;
+	case 3:
+		if (_npcState[1].ttmPage < (UINT_39e5_0be6 + 12)) {
+			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		} else {
+			_npcState[1].byte12 = 1;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 1;
+		}
+		break;
+	case 1:
+		_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		if ((UINT_39e5_0be6 + 8) <= _npcState[1].ttmPage) {
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 2;
+		}
+		if (UINT_39e5_0be6 == 0) {
+			_npcState[1].val1 = _npcState[1].val1 + 8;
+		} else {
+			_npcState[1].val1 = _npcState[1].val1 - 8;
+		}
+		if (absDistToBoss < 0x1e) {
+			arcade34b4();
+		}
+		break;
+	case 5:
+		if (_npcState[1].ttmPage < (int)(UINT_39e5_0be6 + 20)) {
+			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		} else {
+			_npcState[1].byte12 = 7;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 21;
+		}
+		break;
+	case 6:
+		if (_npcState[1].ttmPage < (int)(UINT_39e5_0be6 + 24)) {
+			if (_nTickUpdates & 1) {
+				_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+				if (UINT_39e5_0be6 == 0) {
+					_npcState[1].val1 = _npcState[1].val1 + 6;
+				} else {
+					_npcState[1].val1 = _npcState[1].val1 + -6;
+				}
+			}
+		} else if (absDistToBoss < 40 || _npcState[1].val1 < 0x8d4) {
+			_npcState[1].byte12 = 8;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 25;
+		} else if (_nTickUpdates & 1) {
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 21;
+			if (UINT_39e5_0be6 == 0) {
+				_npcState[1].val1 = _npcState[1].val1 + 6;
+			} else {
+				_npcState[1].val1 = _npcState[1].val1 + -6;
+			}
+		}
+		break;
+	case 7:
+		if (_npcState[1].ttmPage < (int)(UINT_39e5_0be6 + 0x1b)) {
+			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		} else if (absDistToBoss < 40) {
+			arcade34b4();
+		} else {
+			_npcState[1].byte12 = 1;
+			_npcState[1].ttmPage = UINT_39e5_0be6 + 1;
+		}
+		break;
+	case 2:
+	default:
+		if (_stillLoadingScriptsMaybe != 0) {
+			if ((_int0b5c == -1 && _npcState[1].x < 0x96) || (_int0b5c == 1 && 160 < _npcState[1].x)) {
+				arcade1d57();
+			}
+			byte bossByte12 = _npcState[1].byte12;
+			// TODO: do these ever get changed?
+			const int16 INT_39e5_0be0 = 0x3A;
+			const int16 INT_39e5_0bda = 0x20;
+			if (bossByte12 == 100) {
+				int16 absRand;
+				if (_mouseButtonWentDown == 1) {
+					_mouseButtonWentDown = 0;
+					if (_npcState[1].health == 1) {
+						absRand = 6;
+					} else {
+						while (true) {
+							absRand = abs(_nextRandomVal % 4) + 4;
+							if (absRand != 6)
+								break;
+							_nextRandomVal = _getNextRandom();
+						}
+					}
+					if (absRand == 5 || absRand == 6 || absRand == 7) {
+						decBossHealthAndCheck();
+					}
+					_npcState[1].ttmPage = BOSS_2_PAGE_OFFSETS[absRand] + 65;
+					_npcState[1].byte12 = absRand + 100;
+				} else {
+					while (absRand = abs(_nextRandomVal % 16), absRand != 0 && absRand < 4) {
+						bool hitBlade = false;
+						if (_npcState[0].health <= _startDifficultyMaybe + 2) {
+							absRand = 3;
+							hitBlade = true;
+						}
+						if (absRand != 3)
+							hitBlade = true;
+
+						if (hitBlade) {
+							_npcState[1].ttmPage = BOSS_2_PAGE_OFFSETS[absRand] + 65;
+							_npcState[1].byte12 = absRand + 100;
+							for (int16 i = _startDifficultyMaybe + 2; i != 0; i--)
+								bladeTakeHit();
+							return;
+						}
+						_nextRandomVal = _getNextRandom();
+					}
+				}
+			} else if ((bossByte12 != 106 || INT_39e5_0be0 + 0x41 != _npcState[1].ttmPage) &&
+					   (bossByte12 != 103 || INT_39e5_0bda + 0x41 != _npcState[1].ttmPage)) {
+				error("TODO: Fix references to table at 0xb0c");
+				/*
+				if (*(int *)(bossByte12 * 2 + 0xb0c) + 0x41 == _npcState[1].ttmPage) {
+					_npcState[1].byte12 = 100;
+					_npcState[1].ttmPage = 67;
+				} else if (bossByte12 != 100 && _nTickUpdates & 1) {
+					_npcState[1].ttmPage++;
+				}
+				*/
+			}
+		}
+	}
+}
+
+void DragonArcade::arcade1d57() {
+	int16 lastScrollOffset = _scrollXOffset;
+	_scrollXOffset = CLIP(_scrollXOffset + _int0b5c, 0, 282);
+	if (lastScrollOffset != _scrollXOffset) {
+		_scrollXIncrement += _int0b5c;
+	}
+}
+
+void DragonArcade::arcade34b4() {
+	_npcState[0].ttmPage = -1;
+	if (_npcState[0].x < 150) {
+		_int0b5c = -1;
+	} else if (_npcState[0].x < 161) {
+		_int0b5c = 0;
+	} else {
+		_int0b5c = 1;
+	}
+
+	_arcadeNotMovingLeftFlag = -1;
+	// TODO: what is this?
+	// UINT_39e5_0a1f = 1;
+	_stillLoadingScriptsMaybe = 1;
+	_npcState[0].byte12 = -1;
+	_npcState[1].byte12 = 100;
+	_npcState[1].ttmPage = 67;
+	_npcState[1].val1 = _npcState[0].val1;
+	_npcState[1].byte14 = 2;
+}
+
+void DragonArcade::decBossHealth() {
+	if (_npcState[1].health) {
+		_npcState[1].health--;
+	}
+}
 
-	error("DragonArcade::doTickUpdate: finish me");
+void DragonArcade::decBossHealthAndCheck() {
+	if (_npcState[1].health) {
+		_npcState[1].health--;
+		if (!_npcState[1].health) {
+			// boss is dead!
+			if (_npcState[1].ttmPage < 0x20) {
+				_npcState[1].ttmPage = 0x1c;
+			} else {
+				_npcState[1].ttmPage = 0x3b;
+			}
+			_npcState[1].byte12 = 5;
+			setFinishCountdownIfLessThan0(20);
+		}
+	}
+}
 
-	return false;
+void DragonArcade::bladeTakeHit() {
+	if (_npcState[0].health) {
+		_npcState[0].health--;
+	}
+	
+	if (!_enemyHasSmallGun && _npcState[0].health) {
+		_npcState[0].health--;
+	}
+	
+	if (_npcState[0].health == 0) {
+		/* dead! */
+		playSfx(0x4b);
+		if ((_bladeState1 == 0 && _bladeStateOffset + 0x1c <= _npcState[0].ttmPage &&
+			 _npcState[0].ttmPage <= _bladeStateOffset + 0x23) || _bladeState1 == 4) {
+			_bladeState1 = 9;
+			_npcState[0].ttmPage = _bladeStateOffset + 0x67;
+		} else {
+			_bladeState1 = 8;
+			_npcState[0].ttmPage = _bladeStateOffset + 0x62;
+		}
+		setFinishCountdownIfLessThan0(15);
+		_npcState[0].byte14 = 0;
+		_mouseButtonWentDown = 0x80;
+	} else {
+		playSfx(0x29);
+	}
 }
 
+
 void DragonArcade::initIfNeeded() {
 	if (_initFinished)
 		return;
@@ -132,22 +1025,27 @@ void DragonArcade::initIfNeeded() {
 	redraw();
 }
 
+void DragonArcade::updateBladeWithInputs() {
+	if (_stillLoadingScriptsMaybe)
+		return;
+	
+	error("TODO: updateBladeWithInputs: Finish me");
+}
 
 void DragonArcade::resetStageState() {
 	clearAllNPCStates();
 	clearAllBulletStates();
 	_scrollXOffset = 0;
 	_nTickUpdates = 0;
-	//INT_39e5_0a34 = 0;
 	//BYTE_39e5_0a14 = 0;
 	//INT_39e5_3d18 = 0;
 	//UINT_39e5_0a17 = 0;
 	_shouldUpdateState = 0;
-	//INT_39e5_3fa8 = 0;
+	_arcadeNotMovingLeftFlag = 0;
 	_npcState[0].byte12 = 1;
 	_npcState[0].byte14 = 0;
 	_npcState[0].health = (4 - _startDifficultyMaybe) * 3 + 20;
-	_npcState[0].npcState = 3;
+	_npcState[0].ttmPage = 3;
 	_npcState[1].health = 0;
 	_lastDrawnBladeHealth = -1;
 	_lastDrawnBossHealth = -1;
@@ -155,11 +1053,127 @@ void DragonArcade::resetStageState() {
 	_mouseButtonWentDown = 0;
 	_bladeMoveFlag = kBladeMoveNone;
 	// TODO: Work out what those commented out variables are..
-	error("DragonArcade::resetStageState: TODO: Finish me.");
 }
 
+static const int STAGE_0_VAL1[] = {
+	0x191, 0x1BB, 0x1F5,
+	0x25B, 0x2D3, 0x341,
+	0x535, 0x5C9, 0x623
+};
+
+static const byte STAGE_0_VAL2[] = {
+	0, 0, 0, 0xd8, 0xd8, 0, 0, 0, 0xd8
+};
+
+static const byte STAGE_0_BYTE12[] = {
+	5, 4, 4, 5, 4, 5, 4, 5, 5
+};
+
+static const int STAGE_4_VAL1[] = {
+	0x169, 0x19D, 0x1B9,
+	0x30D, 0x32D, 0x457,
+	0x4DB, 0x501, -1
+};
+
+static const byte STAGE_4_VAL2[] = {
+	0, 0, 0, 0, 0, 0xd8, 0, 0, 0xd8
+};
+
+static const byte STAGE_4_BYTE12[] = {
+	5, 4, 4, 5, 4, 5, 5, 4, 5
+};
+
 void DragonArcade::initValuesForStage() {
-	error("DragonArcade::initValuesForStage: TODO: Implement me.");
+	for (int i = 9; i != 0; i--)
+		_npcState[i].byte12 = 0;
+
+	switch (_loadedArcadeStage) {
+	case 0:
+		for (int i = 1; i < 10; i++) {
+			_npcState->val1 = STAGE_0_VAL1[i - 1];
+			_npcState->val2 = STAGE_0_VAL2[i - 1];
+			_npcState->byte12 = STAGE_0_BYTE12[i - 1];
+			if (_npcState->byte12 == 5)
+				_npcState->ttmPage = 39;
+			else
+				_npcState->ttmPage = 30;
+			initValuesForStage0();
+		}
+		break;
+	case 3:
+		initValuesForStage3();
+		break;
+	case 4:
+		for (int i = 1; i < 10; i++) {
+			_npcState->val1 = STAGE_4_VAL1[i - 1];
+			_npcState->val2 = STAGE_4_VAL2[i - 1];
+			_npcState->byte12 = STAGE_4_BYTE12[i - 1];
+			if (_npcState->byte12 == 5)
+				_npcState->ttmPage = 39;
+			else
+				_npcState->ttmPage = 30;
+		}
+		initValuesForStage4();
+		break;
+	case 6:
+		initValuesForStage6();
+		break;
+	default:
+		break;
+	}
+}
+
+void DragonArcade::initValuesForStage0() {
+	_someCounter40f0 = 0;
+	for (int i = 0; i < 4; i++) {
+
+	}
+	_flag40ee = true;
+	_flag40ef = true;
+	/*
+	INT_39e5_3f6c = 0x11f;
+	INT_39e5_3f6e = -0xd;
+	BYTE_39e5_3f7e = 0x1e;
+	INT_39e5_3f7c = 0x20;
+	BYTE_39e5_3f81 = 2;
+	*/
+	error("TODO: initValuesForStage0 Implement me");
+}
+
+void DragonArcade::initValuesForStage3() {
+	clearAllNPCStates();
+	_bossStateUpdateCounter = 0;
+	_npcState[1].val1 = 0x99c;
+	_npcState[1].val2 = -54;
+	_npcState[1].byte12 = 1;
+	_npcState[1].ttmPage = 2;
+	_npcState[1].health = 20;
+	_npcState[1].byte14 = 1;
+	_npcState[1].y = 300;
+	_npcState[2].val1 = 0x9b2;
+	_npcState[2].val2 = -57;
+	_npcState[2].byte12 = -1;
+	_npcState[2].ttmPage = 23;
+	_npcState[2].health = 0;
+	_npcState[2].byte14 = 1;
+}
+
+void DragonArcade::initValuesForStage4() {
+	_someCounter40f0 = 0;
+	for (int i = 0; i < 5; i++) {
+	}
+	error("TODO: initValuesForStage4 Implement me");
+}
+
+void DragonArcade::initValuesForStage6() {
+	clearAllNPCStates();
+	_npcState[1].val1 = 0x9e2;
+	_npcState[1].val2 = -3;
+	_npcState[1].ttmPage = 1;
+	_npcState[1].health = 10;
+	_npcState[1].byte14 = 1;
+	_npcState[1].byte12 = 1;
+	_stillLoadingScriptsMaybe = false;
 }
 
 void DragonArcade::setFinishCountdownIfLessThan0(int16 val) {
@@ -359,7 +1373,7 @@ void DragonArcade::checkToOpenMenu() {
 void DragonArcade::clearAllNPCStates() {
 	for (uint i = 1; i < ARRAYSIZE(_npcState); i++) {
 		_npcState[i].byte12 = 0;
-		_npcState[i].npcState = -1;
+		_npcState[i].ttmPage = -1;
 	}
 }
 
@@ -396,13 +1410,13 @@ void DragonArcade::bladeTakeHitAndCheck() {
 		_bladeHealth--;
 	if (_bladeHealth <= 0) {
 		playSfx(75);
-		if ((_bladeState1 == 0 && _bladeStateOffset + 28 < _npcState[0].npcState && _npcState[0].npcState <= 35)
+		if ((_bladeState1 == 0 && _bladeStateOffset + 28 < _npcState[0].ttmPage && _npcState[0].ttmPage <= 35)
 			|| _bladeState1 == 4) {
 			_bladeState1 = 9;
-			_npcState[0].npcState = _bladeState1 + 103;
+			_npcState[0].ttmPage = _bladeState1 + 103;
 		} else {
 			_bladeState1 = 8;
-			_npcState[0].npcState = _bladeState1 + 98;
+			_npcState[0].ttmPage = _bladeState1 + 98;
 		}
 		setFinishCountdownIfLessThan0(15);
 		_npcState[0].byte14 = 0;
@@ -456,7 +1470,11 @@ void DragonArcade::redraw() {
 	g_system->warpMouse(166, 158);
 }
 
+
 void DragonArcade::runThenDrawBulletsInFlight() {
+	// TODO: Set clip window here? 8,8,124,311
+	_arcadeTTM.runPagesForEachNPC(_scrollXOffset);
+
 	const Common::Rect screenWin(SCREEN_WIDTH, SCREEN_HEIGHT);
 	_arcadeTTM._currentTTMNum = _npcState[0].byte14;
 	_npcState[0].x_11 = 0;
@@ -471,7 +1489,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 	_arcadeTTM._drawYOffset = _arcadeTTM._startYOffset;
 	_arcadeTTM._currentNPCRunningTTM = 0;
 	if (-1 < _npcState[0].byte12) {
-		_arcadeTTM.runNextPage(_npcState[0].npcState);
+		_arcadeTTM.runNextPage(_npcState[0].ttmPage);
 	}
 
 	for (int i = 0; i < ARRAYSIZE(_bullets); i++) {
@@ -493,7 +1511,6 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 		}
 	}
 
-	error("DragonArcade::runThenDrawBulletsInFlight: TODO: implement the first half here.");
 }
 
 } // end namespace Dgds
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index cbd13f26da0..96915b83224 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -51,7 +51,7 @@ struct ArcadeNPCState {
     int16 y_11;
     int16 x_12;
     int16 y_12;
-    int16 npcState;
+    int16 ttmPage;
     int8 byte12;
     int8 byte13;
     int8 health;
@@ -105,7 +105,35 @@ private:
 	bool doTickUpdate();
 	void resetStageState();
 	void initValuesForStage();
+	void initValuesForStage0();
+	void initValuesForStage3();
+	void initValuesForStage4();
+	void initValuesForStage6();
 	void setFinishCountdownIfLessThan0(int16 val);
+	void updateBladeWithInputs();
+	void updateBlade();
+	void updateBoss();
+	void updateBoss2();
+	void decBossHealth();
+	void decBossHealthAndCheck();
+	void bladeTakeHit();
+	void arcade1d57();
+	void arcade2754(int16 findResult);
+	void arcade3e96();
+	void arcade4085();
+	void arcade34b4();
+	bool isNpcInsideXRange(int16 num);
+	void updateBullets();
+	void checkBladeFireAllStages();
+	void checkEnemyFireStage0124();
+	void checkBossFireStage3();
+	void checkBossFireStage6();
+	void updateMouseAndJoystickStates();
+	int16 findValuesIn3d30Array();
+	int16 checkBulletCollision(int16 num);
+	void mouseUpdate();
+	void keyboardUpdate();
+	void limitToCenterOfScreenAndUpdateCursor();
 
 	int16 _bladeHealth;
 	int16 _bossHealth;
@@ -122,8 +150,19 @@ private:
 	int16 _bladeStateOffset;
 	uint16 _mouseButtonWentDown;
 	int16 _scrollXOffset;
-	int16 _nTickUpdates;
+	int32 _nTickUpdates;
 	int16 _startDifficultyMaybe;
+	int16 _bossStateUpdateCounter;
+	int16 _someCounter40f0;
+	int16 _int0b5c;
+	int16 _scrollXIncrement;
+	int16 _lMouseButtonState;
+	int16 _rMouseButtonState;
+	int16 _lastLMouseButtonState;
+	int16 _lastRMouseButtonState;
+	int16 _bladeXMove;
+	int16 _bladeHorizMoveAttempt;
+	int16 _currentArrowNum;
 	bool _haveBigGun;
 	bool _haveBomb;
 	bool _enemyHasSmallGun;
@@ -131,7 +170,15 @@ private:
 	bool _arcadeNeedsBufferCopy;
 	bool _flagInventoryOpened;
 	bool _initFinished;
+	bool _stillLoadingScriptsMaybe;
+	bool _flag40ee;
+	bool _flag40ef;
+	int16 _arcadeNotMovingLeftFlag;
+	bool _bladeHasFired;
+	bool _mouseIsAvailable;
 	DragonBladeMoveFlag _bladeMoveFlag;
+	DragonBladeMoveFlag _keyStateFlags;
+	DragonBladeMoveFlag _bladeMoveFlagBeforeRButton;
 	DragonArcadeBullet _bullets[20];
 	ArcadeNPCState _npcState[10];
 	Common::SharedPtr<Image> _bulletImg;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index 3870fc4ddda..e997190c6cf 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -29,7 +29,12 @@
 
 namespace Dgds {
 
-DragonArcadeTTM::DragonArcadeTTM(ArcadeNPCState *npcState) : _npcState(npcState) {
+DragonArcadeTTM::DragonArcadeTTM(ArcadeNPCState *npcState) : _npcState(npcState),
+_currentTTMNum(0), _currentNPCRunningTTM(0), _drawXOffset(0), _drawYOffset(0),
+_startYOffset(0), _doingInit(false), _drawColBG(0), _drawColFG(0)
+{
+	ARRAYCLEAR(_shapes3);
+	ARRAYCLEAR(_brushes);
 }
 
 void DragonArcadeTTM::clearDataPtrs() {
@@ -283,6 +288,29 @@ int16 DragonArcadeTTM::runScriptPage(int16 pageNum) {
 
 }
 
+void DragonArcadeTTM::runPagesForEachNPC(int16 xScrollOffset) {
+	for (_currentNPCRunningTTM = 19; _currentNPCRunningTTM > 0; _currentNPCRunningTTM--) {
+		ArcadeNPCState &npcState = _npcState[_currentNPCRunningTTM];
+		if (npcState.byte12) {
+			npcState.x_21 = 0;
+			npcState.x_11 = 0;
+			npcState.x_22 = 0;
+			npcState.x_12 = 0;
+			npcState.y_21 = 0;
+			npcState.y_11 = 0;
+			npcState.y_22 = 0;
+			npcState.y_12 = 0;
+			 _drawXOffset = npcState.val1 - xScrollOffset * 8 - 152;
+			 _drawYOffset = npcState.val2;
+			_currentTTMNum = npcState.byte14;
+			if (_drawXOffset > -20 || _drawXOffset < 340) {
+				runNextPage(npcState.ttmPage);
+			}
+		}
+	}
+}
+
+
 void DragonArcadeTTM::freePages(uint16 num) {
 	delete _ttmEnvs[num].scr;
 	_ttmEnvs[num] = TTMEnviro();
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
index bd2809f57c7..60acf34dd78 100644
--- a/engines/dgds/dragon_arcade_ttm.h
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -31,6 +31,7 @@
 namespace Dgds {
 
 struct ArcadeLevelData {
+	ArcadeLevelData() : x(0), y(0), data(0), flag(false) {}
 	int16 x;
 	int16 y;
 	byte data;
@@ -50,6 +51,7 @@ public:
 	int16 runNextPage(int16 pageNum);
 	void freePages(uint16 num);
 	void freeShapes();
+	void runPagesForEachNPC(int16 xScrollOffset);
 
 	uint16 _currentTTMNum;
 	int16 _currentNPCRunningTTM;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index dec74f8ba5e..73db1aada12 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -933,7 +933,7 @@ bool Scene::checkConditions(const Common::Array<SceneConditions> &conds) const {
 bool SDSScene::_dlgWithFlagLo8IsClosing = false;
 DialogFlags SDSScene::_sceneDialogFlags = kDlgFlagNone;
 
-SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false), _ignoreMouseUp(false), _field6_0x14(0), _rbuttonDown(false) {
+SDSScene::SDSScene() : _num(-1), _dragItem(nullptr), _shouldClearDlg(false), _ignoreMouseUp(false), _field6_0x14(0), _rbuttonDown(false), _lbuttonDown(false) {
 }
 
 bool SDSScene::load(const Common::String &filename, ResourceManager *resourceManager, Decompressor *decompressor) {
@@ -1676,6 +1676,7 @@ void SDSScene::mouseMoved(const Common::Point &pt) {
 }
 
 void SDSScene::mouseLDown(const Common::Point &pt) {
+	_lbuttonDown = true;
 	if (hasVisibleDialog()) {
 		debug(9, "Mouse LDown on at %d,%d clearing visible dialog", pt.x, pt.y);
 		_shouldClearDlg = true;
@@ -1716,6 +1717,7 @@ static const ObjectInteraction * _findInteraction(const Common::Array<ObjectInte
 }
 
 void SDSScene::mouseLUp(const Common::Point &pt) {
+	_lbuttonDown = false;
 	if (_ignoreMouseUp) {
 		debug(9, "Ignoring mouseup at %d,%d as it was used to clear a dialog", pt.x, pt.y);
 		_ignoreMouseUp = false;
diff --git a/engines/dgds/scene.h b/engines/dgds/scene.h
index 07ce4ec0449..4da130d1adf 100644
--- a/engines/dgds/scene.h
+++ b/engines/dgds/scene.h
@@ -470,6 +470,8 @@ public:
 	void nextChoice();
 	void activateChoice();
 	bool isTriggerEnabled(uint16 num);
+	bool isLButtonDown() const { return _lbuttonDown; }
+	bool isRButtonDown() const { return _rbuttonDown; }
 
 protected:
 	HotArea *findAreaUnderMouse(const Common::Point &pt);
@@ -506,6 +508,7 @@ private:
 	GameItem *_dragItem;
 	bool _shouldClearDlg;
 	bool _ignoreMouseUp;
+	bool _lbuttonDown;
 	bool _rbuttonDown;
 
 	static bool _dlgWithFlagLo8IsClosing;


Commit: e131bbbe557446297ee19241832c8faddbe6a8f2
    https://github.com/scummvm/scummvm/commit/e131bbbe557446297ee19241832c8faddbe6a8f2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Even more dragon arcade code

Changed paths:
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.h


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index aaa1e5a450b..587e3a755ac 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -80,7 +80,7 @@ bool DragonArcade::doTickUpdate() {
 
 	int16 findResult = findValuesIn3d30Array();
 	arcade2754(findResult);
-	
+
 	switch (_loadedArcadeStage) {
 	case 0:
 	case 1:
@@ -103,41 +103,41 @@ bool DragonArcade::doTickUpdate() {
 		break;
 	}
 
-    updateBullets();
-    //setSomeVideoFlags();
-    runThenDrawBulletsInFlight();
-    checkBladeFireAllStages();
+	updateBullets();
+	//setSomeVideoFlags();
+	runThenDrawBulletsInFlight();
+	checkBladeFireAllStages();
 	switch(_loadedArcadeStage) {
-      case 0:
-      case 1:
-      case 2:
-      case 4:
-        checkEnemyFireStage0124();
-        break;
-      case 3:
-        checkBossFireStage3();
-        break;
-      case 6:
-        checkBossFireStage6();
-        break;
-      default:
+	case 0:
+	case 1:
+	case 2:
+	case 4:
+		checkEnemyFireStage0124();
+		break;
+	case 3:
+		checkBossFireStage3();
+		break;
+	case 6:
+		checkBossFireStage6();
+		break;
+	default:
 		break;
-    }
-    drawHealthBars();
-    //do { } while (_arcadeTickDelay != 0);
-    //_arcadeTickDelay = 4;
-    _nTickUpdates++;
-    
+	}
+	drawHealthBars();
+	//do { } while (_arcadeTickDelay != 0);
+	//_arcadeTickDelay = 4;
+	_nTickUpdates++;
+
 	return true;
 }
 
 void DragonArcade::updateBullets() {
-	for (int i = 19; i > 0; i++) {
+	for (int i = 19; i > 0; i--) {
 		if (_bullets[i]._state == 2 || _bullets[i]._state == 3) {
 			_bullets[i]._state = kBulletInactive;
 			continue;
 		}
-		
+
 		if (_bullets[i]._state == kBulletFlying) {
 			if (_bullets[i]._var1 == 3) {
 				_bullets[i]._y += _bullets[i]._speed;
@@ -175,7 +175,116 @@ void DragonArcade::updateBullets() {
 }
 
 int16 DragonArcade::checkBulletCollision(int16 num) {
-	error("TODO: Implement me");
+	int yoff = 0;
+	for (int i = 19; i >= 0; i--) {
+		if (_npcState[i].byte12 <= 0)
+			continue;
+
+		if (_bullets[num]._var1 == 3) {
+			yoff = 7;
+		}
+		if (_bullets[num]._var1 != 1 || i == 0) {
+			if (_bullets[num]._x < _npcState[i].x_11 || _npcState[i].x_12 < _bullets[num]._x ||
+				_bullets[num]._y + yoff < _npcState[i].y_11 || _npcState[i].y_12 < _bullets[num]._y + yoff) {
+				if (_bullets[num]._x < _npcState[i].x_21 || _npcState[i].x_22 < _bullets[num]._x ||
+					_bullets[num]._y + yoff < _npcState[i].y_21 || _npcState[i].y_22 < _bullets[num]._y + yoff)
+					continue;
+				if (i == 0)
+					return -1;
+
+				if (_loadedArcadeStage == 3) {
+					if (_bullets[num]._var1 == 3)
+						continue;
+				} else {
+					if (_loadedArcadeStage == 4) {
+						if (_bullets[num]._var1 == 1 || _bullets[num]._var1 == 3)
+							continue;
+					} else if (_loadedArcadeStage != 6) {
+						return -1;
+					}
+				}
+
+				if (_bullets[num]._var1 != 2) {
+					return -1;
+				}
+			} else {
+				if (i == 0) {
+					bladeTakeHit();
+					if (_npcState[0].health != 0)
+						return 1;
+
+					if (_bullets[num]._var1 != 3) {
+						return 1;
+					}
+					_shouldUpdateState = 3;
+					return 1;
+				}
+
+				if (6 < _loadedArcadeStage) {
+					return 1;
+				}
+
+				switch (_loadedArcadeStage) {
+				case 0:
+				case 1:
+				case 2:
+				case 4:
+					if (_loadedArcadeStage == 4 || _npcState[i].byte12 < '\x1e') {
+						if (_bullets[num]._var1 != 1) {
+							playSfx(0x56);
+							_npcState[i].byte12 = 1;
+							if (_npcState[i].ttmPage < 0x1c) {
+								_npcState[i].ttmPage = 0x15;
+							} else {
+								_npcState[i].ttmPage = 0x31;
+							}
+							return 1;
+						}
+						break;
+					}
+					if (_npcState[i].byte12 == '\x1e') {
+						_flag40ee = 0;
+					} else {
+						_flag40ef = 0;
+					}
+					_npcState[i].byte12 = 0xf8;
+					_npcState[i].ttmPage = 0x21;
+					break;
+				case 3:
+					if (_bullets[num]._var1 != 3) {
+						if (_npcState[i].byte12 == 1) {
+							_npcState[i].byte12 = 7;
+							_npcState[i].ttmPage = 0x4b;
+						}
+						if (_haveBigGun) {
+							decBossHealth();
+						}
+						decBossHealth();
+						if (_npcState[i].health != 0) {
+							return 1;
+						}
+						_npcState[i].byte12 = 8;
+						_npcState[i].ttmPage = 0x4f;
+						setFinishCountdownIfLessThan0(0x78);
+						return 1;
+					}
+					break;
+				case 6:
+					if (_bullets[num]._var1 != 2) {
+						if (_haveBigGun) {
+							decBossHealthAndCheck();
+						}
+						decBossHealthAndCheck();
+						return 1;
+					}
+					break;
+				default:
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
 }
 
 
@@ -199,7 +308,7 @@ void DragonArcade::checkBladeFireAllStages() {
 	int16 yoff;
 	int16 sndno;
 	ImageFlipMode flipMode;
-	
+
 	_bladeHasFired = false;
 	if (_npcState[0].byte14 != 0)
 		return;
@@ -211,10 +320,10 @@ void DragonArcade::checkBladeFireAllStages() {
 			} else {
 				flipMode = kImageFlipV;
 			}
-			if (_haveBigGun == 0) {
-				yoff = FIRE_Y_OFFSETS_SMALL_GUN[i];
-			} else {
+			if (_haveBigGun) {
 				yoff = FIRE_Y_OFFSETS_BIG_GUN[i];
+			} else {
+				yoff = FIRE_Y_OFFSETS_SMALL_GUN[i];
 			}
 
 			createBullet(FIRE_X_OFFSETS[i] + _npcState[0].x - 0xa0,
@@ -234,7 +343,7 @@ void DragonArcade::checkBladeFireAllStages() {
 }
 
 
-static const int16 ENEMY_FIRE_ALLOWABLE_PAGES[] =  { 3, 0xC, 0x1F, 0x28 };
+static const int16 ENEMY_FIRE_ALLOWABLE_PAGES[] = { 3, 0xC, 0x1F, 0x28 };
 static const int16 ENEMY_FIRE_X_OFFSETS[] = { 0xB1, 0xB3, 0x77, 0x75, };
 static const int16 ENEMY_FIRE_Y_OFFSETS[] = { 0x4E, 0x56, 0x4D, 0x55,};
 
@@ -271,7 +380,7 @@ void DragonArcade::checkBossFireStage6() {
 		createBullet(_npcState[1].val1 - _scrollXOffset * 8 - 19,
 						_npcState[1].val2 + 86, flipMode, 2);
 		playSfx(0x24);
-  }
+	}
 }
 
 void DragonArcade::limitToCenterOfScreenAndUpdateCursor() {
@@ -280,19 +389,20 @@ void DragonArcade::limitToCenterOfScreenAndUpdateCursor() {
 	lastMouse.x = CLIP((int)lastMouse.x, 144, 190);
 	lastMouse.y = CLIP((int)lastMouse.y, 135, 180);
 	g_system->warpMouse(lastMouse.x, lastMouse.y);
-	
+
 	int16 arrowNum = (lastMouse.x - 144) / 16 + ((lastMouse.y - 136) / 16) * 3;
 
-    if (_currentArrowNum != arrowNum && arrowNum < 9) {
+	if (_currentArrowNum != arrowNum && arrowNum < 9) {
 		_currentArrowNum = arrowNum;
 		CursorMan.replaceCursor(*(_arrowImg->getSurface(arrowNum)->surfacePtr()), 0, 0, 0, 0);
-    }
-    //if (g_arcadeNeedsBufferCopy == 0) {
-    //  Arcade_MouseCursorDraw();
-    //}
+	}
+	//if (g_arcadeNeedsBufferCopy == 0) {
+	//  Arcade_MouseCursorDraw();
+	//}
 }
 
 void DragonArcade::keyboardUpdate() {
+	warning("TODO: Keyboard update");
 	// TODO: Keyboard update.
 }
 
@@ -369,35 +479,491 @@ void DragonArcade::updateMouseAndJoystickStates() {
 }
 
 int16 DragonArcade::findValuesIn3d30Array() {
-	error("DragonArcade::findValuesIn3d30Array: Implement me");
+	fill3d30ArrayFromLevelData();
+	if (_bladeState1 == 1 || _bladeState1 == 2) {
+		if ((_bladeStateOffset + 0x38 == _npcState[0].ttmPage) ||
+			(_bladeStateOffset + 0x16 == _npcState[0].ttmPage)) {
+			findMatchOrMinOrMax();
+		} else {
+			findMinIn3d30ArrayLast();
+			if (isAbsFoundValOver990()) {
+				_foundValueFrom3d30Array = -0x100;
+			}
+		}
+	} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
+		if ((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) {
+			findMatchIn3d30Array();
+			if (isAbsFoundValOver990()) {
+				findMinIn3d30ArrayFirst();
+				if (isAbsFoundValOver990()) {
+					findMaxIn3d30Array();
+					if (isAbsFoundValOver990()) {
+						_foundValueFrom3d30Array = -0x100;
+					}
+				}
+			}
+		} else {
+			/* Move up */
+			findMaxIn3d30Array();
+			if (isAbsFoundValOver990()) {
+				findMatchIn3d30Array();
+				if (isAbsFoundValOver990()) {
+					findMinIn3d30ArrayFirst();
+					if (isAbsFoundValOver990()) {
+						_foundValueFrom3d30Array = -0x100;
+					}
+				}
+			}
+		}
+	} else {
+		/* Move down */
+		findMinIn3d30ArrayFirst();
+		if (isAbsFoundValOver990()) {
+			findMatchIn3d30Array();
+			if (isAbsFoundValOver990()) {
+				findMaxIn3d30Array();
+				if (isAbsFoundValOver990()) {
+					_foundValueFrom3d30Array = -0x100;
+				}
+			}
+		}
+	}
+	return _foundValueFrom3d30Array;
 }
 
 bool DragonArcade::isNpcInsideXRange(int16 num) {
 	return _npcState[num].x < 321 && _npcState[num].x > 1;
 }
 
+void DragonArcade::arcade16bc() {
+	_bladeState1 = 5;
+	_npcState[0].ttmPage = _bladeStateOffset + 0x40;
+	_arcadeTTM._startYOffset++;
+	_int0b54 = _arcadeTTM._startYOffset;
+	_uint0a17++;
+}
+
+void DragonArcade::arcade1e83() {
+	_scrollXOffset -= _scrollXIncrement;
+	_npcState[0].x = _npcState[0].x - _bladeXMove;
+}
+
+void DragonArcade::arcade16de(int16 param) {
+	if (_bladeState1 == 2) {
+		_npcState[0].ttmPage = _bladeStateOffset + 0x39;
+	}
+	else {
+		_npcState[0].ttmPage = _bladeStateOffset + 0x17;
+	}
+	_npcState[0].byte14 = 0;
+	_arcadeTTM._startYOffset = param;
+	_uint0a17 = 0;
+	_bladeState1 = 0;
+	// TODO: What are these ?
+	_int3d18 = 0;
+	//INT_39e5_0b5a = 0xf;
+}
 
 void DragonArcade::arcade4085() {
-	error("DragonArcade::arcade4085: implement me");
+	for (int i = 0; i < 2; i = i + 1) {
+		if (_someCounter40f0 == 0x14) {
+			_somethingArray[i].val10 = 0;
+		}
+		_somethingArray[i].val10++;
+		if (_somethingArray[i].val10 < 1 || 0xe < _somethingArray[i].val10) {
+			_somethingArray[i].val12 = 0;
+		}
+		else {
+			if (_somethingArray[i].val10 == 1) {
+				if (isNpcInsideXRange(i + 10))
+					playSfx(0x1d);
+			}
+			_somethingArray[i].val12 = 0xfb;
+			if (_npcState[0].health && _somethingArray[i].val0 - 0x10 <= _npcState[0].val1 &&
+				_npcState[0].val1 <= _somethingArray[i].val0 + 0x37) {
+				bladeTakeHit();
+			}
+		}
+	}
+
+	if ((_someCounter40f0 & 3) == 0) {
+		_somethingArray[2].val10++;
+		_somethingArray[3].val10++;
+		if (0x1e < _somethingArray[2].val10) {
+			_somethingArray[2].val10 = 0xf;
+			_somethingArray[3].val10 = 0xf;
+		}
+	}
+
+	for (int i = 0; i < 2; i = i + 1) {
+		if (_somethingArray[i].val10 == 0x1d) {
+			if (isNpcInsideXRange(i + 0xc))
+				playSfx(0x59);
+			if (_npcState[0].health && _somethingArray[i].val2 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _somethingArray[i].val2 + 0x23) {
+				bladeTakeHit();
+				bladeTakeHit();
+			}
+		}
+	}
+
+	_somethingArray[4].val10++;
+	if (0x35 < _somethingArray[4].val10) {
+		if (isNpcInsideXRange(0xe))
+			playSfx(0x58);
+		_somethingArray[4].val10 = 0x28;
+	}
+	if (_npcState[0].health != 0 && ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone || _arcadeTTM._startYOffset < -6)
+		&& _somethingArray[4].val0 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _somethingArray[4].val0 + 0x23) {
+		bladeTakeHit();
+		bladeTakeHit();
+		if (_npcState[0].health == 0) {
+			/* blade dies! */
+			_npcState[0].byte14 = 2;
+			_npcState[0].ttmPage = 0x22;
+			_npcState[0].byte12 = 14;
+			_bladeState1 = 14;
+			_shouldUpdateState = 2;
+		}
+	}
+
+	_someCounter40f0++;
+	if (_someCounter40f0 == 0x3c) {
+		_someCounter40f0 = 0;
+	}
+}
+
+bool DragonArcade::isAbsFoundValOver990() {
+	return abs(_foundValueFrom3d30Array) > 990;
+}
+
+
+uint16 DragonArcade::moveToNextStage() {
+	int xblock = _scrollXOffset + _npcState[0].x / 8;
+
+	switch(_loadedArcadeStage) {
+	case 0:
+		if (0x31 < _scrollXOffset) {
+			_loadedArcadeStage = 1;
+		}
+		break;
+	case 1:
+		/* stage 1 */
+		if (!_isMovingStage && xblock == 0x80 && 0 < _int0b5c && _bladeState1 == 0) {
+			_scrollXOffset -= _int0b5c;
+			arcade2445();
+			return 1;
+		}
+
+		if (0x89 < xblock && xblock < 0x8d && 0x14 < _arcadeTTM._startYOffset &&
+			_arcadeTTM._startYOffset < 0x46 && _bladeStateOffset == 0) {
+			_scrollXOffset = 0x89 - _npcState[0].x / 8;
+			_arcadeTTM._startYOffset = -0xd;
+			playSFX55AndStuff();
+			_loadedArcadeStage = 2;
+			initValuesForStage2();
+			return 1;
+		}
+		break;
+	case 2:
+		/* stage 2 */
+		if ((!_isMovingStage && xblock == 0x90 && 0 < _int0b5c && _bladeState1 == 0) ||
+			(!_isMovingStage && xblock == 0xe9 && 0 < _int0b5c && _bladeState1 == 0)) {
+			_scrollXOffset -= _int0b5c;
+			arcade2445();
+			return 1;
+		}
+
+		if (0x99 < xblock && xblock < 0x9c && 0x14 < _arcadeTTM._startYOffset &&
+			  _arcadeTTM._startYOffset < 0x46 && _bladeStateOffset == 0) {
+			_scrollXOffset = 0x9a - _npcState[0].x / 8;
+			_arcadeTTM._startYOffset = -0xd;
+			playSFX55AndStuff();
+			return 1;
+		}
+
+		if (_scrollXOffset < 0x100) {
+			if (0xf3 < xblock && xblock < 0xf6 && 0x1e < _arcadeTTM._startYOffset &&
+				 _arcadeTTM._startYOffset < 0x3c && _bladeStateOffset == 0 && _startDifficultyMaybe != 3) {
+				_scrollXOffset = 0xf4 - _npcState[0].x / 8;
+				_arcadeTTM._startYOffset = -0x1a;
+				playSFX55AndStuff();
+				return 1;
+			}
+		} else if (_bladeState1 == 0) {
+			//Arcade_VidPtrs_SrcFront_DstBack();
+			//ResetFlagAt_48a0();
+			//SetFlagAt_48a0_andMaybeMouseUpdate();
+			loadTTMScriptsForStage(3);
+		}
+		break;
+	case 4:
+		/* stage 4 */
+		if (-2 < _arcadeTTM._startYOffset && 0x81 < _npcState[0].val1 && _npcState[0].val1 < 0xc9 && _npcState[0].health != 0) {
+			playSfx(0x57);
+			setFinishCountdownIfLessThan0(0x14);
+			if (_haveBigGun) {
+				_npcState[0].ttmPage = 0x3a;
+			} else {
+				_npcState[0].ttmPage = 0x36;
+			}
+			_bladeState1 = 0xd;
+			_mouseButtonWentDown = 0x80;
+			_npcState[0].byte12 = 13;
+			_npcState[0].health = 0;
+			_npcState[0].byte14 = 2;
+			return 1;
+		}
+
+		if (_scrollXOffset < 0x100) {
+			if (_isMovingStage == 0 && xblock == 0x54 && 0 < _int0b5c && _bladeState1 == 0) {
+				_scrollXOffset -= _int0b5c;
+				arcade2445();
+				return 1;
+			}
+		} else if (_bladeState1 == 0) {
+			//Arcade_VidPtrs_SrcFront_DstBack();
+			//SetFlagAt_48a0_andMaybeMouseUpdate();
+			//ResetFlagAt_48a0();
+			loadTTMScriptsForStage(6);
+		}
+		break;
+	case 6:
+		/* stage 6 */
+		if (_stillLoadingScriptsMaybe == 0 && _scrollXOffset < 0x100) {
+			_scrollXOffset = 0x100;
+			_npcState[0].x -= 8;
+			if (_npcState[0].x < 0) {
+				_npcState[0].x = 0;
+			}
+		} else if (0x11f < xblock && _arcadeNotMovingLeftFlag == 0) {
+			_arcadeNotMovingLeftFlag = 1;
+		}
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+void DragonArcade::playSFX55AndStuff() {
+	_isMovingStage = 0;
+	playSfx(0x55);
+	_bladeState1 = 7;
+	_uint0a17 = 0;
+	// TODO: What are thess?
+	_int3d18 = 0;
+	//INT_39e5_0b5a = 0xf;
+	_int0b5c = 0;
+	_npcState[0].ttmPage = _bladeStateOffset + 0x43;
+}
+
+
+void DragonArcade::fill3d30ArrayFromLevelData() {
+	_array3d30.clear();
+	_array3d1c.clear();
+	Common::Array<uint> offsets;
+	const Common::Array<ArcadeLevelData> &levelData = _arcadeTTM.getLevelData();
+
+	for (uint i = 0; i < levelData.size(); i++) {
+		if (levelData[i].x <= _npcState[0].val1 && _npcState[0].val1 <= levelData[i].x + levelData[i].y) {
+		_array3d30.push_back(levelData[i].data - 108);
+		_array3d1c.push_back(levelData[i].flag);
+		}
+	}
+}
+
+void DragonArcade::findMinIn3d30ArrayLast() {
+	_foundValueFrom3d30Array = 999;
+	for (uint i = 0; i < _array3d30.size(); i++) {
+		if (_int0b54 <= _array3d30[i] && _array3d30[i] < _foundValueFrom3d30Array) {
+			_foundValueFrom3d30Array = _array3d30[i];
+			_foundValueFrom3d1cArray = _array3d1c[i];
+		}
+	}
+}
+
+void DragonArcade::findMinIn3d30ArrayFirst() {
+	_foundValueFrom3d30Array = 999;
+	for (uint i = 0; i < _array3d30.size(); i++) {
+		if (_int0b54 < _array3d30[i] && _array3d30[i] < _foundValueFrom3d30Array) {
+			_foundValueFrom3d30Array = _array3d30[i];
+			_foundValueFrom3d1cArray = _array3d1c[i];
+		}
+	}
+}
+
+void DragonArcade::findMatchIn3d30Array() {
+	_foundValueFrom3d30Array = -999;
+	for (uint i = 0; i < _array3d30.size(); i++) {
+		if (_array3d30[i] == _int0b54) {
+			_foundValueFrom3d30Array = _array3d30[i];
+			_foundValueFrom3d1cArray = _array3d1c[i];
+		}
+	}
+}
+
+void DragonArcade::findMaxIn3d30Array() {
+	_foundValueFrom3d30Array = -999;
+	for (uint i = 0; i < _array3d30.size(); i++) {
+		if (_array3d30[i] < _int0b54 && _foundValueFrom3d30Array < _array3d30[i]) {
+			_foundValueFrom3d30Array = _array3d30[i];
+			_foundValueFrom3d1cArray = _array3d1c[i];
+		}
+	}
+}
+
+void DragonArcade::findMatchOrMinOrMax() {
+	findMatchIn3d30Array();
+	if (isAbsFoundValOver990()) {
+		findMinIn3d30ArrayFirst();
+		if (isAbsFoundValOver990()) {
+			findMaxIn3d30Array();
+		}
+	}
+}
+
+
+void DragonArcade::arcade2445() {
+	_int0b5c = 0;
+	_bladeState1 = 6;
+	_npcState[0].ttmPage += 0x4e;
+	_isMovingStage = true;
+}
+
+static const int16 STAGE_2_VAL1[] = {
+	0x6A3, 0x6CD, 0x7C3
+};
+
+static const int16 STAGE_2_VAL2[] = {
+	0, 0, 0xe9
+};
+
+static const byte STAGE_2_BYTE12[] = {
+	4, 5, 4
+};
+
+static const int16 STAGE_2_TTMPAGE[] = {
+	0x1E, 0x27, 0x1E
+};
+
+static const int16 STAGE_2_VAL1_PART2[] = {
+	0x547, 0x557, 0x567, 0x577
+};
+
+void DragonArcade::initValuesForStage2() {
+	for (int i = 7; i != 0; i--) {
+		_npcState[i].byte12 = 0;
+	}
+	for (int i = 3; i != 0; i--) {
+		_npcState[i].val1 = STAGE_2_VAL1[i - 1];
+		_npcState[i].val2 = STAGE_2_VAL2[i - 1];
+		_npcState[i].byte12 = STAGE_2_BYTE12[i - 1];
+		_npcState[i].ttmPage = STAGE_2_TTMPAGE[i - 1];
+		_npcState[i].byte14 = 1;
+	}
+	for (int i = 10; i < 14; i++) {
+		_npcState[i].val1 = STAGE_2_VAL1_PART2[i - 10];
+	}
+	/*
+	 TODO: What are these?
+	 INT_39e5_3f6c = 0x52f;
+	 INT_39e5_3f6e = -0xd;
+	 BYTE_39e5_3f7e = 0x1f;
+	 INT_39e5_3f7c = 0x20;
+	 BYTE_39e5_3f81 = 2;
+	 */
 }
 
 void DragonArcade::arcade2754(int16 findResult) {
-	error("DragonArcade::arcade2754: implement me");
+	if (0 < _finishCountdown) {
+		_finishCountdown--;
+	}
+	if (_finishCountdown == 0) {
+		if (_npcState[0].health == 0) {
+			if (_shouldUpdateState == 0) {
+				_shouldUpdateState = 1;
+			}
+		} else {
+			_shouldUpdateState = 0;
+		}
+	} else {
+		_flag3d14 = 0;
+		if (100 < _arcadeTTM._startYOffset) {
+			_npcState[0].health = 0;
+			if (_finishCountdown < 1) {
+				setFinishCountdownIfLessThan0(20);
+			} else {
+				_arcadeTTM._startYOffset = 100;
+			}
+		}
+		if (!moveToNextStage()) {
+			if (findResult < _arcadeTTM._startYOffset && _int0b54 <= findResult) {
+				arcade16de(findResult);
+			} else if (_2754Val < _arcadeTTM._startYOffset && _int0b54 <= _2754Val) {
+				arcade1e83();
+				findResult = _2754Val;
+				arcade16de(_2754Val);
+			} else if (_bladeState1 == 0) {
+				if (findResult == -0x100) {
+					arcade16bc();
+				} else if (_2754Val != -0x100) {
+					if (abs(_2754Val - findResult) < 16 || _nTickUpdates == 0) {
+						_arcadeTTM._startYOffset = findResult;
+					} else if (findResult < _2754Val) {
+						findMatchIn3d30Array();
+						if (((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) ||
+							(_2754Val != _foundValueFrom3d30Array)) {
+							findMinIn3d30ArrayFirst();
+							if (!isAbsFoundValOver990()) {
+								_arcadeTTM._startYOffset = _foundValueFrom3d30Array;
+								findResult = _foundValueFrom3d30Array;
+							} else {
+								arcade16bc();
+							}
+						} else {
+							_arcadeTTM._startYOffset = _2754Val;
+							findResult = _2754Val;
+						}
+					} else if (_2754Val < findResult) {
+						if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
+							if (_arcadeTTM._startYOffset + 0x14 < findResult) {
+								_bladeState1 = 1;
+								_npcState[0].ttmPage = _bladeStateOffset + 0x16;
+								_arcadeTTM._startYOffset += 10;
+								_uint0a17++;
+							} else {
+								_arcadeTTM._startYOffset = findResult;
+							}
+						} else {
+							findMatchOrMinOrMax();
+							_arcadeTTM._startYOffset = _foundValueFrom3d30Array;
+							findResult = _foundValueFrom3d30Array;
+						}
+					}
+				}
+			} else if ((_bladeState1 == 3 || _bladeState1 == 4) && 0x19 < abs(_2754Val - findResult) && _nTickUpdates) {
+				findResult = _2754Val;
+			}
+		}
+		_npcState[0].val1 = _scrollXOffset * 8 + _npcState[0].x;
+		_int0b54 = _arcadeTTM._startYOffset;
+		_2754Val = findResult;
+	}
 }
 
 
 static const int16 arrayC5A[4][7] {
-    { 0x8, 0x19, 0x5A, 0x78, 0x8C, 0xA5, 0xBE },
-    { 0x6, 0x28, 0x5A, 0x87, 0x96, 0xAA, 0xC0 },
-    { 0x4, 0x37, 0x69, 0x79, 0x91, 0xA0, 0xC2 },
-    { 0x2, 0x46, 0x69, 0x87, 0x9B, 0xAF, 0xC4 },
+	{ 0x8, 0x19, 0x5A, 0x78, 0x8C, 0xA5, 0xBE },
+	{ 0x6, 0x28, 0x5A, 0x87, 0x96, 0xAA, 0xC0 },
+	{ 0x4, 0x37, 0x69, 0x79, 0x91, 0xA0, 0xC2 },
+	{ 0x2, 0x46, 0x69, 0x87, 0x9B, 0xAF, 0xC4 },
 };
 
 static const int16 arrayC92[4][7] {
 	{ 0xA, 0x37, 0x46, 0x55, 0x91, 0xAA, 0xC8 },
 	{ 0x19, 0x5F, 0x87, 0x9B, 0xB9, 0xD7, -0x1 },
 	{ 0x19, 0x23, 0x69, 0x7D, 0x9B, 0xB9, 0xD7 },
-	{ 0xA, 0x37, 0x46, 0x73,  0xAA, 0xC8,  -0x1 },
+	{ 0xA, 0x37, 0x46, 0x73, 0xAA, 0xC8, -0x1 },
 };
 
 
@@ -439,10 +1005,10 @@ void DragonArcade::arcade3e96() {
 				setFinishCountdownIfLessThan0(20);
 				_npcState[0].byte14 = 2;
 				_npcState[0].health = 0;
-				if (_haveBigGun == 0) {
-					_npcState[0].ttmPage = 0x22;
-				} else {
+				if (_haveBigGun) {
 					_npcState[0].ttmPage = 0x19;
+				} else {
+					_npcState[0].ttmPage = 0x22;
 				}
 				_npcState[0].byte12 = 12;
 				_bladeState1 = 0xc;
@@ -452,14 +1018,14 @@ void DragonArcade::arcade3e96() {
 	}
 	_someCounter40f0++;
 	if (_someCounter40f0 == 221) {
-        _someCounter40f0 = 0;
+		_someCounter40f0 = 0;
 	}
 
 }
 
 void DragonArcade::updateBlade() {
 	int16 local_6 = 0;
-	
+
 	for (int i = 9; i > 0; i--) {
 		if (_npcState[i].byte12 == 0)
 			continue;
@@ -469,7 +1035,7 @@ void DragonArcade::updateBlade() {
 		if (_npcState[i].byte13 == 0 &&
 			((startPage != 0 && _npcState[i].val1 < _npcState[0].val1) ||
 			 (startPage == 0 && _npcState[0].val1 < _npcState[i].val1))) {
-			
+
 			if (_npcState[i].byte12 == 4 || _npcState[i].byte12 == 5) {
 				if (_npcState[i].byte12 == 4) {
 					_npcState[i].byte13 = 5;
@@ -486,7 +1052,7 @@ void DragonArcade::updateBlade() {
 
 		if (local_6 != 0)
 			continue;
-		
+
 		switch (_npcState[i].byte12 - 1) {
 		case 5:
 			if ( _npcState[i].ttmPage < startPage + 11) {
@@ -665,8 +1231,7 @@ void DragonArcade::updateBoss() {
 	case 4:
 		if (_npcState[1].ttmPage < 37) {
 			_npcState[1].ttmPage++;
-			// TODO: does UINT_39e5_0a17 ever get modified? It's set 0 in resetStageState
-			if (bossIsClose && absDistToBoss < 50 && /*UINT_39e5_0a17 == 0 &&*/ 33 < _npcState[1].ttmPage && _npcState[1].ttmPage < 37) {
+			if (bossIsClose && absDistToBoss < 50 && _uint0a17 == 0 && 33 < _npcState[1].ttmPage && _npcState[1].ttmPage < 37) {
 				_npcState[0].byte12 = 10;
 				_bladeState1 = 10;
 				_npcState[0].ttmPage = 76;
@@ -704,9 +1269,6 @@ void DragonArcade::updateBoss() {
 }
 
 
-// FIXME: remove this
-uint16 UINT_39e5_0be6 = 0;
-
 static const int16 BOSS_2_PAGE_OFFSETS[] = { 2, 2, 0xe, 0x1b, 0x21, 0x2a, 0x34, 0x3b };
 
 void DragonArcade::updateBoss2() {
@@ -715,31 +1277,31 @@ void DragonArcade::updateBoss2() {
 		_scrollXOffset++;
 		_npcState[0].x -= 8;
 	}
-	
+
 	if (_bladeState1 == 5) {
 		return;
 	}
-	
+
 	int distToBoss = _npcState[1].x - _npcState[0].x;
 	int absDistToBoss = abs(distToBoss);
-	
+
 	switch (_npcState[1].byte12 - 1) {
 	case 0:
 		if (_npcState[1].x - _npcState[0].x < 1) {
-			UINT_39e5_0be6 = 0;
+			_uint0be6 = 0;
 		} else {
-			UINT_39e5_0be6 = 31;
+			_uint0be6 = 31;
 		}
 		if ((_nextRandomVal & 0xfU) == 0xf) {
 			if (abs(_npcState[1].y - _npcState[0].y) > 35)
 				return;
-			
+
 			_npcState[1].byte12 = 4;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 9;
+			_npcState[1].ttmPage = _uint0be6 + 9;
 		}
 		if ((_nextRandomVal & 0xfU) == 7 && absDistToBoss > 20 && _npcState[1].val1 < 0x938) {
 			_npcState[1].byte12 = 2;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 2;
+			_npcState[1].ttmPage = _uint0be6 + 2;
 		}
 		else if (_bladeHasFired == 0 || _npcState[1].val1 < 0x939) {
 			if (absDistToBoss < 0x1e) {
@@ -748,28 +1310,28 @@ void DragonArcade::updateBoss2() {
 		}
 		else {
 			_npcState[1].byte12 = 6;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 13;
+			_npcState[1].ttmPage = _uint0be6 + 13;
 		}
 		break;
 	case 4:
-		if (_npcState[1].ttmPage < (UINT_39e5_0be6 + 0x1f)) {
+		if (_npcState[1].ttmPage < (_uint0be6 + 0x1f)) {
 			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
 		}
 		break;
 	case 3:
-		if (_npcState[1].ttmPage < (UINT_39e5_0be6 + 12)) {
+		if (_npcState[1].ttmPage < (_uint0be6 + 12)) {
 			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
 		} else {
 			_npcState[1].byte12 = 1;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 1;
+			_npcState[1].ttmPage = _uint0be6 + 1;
 		}
 		break;
 	case 1:
 		_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
-		if ((UINT_39e5_0be6 + 8) <= _npcState[1].ttmPage) {
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 2;
+		if ((_uint0be6 + 8) <= _npcState[1].ttmPage) {
+			_npcState[1].ttmPage = _uint0be6 + 2;
 		}
-		if (UINT_39e5_0be6 == 0) {
+		if (_uint0be6 == 0) {
 			_npcState[1].val1 = _npcState[1].val1 + 8;
 		} else {
 			_npcState[1].val1 = _npcState[1].val1 - 8;
@@ -779,18 +1341,18 @@ void DragonArcade::updateBoss2() {
 		}
 		break;
 	case 5:
-		if (_npcState[1].ttmPage < (int)(UINT_39e5_0be6 + 20)) {
+		if (_npcState[1].ttmPage < (int)(_uint0be6 + 20)) {
 			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
 		} else {
 			_npcState[1].byte12 = 7;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 21;
+			_npcState[1].ttmPage = _uint0be6 + 21;
 		}
 		break;
 	case 6:
-		if (_npcState[1].ttmPage < (int)(UINT_39e5_0be6 + 24)) {
+		if (_npcState[1].ttmPage < (int)(_uint0be6 + 24)) {
 			if (_nTickUpdates & 1) {
 				_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
-				if (UINT_39e5_0be6 == 0) {
+				if (_uint0be6 == 0) {
 					_npcState[1].val1 = _npcState[1].val1 + 6;
 				} else {
 					_npcState[1].val1 = _npcState[1].val1 + -6;
@@ -798,10 +1360,10 @@ void DragonArcade::updateBoss2() {
 			}
 		} else if (absDistToBoss < 40 || _npcState[1].val1 < 0x8d4) {
 			_npcState[1].byte12 = 8;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 25;
+			_npcState[1].ttmPage = _uint0be6 + 25;
 		} else if (_nTickUpdates & 1) {
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 21;
-			if (UINT_39e5_0be6 == 0) {
+			_npcState[1].ttmPage = _uint0be6 + 21;
+			if (_uint0be6 == 0) {
 				_npcState[1].val1 = _npcState[1].val1 + 6;
 			} else {
 				_npcState[1].val1 = _npcState[1].val1 + -6;
@@ -809,20 +1371,20 @@ void DragonArcade::updateBoss2() {
 		}
 		break;
 	case 7:
-		if (_npcState[1].ttmPage < (int)(UINT_39e5_0be6 + 0x1b)) {
+		if (_npcState[1].ttmPage < (int)(_uint0be6 + 0x1b)) {
 			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
 		} else if (absDistToBoss < 40) {
 			arcade34b4();
 		} else {
 			_npcState[1].byte12 = 1;
-			_npcState[1].ttmPage = UINT_39e5_0be6 + 1;
+			_npcState[1].ttmPage = _uint0be6 + 1;
 		}
 		break;
 	case 2:
 	default:
 		if (_stillLoadingScriptsMaybe != 0) {
 			if ((_int0b5c == -1 && _npcState[1].x < 0x96) || (_int0b5c == 1 && 160 < _npcState[1].x)) {
-				arcade1d57();
+				arcadeUpdateXScrollOffset();
 			}
 			byte bossByte12 = _npcState[1].byte12;
 			// TODO: do these ever get changed?
@@ -883,7 +1445,7 @@ void DragonArcade::updateBoss2() {
 	}
 }
 
-void DragonArcade::arcade1d57() {
+void DragonArcade::arcadeUpdateXScrollOffset() {
 	int16 lastScrollOffset = _scrollXOffset;
 	_scrollXOffset = CLIP(_scrollXOffset + _int0b5c, 0, 282);
 	if (lastScrollOffset != _scrollXOffset) {
@@ -938,11 +1500,11 @@ void DragonArcade::bladeTakeHit() {
 	if (_npcState[0].health) {
 		_npcState[0].health--;
 	}
-	
+
 	if (!_enemyHasSmallGun && _npcState[0].health) {
 		_npcState[0].health--;
 	}
-	
+
 	if (_npcState[0].health == 0) {
 		/* dead! */
 		playSfx(0x4b);
@@ -1028,18 +1590,250 @@ void DragonArcade::initIfNeeded() {
 void DragonArcade::updateBladeWithInputs() {
 	if (_stillLoadingScriptsMaybe)
 		return;
-	
-	error("TODO: updateBladeWithInputs: Finish me");
+
+	// TODO: What are these?
+	//if ((INT_39e5_0b5a != 0) && (INT_39e5_0b5a--, INT_39e5_0b5a == 0)) {
+	//	INT_39e5_0b58 = 0;
+	//}
+
+	if ((_bladeHorizMoveAttempt & 1) == 0) {
+		_bladeStateOffset = 0;
+	} else {
+		_bladeStateOffset = 0x7a;
+	}
+	if (_bladeState1 == 0) {
+		if (!_flag3d14) {
+			_npcState[0].ttmPage++;
+		}
+		handleMouseStates();
+		return;
+	}
+
+	int16 newPage = 0;
+
+	switch (_bladeState1 - 1) {
+	case 0:
+		if (_bladeStateOffset + 0x1a == _npcState[0].ttmPage) {
+			_npcState[0].ttmPage = _bladeStateOffset + 0x16;
+		}
+		newPage = _bladeStateOffset + 0x19;
+		break;
+	case 1:
+		if (_bladeStateOffset + 0x3e == _npcState[0].ttmPage) {
+			_npcState[0].ttmPage = _bladeStateOffset + 0x38;
+		}
+		newPage = _bladeStateOffset + 0x3d;
+		if ((_bladeStateOffset + 0x32 < _npcState[0].ttmPage) &&
+			(_npcState[0].ttmPage <= _bladeStateOffset + 0x38)) {
+			moveBladeX();
+		}
+		break;
+	case 2:
+		newPage = _bladeStateOffset + 0x7b;
+		break;
+	case 3:
+		newPage = _bladeStateOffset + 0x2c;
+		break;
+	case 4:
+		_npcState[0].ttmPage = _bladeStateOffset + 0x40;
+		moveBladeX();
+		newPage = 999;
+		break;
+	case 5:
+		newPage = _bladeStateOffset + 0x61;
+		break;
+	case 6:
+		newPage = _bladeStateOffset + 0x4d;
+		if (_bladeStateOffset == 0) {
+			_int0b5c = 1;
+		} else {
+			_int0b5c = -1;
+		}
+		if (newPage <= _npcState[0].ttmPage + 2 && _npcState[0].ttmPage <= newPage) {
+			_npcState[0].x = _npcState[0].x + 4;
+		}
+		break;
+	case 7:
+		if (_npcState[0].ttmPage + 1 <= _bladeStateOffset + 0x66) {
+			_npcState[0].ttmPage++;
+		} else {
+			_npcState[0].ttmPage = _bladeStateOffset + 0x66;
+		}
+		return;
+	case 8:
+		if (_npcState[0].ttmPage + 1 <= _bladeStateOffset + 0x6c) {
+			_npcState[0].ttmPage++;
+		} else {
+			_npcState[0].ttmPage = _bladeStateOffset + 0x6c;
+		}
+		return;
+	case 9:
+		if (_npcState[0].ttmPage < 0x4f) {
+			_npcState[0].ttmPage++;
+			_int0b5c = -1;
+			moveBladeX();
+		} else {
+			handleMouseStates();
+		}
+		return;
+	case 10:
+		if (_haveBigGun == 0) {
+			newPage = 0xe;
+		} else {
+			newPage = 0x19;
+		}
+		if (_npcState[0].ttmPage < newPage) {
+			_npcState[0].ttmPage++;
+		} else {
+			_npcState[3].val1 = _npcState[0].val1 + 0x16;
+			_npcState[3].val2 = -0x20;
+			_npcState[3].byte12 = -2;
+			_npcState[3].ttmPage = 0x21;
+			_npcState[3].byte14 = 2;
+			_npcState[3].health = 20;
+			_npcState[0].byte14 = 0;
+			handleMouseStates();
+		}
+		return;
+	case 11:
+		if (_haveBigGun == 0) {
+			newPage = 0x28;
+		} else {
+			newPage = 0x1f;
+		}
+		if (newPage < _npcState[0].ttmPage + 1) {
+			_npcState[0].ttmPage = newPage;
+		} else {
+			_npcState[0].ttmPage++;
+		}
+		return;
+	case 12:
+		if ((_nTickUpdates & 1) == 0) {
+			return;
+		}
+		_npcState[0].ttmPage = _npcState[0].ttmPage + 1;
+		if (_haveBigGun != 0) {
+			if (_npcState[0].ttmPage >= 0x3e)
+				_npcState[0].ttmPage = 0x3d;
+		} else {
+			if (_npcState[0].ttmPage >= 0x3a) {
+				_npcState[0].ttmPage = 0x39;
+			}
+		}
+		return;
+	case 13:
+		if ((_nTickUpdates & 1) == 0) {
+			return;
+		}
+		if (_npcState[0].ttmPage + 1 < 0x26) {
+			_npcState[0].ttmPage++;
+		} else {
+			_npcState[0].ttmPage = 0x22;
+		}
+		return;
+	default:
+		break;
+	}
+
+	if (!_flag3d14)
+		_npcState[0].ttmPage++;
+
+	if (newPage < _npcState[0].ttmPage) {
+		handleMouseStates();
+	} else if (_uint0a17 == 0) {
+		if (_bladeState1 == 1) {
+			if (_bladeStateOffset + 0x16 == _npcState[0].ttmPage) {
+				_int3d18 = _int0b58 * -4;
+				_uint0a17 = 1;
+			}
+		}
+		else if ((_bladeState1 == 2) &&
+				 (_bladeStateOffset + 0x38 == _npcState[0].ttmPage)) {
+			_int3d18 = _int0b58 * -4;
+			_uint0a17 = 1;
+		}
+	} else {
+		if (_mouseButtonWentDown == 1) {
+			_mouseButtonWentDown = 0;
+			if (_bladeState1 == 2) {
+				_npcState[0].ttmPage = _bladeStateOffset + 0x3f;
+			} else if (_bladeState1 == 1) {
+				_npcState[0].ttmPage = _bladeStateOffset + 0x1b;
+			}
+		}
+		if (_bladeState1 == 1 || _bladeState1 == 2 || _bladeState1 == 5) {
+			_int3d18 += 2;
+			_arcadeTTM._startYOffset += _int3d18;
+			_npcState[0].ttmPage--;
+		}
+	}
 }
 
+void DragonArcade::moveBladeX() {
+	if (_flag3d14)
+		return;
+
+	if (_arcadeNotMovingLeftFlag != 0)
+		return;
+
+	if (_int0b5c < 1) {
+		if (-1 < _int0b5c) {
+			// nothing
+		} else if (_scrollXOffset == 0) {
+			if (0 < _npcState[0].x)
+				_bladeXMove = -4;
+		} else if (0x104 < _npcState[0].x) {
+			_bladeXMove = -4;
+			_int0b60 = 0;
+		} else if (_npcState[0].x < 0xa0) {
+			_int0b60 = 1;
+			_bladeXMove = 4;
+			updateXScrollOffset();
+		} else if (_int0b60 == 1) {
+			updateXScrollOffset();
+			_bladeXMove = 4;
+		} else {
+			_bladeXMove = -4;
+			return;
+		}
+		_npcState[0].x += _bladeXMove;
+		return;
+	} else {
+		if (_scrollXOffset == 0x11a) {
+			if (_npcState[0].x < 0x140)
+				_bladeXMove = 4;
+
+		} else if (0xa0 < _npcState[0].x) {
+			_int0b60 = -1;
+			_bladeXMove = -4;
+			updateXScrollOffset();
+		} else if (_npcState[0].x < 0x3c) {
+			_int0b60 = 0;
+			_bladeXMove = 4;
+		} else if (_int0b60 != -1) {
+			_bladeXMove = 4;
+		} else {
+			updateXScrollOffset();
+			_bladeXMove = -4;
+			return;
+		}
+	}
+	_npcState[0].x += _bladeXMove;
+}
+
+void DragonArcade::handleMouseStates() {
+	error("TODO: handleMouseStates: Implement me");
+}
+
+
 void DragonArcade::resetStageState() {
 	clearAllNPCStates();
 	clearAllBulletStates();
 	_scrollXOffset = 0;
 	_nTickUpdates = 0;
-	//BYTE_39e5_0a14 = 0;
-	//INT_39e5_3d18 = 0;
-	//UINT_39e5_0a17 = 0;
+	_isMovingStage = false;
+	_int3d18 = 0;
+	_uint0a17 = 0;
 	_shouldUpdateState = 0;
 	_arcadeNotMovingLeftFlag = 0;
 	_npcState[0].byte12 = 1;
@@ -1052,7 +1846,6 @@ void DragonArcade::resetStageState() {
 	_bladeState1 = 0;
 	_mouseButtonWentDown = 0;
 	_bladeMoveFlag = kBladeMoveNone;
-	// TODO: Work out what those commented out variables are..
 }
 
 static const int STAGE_0_VAL1[] = {
@@ -1123,21 +1916,38 @@ void DragonArcade::initValuesForStage() {
 	}
 }
 
+static const int16 STAGE_0_ST_INT0[] = {
+	0x13F, 0x150, 0x161, 0x172
+};
+
+static const int16 STAGE_0_ST_INT0_2[] = {
+	0x317, 0x328, 0x339, 0x34A
+};
+
+static const int16 STAGE_0_ST_VAL10[] = {
+	 0, 0x1E, 0xF, 0
+};
+
 void DragonArcade::initValuesForStage0() {
 	_someCounter40f0 = 0;
 	for (int i = 0; i < 4; i++) {
-
+		_somethingArray[i].val0 = STAGE_0_ST_INT0[i];
+		_somethingArray[i].val2 = 2;
+		_somethingArray[i].val10 = STAGE_0_ST_VAL10[i];
+		_somethingArray[i].val15 = 2;
+
+		_somethingArray[i + 4].val0 = STAGE_0_ST_INT0_2[i];
+		_somethingArray[i + 4].val2 = -37;
+		_somethingArray[i + 4].val10 = STAGE_0_ST_VAL10[i];
+		_somethingArray[i + 4].val15 = 2;
 	}
 	_flag40ee = true;
 	_flag40ef = true;
-	/*
-	INT_39e5_3f6c = 0x11f;
-	INT_39e5_3f6e = -0xd;
-	BYTE_39e5_3f7e = 0x1e;
-	INT_39e5_3f7c = 0x20;
-	BYTE_39e5_3f81 = 2;
-	*/
-	error("TODO: initValuesForStage0 Implement me");
+	_somethingArray[8].val0 = 0x11f;
+	_somethingArray[8].val2 = -0xd;
+	_somethingArray[8].val12 = 0x1e;
+	_somethingArray[8].val10 = 0x20;
+	_somethingArray[8].val15 = 2;
 }
 
 void DragonArcade::initValuesForStage3() {
@@ -1158,11 +1968,32 @@ void DragonArcade::initValuesForStage3() {
 	_npcState[2].byte14 = 1;
 }
 
+static const int16 STAGE_4_ST_INT0[] = {
+	0x1F9, 0x551, 0x362, 0x592, 0x7AF
+};
+
+static const int16 STAGE_4_ST_INT2[] = {
+	8, 8, 6, 6, 6
+};
+
+static const int16 STAGE_4_ST_INT10[] = {
+	0, 0, 0xf, 0xf, 0x28
+};
+
+static const byte STAGE_4_ST_BYTE12[] = {
+	0, 0, 0xfa, 0xfa, 0xf9
+};
+
 void DragonArcade::initValuesForStage4() {
 	_someCounter40f0 = 0;
 	for (int i = 0; i < 5; i++) {
+		_somethingArray[i].val0 = STAGE_4_ST_INT0[i];
+		_somethingArray[i].val2 = STAGE_4_ST_INT2[i];
+		_somethingArray[i].val10 = STAGE_4_ST_INT10[i];
+		_somethingArray[i].val12 = STAGE_4_ST_BYTE12[i];
+		_somethingArray[i].val14 = 1;
+		_somethingArray[i].val15 = 2;
 	}
-	error("TODO: initValuesForStage4 Implement me");
 }
 
 void DragonArcade::initValuesForStage6() {
@@ -1217,26 +2048,26 @@ void DragonArcade::arcadeTick() {
 		globals->setArcadeState(30);
 		return;
 	case 30:
-        loadTTMScriptsForStage(_nextStage);
-        // These don't seem to ever be used?
-        // UINT_39e5_0d0e = 0;
-        // UINT_39e5_0d10 = 0;
-        globals->setArcadeState(5);
-        _arcadeNeedsBufferCopy = true;
-        _flagInventoryOpened = false;
-        return;
+		loadTTMScriptsForStage(_nextStage);
+		// These don't seem to ever be used?
+		// UINT_39e5_0d0e = 0;
+		// UINT_39e5_0d10 = 0;
+		globals->setArcadeState(5);
+		_arcadeNeedsBufferCopy = true;
+		_flagInventoryOpened = false;
+		return;
 	default:
 		_haveBomb = arcadeState > 20;
 		if (_haveBomb)
-		  globals->setArcadeState(arcadeState - 20);
+			globals->setArcadeState(arcadeState - 20);
 
 		_enemyHasSmallGun = arcadeState > 10;
 		if (_enemyHasSmallGun != 0)
-		  globals->setArcadeState(arcadeState - 10);
+			globals->setArcadeState(arcadeState - 10);
 
 		bool _haveBigGun = arcadeState > 2;
-		if (_haveBigGun != 0)
-		  globals->setArcadeState(arcadeState - 2);
+		if (_haveBigGun)
+			globals->setArcadeState(arcadeState - 2);
 
 		_nextStage = (arcadeState & 1) ? 4 : 0;
 
@@ -1250,7 +2081,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 	const char *ttm2;
 
 	switch(stage) {
-    case 0:
+	case 0:
 		resetStageState();
 		ttm1 = "STATIONA.TTM";
 		ttm2 = "FLAMDEAD.TTM";
@@ -1262,7 +2093,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		ttm1 = "DRAGON.TTM";
 		ttm2 = "GRENADE.TTM";
 		break;
-    case 4:
+	case 4:
 		resetStageState();
 		ttm1 = "STATIONA.TTM";
 		ttm2 = "AARC.TTM";
@@ -1270,7 +2101,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		_npcState[0].val1 = 140;
 		_arcadeTTM._startYOffset = -43;
 		break;
-    case 6:
+	case 6:
 		_arcadeTTM._currentNPCRunningTTM = 0;
 		_arcadeTTM.runNextPage(276);
 		ttm1 = "SNAKERUN.TTM";
@@ -1279,9 +2110,9 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		else
 			ttm2 = "LITFIGHT.TTM";
 		break;
-    default:
+	default:
 		return;
-    }
+	}
 
 	if (stage != _loadedArcadeStage) {
 		_currentArcadeTT3Num = 1;
@@ -1303,7 +2134,8 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		_arcadeTTM.finishTTMParse(envNum);
 		_arcadeTTM.runNextPage(0);
 	}
-	//INT_39e5_0b54 = _startYOffset;
+
+	_int0b54 = _arcadeTTM._startYOffset;
 	_finishCountdown = -1;
 	//INT_39e5_0be4 = 0; // this only ever gets set 0?
 	_loadedArcadeStage = stage;
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index 96915b83224..8c9cef558b7 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -43,25 +43,36 @@ enum DragonBladeMoveFlag {
 };
 
 struct ArcadeNPCState {
-    int16 val1;
-    int16 val2;
-    int16 x;
-    int16 y;
-    int16 x_11;
-    int16 y_11;
-    int16 x_12;
-    int16 y_12;
-    int16 ttmPage;
-    int8 byte12;
-    int8 byte13;
-    int8 health;
-    int8 byte14; /* Set to 0, 1 or 2 */
-    int16 x_21;
-    int16 y_21;
-    int16 x_22;
-    int16 y_22;
+	int16 val1;
+	int16 val2;
+	int16 x;
+	int16 y;
+	int16 x_11;
+	int16 y_11;
+	int16 x_12;
+	int16 y_12;
+	int16 ttmPage;
+	int8 byte12;
+	int8 byte13;
+	int8 health;
+	int8 byte14; /* Set to 0, 1 or 2 */
+	int16 x_21;
+	int16 y_21;
+	int16 x_22;
+	int16 y_22;
 };
 
+struct AracdeSomething {
+	int16 val0;
+	int16 val2;
+	byte unk4[12];
+	int16 val10;
+	byte val12;
+	byte unk13;
+	byte val14;
+	byte val15;
+	byte unk16[8];
+};
 
 class DragonArcadeBullet {
 public:
@@ -106,6 +117,7 @@ private:
 	void resetStageState();
 	void initValuesForStage();
 	void initValuesForStage0();
+	void initValuesForStage2();
 	void initValuesForStage3();
 	void initValuesForStage4();
 	void initValuesForStage6();
@@ -117,7 +129,11 @@ private:
 	void decBossHealth();
 	void decBossHealthAndCheck();
 	void bladeTakeHit();
-	void arcade1d57();
+	void arcade16bc();
+	void arcade16de(int16 param);
+	void arcadeUpdateXScrollOffset();
+	void arcade1e83();
+	void arcade2445();
 	void arcade2754(int16 findResult);
 	void arcade3e96();
 	void arcade4085();
@@ -134,6 +150,18 @@ private:
 	void mouseUpdate();
 	void keyboardUpdate();
 	void limitToCenterOfScreenAndUpdateCursor();
+	uint16 moveToNextStage();
+	void findMatchIn3d30Array();
+	void findMinIn3d30ArrayFirst();
+	void findMinIn3d30ArrayLast();
+	void findMatchOrMinOrMax();
+	void findMaxIn3d30Array();
+	void fill3d30ArrayFromLevelData();
+	bool isAbsFoundValOver990();
+	void playSFX55AndStuff();
+	void moveBladeX();
+	void handleMouseStates();
+	void updateXScrollOffset();
 
 	int16 _bladeHealth;
 	int16 _bossHealth;
@@ -155,6 +183,13 @@ private:
 	int16 _bossStateUpdateCounter;
 	int16 _someCounter40f0;
 	int16 _int0b5c;
+	uint16 _uint0a17;
+	int16 _int0b54;
+	int16 _int0b58;
+	int16 _int0b60;
+	int16 _int3d18;
+	uint16 _uint0be6;
+	bool _flag3d14;
 	int16 _scrollXIncrement;
 	int16 _lMouseButtonState;
 	int16 _rMouseButtonState;
@@ -163,6 +198,10 @@ private:
 	int16 _bladeXMove;
 	int16 _bladeHorizMoveAttempt;
 	int16 _currentArrowNum;
+	int16 _foundValueFrom3d30Array;
+	bool _foundValueFrom3d1cArray;
+	int16 _2754Val;
+
 	bool _haveBigGun;
 	bool _haveBomb;
 	bool _enemyHasSmallGun;
@@ -176,15 +215,19 @@ private:
 	int16 _arcadeNotMovingLeftFlag;
 	bool _bladeHasFired;
 	bool _mouseIsAvailable;
+	bool _isMovingStage;
 	DragonBladeMoveFlag _bladeMoveFlag;
 	DragonBladeMoveFlag _keyStateFlags;
 	DragonBladeMoveFlag _bladeMoveFlagBeforeRButton;
 	DragonArcadeBullet _bullets[20];
 	ArcadeNPCState _npcState[10];
+	AracdeSomething _somethingArray[9];
 	Common::SharedPtr<Image> _bulletImg;
 	Common::SharedPtr<Image> _arrowImg;
 	Common::SharedPtr<Image> _scrollImg;
 	DragonArcadeTTM _arcadeTTM;
+	Common::Array<int16> _array3d30;
+	Common::Array<bool> _array3d1c;
 };
 
 } // end namespace Dgds
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
index 60acf34dd78..7b5a9e4e51a 100644
--- a/engines/dgds/dragon_arcade_ttm.h
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -52,6 +52,7 @@ public:
 	void freePages(uint16 num);
 	void freeShapes();
 	void runPagesForEachNPC(int16 xScrollOffset);
+	const Common::Array<ArcadeLevelData> &getLevelData() { return _levelData; }
 
 	uint16 _currentTTMNum;
 	int16 _currentNPCRunningTTM;


Commit: 8f41c8d511aedc9539d663889bcaae419f7d9ddc
    https://github.com/scummvm/scummvm/commit/8f41c8d511aedc9539d663889bcaae419f7d9ddc
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Dragon arcade nearly complete

Code translation done, now just have to make it work

Changed paths:
    engines/dgds/dgds.cpp
    engines/dgds/dgds.h
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/scene.cpp


diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index a9762cc4a0f..f06ed4814b8 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -62,6 +62,7 @@
 #include "dgds/scripts.h"
 #include "dgds/sound.h"
 #include "dgds/game_palettes.h"
+#include "dgds/dragon_arcade.h"
 
 // for frame contents debugging
 //#define DUMP_FRAME_DATA 1
@@ -83,7 +84,8 @@ DgdsEngine::DgdsEngine(OSystem *syst, const ADGameDescription *gameDesc)
 	_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) {
+	_rstFileName(nullptr), _difficulty(1), _menu(nullptr), _adsInterp(nullptr), _isDemo(false),
+	_dragonArcade(nullptr) {
 	syncSoundSettings();
 
 	_platform = gameDesc->platform;
@@ -124,6 +126,7 @@ DgdsEngine::~DgdsEngine() {
 	delete _menu;
 	delete _inventory;
 	delete _shellGame;
+	delete _dragonArcade;
 
 	_icons.reset();
 	_corners.reset();
@@ -326,7 +329,9 @@ void DgdsEngine::init(bool restarting) {
 	_menu = new Menu();
 	_adsInterp = new ADSInterpreter(this);
 	_inventory = new Inventory();
-	if (_gameId == GID_HOC)
+	if (_gameId == GID_DRAGON)
+		_dragonArcade = new DragonArcade();
+	else if (_gameId == GID_HOC)
 		_shellGame = new ShellGame();
 
 	_backgroundBuffer.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index ae60cf04614..1fab810adc5 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -59,6 +59,7 @@ struct DgdsADS;
 class ADSInterpreter;
 class Globals;
 class ShellGame;
+class DragonArcade;
 
 const float MS_PER_FRAME = 16.6667f;
 
@@ -117,6 +118,9 @@ private:
 	Globals *_gameGlobals;
 	Inventory *_inventory;
 
+	// Dragon only
+	DragonArcade *_dragonArcade;
+
 	// HoC only
 	ShellGame *_shellGame;
 
@@ -218,6 +222,7 @@ public:
 	void setMenuToTrigger(MenuId menu) { _menuToTrigger = menu; }
 	bool isInvButtonVisible() const;
 	ShellGame *getShellGame() { return _shellGame; }
+	DragonArcade *getDragonArcade() { return _dragonArcade; }
 
 	static DgdsEngine *getInstance() { return static_cast<DgdsEngine *>(g_engine); }
 	void setFlipMode(bool mode) { _flipMode = mode; }
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 587e3a755ac..9a61ab23fe5 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -37,7 +37,19 @@
 
 namespace Dgds {
 
-DragonArcade::DragonArcade() : _arcadeTTM(_npcState) {
+DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(0),
+	_lastDrawnBossHealth(0), _nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _arcadeModeSomethingCounter(0),
+	_currentArcadeTT3Num(0), _shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladeStateOffset(0),
+	_mouseButtonWentDown(0), _scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0),
+	_someCounter40f0(0), _int0b5c(0), _uint0a17(0), _int0b54(0), _int0b58(0), _int0b5a(0), _int0b60(0), _int3d18(0),
+	_uint0be6(0), _flag3d14(0), _scrollXIncrement(0), _lMouseButtonState(0), _rMouseButtonState(0), _lastLMouseButtonState(0),
+	_lastRMouseButtonState(0), _bladeXMove(0), _bladeHorizMoveAttempt(0), _currentArrowNum(0), _foundValueFrom3d30Array(0),
+	_foundValueFrom3d1cArray(0), _2754Val(0), _arcadeNotMovingLeftFlag(0), _haveBigGun(true), _haveBomb(true),
+	_enemyHasSmallGun(false), _dontRedrawBgndAndWeapons(false), _arcadeNeedsBufferCopy(false), _flagInventoryOpened(false),
+	_initFinished(false), _stillLoadingScriptsMaybe(false), _flag40ee(false), _flag40ef(false), _bladeHasFired(false),
+	_mouseIsAvailable(false), _isMovingStage(false), _bladeMoveFlag(kBladeMoveNone), _keyStateFlags(kBladeMoveNone),
+	_bladeMoveFlagBeforeRButton(kBladeMoveNone)
+{
 }
 
 static uint _getNextRandom() {
@@ -310,7 +322,7 @@ void DragonArcade::checkBladeFireAllStages() {
 	ImageFlipMode flipMode;
 
 	_bladeHasFired = false;
-	if (_npcState[0].byte14 != 0)
+	if (_npcState[0].byte15 != 0)
 		return;
 
 	for (int i = 0; i < 8; i++) {
@@ -555,70 +567,70 @@ void DragonArcade::arcade16de(int16 param) {
 	else {
 		_npcState[0].ttmPage = _bladeStateOffset + 0x17;
 	}
-	_npcState[0].byte14 = 0;
+	_npcState[0].byte15 = 0;
 	_arcadeTTM._startYOffset = param;
 	_uint0a17 = 0;
 	_bladeState1 = 0;
 	// TODO: What are these ?
 	_int3d18 = 0;
-	//INT_39e5_0b5a = 0xf;
+	_int0b5a = 0xf;
 }
 
 void DragonArcade::arcade4085() {
-	for (int i = 0; i < 2; i = i + 1) {
+	for (int i = 10; i < 12; i++) {
 		if (_someCounter40f0 == 0x14) {
-			_somethingArray[i].val10 = 0;
+			_npcState[i].ttmPage = 0;
 		}
-		_somethingArray[i].val10++;
-		if (_somethingArray[i].val10 < 1 || 0xe < _somethingArray[i].val10) {
-			_somethingArray[i].val12 = 0;
+		_npcState[i].ttmPage++;
+		if (_npcState[i].ttmPage < 1 || 0xe < _npcState[i].ttmPage) {
+			_npcState[i].byte12 = 0;
 		}
 		else {
-			if (_somethingArray[i].val10 == 1) {
-				if (isNpcInsideXRange(i + 10))
+			if (_npcState[i].ttmPage == 1) {
+				if (isNpcInsideXRange(i))
 					playSfx(0x1d);
 			}
-			_somethingArray[i].val12 = 0xfb;
-			if (_npcState[0].health && _somethingArray[i].val0 - 0x10 <= _npcState[0].val1 &&
-				_npcState[0].val1 <= _somethingArray[i].val0 + 0x37) {
+			_npcState[i].byte12 = 0xfb;
+			if (_npcState[0].health && _npcState[i].val1 - 0x10 <= _npcState[0].val1 &&
+				_npcState[0].val1 <= _npcState[i].val1 + 0x37) {
 				bladeTakeHit();
 			}
 		}
 	}
 
 	if ((_someCounter40f0 & 3) == 0) {
-		_somethingArray[2].val10++;
-		_somethingArray[3].val10++;
-		if (0x1e < _somethingArray[2].val10) {
-			_somethingArray[2].val10 = 0xf;
-			_somethingArray[3].val10 = 0xf;
+		_npcState[12].ttmPage++;
+		_npcState[13].ttmPage++;
+		if (0x1e < _npcState[12].ttmPage) {
+			_npcState[12].ttmPage = 0xf;
+			_npcState[13].ttmPage = 0xf;
 		}
 	}
 
-	for (int i = 0; i < 2; i = i + 1) {
-		if (_somethingArray[i].val10 == 0x1d) {
-			if (isNpcInsideXRange(i + 0xc))
+	for (int i = 10; i < 12; i++) {
+		if (_npcState[i].ttmPage == 0x1d) {
+			if (isNpcInsideXRange(i + 2))
 				playSfx(0x59);
-			if (_npcState[0].health && _somethingArray[i].val2 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _somethingArray[i].val2 + 0x23) {
+			if (_npcState[0].health && _npcState[i].val2 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _npcState[i].val2 + 0x23) {
 				bladeTakeHit();
 				bladeTakeHit();
 			}
 		}
 	}
 
-	_somethingArray[4].val10++;
-	if (0x35 < _somethingArray[4].val10) {
+	_npcState[14].ttmPage++;
+	if (0x35 < _npcState[14].ttmPage) {
 		if (isNpcInsideXRange(0xe))
 			playSfx(0x58);
-		_somethingArray[4].val10 = 0x28;
+		_npcState[14].ttmPage = 0x28;
 	}
 	if (_npcState[0].health != 0 && ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone || _arcadeTTM._startYOffset < -6)
-		&& _somethingArray[4].val0 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _somethingArray[4].val0 + 0x23) {
+		&& _npcState[14].val1 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _npcState[14].val1 + 0x23) {
 		bladeTakeHit();
 		bladeTakeHit();
 		if (_npcState[0].health == 0) {
 			/* blade dies! */
-			_npcState[0].byte14 = 2;
+			_npcState[0].byte15 = 2;
 			_npcState[0].ttmPage = 0x22;
 			_npcState[0].byte12 = 14;
 			_bladeState1 = 14;
@@ -710,7 +722,7 @@ uint16 DragonArcade::moveToNextStage() {
 			_mouseButtonWentDown = 0x80;
 			_npcState[0].byte12 = 13;
 			_npcState[0].health = 0;
-			_npcState[0].byte14 = 2;
+			_npcState[0].byte15 = 2;
 			return 1;
 		}
 
@@ -752,7 +764,7 @@ void DragonArcade::playSFX55AndStuff() {
 	_uint0a17 = 0;
 	// TODO: What are thess?
 	_int3d18 = 0;
-	//INT_39e5_0b5a = 0xf;
+	_int0b5a = 0xf;
 	_int0b5c = 0;
 	_npcState[0].ttmPage = _bladeStateOffset + 0x43;
 }
@@ -859,7 +871,7 @@ void DragonArcade::initValuesForStage2() {
 		_npcState[i].val2 = STAGE_2_VAL2[i - 1];
 		_npcState[i].byte12 = STAGE_2_BYTE12[i - 1];
 		_npcState[i].ttmPage = STAGE_2_TTMPAGE[i - 1];
-		_npcState[i].byte14 = 1;
+		_npcState[i].byte15 = 1;
 	}
 	for (int i = 10; i < 14; i++) {
 		_npcState[i].val1 = STAGE_2_VAL1_PART2[i - 10];
@@ -1003,7 +1015,7 @@ void DragonArcade::arcade3e96() {
 				(_loadedArcadeStage != 1 || _arcadeTTM._startYOffset < -9 ||
 				 (_bladeMoveFlag & kBladeMoveRight) == kBladeMoveNone)) {
 				setFinishCountdownIfLessThan0(20);
-				_npcState[0].byte14 = 2;
+				_npcState[0].byte15 = 2;
 				_npcState[0].health = 0;
 				if (_haveBigGun) {
 					_npcState[0].ttmPage = 0x19;
@@ -1259,7 +1271,7 @@ void DragonArcade::updateBoss() {
 		if (_npcState[3].health == 0) {
 			_npcState[3].byte12 = -3;
 			_npcState[3].ttmPage = 39;
-			_npcState[3].byte14 = 1;
+			_npcState[3].byte15 = 1;
 		}
 	} else if (_npcState[3].byte12 == -3) {
 		_npcState[3].ttmPage++;
@@ -1384,7 +1396,7 @@ void DragonArcade::updateBoss2() {
 	default:
 		if (_stillLoadingScriptsMaybe != 0) {
 			if ((_int0b5c == -1 && _npcState[1].x < 0x96) || (_int0b5c == 1 && 160 < _npcState[1].x)) {
-				arcadeUpdateXScrollOffset();
+				updateXScrollOffset();
 			}
 			byte bossByte12 = _npcState[1].byte12;
 			// TODO: do these ever get changed?
@@ -1445,7 +1457,7 @@ void DragonArcade::updateBoss2() {
 	}
 }
 
-void DragonArcade::arcadeUpdateXScrollOffset() {
+void DragonArcade::updateXScrollOffset() {
 	int16 lastScrollOffset = _scrollXOffset;
 	_scrollXOffset = CLIP(_scrollXOffset + _int0b5c, 0, 282);
 	if (lastScrollOffset != _scrollXOffset) {
@@ -1471,7 +1483,7 @@ void DragonArcade::arcade34b4() {
 	_npcState[1].byte12 = 100;
 	_npcState[1].ttmPage = 67;
 	_npcState[1].val1 = _npcState[0].val1;
-	_npcState[1].byte14 = 2;
+	_npcState[1].byte15 = 2;
 }
 
 void DragonArcade::decBossHealth() {
@@ -1517,7 +1529,7 @@ void DragonArcade::bladeTakeHit() {
 			_npcState[0].ttmPage = _bladeStateOffset + 0x62;
 		}
 		setFinishCountdownIfLessThan0(15);
-		_npcState[0].byte14 = 0;
+		_npcState[0].byte15 = 0;
 		_mouseButtonWentDown = 0x80;
 	} else {
 		playSfx(0x29);
@@ -1548,10 +1560,8 @@ void DragonArcade::initIfNeeded() {
 	_scrollImg->loadBitmap(scrollBmpName);
 
 	_arcadeTTM.clearDataPtrs();
-
-	int16 envNum;
 	_arcadeTTM._currentTTMNum = 0;
-	envNum = _arcadeTTM.load(ttmName);
+	int16 envNum = _arcadeTTM.load(ttmName);
 	_arcadeTTM.finishTTMParse(envNum);
 	_arcadeTTM._doingInit = true;
 	for (int i = 0; i < 8; i++) {
@@ -1592,9 +1602,9 @@ void DragonArcade::updateBladeWithInputs() {
 		return;
 
 	// TODO: What are these?
-	//if ((INT_39e5_0b5a != 0) && (INT_39e5_0b5a--, INT_39e5_0b5a == 0)) {
-	//	INT_39e5_0b58 = 0;
-	//}
+	if ((_int0b5a != 0) && (_int0b5a--, _int0b5a == 0)) {
+		_int0b58 = 0;
+	}
 
 	if ((_bladeHorizMoveAttempt & 1) == 0) {
 		_bladeStateOffset = 0;
@@ -1689,9 +1699,9 @@ void DragonArcade::updateBladeWithInputs() {
 			_npcState[3].val2 = -0x20;
 			_npcState[3].byte12 = -2;
 			_npcState[3].ttmPage = 0x21;
-			_npcState[3].byte14 = 2;
+			_npcState[3].byte15 = 2;
 			_npcState[3].health = 20;
-			_npcState[0].byte14 = 0;
+			_npcState[0].byte15 = 0;
 			handleMouseStates();
 		}
 		return;
@@ -1822,9 +1832,109 @@ void DragonArcade::moveBladeX() {
 }
 
 void DragonArcade::handleMouseStates() {
-	error("TODO: handleMouseStates: Implement me");
-}
+	if (_mouseButtonWentDown == 0) {
+		_bladeState1 = 0;
+		if ((_bladeMoveFlag & (kBladeMoveRight | kBladeMoveLeft)) == kBladeMoveNone) {
+			/* not moving up or down */
+			if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
+				_npcState[0].ttmPage = _bladeStateOffset + 2;
+			} else {
+				_npcState[0].ttmPage = _bladeStateOffset + 0xe;
+			}
+		} else {
+			moveBladeX();
+			if (_foundValueFrom3d1cArray == 0) {
+				if ((_npcState[0].ttmPage < _bladeStateOffset + 0x6d) ||
+					(_bladeStateOffset + 0x70 < _npcState[0].ttmPage)) {
+					_npcState[0].ttmPage = _bladeStateOffset + 0x6d;
+				}
+			} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
+				if ((_npcState[0].ttmPage < _bladeStateOffset + 3) ||
+					(_bladeStateOffset + 10 < _npcState[0].ttmPage)) {
+					_npcState[0].ttmPage = _bladeStateOffset + 3;
+				}
+			} else if ((_npcState[0].ttmPage < _bladeStateOffset + 0x1c) ||
+					   (_bladeStateOffset + 0x23 < _npcState[0].ttmPage)) {
+				_npcState[0].ttmPage = _bladeStateOffset + 0x1c;
+			}
+		}
+	} else if (_mouseButtonWentDown == 1) {
+		if (_loadedArcadeStage == 3 && _haveBomb != 0 && _npcState[1].health != 0 &&
+			  0x19 < abs(_npcState[1].y - _npcState[0].y) && abs(_npcState[1].x - _npcState[0].x) < 0x28) {
+			/* use a bomb */
+			_bladeState1 = 0xb;
+			_haveBomb = false;
+			_npcState[0].byte15 = 2;
+			if (_haveBigGun == 0) {
+				_npcState[0].ttmPage = 4;
+			} else {
+				_npcState[0].ttmPage = 0xf;
+			}
+		} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
+			_bladeState1 = 3;
+			_npcState[0].ttmPage = _bladeStateOffset + 0x71;
+		} else {
+			_bladeState1 = 4;
+			_npcState[0].ttmPage = _bladeStateOffset + 0x24;
+		}
+	} else if (_mouseButtonWentDown == 2) {
+		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == 0) {
+			_bladeMoveFlag = static_cast<DragonBladeMoveFlag>(_bladeMoveFlagBeforeRButton | (_bladeHorizMoveAttempt & (kBladeMoveLeft | kBladeMoveRight)));
+		} else {
+			_bladeMoveFlag = _bladeMoveFlagBeforeRButton;
+			_bladeHorizMoveAttempt = _bladeMoveFlagBeforeRButton;
+		}
 
+		if ((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) {
+			if (_int0b58 + 1 < 5) {
+				_int0b58++;
+			} else {
+				_int0b58 = 4;
+			}
+		} else {
+			_int0b58 = 4;
+		}
+
+		_int0b5a = 0;
+		_int0b5c = 0;
+		if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
+			_bladeStateOffset = 0;
+		} else {
+			_bladeStateOffset = 0x7a;
+		}
+
+		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == 0) {
+			_bladeState1 = 1;
+			_npcState[0].ttmPage = _bladeStateOffset + 0xf;
+		} else {
+			if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
+				_int0b5c = 1;
+			} else {
+				_int0b5c = -1;
+			}
+			_isMovingStage = 0;
+			_bladeState1 = 2;
+			_npcState[0].ttmPage = _bladeStateOffset + 0x2d;
+		}
+
+		if ((_bladeMoveFlagBeforeRButton & kBladeMoveRight) != 0) {
+			findMinIn3d30ArrayFirst();
+			if (!isAbsFoundValOver990()) {
+				if (_bladeState1 == 2) {
+					_npcState[0].ttmPage = _bladeStateOffset + 0x38;
+				} else {
+					_npcState[0].ttmPage = _bladeStateOffset + 0x16;
+				}
+				_arcadeTTM._startYOffset++;
+				_uint0a17++;
+				_int0b54 = _arcadeTTM._startYOffset;
+			}
+		}
+		playSfx(0x54);
+		_bladeMoveFlagBeforeRButton = kBladeMoveNone;
+	}
+	_mouseButtonWentDown = 0;
+}
 
 void DragonArcade::resetStageState() {
 	clearAllNPCStates();
@@ -1837,7 +1947,7 @@ void DragonArcade::resetStageState() {
 	_shouldUpdateState = 0;
 	_arcadeNotMovingLeftFlag = 0;
 	_npcState[0].byte12 = 1;
-	_npcState[0].byte14 = 0;
+	_npcState[0].byte15 = 0;
 	_npcState[0].health = (4 - _startDifficultyMaybe) * 3 + 20;
 	_npcState[0].ttmPage = 3;
 	_npcState[1].health = 0;
@@ -1916,38 +2026,38 @@ void DragonArcade::initValuesForStage() {
 	}
 }
 
-static const int16 STAGE_0_ST_INT0[] = {
+static const int16 STAGE_0_ST_INT1[] = {
 	0x13F, 0x150, 0x161, 0x172
 };
 
-static const int16 STAGE_0_ST_INT0_2[] = {
+static const int16 STAGE_0_ST_INT1_2[] = {
 	0x317, 0x328, 0x339, 0x34A
 };
 
-static const int16 STAGE_0_ST_VAL10[] = {
+static const int16 STAGE_0_ST_TTMPAGE[] = {
 	 0, 0x1E, 0xF, 0
 };
 
 void DragonArcade::initValuesForStage0() {
 	_someCounter40f0 = 0;
-	for (int i = 0; i < 4; i++) {
-		_somethingArray[i].val0 = STAGE_0_ST_INT0[i];
-		_somethingArray[i].val2 = 2;
-		_somethingArray[i].val10 = STAGE_0_ST_VAL10[i];
-		_somethingArray[i].val15 = 2;
+	for (int i = 10; i < 14; i++) {
+		_npcState[i].val1 = STAGE_0_ST_INT1[i - 10];
+		_npcState[i].val2 = 2;
+		_npcState[i].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
+		_npcState[i].byte15 = 2;
 
-		_somethingArray[i + 4].val0 = STAGE_0_ST_INT0_2[i];
-		_somethingArray[i + 4].val2 = -37;
-		_somethingArray[i + 4].val10 = STAGE_0_ST_VAL10[i];
-		_somethingArray[i + 4].val15 = 2;
+		_npcState[i + 4].val1 = STAGE_0_ST_INT1_2[i - 10];
+		_npcState[i + 4].val2 = -37;
+		_npcState[i + 4].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
+		_npcState[i + 4].byte15 = 2;
 	}
 	_flag40ee = true;
 	_flag40ef = true;
-	_somethingArray[8].val0 = 0x11f;
-	_somethingArray[8].val2 = -0xd;
-	_somethingArray[8].val12 = 0x1e;
-	_somethingArray[8].val10 = 0x20;
-	_somethingArray[8].val15 = 2;
+	_npcState[18].val1 = 0x11f;
+	_npcState[18].val2 = -0xd;
+	_npcState[18].byte12 = 0x1e;
+	_npcState[18].ttmPage = 0x20;
+	_npcState[18].byte15 = 2;
 }
 
 void DragonArcade::initValuesForStage3() {
@@ -1958,14 +2068,14 @@ void DragonArcade::initValuesForStage3() {
 	_npcState[1].byte12 = 1;
 	_npcState[1].ttmPage = 2;
 	_npcState[1].health = 20;
-	_npcState[1].byte14 = 1;
+	_npcState[1].byte15 = 1;
 	_npcState[1].y = 300;
 	_npcState[2].val1 = 0x9b2;
 	_npcState[2].val2 = -57;
 	_npcState[2].byte12 = -1;
 	_npcState[2].ttmPage = 23;
 	_npcState[2].health = 0;
-	_npcState[2].byte14 = 1;
+	_npcState[2].byte15 = 1;
 }
 
 static const int16 STAGE_4_ST_INT0[] = {
@@ -1976,7 +2086,7 @@ static const int16 STAGE_4_ST_INT2[] = {
 	8, 8, 6, 6, 6
 };
 
-static const int16 STAGE_4_ST_INT10[] = {
+static const int16 STAGE_4_ST_TTMPAGE[] = {
 	0, 0, 0xf, 0xf, 0x28
 };
 
@@ -1986,13 +2096,13 @@ static const byte STAGE_4_ST_BYTE12[] = {
 
 void DragonArcade::initValuesForStage4() {
 	_someCounter40f0 = 0;
-	for (int i = 0; i < 5; i++) {
-		_somethingArray[i].val0 = STAGE_4_ST_INT0[i];
-		_somethingArray[i].val2 = STAGE_4_ST_INT2[i];
-		_somethingArray[i].val10 = STAGE_4_ST_INT10[i];
-		_somethingArray[i].val12 = STAGE_4_ST_BYTE12[i];
-		_somethingArray[i].val14 = 1;
-		_somethingArray[i].val15 = 2;
+	for (int i = 10; i < 15; i++) {
+		_npcState[i].val1 = STAGE_4_ST_INT0[i - 10];
+		_npcState[i].val2 = STAGE_4_ST_INT2[i - 10];
+		_npcState[i].ttmPage = STAGE_4_ST_TTMPAGE[i - 10];
+		_npcState[i].byte12 = STAGE_4_ST_BYTE12[i - 10];
+		_npcState[i].health = 1;
+		_npcState[i].byte15 = 2;
 	}
 }
 
@@ -2002,7 +2112,7 @@ void DragonArcade::initValuesForStage6() {
 	_npcState[1].val2 = -3;
 	_npcState[1].ttmPage = 1;
 	_npcState[1].health = 10;
-	_npcState[1].byte14 = 1;
+	_npcState[1].byte15 = 1;
 	_npcState[1].byte12 = 1;
 	_stillLoadingScriptsMaybe = false;
 }
@@ -2236,11 +2346,11 @@ void DragonArcade::playSfx(int16 num) const {
 }
 
 void DragonArcade::bladeTakeHitAndCheck() {
-	if (_bladeHealth)
-		_bladeHealth--;
-	if (!_enemyHasSmallGun && _bladeHealth)
-		_bladeHealth--;
-	if (_bladeHealth <= 0) {
+	if (_npcState[0].health)
+		_npcState[0].health--;
+	if (!_enemyHasSmallGun && _npcState[0].health)
+		_npcState[0].health--;
+	if (_npcState[0].health <= 0) {
 		playSfx(75);
 		if ((_bladeState1 == 0 && _bladeStateOffset + 28 < _npcState[0].ttmPage && _npcState[0].ttmPage <= 35)
 			|| _bladeState1 == 4) {
@@ -2251,7 +2361,7 @@ void DragonArcade::bladeTakeHitAndCheck() {
 			_npcState[0].ttmPage = _bladeState1 + 98;
 		}
 		setFinishCountdownIfLessThan0(15);
-		_npcState[0].byte14 = 0;
+		_npcState[0].byte15 = 0;
 		_mouseButtonWentDown = 0x80;
 	} else {
 		playSfx(41);
@@ -2261,29 +2371,29 @@ void DragonArcade::bladeTakeHitAndCheck() {
 void DragonArcade::drawHealthBars() {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 
-	if (_bladeHealth != _lastDrawnBladeHealth) {
+	if (_npcState[0].health != _lastDrawnBladeHealth) {
 		Common::Rect clearRect(Common::Point(10, 155), 64, 10);
 		engine->_compositionBuffer.fillRect(clearRect, 0);
 
-		for (int i = 1; i <= _bladeHealth; i++) {
+		for (int i = 1; i <= _npcState[0].health; i++) {
 			int x = 8 + i * 2;
 			engine->_compositionBuffer.drawLine(x, 155, x, 162, 12);
 		}
 
-		_lastDrawnBladeHealth = _bladeHealth;
+		_lastDrawnBladeHealth = _npcState[0].health;
 	}
 
-	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) && (_bossHealth != _lastDrawnBossHealth)) {
+	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) && (_npcState[1].health != _lastDrawnBossHealth)) {
 		Common::Rect clearRect(Common::Point(10, 167), 60, 8);
 		engine->_compositionBuffer.fillRect(clearRect, 0);
 
 		byte color = (_loadedArcadeStage == 3) ? 2 : 9;
 
-		for (int i = 1; i <= _bossHealth; i++) {
+		for (int i = 1; i <= _npcState[1].health; i++) {
 			int x = 8 + i * 2;
 			engine->_compositionBuffer.drawLine(x, 167, x, 174, color);
 		}
-		_lastDrawnBossHealth = _bossHealth;
+		_lastDrawnBossHealth = _npcState[1].health;
 	}
 }
 
@@ -2308,7 +2418,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 	_arcadeTTM.runPagesForEachNPC(_scrollXOffset);
 
 	const Common::Rect screenWin(SCREEN_WIDTH, SCREEN_HEIGHT);
-	_arcadeTTM._currentTTMNum = _npcState[0].byte14;
+	_arcadeTTM._currentTTMNum = _npcState[0].byte15;
 	_npcState[0].x_11 = 0;
 	_npcState[0].x_12 = 0;
 	_npcState[0].x_21 = 0;
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index 8c9cef558b7..f0148054111 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -42,7 +42,11 @@ enum DragonBladeMoveFlag {
 	kBladeMoveLeft = 8,
 };
 
-struct ArcadeNPCState {
+class ArcadeNPCState {
+public:
+	ArcadeNPCState() : val1(0), val2(0), x(0), y(0), x_11(0), y_11(0), x_12(0), y_12(0),
+		ttmPage(0), byte12(0), byte13(0), health(0), byte15(0), x_21(0), y_21(0),
+		x_22(0), y_22(0) {}
 	int16 val1;
 	int16 val2;
 	int16 x;
@@ -55,25 +59,13 @@ struct ArcadeNPCState {
 	int8 byte12;
 	int8 byte13;
 	int8 health;
-	int8 byte14; /* Set to 0, 1 or 2 */
+	int8 byte15; /* Set to 0, 1 or 2 */
 	int16 x_21;
 	int16 y_21;
 	int16 x_22;
 	int16 y_22;
 };
 
-struct AracdeSomething {
-	int16 val0;
-	int16 val2;
-	byte unk4[12];
-	int16 val10;
-	byte val12;
-	byte unk13;
-	byte val14;
-	byte val15;
-	byte unk16[8];
-};
-
 class DragonArcadeBullet {
 public:
 	DragonArcadeBullet() : _x(0), _y(0), _state(kBulletInactive),
@@ -103,7 +95,7 @@ private:
 	void clearAllNPCStates();
 	void createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16 var1);
 	void bladeTakeHitAndCheck();
-	void enemyTakeHit() { _bossHealth--; }
+	void enemyTakeHit() { _npcState[1].health--; }
 	void enemyTakeHitAndCheck();
 	void playSfx(int16 num) const;
 	void drawBulletHitCircles(uint16 x, uint16 y, bool flag);
@@ -131,13 +123,13 @@ private:
 	void bladeTakeHit();
 	void arcade16bc();
 	void arcade16de(int16 param);
-	void arcadeUpdateXScrollOffset();
 	void arcade1e83();
 	void arcade2445();
 	void arcade2754(int16 findResult);
+	void arcade34b4();
 	void arcade3e96();
 	void arcade4085();
-	void arcade34b4();
+	void updateXScrollOffset();
 	bool isNpcInsideXRange(int16 num);
 	void updateBullets();
 	void checkBladeFireAllStages();
@@ -161,10 +153,7 @@ private:
 	void playSFX55AndStuff();
 	void moveBladeX();
 	void handleMouseStates();
-	void updateXScrollOffset();
 
-	int16 _bladeHealth;
-	int16 _bossHealth;
 	int16 _lastDrawnBladeHealth;
 	int16 _lastDrawnBossHealth;
 	uint16 _nextRandomVal;
@@ -186,6 +175,7 @@ private:
 	uint16 _uint0a17;
 	int16 _int0b54;
 	int16 _int0b58;
+	int16 _int0b5a;
 	int16 _int0b60;
 	int16 _int3d18;
 	uint16 _uint0be6;
@@ -220,8 +210,7 @@ private:
 	DragonBladeMoveFlag _keyStateFlags;
 	DragonBladeMoveFlag _bladeMoveFlagBeforeRButton;
 	DragonArcadeBullet _bullets[20];
-	ArcadeNPCState _npcState[10];
-	AracdeSomething _somethingArray[9];
+	ArcadeNPCState _npcState[20];
 	Common::SharedPtr<Image> _bulletImg;
 	Common::SharedPtr<Image> _arrowImg;
 	Common::SharedPtr<Image> _scrollImg;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index e997190c6cf..6f835c45996 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -30,8 +30,8 @@
 namespace Dgds {
 
 DragonArcadeTTM::DragonArcadeTTM(ArcadeNPCState *npcState) : _npcState(npcState),
-_currentTTMNum(0), _currentNPCRunningTTM(0), _drawXOffset(0), _drawYOffset(0),
-_startYOffset(0), _doingInit(false), _drawColBG(0), _drawColFG(0)
+	_currentTTMNum(0), _currentNPCRunningTTM(0), _drawXOffset(0), _drawYOffset(0),
+	_startYOffset(0), _doingInit(false), _drawColBG(0), _drawColFG(0)
 {
 	ARRAYCLEAR(_shapes3);
 	ARRAYCLEAR(_brushes);
@@ -51,6 +51,7 @@ int16 DragonArcadeTTM::load(const char *filename) {
 	for (envNum = 0; envNum < ARRAYSIZE(_ttmEnvs); envNum++) {
 		if (_ttmEnvs[envNum].scr == nullptr) {
 			env = &_ttmEnvs[envNum];
+			break;
 		}
 	}
 	if (!env)
@@ -157,7 +158,7 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		engine->_soundPlayer->playSFX(sound);
 		break;
 	}
-	case 0x4054: { // SET NPC POS 1
+	case 0x4504: { // SET NPC POS 1
 		int16 x = _drawXOffset + ivals[0];
 		int16 y = _drawYOffset + ivals[1] + 2;
 		_npcState[_currentNPCRunningTTM].x_11 = x;
@@ -237,12 +238,14 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		if (_currentNPCRunningTTM == 0) {
 			int16 x = ivals[0] + _npcState[0].x - 152;
 			int16 y = ivals[1] + _startYOffset + 2;
-			_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
+			if (_shapes[_currentTTMNum])
+				_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
 			_npcState[0].y = ivals[1];
 		} else {
 			int16 x = ivals[0] + _drawXOffset;
 			int16 y = ivals[1] + _drawYOffset + 2;
-			_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
+			if (_shapes[_currentTTMNum])
+				_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
 			_npcState[_currentNPCRunningTTM].x = ivals[0];
 			_npcState[_currentNPCRunningTTM].y = ivals[1];
 		}
@@ -259,7 +262,7 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		// Do nothing (ignore arg)
 		break;
 	default:
-		error("Unsupported TTM opcode 0x%04x for Dragon arcade.", op);
+		warning("Unsupported TTM opcode 0x%04x for Dragon arcade.", op);
 	}
 	return 0;
 }
@@ -283,6 +286,7 @@ int16 DragonArcadeTTM::runScriptPage(int16 pageNum) {
 		}
 
 		handleOperation(_ttmEnvs[_currentTTMNum], pageNum, opcode, count, ivals, sval);
+		opcode = scr->readUint16LE();
 	}
 	return 1;
 
@@ -302,7 +306,7 @@ void DragonArcadeTTM::runPagesForEachNPC(int16 xScrollOffset) {
 			npcState.y_12 = 0;
 			 _drawXOffset = npcState.val1 - xScrollOffset * 8 - 152;
 			 _drawYOffset = npcState.val2;
-			_currentTTMNum = npcState.byte14;
+			_currentTTMNum = npcState.byte15;
 			if (_drawXOffset > -20 || _drawXOffset < 340) {
 				runNextPage(npcState.ttmPage);
 			}
@@ -319,6 +323,7 @@ void DragonArcadeTTM::freePages(uint16 num) {
 void DragonArcadeTTM::freeShapes() {
 	_shapes3[_currentTTMNum] = 0;
 	_shapes[_currentTTMNum].reset();
+	_shapes2[_currentTTMNum].reset();
 	for (int i = 0; i < 6; i++) {
 		_allShapes[i * 5 + _currentTTMNum].reset();
 	}
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 73db1aada12..7595f8c1e76 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -42,6 +42,7 @@
 #include "dgds/globals.h"
 #include "dgds/image.h"
 #include "dgds/inventory.h"
+#include "dgds/dragon_arcade.h"
 
 namespace Dgds {
 
@@ -752,9 +753,10 @@ bool Scene::runDragonOp(const SceneOp &op) {
 	case kSceneOpArcadeTick:
 		// TODO: Implement this properly! for now just
 		// set the global arcade state variable to the "skip" value.
-		warning("Setting arcade global to 8 (skip)");
-		g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
-		engine->getGameGlobals()->setGlobal(0x21, 6);
+		//warning("Setting arcade global to 8 (skip)");
+		//g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
+		//engine->getGameGlobals()->setGlobal(0x21, 6);
+		engine->getDragonArcade()->arcadeTick();
 		break;
 	case kSceneOpDrawDragonCountdown1:
 		_drawDragonCountdown(FontManager::k4x5Font, 141, 56);


Commit: ce4c983b1c7857a36d437d18f7a7636288be2931
    https://github.com/scummvm/scummvm/commit/ce4c983b1c7857a36d437d18f7a7636288be2931
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Dragon arcade starting to work

Changed paths:
    engines/dgds/dgds.cpp
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/dragon_arcade_ttm.h
    engines/dgds/globals.h


diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index f06ed4814b8..cd44ccb2dad 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -699,7 +699,7 @@ bool DgdsEngine::canSaveGameStateCurrently(Common::U32String *msg /*= nullptr*/)
 }
 
 bool DgdsEngine::canSaveAutosaveCurrently() {
-	return canSaveGameStateCurrently() && !_scene->hasVisibleDialog() && !_menu->menuShown();
+	return canSaveGameStateCurrently() && !_scene->hasVisibleDialog() && !_menu->menuShown() && _gameGlobals->getGameIsInteractiveGlobal();
 }
 
 Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 9a61ab23fe5..9887faf2bf7 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -37,14 +37,14 @@
 
 namespace Dgds {
 
-DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(0),
-	_lastDrawnBossHealth(0), _nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _arcadeModeSomethingCounter(0),
+DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1),
+	_lastDrawnBossHealth(-1), _nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _arcadeModeSomethingCounter(0),
 	_currentArcadeTT3Num(0), _shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladeStateOffset(0),
 	_mouseButtonWentDown(0), _scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0),
-	_someCounter40f0(0), _int0b5c(0), _uint0a17(0), _int0b54(0), _int0b58(0), _int0b5a(0), _int0b60(0), _int3d18(0),
-	_uint0be6(0), _flag3d14(0), _scrollXIncrement(0), _lMouseButtonState(0), _rMouseButtonState(0), _lastLMouseButtonState(0),
-	_lastRMouseButtonState(0), _bladeXMove(0), _bladeHorizMoveAttempt(0), _currentArrowNum(0), _foundValueFrom3d30Array(0),
-	_foundValueFrom3d1cArray(0), _2754Val(0), _arcadeNotMovingLeftFlag(0), _haveBigGun(true), _haveBomb(true),
+	_someCounter40f0(0), _scrollVelocityX(0), _uint0a17(0), _currentYOffset(0), _int0b58(0), _int0b5a(0), _int0b60(0), _ttmYAdjust(0),
+	_uint0be6(0), _dontMoveBladeFlag(false), _scrollXIncrement(0), _lMouseButtonState(0), _rMouseButtonState(0), _lastLMouseButtonState(0),
+	_lastRMouseButtonState(0), _bladeXMove(0), _bladeHorizMoveAttempt(0), _currentArrowNum(0), _foundFloorY(0),
+	_foundFloorFlag(0), _lastFloorY(0), _arcadeNotMovingLeftFlag(0), _haveBigGun(true), _haveBomb(true),
 	_enemyHasSmallGun(false), _dontRedrawBgndAndWeapons(false), _arcadeNeedsBufferCopy(false), _flagInventoryOpened(false),
 	_initFinished(false), _stillLoadingScriptsMaybe(false), _flag40ee(false), _flag40ef(false), _bladeHasFired(false),
 	_mouseIsAvailable(false), _isMovingStage(false), _bladeMoveFlag(kBladeMoveNone), _keyStateFlags(kBladeMoveNone),
@@ -90,8 +90,8 @@ bool DragonArcade::doTickUpdate() {
 		updateBladeWithInputs();
 	}
 
-	int16 findResult = findValuesIn3d30Array();
-	arcade2754(findResult);
+	int16 floorY = findFloorUnderBlade();
+	arcade2754(floorY);
 
 	switch (_loadedArcadeStage) {
 	case 0:
@@ -116,7 +116,7 @@ bool DragonArcade::doTickUpdate() {
 	}
 
 	updateBullets();
-	//setSomeVideoFlags();
+	drawScrollBmp();
 	runThenDrawBulletsInFlight();
 	checkBladeFireAllStages();
 	switch(_loadedArcadeStage) {
@@ -232,10 +232,6 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 					return 1;
 				}
 
-				if (6 < _loadedArcadeStage) {
-					return 1;
-				}
-
 				switch (_loadedArcadeStage) {
 				case 0:
 				case 1:
@@ -363,12 +359,13 @@ void DragonArcade::checkEnemyFireStage0124() {
 	for (int i = 9; i != 0; i--) {
 		if (_npcState[i].byte12 == 0)
 			continue;
+
 		for (int j = 0; j < 4; j++) {
 			if (_npcState[i].x < 0x154 && -20 < _npcState[i].x &&
 				ENEMY_FIRE_ALLOWABLE_PAGES[j] == _npcState[i].ttmPage) {
 				ImageFlipMode flipMode = (_npcState[i].ttmPage < 0x1d) ? kImageFlipNone : kImageFlipV;
-				createBullet(ENEMY_FIRE_X_OFFSETS[j] + _npcState[i].val1 - _scrollXOffset * 8 - 0xa0,
-							 ENEMY_FIRE_Y_OFFSETS[j] + _npcState[i].val2 + 3, flipMode, 1);
+				createBullet(ENEMY_FIRE_X_OFFSETS[j] + _npcState[i].xx - _scrollXOffset * 8 - 0xa0,
+							 ENEMY_FIRE_Y_OFFSETS[j] + _npcState[i].yy + 3, flipMode, 1);
 				playSfx(0x25);
 			}
 		}
@@ -378,8 +375,8 @@ void DragonArcade::checkEnemyFireStage0124() {
 
 void DragonArcade::checkBossFireStage3() {
 	if (_npcState[1].x < 0x154 && -20 < _npcState[1].x && _npcState[1].ttmPage == 22) {
-		createBullet(_npcState[1].val1 - _scrollXOffset * 8 - 44,
-						_npcState[1].val2 + 70, kImageFlipH, 3);
+		createBullet(_npcState[1].xx - _scrollXOffset * 8 - 44,
+						_npcState[1].yy + 70, kImageFlipH, 3);
 		playSfx(0x2a);
 	}
 }
@@ -389,8 +386,8 @@ void DragonArcade::checkBossFireStage6() {
 
 	if (_npcState[1].x < 0x154 && -20 < _npcState[1].x &&
 		(_npcState[1].ttmPage == 9 || _npcState[1].ttmPage == 0x28)) {
-		createBullet(_npcState[1].val1 - _scrollXOffset * 8 - 19,
-						_npcState[1].val2 + 86, flipMode, 2);
+		createBullet(_npcState[1].xx - _scrollXOffset * 8 - 19,
+						_npcState[1].yy + 86, flipMode, 2);
 		playSfx(0x24);
 	}
 }
@@ -456,18 +453,18 @@ void DragonArcade::updateMouseAndJoystickStates() {
 		if ((_keyStateFlags & kBladeMoveRight) == kBladeMoveNone) {
 			if ((_keyStateFlags & kBladeMoveLeft) != kBladeMoveNone) {
 				if (_arcadeNotMovingLeftFlag) {
-					_arcadeNotMovingLeftFlag = false;
+					_arcadeNotMovingLeftFlag = 0;
 				}
 				_bladeMoveFlag = kBladeMoveLeft;
 				if (_bladeState1 == 0) {
-					_int0b5c = -1;
+					_scrollVelocityX = -1;
 					_bladeHorizMoveAttempt = 1;
 				}
 			}
 		} else {
 			_bladeMoveFlag = kBladeMoveRight;
 			if (_bladeState1 == 0) {
-				_int0b5c = 1;
+				_scrollVelocityX = 1;
 				_bladeHorizMoveAttempt = 2;
 			}
 		}
@@ -490,57 +487,57 @@ void DragonArcade::updateMouseAndJoystickStates() {
 	}
 }
 
-int16 DragonArcade::findValuesIn3d30Array() {
-	fill3d30ArrayFromLevelData();
+int16 DragonArcade::findFloorUnderBlade() {
+	updateFloorsUnderBlade();
 	if (_bladeState1 == 1 || _bladeState1 == 2) {
 		if ((_bladeStateOffset + 0x38 == _npcState[0].ttmPage) ||
 			(_bladeStateOffset + 0x16 == _npcState[0].ttmPage)) {
-			findMatchOrMinOrMax();
+			findFloorMatchOrMinOrMax();
 		} else {
-			findMinIn3d30ArrayLast();
-			if (isAbsFoundValOver990()) {
-				_foundValueFrom3d30Array = -0x100;
+			findFloorMinGE();
+			if (isFloorNotFound()) {
+				_foundFloorY = -0x100;
 			}
 		}
 	} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
 		if ((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) {
-			findMatchIn3d30Array();
-			if (isAbsFoundValOver990()) {
-				findMinIn3d30ArrayFirst();
-				if (isAbsFoundValOver990()) {
-					findMaxIn3d30Array();
-					if (isAbsFoundValOver990()) {
-						_foundValueFrom3d30Array = -0x100;
+			findFloorMatch();
+			if (isFloorNotFound()) {
+				findFloorMinGT();
+				if (isFloorNotFound()) {
+					findFloorMax();
+					if (isFloorNotFound()) {
+						_foundFloorY = -0x100;
 					}
 				}
 			}
 		} else {
 			/* Move up */
-			findMaxIn3d30Array();
-			if (isAbsFoundValOver990()) {
-				findMatchIn3d30Array();
-				if (isAbsFoundValOver990()) {
-					findMinIn3d30ArrayFirst();
-					if (isAbsFoundValOver990()) {
-						_foundValueFrom3d30Array = -0x100;
+			findFloorMax();
+			if (isFloorNotFound()) {
+				findFloorMatch();
+				if (isFloorNotFound()) {
+					findFloorMinGT();
+					if (isFloorNotFound()) {
+						_foundFloorY = -0x100;
 					}
 				}
 			}
 		}
 	} else {
 		/* Move down */
-		findMinIn3d30ArrayFirst();
-		if (isAbsFoundValOver990()) {
-			findMatchIn3d30Array();
-			if (isAbsFoundValOver990()) {
-				findMaxIn3d30Array();
-				if (isAbsFoundValOver990()) {
-					_foundValueFrom3d30Array = -0x100;
+		findFloorMinGT();
+		if (isFloorNotFound()) {
+			findFloorMatch();
+			if (isFloorNotFound()) {
+				findFloorMax();
+				if (isFloorNotFound()) {
+					_foundFloorY = -0x100;
 				}
 			}
 		}
 	}
-	return _foundValueFrom3d30Array;
+	return _foundFloorY;
 }
 
 bool DragonArcade::isNpcInsideXRange(int16 num) {
@@ -551,7 +548,7 @@ void DragonArcade::arcade16bc() {
 	_bladeState1 = 5;
 	_npcState[0].ttmPage = _bladeStateOffset + 0x40;
 	_arcadeTTM._startYOffset++;
-	_int0b54 = _arcadeTTM._startYOffset;
+	_currentYOffset = _arcadeTTM._startYOffset;
 	_uint0a17++;
 }
 
@@ -572,8 +569,8 @@ void DragonArcade::arcade16de(int16 param) {
 	_uint0a17 = 0;
 	_bladeState1 = 0;
 	// TODO: What are these ?
-	_int3d18 = 0;
-	_int0b5a = 0xf;
+	_ttmYAdjust = 0;
+	_int0b5a = 15;
 }
 
 void DragonArcade::arcade4085() {
@@ -591,8 +588,8 @@ void DragonArcade::arcade4085() {
 					playSfx(0x1d);
 			}
 			_npcState[i].byte12 = 0xfb;
-			if (_npcState[0].health && _npcState[i].val1 - 0x10 <= _npcState[0].val1 &&
-				_npcState[0].val1 <= _npcState[i].val1 + 0x37) {
+			if (_npcState[0].health && _npcState[i].xx - 0x10 <= _npcState[0].xx &&
+				_npcState[0].xx <= _npcState[i].xx + 0x37) {
 				bladeTakeHit();
 			}
 		}
@@ -611,7 +608,7 @@ void DragonArcade::arcade4085() {
 		if (_npcState[i].ttmPage == 0x1d) {
 			if (isNpcInsideXRange(i + 2))
 				playSfx(0x59);
-			if (_npcState[0].health && _npcState[i].val2 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _npcState[i].val2 + 0x23) {
+			if (_npcState[0].health && _npcState[i].yy - 0x10 <= _npcState[0].xx && _npcState[0].xx <= _npcState[i].yy + 0x23) {
 				bladeTakeHit();
 				bladeTakeHit();
 			}
@@ -625,7 +622,7 @@ void DragonArcade::arcade4085() {
 		_npcState[14].ttmPage = 0x28;
 	}
 	if (_npcState[0].health != 0 && ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone || _arcadeTTM._startYOffset < -6)
-		&& _npcState[14].val1 - 0x10 <= _npcState[0].val1 && _npcState[0].val1 <= _npcState[14].val1 + 0x23) {
+		&& _npcState[14].xx - 0x10 <= _npcState[0].xx && _npcState[0].xx <= _npcState[14].xx + 0x23) {
 		bladeTakeHit();
 		bladeTakeHit();
 		if (_npcState[0].health == 0) {
@@ -644,8 +641,8 @@ void DragonArcade::arcade4085() {
 	}
 }
 
-bool DragonArcade::isAbsFoundValOver990() {
-	return abs(_foundValueFrom3d30Array) > 990;
+bool DragonArcade::isFloorNotFound() {
+	return abs(_foundFloorY) > 990;
 }
 
 
@@ -659,9 +656,8 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 		break;
 	case 1:
-		/* stage 1 */
-		if (!_isMovingStage && xblock == 0x80 && 0 < _int0b5c && _bladeState1 == 0) {
-			_scrollXOffset -= _int0b5c;
+		if (!_isMovingStage && xblock == 0x80 && 0 < _scrollVelocityX && _bladeState1 == 0) {
+			_scrollXOffset -= _scrollVelocityX;
 			arcade2445();
 			return 1;
 		}
@@ -677,10 +673,9 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 		break;
 	case 2:
-		/* stage 2 */
-		if ((!_isMovingStage && xblock == 0x90 && 0 < _int0b5c && _bladeState1 == 0) ||
-			(!_isMovingStage && xblock == 0xe9 && 0 < _int0b5c && _bladeState1 == 0)) {
-			_scrollXOffset -= _int0b5c;
+		if ((!_isMovingStage && xblock == 0x90 && 0 < _scrollVelocityX && _bladeState1 == 0) ||
+			(!_isMovingStage && xblock == 0xe9 && 0 < _scrollVelocityX && _bladeState1 == 0)) {
+			_scrollXOffset -= _scrollVelocityX;
 			arcade2445();
 			return 1;
 		}
@@ -709,8 +704,9 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 		break;
 	case 4:
-		/* stage 4 */
-		if (-2 < _arcadeTTM._startYOffset && 0x81 < _npcState[0].val1 && _npcState[0].val1 < 0xc9 && _npcState[0].health != 0) {
+		/*
+		**FIXME**: Blade Dropping off screen.. this triggers at the start and shouldn't??
+		if (-2 < _arcadeTTM._startYOffset && 129 < _npcState[0].xx && _npcState[0].xx < 201 && _npcState[0].health != 0) {
 			playSfx(0x57);
 			setFinishCountdownIfLessThan0(0x14);
 			if (_haveBigGun) {
@@ -724,11 +720,11 @@ uint16 DragonArcade::moveToNextStage() {
 			_npcState[0].health = 0;
 			_npcState[0].byte15 = 2;
 			return 1;
-		}
+		} */
 
 		if (_scrollXOffset < 0x100) {
-			if (_isMovingStage == 0 && xblock == 0x54 && 0 < _int0b5c && _bladeState1 == 0) {
-				_scrollXOffset -= _int0b5c;
+			if (_isMovingStage == 0 && xblock == 0x54 && 0 < _scrollVelocityX && _bladeState1 == 0) {
+				_scrollXOffset -= _scrollVelocityX;
 				arcade2445();
 				return 1;
 			}
@@ -740,8 +736,7 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 		break;
 	case 6:
-		/* stage 6 */
-		if (_stillLoadingScriptsMaybe == 0 && _scrollXOffset < 0x100) {
+		if (!_stillLoadingScriptsMaybe && _scrollXOffset < 0x100) {
 			_scrollXOffset = 0x100;
 			_npcState[0].x -= 8;
 			if (_npcState[0].x < 0) {
@@ -750,6 +745,7 @@ uint16 DragonArcade::moveToNextStage() {
 		} else if (0x11f < xblock && _arcadeNotMovingLeftFlag == 0) {
 			_arcadeNotMovingLeftFlag = 1;
 		}
+		break;
 	default:
 		break;
 	}
@@ -762,81 +758,81 @@ void DragonArcade::playSFX55AndStuff() {
 	playSfx(0x55);
 	_bladeState1 = 7;
 	_uint0a17 = 0;
-	// TODO: What are thess?
-	_int3d18 = 0;
-	_int0b5a = 0xf;
-	_int0b5c = 0;
+	// TODO: What are these?
+	_ttmYAdjust = 0;
+	_int0b5a = 15;
+	_scrollVelocityX = 0;
 	_npcState[0].ttmPage = _bladeStateOffset + 0x43;
 }
 
 
-void DragonArcade::fill3d30ArrayFromLevelData() {
-	_array3d30.clear();
-	_array3d1c.clear();
+void DragonArcade::updateFloorsUnderBlade() {
+	_floorY.clear();
+	_floorFlag.clear();
 	Common::Array<uint> offsets;
-	const Common::Array<ArcadeLevelData> &levelData = _arcadeTTM.getLevelData();
+	const Common::Array<ArcadeFloor> &floorData = _arcadeTTM.getFloorData();
 
-	for (uint i = 0; i < levelData.size(); i++) {
-		if (levelData[i].x <= _npcState[0].val1 && _npcState[0].val1 <= levelData[i].x + levelData[i].y) {
-		_array3d30.push_back(levelData[i].data - 108);
-		_array3d1c.push_back(levelData[i].flag);
+	for (uint i = 0; i < floorData.size(); i++) {
+		if (floorData[i].x <= _npcState[0].xx && _npcState[0].xx <= floorData[i].x + floorData[i].width) {
+			_floorY.push_back(floorData[i].yval - 108);
+			_floorFlag.push_back(floorData[i].flag);
 		}
 	}
 }
 
-void DragonArcade::findMinIn3d30ArrayLast() {
-	_foundValueFrom3d30Array = 999;
-	for (uint i = 0; i < _array3d30.size(); i++) {
-		if (_int0b54 <= _array3d30[i] && _array3d30[i] < _foundValueFrom3d30Array) {
-			_foundValueFrom3d30Array = _array3d30[i];
-			_foundValueFrom3d1cArray = _array3d1c[i];
+void DragonArcade::findFloorMinGE() {
+	_foundFloorY = 999;
+	for (uint i = 0; i < _floorY.size(); i++) {
+		if (_currentYOffset <= _floorY[i] && _floorY[i] < _foundFloorY) {
+			_foundFloorY = _floorY[i];
+			_foundFloorFlag = _floorFlag[i];
 		}
 	}
 }
 
-void DragonArcade::findMinIn3d30ArrayFirst() {
-	_foundValueFrom3d30Array = 999;
-	for (uint i = 0; i < _array3d30.size(); i++) {
-		if (_int0b54 < _array3d30[i] && _array3d30[i] < _foundValueFrom3d30Array) {
-			_foundValueFrom3d30Array = _array3d30[i];
-			_foundValueFrom3d1cArray = _array3d1c[i];
+void DragonArcade::findFloorMinGT() {
+	_foundFloorY = 999;
+	for (uint i = 0; i < _floorY.size(); i++) {
+		if (_currentYOffset < _floorY[i] && _floorY[i] < _foundFloorY) {
+			_foundFloorY = _floorY[i];
+			_foundFloorFlag = _floorFlag[i];
 		}
 	}
 }
 
-void DragonArcade::findMatchIn3d30Array() {
-	_foundValueFrom3d30Array = -999;
-	for (uint i = 0; i < _array3d30.size(); i++) {
-		if (_array3d30[i] == _int0b54) {
-			_foundValueFrom3d30Array = _array3d30[i];
-			_foundValueFrom3d1cArray = _array3d1c[i];
+void DragonArcade::findFloorMatch() {
+	_foundFloorY = -999;
+	for (uint i = 0; i < _floorY.size(); i++) {
+		if (_floorY[i] == _currentYOffset) {
+			_foundFloorY = _floorY[i];
+			_foundFloorFlag = _floorFlag[i];
 		}
 	}
 }
 
-void DragonArcade::findMaxIn3d30Array() {
-	_foundValueFrom3d30Array = -999;
-	for (uint i = 0; i < _array3d30.size(); i++) {
-		if (_array3d30[i] < _int0b54 && _foundValueFrom3d30Array < _array3d30[i]) {
-			_foundValueFrom3d30Array = _array3d30[i];
-			_foundValueFrom3d1cArray = _array3d1c[i];
+void DragonArcade::findFloorMax() {
+	_foundFloorY = -999;
+	for (uint i = 0; i < _floorY.size(); i++) {
+		if (_floorY[i] < _currentYOffset && _foundFloorY < _floorY[i]) {
+			_foundFloorY = _floorY[i];
+			_foundFloorFlag = _floorFlag[i];
 		}
 	}
 }
 
-void DragonArcade::findMatchOrMinOrMax() {
-	findMatchIn3d30Array();
-	if (isAbsFoundValOver990()) {
-		findMinIn3d30ArrayFirst();
-		if (isAbsFoundValOver990()) {
-			findMaxIn3d30Array();
+void DragonArcade::findFloorMatchOrMinOrMax() {
+	findFloorMatch();
+	if (isFloorNotFound()) {
+		findFloorMinGT();
+		if (isFloorNotFound()) {
+			findFloorMax();
 		}
 	}
 }
 
 
 void DragonArcade::arcade2445() {
-	_int0b5c = 0;
+	_scrollVelocityX = 0;
 	_bladeState1 = 6;
 	_npcState[0].ttmPage += 0x4e;
 	_isMovingStage = true;
@@ -867,14 +863,14 @@ void DragonArcade::initValuesForStage2() {
 		_npcState[i].byte12 = 0;
 	}
 	for (int i = 3; i != 0; i--) {
-		_npcState[i].val1 = STAGE_2_VAL1[i - 1];
-		_npcState[i].val2 = STAGE_2_VAL2[i - 1];
+		_npcState[i].xx = STAGE_2_VAL1[i - 1];
+		_npcState[i].yy = STAGE_2_VAL2[i - 1];
 		_npcState[i].byte12 = STAGE_2_BYTE12[i - 1];
 		_npcState[i].ttmPage = STAGE_2_TTMPAGE[i - 1];
 		_npcState[i].byte15 = 1;
 	}
 	for (int i = 10; i < 14; i++) {
-		_npcState[i].val1 = STAGE_2_VAL1_PART2[i - 10];
+		_npcState[i].xx = STAGE_2_VAL1_PART2[i - 10];
 	}
 	/*
 	 TODO: What are these?
@@ -886,10 +882,11 @@ void DragonArcade::initValuesForStage2() {
 	 */
 }
 
-void DragonArcade::arcade2754(int16 findResult) {
+void DragonArcade::arcade2754(int16 floorY) {
 	if (0 < _finishCountdown) {
 		_finishCountdown--;
 	}
+
 	if (_finishCountdown == 0) {
 		if (_npcState[0].health == 0) {
 			if (_shouldUpdateState == 0) {
@@ -899,7 +896,7 @@ void DragonArcade::arcade2754(int16 findResult) {
 			_shouldUpdateState = 0;
 		}
 	} else {
-		_flag3d14 = 0;
+		_dontMoveBladeFlag = false;
 		if (100 < _arcadeTTM._startYOffset) {
 			_npcState[0].health = 0;
 			if (_finishCountdown < 1) {
@@ -909,57 +906,57 @@ void DragonArcade::arcade2754(int16 findResult) {
 			}
 		}
 		if (!moveToNextStage()) {
-			if (findResult < _arcadeTTM._startYOffset && _int0b54 <= findResult) {
-				arcade16de(findResult);
-			} else if (_2754Val < _arcadeTTM._startYOffset && _int0b54 <= _2754Val) {
+			if (floorY < _arcadeTTM._startYOffset && _currentYOffset <= floorY) {
+				arcade16de(floorY);
+			} else if (_lastFloorY < _arcadeTTM._startYOffset && _currentYOffset <= _lastFloorY) {
 				arcade1e83();
-				findResult = _2754Val;
-				arcade16de(_2754Val);
+				floorY = _lastFloorY;
+				arcade16de(_lastFloorY);
 			} else if (_bladeState1 == 0) {
-				if (findResult == -0x100) {
+				if (floorY == -0x100) {
 					arcade16bc();
-				} else if (_2754Val != -0x100) {
-					if (abs(_2754Val - findResult) < 16 || _nTickUpdates == 0) {
-						_arcadeTTM._startYOffset = findResult;
-					} else if (findResult < _2754Val) {
-						findMatchIn3d30Array();
+				} else if (_lastFloorY != -0x100) {
+					if (abs(_lastFloorY - floorY) < 16 || _nTickUpdates == 0) {
+						_arcadeTTM._startYOffset = floorY;
+					} else if (floorY < _lastFloorY) {
+						findFloorMatch();
 						if (((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) ||
-							(_2754Val != _foundValueFrom3d30Array)) {
-							findMinIn3d30ArrayFirst();
-							if (!isAbsFoundValOver990()) {
-								_arcadeTTM._startYOffset = _foundValueFrom3d30Array;
-								findResult = _foundValueFrom3d30Array;
+							(_lastFloorY != _foundFloorY)) {
+							findFloorMinGT();
+							if (!isFloorNotFound()) {
+								_arcadeTTM._startYOffset = _foundFloorY;
+								floorY = _foundFloorY;
 							} else {
 								arcade16bc();
 							}
 						} else {
-							_arcadeTTM._startYOffset = _2754Val;
-							findResult = _2754Val;
+							_arcadeTTM._startYOffset = _lastFloorY;
+							floorY = _lastFloorY;
 						}
-					} else if (_2754Val < findResult) {
+					} else if (_lastFloorY < floorY) {
 						if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
-							if (_arcadeTTM._startYOffset + 0x14 < findResult) {
+							if (_arcadeTTM._startYOffset + 0x14 < floorY) {
 								_bladeState1 = 1;
 								_npcState[0].ttmPage = _bladeStateOffset + 0x16;
 								_arcadeTTM._startYOffset += 10;
 								_uint0a17++;
 							} else {
-								_arcadeTTM._startYOffset = findResult;
+								_arcadeTTM._startYOffset = floorY;
 							}
 						} else {
-							findMatchOrMinOrMax();
-							_arcadeTTM._startYOffset = _foundValueFrom3d30Array;
-							findResult = _foundValueFrom3d30Array;
+							findFloorMatchOrMinOrMax();
+							_arcadeTTM._startYOffset = _foundFloorY;
+							floorY = _foundFloorY;
 						}
 					}
 				}
-			} else if ((_bladeState1 == 3 || _bladeState1 == 4) && 0x19 < abs(_2754Val - findResult) && _nTickUpdates) {
-				findResult = _2754Val;
+			} else if ((_bladeState1 == 3 || _bladeState1 == 4) && 0x19 < abs(_lastFloorY - floorY) && _nTickUpdates) {
+				floorY = _lastFloorY;
 			}
 		}
-		_npcState[0].val1 = _scrollXOffset * 8 + _npcState[0].x;
-		_int0b54 = _arcadeTTM._startYOffset;
-		_2754Val = findResult;
+		_npcState[0].xx = _scrollXOffset * 8 + _npcState[0].x;
+		_currentYOffset = _arcadeTTM._startYOffset;
+		_lastFloorY = floorY;
 	}
 }
 
@@ -999,7 +996,6 @@ void DragonArcade::arcade3e96() {
 		}
 	}
 
-
 	for (int i = 10; i < 18; i++) {
 		_npcState[i].ttmPage++;
 		if (_npcState[i].ttmPage < 2 || _npcState[i].ttmPage > 18) {
@@ -1010,8 +1006,8 @@ void DragonArcade::arcade3e96() {
 			}
 			_npcState[i].byte12 = 0xfc;
 			if (_npcState[i].ttmPage < 0xf &&
-				_npcState[i].val1 - 16 <= _npcState[0].val1 &&
-				_npcState[0].val1 <= _npcState[i].val1 + 12 && _npcState[0].health != 0 &&
+				_npcState[i].xx - 16 <= _npcState[0].xx &&
+				_npcState[0].xx <= _npcState[i].xx + 12 && _npcState[0].health != 0 &&
 				(_loadedArcadeStage != 1 || _arcadeTTM._startYOffset < -9 ||
 				 (_bladeMoveFlag & kBladeMoveRight) == kBladeMoveNone)) {
 				setFinishCountdownIfLessThan0(20);
@@ -1045,8 +1041,8 @@ void DragonArcade::updateBlade() {
 		int16 startPage = (_npcState[i].ttmPage < 30) ? 0 : 28;
 
 		if (_npcState[i].byte13 == 0 &&
-			((startPage != 0 && _npcState[i].val1 < _npcState[0].val1) ||
-			 (startPage == 0 && _npcState[0].val1 < _npcState[i].val1))) {
+			((startPage != 0 && _npcState[i].xx < _npcState[0].xx) ||
+			 (startPage == 0 && _npcState[0].xx < _npcState[i].xx))) {
 
 			if (_npcState[i].byte12 == 4 || _npcState[i].byte12 == 5) {
 				if (_npcState[i].byte12 == 4) {
@@ -1225,7 +1221,7 @@ void DragonArcade::updateBoss() {
 	case 2:
 		if (_npcState[1].ttmPage < 16) {
 			_npcState[1].ttmPage++;
-			_npcState[1].val1 += 6;
+			_npcState[1].xx += 6;
 		} else {
 			_npcState[1].byte12 = 1;
 			_npcState[1].ttmPage = 2;
@@ -1234,7 +1230,7 @@ void DragonArcade::updateBoss() {
 	case 1:
 		if (_npcState[1].ttmPage < 9) {
 			_npcState[1].ttmPage++;
-			_npcState[1].val1 -= 6;
+			_npcState[1].xx -= 6;
 		} else {
 			_npcState[1].byte12 = 5;
 			_npcState[1].ttmPage = 30;
@@ -1284,8 +1280,8 @@ void DragonArcade::updateBoss() {
 static const int16 BOSS_2_PAGE_OFFSETS[] = { 2, 2, 0xe, 0x1b, 0x21, 0x2a, 0x34, 0x3b };
 
 void DragonArcade::updateBoss2() {
-	if (_arcadeNotMovingLeftFlag && 269 < _scrollXOffset + _npcState[0].x / 8 && _scrollXOffset < 282) {
-		_int0b5c = 1;
+	if (_arcadeNotMovingLeftFlag > 0 && 269 < _scrollXOffset + _npcState[0].x / 8 && _scrollXOffset < 282) {
+		_scrollVelocityX = 1;
 		_scrollXOffset++;
 		_npcState[0].x -= 8;
 	}
@@ -1311,11 +1307,11 @@ void DragonArcade::updateBoss2() {
 			_npcState[1].byte12 = 4;
 			_npcState[1].ttmPage = _uint0be6 + 9;
 		}
-		if ((_nextRandomVal & 0xfU) == 7 && absDistToBoss > 20 && _npcState[1].val1 < 0x938) {
+		if ((_nextRandomVal & 0xfU) == 7 && absDistToBoss > 20 && _npcState[1].xx < 0x938) {
 			_npcState[1].byte12 = 2;
 			_npcState[1].ttmPage = _uint0be6 + 2;
 		}
-		else if (_bladeHasFired == 0 || _npcState[1].val1 < 0x939) {
+		else if (_bladeHasFired == 0 || _npcState[1].xx < 0x939) {
 			if (absDistToBoss < 0x1e) {
 				arcade34b4();
 			}
@@ -1344,9 +1340,9 @@ void DragonArcade::updateBoss2() {
 			_npcState[1].ttmPage = _uint0be6 + 2;
 		}
 		if (_uint0be6 == 0) {
-			_npcState[1].val1 = _npcState[1].val1 + 8;
+			_npcState[1].xx = _npcState[1].xx + 8;
 		} else {
-			_npcState[1].val1 = _npcState[1].val1 - 8;
+			_npcState[1].xx = _npcState[1].xx - 8;
 		}
 		if (absDistToBoss < 0x1e) {
 			arcade34b4();
@@ -1365,20 +1361,20 @@ void DragonArcade::updateBoss2() {
 			if (_nTickUpdates & 1) {
 				_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
 				if (_uint0be6 == 0) {
-					_npcState[1].val1 = _npcState[1].val1 + 6;
+					_npcState[1].xx = _npcState[1].xx + 6;
 				} else {
-					_npcState[1].val1 = _npcState[1].val1 + -6;
+					_npcState[1].xx = _npcState[1].xx + -6;
 				}
 			}
-		} else if (absDistToBoss < 40 || _npcState[1].val1 < 0x8d4) {
+		} else if (absDistToBoss < 40 || _npcState[1].xx < 0x8d4) {
 			_npcState[1].byte12 = 8;
 			_npcState[1].ttmPage = _uint0be6 + 25;
 		} else if (_nTickUpdates & 1) {
 			_npcState[1].ttmPage = _uint0be6 + 21;
 			if (_uint0be6 == 0) {
-				_npcState[1].val1 = _npcState[1].val1 + 6;
+				_npcState[1].xx = _npcState[1].xx + 6;
 			} else {
-				_npcState[1].val1 = _npcState[1].val1 + -6;
+				_npcState[1].xx = _npcState[1].xx + -6;
 			}
 		}
 		break;
@@ -1394,8 +1390,8 @@ void DragonArcade::updateBoss2() {
 		break;
 	case 2:
 	default:
-		if (_stillLoadingScriptsMaybe != 0) {
-			if ((_int0b5c == -1 && _npcState[1].x < 0x96) || (_int0b5c == 1 && 160 < _npcState[1].x)) {
+		if (_stillLoadingScriptsMaybe) {
+			if ((_scrollVelocityX == -1 && _npcState[1].x < 0x96) || (_scrollVelocityX == 1 && 160 < _npcState[1].x)) {
 				updateXScrollOffset();
 			}
 			byte bossByte12 = _npcState[1].byte12;
@@ -1459,30 +1455,30 @@ void DragonArcade::updateBoss2() {
 
 void DragonArcade::updateXScrollOffset() {
 	int16 lastScrollOffset = _scrollXOffset;
-	_scrollXOffset = CLIP(_scrollXOffset + _int0b5c, 0, 282);
+	_scrollXOffset = CLIP(_scrollXOffset + _scrollVelocityX, 0, 282);
 	if (lastScrollOffset != _scrollXOffset) {
-		_scrollXIncrement += _int0b5c;
+		_scrollXIncrement += _scrollVelocityX;
 	}
 }
 
 void DragonArcade::arcade34b4() {
 	_npcState[0].ttmPage = -1;
 	if (_npcState[0].x < 150) {
-		_int0b5c = -1;
+		_scrollVelocityX = -1;
 	} else if (_npcState[0].x < 161) {
-		_int0b5c = 0;
+		_scrollVelocityX = 0;
 	} else {
-		_int0b5c = 1;
+		_scrollVelocityX = 1;
 	}
 
 	_arcadeNotMovingLeftFlag = -1;
 	// TODO: what is this?
 	// UINT_39e5_0a1f = 1;
-	_stillLoadingScriptsMaybe = 1;
+	_stillLoadingScriptsMaybe = true;
 	_npcState[0].byte12 = -1;
 	_npcState[1].byte12 = 100;
 	_npcState[1].ttmPage = 67;
-	_npcState[1].val1 = _npcState[0].val1;
+	_npcState[1].xx = _npcState[0].xx;
 	_npcState[1].byte15 = 2;
 }
 
@@ -1602,8 +1598,10 @@ void DragonArcade::updateBladeWithInputs() {
 		return;
 
 	// TODO: What are these?
-	if ((_int0b5a != 0) && (_int0b5a--, _int0b5a == 0)) {
-		_int0b58 = 0;
+	if (_int0b5a != 0) {
+		_int0b5a--;
+		if (_int0b5a == 0)
+			_int0b58 = 0;
 	}
 
 	if ((_bladeHorizMoveAttempt & 1) == 0) {
@@ -1612,7 +1610,7 @@ void DragonArcade::updateBladeWithInputs() {
 		_bladeStateOffset = 0x7a;
 	}
 	if (_bladeState1 == 0) {
-		if (!_flag3d14) {
+		if (!_dontMoveBladeFlag) {
 			_npcState[0].ttmPage++;
 		}
 		handleMouseStates();
@@ -1655,9 +1653,9 @@ void DragonArcade::updateBladeWithInputs() {
 	case 6:
 		newPage = _bladeStateOffset + 0x4d;
 		if (_bladeStateOffset == 0) {
-			_int0b5c = 1;
+			_scrollVelocityX = 1;
 		} else {
-			_int0b5c = -1;
+			_scrollVelocityX = -1;
 		}
 		if (newPage <= _npcState[0].ttmPage + 2 && _npcState[0].ttmPage <= newPage) {
 			_npcState[0].x = _npcState[0].x + 4;
@@ -1680,7 +1678,7 @@ void DragonArcade::updateBladeWithInputs() {
 	case 9:
 		if (_npcState[0].ttmPage < 0x4f) {
 			_npcState[0].ttmPage++;
-			_int0b5c = -1;
+			_scrollVelocityX = -1;
 			moveBladeX();
 		} else {
 			handleMouseStates();
@@ -1695,8 +1693,8 @@ void DragonArcade::updateBladeWithInputs() {
 		if (_npcState[0].ttmPage < newPage) {
 			_npcState[0].ttmPage++;
 		} else {
-			_npcState[3].val1 = _npcState[0].val1 + 0x16;
-			_npcState[3].val2 = -0x20;
+			_npcState[3].xx = _npcState[0].xx + 0x16;
+			_npcState[3].yy = -0x20;
 			_npcState[3].byte12 = -2;
 			_npcState[3].ttmPage = 0x21;
 			_npcState[3].byte15 = 2;
@@ -1745,7 +1743,7 @@ void DragonArcade::updateBladeWithInputs() {
 		break;
 	}
 
-	if (!_flag3d14)
+	if (!_dontMoveBladeFlag)
 		_npcState[0].ttmPage++;
 
 	if (newPage < _npcState[0].ttmPage) {
@@ -1753,13 +1751,13 @@ void DragonArcade::updateBladeWithInputs() {
 	} else if (_uint0a17 == 0) {
 		if (_bladeState1 == 1) {
 			if (_bladeStateOffset + 0x16 == _npcState[0].ttmPage) {
-				_int3d18 = _int0b58 * -4;
+				_ttmYAdjust = _int0b58 * -4;
 				_uint0a17 = 1;
 			}
 		}
 		else if ((_bladeState1 == 2) &&
 				 (_bladeStateOffset + 0x38 == _npcState[0].ttmPage)) {
-			_int3d18 = _int0b58 * -4;
+			_ttmYAdjust = _int0b58 * -4;
 			_uint0a17 = 1;
 		}
 	} else {
@@ -1772,22 +1770,22 @@ void DragonArcade::updateBladeWithInputs() {
 			}
 		}
 		if (_bladeState1 == 1 || _bladeState1 == 2 || _bladeState1 == 5) {
-			_int3d18 += 2;
-			_arcadeTTM._startYOffset += _int3d18;
+			_ttmYAdjust += 2;
+			_arcadeTTM._startYOffset += _ttmYAdjust;
 			_npcState[0].ttmPage--;
 		}
 	}
 }
 
 void DragonArcade::moveBladeX() {
-	if (_flag3d14)
+	if (_dontMoveBladeFlag)
 		return;
 
 	if (_arcadeNotMovingLeftFlag != 0)
 		return;
 
-	if (_int0b5c < 1) {
-		if (-1 < _int0b5c) {
+	if (_scrollVelocityX < 1) {
+		if (-1 < _scrollVelocityX) {
 			// nothing
 		} else if (_scrollXOffset == 0) {
 			if (0 < _npcState[0].x)
@@ -1804,10 +1802,7 @@ void DragonArcade::moveBladeX() {
 			_bladeXMove = 4;
 		} else {
 			_bladeXMove = -4;
-			return;
 		}
-		_npcState[0].x += _bladeXMove;
-		return;
 	} else {
 		if (_scrollXOffset == 0x11a) {
 			if (_npcState[0].x < 0x140)
@@ -1825,7 +1820,6 @@ void DragonArcade::moveBladeX() {
 		} else {
 			updateXScrollOffset();
 			_bladeXMove = -4;
-			return;
 		}
 	}
 	_npcState[0].x += _bladeXMove;
@@ -1843,7 +1837,7 @@ void DragonArcade::handleMouseStates() {
 			}
 		} else {
 			moveBladeX();
-			if (_foundValueFrom3d1cArray == 0) {
+			if (_foundFloorFlag == 0) {
 				if ((_npcState[0].ttmPage < _bladeStateOffset + 0x6d) ||
 					(_bladeStateOffset + 0x70 < _npcState[0].ttmPage)) {
 					_npcState[0].ttmPage = _bladeStateOffset + 0x6d;
@@ -1896,7 +1890,7 @@ void DragonArcade::handleMouseStates() {
 		}
 
 		_int0b5a = 0;
-		_int0b5c = 0;
+		_scrollVelocityX = 0;
 		if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
 			_bladeStateOffset = 0;
 		} else {
@@ -1908,9 +1902,9 @@ void DragonArcade::handleMouseStates() {
 			_npcState[0].ttmPage = _bladeStateOffset + 0xf;
 		} else {
 			if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
-				_int0b5c = 1;
+				_scrollVelocityX = 1;
 			} else {
-				_int0b5c = -1;
+				_scrollVelocityX = -1;
 			}
 			_isMovingStage = 0;
 			_bladeState1 = 2;
@@ -1918,8 +1912,8 @@ void DragonArcade::handleMouseStates() {
 		}
 
 		if ((_bladeMoveFlagBeforeRButton & kBladeMoveRight) != 0) {
-			findMinIn3d30ArrayFirst();
-			if (!isAbsFoundValOver990()) {
+			findFloorMinGT();
+			if (!isFloorNotFound()) {
 				if (_bladeState1 == 2) {
 					_npcState[0].ttmPage = _bladeStateOffset + 0x38;
 				} else {
@@ -1927,7 +1921,7 @@ void DragonArcade::handleMouseStates() {
 				}
 				_arcadeTTM._startYOffset++;
 				_uint0a17++;
-				_int0b54 = _arcadeTTM._startYOffset;
+				_currentYOffset = _arcadeTTM._startYOffset;
 			}
 		}
 		playSfx(0x54);
@@ -1942,7 +1936,7 @@ void DragonArcade::resetStageState() {
 	_scrollXOffset = 0;
 	_nTickUpdates = 0;
 	_isMovingStage = false;
-	_int3d18 = 0;
+	_ttmYAdjust = 0;
 	_uint0a17 = 0;
 	_shouldUpdateState = 0;
 	_arcadeNotMovingLeftFlag = 0;
@@ -1993,8 +1987,8 @@ void DragonArcade::initValuesForStage() {
 	switch (_loadedArcadeStage) {
 	case 0:
 		for (int i = 1; i < 10; i++) {
-			_npcState->val1 = STAGE_0_VAL1[i - 1];
-			_npcState->val2 = STAGE_0_VAL2[i - 1];
+			_npcState->xx = STAGE_0_VAL1[i - 1];
+			_npcState->yy = STAGE_0_VAL2[i - 1];
 			_npcState->byte12 = STAGE_0_BYTE12[i - 1];
 			if (_npcState->byte12 == 5)
 				_npcState->ttmPage = 39;
@@ -2008,8 +2002,8 @@ void DragonArcade::initValuesForStage() {
 		break;
 	case 4:
 		for (int i = 1; i < 10; i++) {
-			_npcState->val1 = STAGE_4_VAL1[i - 1];
-			_npcState->val2 = STAGE_4_VAL2[i - 1];
+			_npcState->xx = STAGE_4_VAL1[i - 1];
+			_npcState->yy = STAGE_4_VAL2[i - 1];
 			_npcState->byte12 = STAGE_4_BYTE12[i - 1];
 			if (_npcState->byte12 == 5)
 				_npcState->ttmPage = 39;
@@ -2041,20 +2035,20 @@ static const int16 STAGE_0_ST_TTMPAGE[] = {
 void DragonArcade::initValuesForStage0() {
 	_someCounter40f0 = 0;
 	for (int i = 10; i < 14; i++) {
-		_npcState[i].val1 = STAGE_0_ST_INT1[i - 10];
-		_npcState[i].val2 = 2;
+		_npcState[i].xx = STAGE_0_ST_INT1[i - 10];
+		_npcState[i].yy = 2;
 		_npcState[i].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
 		_npcState[i].byte15 = 2;
 
-		_npcState[i + 4].val1 = STAGE_0_ST_INT1_2[i - 10];
-		_npcState[i + 4].val2 = -37;
+		_npcState[i + 4].xx = STAGE_0_ST_INT1_2[i - 10];
+		_npcState[i + 4].yy = -37;
 		_npcState[i + 4].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
 		_npcState[i + 4].byte15 = 2;
 	}
 	_flag40ee = true;
 	_flag40ef = true;
-	_npcState[18].val1 = 0x11f;
-	_npcState[18].val2 = -0xd;
+	_npcState[18].xx = 0x11f;
+	_npcState[18].yy = -0xd;
 	_npcState[18].byte12 = 0x1e;
 	_npcState[18].ttmPage = 0x20;
 	_npcState[18].byte15 = 2;
@@ -2063,15 +2057,15 @@ void DragonArcade::initValuesForStage0() {
 void DragonArcade::initValuesForStage3() {
 	clearAllNPCStates();
 	_bossStateUpdateCounter = 0;
-	_npcState[1].val1 = 0x99c;
-	_npcState[1].val2 = -54;
+	_npcState[1].xx = 0x99c;
+	_npcState[1].yy = -54;
 	_npcState[1].byte12 = 1;
 	_npcState[1].ttmPage = 2;
 	_npcState[1].health = 20;
 	_npcState[1].byte15 = 1;
 	_npcState[1].y = 300;
-	_npcState[2].val1 = 0x9b2;
-	_npcState[2].val2 = -57;
+	_npcState[2].xx = 0x9b2;
+	_npcState[2].yy = -57;
 	_npcState[2].byte12 = -1;
 	_npcState[2].ttmPage = 23;
 	_npcState[2].health = 0;
@@ -2097,8 +2091,8 @@ static const byte STAGE_4_ST_BYTE12[] = {
 void DragonArcade::initValuesForStage4() {
 	_someCounter40f0 = 0;
 	for (int i = 10; i < 15; i++) {
-		_npcState[i].val1 = STAGE_4_ST_INT0[i - 10];
-		_npcState[i].val2 = STAGE_4_ST_INT2[i - 10];
+		_npcState[i].xx = STAGE_4_ST_INT0[i - 10];
+		_npcState[i].yy = STAGE_4_ST_INT2[i - 10];
 		_npcState[i].ttmPage = STAGE_4_ST_TTMPAGE[i - 10];
 		_npcState[i].byte12 = STAGE_4_ST_BYTE12[i - 10];
 		_npcState[i].health = 1;
@@ -2108,8 +2102,8 @@ void DragonArcade::initValuesForStage4() {
 
 void DragonArcade::initValuesForStage6() {
 	clearAllNPCStates();
-	_npcState[1].val1 = 0x9e2;
-	_npcState[1].val2 = -3;
+	_npcState[1].xx = 0x9e2;
+	_npcState[1].yy = -3;
 	_npcState[1].ttmPage = 1;
 	_npcState[1].health = 10;
 	_npcState[1].byte15 = 1;
@@ -2168,16 +2162,22 @@ void DragonArcade::arcadeTick() {
 		return;
 	default:
 		_haveBomb = arcadeState > 20;
-		if (_haveBomb)
-			globals->setArcadeState(arcadeState - 20);
+		if (_haveBomb) {
+			arcadeState -= 20;
+			globals->setArcadeState(arcadeState);
+		}
 
 		_enemyHasSmallGun = arcadeState > 10;
-		if (_enemyHasSmallGun != 0)
-			globals->setArcadeState(arcadeState - 10);
+		if (_enemyHasSmallGun != 0) {
+			arcadeState -= 10;
+			globals->setArcadeState(arcadeState);
+		}
 
-		bool _haveBigGun = arcadeState > 2;
-		if (_haveBigGun)
-			globals->setArcadeState(arcadeState - 2);
+		_haveBigGun = arcadeState > 2;
+		if (_haveBigGun) {
+			arcadeState -= 2;
+			globals->setArcadeState(arcadeState);
+		}
 
 		_nextStage = (arcadeState & 1) ? 4 : 0;
 
@@ -2196,7 +2196,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		ttm1 = "STATIONA.TTM";
 		ttm2 = "FLAMDEAD.TTM";
 		_npcState[0].x = 160;
-		_npcState[0].val1 = 160;
+		_npcState[0].xx = 160;
 		_arcadeTTM._startYOffset = 0;
 		break;
 	case 3:
@@ -2208,7 +2208,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		ttm1 = "STATIONA.TTM";
 		ttm2 = "AARC.TTM";
 		_npcState[0].x = 140;
-		_npcState[0].val1 = 140;
+		_npcState[0].xx = 140;
 		_arcadeTTM._startYOffset = -43;
 		break;
 	case 6:
@@ -2245,7 +2245,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		_arcadeTTM.runNextPage(0);
 	}
 
-	_int0b54 = _arcadeTTM._startYOffset;
+	_currentYOffset = _arcadeTTM._startYOffset;
 	_finishCountdown = -1;
 	//INT_39e5_0be4 = 0; // this only ever gets set 0?
 	_loadedArcadeStage = stage;
@@ -2292,12 +2292,12 @@ void DragonArcade::drawBackgroundAndWeapons() {
 	}
 }
 
-void DragonArcade::drawBulletHitCircles(uint16 x, uint16 y, bool flag) {
+void DragonArcade::drawBulletHitCircles(uint16 x, uint16 y, bool colorFlag) {
 	static const byte COLORS[2][3] = { {0, 1, 9}, {0, 4, 12} };
 
 	Graphics::ManagedSurface &dst = DgdsEngine::getInstance()->_compositionBuffer;
 	for (int i = 0; i < 3; i++) {
-		byte col = COLORS[flag][i];
+		byte col = COLORS[colorFlag][i];
 		Drawing::filledCircle(x, y, 4 - i, 4 - i, &dst, col, col);
 	}
 }
@@ -2371,7 +2371,7 @@ void DragonArcade::bladeTakeHitAndCheck() {
 void DragonArcade::drawHealthBars() {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 
-	if (_npcState[0].health != _lastDrawnBladeHealth) {
+	//if (_npcState[0].health != _lastDrawnBladeHealth) {
 		Common::Rect clearRect(Common::Point(10, 155), 64, 10);
 		engine->_compositionBuffer.fillRect(clearRect, 0);
 
@@ -2381,9 +2381,9 @@ void DragonArcade::drawHealthBars() {
 		}
 
 		_lastDrawnBladeHealth = _npcState[0].health;
-	}
+	//}
 
-	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) && (_npcState[1].health != _lastDrawnBossHealth)) {
+	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) /*&& (_npcState[1].health != _lastDrawnBossHealth)*/) {
 		Common::Rect clearRect(Common::Point(10, 167), 60, 8);
 		engine->_compositionBuffer.fillRect(clearRect, 0);
 
@@ -2401,6 +2401,7 @@ void DragonArcade::redraw() {
 	if (!_dontRedrawBgndAndWeapons)
 		drawBackgroundAndWeapons();
 
+	drawScrollBmp();
 	runThenDrawBulletsInFlight();
 	_lastDrawnBladeHealth = -1;
 	_lastDrawnBossHealth = -1;
@@ -2412,6 +2413,12 @@ void DragonArcade::redraw() {
 	g_system->warpMouse(166, 158);
 }
 
+void DragonArcade::drawScrollBmp() {
+	const Common::Rect drawWin(Common::Point(8, 8), SCREEN_WIDTH - 16, 117);
+	Graphics::ManagedSurface &dst = DgdsEngine::getInstance()->_compositionBuffer;
+	_scrollImg->drawScrollBitmap(8, 8, 320 - 16, 117, _scrollXOffset, 0, drawWin, dst);
+}
+
 
 void DragonArcade::runThenDrawBulletsInFlight() {
 	// TODO: Set clip window here? 8,8,124,311
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index f0148054111..497595313be 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -44,11 +44,11 @@ enum DragonBladeMoveFlag {
 
 class ArcadeNPCState {
 public:
-	ArcadeNPCState() : val1(0), val2(0), x(0), y(0), x_11(0), y_11(0), x_12(0), y_12(0),
+	ArcadeNPCState() : xx(0), yy(0), x(0), y(0), x_11(0), y_11(0), x_12(0), y_12(0),
 		ttmPage(0), byte12(0), byte13(0), health(0), byte15(0), x_21(0), y_21(0),
 		x_22(0), y_22(0) {}
-	int16 val1;
-	int16 val2;
+	int16 xx;
+	int16 yy;
 	int16 x;
 	int16 y;
 	int16 x_11;
@@ -98,7 +98,7 @@ private:
 	void enemyTakeHit() { _npcState[1].health--; }
 	void enemyTakeHitAndCheck();
 	void playSfx(int16 num) const;
-	void drawBulletHitCircles(uint16 x, uint16 y, bool flag);
+	void drawBulletHitCircles(uint16 x, uint16 y, bool colorFlag);
 	void drawHealthBars();
 	void runThenDrawBulletsInFlight();
 	void redraw();
@@ -137,22 +137,23 @@ private:
 	void checkBossFireStage3();
 	void checkBossFireStage6();
 	void updateMouseAndJoystickStates();
-	int16 findValuesIn3d30Array();
+	int16 findFloorUnderBlade();
 	int16 checkBulletCollision(int16 num);
 	void mouseUpdate();
 	void keyboardUpdate();
 	void limitToCenterOfScreenAndUpdateCursor();
 	uint16 moveToNextStage();
-	void findMatchIn3d30Array();
-	void findMinIn3d30ArrayFirst();
-	void findMinIn3d30ArrayLast();
-	void findMatchOrMinOrMax();
-	void findMaxIn3d30Array();
-	void fill3d30ArrayFromLevelData();
-	bool isAbsFoundValOver990();
+	void findFloorMatch();
+	void findFloorMinGT();
+	void findFloorMinGE();
+	void findFloorMatchOrMinOrMax();
+	void findFloorMax();
+	void updateFloorsUnderBlade();
+	bool isFloorNotFound();
 	void playSFX55AndStuff();
 	void moveBladeX();
 	void handleMouseStates();
+	void drawScrollBmp();
 
 	int16 _lastDrawnBladeHealth;
 	int16 _lastDrawnBossHealth;
@@ -171,15 +172,15 @@ private:
 	int16 _startDifficultyMaybe;
 	int16 _bossStateUpdateCounter;
 	int16 _someCounter40f0;
-	int16 _int0b5c;
+	int16 _scrollVelocityX;
 	uint16 _uint0a17;
-	int16 _int0b54;
+	int16 _currentYOffset;
 	int16 _int0b58;
 	int16 _int0b5a;
 	int16 _int0b60;
-	int16 _int3d18;
+	int16 _ttmYAdjust;
 	uint16 _uint0be6;
-	bool _flag3d14;
+	bool _dontMoveBladeFlag;
 	int16 _scrollXIncrement;
 	int16 _lMouseButtonState;
 	int16 _rMouseButtonState;
@@ -188,9 +189,9 @@ private:
 	int16 _bladeXMove;
 	int16 _bladeHorizMoveAttempt;
 	int16 _currentArrowNum;
-	int16 _foundValueFrom3d30Array;
-	bool _foundValueFrom3d1cArray;
-	int16 _2754Val;
+	int16 _foundFloorY;
+	bool _foundFloorFlag;
+	int16 _lastFloorY;
 
 	bool _haveBigGun;
 	bool _haveBomb;
@@ -215,8 +216,8 @@ private:
 	Common::SharedPtr<Image> _arrowImg;
 	Common::SharedPtr<Image> _scrollImg;
 	DragonArcadeTTM _arcadeTTM;
-	Common::Array<int16> _array3d30;
-	Common::Array<bool> _array3d1c;
+	Common::Array<int16> _floorY;
+	Common::Array<bool> _floorFlag;
 };
 
 } // end namespace Dgds
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index 6f835c45996..a9c6fd6e7df 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -182,12 +182,12 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 	}
 	case 0xA104: // DRAW FILLED RECT
 		if (_doingInit) {
-			ArcadeLevelData data;
+			ArcadeFloor data;
 			data.x = (page - 1) * 320 + ivals[0];
-			data.y = ivals[2];
-			data.data = (byte)ivals[1];
+			data.width = ivals[2];
+			data.yval = (byte)ivals[1];
 			data.flag = false;
-			_levelData.push_back(data);
+			_floorData.push_back(data);
 		} else {
 			const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
 			compBuffer.fillRect(rect, _drawColFG);
@@ -195,12 +195,12 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		break;
 	case 0xA114: // DRAW EMPTY RECT
 		if (_doingInit) {
-			ArcadeLevelData data;
+			ArcadeFloor data;
 			data.x = (page - 1) * 320 + ivals[0];
-			data.y = ivals[2];
-			data.data = (byte)ivals[1];
+			data.width = ivals[2];
+			data.yval = (byte)ivals[1];
 			data.flag = true;
-			_levelData.push_back(data);
+			_floorData.push_back(data);
 		} else {
 			const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2] - 1, ivals[3] - 1);
 			compBuffer.drawLine(r.left, r.top, r.right, r.top, _drawColFG);
@@ -304,8 +304,8 @@ void DragonArcadeTTM::runPagesForEachNPC(int16 xScrollOffset) {
 			npcState.y_11 = 0;
 			npcState.y_22 = 0;
 			npcState.y_12 = 0;
-			 _drawXOffset = npcState.val1 - xScrollOffset * 8 - 152;
-			 _drawYOffset = npcState.val2;
+			 _drawXOffset = npcState.xx - xScrollOffset * 8 - 152;
+			 _drawYOffset = npcState.yy;
 			_currentTTMNum = npcState.byte15;
 			if (_drawXOffset > -20 || _drawXOffset < 340) {
 				runNextPage(npcState.ttmPage);
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
index 7b5a9e4e51a..a8288ecbc53 100644
--- a/engines/dgds/dragon_arcade_ttm.h
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -30,11 +30,15 @@
 
 namespace Dgds {
 
-struct ArcadeLevelData {
-	ArcadeLevelData() : x(0), y(0), data(0), flag(false) {}
+/**
+ * A segment of floor in the arcade section with a start x, width, height, and flag.
+ */
+class ArcadeFloor {
+public:
+	ArcadeFloor() : x(0), width(0), yval(0), flag(false) {}
 	int16 x;
-	int16 y;
-	byte data;
+	int16 width;
+	byte yval;
 	bool flag;
 };
 
@@ -52,7 +56,7 @@ public:
 	void freePages(uint16 num);
 	void freeShapes();
 	void runPagesForEachNPC(int16 xScrollOffset);
-	const Common::Array<ArcadeLevelData> &getLevelData() { return _levelData; }
+	const Common::Array<ArcadeFloor> &getFloorData() { return _floorData; }
 
 	uint16 _currentTTMNum;
 	int16 _currentNPCRunningTTM;
@@ -74,8 +78,8 @@ private:
 	byte _drawColFG;
 	byte _drawColBG;
 	ArcadeNPCState *_npcState;
-	// int16 _numA1x4OpsInInit; // implicit by count of items in _levelData
-	Common::Array<ArcadeLevelData> _levelData;
+	// int16 _numA1x4OpsInInit; // implicit by count of items in _floorData
+	Common::Array<ArcadeFloor> _floorData;
 
 	// Note: only a subset of the enviro members get used, but
 	// use the same structure for simplicity.
diff --git a/engines/dgds/globals.h b/engines/dgds/globals.h
index f29d802da65..30cae66926d 100644
--- a/engines/dgds/globals.h
+++ b/engines/dgds/globals.h
@@ -94,6 +94,7 @@ public:
 	int16 getGameMinsToAddOnRClick() const { return _gameMinsToAddOnRClick; }
 	int16 getGameMinsToAddOnDragFinished() const { return _gameMinsToAddOnDragFinished; }
 	int16 getGameMinsToAddOnObjInteraction() const { return _gameMinsToAddOnObjInteraction; }
+	int16 getGameIsInteractiveGlobal() { return _gameIsInteractiveGlobal; }
 
 	void setLastSceneNum(int16 num) { _lastOpcode1SceneChageNum = num; }
 


Commit: e5aaf8d063eea0348847e7d81604abb2137b8102
    https://github.com/scummvm/scummvm/commit/e5aaf8d063eea0348847e7d81604abb2137b8102
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Add keyboard and fix some bugs in Dragon arcade

Changed paths:
    engines/dgds/dgds.cpp
    engines/dgds/dgds.h
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/dragon_arcade_ttm.h
    engines/dgds/image.h
    engines/dgds/menu.cpp


diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index cd44ccb2dad..14606da6e5f 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -32,7 +32,7 @@
 #include "common/substream.h"
 #include "common/system.h"
 
-#include "common/formats/iff_container.h"
+#include "backends/keymapper/keymapper.h"
 
 #include "graphics/cursorman.h"
 #include "graphics/font.h"
@@ -536,6 +536,12 @@ Common::Error DgdsEngine::run() {
 					|| ev.type == Common::EVENT_MOUSEMOVE) {
 				mouseEvent = ev.type;
 				_lastMouse = ev.mouse;
+			} else if (ev.type == Common::EVENT_KEYDOWN) {
+				if (_dragonArcade)
+					_dragonArcade->onKeyDown(ev.kbd);
+			} else if (ev.type == Common::EVENT_KEYUP) {
+				if (_dragonArcade)
+					_dragonArcade->onKeyUp(ev.kbd);
 			}
 		}
 
@@ -702,6 +708,14 @@ bool DgdsEngine::canSaveAutosaveCurrently() {
 	return canSaveGameStateCurrently() && !_scene->hasVisibleDialog() && !_menu->menuShown() && _gameGlobals->getGameIsInteractiveGlobal();
 }
 
+void DgdsEngine::enableKeymapper() {
+	_eventMan->getKeymapper()->setEnabled(true);
+}
+
+void DgdsEngine::disableKeymapper() {
+	_eventMan->getKeymapper()->setEnabled(false);
+}
+
 Common::Error DgdsEngine::syncGame(Common::Serializer &s) {
 	//
 	// Version history:
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index 1fab810adc5..afce3d193cb 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -91,6 +91,20 @@ enum DgdsKeyEvent {
 	kDgdsKeyActivate,
 };
 
+enum DragonArcadeKeyEvent {
+	kDragonArcadeKeyLeft,
+	kDragonArcadeKeyRight,
+	kDragonArcadeKeyUp,
+	kDragonArcadeKeyDown,
+	kDragonArcadeKeyLeftUp,
+	kDragonArcadeKeyRightUp,
+	kDragonArcadeKeyLeftDown,
+	kDragonArcadeKeyRightDown,
+	kDragonArcadeKeyJumpMode,
+	kDragonArcadeKeyFire,
+};
+
+
 class DgdsEngine : public Engine {
 public:
 	Common::Platform _platform;
@@ -227,6 +241,9 @@ public:
 	static DgdsEngine *getInstance() { return static_cast<DgdsEngine *>(g_engine); }
 	void setFlipMode(bool mode) { _flipMode = mode; }
 
+	void enableKeymapper();
+	void disableKeymapper();
+
 private:
 	Common::Error syncGame(Common::Serializer &s);
 
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 9887faf2bf7..fafc9e20106 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -37,18 +37,18 @@
 
 namespace Dgds {
 
-DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1),
-	_lastDrawnBossHealth(-1), _nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _arcadeModeSomethingCounter(0),
-	_currentArcadeTT3Num(0), _shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladeStateOffset(0),
-	_mouseButtonWentDown(0), _scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0),
-	_someCounter40f0(0), _scrollVelocityX(0), _uint0a17(0), _currentYOffset(0), _int0b58(0), _int0b5a(0), _int0b60(0), _ttmYAdjust(0),
-	_uint0be6(0), _dontMoveBladeFlag(false), _scrollXIncrement(0), _lMouseButtonState(0), _rMouseButtonState(0), _lastLMouseButtonState(0),
-	_lastRMouseButtonState(0), _bladeXMove(0), _bladeHorizMoveAttempt(0), _currentArrowNum(0), _foundFloorY(0),
-	_foundFloorFlag(0), _lastFloorY(0), _arcadeNotMovingLeftFlag(0), _haveBigGun(true), _haveBomb(true),
-	_enemyHasSmallGun(false), _dontRedrawBgndAndWeapons(false), _arcadeNeedsBufferCopy(false), _flagInventoryOpened(false),
-	_initFinished(false), _stillLoadingScriptsMaybe(false), _flag40ee(false), _flag40ef(false), _bladeHasFired(false),
-	_mouseIsAvailable(false), _isMovingStage(false), _bladeMoveFlag(kBladeMoveNone), _keyStateFlags(kBladeMoveNone),
-	_bladeMoveFlagBeforeRButton(kBladeMoveNone)
+DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1), _lastDrawnBossHealth(-1),
+	_nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _arcadeModeSomethingCounter(0),
+	_shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladeStateOffset(0), _mouseButtonWentDown(0),
+	_scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0), _someCounter40f0(0),
+	_scrollVelocityX(0), _uint0a17(0), _currentYOffset(0), _int0b58(0), _int0b5a(0), _int0b60(0), _ttmYAdjust(0),
+	_uint0be6(0), _dontMoveBladeFlag(false), _scrollXIncrement(0), _lMouseButtonState(false), _rMouseButtonState(false),
+	_lastLMouseButtonState(false), _lastRMouseButtonState(false), _bladeXMove(0), _bladeHorizMoveAttempt(0),
+	_currentArrowNum(0), _foundFloorY(0), _foundFloorFlag(0), _lastFloorY(0), _arcadeNotMovingLeftFlag(0),
+	_haveBigGun(true), _haveBomb(true), _enemyHasSmallGun(false), _dontRedrawBgndAndWeapons(false),
+	_arcadeNeedsBufferCopy(false), _flagInventoryOpened(false), _initFinished(false), _stillLoadingScriptsMaybe(false),
+	_flag40ee(false), _flag40ef(false), _bladeHasFired(false), _mouseIsAvailable(false), _isMovingStage(false),
+	_bladeMoveFlag(kBladeMoveNone), _keyStateFlags(kBladeMoveNone), _bladeMoveFlagBeforeRButton(kBladeMoveNone)
 {
 }
 
@@ -71,6 +71,10 @@ void DragonArcade::finish() {
 	_arrowImg.reset();
 	_scrollImg.reset();
 	_loadedArcadeStage = -1;
+
+	DgdsEngine *engine = DgdsEngine::getInstance();
+	engine->enableKeymapper();
+
 	_initFinished = false;
 	warning("TODO: DragonArcade::finish: copy/clear some vid buffers here?");
 }
@@ -318,7 +322,7 @@ void DragonArcade::checkBladeFireAllStages() {
 	ImageFlipMode flipMode;
 
 	_bladeHasFired = false;
-	if (_npcState[0].byte15 != 0)
+	if (_npcState[0].ttmNum != 0)
 		return;
 
 	for (int i = 0; i < 8; i++) {
@@ -326,7 +330,7 @@ void DragonArcade::checkBladeFireAllStages() {
 			if (_npcState[0].ttmPage < 0x7b) {
 				flipMode = kImageFlipNone;
 			} else {
-				flipMode = kImageFlipV;
+				flipMode = kImageFlipH;
 			}
 			if (_haveBigGun) {
 				yoff = FIRE_Y_OFFSETS_BIG_GUN[i];
@@ -363,7 +367,7 @@ void DragonArcade::checkEnemyFireStage0124() {
 		for (int j = 0; j < 4; j++) {
 			if (_npcState[i].x < 0x154 && -20 < _npcState[i].x &&
 				ENEMY_FIRE_ALLOWABLE_PAGES[j] == _npcState[i].ttmPage) {
-				ImageFlipMode flipMode = (_npcState[i].ttmPage < 0x1d) ? kImageFlipNone : kImageFlipV;
+				ImageFlipMode flipMode = (_npcState[i].ttmPage < 0x1d) ? kImageFlipNone : kImageFlipH;
 				createBullet(ENEMY_FIRE_X_OFFSETS[j] + _npcState[i].xx - _scrollXOffset * 8 - 0xa0,
 							 ENEMY_FIRE_Y_OFFSETS[j] + _npcState[i].yy + 3, flipMode, 1);
 				playSfx(0x25);
@@ -382,7 +386,7 @@ void DragonArcade::checkBossFireStage3() {
 }
 
 void DragonArcade::checkBossFireStage6() {
-	ImageFlipMode flipMode = (_npcState[1].ttmPage < 0x28) ? kImageFlipNone: kImageFlipV;
+	ImageFlipMode flipMode = (_npcState[1].ttmPage < 0x28) ? kImageFlipNone: kImageFlipH;
 
 	if (_npcState[1].x < 0x154 && -20 < _npcState[1].x &&
 		(_npcState[1].ttmPage == 9 || _npcState[1].ttmPage == 0x28)) {
@@ -410,15 +414,108 @@ void DragonArcade::limitToCenterOfScreenAndUpdateCursor() {
 	//}
 }
 
+void DragonArcade::onKeyDown(Common::KeyState kbd) {
+	switch (kbd.keycode) {
+	case Common::KEYCODE_KP7:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveUp | kBladeMoveLeft);
+		break;
+	case Common::KEYCODE_KP8:
+	case Common::KEYCODE_UP:
+	case Common::KEYCODE_w:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveUp);
+		break;
+	case Common::KEYCODE_KP9:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveUp | kBladeMoveRight);
+		break;
+	case Common::KEYCODE_KP4:
+	case Common::KEYCODE_LEFT:
+	case Common::KEYCODE_a:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveLeft);
+		break;
+	case Common::KEYCODE_KP6:
+	case Common::KEYCODE_RIGHT:
+	case Common::KEYCODE_d:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveRight);
+		break;
+	case Common::KEYCODE_KP1:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveDown | kBladeMoveLeft);
+		break;
+	case Common::KEYCODE_KP2:
+	case Common::KEYCODE_DOWN:
+	case Common::KEYCODE_x:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveDown);
+		break;
+	case Common::KEYCODE_KP3:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags | kBladeMoveDown | kBladeMoveRight);
+		break;
+	case Common::KEYCODE_SPACE:
+		_lMouseButtonState = true;
+		break;
+	case Common::KEYCODE_RETURN:
+	case Common::KEYCODE_KP_ENTER:
+		_rMouseButtonState = true;
+		break;
+	default:
+		break;
+	}
+}
+
+void DragonArcade::onKeyUp(Common::KeyState kbd) {
+	switch (kbd.keycode) {
+	case Common::KEYCODE_KP7:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~(kBladeMoveUp | kBladeMoveLeft));
+		break;
+	case Common::KEYCODE_KP8:
+	case Common::KEYCODE_UP:
+	case Common::KEYCODE_w:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~kBladeMoveUp);
+		break;
+	case Common::KEYCODE_KP9:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~(kBladeMoveUp | kBladeMoveRight));
+		break;
+	case Common::KEYCODE_KP4:
+	case Common::KEYCODE_LEFT:
+	case Common::KEYCODE_a:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~kBladeMoveLeft);
+		break;
+	case Common::KEYCODE_KP6:
+	case Common::KEYCODE_RIGHT:
+	case Common::KEYCODE_d:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~kBladeMoveRight);
+		break;
+	case Common::KEYCODE_KP1:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~(kBladeMoveDown | kBladeMoveLeft));
+		break;
+	case Common::KEYCODE_KP2:
+	case Common::KEYCODE_DOWN:
+	case Common::KEYCODE_x:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~kBladeMoveDown);
+		break;
+	case Common::KEYCODE_KP3:
+		_keyStateFlags = static_cast<DragonBladeMoveFlag>(_keyStateFlags & ~(kBladeMoveDown | kBladeMoveRight));
+		break;
+	case Common::KEYCODE_SPACE:
+		_lMouseButtonState = false;
+		break;
+	case Common::KEYCODE_RETURN:
+	case Common::KEYCODE_KP_ENTER:
+		_rMouseButtonState = false;
+		break;
+	default:
+		break;
+	}
+}
+
+
 void DragonArcade::keyboardUpdate() {
-	warning("TODO: Keyboard update");
+	//warning("TODO: Keyboard update");
 	// TODO: Keyboard update.
 }
 
 void DragonArcade::mouseUpdate() {
 	limitToCenterOfScreenAndUpdateCursor();
-	_rMouseButtonState = DgdsEngine::getInstance()->getScene()->isRButtonDown();
-	_lMouseButtonState = DgdsEngine::getInstance()->getScene()->isLButtonDown();
+	_rMouseButtonState |= DgdsEngine::getInstance()->getScene()->isRButtonDown();
+	_lMouseButtonState |= DgdsEngine::getInstance()->getScene()->isLButtonDown();
 	int16 arrowRow = _currentArrowNum / 3;
 	if (arrowRow == 0) {
 		_keyStateFlags = kBladeMoveUp;
@@ -437,8 +534,8 @@ void DragonArcade::mouseUpdate() {
 void DragonArcade::updateMouseAndJoystickStates() {
 	_bladeXMove = 0;
 	_scrollXIncrement = 0;
-	_rMouseButtonState = 0;
-	_lMouseButtonState = 0;
+	_rMouseButtonState = false;
+	_lMouseButtonState = false;
 	if (!_mouseIsAvailable) {
 		//if (g_optionJoystickOnButtonState != 0) {
 		//	Joystick_ArcadeUpdate();
@@ -475,10 +572,10 @@ void DragonArcade::updateMouseAndJoystickStates() {
 		} else {
 			_bladeMoveFlag = static_cast<DragonBladeMoveFlag>(_bladeMoveFlag | kBladeMoveUp);
 		}
-		if ((_lMouseButtonState != 0) && (_lastLMouseButtonState == 0)) {
+		if (_lMouseButtonState && !_lastLMouseButtonState) {
 			_mouseButtonWentDown = 1;
 		}
-		if (_rMouseButtonState != 0 && _lastRMouseButtonState == 0 && _bladeState1 != 2 && _bladeState1 != 1) {
+		if (_rMouseButtonState && !_lastRMouseButtonState && _bladeState1 != 2 && _bladeState1 != 1) {
 			_mouseButtonWentDown = 2;
 			_bladeMoveFlagBeforeRButton = _bladeMoveFlag;
 		}
@@ -501,6 +598,7 @@ int16 DragonArcade::findFloorUnderBlade() {
 		}
 	} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
 		if ((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) {
+			/* Not moving up or down */
 			findFloorMatch();
 			if (isFloorNotFound()) {
 				findFloorMinGT();
@@ -564,7 +662,7 @@ void DragonArcade::arcade16de(int16 param) {
 	else {
 		_npcState[0].ttmPage = _bladeStateOffset + 0x17;
 	}
-	_npcState[0].byte15 = 0;
+	_npcState[0].ttmNum = 0;
 	_arcadeTTM._startYOffset = param;
 	_uint0a17 = 0;
 	_bladeState1 = 0;
@@ -627,7 +725,7 @@ void DragonArcade::arcade4085() {
 		bladeTakeHit();
 		if (_npcState[0].health == 0) {
 			/* blade dies! */
-			_npcState[0].byte15 = 2;
+			_npcState[0].ttmNum = 2;
 			_npcState[0].ttmPage = 0x22;
 			_npcState[0].byte12 = 14;
 			_bladeState1 = 14;
@@ -867,7 +965,7 @@ void DragonArcade::initValuesForStage2() {
 		_npcState[i].yy = STAGE_2_VAL2[i - 1];
 		_npcState[i].byte12 = STAGE_2_BYTE12[i - 1];
 		_npcState[i].ttmPage = STAGE_2_TTMPAGE[i - 1];
-		_npcState[i].byte15 = 1;
+		_npcState[i].ttmNum = 1;
 	}
 	for (int i = 10; i < 14; i++) {
 		_npcState[i].xx = STAGE_2_VAL1_PART2[i - 10];
@@ -916,6 +1014,7 @@ void DragonArcade::arcade2754(int16 floorY) {
 				if (floorY == -0x100) {
 					arcade16bc();
 				} else if (_lastFloorY != -0x100) {
+					// Pop to new floor level if close enough
 					if (abs(_lastFloorY - floorY) < 16 || _nTickUpdates == 0) {
 						_arcadeTTM._startYOffset = floorY;
 					} else if (floorY < _lastFloorY) {
@@ -1011,7 +1110,7 @@ void DragonArcade::arcade3e96() {
 				(_loadedArcadeStage != 1 || _arcadeTTM._startYOffset < -9 ||
 				 (_bladeMoveFlag & kBladeMoveRight) == kBladeMoveNone)) {
 				setFinishCountdownIfLessThan0(20);
-				_npcState[0].byte15 = 2;
+				_npcState[0].ttmNum = 2;
 				_npcState[0].health = 0;
 				if (_haveBigGun) {
 					_npcState[0].ttmPage = 0x19;
@@ -1267,7 +1366,7 @@ void DragonArcade::updateBoss() {
 		if (_npcState[3].health == 0) {
 			_npcState[3].byte12 = -3;
 			_npcState[3].ttmPage = 39;
-			_npcState[3].byte15 = 1;
+			_npcState[3].ttmNum = 1;
 		}
 	} else if (_npcState[3].byte12 == -3) {
 		_npcState[3].ttmPage++;
@@ -1479,7 +1578,7 @@ void DragonArcade::arcade34b4() {
 	_npcState[1].byte12 = 100;
 	_npcState[1].ttmPage = 67;
 	_npcState[1].xx = _npcState[0].xx;
-	_npcState[1].byte15 = 2;
+	_npcState[1].ttmNum = 2;
 }
 
 void DragonArcade::decBossHealth() {
@@ -1525,7 +1624,7 @@ void DragonArcade::bladeTakeHit() {
 			_npcState[0].ttmPage = _bladeStateOffset + 0x62;
 		}
 		setFinishCountdownIfLessThan0(15);
-		_npcState[0].byte15 = 0;
+		_npcState[0].ttmNum = 0;
 		_mouseButtonWentDown = 0x80;
 	} else {
 		playSfx(0x29);
@@ -1538,6 +1637,8 @@ void DragonArcade::initIfNeeded() {
 		return;
 
 	DgdsEngine *engine = DgdsEngine::getInstance();
+	engine->disableKeymapper();
+
 	const char *ttmName;
 	const char *scrollBmpName;
 	const char *songName;
@@ -1697,9 +1798,9 @@ void DragonArcade::updateBladeWithInputs() {
 			_npcState[3].yy = -0x20;
 			_npcState[3].byte12 = -2;
 			_npcState[3].ttmPage = 0x21;
-			_npcState[3].byte15 = 2;
+			_npcState[3].ttmNum = 2;
 			_npcState[3].health = 20;
-			_npcState[0].byte15 = 0;
+			_npcState[0].ttmNum = 0;
 			handleMouseStates();
 		}
 		return;
@@ -1858,7 +1959,7 @@ void DragonArcade::handleMouseStates() {
 			/* use a bomb */
 			_bladeState1 = 0xb;
 			_haveBomb = false;
-			_npcState[0].byte15 = 2;
+			_npcState[0].ttmNum = 2;
 			if (_haveBigGun == 0) {
 				_npcState[0].ttmPage = 4;
 			} else {
@@ -1941,7 +2042,7 @@ void DragonArcade::resetStageState() {
 	_shouldUpdateState = 0;
 	_arcadeNotMovingLeftFlag = 0;
 	_npcState[0].byte12 = 1;
-	_npcState[0].byte15 = 0;
+	_npcState[0].ttmNum = 0;
 	_npcState[0].health = (4 - _startDifficultyMaybe) * 3 + 20;
 	_npcState[0].ttmPage = 3;
 	_npcState[1].health = 0;
@@ -1952,31 +2053,31 @@ void DragonArcade::resetStageState() {
 	_bladeMoveFlag = kBladeMoveNone;
 }
 
-static const int STAGE_0_VAL1[] = {
+static const int STAGE_0_NPC_XX[] = {
 	0x191, 0x1BB, 0x1F5,
 	0x25B, 0x2D3, 0x341,
 	0x535, 0x5C9, 0x623
 };
 
-static const byte STAGE_0_VAL2[] = {
+static const byte STAGE_0_NPC_YY[] = {
 	0, 0, 0, 0xd8, 0xd8, 0, 0, 0, 0xd8
 };
 
-static const byte STAGE_0_BYTE12[] = {
+static const byte STAGE_0_NPC_BYTE12[] = {
 	5, 4, 4, 5, 4, 5, 4, 5, 5
 };
 
-static const int STAGE_4_VAL1[] = {
+static const int STAGE_4_NPC_XX_1[] = {
 	0x169, 0x19D, 0x1B9,
 	0x30D, 0x32D, 0x457,
 	0x4DB, 0x501, -1
 };
 
-static const byte STAGE_4_VAL2[] = {
+static const byte STAGE_4_NPC_YY_1[] = {
 	0, 0, 0, 0, 0, 0xd8, 0, 0, 0xd8
 };
 
-static const byte STAGE_4_BYTE12[] = {
+static const byte STAGE_4_NPC_BYTE12_1[] = {
 	5, 4, 4, 5, 4, 5, 5, 4, 5
 };
 
@@ -1987,28 +2088,30 @@ void DragonArcade::initValuesForStage() {
 	switch (_loadedArcadeStage) {
 	case 0:
 		for (int i = 1; i < 10; i++) {
-			_npcState->xx = STAGE_0_VAL1[i - 1];
-			_npcState->yy = STAGE_0_VAL2[i - 1];
-			_npcState->byte12 = STAGE_0_BYTE12[i - 1];
-			if (_npcState->byte12 == 5)
-				_npcState->ttmPage = 39;
+			_npcState[i].xx = STAGE_0_NPC_XX[i - 1];
+			_npcState[i].yy = STAGE_0_NPC_YY[i - 1];
+			_npcState[i].byte12 = STAGE_0_NPC_BYTE12[i - 1];
+			if (_npcState[i].byte12 == 5)
+				_npcState[i].ttmPage = 39;
 			else
-				_npcState->ttmPage = 30;
-			initValuesForStage0();
+				_npcState[i].ttmPage = 30;
+			_npcState[i].ttmNum = 1;
 		}
+		initValuesForStage0();
 		break;
 	case 3:
 		initValuesForStage3();
 		break;
 	case 4:
 		for (int i = 1; i < 10; i++) {
-			_npcState->xx = STAGE_4_VAL1[i - 1];
-			_npcState->yy = STAGE_4_VAL2[i - 1];
-			_npcState->byte12 = STAGE_4_BYTE12[i - 1];
-			if (_npcState->byte12 == 5)
-				_npcState->ttmPage = 39;
+			_npcState[i].xx = STAGE_4_NPC_XX_1[i - 1];
+			_npcState[i].yy = STAGE_4_NPC_YY_1[i - 1];
+			_npcState[i].byte12 = STAGE_4_NPC_BYTE12_1[i - 1];
+			if (_npcState[i].byte12 == 5)
+				_npcState[i].ttmPage = 39;
 			else
-				_npcState->ttmPage = 30;
+				_npcState[i].ttmPage = 30;
+			_npcState[i].ttmNum = 1;
 		}
 		initValuesForStage4();
 		break;
@@ -2038,12 +2141,12 @@ void DragonArcade::initValuesForStage0() {
 		_npcState[i].xx = STAGE_0_ST_INT1[i - 10];
 		_npcState[i].yy = 2;
 		_npcState[i].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
-		_npcState[i].byte15 = 2;
+		_npcState[i].ttmNum = 2;
 
 		_npcState[i + 4].xx = STAGE_0_ST_INT1_2[i - 10];
 		_npcState[i + 4].yy = -37;
 		_npcState[i + 4].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
-		_npcState[i + 4].byte15 = 2;
+		_npcState[i + 4].ttmNum = 2;
 	}
 	_flag40ee = true;
 	_flag40ef = true;
@@ -2051,7 +2154,7 @@ void DragonArcade::initValuesForStage0() {
 	_npcState[18].yy = -0xd;
 	_npcState[18].byte12 = 0x1e;
 	_npcState[18].ttmPage = 0x20;
-	_npcState[18].byte15 = 2;
+	_npcState[18].ttmNum = 2;
 }
 
 void DragonArcade::initValuesForStage3() {
@@ -2062,21 +2165,21 @@ void DragonArcade::initValuesForStage3() {
 	_npcState[1].byte12 = 1;
 	_npcState[1].ttmPage = 2;
 	_npcState[1].health = 20;
-	_npcState[1].byte15 = 1;
+	_npcState[1].ttmNum = 1;
 	_npcState[1].y = 300;
 	_npcState[2].xx = 0x9b2;
 	_npcState[2].yy = -57;
 	_npcState[2].byte12 = -1;
 	_npcState[2].ttmPage = 23;
 	_npcState[2].health = 0;
-	_npcState[2].byte15 = 1;
+	_npcState[2].ttmNum = 1;
 }
 
-static const int16 STAGE_4_ST_INT0[] = {
+static const int16 STAGE_4_NPC_XX[] = {
 	0x1F9, 0x551, 0x362, 0x592, 0x7AF
 };
 
-static const int16 STAGE_4_ST_INT2[] = {
+static const int16 STAGE_4_NPC_YY[] = {
 	8, 8, 6, 6, 6
 };
 
@@ -2091,12 +2194,12 @@ static const byte STAGE_4_ST_BYTE12[] = {
 void DragonArcade::initValuesForStage4() {
 	_someCounter40f0 = 0;
 	for (int i = 10; i < 15; i++) {
-		_npcState[i].xx = STAGE_4_ST_INT0[i - 10];
-		_npcState[i].yy = STAGE_4_ST_INT2[i - 10];
+		_npcState[i].xx = STAGE_4_NPC_XX[i - 10];
+		_npcState[i].yy = STAGE_4_NPC_YY[i - 10];
 		_npcState[i].ttmPage = STAGE_4_ST_TTMPAGE[i - 10];
 		_npcState[i].byte12 = STAGE_4_ST_BYTE12[i - 10];
 		_npcState[i].health = 1;
-		_npcState[i].byte15 = 2;
+		_npcState[i].ttmNum = 2;
 	}
 }
 
@@ -2106,7 +2209,7 @@ void DragonArcade::initValuesForStage6() {
 	_npcState[1].yy = -3;
 	_npcState[1].ttmPage = 1;
 	_npcState[1].health = 10;
-	_npcState[1].byte15 = 1;
+	_npcState[1].ttmNum = 1;
 	_npcState[1].byte12 = 1;
 	_stillLoadingScriptsMaybe = false;
 }
@@ -2225,19 +2328,20 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 	}
 
 	if (stage != _loadedArcadeStage) {
-		_currentArcadeTT3Num = 1;
+		int16 envNum;
+		_arcadeTTM._currentTTMNum = 1;
 		_arcadeTTM.freeShapes();
 		_arcadeTTM.freePages(1);
 		//g_TT3ScriptDataPtrs[1][0] = nullptr;
 		//g_TT3ScriptDataPtrs[1][1] = nullptr;
-		_currentArcadeTT3Num = 2;
+		_arcadeTTM._currentTTMNum = 2;
 		_arcadeTTM.freeShapes();
 		_arcadeTTM.freePages(2);
-		_currentArcadeTT3Num = 1;
-		int16 envNum = _arcadeTTM.load(ttm1);
+		_arcadeTTM._currentTTMNum = 1;
+		envNum = _arcadeTTM.load(ttm1);
 		_arcadeTTM.finishTTMParse(envNum);
 		_arcadeTTM.runNextPage(0);
-		_currentArcadeTT3Num = 2;
+		_arcadeTTM._currentTTMNum = 2;
 		//g_TT3ScriptDataPtrs[2][0] = nullptr;
 		//g_TT3ScriptDataPtrs[2][1] = nullptr;
 		envNum = _arcadeTTM.load(ttm2);
@@ -2247,7 +2351,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 
 	_currentYOffset = _arcadeTTM._startYOffset;
 	_finishCountdown = -1;
-	//INT_39e5_0be4 = 0; // this only ever gets set 0?
+	_stillLoadingScriptsMaybe = 0;
 	_loadedArcadeStage = stage;
 	initValuesForStage();
 }
@@ -2330,7 +2434,7 @@ void DragonArcade::createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16
 		if (_bullets[i]._state == kBulletInactive) {
 			_bullets[i]._state = kBulletFlying;
 			_bullets[i]._x = x;
-			_bullets[i]._y = x;
+			_bullets[i]._y = y;
 			_bullets[i]._flipMode = flipMode;
 			_bullets[i]._var1 = var1;
 			if (var1 == 3)
@@ -2361,7 +2465,7 @@ void DragonArcade::bladeTakeHitAndCheck() {
 			_npcState[0].ttmPage = _bladeState1 + 98;
 		}
 		setFinishCountdownIfLessThan0(15);
-		_npcState[0].byte15 = 0;
+		_npcState[0].ttmNum = 0;
 		_mouseButtonWentDown = 0x80;
 	} else {
 		playSfx(41);
@@ -2372,8 +2476,8 @@ void DragonArcade::drawHealthBars() {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 
 	//if (_npcState[0].health != _lastDrawnBladeHealth) {
-		Common::Rect clearRect(Common::Point(10, 155), 64, 10);
-		engine->_compositionBuffer.fillRect(clearRect, 0);
+		const Common::Rect clearRect1(Common::Point(10, 155), 64, 10);
+		engine->_compositionBuffer.fillRect(clearRect1, 0);
 
 		for (int i = 1; i <= _npcState[0].health; i++) {
 			int x = 8 + i * 2;
@@ -2384,8 +2488,8 @@ void DragonArcade::drawHealthBars() {
 	//}
 
 	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) /*&& (_npcState[1].health != _lastDrawnBossHealth)*/) {
-		Common::Rect clearRect(Common::Point(10, 167), 60, 8);
-		engine->_compositionBuffer.fillRect(clearRect, 0);
+		const Common::Rect clearRect2(Common::Point(10, 167), 60, 8);
+		engine->_compositionBuffer.fillRect(clearRect2, 0);
 
 		byte color = (_loadedArcadeStage == 3) ? 2 : 9;
 
@@ -2425,7 +2529,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 	_arcadeTTM.runPagesForEachNPC(_scrollXOffset);
 
 	const Common::Rect screenWin(SCREEN_WIDTH, SCREEN_HEIGHT);
-	_arcadeTTM._currentTTMNum = _npcState[0].byte15;
+	_arcadeTTM._currentTTMNum = _npcState[0].ttmNum;
 	_npcState[0].x_11 = 0;
 	_npcState[0].x_12 = 0;
 	_npcState[0].x_21 = 0;
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index 497595313be..a49a26d25a4 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -45,7 +45,7 @@ enum DragonBladeMoveFlag {
 class ArcadeNPCState {
 public:
 	ArcadeNPCState() : xx(0), yy(0), x(0), y(0), x_11(0), y_11(0), x_12(0), y_12(0),
-		ttmPage(0), byte12(0), byte13(0), health(0), byte15(0), x_21(0), y_21(0),
+		ttmPage(0), byte12(0), byte13(0), health(0), ttmNum(0), x_21(0), y_21(0),
 		x_22(0), y_22(0) {}
 	int16 xx;
 	int16 yy;
@@ -59,7 +59,7 @@ public:
 	int8 byte12;
 	int8 byte13;
 	int8 health;
-	int8 byte15; /* Set to 0, 1 or 2 */
+	int8 ttmNum; /* Set to 0, 1 or 2 */
 	int16 x_21;
 	int16 y_21;
 	int16 x_22;
@@ -86,6 +86,8 @@ public:
 	DragonArcade();
 
 	void arcadeTick();
+	void onKeyDown(Common::KeyState kbd);
+	void onKeyUp(Common::KeyState kbd);
 
 private:
 	void initIfNeeded();
@@ -161,7 +163,6 @@ private:
 	int16 _loadedArcadeStage;
 	int16 _nextStage;
 	int16 _arcadeModeSomethingCounter;
-	int16 _currentArcadeTT3Num;
 	int16 _shouldUpdateState;
 	int16 _finishCountdown;
 	int16 _bladeState1;
@@ -182,10 +183,10 @@ private:
 	uint16 _uint0be6;
 	bool _dontMoveBladeFlag;
 	int16 _scrollXIncrement;
-	int16 _lMouseButtonState;
-	int16 _rMouseButtonState;
-	int16 _lastLMouseButtonState;
-	int16 _lastRMouseButtonState;
+	bool _lMouseButtonState;
+	bool _rMouseButtonState;
+	bool _lastLMouseButtonState;
+	bool _lastRMouseButtonState;
 	int16 _bladeXMove;
 	int16 _bladeHorizMoveAttempt;
 	int16 _currentArrowNum;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index a9c6fd6e7df..79c670bc425 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -29,12 +29,17 @@
 
 namespace Dgds {
 
+Common::String ArcadeFloor::dump() {
+	return Common::String::format("ArcadeFloor<x:%d-%d y:%d flg:%d>",
+				x, x + width, yval, flag);
+}
+
+
 DragonArcadeTTM::DragonArcadeTTM(ArcadeNPCState *npcState) : _npcState(npcState),
 	_currentTTMNum(0), _currentNPCRunningTTM(0), _drawXOffset(0), _drawYOffset(0),
 	_startYOffset(0), _doingInit(false), _drawColBG(0), _drawColFG(0)
 {
 	ARRAYCLEAR(_shapes3);
-	ARRAYCLEAR(_brushes);
 }
 
 void DragonArcadeTTM::clearDataPtrs() {
@@ -51,6 +56,7 @@ int16 DragonArcadeTTM::load(const char *filename) {
 	for (envNum = 0; envNum < ARRAYSIZE(_ttmEnvs); envNum++) {
 		if (_ttmEnvs[envNum].scr == nullptr) {
 			env = &_ttmEnvs[envNum];
+			debug("Arcade TTM load %s into env %d", filename, envNum);
 			break;
 		}
 	}
@@ -102,7 +108,7 @@ int16 DragonArcadeTTM::runNextPage(int16 pageNum) {
 	//UINT_39e5_3ca2 = 0;
 
 	if (pageNum < _ttmEnvs[_currentTTMNum]._totalFrames && pageNum > -1 &&
-	_ttmEnvs[_currentTTMNum]._frameOffsets[pageNum] > -1) {
+			_ttmEnvs[_currentTTMNum]._frameOffsets[pageNum] > -1) {
 		return runScriptPage(pageNum);
 	} else {
 		return 0;
@@ -124,14 +130,16 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		engine->adsInterpreter()->setScriptDelay((int)(ivals[0] * MS_PER_FRAME));
 		break;
 	case 0x1031: // SET BRUSH
+		//debug("Set brush %d for slot %d", ivals[0], _currentTTMNum);
 		if (!_shapes2[_currentTTMNum]) {
-			_brushes[_currentTTMNum] = 0;
+			_brushes[_currentTTMNum].reset();
 		} else {
-			_brushes[_currentTTMNum] = ivals[0];
+			_brushes[_currentTTMNum] = Brush(_shapes2[_currentTTMNum], ivals[0]);
 		}
 		break;
 	case 0x1051: // SET SHAPE
 		_shapes3[_currentTTMNum] = ivals[0];
+		//debug("Set img %d into slot %d", ivals[0], _currentTTMNum);
 		_shapes[_currentTTMNum] = _allShapes[ivals[0] * 5 + _currentTTMNum];
 		_shapes2[_currentTTMNum] = _allShapes[ivals[0] * 5 + _currentTTMNum];
 		break;
@@ -187,6 +195,7 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 			data.width = ivals[2];
 			data.yval = (byte)ivals[1];
 			data.flag = false;
+			debug("Floor: %s", data.dump().c_str());
 			_floorData.push_back(data);
 		} else {
 			const Common::Rect rect(Common::Point(ivals[0], ivals[1]), ivals[2], ivals[3]);
@@ -200,6 +209,7 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 			data.width = ivals[2];
 			data.yval = (byte)ivals[1];
 			data.flag = true;
+			debug("Floor: %s", data.dump().c_str());
 			_floorData.push_back(data);
 		} else {
 			const Common::Rect r(Common::Point(ivals[0], ivals[1]), ivals[2] - 1, ivals[3] - 1);
@@ -234,18 +244,19 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		else if (op == 0xa532)
 			flipMode = kImageFlipHV;
 
-		Common::Rect drawWin(SCREEN_WIDTH, SCREEN_HEIGHT);
+		// Only draw in the scroll area
+		const Common::Rect drawWin(Common::Point(8, 8), SCREEN_WIDTH - 16, 117);
 		if (_currentNPCRunningTTM == 0) {
 			int16 x = ivals[0] + _npcState[0].x - 152;
 			int16 y = ivals[1] + _startYOffset + 2;
-			if (_shapes[_currentTTMNum])
-				_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
+			if (_brushes[_currentTTMNum].isValid())
+				_brushes[_currentTTMNum].getShape()->drawBitmap(_brushes[_currentTTMNum].getFrame(), x, y, drawWin, compBuffer, flipMode);
 			_npcState[0].y = ivals[1];
 		} else {
 			int16 x = ivals[0] + _drawXOffset;
 			int16 y = ivals[1] + _drawYOffset + 2;
-			if (_shapes[_currentTTMNum])
-				_shapes[_currentTTMNum]->drawBitmap(_brushes[_currentTTMNum], x, y, drawWin, compBuffer, flipMode);
+			if (_brushes[_currentTTMNum].isValid())
+				_brushes[_currentTTMNum].getShape()->drawBitmap(_brushes[_currentTTMNum].getFrame(), x, y, drawWin, compBuffer, flipMode);
 			_npcState[_currentNPCRunningTTM].x = ivals[0];
 			_npcState[_currentNPCRunningTTM].y = ivals[1];
 		}
@@ -254,6 +265,7 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 	case 0xF02F: {
 		_shapes[_currentTTMNum].reset(new Image(engine->getResourceManager(), engine->getDecompressor()));
 		_shapes[_currentTTMNum]->loadBitmap(sval);
+		debug("Load img %s into slot %d", sval.c_str(), _currentTTMNum);
 		_shapes2[_currentTTMNum] = _shapes[_currentTTMNum];
 		_allShapes[_shapes3[_currentTTMNum] * 5 + _currentTTMNum] = _shapes[_currentTTMNum];
 		break;
@@ -306,7 +318,7 @@ void DragonArcadeTTM::runPagesForEachNPC(int16 xScrollOffset) {
 			npcState.y_12 = 0;
 			 _drawXOffset = npcState.xx - xScrollOffset * 8 - 152;
 			 _drawYOffset = npcState.yy;
-			_currentTTMNum = npcState.byte15;
+			_currentTTMNum = npcState.ttmNum;
 			if (_drawXOffset > -20 || _drawXOffset < 340) {
 				runNextPage(npcState.ttmPage);
 			}
diff --git a/engines/dgds/dragon_arcade_ttm.h b/engines/dgds/dragon_arcade_ttm.h
index a8288ecbc53..344fe94ee3e 100644
--- a/engines/dgds/dragon_arcade_ttm.h
+++ b/engines/dgds/dragon_arcade_ttm.h
@@ -40,6 +40,33 @@ public:
 	int16 width;
 	byte yval;
 	bool flag;
+
+	Common::String dump();
+};
+
+
+/**
+The regular TTM interpreter always uses the environment's shape for the brushes,
+but the arcade one stores brushes as pointers to the exact frame within the shape.
+
+In practice this may make no difference - maybe we can track use shapes2 and
+store the frame number?
+*/
+class Brush {
+public:
+	Brush() : _frame(0) {}
+	Brush(const Common::SharedPtr<Image> &shape, int16 frame) : _shape(shape), _frame(frame) {}
+
+	void reset() {
+		_shape.reset();
+		_frame = 0;
+	}
+	bool isValid() const { return _shape && _shape->loadedFrameCount() > _frame; }
+	const Common::SharedPtr<Image> &getShape() const { return _shape; }
+	int16 getFrame() const { return _frame; }
+private:
+	Common::SharedPtr<Image> _shape;
+	int16 _frame;
 };
 
 struct ArcadeNPCState;
@@ -70,10 +97,10 @@ private:
 	int16 handleOperation(TTMEnviro &env, int16 page, uint16 op, byte count, const int16 *ivals, const Common::String &sval);
 
 	int16 _shapes3[6];
-	Common::SharedPtr<Image> _shapes2[6];
 	Common::SharedPtr<Image> _shapes[6];
+	Common::SharedPtr<Image> _shapes2[6];
 	Common::SharedPtr<Image> _allShapes[30];
-	int16 _brushes[6];
+	Brush _brushes[6];
 
 	byte _drawColFG;
 	byte _drawColBG;
diff --git a/engines/dgds/image.h b/engines/dgds/image.h
index abcd28acd7d..ea33653e106 100644
--- a/engines/dgds/image.h
+++ b/engines/dgds/image.h
@@ -43,8 +43,8 @@ class ResourceManager;
 
 enum ImageFlipMode {
 	kImageFlipNone = 0,
-	kImageFlipH = 1,
-	kImageFlipV = 2,
+	kImageFlipV = 1,
+	kImageFlipH = 2,
 	kImageFlipHV = 3,
 };
 
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index bd715394950..95b34063fe6 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -350,7 +350,8 @@ void Menu::onMouseLUp(const Common::Point &mouse) {
 	// Click animation
 	if (dynamic_cast<ButtonGadget *>(gadget)) {
 		gadget->toggle(false);
-		isToggle = updateOptionsGadget(gadget);
+		if (_curMenu == kMenuOptions)
+			isToggle = updateOptionsGadget(gadget);
 		drawMenu(_curMenu);
 		g_system->delayMillis(500);
 		gadget->toggle(true);


Commit: 7b353c0dda5cbefcda30b5488f1045397bc6f6f2
    https://github.com/scummvm/scummvm/commit/7b353c0dda5cbefcda30b5488f1045397bc6f6f2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Fix small dragon arcade bugs

Changed paths:
    engines/dgds/dgds.cpp
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/menu.cpp


diff --git a/engines/dgds/dgds.cpp b/engines/dgds/dgds.cpp
index 14606da6e5f..22c31efe7c6 100644
--- a/engines/dgds/dgds.cpp
+++ b/engines/dgds/dgds.cpp
@@ -462,8 +462,6 @@ Common::Error DgdsEngine::run() {
 	init(false);
 	loadGameFiles();
 
-	// changeScene(55); // to test DRAGON intro sequence (after credits)
-
 	// If a savegame was selected from the launcher, load it now.
 	int saveSlot = ConfMan.getInt("save_slot");
 	if (saveSlot != -1)
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index fafc9e20106..274873b21bd 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -38,7 +38,7 @@
 namespace Dgds {
 
 DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1), _lastDrawnBossHealth(-1),
-	_nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _arcadeModeSomethingCounter(0),
+	_nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _attemptCounter(0),
 	_shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladeStateOffset(0), _mouseButtonWentDown(0),
 	_scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0), _someCounter40f0(0),
 	_scrollVelocityX(0), _uint0a17(0), _currentYOffset(0), _int0b58(0), _int0b5a(0), _int0b60(0), _ttmYAdjust(0),
@@ -46,7 +46,7 @@ DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1),
 	_lastLMouseButtonState(false), _lastRMouseButtonState(false), _bladeXMove(0), _bladeHorizMoveAttempt(0),
 	_currentArrowNum(0), _foundFloorY(0), _foundFloorFlag(0), _lastFloorY(0), _arcadeNotMovingLeftFlag(0),
 	_haveBigGun(true), _haveBomb(true), _enemyHasSmallGun(false), _dontRedrawBgndAndWeapons(false),
-	_arcadeNeedsBufferCopy(false), _flagInventoryOpened(false), _initFinished(false), _stillLoadingScriptsMaybe(false),
+	/*_arcadeNeedsBufferCopy(false), _flagInventoryOpened(false),*/ _initFinished(false), _stillLoadingScriptsMaybe(false),
 	_flag40ee(false), _flag40ef(false), _bladeHasFired(false), _mouseIsAvailable(false), _isMovingStage(false),
 	_bladeMoveFlag(kBladeMoveNone), _keyStateFlags(kBladeMoveNone), _bladeMoveFlagBeforeRButton(kBladeMoveNone)
 {
@@ -89,10 +89,10 @@ bool DragonArcade::doTickUpdate() {
 
 	_nextRandomVal = _getNextRandom();
 
-	if (!_arcadeNeedsBufferCopy) {
+	//if (!_arcadeNeedsBufferCopy) {
 		updateMouseAndJoystickStates();
 		updateBladeWithInputs();
-	}
+	//}
 
 	int16 floorY = findFloorUnderBlade();
 	arcade2754(floorY);
@@ -241,7 +241,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 				case 1:
 				case 2:
 				case 4:
-					if (_loadedArcadeStage == 4 || _npcState[i].byte12 < '\x1e') {
+					if (_loadedArcadeStage == 4 || _npcState[i].byte12 < 0x1e) {
 						if (_bullets[num]._var1 != 1) {
 							playSfx(0x56);
 							_npcState[i].byte12 = 1;
@@ -254,7 +254,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 						}
 						break;
 					}
-					if (_npcState[i].byte12 == '\x1e') {
+					if (_npcState[i].byte12 == 0x1e) {
 						_flag40ee = 0;
 					} else {
 						_flag40ef = 0;
@@ -355,7 +355,7 @@ void DragonArcade::checkBladeFireAllStages() {
 }
 
 
-static const int16 ENEMY_FIRE_ALLOWABLE_PAGES[] = { 3, 0xC, 0x1F, 0x28 };
+static const int16 ENEMY_FIRE_ALLOWABLE_PAGES[] = { 3, 12, 31, 40 };
 static const int16 ENEMY_FIRE_X_OFFSETS[] = { 0xB1, 0xB3, 0x77, 0x75, };
 static const int16 ENEMY_FIRE_Y_OFFSETS[] = { 0x4E, 0x56, 0x4D, 0x55,};
 
@@ -365,8 +365,9 @@ void DragonArcade::checkEnemyFireStage0124() {
 			continue;
 
 		for (int j = 0; j < 4; j++) {
-			if (_npcState[i].x < 0x154 && -20 < _npcState[i].x &&
+			if (_npcState[i].x < 340 && -20 < _npcState[i].x &&
 				ENEMY_FIRE_ALLOWABLE_PAGES[j] == _npcState[i].ttmPage) {
+				debug("enemy %d @ %d firing type %d on page %d", i, _npcState[i].x, j, _npcState[i].ttmPage);
 				ImageFlipMode flipMode = (_npcState[i].ttmPage < 0x1d) ? kImageFlipNone : kImageFlipH;
 				createBullet(ENEMY_FIRE_X_OFFSETS[j] + _npcState[i].xx - _scrollXOffset * 8 - 0xa0,
 							 ENEMY_FIRE_Y_OFFSETS[j] + _npcState[i].yy + 3, flipMode, 1);
@@ -534,8 +535,8 @@ void DragonArcade::mouseUpdate() {
 void DragonArcade::updateMouseAndJoystickStates() {
 	_bladeXMove = 0;
 	_scrollXIncrement = 0;
-	_rMouseButtonState = false;
-	_lMouseButtonState = false;
+	//_rMouseButtonState = false;
+	//_lMouseButtonState = false;
 	if (!_mouseIsAvailable) {
 		//if (g_optionJoystickOnButtonState != 0) {
 		//	Joystick_ArcadeUpdate();
@@ -666,7 +667,6 @@ void DragonArcade::arcade16de(int16 param) {
 	_arcadeTTM._startYOffset = param;
 	_uint0a17 = 0;
 	_bladeState1 = 0;
-	// TODO: What are these ?
 	_ttmYAdjust = 0;
 	_int0b5a = 15;
 }
@@ -802,8 +802,6 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 		break;
 	case 4:
-		/*
-		**FIXME**: Blade Dropping off screen.. this triggers at the start and shouldn't??
 		if (-2 < _arcadeTTM._startYOffset && 129 < _npcState[0].xx && _npcState[0].xx < 201 && _npcState[0].health != 0) {
 			playSfx(0x57);
 			setFinishCountdownIfLessThan0(0x14);
@@ -816,9 +814,9 @@ uint16 DragonArcade::moveToNextStage() {
 			_mouseButtonWentDown = 0x80;
 			_npcState[0].byte12 = 13;
 			_npcState[0].health = 0;
-			_npcState[0].byte15 = 2;
+			_npcState[0].ttmNum = 2;
 			return 1;
-		} */
+		}
 
 		if (_scrollXOffset < 0x100) {
 			if (_isMovingStage == 0 && xblock == 0x54 && 0 < _scrollVelocityX && _bladeState1 == 0) {
@@ -856,7 +854,6 @@ void DragonArcade::playSFX55AndStuff() {
 	playSfx(0x55);
 	_bladeState1 = 7;
 	_uint0a17 = 0;
-	// TODO: What are these?
 	_ttmYAdjust = 0;
 	_int0b5a = 15;
 	_scrollVelocityX = 0;
@@ -970,14 +967,11 @@ void DragonArcade::initValuesForStage2() {
 	for (int i = 10; i < 14; i++) {
 		_npcState[i].xx = STAGE_2_VAL1_PART2[i - 10];
 	}
-	/*
-	 TODO: What are these?
-	 INT_39e5_3f6c = 0x52f;
-	 INT_39e5_3f6e = -0xd;
-	 BYTE_39e5_3f7e = 0x1f;
-	 INT_39e5_3f7c = 0x20;
-	 BYTE_39e5_3f81 = 2;
-	 */
+	_npcState[18].xx = 0x52f;
+	_npcState[18].yy = -13;
+	_npcState[18].byte12 = 31;
+	_npcState[18].ttmPage = 32;
+	_npcState[18].ttmNum = 2;
 }
 
 void DragonArcade::arcade2754(int16 floorY) {
@@ -1688,7 +1682,7 @@ void DragonArcade::initIfNeeded() {
 	drawBackgroundAndWeapons();
 	loadTTMScriptsForStage(_nextStage);
 	_initFinished = true;
-	_arcadeModeSomethingCounter = 0;
+	_attemptCounter = 0;
 	g_system->warpMouse(166, 158);
 	_dontRedrawBgndAndWeapons = true;
 	redraw();
@@ -1698,7 +1692,6 @@ void DragonArcade::updateBladeWithInputs() {
 	if (_stillLoadingScriptsMaybe)
 		return;
 
-	// TODO: What are these?
 	if (_int0b5a != 0) {
 		_int0b5a--;
 		if (_int0b5a == 0)
@@ -1855,9 +1848,7 @@ void DragonArcade::updateBladeWithInputs() {
 				_ttmYAdjust = _int0b58 * -4;
 				_uint0a17 = 1;
 			}
-		}
-		else if ((_bladeState1 == 2) &&
-				 (_bladeStateOffset + 0x38 == _npcState[0].ttmPage)) {
+		} else if (_bladeState1 == 2 && _bladeStateOffset + 0x38 == _npcState[0].ttmPage) {
 			_ttmYAdjust = _int0b58 * -4;
 			_uint0a17 = 1;
 		}
@@ -1954,7 +1945,7 @@ void DragonArcade::handleMouseStates() {
 			}
 		}
 	} else if (_mouseButtonWentDown == 1) {
-		if (_loadedArcadeStage == 3 && _haveBomb != 0 && _npcState[1].health != 0 &&
+		if (_loadedArcadeStage == 3 && _haveBomb && _npcState[1].health != 0 &&
 			  0x19 < abs(_npcState[1].y - _npcState[0].y) && abs(_npcState[1].x - _npcState[0].x) < 0x28) {
 			/* use a bomb */
 			_bladeState1 = 0xb;
@@ -1973,7 +1964,7 @@ void DragonArcade::handleMouseStates() {
 			_npcState[0].ttmPage = _bladeStateOffset + 0x24;
 		}
 	} else if (_mouseButtonWentDown == 2) {
-		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == 0) {
+		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == kBladeMoveNone) {
 			_bladeMoveFlag = static_cast<DragonBladeMoveFlag>(_bladeMoveFlagBeforeRButton | (_bladeHorizMoveAttempt & (kBladeMoveLeft | kBladeMoveRight)));
 		} else {
 			_bladeMoveFlag = _bladeMoveFlagBeforeRButton;
@@ -1981,7 +1972,7 @@ void DragonArcade::handleMouseStates() {
 		}
 
 		if ((_bladeMoveFlag & kBladeMoveUp) == kBladeMoveNone) {
-			if (_int0b58 + 1 < 5) {
+			if (_int0b58 < 4) {
 				_int0b58++;
 			} else {
 				_int0b58 = 4;
@@ -1998,9 +1989,9 @@ void DragonArcade::handleMouseStates() {
 			_bladeStateOffset = 0x7a;
 		}
 
-		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == 0) {
+		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == kBladeMoveNone) {
 			_bladeState1 = 1;
-			_npcState[0].ttmPage = _bladeStateOffset + 0xf;
+			_npcState[0].ttmPage = _bladeStateOffset + 15;
 		} else {
 			if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
 				_scrollVelocityX = 1;
@@ -2012,7 +2003,7 @@ void DragonArcade::handleMouseStates() {
 			_npcState[0].ttmPage = _bladeStateOffset + 0x2d;
 		}
 
-		if ((_bladeMoveFlagBeforeRButton & kBladeMoveRight) != 0) {
+		if ((_bladeMoveFlagBeforeRButton & kBladeMoveDown) != kBladeMoveNone) {
 			findFloorMinGT();
 			if (!isFloorNotFound()) {
 				if (_bladeState1 == 2) {
@@ -2103,7 +2094,9 @@ void DragonArcade::initValuesForStage() {
 		initValuesForStage3();
 		break;
 	case 4:
-		for (int i = 1; i < 10; i++) {
+		// Note: The original also only does 8 NPCs here even though the arrays have
+		// 9 values in them (note the last x value is -1).
+		for (int i = 1; i < 9; i++) {
 			_npcState[i].xx = STAGE_4_NPC_XX_1[i - 1];
 			_npcState[i].yy = STAGE_4_NPC_YY_1[i - 1];
 			_npcState[i].byte12 = STAGE_4_NPC_BYTE12_1[i - 1];
@@ -2235,7 +2228,7 @@ void DragonArcade::arcadeTick() {
 			globals->setArcadeState(6);
 			return;
 		}
-		_arcadeModeSomethingCounter++;
+		_attemptCounter++;
 		checkToOpenMenu();
 		globals->setArcadeState(0);
 		return;
@@ -2247,21 +2240,24 @@ void DragonArcade::arcadeTick() {
 		finish();
 		return;
 	case 10:
+		// Restart? No.
 		fadeInAndClearScreen();
 		finish();
 		globals->setArcadeState(_shouldUpdateState + 6);
 		return;
 	case 20:
+		// Restart? Yes.
 		globals->setArcadeState(30);
 		return;
 	case 30:
+		// Do (re)start
 		loadTTMScriptsForStage(_nextStage);
 		// These don't seem to ever be used?
 		// UINT_39e5_0d0e = 0;
 		// UINT_39e5_0d10 = 0;
 		globals->setArcadeState(5);
-		_arcadeNeedsBufferCopy = true;
-		_flagInventoryOpened = false;
+		//_arcadeNeedsBufferCopy = true;
+		//flagInventoryOpened = false;
 		return;
 	default:
 		_haveBomb = arcadeState > 20;
@@ -2407,7 +2403,7 @@ void DragonArcade::drawBulletHitCircles(uint16 x, uint16 y, bool colorFlag) {
 }
 
 void DragonArcade::checkToOpenMenu() {
-	if (_arcadeModeSomethingCounter < 5) {
+	if (_attemptCounter < 5) {
 		// Open menu 45, hightlight widget 139
 		DgdsEngine::getInstance()->setMenuToTrigger(kMenuReplayArcade);
 	} else {
@@ -2528,7 +2524,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 	// TODO: Set clip window here? 8,8,124,311
 	_arcadeTTM.runPagesForEachNPC(_scrollXOffset);
 
-	const Common::Rect screenWin(SCREEN_WIDTH, SCREEN_HEIGHT);
+	const Common::Rect screenWin(Common::Point(8, 8), SCREEN_WIDTH - 16, 117);
 	_arcadeTTM._currentTTMNum = _npcState[0].ttmNum;
 	_npcState[0].x_11 = 0;
 	_npcState[0].x_12 = 0;
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index a49a26d25a4..588f3a94077 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -162,7 +162,7 @@ private:
 	uint16 _nextRandomVal;
 	int16 _loadedArcadeStage;
 	int16 _nextStage;
-	int16 _arcadeModeSomethingCounter;
+	int16 _attemptCounter;
 	int16 _shouldUpdateState;
 	int16 _finishCountdown;
 	int16 _bladeState1;
@@ -198,8 +198,9 @@ private:
 	bool _haveBomb;
 	bool _enemyHasSmallGun;
 	bool _dontRedrawBgndAndWeapons;
-	bool _arcadeNeedsBufferCopy;
-	bool _flagInventoryOpened;
+	// maybe don't need these
+	//bool _arcadeNeedsBufferCopy;
+	//bool _flagInventoryOpened;
 	bool _initFinished;
 	bool _stillLoadingScriptsMaybe;
 	bool _flag40ee;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index 79c670bc425..5c53e2f11c8 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -105,6 +105,7 @@ void DragonArcadeTTM::finishTTMParse(int16 envNum) {
 
 int16 DragonArcadeTTM::runNextPage(int16 pageNum) {
 	_shapes2[_currentTTMNum] = _shapes[_currentTTMNum];
+	// TODO: what is this?
 	//UINT_39e5_3ca2 = 0;
 
 	if (pageNum < _ttmEnvs[_currentTTMNum]._totalFrames && pageNum > -1 &&
@@ -251,14 +252,14 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 			int16 y = ivals[1] + _startYOffset + 2;
 			if (_brushes[_currentTTMNum].isValid())
 				_brushes[_currentTTMNum].getShape()->drawBitmap(_brushes[_currentTTMNum].getFrame(), x, y, drawWin, compBuffer, flipMode);
-			_npcState[0].y = ivals[1];
+			_npcState[0].y = y;
 		} else {
 			int16 x = ivals[0] + _drawXOffset;
 			int16 y = ivals[1] + _drawYOffset + 2;
 			if (_brushes[_currentTTMNum].isValid())
 				_brushes[_currentTTMNum].getShape()->drawBitmap(_brushes[_currentTTMNum].getFrame(), x, y, drawWin, compBuffer, flipMode);
-			_npcState[_currentNPCRunningTTM].x = ivals[0];
-			_npcState[_currentNPCRunningTTM].y = ivals[1];
+			_npcState[_currentNPCRunningTTM].x = x;
+			_npcState[_currentNPCRunningTTM].y = y;
 		}
 		break;
 	}
@@ -316,8 +317,8 @@ void DragonArcadeTTM::runPagesForEachNPC(int16 xScrollOffset) {
 			npcState.y_11 = 0;
 			npcState.y_22 = 0;
 			npcState.y_12 = 0;
-			 _drawXOffset = npcState.xx - xScrollOffset * 8 - 152;
-			 _drawYOffset = npcState.yy;
+			_drawXOffset = npcState.xx - xScrollOffset * 8 - 152;
+			_drawYOffset = npcState.yy;
 			_currentTTMNum = npcState.ttmNum;
 			if (_drawXOffset > -20 || _drawXOffset < 340) {
 				runNextPage(npcState.ttmPage);
diff --git a/engines/dgds/menu.cpp b/engines/dgds/menu.cpp
index 95b34063fe6..76de0ce82f6 100644
--- a/engines/dgds/menu.cpp
+++ b/engines/dgds/menu.cpp
@@ -31,6 +31,7 @@
 
 #include "dgds/includes.h"
 #include "dgds/font.h"
+#include "dgds/globals.h"
 #include "dgds/menu.h"
 #include "dgds/music.h"
 #include "dgds/request.h"
@@ -111,6 +112,13 @@ enum MenuButtonIds {
 	kMenuRestartYes = 163,
 	kMenuRestartNo = 164,
 
+	// For Dragon arcade
+	kMenuDragonReplayArcadeYes = 139,
+	kMenuDragonReplayArcadeNo = 140,
+
+	kMenuDragonFrustratedArcadeWin = 147,
+	kMenuDragonFrustratedArcadeKeepTrying = 148,
+
 	kMenuGameOverQuit = 169,
 	kMenuGameOverRestart = 168,
 	kMenuGameOverRestore = 170,
@@ -495,6 +503,22 @@ void Menu::handleClick(const Common::Point &mouse) {
 		drawMenu(_curMenu);
 		break;
 	}
+	case kMenuDragonReplayArcadeYes:
+	case kMenuDragonReplayArcadeNo:
+		if (engine->getGameId() == GID_DRAGON && _curMenu == kMenuReplayArcade) {
+			DragonGlobals *dragonGlobals = static_cast<DragonGlobals *>(engine->getGameGlobals());
+			dragonGlobals->setArcadeState(clickedMenuItem == kMenuDragonReplayArcadeYes ? 20 : 10);
+			_curMenu = kMenuNone;
+		}
+		break;
+	case kMenuDragonFrustratedArcadeWin:
+	case kMenuDragonFrustratedArcadeKeepTrying:
+		if (engine->getGameId() == GID_DRAGON && _curMenu == kMenuArcadeFrustrated) {
+			DragonGlobals *dragonGlobals = static_cast<DragonGlobals *>(engine->getGameGlobals());
+			dragonGlobals->setArcadeState(clickedMenuItem == kMenuDragonFrustratedArcadeWin ? 6 : 20);
+			_curMenu = kMenuNone;
+		}
+		break;
 	case kMenuTankTrainSkipArcade:
 		hideMenu();
 		if (currentScene == 73)


Commit: 836010fa7e9191a44de27ad4bb59560d705e490b
    https://github.com/scummvm/scummvm/commit/836010fa7e9191a44de27ad4bb59560d705e490b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Clean up dragon arcade code slightly

Changed paths:
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/dragon_arcade_ttm.cpp
    engines/dgds/globals.cpp


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 274873b21bd..c7ea20f0f95 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -43,8 +43,8 @@ DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1),
 	_scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0), _someCounter40f0(0),
 	_scrollVelocityX(0), _uint0a17(0), _currentYOffset(0), _int0b58(0), _int0b5a(0), _int0b60(0), _ttmYAdjust(0),
 	_uint0be6(0), _dontMoveBladeFlag(false), _scrollXIncrement(0), _lMouseButtonState(false), _rMouseButtonState(false),
-	_lastLMouseButtonState(false), _lastRMouseButtonState(false), _bladeXMove(0), _bladeHorizMoveAttempt(0),
-	_currentArrowNum(0), _foundFloorY(0), _foundFloorFlag(0), _lastFloorY(0), _arcadeNotMovingLeftFlag(0),
+	_lastLMouseButtonState(false), _lastRMouseButtonState(false), _bladeXMove(0), _bladeHorizMoveAttempt(kBladeMoveNone),
+	_currentArrowNum(0), _foundFloorY(0), _foundFloorFlag(false), _lastFloorY(0), _someMoveDirection(0),
 	_haveBigGun(true), _haveBomb(true), _enemyHasSmallGun(false), _dontRedrawBgndAndWeapons(false),
 	/*_arcadeNeedsBufferCopy(false), _flagInventoryOpened(false),*/ _initFinished(false), _stillLoadingScriptsMaybe(false),
 	_flag40ee(false), _flag40ef(false), _bladeHasFired(false), _mouseIsAvailable(false), _isMovingStage(false),
@@ -80,19 +80,15 @@ void DragonArcade::finish() {
 }
 
 bool DragonArcade::doTickUpdate() {
-	// TODO: Copy video buffers here?
-
+	// Note: original has a few buffer copy adjustments here,
+	// but we never need them I think because we clear+flip every time.
 	if (_finishCountdown == 0)
 		return false;
 
-	// TODO: Set video mask here?
-
 	_nextRandomVal = _getNextRandom();
 
-	//if (!_arcadeNeedsBufferCopy) {
-		updateMouseAndJoystickStates();
-		updateBladeWithInputs();
-	//}
+	updateMouseAndJoystickStates();
+	updateBladeWithInputs();
 
 	int16 floorY = findFloorUnderBlade();
 	arcade2754(floorY);
@@ -156,31 +152,27 @@ void DragonArcade::updateBullets() {
 
 		if (_bullets[i]._state == kBulletFlying) {
 			if (_bullets[i]._var1 == 3) {
-				_bullets[i]._y += _bullets[i]._speed;
+				_bullets[i]._y += _bullets[i]._ySpeed;
 			}
-			if (_bullets[i]._flipMode == 0) {
+			if (_bullets[i]._flipMode == kImageFlipNone) {
 				_bullets[i]._x -= (_scrollXIncrement * 8 - 10);
-				if (_bullets[i]._x < 0x141) {
-					int iVar2 = checkBulletCollision(i);
-					if (iVar2 != 0) {
-						if (iVar2 < 1) {
-							_bullets[i]._state = kBulletHittingEnemy;
-						} else {
-							_bullets[i]._state = kBulletHittingBlade;
-						}
+				if (_bullets[i]._x < 321) {
+					int16 collisionResult = checkBulletCollision(i);
+					if (collisionResult == -1) {
+						_bullets[i]._state = kBulletHittingEnemy;
+					} else if (collisionResult == 1) {
+						_bullets[i]._state = kBulletHittingBlade;
 					}
 					continue;
 				}
 			} else {
 				_bullets[i]._x -= (_scrollXIncrement * 8 + 10);
-				if (-0x29 < _bullets[i]._x) {
-					int iVar2 = checkBulletCollision(i);
-					if (iVar2 != 0) {
-						if (iVar2 < 1) {
-							_bullets[i]._state = kBulletHittingEnemy;
-						} else {
-							_bullets[i]._state = kBulletHittingBlade;
-						}
+				if (_bullets[i]._x > -41) {
+					int16 collisionResult = checkBulletCollision(i);
+					if (collisionResult == -1) {
+						_bullets[i]._state = kBulletHittingEnemy;
+					} else if (collisionResult == 1) {
+						_bullets[i]._state = kBulletHittingBlade;
 					}
 					continue;
 				}
@@ -255,9 +247,9 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 						break;
 					}
 					if (_npcState[i].byte12 == 0x1e) {
-						_flag40ee = 0;
+						_flag40ee = false;
 					} else {
-						_flag40ef = 0;
+						_flag40ef = false;
 					}
 					_npcState[i].byte12 = 0xf8;
 					_npcState[i].ttmPage = 0x21;
@@ -550,20 +542,20 @@ void DragonArcade::updateMouseAndJoystickStates() {
 		_bladeMoveFlag = kBladeMoveNone;
 		if ((_keyStateFlags & kBladeMoveRight) == kBladeMoveNone) {
 			if ((_keyStateFlags & kBladeMoveLeft) != kBladeMoveNone) {
-				if (_arcadeNotMovingLeftFlag) {
-					_arcadeNotMovingLeftFlag = 0;
+				if (_someMoveDirection) {
+					_someMoveDirection = 0;
 				}
 				_bladeMoveFlag = kBladeMoveLeft;
 				if (_bladeState1 == 0) {
 					_scrollVelocityX = -1;
-					_bladeHorizMoveAttempt = 1;
+					_bladeHorizMoveAttempt = kBladeMoveLeft;
 				}
 			}
 		} else {
 			_bladeMoveFlag = kBladeMoveRight;
 			if (_bladeState1 == 0) {
 				_scrollVelocityX = 1;
-				_bladeHorizMoveAttempt = 2;
+				_bladeHorizMoveAttempt = kBladeMoveRight;
 			}
 		}
 		if ((_keyStateFlags & kBladeMoveUp) == kBladeMoveNone) {
@@ -734,7 +726,7 @@ void DragonArcade::arcade4085() {
 	}
 
 	_someCounter40f0++;
-	if (_someCounter40f0 == 0x3c) {
+	if (_someCounter40f0 == 60) {
 		_someCounter40f0 = 0;
 	}
 }
@@ -819,7 +811,7 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 
 		if (_scrollXOffset < 0x100) {
-			if (_isMovingStage == 0 && xblock == 0x54 && 0 < _scrollVelocityX && _bladeState1 == 0) {
+			if (!_isMovingStage && xblock == 0x54 && 0 < _scrollVelocityX && _bladeState1 == 0) {
 				_scrollXOffset -= _scrollVelocityX;
 				arcade2445();
 				return 1;
@@ -838,8 +830,8 @@ uint16 DragonArcade::moveToNextStage() {
 			if (_npcState[0].x < 0) {
 				_npcState[0].x = 0;
 			}
-		} else if (0x11f < xblock && _arcadeNotMovingLeftFlag == 0) {
-			_arcadeNotMovingLeftFlag = 1;
+		} else if (0x11f < xblock && _someMoveDirection == 0) {
+			_someMoveDirection = 1;
 		}
 		break;
 	default:
@@ -850,7 +842,7 @@ uint16 DragonArcade::moveToNextStage() {
 }
 
 void DragonArcade::playSFX55AndStuff() {
-	_isMovingStage = 0;
+	_isMovingStage = false;
 	playSfx(0x55);
 	_bladeState1 = 7;
 	_uint0a17 = 0;
@@ -864,13 +856,12 @@ void DragonArcade::playSFX55AndStuff() {
 void DragonArcade::updateFloorsUnderBlade() {
 	_floorY.clear();
 	_floorFlag.clear();
-	Common::Array<uint> offsets;
 	const Common::Array<ArcadeFloor> &floorData = _arcadeTTM.getFloorData();
 
-	for (uint i = 0; i < floorData.size(); i++) {
-		if (floorData[i].x <= _npcState[0].xx && _npcState[0].xx <= floorData[i].x + floorData[i].width) {
-			_floorY.push_back(floorData[i].yval - 108);
-			_floorFlag.push_back(floorData[i].flag);
+	for (const auto &floor : floorData) {
+		if (floor.x <= _npcState[0].xx && _npcState[0].xx <= floor.x + floor.width) {
+			_floorY.push_back(floor.yval - 108);
+			_floorFlag.push_back(floor.flag);
 		}
 	}
 }
@@ -933,11 +924,11 @@ void DragonArcade::arcade2445() {
 	_isMovingStage = true;
 }
 
-static const int16 STAGE_2_VAL1[] = {
+static const int16 STAGE_2_XX[] = {
 	0x6A3, 0x6CD, 0x7C3
 };
 
-static const int16 STAGE_2_VAL2[] = {
+static const int16 STAGE_2_YY[] = {
 	0, 0, 0xe9
 };
 
@@ -958,8 +949,8 @@ void DragonArcade::initValuesForStage2() {
 		_npcState[i].byte12 = 0;
 	}
 	for (int i = 3; i != 0; i--) {
-		_npcState[i].xx = STAGE_2_VAL1[i - 1];
-		_npcState[i].yy = STAGE_2_VAL2[i - 1];
+		_npcState[i].xx = STAGE_2_XX[i - 1];
+		_npcState[i].yy = STAGE_2_YY[i - 1];
 		_npcState[i].byte12 = STAGE_2_BYTE12[i - 1];
 		_npcState[i].ttmPage = STAGE_2_TTMPAGE[i - 1];
 		_npcState[i].ttmNum = 1;
@@ -1234,7 +1225,7 @@ void DragonArcade::updateBlade() {
 
 
 void DragonArcade::updateBoss() {
-	_npcState[2].ttmPage = _npcState[2].ttmPage + 1;
+	_npcState[2].ttmPage++;
 	if (29 < _npcState[2].ttmPage) {
 		_npcState[2].ttmPage = 23;
 	}
@@ -1373,7 +1364,7 @@ void DragonArcade::updateBoss() {
 static const int16 BOSS_2_PAGE_OFFSETS[] = { 2, 2, 0xe, 0x1b, 0x21, 0x2a, 0x34, 0x3b };
 
 void DragonArcade::updateBoss2() {
-	if (_arcadeNotMovingLeftFlag > 0 && 269 < _scrollXOffset + _npcState[0].x / 8 && _scrollXOffset < 282) {
+	if (_someMoveDirection > 0 && 269 < _scrollXOffset + _npcState[0].x / 8 && _scrollXOffset < 282) {
 		_scrollVelocityX = 1;
 		_scrollXOffset++;
 		_npcState[0].x -= 8;
@@ -1403,39 +1394,37 @@ void DragonArcade::updateBoss2() {
 		if ((_nextRandomVal & 0xfU) == 7 && absDistToBoss > 20 && _npcState[1].xx < 0x938) {
 			_npcState[1].byte12 = 2;
 			_npcState[1].ttmPage = _uint0be6 + 2;
-		}
-		else if (_bladeHasFired == 0 || _npcState[1].xx < 0x939) {
+		} else if (!_bladeHasFired || _npcState[1].xx < 0x939) {
 			if (absDistToBoss < 0x1e) {
 				arcade34b4();
 			}
-		}
-		else {
+		} else {
 			_npcState[1].byte12 = 6;
 			_npcState[1].ttmPage = _uint0be6 + 13;
 		}
 		break;
 	case 4:
 		if (_npcState[1].ttmPage < (_uint0be6 + 0x1f)) {
-			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+			_npcState[1].ttmPage++;
 		}
 		break;
 	case 3:
 		if (_npcState[1].ttmPage < (_uint0be6 + 12)) {
-			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+			_npcState[1].ttmPage++;
 		} else {
 			_npcState[1].byte12 = 1;
 			_npcState[1].ttmPage = _uint0be6 + 1;
 		}
 		break;
 	case 1:
-		_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		_npcState[1].ttmPage++;
 		if ((_uint0be6 + 8) <= _npcState[1].ttmPage) {
 			_npcState[1].ttmPage = _uint0be6 + 2;
 		}
 		if (_uint0be6 == 0) {
-			_npcState[1].xx = _npcState[1].xx + 8;
+			_npcState[1].xx += 8;
 		} else {
-			_npcState[1].xx = _npcState[1].xx - 8;
+			_npcState[1].xx -= 8;
 		}
 		if (absDistToBoss < 0x1e) {
 			arcade34b4();
@@ -1443,7 +1432,7 @@ void DragonArcade::updateBoss2() {
 		break;
 	case 5:
 		if (_npcState[1].ttmPage < (int)(_uint0be6 + 20)) {
-			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+			_npcState[1].ttmPage++;
 		} else {
 			_npcState[1].byte12 = 7;
 			_npcState[1].ttmPage = _uint0be6 + 21;
@@ -1452,11 +1441,11 @@ void DragonArcade::updateBoss2() {
 	case 6:
 		if (_npcState[1].ttmPage < (int)(_uint0be6 + 24)) {
 			if (_nTickUpdates & 1) {
-				_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+				_npcState[1].ttmPage++;
 				if (_uint0be6 == 0) {
-					_npcState[1].xx = _npcState[1].xx + 6;
+					_npcState[1].xx += 6;
 				} else {
-					_npcState[1].xx = _npcState[1].xx + -6;
+					_npcState[1].xx -= 6;
 				}
 			}
 		} else if (absDistToBoss < 40 || _npcState[1].xx < 0x8d4) {
@@ -1465,15 +1454,15 @@ void DragonArcade::updateBoss2() {
 		} else if (_nTickUpdates & 1) {
 			_npcState[1].ttmPage = _uint0be6 + 21;
 			if (_uint0be6 == 0) {
-				_npcState[1].xx = _npcState[1].xx + 6;
+				_npcState[1].xx += 6;
 			} else {
-				_npcState[1].xx = _npcState[1].xx + -6;
+				_npcState[1].xx -= 6;
 			}
 		}
 		break;
 	case 7:
-		if (_npcState[1].ttmPage < (int)(_uint0be6 + 0x1b)) {
-			_npcState[1].ttmPage = _npcState[1].ttmPage + 1;
+		if (_npcState[1].ttmPage < _uint0be6 + 0x1b) {
+			_npcState[1].ttmPage++;
 		} else if (absDistToBoss < 40) {
 			arcade34b4();
 		} else {
@@ -1564,7 +1553,7 @@ void DragonArcade::arcade34b4() {
 		_scrollVelocityX = 1;
 	}
 
-	_arcadeNotMovingLeftFlag = -1;
+	_someMoveDirection = -1;
 	// TODO: what is this?
 	// UINT_39e5_0a1f = 1;
 	_stillLoadingScriptsMaybe = true;
@@ -1698,7 +1687,7 @@ void DragonArcade::updateBladeWithInputs() {
 			_int0b58 = 0;
 	}
 
-	if ((_bladeHorizMoveAttempt & 1) == 0) {
+	if ((_bladeHorizMoveAttempt & kBladeMoveLeft) == kBladeMoveNone) {
 		_bladeStateOffset = 0;
 	} else {
 		_bladeStateOffset = 0x7a;
@@ -1756,14 +1745,14 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		break;
 	case 7:
-		if (_npcState[0].ttmPage + 1 <= _bladeStateOffset + 0x66) {
+		if (_npcState[0].ttmPage < _bladeStateOffset + 0x66) {
 			_npcState[0].ttmPage++;
 		} else {
 			_npcState[0].ttmPage = _bladeStateOffset + 0x66;
 		}
 		return;
 	case 8:
-		if (_npcState[0].ttmPage + 1 <= _bladeStateOffset + 0x6c) {
+		if (_npcState[0].ttmPage < _bladeStateOffset + 0x6c) {
 			_npcState[0].ttmPage++;
 		} else {
 			_npcState[0].ttmPage = _bladeStateOffset + 0x6c;
@@ -1779,12 +1768,7 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		return;
 	case 10:
-		if (_haveBigGun == 0) {
-			newPage = 0xe;
-		} else {
-			newPage = 0x19;
-		}
-		if (_npcState[0].ttmPage < newPage) {
+		if (_npcState[0].ttmPage < (_haveBigGun ? 0x19 : 0xe)) {
 			_npcState[0].ttmPage++;
 		} else {
 			_npcState[3].xx = _npcState[0].xx + 0x16;
@@ -1798,7 +1782,7 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		return;
 	case 11:
-		if (_haveBigGun == 0) {
+		if (!_haveBigGun) {
 			newPage = 0x28;
 		} else {
 			newPage = 0x1f;
@@ -1810,21 +1794,21 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		return;
 	case 12:
-		if ((_nTickUpdates & 1) == 0) {
+		if (!(_nTickUpdates & 1)) {
 			return;
 		}
-		_npcState[0].ttmPage = _npcState[0].ttmPage + 1;
-		if (_haveBigGun != 0) {
-			if (_npcState[0].ttmPage >= 0x3e)
+		_npcState[0].ttmPage++;
+		if (_haveBigGun) {
+			if (_npcState[0].ttmPage > 0x3d)
 				_npcState[0].ttmPage = 0x3d;
 		} else {
-			if (_npcState[0].ttmPage >= 0x3a) {
+			if (_npcState[0].ttmPage > 0x39) {
 				_npcState[0].ttmPage = 0x39;
 			}
 		}
 		return;
 	case 13:
-		if ((_nTickUpdates & 1) == 0) {
+		if (!(_nTickUpdates & 1)) {
 			return;
 		}
 		if (_npcState[0].ttmPage + 1 < 0x26) {
@@ -1873,19 +1857,17 @@ void DragonArcade::moveBladeX() {
 	if (_dontMoveBladeFlag)
 		return;
 
-	if (_arcadeNotMovingLeftFlag != 0)
+	if (_someMoveDirection != 0)
 		return;
 
-	if (_scrollVelocityX < 1) {
-		if (-1 < _scrollVelocityX) {
-			// nothing
-		} else if (_scrollXOffset == 0) {
-			if (0 < _npcState[0].x)
+	if (_scrollVelocityX < 0) {
+		if (_scrollXOffset == 0) {
+			if (_npcState[0].x > 0)
 				_bladeXMove = -4;
-		} else if (0x104 < _npcState[0].x) {
+		} else if (_npcState[0].x > 260) {
 			_bladeXMove = -4;
 			_int0b60 = 0;
-		} else if (_npcState[0].x < 0xa0) {
+		} else if (_npcState[0].x < 160) {
 			_int0b60 = 1;
 			_bladeXMove = 4;
 			updateXScrollOffset();
@@ -1895,16 +1877,16 @@ void DragonArcade::moveBladeX() {
 		} else {
 			_bladeXMove = -4;
 		}
-	} else {
-		if (_scrollXOffset == 0x11a) {
-			if (_npcState[0].x < 0x140)
+	} else if (_scrollVelocityX > 0) {
+		if (_scrollXOffset == 282) {
+			if (_npcState[0].x < 320)
 				_bladeXMove = 4;
 
 		} else if (0xa0 < _npcState[0].x) {
 			_int0b60 = -1;
 			_bladeXMove = -4;
 			updateXScrollOffset();
-		} else if (_npcState[0].x < 0x3c) {
+		} else if (_npcState[0].x < 60) {
 			_int0b60 = 0;
 			_bladeXMove = 4;
 		} else if (_int0b60 != -1) {
@@ -1929,7 +1911,7 @@ void DragonArcade::handleMouseStates() {
 			}
 		} else {
 			moveBladeX();
-			if (_foundFloorFlag == 0) {
+			if (!_foundFloorFlag) {
 				if ((_npcState[0].ttmPage < _bladeStateOffset + 0x6d) ||
 					(_bladeStateOffset + 0x70 < _npcState[0].ttmPage)) {
 					_npcState[0].ttmPage = _bladeStateOffset + 0x6d;
@@ -1947,11 +1929,11 @@ void DragonArcade::handleMouseStates() {
 	} else if (_mouseButtonWentDown == 1) {
 		if (_loadedArcadeStage == 3 && _haveBomb && _npcState[1].health != 0 &&
 			  0x19 < abs(_npcState[1].y - _npcState[0].y) && abs(_npcState[1].x - _npcState[0].x) < 0x28) {
-			/* use a bomb */
+			// use a bomb
 			_bladeState1 = 0xb;
 			_haveBomb = false;
 			_npcState[0].ttmNum = 2;
-			if (_haveBigGun == 0) {
+			if (!_haveBigGun) {
 				_npcState[0].ttmPage = 4;
 			} else {
 				_npcState[0].ttmPage = 0xf;
@@ -1990,17 +1972,21 @@ void DragonArcade::handleMouseStates() {
 		}
 
 		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == kBladeMoveNone) {
+			// Not jumping left or right
 			_bladeState1 = 1;
 			_npcState[0].ttmPage = _bladeStateOffset + 15;
+			debug("Move: blade jump up -> ttm %d", _npcState[0].ttmPage);
 		} else {
+			// Jump to left or right
 			if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
 				_scrollVelocityX = 1;
 			} else {
 				_scrollVelocityX = -1;
 			}
-			_isMovingStage = 0;
+			_isMovingStage = false;
 			_bladeState1 = 2;
 			_npcState[0].ttmPage = _bladeStateOffset + 0x2d;
+			debug("Move: blade jump up -> ttm %d velocity %d", _npcState[0].ttmPage, _scrollVelocityX);
 		}
 
 		if ((_bladeMoveFlagBeforeRButton & kBladeMoveDown) != kBladeMoveNone) {
@@ -2011,6 +1997,7 @@ void DragonArcade::handleMouseStates() {
 				} else {
 					_npcState[0].ttmPage = _bladeStateOffset + 0x16;
 				}
+				debug("Move: blade jump down -> ttm %d", _npcState[0].ttmPage);
 				_arcadeTTM._startYOffset++;
 				_uint0a17++;
 				_currentYOffset = _arcadeTTM._startYOffset;
@@ -2031,7 +2018,7 @@ void DragonArcade::resetStageState() {
 	_ttmYAdjust = 0;
 	_uint0a17 = 0;
 	_shouldUpdateState = 0;
-	_arcadeNotMovingLeftFlag = 0;
+	_someMoveDirection = 0;
 	_npcState[0].byte12 = 1;
 	_npcState[0].ttmNum = 0;
 	_npcState[0].health = (4 - _startDifficultyMaybe) * 3 + 20;
@@ -2267,7 +2254,7 @@ void DragonArcade::arcadeTick() {
 		}
 
 		_enemyHasSmallGun = arcadeState > 10;
-		if (_enemyHasSmallGun != 0) {
+		if (_enemyHasSmallGun) {
 			arcadeState -= 10;
 			globals->setArcadeState(arcadeState);
 		}
@@ -2328,8 +2315,7 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		_arcadeTTM._currentTTMNum = 1;
 		_arcadeTTM.freeShapes();
 		_arcadeTTM.freePages(1);
-		//g_TT3ScriptDataPtrs[1][0] = nullptr;
-		//g_TT3ScriptDataPtrs[1][1] = nullptr;
+		// original also clears data pointers here, but we do that in freePages()
 		_arcadeTTM._currentTTMNum = 2;
 		_arcadeTTM.freeShapes();
 		_arcadeTTM.freePages(2);
@@ -2338,8 +2324,6 @@ void DragonArcade::loadTTMScriptsForStage(uint16 stage) {
 		_arcadeTTM.finishTTMParse(envNum);
 		_arcadeTTM.runNextPage(0);
 		_arcadeTTM._currentTTMNum = 2;
-		//g_TT3ScriptDataPtrs[2][0] = nullptr;
-		//g_TT3ScriptDataPtrs[2][1] = nullptr;
 		envNum = _arcadeTTM.load(ttm2);
 		_arcadeTTM.finishTTMParse(envNum);
 		_arcadeTTM.runNextPage(0);
@@ -2434,7 +2418,7 @@ void DragonArcade::createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16
 			_bullets[i]._flipMode = flipMode;
 			_bullets[i]._var1 = var1;
 			if (var1 == 3)
-				_bullets[i]._speed = _nextRandomVal & 3;
+				_bullets[i]._ySpeed = _nextRandomVal & 3;
 
 			break;
 		}
@@ -2516,15 +2500,15 @@ void DragonArcade::redraw() {
 void DragonArcade::drawScrollBmp() {
 	const Common::Rect drawWin(Common::Point(8, 8), SCREEN_WIDTH - 16, 117);
 	Graphics::ManagedSurface &dst = DgdsEngine::getInstance()->_compositionBuffer;
-	_scrollImg->drawScrollBitmap(8, 8, 320 - 16, 117, _scrollXOffset, 0, drawWin, dst);
+	_scrollImg->drawScrollBitmap(drawWin.left, drawWin.top, drawWin.width(), drawWin.height(),
+						_scrollXOffset, 0, drawWin, dst);
 }
 
 
 void DragonArcade::runThenDrawBulletsInFlight() {
-	// TODO: Set clip window here? 8,8,124,311
 	_arcadeTTM.runPagesForEachNPC(_scrollXOffset);
 
-	const Common::Rect screenWin(Common::Point(8, 8), SCREEN_WIDTH - 16, 117);
+	const Common::Rect drawWin(Common::Point(8, 8), SCREEN_WIDTH - 16, 117);
 	_arcadeTTM._currentTTMNum = _npcState[0].ttmNum;
 	_npcState[0].x_11 = 0;
 	_npcState[0].x_12 = 0;
@@ -2556,7 +2540,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 			} else {
 				frameno = 0;
 			}
-			_bulletImg->drawBitmap(frameno, x, y, screenWin, DgdsEngine::getInstance()->_compositionBuffer, _bullets[i]._flipMode);
+			_bulletImg->drawBitmap(frameno, x, y, drawWin, DgdsEngine::getInstance()->_compositionBuffer, _bullets[i]._flipMode);
 		}
 	}
 
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index 588f3a94077..b95ec153f4a 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -69,14 +69,14 @@ public:
 class DragonArcadeBullet {
 public:
 	DragonArcadeBullet() : _x(0), _y(0), _state(kBulletInactive),
-		_flipMode(kImageFlipNone), _var1(0), _speed(0), _var2(0), _var3(0) {}
+		_flipMode(kImageFlipNone), _var1(0), _ySpeed(0), _var2(0), _var3(0) {}
 
 	int16 _x;
 	int16 _y;
 	DragonBulletState _state;
 	ImageFlipMode _flipMode;
 	int16 _var1;
-	uint16 _speed;
+	uint16 _ySpeed;
 	int16 _var2;
 	int16 _var3;
 };
@@ -188,7 +188,6 @@ private:
 	bool _lastLMouseButtonState;
 	bool _lastRMouseButtonState;
 	int16 _bladeXMove;
-	int16 _bladeHorizMoveAttempt;
 	int16 _currentArrowNum;
 	int16 _foundFloorY;
 	bool _foundFloorFlag;
@@ -205,13 +204,14 @@ private:
 	bool _stillLoadingScriptsMaybe;
 	bool _flag40ee;
 	bool _flag40ef;
-	int16 _arcadeNotMovingLeftFlag;
+	int16 _someMoveDirection;
 	bool _bladeHasFired;
 	bool _mouseIsAvailable;
 	bool _isMovingStage;
 	DragonBladeMoveFlag _bladeMoveFlag;
 	DragonBladeMoveFlag _keyStateFlags;
 	DragonBladeMoveFlag _bladeMoveFlagBeforeRButton;
+	DragonBladeMoveFlag _bladeHorizMoveAttempt;
 	DragonArcadeBullet _bullets[20];
 	ArcadeNPCState _npcState[20];
 	Common::SharedPtr<Image> _bulletImg;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index 5c53e2f11c8..f5c0696d0bc 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -151,6 +151,10 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 	case 0x1111:
 		// Do nothing (ignore arg)
 		break;
+	case 0x1201:
+		// This doesn't seem explicitly handled in the original, but assume we just
+		// ignore it??
+		break;
 	case 0x2002: // SET COLORS
 		_drawColFG = (byte)ivals[0];
 		_drawColBG = (byte)ivals[1];
diff --git a/engines/dgds/globals.cpp b/engines/dgds/globals.cpp
index 760cdae9cc3..36169815a4f 100644
--- a/engines/dgds/globals.cpp
+++ b/engines/dgds/globals.cpp
@@ -107,7 +107,7 @@ int16 Globals::getGlobal(uint16 num) {
 }
 
 int16 Globals::setGlobal(uint16 num, int16 val) {
-	debug("setGlobal %d -> %d", num, val);
+	//debug("setGlobal %d -> %d", num, val);
 	for (auto &global : _globals) {
 		if (global->getNum() == num)
 			return global->set(val);


Commit: 2ec7643b444904ceefc498c090f445b7f721f079
    https://github.com/scummvm/scummvm/commit/2ec7643b444904ceefc498c090f445b7f721f079
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Improve dragon arcade var names

Changed paths:
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index c7ea20f0f95..aaad9675ae1 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -144,14 +144,14 @@ bool DragonArcade::doTickUpdate() {
 }
 
 void DragonArcade::updateBullets() {
-	for (int i = 19; i > 0; i--) {
-		if (_bullets[i]._state == 2 || _bullets[i]._state == 3) {
+	for (int i = 19; i >= 0; i--) {
+		if (_bullets[i]._state == kBulletHittingBlade || _bullets[i]._state == kBulletHittingEnemy) {
 			_bullets[i]._state = kBulletInactive;
 			continue;
 		}
 
 		if (_bullets[i]._state == kBulletFlying) {
-			if (_bullets[i]._var1 == 3) {
+			if (_bullets[i]._bulletType == 3) {
 				_bullets[i]._y += _bullets[i]._ySpeed;
 			}
 			if (_bullets[i]._flipMode == kImageFlipNone) {
@@ -188,10 +188,10 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 		if (_npcState[i].byte12 <= 0)
 			continue;
 
-		if (_bullets[num]._var1 == 3) {
+		if (_bullets[num]._bulletType == 3) {
 			yoff = 7;
 		}
-		if (_bullets[num]._var1 != 1 || i == 0) {
+		if (_bullets[num]._bulletType != 1 || i == 0) {
 			if (_bullets[num]._x < _npcState[i].x_11 || _npcState[i].x_12 < _bullets[num]._x ||
 				_bullets[num]._y + yoff < _npcState[i].y_11 || _npcState[i].y_12 < _bullets[num]._y + yoff) {
 				if (_bullets[num]._x < _npcState[i].x_21 || _npcState[i].x_22 < _bullets[num]._x ||
@@ -201,18 +201,18 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 					return -1;
 
 				if (_loadedArcadeStage == 3) {
-					if (_bullets[num]._var1 == 3)
+					if (_bullets[num]._bulletType == 3)
 						continue;
 				} else {
 					if (_loadedArcadeStage == 4) {
-						if (_bullets[num]._var1 == 1 || _bullets[num]._var1 == 3)
+						if (_bullets[num]._bulletType == 1 || _bullets[num]._bulletType == 3)
 							continue;
 					} else if (_loadedArcadeStage != 6) {
 						return -1;
 					}
 				}
 
-				if (_bullets[num]._var1 != 2) {
+				if (_bullets[num]._bulletType != 2) {
 					return -1;
 				}
 			} else {
@@ -221,7 +221,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 					if (_npcState[0].health != 0)
 						return 1;
 
-					if (_bullets[num]._var1 != 3) {
+					if (_bullets[num]._bulletType != 3) {
 						return 1;
 					}
 					_shouldUpdateState = 3;
@@ -234,7 +234,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 				case 2:
 				case 4:
 					if (_loadedArcadeStage == 4 || _npcState[i].byte12 < 0x1e) {
-						if (_bullets[num]._var1 != 1) {
+						if (_bullets[num]._bulletType != 1) {
 							playSfx(0x56);
 							_npcState[i].byte12 = 1;
 							if (_npcState[i].ttmPage < 0x1c) {
@@ -255,7 +255,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 					_npcState[i].ttmPage = 0x21;
 					break;
 				case 3:
-					if (_bullets[num]._var1 != 3) {
+					if (_bullets[num]._bulletType != 3) {
 						if (_npcState[i].byte12 == 1) {
 							_npcState[i].byte12 = 7;
 							_npcState[i].ttmPage = 0x4b;
@@ -274,7 +274,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 					}
 					break;
 				case 6:
-					if (_bullets[num]._var1 != 2) {
+					if (_bullets[num]._bulletType != 2) {
 						if (_haveBigGun) {
 							decBossHealthAndCheck();
 						}
@@ -1233,7 +1233,7 @@ void DragonArcade::updateBoss() {
 	int16 distToBoss = _npcState[1].x - _npcState[0].x;
 	int16 absDistToBoss = abs(distToBoss);
 	bool bossIsClose = absDistToBoss < 20;
-	uint16 uVar4 = _nextRandomVal & 0xf;
+	uint16 randVal = _nextRandomVal & 0xf;
 
 	switch(_npcState[1].byte12) {
 	case 0:
@@ -1242,15 +1242,15 @@ void DragonArcade::updateBoss() {
 				_npcState[1].byte12 = 5;
 				_npcState[1].ttmPage = 30;
 			}
-		} else if (distToBoss < 0 || (_bossStateUpdateCounter < 0 && uVar4 == 7)) {
+		} else if (distToBoss < 0 || (_bossStateUpdateCounter < 0 && randVal == 7)) {
 			_npcState[1].byte12 = 3;
 			_npcState[1].ttmPage = 10;
 			_bossStateUpdateCounter++;
-		} else if ((bossIsClose && distToBoss < 70 && 0 < distToBoss && uVar4 == 0xf) || (0 < _bossStateUpdateCounter && uVar4 == 7)) {
+		} else if ((bossIsClose && distToBoss < 70 && 0 < distToBoss && randVal == 0xf) || (0 < _bossStateUpdateCounter && randVal == 7)) {
 			_npcState[1].byte12 = 2;
 			_npcState[1].ttmPage = 3;
 			_bossStateUpdateCounter--;
-		} else if (_bossStateUpdateCounter == 0 && uVar4 == 0xf) {
+		} else if (_bossStateUpdateCounter == 0 && randVal == 0xf) {
 			_npcState[1].byte12 = 4;
 			_npcState[1].ttmPage = 17;
 		}
@@ -2409,15 +2409,15 @@ void DragonArcade::clearAllBulletStates() {
 	}
 }
 
-void DragonArcade::createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16 var1) {
+void DragonArcade::createBullet(int16 x, int16 y, ImageFlipMode flipMode, int16 bulletType) {
 	for (uint i = 0; i < ARRAYSIZE(_bullets); i++) {
 		if (_bullets[i]._state == kBulletInactive) {
 			_bullets[i]._state = kBulletFlying;
 			_bullets[i]._x = x;
 			_bullets[i]._y = y;
 			_bullets[i]._flipMode = flipMode;
-			_bullets[i]._var1 = var1;
-			if (var1 == 3)
+			_bullets[i]._bulletType = bulletType;
+			if (bulletType == 3)
 				_bullets[i]._ySpeed = _nextRandomVal & 3;
 
 			break;
@@ -2534,7 +2534,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 			drawBulletHitCircles(x, y, true);
 		} else if (_bullets[i]._state == kBulletFlying) {
 			int16 frameno;
-			if (_bullets[i]._var1 == 3) {
+			if (_bullets[i]._bulletType == 3) {
 				// FIXME: this is a bit weird?
 				frameno = (_nextRandomVal % 3);
 			} else {
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index b95ec153f4a..8c7797c901a 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -69,16 +69,17 @@ public:
 class DragonArcadeBullet {
 public:
 	DragonArcadeBullet() : _x(0), _y(0), _state(kBulletInactive),
-		_flipMode(kImageFlipNone), _var1(0), _ySpeed(0), _var2(0), _var3(0) {}
+		_flipMode(kImageFlipNone), _bulletType(0), _ySpeed(0) {}
 
 	int16 _x;
 	int16 _y;
 	DragonBulletState _state;
 	ImageFlipMode _flipMode;
-	int16 _var1;
+	int16 _bulletType;
 	uint16 _ySpeed;
-	int16 _var2;
-	int16 _var3;
+	// these fields are in the original but seem to not be used.
+	// int16 _var2;
+	// int16 _var3;
 };
 
 class DragonArcade {
@@ -95,7 +96,7 @@ private:
 	void checkToOpenMenu();
 	void clearAllBulletStates();
 	void clearAllNPCStates();
-	void createBullet(int16 x, int16 y, ImageFlipMode flipMode, uint16 var1);
+	void createBullet(int16 x, int16 y, ImageFlipMode flipMode, int16 bulletType);
 	void bladeTakeHitAndCheck();
 	void enemyTakeHit() { _npcState[1].health--; }
 	void enemyTakeHitAndCheck();


Commit: 41b6df5a553647ea25f55a054bf5f75ec0e2323c
    https://github.com/scummvm/scummvm/commit/41b6df5a553647ea25f55a054bf5f75ec0e2323c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Fix fight in dragon arcade 1

Changed paths:
    engines/dgds/dragon_arcade.cpp


diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index aaad9675ae1..5e7fa74033b 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -1477,7 +1477,7 @@ void DragonArcade::updateBoss2() {
 				updateXScrollOffset();
 			}
 			byte bossByte12 = _npcState[1].byte12;
-			// TODO: do these ever get changed?
+			// Note: these never get changed? they're items in INT_TABLE_0BCE
 			const int16 INT_39e5_0be0 = 0x3A;
 			const int16 INT_39e5_0bda = 0x20;
 			if (bossByte12 == 100) {
@@ -1521,15 +1521,15 @@ void DragonArcade::updateBoss2() {
 				}
 			} else if ((bossByte12 != 106 || INT_39e5_0be0 + 0x41 != _npcState[1].ttmPage) &&
 					   (bossByte12 != 103 || INT_39e5_0bda + 0x41 != _npcState[1].ttmPage)) {
-				error("TODO: Fix references to table at 0xb0c");
-				/*
-				if (*(int *)(bossByte12 * 2 + 0xb0c) + 0x41 == _npcState[1].ttmPage) {
+				// code uses 0x0b0c + byte12, but table that's actually used starts at 0xbce
+				static const int16 INT_TABLE_0BCE[] = {0x2a, 0x34, 0x3b, 0x2, 0xD, 0x1A, 0x20, 0x29, 0x33, 0x3A, 0x42};
+				assert(bossByte12 >= 97 && bossByte12 - 97 < ARRAYSIZE(INT_TABLE_0BCE));
+				if (INT_TABLE_0BCE[bossByte12 - 97] + 0x41 == _npcState[1].ttmPage) {
 					_npcState[1].byte12 = 100;
 					_npcState[1].ttmPage = 67;
 				} else if (bossByte12 != 100 && _nTickUpdates & 1) {
 					_npcState[1].ttmPage++;
 				}
-				*/
 			}
 		}
 	}


Commit: c80a5b4a2845022217d07483542d693d7951b85d
    https://github.com/scummvm/scummvm/commit/c80a5b4a2845022217d07483542d693d7951b85d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Dragon sequence almost complete

Changed paths:
    engines/dgds/ads.cpp
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade_ttm.cpp


diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index 924c38056ed..0beba1b84ee 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -1010,7 +1010,7 @@ Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
 	}
 
 	s.syncString(activeScript);
-	assert(_adsTexts.contains(activeScript));
+	assert(activeScript.empty() || _adsTexts.contains(activeScript));
 	_adsData = &_adsTexts[activeScript];
 
 	return Common::kNoError;
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index 5e7fa74033b..c25d5d7f98f 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -739,7 +739,7 @@ bool DragonArcade::isFloorNotFound() {
 uint16 DragonArcade::moveToNextStage() {
 	int xblock = _scrollXOffset + _npcState[0].x / 8;
 
-	switch(_loadedArcadeStage) {
+	switch (_loadedArcadeStage) {
 	case 0:
 		if (0x31 < _scrollXOffset) {
 			_loadedArcadeStage = 1;
@@ -755,7 +755,7 @@ uint16 DragonArcade::moveToNextStage() {
 		if (0x89 < xblock && xblock < 0x8d && 0x14 < _arcadeTTM._startYOffset &&
 			_arcadeTTM._startYOffset < 0x46 && _bladeStateOffset == 0) {
 			_scrollXOffset = 0x89 - _npcState[0].x / 8;
-			_arcadeTTM._startYOffset = -0xd;
+			_arcadeTTM._startYOffset = -13;
 			playSFX55AndStuff();
 			_loadedArcadeStage = 2;
 			initValuesForStage2();
@@ -773,7 +773,7 @@ uint16 DragonArcade::moveToNextStage() {
 		if (0x99 < xblock && xblock < 0x9c && 0x14 < _arcadeTTM._startYOffset &&
 			  _arcadeTTM._startYOffset < 0x46 && _bladeStateOffset == 0) {
 			_scrollXOffset = 0x9a - _npcState[0].x / 8;
-			_arcadeTTM._startYOffset = -0xd;
+			_arcadeTTM._startYOffset = -13;
 			playSFX55AndStuff();
 			return 1;
 		}
@@ -929,7 +929,7 @@ static const int16 STAGE_2_XX[] = {
 };
 
 static const int16 STAGE_2_YY[] = {
-	0, 0, 0xe9
+	0, 0, -23
 };
 
 static const byte STAGE_2_BYTE12[] = {
@@ -1045,14 +1045,14 @@ void DragonArcade::arcade2754(int16 floorY) {
 }
 
 
-static const int16 arrayC5A[4][7] {
+static const int16 INT_ARRAY_C5A[4][7] {
 	{ 0x8, 0x19, 0x5A, 0x78, 0x8C, 0xA5, 0xBE },
 	{ 0x6, 0x28, 0x5A, 0x87, 0x96, 0xAA, 0xC0 },
 	{ 0x4, 0x37, 0x69, 0x79, 0x91, 0xA0, 0xC2 },
 	{ 0x2, 0x46, 0x69, 0x87, 0x9B, 0xAF, 0xC4 },
 };
 
-static const int16 arrayC92[4][7] {
+static const int16 INT_ARRAY_C92[4][7] {
 	{ 0xA, 0x37, 0x46, 0x55, 0x91, 0xAA, 0xC8 },
 	{ 0x19, 0x5F, 0x87, 0x9B, 0xB9, 0xD7, -0x1 },
 	{ 0x19, 0x23, 0x69, 0x7D, 0x9B, 0xB9, 0xD7 },
@@ -1064,18 +1064,18 @@ void DragonArcade::arcade3e96() {
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 7; j++) {
 			if (_loadedArcadeStage == 0) {
-				if (_flag40ee && arrayC5A[i][j] == _someCounter40f0) {
-					_npcState[i].ttmPage = 1;
+				if (_flag40ee && INT_ARRAY_C5A[i][j] == _someCounter40f0) {
+					_npcState[i + 10].ttmPage = 1;
 				}
 			} else if (_loadedArcadeStage == 1) {
-				if (arrayC92[i][j] == _someCounter40f0) {
-					_npcState[4 + i].ttmPage = 1;
+				if (INT_ARRAY_C92[i][j] == _someCounter40f0) {
+					_npcState[i + 4 + 10].ttmPage = 1;
 				}
-				if (_flag40ee && arrayC5A[i][j] == _someCounter40f0) {
-					_npcState[i].ttmPage = 1;
+				if (_flag40ee && INT_ARRAY_C5A[i][j] == _someCounter40f0) {
+					_npcState[i + 10].ttmPage = 1;
 				}
-			} else if (_loadedArcadeStage == 2 && _flag40ef && arrayC92[i][j] == _someCounter40f0) {
-				_npcState[i].ttmPage = 1;
+			} else if (_loadedArcadeStage == 2 && _flag40ef && INT_ARRAY_C92[i][j] == _someCounter40f0) {
+				_npcState[i + 10].ttmPage = 1;
 			}
 		}
 	}
@@ -1235,7 +1235,7 @@ void DragonArcade::updateBoss() {
 	bool bossIsClose = absDistToBoss < 20;
 	uint16 randVal = _nextRandomVal & 0xf;
 
-	switch(_npcState[1].byte12) {
+	switch(_npcState[1].byte12 - 1) {
 	case 0:
 		if (bossIsClose && absDistToBoss < 45) {
 			if (_bladeState1 != 8 && _bladeState1 != 9) {
@@ -2031,28 +2031,28 @@ void DragonArcade::resetStageState() {
 	_bladeMoveFlag = kBladeMoveNone;
 }
 
-static const int STAGE_0_NPC_XX[] = {
+static const int16 STAGE_0_NPC_XX[] = {
 	0x191, 0x1BB, 0x1F5,
 	0x25B, 0x2D3, 0x341,
 	0x535, 0x5C9, 0x623
 };
 
-static const byte STAGE_0_NPC_YY[] = {
-	0, 0, 0, 0xd8, 0xd8, 0, 0, 0, 0xd8
+static const int16 STAGE_0_NPC_YY[] = {
+	0, 0, 0, -40, -40, 0, 0, 0, -40
 };
 
 static const byte STAGE_0_NPC_BYTE12[] = {
 	5, 4, 4, 5, 4, 5, 4, 5, 5
 };
 
-static const int STAGE_4_NPC_XX_1[] = {
+static const int16 STAGE_4_NPC_XX_1[] = {
 	0x169, 0x19D, 0x1B9,
 	0x30D, 0x32D, 0x457,
 	0x4DB, 0x501, -1
 };
 
-static const byte STAGE_4_NPC_YY_1[] = {
-	0, 0, 0, 0, 0, 0xd8, 0, 0, 0xd8
+static const int16 STAGE_4_NPC_YY_1[] = {
+	0, 0, 0, 0, 0, -40, 0, 0, -40
 };
 
 static const byte STAGE_4_NPC_BYTE12_1[] = {
@@ -2103,35 +2103,35 @@ void DragonArcade::initValuesForStage() {
 	}
 }
 
-static const int16 STAGE_0_ST_INT1[] = {
+static const int16 STAGE_0_NPC2_XX_1[] = {
 	0x13F, 0x150, 0x161, 0x172
 };
 
-static const int16 STAGE_0_ST_INT1_2[] = {
+static const int16 STAGE_0_NPC2_XX_2[] = {
 	0x317, 0x328, 0x339, 0x34A
 };
 
-static const int16 STAGE_0_ST_TTMPAGE[] = {
+static const int16 STAGE_0_NPC2_TTMPAGE[] = {
 	 0, 0x1E, 0xF, 0
 };
 
 void DragonArcade::initValuesForStage0() {
 	_someCounter40f0 = 0;
 	for (int i = 10; i < 14; i++) {
-		_npcState[i].xx = STAGE_0_ST_INT1[i - 10];
+		_npcState[i].xx = STAGE_0_NPC2_XX_1[i - 10];
 		_npcState[i].yy = 2;
-		_npcState[i].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
+		_npcState[i].ttmPage = STAGE_0_NPC2_TTMPAGE[i - 10];
 		_npcState[i].ttmNum = 2;
 
-		_npcState[i + 4].xx = STAGE_0_ST_INT1_2[i - 10];
+		_npcState[i + 4].xx = STAGE_0_NPC2_XX_2[i - 10];
 		_npcState[i + 4].yy = -37;
-		_npcState[i + 4].ttmPage = STAGE_0_ST_TTMPAGE[i - 10];
+		_npcState[i + 4].ttmPage = STAGE_0_NPC2_TTMPAGE[i - 10];
 		_npcState[i + 4].ttmNum = 2;
 	}
 	_flag40ee = true;
 	_flag40ef = true;
 	_npcState[18].xx = 0x11f;
-	_npcState[18].yy = -0xd;
+	_npcState[18].yy = -13;
 	_npcState[18].byte12 = 0x1e;
 	_npcState[18].ttmPage = 0x20;
 	_npcState[18].ttmNum = 2;
diff --git a/engines/dgds/dragon_arcade_ttm.cpp b/engines/dgds/dragon_arcade_ttm.cpp
index f5c0696d0bc..123fc329468 100644
--- a/engines/dgds/dragon_arcade_ttm.cpp
+++ b/engines/dgds/dragon_arcade_ttm.cpp
@@ -120,6 +120,10 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 	DgdsEngine *engine = DgdsEngine::getInstance();
 	Graphics::ManagedSurface &compBuffer = engine->_compositionBuffer;
 	switch (op) {
+	case 0x0020:
+		// This doesn't seem explicitly handled in the original, but appears in
+		// arcade sequence 2 - just ignore it??
+		break;
 	case 0x0070:
 		// Do nothing.
 		break;
@@ -152,8 +156,8 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		// Do nothing (ignore arg)
 		break;
 	case 0x1201:
-		// This doesn't seem explicitly handled in the original, but assume we just
-		// ignore it??
+		// This doesn't seem explicitly handled in the original, but appears in
+		// arcade sequence 1 - just ignore it??
 		break;
 	case 0x2002: // SET COLORS
 		_drawColFG = (byte)ivals[0];
@@ -280,6 +284,7 @@ int16 DragonArcadeTTM::handleOperation(TTMEnviro &env, int16 page, uint16 op, by
 		break;
 	default:
 		warning("Unsupported TTM opcode 0x%04x for Dragon arcade.", op);
+		break;
 	}
 	return 0;
 }


Commit: d7a6701a66c66578539c4010f3ca9df1bd40d5f5
    https://github.com/scummvm/scummvm/commit/d7a6701a66c66578539c4010f3ca9df1bd40d5f5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2024-09-22T10:01:25+03:00

Commit Message:
DGDS: Reduce unneeded hex numbers in dragon arcade code

Changed paths:
    engines/dgds/ads.cpp
    engines/dgds/dgds.h
    engines/dgds/dragon_arcade.cpp
    engines/dgds/dragon_arcade.h
    engines/dgds/scene.cpp


diff --git a/engines/dgds/ads.cpp b/engines/dgds/ads.cpp
index 0beba1b84ee..ba77fdf2d72 100644
--- a/engines/dgds/ads.cpp
+++ b/engines/dgds/ads.cpp
@@ -1011,7 +1011,7 @@ Common::Error ADSInterpreter::syncState(Common::Serializer &s) {
 
 	s.syncString(activeScript);
 	assert(activeScript.empty() || _adsTexts.contains(activeScript));
-	_adsData = &_adsTexts[activeScript];
+	_adsData = activeScript.empty() ? nullptr : &_adsTexts[activeScript];
 
 	return Common::kNoError;
 }
diff --git a/engines/dgds/dgds.h b/engines/dgds/dgds.h
index afce3d193cb..eafab0d6857 100644
--- a/engines/dgds/dgds.h
+++ b/engines/dgds/dgds.h
@@ -91,6 +91,8 @@ enum DgdsKeyEvent {
 	kDgdsKeyActivate,
 };
 
+// TODO: Enable keymapper for dragon arcade sequences
+/*
 enum DragonArcadeKeyEvent {
 	kDragonArcadeKeyLeft,
 	kDragonArcadeKeyRight,
@@ -103,6 +105,7 @@ enum DragonArcadeKeyEvent {
 	kDragonArcadeKeyJumpMode,
 	kDragonArcadeKeyFire,
 };
+*/
 
 
 class DgdsEngine : public Engine {
diff --git a/engines/dgds/dragon_arcade.cpp b/engines/dgds/dragon_arcade.cpp
index c25d5d7f98f..b9482457833 100644
--- a/engines/dgds/dragon_arcade.cpp
+++ b/engines/dgds/dragon_arcade.cpp
@@ -39,8 +39,8 @@ namespace Dgds {
 
 DragonArcade::DragonArcade() : _arcadeTTM(_npcState), _lastDrawnBladeHealth(-1), _lastDrawnBossHealth(-1),
 	_nextRandomVal(0), _loadedArcadeStage(-1), _nextStage(0), _attemptCounter(0),
-	_shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladeStateOffset(0), _mouseButtonWentDown(0),
-	_scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0), _someCounter40f0(0),
+	_shouldUpdateState(0), _finishCountdown(0), _bladeState1(0), _bladePageOffset(0), _mouseButtonWentDown(0),
+	_scrollXOffset(0), _nTickUpdates(0), _startDifficultyMaybe(0), _bossStateUpdateCounter(0), _npcStateResetCounter(0),
 	_scrollVelocityX(0), _uint0a17(0), _currentYOffset(0), _int0b58(0), _int0b5a(0), _int0b60(0), _ttmYAdjust(0),
 	_uint0be6(0), _dontMoveBladeFlag(false), _scrollXIncrement(0), _lMouseButtonState(false), _rMouseButtonState(false),
 	_lastLMouseButtonState(false), _lastRMouseButtonState(false), _bladeXMove(0), _bladeHorizMoveAttempt(kBladeMoveNone),
@@ -233,32 +233,32 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 				case 1:
 				case 2:
 				case 4:
-					if (_loadedArcadeStage == 4 || _npcState[i].byte12 < 0x1e) {
+					if (_loadedArcadeStage == 4 || _npcState[i].byte12 < 30) {
 						if (_bullets[num]._bulletType != 1) {
 							playSfx(0x56);
 							_npcState[i].byte12 = 1;
-							if (_npcState[i].ttmPage < 0x1c) {
-								_npcState[i].ttmPage = 0x15;
+							if (_npcState[i].ttmPage < 28) {
+								_npcState[i].ttmPage = 21;
 							} else {
-								_npcState[i].ttmPage = 0x31;
+								_npcState[i].ttmPage = 49;
 							}
 							return 1;
 						}
 						break;
 					}
-					if (_npcState[i].byte12 == 0x1e) {
+					if (_npcState[i].byte12 == 30) {
 						_flag40ee = false;
 					} else {
 						_flag40ef = false;
 					}
 					_npcState[i].byte12 = 0xf8;
-					_npcState[i].ttmPage = 0x21;
+					_npcState[i].ttmPage = 33;
 					break;
 				case 3:
 					if (_bullets[num]._bulletType != 3) {
 						if (_npcState[i].byte12 == 1) {
 							_npcState[i].byte12 = 7;
-							_npcState[i].ttmPage = 0x4b;
+							_npcState[i].ttmPage = 75;
 						}
 						if (_haveBigGun) {
 							decBossHealth();
@@ -268,7 +268,7 @@ int16 DragonArcade::checkBulletCollision(int16 num) {
 							return 1;
 						}
 						_npcState[i].byte12 = 8;
-						_npcState[i].ttmPage = 0x4f;
+						_npcState[i].ttmPage = 79;
 						setFinishCountdownIfLessThan0(0x78);
 						return 1;
 					}
@@ -319,7 +319,7 @@ void DragonArcade::checkBladeFireAllStages() {
 
 	for (int i = 0; i < 8; i++) {
 		if (FIRE_ALLOWABLE_PAGES[i] == _npcState[0].ttmPage) {
-			if (_npcState[0].ttmPage < 0x7b) {
+			if (_npcState[0].ttmPage < 123) {
 				flipMode = kImageFlipNone;
 			} else {
 				flipMode = kImageFlipH;
@@ -335,9 +335,9 @@ void DragonArcade::checkBladeFireAllStages() {
 
 			// is this always 0?
 			//if (INT_39e5_0c58 == 0) {
-			sndno = 0x2f;
+			sndno = 47;
 			//} else {
-			//sndno = 0x34;
+			//sndno = 52;
 			//}
 			playSfx(sndno);
 			_bladeHasFired = true;
@@ -360,7 +360,7 @@ void DragonArcade::checkEnemyFireStage0124() {
 			if (_npcState[i].x < 340 && -20 < _npcState[i].x &&
 				ENEMY_FIRE_ALLOWABLE_PAGES[j] == _npcState[i].ttmPage) {
 				debug("enemy %d @ %d firing type %d on page %d", i, _npcState[i].x, j, _npcState[i].ttmPage);
-				ImageFlipMode flipMode = (_npcState[i].ttmPage < 0x1d) ? kImageFlipNone : kImageFlipH;
+				ImageFlipMode flipMode = (_npcState[i].ttmPage < 29) ? kImageFlipNone : kImageFlipH;
 				createBullet(ENEMY_FIRE_X_OFFSETS[j] + _npcState[i].xx - _scrollXOffset * 8 - 0xa0,
 							 ENEMY_FIRE_Y_OFFSETS[j] + _npcState[i].yy + 3, flipMode, 1);
 				playSfx(0x25);
@@ -379,10 +379,10 @@ void DragonArcade::checkBossFireStage3() {
 }
 
 void DragonArcade::checkBossFireStage6() {
-	ImageFlipMode flipMode = (_npcState[1].ttmPage < 0x28) ? kImageFlipNone: kImageFlipH;
+	ImageFlipMode flipMode = (_npcState[1].ttmPage < 40) ? kImageFlipNone: kImageFlipH;
 
 	if (_npcState[1].x < 0x154 && -20 < _npcState[1].x &&
-		(_npcState[1].ttmPage == 9 || _npcState[1].ttmPage == 0x28)) {
+		(_npcState[1].ttmPage == 9 || _npcState[1].ttmPage == 40)) {
 		createBullet(_npcState[1].xx - _scrollXOffset * 8 - 19,
 						_npcState[1].yy + 86, flipMode, 2);
 		playSfx(0x24);
@@ -580,8 +580,8 @@ void DragonArcade::updateMouseAndJoystickStates() {
 int16 DragonArcade::findFloorUnderBlade() {
 	updateFloorsUnderBlade();
 	if (_bladeState1 == 1 || _bladeState1 == 2) {
-		if ((_bladeStateOffset + 0x38 == _npcState[0].ttmPage) ||
-			(_bladeStateOffset + 0x16 == _npcState[0].ttmPage)) {
+		if ((_bladePageOffset + 56 == _npcState[0].ttmPage) ||
+			(_bladePageOffset + 22 == _npcState[0].ttmPage)) {
 			findFloorMatchOrMinOrMax();
 		} else {
 			findFloorMinGE();
@@ -637,7 +637,7 @@ bool DragonArcade::isNpcInsideXRange(int16 num) {
 
 void DragonArcade::arcade16bc() {
 	_bladeState1 = 5;
-	_npcState[0].ttmPage = _bladeStateOffset + 0x40;
+	_npcState[0].ttmPage = _bladePageOffset + 64;
 	_arcadeTTM._startYOffset++;
 	_currentYOffset = _arcadeTTM._startYOffset;
 	_uint0a17++;
@@ -650,10 +650,10 @@ void DragonArcade::arcade1e83() {
 
 void DragonArcade::arcade16de(int16 param) {
 	if (_bladeState1 == 2) {
-		_npcState[0].ttmPage = _bladeStateOffset + 0x39;
+		_npcState[0].ttmPage = _bladePageOffset + 57;
 	}
 	else {
-		_npcState[0].ttmPage = _bladeStateOffset + 0x17;
+		_npcState[0].ttmPage = _bladePageOffset + 23;
 	}
 	_npcState[0].ttmNum = 0;
 	_arcadeTTM._startYOffset = param;
@@ -665,11 +665,11 @@ void DragonArcade::arcade16de(int16 param) {
 
 void DragonArcade::arcade4085() {
 	for (int i = 10; i < 12; i++) {
-		if (_someCounter40f0 == 0x14) {
+		if (_npcStateResetCounter == 20) {
 			_npcState[i].ttmPage = 0;
 		}
 		_npcState[i].ttmPage++;
-		if (_npcState[i].ttmPage < 1 || 0xe < _npcState[i].ttmPage) {
+		if (_npcState[i].ttmPage < 1 || 14 < _npcState[i].ttmPage) {
 			_npcState[i].byte12 = 0;
 		}
 		else {
@@ -685,17 +685,17 @@ void DragonArcade::arcade4085() {
 		}
 	}
 
-	if ((_someCounter40f0 & 3) == 0) {
+	if ((_npcStateResetCounter & 3) == 0) {
 		_npcState[12].ttmPage++;
 		_npcState[13].ttmPage++;
 		if (0x1e < _npcState[12].ttmPage) {
-			_npcState[12].ttmPage = 0xf;
-			_npcState[13].ttmPage = 0xf;
+			_npcState[12].ttmPage = 15;
+			_npcState[13].ttmPage = 15;
 		}
 	}
 
 	for (int i = 10; i < 12; i++) {
-		if (_npcState[i].ttmPage == 0x1d) {
+		if (_npcState[i].ttmPage == 29) {
 			if (isNpcInsideXRange(i + 2))
 				playSfx(0x59);
 			if (_npcState[0].health && _npcState[i].yy - 0x10 <= _npcState[0].xx && _npcState[0].xx <= _npcState[i].yy + 0x23) {
@@ -709,7 +709,7 @@ void DragonArcade::arcade4085() {
 	if (0x35 < _npcState[14].ttmPage) {
 		if (isNpcInsideXRange(0xe))
 			playSfx(0x58);
-		_npcState[14].ttmPage = 0x28;
+		_npcState[14].ttmPage = 40;
 	}
 	if (_npcState[0].health != 0 && ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone || _arcadeTTM._startYOffset < -6)
 		&& _npcState[14].xx - 0x10 <= _npcState[0].xx && _npcState[0].xx <= _npcState[14].xx + 0x23) {
@@ -718,16 +718,16 @@ void DragonArcade::arcade4085() {
 		if (_npcState[0].health == 0) {
 			/* blade dies! */
 			_npcState[0].ttmNum = 2;
-			_npcState[0].ttmPage = 0x22;
+			_npcState[0].ttmPage = 34;
 			_npcState[0].byte12 = 14;
 			_bladeState1 = 14;
 			_shouldUpdateState = 2;
 		}
 	}
 
-	_someCounter40f0++;
-	if (_someCounter40f0 == 60) {
-		_someCounter40f0 = 0;
+	_npcStateResetCounter++;
+	if (_npcStateResetCounter == 60) {
+		_npcStateResetCounter = 0;
 	}
 }
 
@@ -752,8 +752,8 @@ uint16 DragonArcade::moveToNextStage() {
 			return 1;
 		}
 
-		if (0x89 < xblock && xblock < 0x8d && 0x14 < _arcadeTTM._startYOffset &&
-			_arcadeTTM._startYOffset < 0x46 && _bladeStateOffset == 0) {
+		if (0x89 < xblock && xblock < 0x8d && 20 < _arcadeTTM._startYOffset &&
+			_arcadeTTM._startYOffset < 70 && _bladePageOffset == 0) {
 			_scrollXOffset = 0x89 - _npcState[0].x / 8;
 			_arcadeTTM._startYOffset = -13;
 			playSFX55AndStuff();
@@ -770,8 +770,8 @@ uint16 DragonArcade::moveToNextStage() {
 			return 1;
 		}
 
-		if (0x99 < xblock && xblock < 0x9c && 0x14 < _arcadeTTM._startYOffset &&
-			  _arcadeTTM._startYOffset < 0x46 && _bladeStateOffset == 0) {
+		if (0x99 < xblock && xblock < 0x9c && 20 < _arcadeTTM._startYOffset &&
+			  _arcadeTTM._startYOffset < 70 && _bladePageOffset == 0) {
 			_scrollXOffset = 0x9a - _npcState[0].x / 8;
 			_arcadeTTM._startYOffset = -13;
 			playSFX55AndStuff();
@@ -779,8 +779,8 @@ uint16 DragonArcade::moveToNextStage() {
 		}
 
 		if (_scrollXOffset < 0x100) {
-			if (0xf3 < xblock && xblock < 0xf6 && 0x1e < _arcadeTTM._startYOffset &&
-				 _arcadeTTM._startYOffset < 0x3c && _bladeStateOffset == 0 && _startDifficultyMaybe != 3) {
+			if (0xf3 < xblock && xblock < 0xf6 && 30 < _arcadeTTM._startYOffset &&
+				 _arcadeTTM._startYOffset < 60 && _bladePageOffset == 0 && _startDifficultyMaybe != 3) {
 				_scrollXOffset = 0xf4 - _npcState[0].x / 8;
 				_arcadeTTM._startYOffset = -0x1a;
 				playSFX55AndStuff();
@@ -798,11 +798,11 @@ uint16 DragonArcade::moveToNextStage() {
 			playSfx(0x57);
 			setFinishCountdownIfLessThan0(0x14);
 			if (_haveBigGun) {
-				_npcState[0].ttmPage = 0x3a;
+				_npcState[0].ttmPage = 58;
 			} else {
-				_npcState[0].ttmPage = 0x36;
+				_npcState[0].ttmPage = 54;
 			}
-			_bladeState1 = 0xd;
+			_bladeState1 = 13;
 			_mouseButtonWentDown = 0x80;
 			_npcState[0].byte12 = 13;
 			_npcState[0].health = 0;
@@ -849,7 +849,7 @@ void DragonArcade::playSFX55AndStuff() {
 	_ttmYAdjust = 0;
 	_int0b5a = 15;
 	_scrollVelocityX = 0;
-	_npcState[0].ttmPage = _bladeStateOffset + 0x43;
+	_npcState[0].ttmPage = _bladePageOffset + 67;
 }
 
 
@@ -920,7 +920,7 @@ void DragonArcade::findFloorMatchOrMinOrMax() {
 void DragonArcade::arcade2445() {
 	_scrollVelocityX = 0;
 	_bladeState1 = 6;
-	_npcState[0].ttmPage += 0x4e;
+	_npcState[0].ttmPage += 78;
 	_isMovingStage = true;
 }
 
@@ -937,7 +937,7 @@ static const byte STAGE_2_BYTE12[] = {
 };
 
 static const int16 STAGE_2_TTMPAGE[] = {
-	0x1E, 0x27, 0x1E
+	30, 39, 30
 };
 
 static const int16 STAGE_2_VAL1_PART2[] = {
@@ -1019,9 +1019,9 @@ void DragonArcade::arcade2754(int16 floorY) {
 						}
 					} else if (_lastFloorY < floorY) {
 						if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
-							if (_arcadeTTM._startYOffset + 0x14 < floorY) {
+							if (_arcadeTTM._startYOffset + 20 < floorY) {
 								_bladeState1 = 1;
-								_npcState[0].ttmPage = _bladeStateOffset + 0x16;
+								_npcState[0].ttmPage = _bladePageOffset + 22;
 								_arcadeTTM._startYOffset += 10;
 								_uint0a17++;
 							} else {
@@ -1034,7 +1034,7 @@ void DragonArcade::arcade2754(int16 floorY) {
 						}
 					}
 				}
-			} else if ((_bladeState1 == 3 || _bladeState1 == 4) && 0x19 < abs(_lastFloorY - floorY) && _nTickUpdates) {
+			} else if ((_bladeState1 == 3 || _bladeState1 == 4) && 25 < abs(_lastFloorY - floorY) && _nTickUpdates) {
 				floorY = _lastFloorY;
 			}
 		}
@@ -1044,15 +1044,16 @@ void DragonArcade::arcade2754(int16 floorY) {
 	}
 }
 
-
-static const int16 INT_ARRAY_C5A[4][7] {
+// Array at 0c5a in original
+static const int16 NPC_RESET_COUNTS_1[4][7] {
 	{ 0x8, 0x19, 0x5A, 0x78, 0x8C, 0xA5, 0xBE },
 	{ 0x6, 0x28, 0x5A, 0x87, 0x96, 0xAA, 0xC0 },
 	{ 0x4, 0x37, 0x69, 0x79, 0x91, 0xA0, 0xC2 },
 	{ 0x2, 0x46, 0x69, 0x87, 0x9B, 0xAF, 0xC4 },
 };
 
-static const int16 INT_ARRAY_C92[4][7] {
+// Array at 0c92 in original
+static const int16 NPC_RESET_COUNTS_2[4][7] {
 	{ 0xA, 0x37, 0x46, 0x55, 0x91, 0xAA, 0xC8 },
 	{ 0x19, 0x5F, 0x87, 0x9B, 0xB9, 0xD7, -0x1 },
 	{ 0x19, 0x23, 0x69, 0x7D, 0x9B, 0xB9, 0xD7 },
@@ -1063,18 +1064,16 @@ static const int16 INT_ARRAY_C92[4][7] {
 void DragonArcade::arcade3e96() {
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 7; j++) {
-			if (_loadedArcadeStage == 0) {
-				if (_flag40ee && INT_ARRAY_C5A[i][j] == _someCounter40f0) {
-					_npcState[i + 10].ttmPage = 1;
-				}
+			if (_loadedArcadeStage == 0 && _flag40ee && NPC_RESET_COUNTS_1[i][j] == _npcStateResetCounter) {
+				_npcState[i + 10].ttmPage = 1;
 			} else if (_loadedArcadeStage == 1) {
-				if (INT_ARRAY_C92[i][j] == _someCounter40f0) {
+				if (NPC_RESET_COUNTS_2[i][j] == _npcStateResetCounter) {
 					_npcState[i + 4 + 10].ttmPage = 1;
 				}
-				if (_flag40ee && INT_ARRAY_C5A[i][j] == _someCounter40f0) {
+				if (_flag40ee && NPC_RESET_COUNTS_1[i][j] == _npcStateResetCounter) {
 					_npcState[i + 10].ttmPage = 1;
 				}
-			} else if (_loadedArcadeStage == 2 && _flag40ef && INT_ARRAY_C92[i][j] == _someCounter40f0) {
+			} else if (_loadedArcadeStage == 2 && _flag40ef && NPC_RESET_COUNTS_2[i][j] == _npcStateResetCounter) {
 				_npcState[i + 10].ttmPage = 1;
 			}
 		}
@@ -1089,7 +1088,7 @@ void DragonArcade::arcade3e96() {
 				playSfx(0x5a);
 			}
 			_npcState[i].byte12 = 0xfc;
-			if (_npcState[i].ttmPage < 0xf &&
+			if (_npcState[i].ttmPage < 15 &&
 				_npcState[i].xx - 16 <= _npcState[0].xx &&
 				_npcState[0].xx <= _npcState[i].xx + 12 && _npcState[0].health != 0 &&
 				(_loadedArcadeStage != 1 || _arcadeTTM._startYOffset < -9 ||
@@ -1098,19 +1097,19 @@ void DragonArcade::arcade3e96() {
 				_npcState[0].ttmNum = 2;
 				_npcState[0].health = 0;
 				if (_haveBigGun) {
-					_npcState[0].ttmPage = 0x19;
+					_npcState[0].ttmPage = 25;
 				} else {
-					_npcState[0].ttmPage = 0x22;
+					_npcState[0].ttmPage = 34;
 				}
 				_npcState[0].byte12 = 12;
-				_bladeState1 = 0xc;
+				_bladeState1 = 12;
 				_mouseButtonWentDown = 0x80;
 			}
 		}
 	}
-	_someCounter40f0++;
-	if (_someCounter40f0 == 221) {
-		_someCounter40f0 = 0;
+	_npcStateResetCounter++;
+	if (_npcStateResetCounter == 221) {
+		_npcStateResetCounter = 0;
 	}
 
 }
@@ -1190,14 +1189,14 @@ void DragonArcade::updateBlade() {
 			}
 			break;
 		case 3:
-			if ((0xf - i == (_nextRandomVal & 0xf)) &&
+			if ((15 - i == (_nextRandomVal % 16)) &&
 				 abs(_npcState[i].y - _npcState[0].y) < 36 && _npcState[0].health != 0) {
 				_npcState[i].byte12 = 2;
 				_npcState[i].ttmPage = startPage + 3;
 			}
 			break;
 		case 4:
-			if ((0xf - i == (_nextRandomVal & 0xf)) &&
+			if ((15 - i == (_nextRandomVal % 16)) &&
 				  abs(_npcState[i].y - _npcState[0].y) < 36 && _bladeState1 != 8 && _bladeState1 != 9) {
 				_npcState[i].byte12 = 3;
 				_npcState[i].ttmPage = startPage + 12;
@@ -1233,7 +1232,7 @@ void DragonArcade::updateBoss() {
 	int16 distToBoss = _npcState[1].x - _npcState[0].x;
 	int16 absDistToBoss = abs(distToBoss);
 	bool bossIsClose = absDistToBoss < 20;
-	uint16 randVal = _nextRandomVal & 0xf;
+	uint16 randVal = _nextRandomVal % 16;
 
 	switch(_npcState[1].byte12 - 1) {
 	case 0:
@@ -1246,11 +1245,11 @@ void DragonArcade::updateBoss() {
 			_npcState[1].byte12 = 3;
 			_npcState[1].ttmPage = 10;
 			_bossStateUpdateCounter++;
-		} else if ((bossIsClose && distToBoss < 70 && 0 < distToBoss && randVal == 0xf) || (0 < _bossStateUpdateCounter && randVal == 7)) {
+		} else if ((bossIsClose && distToBoss < 70 && 0 < distToBoss && randVal == 15) || (0 < _bossStateUpdateCounter && randVal == 7)) {
 			_npcState[1].byte12 = 2;
 			_npcState[1].ttmPage = 3;
 			_bossStateUpdateCounter--;
-		} else if (_bossStateUpdateCounter == 0 && randVal == 0xf) {
+		} else if (_bossStateUpdateCounter == 0 && randVal == 15) {
 			_npcState[1].byte12 = 4;
 			_npcState[1].ttmPage = 17;
 		}
@@ -1267,7 +1266,7 @@ void DragonArcade::updateBoss() {
 		if (0x37 < _npcState[1].ttmPage) {
 			decBossHealth();
 		}
-		if ((_npcState[1].ttmPage != 67 || (_nTickUpdates & 0x1fU) == 0) && _npcState[1].ttmPage < 74) {
+		if ((_npcState[1].ttmPage != 67 || (_nTickUpdates % 32) == 0) && _npcState[1].ttmPage < 74) {
 			if (_npcState[1].ttmPage < 68) {
 				_npcState[1].ttmPage++;
 			} else if (!(_nTickUpdates & 1)) {
@@ -1278,7 +1277,7 @@ void DragonArcade::updateBoss() {
 		}
 		break;
 	case 8:
-		if ((_npcState[1].ttmPage != 67 || (_nTickUpdates & 0x1fU) == 0) && _npcState[1].ttmPage < 74) {
+		if ((_npcState[1].ttmPage != 67 || (_nTickUpdates % 32) == 0) && _npcState[1].ttmPage < 74) {
 			playSfx(75);
 			setFinishCountdownIfLessThan0(20);
 			if (_npcState[1].ttmPage == 67) {
@@ -1361,7 +1360,7 @@ void DragonArcade::updateBoss() {
 }
 
 
-static const int16 BOSS_2_PAGE_OFFSETS[] = { 2, 2, 0xe, 0x1b, 0x21, 0x2a, 0x34, 0x3b };
+static const int16 BOSS_2_PAGE_OFFSETS[] = { 2, 2, 14, 27, 33, 42, 52, 59 };
 
 void DragonArcade::updateBoss2() {
 	if (_someMoveDirection > 0 && 269 < _scrollXOffset + _npcState[0].x / 8 && _scrollXOffset < 282) {
@@ -1384,18 +1383,18 @@ void DragonArcade::updateBoss2() {
 		} else {
 			_uint0be6 = 31;
 		}
-		if ((_nextRandomVal & 0xfU) == 0xf) {
+		if ((_nextRandomVal % 16) == 15) {
 			if (abs(_npcState[1].y - _npcState[0].y) > 35)
 				return;
 
 			_npcState[1].byte12 = 4;
 			_npcState[1].ttmPage = _uint0be6 + 9;
 		}
-		if ((_nextRandomVal & 0xfU) == 7 && absDistToBoss > 20 && _npcState[1].xx < 0x938) {
+		if ((_nextRandomVal % 16) == 7 && absDistToBoss > 20 && _npcState[1].xx < 0x938) {
 			_npcState[1].byte12 = 2;
 			_npcState[1].ttmPage = _uint0be6 + 2;
 		} else if (!_bladeHasFired || _npcState[1].xx < 0x939) {
-			if (absDistToBoss < 0x1e) {
+			if (absDistToBoss < 30) {
 				arcade34b4();
 			}
 		} else {
@@ -1404,7 +1403,7 @@ void DragonArcade::updateBoss2() {
 		}
 		break;
 	case 4:
-		if (_npcState[1].ttmPage < (_uint0be6 + 0x1f)) {
+		if (_npcState[1].ttmPage < (_uint0be6 + 31)) {
 			_npcState[1].ttmPage++;
 		}
 		break;
@@ -1426,7 +1425,7 @@ void DragonArcade::updateBoss2() {
 		} else {
 			_npcState[1].xx -= 8;
 		}
-		if (absDistToBoss < 0x1e) {
+		if (absDistToBoss < 30) {
 			arcade34b4();
 		}
 		break;
@@ -1461,7 +1460,7 @@ void DragonArcade::updateBoss2() {
 		}
 		break;
 	case 7:
-		if (_npcState[1].ttmPage < _uint0be6 + 0x1b) {
+		if (_npcState[1].ttmPage < _uint0be6 + 27) {
 			_npcState[1].ttmPage++;
 		} else if (absDistToBoss < 40) {
 			arcade34b4();
@@ -1478,8 +1477,8 @@ void DragonArcade::updateBoss2() {
 			}
 			byte bossByte12 = _npcState[1].byte12;
 			// Note: these never get changed? they're items in INT_TABLE_0BCE
-			const int16 INT_39e5_0be0 = 0x3A;
-			const int16 INT_39e5_0bda = 0x20;
+			const int16 INT_39e5_0be0 = 58;
+			const int16 INT_39e5_0bda = 32;
 			if (bossByte12 == 100) {
 				int16 absRand;
 				if (_mouseButtonWentDown == 1) {
@@ -1575,10 +1574,10 @@ void DragonArcade::decBossHealthAndCheck() {
 		_npcState[1].health--;
 		if (!_npcState[1].health) {
 			// boss is dead!
-			if (_npcState[1].ttmPage < 0x20) {
-				_npcState[1].ttmPage = 0x1c;
+			if (_npcState[1].ttmPage < 32) {
+				_npcState[1].ttmPage = 28;
 			} else {
-				_npcState[1].ttmPage = 0x3b;
+				_npcState[1].ttmPage = 59;
 			}
 			_npcState[1].byte12 = 5;
 			setFinishCountdownIfLessThan0(20);
@@ -1598,13 +1597,13 @@ void DragonArcade::bladeTakeHit() {
 	if (_npcState[0].health == 0) {
 		/* dead! */
 		playSfx(0x4b);
-		if ((_bladeState1 == 0 && _bladeStateOffset + 0x1c <= _npcState[0].ttmPage &&
-			 _npcState[0].ttmPage <= _bladeStateOffset + 0x23) || _bladeState1 == 4) {
+		if ((_bladeState1 == 0 && _bladePageOffset + 28 <= _npcState[0].ttmPage &&
+			 _npcState[0].ttmPage <= _bladePageOffset + 35) || _bladeState1 == 4) {
 			_bladeState1 = 9;
-			_npcState[0].ttmPage = _bladeStateOffset + 0x67;
+			_npcState[0].ttmPage = _bladePageOffset + 103;
 		} else {
 			_bladeState1 = 8;
-			_npcState[0].ttmPage = _bladeStateOffset + 0x62;
+			_npcState[0].ttmPage = _bladePageOffset + 98;
 		}
 		setFinishCountdownIfLessThan0(15);
 		_npcState[0].ttmNum = 0;
@@ -1688,9 +1687,9 @@ void DragonArcade::updateBladeWithInputs() {
 	}
 
 	if ((_bladeHorizMoveAttempt & kBladeMoveLeft) == kBladeMoveNone) {
-		_bladeStateOffset = 0;
+		_bladePageOffset = 0;
 	} else {
-		_bladeStateOffset = 0x7a;
+		_bladePageOffset = 122;
 	}
 	if (_bladeState1 == 0) {
 		if (!_dontMoveBladeFlag) {
@@ -1704,38 +1703,38 @@ void DragonArcade::updateBladeWithInputs() {
 
 	switch (_bladeState1 - 1) {
 	case 0:
-		if (_bladeStateOffset + 0x1a == _npcState[0].ttmPage) {
-			_npcState[0].ttmPage = _bladeStateOffset + 0x16;
+		if (_bladePageOffset + 26 == _npcState[0].ttmPage) {
+			_npcState[0].ttmPage = _bladePageOffset + 22;
 		}
-		newPage = _bladeStateOffset + 0x19;
+		newPage = _bladePageOffset + 25;
 		break;
 	case 1:
-		if (_bladeStateOffset + 0x3e == _npcState[0].ttmPage) {
-			_npcState[0].ttmPage = _bladeStateOffset + 0x38;
+		if (_bladePageOffset + 62 == _npcState[0].ttmPage) {
+			_npcState[0].ttmPage = _bladePageOffset + 56;
 		}
-		newPage = _bladeStateOffset + 0x3d;
-		if ((_bladeStateOffset + 0x32 < _npcState[0].ttmPage) &&
-			(_npcState[0].ttmPage <= _bladeStateOffset + 0x38)) {
+		newPage = _bladePageOffset + 61;
+		if ((_bladePageOffset + 50 < _npcState[0].ttmPage) &&
+			(_npcState[0].ttmPage <= _bladePageOffset + 56)) {
 			moveBladeX();
 		}
 		break;
 	case 2:
-		newPage = _bladeStateOffset + 0x7b;
+		newPage = _bladePageOffset + 123;
 		break;
 	case 3:
-		newPage = _bladeStateOffset + 0x2c;
+		newPage = _bladePageOffset + 44;
 		break;
 	case 4:
-		_npcState[0].ttmPage = _bladeStateOffset + 0x40;
+		_npcState[0].ttmPage = _bladePageOffset + 64;
 		moveBladeX();
 		newPage = 999;
 		break;
 	case 5:
-		newPage = _bladeStateOffset + 0x61;
+		newPage = _bladePageOffset + 97;
 		break;
 	case 6:
-		newPage = _bladeStateOffset + 0x4d;
-		if (_bladeStateOffset == 0) {
+		newPage = _bladePageOffset + 77;
+		if (_bladePageOffset == 0) {
 			_scrollVelocityX = 1;
 		} else {
 			_scrollVelocityX = -1;
@@ -1745,21 +1744,21 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		break;
 	case 7:
-		if (_npcState[0].ttmPage < _bladeStateOffset + 0x66) {
+		if (_npcState[0].ttmPage < _bladePageOffset + 102) {
 			_npcState[0].ttmPage++;
 		} else {
-			_npcState[0].ttmPage = _bladeStateOffset + 0x66;
+			_npcState[0].ttmPage = _bladePageOffset + 102;
 		}
 		return;
 	case 8:
-		if (_npcState[0].ttmPage < _bladeStateOffset + 0x6c) {
+		if (_npcState[0].ttmPage < _bladePageOffset + 108) {
 			_npcState[0].ttmPage++;
 		} else {
-			_npcState[0].ttmPage = _bladeStateOffset + 0x6c;
+			_npcState[0].ttmPage = _bladePageOffset + 108;
 		}
 		return;
 	case 9:
-		if (_npcState[0].ttmPage < 0x4f) {
+		if (_npcState[0].ttmPage < 79) {
 			_npcState[0].ttmPage++;
 			_scrollVelocityX = -1;
 			moveBladeX();
@@ -1768,13 +1767,13 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		return;
 	case 10:
-		if (_npcState[0].ttmPage < (_haveBigGun ? 0x19 : 0xe)) {
+		if (_npcState[0].ttmPage < (_haveBigGun ? 25 : 14)) {
 			_npcState[0].ttmPage++;
 		} else {
-			_npcState[3].xx = _npcState[0].xx + 0x16;
-			_npcState[3].yy = -0x20;
+			_npcState[3].xx = _npcState[0].xx + 22;
+			_npcState[3].yy = -32;
 			_npcState[3].byte12 = -2;
-			_npcState[3].ttmPage = 0x21;
+			_npcState[3].ttmPage = 33;
 			_npcState[3].ttmNum = 2;
 			_npcState[3].health = 20;
 			_npcState[0].ttmNum = 0;
@@ -1783,9 +1782,9 @@ void DragonArcade::updateBladeWithInputs() {
 		return;
 	case 11:
 		if (!_haveBigGun) {
-			newPage = 0x28;
+			newPage = 40;
 		} else {
-			newPage = 0x1f;
+			newPage = 31;
 		}
 		if (newPage < _npcState[0].ttmPage + 1) {
 			_npcState[0].ttmPage = newPage;
@@ -1799,11 +1798,11 @@ void DragonArcade::updateBladeWithInputs() {
 		}
 		_npcState[0].ttmPage++;
 		if (_haveBigGun) {
-			if (_npcState[0].ttmPage > 0x3d)
-				_npcState[0].ttmPage = 0x3d;
+			if (_npcState[0].ttmPage > 61)
+				_npcState[0].ttmPage = 61;
 		} else {
-			if (_npcState[0].ttmPage > 0x39) {
-				_npcState[0].ttmPage = 0x39;
+			if (_npcState[0].ttmPage > 57) {
+				_npcState[0].ttmPage = 57;
 			}
 		}
 		return;
@@ -1811,10 +1810,10 @@ void DragonArcade::updateBladeWithInputs() {
 		if (!(_nTickUpdates & 1)) {
 			return;
 		}
-		if (_npcState[0].ttmPage + 1 < 0x26) {
+		if (_npcState[0].ttmPage + 1 < 38) {
 			_npcState[0].ttmPage++;
 		} else {
-			_npcState[0].ttmPage = 0x22;
+			_npcState[0].ttmPage = 34;
 		}
 		return;
 	default:
@@ -1828,11 +1827,11 @@ void DragonArcade::updateBladeWithInputs() {
 		handleMouseStates();
 	} else if (_uint0a17 == 0) {
 		if (_bladeState1 == 1) {
-			if (_bladeStateOffset + 0x16 == _npcState[0].ttmPage) {
+			if (_bladePageOffset + 22 == _npcState[0].ttmPage) {
 				_ttmYAdjust = _int0b58 * -4;
 				_uint0a17 = 1;
 			}
-		} else if (_bladeState1 == 2 && _bladeStateOffset + 0x38 == _npcState[0].ttmPage) {
+		} else if (_bladeState1 == 2 && _bladePageOffset + 56 == _npcState[0].ttmPage) {
 			_ttmYAdjust = _int0b58 * -4;
 			_uint0a17 = 1;
 		}
@@ -1840,9 +1839,9 @@ void DragonArcade::updateBladeWithInputs() {
 		if (_mouseButtonWentDown == 1) {
 			_mouseButtonWentDown = 0;
 			if (_bladeState1 == 2) {
-				_npcState[0].ttmPage = _bladeStateOffset + 0x3f;
+				_npcState[0].ttmPage = _bladePageOffset + 63;
 			} else if (_bladeState1 == 1) {
-				_npcState[0].ttmPage = _bladeStateOffset + 0x1b;
+				_npcState[0].ttmPage = _bladePageOffset + 27;
 			}
 		}
 		if (_bladeState1 == 1 || _bladeState1 == 2 || _bladeState1 == 5) {
@@ -1905,45 +1904,45 @@ void DragonArcade::handleMouseStates() {
 		if ((_bladeMoveFlag & (kBladeMoveRight | kBladeMoveLeft)) == kBladeMoveNone) {
 			/* not moving up or down */
 			if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
-				_npcState[0].ttmPage = _bladeStateOffset + 2;
+				_npcState[0].ttmPage = _bladePageOffset + 2;
 			} else {
-				_npcState[0].ttmPage = _bladeStateOffset + 0xe;
+				_npcState[0].ttmPage = _bladePageOffset + 14;
 			}
 		} else {
 			moveBladeX();
 			if (!_foundFloorFlag) {
-				if ((_npcState[0].ttmPage < _bladeStateOffset + 0x6d) ||
-					(_bladeStateOffset + 0x70 < _npcState[0].ttmPage)) {
-					_npcState[0].ttmPage = _bladeStateOffset + 0x6d;
+				if ((_npcState[0].ttmPage < _bladePageOffset + 109) ||
+					(_bladePageOffset + 112 < _npcState[0].ttmPage)) {
+					_npcState[0].ttmPage = _bladePageOffset + 109;
 				}
 			} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
-				if ((_npcState[0].ttmPage < _bladeStateOffset + 3) ||
-					(_bladeStateOffset + 10 < _npcState[0].ttmPage)) {
-					_npcState[0].ttmPage = _bladeStateOffset + 3;
+				if ((_npcState[0].ttmPage < _bladePageOffset + 3) ||
+					(_bladePageOffset + 10 < _npcState[0].ttmPage)) {
+					_npcState[0].ttmPage = _bladePageOffset + 3;
 				}
-			} else if ((_npcState[0].ttmPage < _bladeStateOffset + 0x1c) ||
-					   (_bladeStateOffset + 0x23 < _npcState[0].ttmPage)) {
-				_npcState[0].ttmPage = _bladeStateOffset + 0x1c;
+			} else if ((_npcState[0].ttmPage < _bladePageOffset + 28) ||
+					   (_bladePageOffset + 35 < _npcState[0].ttmPage)) {
+				_npcState[0].ttmPage = _bladePageOffset + 28;
 			}
 		}
 	} else if (_mouseButtonWentDown == 1) {
 		if (_loadedArcadeStage == 3 && _haveBomb && _npcState[1].health != 0 &&
-			  0x19 < abs(_npcState[1].y - _npcState[0].y) && abs(_npcState[1].x - _npcState[0].x) < 0x28) {
+			  25 < abs(_npcState[1].y - _npcState[0].y) && abs(_npcState[1].x - _npcState[0].x) < 40) {
 			// use a bomb
-			_bladeState1 = 0xb;
+			_bladeState1 = 11;
 			_haveBomb = false;
 			_npcState[0].ttmNum = 2;
 			if (!_haveBigGun) {
 				_npcState[0].ttmPage = 4;
 			} else {
-				_npcState[0].ttmPage = 0xf;
+				_npcState[0].ttmPage = 15;
 			}
 		} else if ((_bladeMoveFlag & kBladeMoveDown) == kBladeMoveNone) {
 			_bladeState1 = 3;
-			_npcState[0].ttmPage = _bladeStateOffset + 0x71;
+			_npcState[0].ttmPage = _bladePageOffset + 113;
 		} else {
 			_bladeState1 = 4;
-			_npcState[0].ttmPage = _bladeStateOffset + 0x24;
+			_npcState[0].ttmPage = _bladePageOffset + 36;
 		}
 	} else if (_mouseButtonWentDown == 2) {
 		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == kBladeMoveNone) {
@@ -1966,15 +1965,15 @@ void DragonArcade::handleMouseStates() {
 		_int0b5a = 0;
 		_scrollVelocityX = 0;
 		if ((_bladeMoveFlag & kBladeMoveLeft) == kBladeMoveNone) {
-			_bladeStateOffset = 0;
+			_bladePageOffset = 0;
 		} else {
-			_bladeStateOffset = 0x7a;
+			_bladePageOffset = 122;
 		}
 
 		if ((_bladeMoveFlagBeforeRButton & (kBladeMoveLeft | kBladeMoveRight)) == kBladeMoveNone) {
 			// Not jumping left or right
 			_bladeState1 = 1;
-			_npcState[0].ttmPage = _bladeStateOffset + 15;
+			_npcState[0].ttmPage = _bladePageOffset + 15;
 			debug("Move: blade jump up -> ttm %d", _npcState[0].ttmPage);
 		} else {
 			// Jump to left or right
@@ -1985,7 +1984,7 @@ void DragonArcade::handleMouseStates() {
 			}
 			_isMovingStage = false;
 			_bladeState1 = 2;
-			_npcState[0].ttmPage = _bladeStateOffset + 0x2d;
+			_npcState[0].ttmPage = _bladePageOffset + 45;
 			debug("Move: blade jump up -> ttm %d velocity %d", _npcState[0].ttmPage, _scrollVelocityX);
 		}
 
@@ -1993,9 +1992,9 @@ void DragonArcade::handleMouseStates() {
 			findFloorMinGT();
 			if (!isFloorNotFound()) {
 				if (_bladeState1 == 2) {
-					_npcState[0].ttmPage = _bladeStateOffset + 0x38;
+					_npcState[0].ttmPage = _bladePageOffset + 56;
 				} else {
-					_npcState[0].ttmPage = _bladeStateOffset + 0x16;
+					_npcState[0].ttmPage = _bladePageOffset + 22;
 				}
 				debug("Move: blade jump down -> ttm %d", _npcState[0].ttmPage);
 				_arcadeTTM._startYOffset++;
@@ -2112,11 +2111,11 @@ static const int16 STAGE_0_NPC2_XX_2[] = {
 };
 
 static const int16 STAGE_0_NPC2_TTMPAGE[] = {
-	 0, 0x1E, 0xF, 0
+	 0, 30, 15, 0
 };
 
 void DragonArcade::initValuesForStage0() {
-	_someCounter40f0 = 0;
+	_npcStateResetCounter = 0;
 	for (int i = 10; i < 14; i++) {
 		_npcState[i].xx = STAGE_0_NPC2_XX_1[i - 10];
 		_npcState[i].yy = 2;
@@ -2132,8 +2131,8 @@ void DragonArcade::initValuesForStage0() {
 	_flag40ef = true;
 	_npcState[18].xx = 0x11f;
 	_npcState[18].yy = -13;
-	_npcState[18].byte12 = 0x1e;
-	_npcState[18].ttmPage = 0x20;
+	_npcState[18].byte12 = 30;
+	_npcState[18].ttmPage = 32;
 	_npcState[18].ttmNum = 2;
 }
 
@@ -2164,7 +2163,7 @@ static const int16 STAGE_4_NPC_YY[] = {
 };
 
 static const int16 STAGE_4_ST_TTMPAGE[] = {
-	0, 0, 0xf, 0xf, 0x28
+	0, 0, 15, 15, 40
 };
 
 static const byte STAGE_4_ST_BYTE12[] = {
@@ -2172,7 +2171,7 @@ static const byte STAGE_4_ST_BYTE12[] = {
 };
 
 void DragonArcade::initValuesForStage4() {
-	_someCounter40f0 = 0;
+	_npcStateResetCounter = 0;
 	for (int i = 10; i < 15; i++) {
 		_npcState[i].xx = STAGE_4_NPC_XX[i - 10];
 		_npcState[i].yy = STAGE_4_NPC_YY[i - 10];
@@ -2436,7 +2435,7 @@ void DragonArcade::bladeTakeHitAndCheck() {
 		_npcState[0].health--;
 	if (_npcState[0].health <= 0) {
 		playSfx(75);
-		if ((_bladeState1 == 0 && _bladeStateOffset + 28 < _npcState[0].ttmPage && _npcState[0].ttmPage <= 35)
+		if ((_bladeState1 == 0 && _bladePageOffset + 28 < _npcState[0].ttmPage && _npcState[0].ttmPage <= 35)
 			|| _bladeState1 == 4) {
 			_bladeState1 = 9;
 			_npcState[0].ttmPage = _bladeState1 + 103;
@@ -2455,19 +2454,21 @@ void DragonArcade::bladeTakeHitAndCheck() {
 void DragonArcade::drawHealthBars() {
 	DgdsEngine *engine = DgdsEngine::getInstance();
 
-	//if (_npcState[0].health != _lastDrawnBladeHealth) {
-		const Common::Rect clearRect1(Common::Point(10, 155), 64, 10);
-		engine->_compositionBuffer.fillRect(clearRect1, 0);
+	// Note: the original here checks _npcState[0].health vs _lastDrawnBladeHealth
+	// and _npcState[1].health vs _lastDrawnBossHealth to avoid redrawing every time,
+	// but we clear the screen every time so just redraw it each time.
 
-		for (int i = 1; i <= _npcState[0].health; i++) {
-			int x = 8 + i * 2;
-			engine->_compositionBuffer.drawLine(x, 155, x, 162, 12);
-		}
+	const Common::Rect clearRect1(Common::Point(10, 155), 64, 10);
+	engine->_compositionBuffer.fillRect(clearRect1, 0);
 
-		_lastDrawnBladeHealth = _npcState[0].health;
-	//}
+	for (int i = 1; i <= _npcState[0].health; i++) {
+		int x = 8 + i * 2;
+		engine->_compositionBuffer.drawLine(x, 155, x, 162, 12);
+	}
+
+	_lastDrawnBladeHealth = _npcState[0].health;
 
-	if (((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) /*&& (_npcState[1].health != _lastDrawnBossHealth)*/) {
+	if ((_loadedArcadeStage == 3 || _loadedArcadeStage == 6) || _lastDrawnBossHealth == -1) {
 		const Common::Rect clearRect2(Common::Point(10, 167), 60, 8);
 		engine->_compositionBuffer.fillRect(clearRect2, 0);
 
@@ -2535,7 +2536,7 @@ void DragonArcade::runThenDrawBulletsInFlight() {
 		} else if (_bullets[i]._state == kBulletFlying) {
 			int16 frameno;
 			if (_bullets[i]._bulletType == 3) {
-				// FIXME: this is a bit weird?
+				// TODO: check this.. it's a bit weird?
 				frameno = (_nextRandomVal % 3);
 			} else {
 				frameno = 0;
diff --git a/engines/dgds/dragon_arcade.h b/engines/dgds/dragon_arcade.h
index 8c7797c901a..00489ae185c 100644
--- a/engines/dgds/dragon_arcade.h
+++ b/engines/dgds/dragon_arcade.h
@@ -167,13 +167,13 @@ private:
 	int16 _shouldUpdateState;
 	int16 _finishCountdown;
 	int16 _bladeState1;
-	int16 _bladeStateOffset;
+	int16 _bladePageOffset;
 	uint16 _mouseButtonWentDown;
 	int16 _scrollXOffset;
 	int32 _nTickUpdates;
 	int16 _startDifficultyMaybe;
 	int16 _bossStateUpdateCounter;
-	int16 _someCounter40f0;
+	int16 _npcStateResetCounter;
 	int16 _scrollVelocityX;
 	uint16 _uint0a17;
 	int16 _currentYOffset;
diff --git a/engines/dgds/scene.cpp b/engines/dgds/scene.cpp
index 7595f8c1e76..33621b93897 100644
--- a/engines/dgds/scene.cpp
+++ b/engines/dgds/scene.cpp
@@ -751,11 +751,9 @@ bool Scene::runDragonOp(const SceneOp &op) {
 		engine->getScene()->addAndShowTiredDialog();
 		break;
 	case kSceneOpArcadeTick:
-		// TODO: Implement this properly! for now just
-		// set the global arcade state variable to the "skip" value.
-		//warning("Setting arcade global to 8 (skip)");
-		//g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
-		//engine->getGameGlobals()->setGlobal(0x21, 6);
+		// TODO: Add a configuration option to skip arcade sequence?
+		// g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
+		// engine->getGameGlobals()->setGlobal(0x21, 6);
 		engine->getDragonArcade()->arcadeTick();
 		break;
 	case kSceneOpDrawDragonCountdown1:




More information about the Scummvm-git-logs mailing list