[Scummvm-git-logs] scummvm master -> 22a87016add2f81697cbe7e54b96a1418b976a94

neuromancer noreply at scummvm.org
Wed May 25 11:01:29 UTC 2022


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

Summary:
95217f6ffa HYPNO: basic implementation of the retry menu in boyz
5a6bb5a691 HYPNO: improved implementation of the retry menu in boyz
fbe34784ac HYPNO: correctly implemented the team health in boyz
a2a6f9f3b4 HYPNO: removed _ammoTeam variable to use _ammo instead in boyz
3aa0004868 HYPNO: implemented mouse support for retry menu in boyz
7793754c33 HYPNO: add code to show game credits in boyz
430c703c03 HYPNO: implement basic difficulty selection menu in boyz
55a9e96b3d HYPNO: implement save and load of player profiles in boyz
9c720c8c60 HYPNO: count the number of used lives in boyz
4420f6ccf9 HYPNO: show game profiles in main menu in boyz
d034cc1ba2 HYPNO: improved profile saving in boyz
bae1dffdde HYPNO: skip level is captor is not killed in boyz
6a16c8bbb5 HYPNO: added basic implementation for selection in specific scenes in boyz
f6b018140b HYPNO: corrected default cursor in boyz
c443f2e93f HYPNO: partial implementation of the select screen in level c3 in boyz
ffdefe757d HYPNO: save/load game state variables and some fixes in boyz
bbbf96a166 HYPNO: implement select_ho level in boyz
d76aac7830 HYPNO: allow to run level c35 with no weapon in boyz
a62e363ab8 HYPNO: initial implementation of level c35 in boyz
7c9ff5842c HYPNO: refactor check conditions for c3 levels in boyz
78a96a91c4 HYPNO: update game state when player wins the cup game in boyz
5e321a0e66 HYPNO: allow to stop and wait for a user action in the middle of arcade sequence in boyz
382b7b0ff6 HYPNO: fixes for level c51 in boyz
f30fb8706b HYPNO: correctly finish level c353 in boyz
22a87016ad HYPNO: correctly finish levels c352 and c355 in boyz


Commit: 95217f6ffaf49d385dd26f0839c27eb0fe69bb6b
    https://github.com/scummvm/scummvm/commit/95217f6ffaf49d385dd26f0839c27eb0fe69bb6b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: basic implementation of the retry menu in boyz

Changed paths:
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index c387311a5f7..df83f624bf9 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -90,40 +90,43 @@ void BoyzEngine::loadAssets() {
 	_levels["<main_menu>"] = menu;
 	_levels["<main_menu>"]->levelIfWin = "<select_boyz>";
 
-	loadArcadeLevel("c19.mi_", "c11.mi_", "??", "");
-	loadArcadeLevel("c11.mi_", "c12.mi_", "??", "");
-	loadArcadeLevel("c12.mi_", "c14.mi_", "??", "");
-	loadArcadeLevel("c14.mi_", "c13.mi_", "??", "");
-	loadArcadeLevel("c13.mi_", "c15.mi_", "??", "");
-	loadArcadeLevel("c15.mi_", "c16.mi_", "??", "");
-	loadArcadeLevel("c16.mi_", "c17.mi_", "??", "");
-	loadArcadeLevel("c17.mi_", "c18.mi_", "??", "");
-	loadArcadeLevel("c18.mi_", "c21.mi_", "??", "");
-
-	loadArcadeLevel("c21.mi_", "c22.mi_", "??", "");
-	loadArcadeLevel("c22.mi_", "c31.mi_", "??", "");
-	loadArcadeLevel("c31.mi_", "c32.mi_", "??", "");
-	loadArcadeLevel("c32.mi_", "c33.mi_", "??", "");
-	loadArcadeLevel("c33.mi_", "c34.mi_", "??", "");
-	loadArcadeLevel("c34.mi_", "c35.mi_", "??", "");
-	loadArcadeLevel("c35.mi_", "c352.mi_", "??", "");
-	loadArcadeLevel("c352.mi_", "c353.mi_", "??", "");
-	loadArcadeLevel("c353.mi_", "c354.mi_", "??", "");
-	loadArcadeLevel("c354.mi_", "c355.mi_", "??", "");
-	loadArcadeLevel("c355.mi_", "c36.mi_", "??", "");
-	loadArcadeLevel("c36.mi_", "c41.mi_", "??", "");
-	loadArcadeLevel("c41.mi_", "c42.mi_", "??", "");
-	loadArcadeLevel("c42.mi_", "c51.mi_", "??", "");
-
-	loadArcadeLevel("c51.mi_", "c52.mi_", "??", "");
-	loadArcadeLevel("c52.mi_", "c53.mi_", "??", "");
-	loadArcadeLevel("c53.mi_", "c54.mi_", "??", "");
-	loadArcadeLevel("c54.mi_", "c55.mi_", "??", "");
-	loadArcadeLevel("c55.mi_", "c56.mi_", "??", "");
-	loadArcadeLevel("c56.mi_", "c57.mi_", "??", "");
-	loadArcadeLevel("c57.mi_", "c58.mi_", "??", "");
-	loadArcadeLevel("c58.mi_", "c59.mi_", "??", "");
-	loadArcadeLevel("c59.mi_", "<credits>", "??", "");
+	Code *retry = new Code("<retry_menu>");
+	_levels["<retry_menu>"] = retry;
+
+	loadArcadeLevel("c19.mi_", "c11.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c11.mi_", "c12.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c12.mi_", "c14.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c14.mi_", "c13.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c13.mi_", "c15.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c15.mi_", "c16.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c16.mi_", "c17.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c17.mi_", "c18.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c18.mi_", "c21.mi_", "<retry_menu>", "");
+
+	loadArcadeLevel("c21.mi_", "c22.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c22.mi_", "c31.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c31.mi_", "c32.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c32.mi_", "c33.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c33.mi_", "c34.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c34.mi_", "c35.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c35.mi_", "c352.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c352.mi_", "c353.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c353.mi_", "c354.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c354.mi_", "c355.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c355.mi_", "c36.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c36.mi_", "c41.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c41.mi_", "c42.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c42.mi_", "c51.mi_", "<retry_menu>", "");
+
+	loadArcadeLevel("c51.mi_", "c52.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c52.mi_", "c53.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c53.mi_", "c54.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c54.mi_", "c55.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c55.mi_", "c56.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c56.mi_", "c57.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c57.mi_", "c58.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c58.mi_", "c59.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c59.mi_", "<credits>", "<retry_menu>", "");
 
 	loadSceneLevel(selectBoyz, "<select_boyz>", "", "");
 	Scene *sc = (Scene *) _levels["<select_boyz>"];
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 7a69e23d5c3..2ccb0668be9 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -32,6 +32,8 @@ namespace Hypno {
 void BoyzEngine::runCode(Code *code) {
 	if (code->name == "<main_menu>")
 		runMainMenu(code);
+	else if (code->name == "<retry_menu>")
+		runRetryMenu(code);
 	else
 		error("invalid hardcoded level: %s", code->name.c_str());
 }
@@ -86,4 +88,49 @@ void BoyzEngine::runMainMenu(Code *code) {
 	delete menu;
 }
 
+void BoyzEngine::runRetryMenu(Code *code) {
+	_lives--;
+
+	uint32 idx = _rnd->getRandomNumber(_deathVideo.size() - 1);
+	Filename filename = _deathVideo[idx];
+	MVideo video(filename, Common::Point(0, 0), false, true, false);
+	disableCursor();
+	runIntro(video);
+
+	Common::Event event;
+	byte *palette;
+	Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 3, &palette);
+	loadPalette(palette, 0, 256);
+	drawImage(*menu, 0, 0, false);
+	bool cont = true;
+	while (!shouldQuit() && cont) {
+		while (g_system->getEventManager()->pollEvent(event)) {
+			// Events
+			switch (event.type) {
+
+			case Common::EVENT_QUIT:
+			case Common::EVENT_RETURN_TO_LAUNCHER:
+				break;
+
+			case Common::EVENT_KEYDOWN:
+				if (event.kbd.keycode == Common::KEYCODE_s) {
+					_nextLevel = _checkpoint;
+					cont = false;
+				}
+				break;
+
+			default:
+				break;
+			}
+		}
+
+		drawScreen();
+		g_system->delayMillis(10);
+	}
+
+	menu->free();
+	delete menu;
+}
+
+
 } // End of namespace Hypno
\ No newline at end of file
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index 4df9fd83eae..5f502031a4b 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -566,6 +566,7 @@ public:
 
 	private:
 	void runMainMenu(Code *code);
+	void runRetryMenu(Code *code);
 
 	int _ammoTeam[7];
 	int _healthTeam[7];


Commit: 5a6bb5a691eeb36796982c2971aabd470091a2b9
    https://github.com/scummvm/scummvm/commit/5a6bb5a691eeb36796982c2971aabd470091a2b9
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: improved implementation of the retry menu in boyz

Changed paths:
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 2ccb0668be9..04991a09349 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -99,7 +99,7 @@ void BoyzEngine::runRetryMenu(Code *code) {
 
 	Common::Event event;
 	byte *palette;
-	Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 3, &palette);
+	Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 5, &palette);
 	loadPalette(palette, 0, 256);
 	drawImage(*menu, 0, 0, false);
 	bool cont = true;
@@ -116,6 +116,15 @@ void BoyzEngine::runRetryMenu(Code *code) {
 				if (event.kbd.keycode == Common::KEYCODE_s) {
 					_nextLevel = _checkpoint;
 					cont = false;
+				} else if (event.kbd.keycode == Common::KEYCODE_t) {
+					// Restore initial health for the team
+					for (int i = 0; i < 7; i++)
+						_healthTeam[i] = _maxHealth;
+
+					_nextLevel = firstLevelTerritory(_checkpoint);
+					cont = false;
+				} else if (event.kbd.keycode == Common::KEYCODE_q) {
+					quitGame();
 				}
 				break;
 
@@ -132,5 +141,19 @@ void BoyzEngine::runRetryMenu(Code *code) {
 	delete menu;
 }
 
+Common::String BoyzEngine::firstLevelTerritory(const Common::String &level) {
+	if (Common::matchString(level.c_str(), "c1#.mi_"))
+		return "c19.mi_";
+	else if (Common::matchString(level.c_str(), "c2#.mi_"))
+		return "c21.mi_";
+	else if (Common::matchString(level.c_str(), "c3#.mi_"))
+		return "c31.mi_";
+	else if (Common::matchString(level.c_str(), "c4#.mi_"))
+		return "c41.mi_";
+	else if (Common::matchString(level.c_str(), "c5#.mi_"))
+		return "c51.mi_";
+	else
+		error("Invalid territory for level %s", level.c_str());
+}
 
 } // End of namespace Hypno
\ No newline at end of file
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index 5f502031a4b..cb120ad294c 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -567,6 +567,8 @@ public:
 	private:
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);
+	Common::String firstLevelTerritory(const Common::String &level);
+
 
 	int _ammoTeam[7];
 	int _healthTeam[7];


Commit: fbe34784ac78d7cbbbaf14a8f717460baacf11e4
    https://github.com/scummvm/scummvm/commit/fbe34784ac78d7cbbbaf14a8f717460baacf11e4
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: correctly implemented the team health in boyz

Changed paths:
    engines/hypno/arcade.cpp
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h
    engines/hypno/spider/arcade.cpp
    engines/hypno/wet/arcade.cpp


diff --git a/engines/hypno/arcade.cpp b/engines/hypno/arcade.cpp
index 6fdaa6e4489..bb892bd6447 100644
--- a/engines/hypno/arcade.cpp
+++ b/engines/hypno/arcade.cpp
@@ -219,8 +219,6 @@ void HypnoEngine::runArcade(ArcadeShooting *arc) {
 	_shootSound = arc->shootSound;
 	_hitSound = arc->hitSound;
 	_additionalSound = arc->additionalSound;
-	_health = arc->health;
-	_maxHealth = _health;
 	debugC(1, kHypnoDebugArcade, "Starting segment of type %x of size %d", segments[_segmentIdx].type, segments[_segmentIdx].size);
 	_shoots.clear();
 	_skipLevel = false;
diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 1f1e4aab5ad..c5610dbfe8a 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -58,6 +58,7 @@ void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
 
 	updateFromScript();
 	_shootsDestroyed.clear();
+	_health = _previousHealth;
 }
 
 void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
@@ -66,11 +67,12 @@ void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
 		delete _playerFrames[i];
 	}
 
-	if (_healthTeam[_currentActor] <= 0) {
+	if (_health <= 0) {
 		MVideo video(_deathDay[_currentActor], Common::Point(0, 0), false, true, false);
 		disableCursor();
 		runIntro(video);
-	}
+	} else
+		_previousHealth = _health;
 
 }
 
@@ -81,7 +83,6 @@ void BoyzEngine::pressedKey(const int keycode) {
 			return;
 		}
 	} else if (keycode == Common::KEYCODE_k) { // Added for testing
-		_healthTeam[_currentActor] = 0;
 		_health = 0;
 	} else if (keycode == Common::KEYCODE_ESCAPE) {
 		openMainMenuDialog();
@@ -126,7 +127,7 @@ void BoyzEngine::drawPlayer() {
 void BoyzEngine::drawHealth() {
 	updateFromScript();
 
-	float w = float(_healthTeam[_currentActor]) / float(_maxHealth);
+	float w = float(_health) / float(_maxHealth);
 	Common::Rect healthBarBox(0, 0, int((_healthBar[_currentActor].w - 3) * w), _healthBar[_currentActor].h / 2);
 
 	uint32 c = kHypnoColorWhiteOrBlue; // white
@@ -161,8 +162,7 @@ void BoyzEngine::hitPlayer() {
 	_compositeSurface->fillRect(Common::Rect(0, 0, _screenW, _screenH), c);
 	drawScreen();
 	if (!_infiniteHealthCheat) {
-		_healthTeam[_currentActor] = _healthTeam[_currentActor] - 10;
-		_health = _healthTeam[_currentActor];
+		_health = _health - 10;
 	}
 	if (!_hitSound.empty())
 		playSound(_soundPath + _hitSound, 1, 11025);
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index df83f624bf9..128b99a339f 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -322,9 +322,8 @@ void BoyzEngine::loadAssets() {
 	_warningHostage = "warnings/w08s.smk";
 
 	// Set initial health for the team
-	for (int i = 0; i < 7; i++) {
-		_healthTeam[i] = _maxHealth;
-	}
+	_health = _maxHealth;
+	_previousHealth = _maxHealth;
 
 	targets->free();
 	delete targets;
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 04991a09349..e2242002b99 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -118,8 +118,7 @@ void BoyzEngine::runRetryMenu(Code *code) {
 					cont = false;
 				} else if (event.kbd.keycode == Common::KEYCODE_t) {
 					// Restore initial health for the team
-					for (int i = 0; i < 7; i++)
-						_healthTeam[i] = _maxHealth;
+					_health = _maxHealth;
 
 					_nextLevel = firstLevelTerritory(_checkpoint);
 					cont = false;
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index cb120ad294c..dfd30be35f0 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -571,7 +571,7 @@ public:
 
 
 	int _ammoTeam[7];
-	int _healthTeam[7];
+	int _previousHealth;
 	Graphics::Surface _healthBar[7];
 	Graphics::Surface _ammoBar[7];
 	Graphics::Surface _portrait[7];
diff --git a/engines/hypno/spider/arcade.cpp b/engines/hypno/spider/arcade.cpp
index 342197884ff..6cca363fa77 100644
--- a/engines/hypno/spider/arcade.cpp
+++ b/engines/hypno/spider/arcade.cpp
@@ -34,6 +34,9 @@ static const int shootOriginIndex[9][2] = {
 	{41, 3}, {51, 3}, {65, 6}, {40, 16}, {58, 20}, {67, 10}, {37, 14}, {37, 15}, {67, 22}};
 
 void SpiderEngine::runBeforeArcade(ArcadeShooting *arc) {
+	_health = arc->health;
+	_maxHealth = _health;
+
 	_checkpoint = _currentLevel;
 	assert(!arc->player.empty());
 	_playerFrames = decodeFrames(arc->player);
diff --git a/engines/hypno/wet/arcade.cpp b/engines/hypno/wet/arcade.cpp
index f99b7f1ee08..befa31d9260 100644
--- a/engines/hypno/wet/arcade.cpp
+++ b/engines/hypno/wet/arcade.cpp
@@ -497,6 +497,8 @@ uint32 WetEngine::findPaletteIndexZones(uint32 id) {
 }
 
 void WetEngine::runBeforeArcade(ArcadeShooting *arc) {
+	_health = arc->health;
+	_maxHealth = _health;
 	resetStatistics();
 	_checkpoint = _currentLevel;
 	MVideo *video;


Commit: a2a6f9f3b4b1778b6f584db8668fd7605a68c329
    https://github.com/scummvm/scummvm/commit/a2a6f9f3b4b1778b6f584db8668fd7605a68c329
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: removed _ammoTeam variable to use _ammo instead in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index c5610dbfe8a..f7a3c376263 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -53,7 +53,7 @@ void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
 	_currentScript = arc->script;
 	// Reload all weapons
 	for (Script::iterator it = _currentScript.begin(); it != _currentScript.end(); ++it) {
-		_ammoTeam[it->actor] = _weaponMaxAmmo[it->cursor];
+		_ammo = _weaponMaxAmmo[it->cursor];
 	}
 
 	updateFromScript();
@@ -94,6 +94,9 @@ void BoyzEngine::updateFromScript() {
 		ScriptInfo si = *_currentScript.begin();
 		//debug("%d %d %d", si.time, _background->decoder->getCurFrame(), si.actor);
 		if (!_background || int(si.time) <= _background->decoder->getCurFrame()) {
+			if (_currentActor != si.actor)
+				_ammo = _weaponMaxAmmo[si.cursor];
+
 			_currentActor = si.actor;
 			_currentMode = si.mode;
 			_currentWeapon = si.cursor;
@@ -146,7 +149,7 @@ void BoyzEngine::drawAmmo() {
 
 	float w = float(_ammoBar[_currentActor].w) / float(_weaponMaxAmmo[_currentWeapon]);
 
-	Common::Rect ammoBarBox(320 - int(_ammoTeam[_currentActor] * w), 0, 320, _ammoBar[_currentActor].h / 2);
+	Common::Rect ammoBarBox(320 - int(_ammo * w), 0, 320, _ammoBar[_currentActor].h / 2);
 	uint32 c = kHypnoColorGreen; // green
 	_compositeSurface->fillRect(ammoBarBox, c);
 
@@ -274,13 +277,13 @@ bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool
 	}
 
 	if (!secondary) {
-		if (_ammoTeam[_currentActor] == 0) {
+		if (_ammo == 0) {
 			if (!arc->noAmmoSound.empty())
 				playSound(_soundPath + arc->noAmmoSound, 1, arc->noAmmoSoundRate);
 			return false;
 		}
 		if (!_infiniteAmmoCheat)
-			_ammoTeam[_currentActor]--;
+			_ammo--;
 		playSound(_soundPath + _weaponShootSound[_currentWeapon], 1);
 		incShotsFired();
 	}
@@ -453,7 +456,7 @@ bool BoyzEngine::clickedSecondaryShoot(const Common::Point &mousePos) {
 
 	Common::Rect ammoBarBox(320 - _ammoBar[_currentActor].w, 0, 320, _ammoBar[_currentActor].h);
 	if (ammoBarBox.contains(mousePos)) {
-		_ammoTeam[_currentActor] = _weaponMaxAmmo[_currentWeapon];
+		_ammo = _weaponMaxAmmo[_currentWeapon];
 		playSound(_soundPath + _weaponReloadSound[_currentWeapon], 1);
 		return false;
 	}
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 128b99a339f..86a266eba85 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -36,7 +36,6 @@ BoyzEngine::BoyzEngine(OSystem *syst, const ADGameDescription *gd) : HypnoEngine
 	_crosshairsPalette = nullptr;
 
 	for (int i = 0; i < 6; i++) {
-		_ammoTeam[i] = 0;
 		_weaponMaxAmmo[i] = 0;
 	}
 }
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index dfd30be35f0..4dc803b9cbe 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -570,7 +570,6 @@ public:
 	Common::String firstLevelTerritory(const Common::String &level);
 
 
-	int _ammoTeam[7];
 	int _previousHealth;
 	Graphics::Surface _healthBar[7];
 	Graphics::Surface _ammoBar[7];


Commit: 3aa00048682bde5e10f9d6abdac72c2dacf6d1fb
    https://github.com/scummvm/scummvm/commit/3aa00048682bde5e10f9d6abdac72c2dacf6d1fb
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: implemented mouse support for retry menu in boyz

Changed paths:
    engines/hypno/boyz/hard.cpp
    engines/hypno/cursors.cpp


diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index e2242002b99..b4091b70ef7 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -96,8 +96,14 @@ void BoyzEngine::runRetryMenu(Code *code) {
 	MVideo video(filename, Common::Point(0, 0), false, true, false);
 	disableCursor();
 	runIntro(video);
+	changeCursor("crosshair");
+
+	Common::Rect retryMissionBox(73, 62, 245, 77);
+	Common::Rect restartTerritoryBox(73, 81, 245, 96);
+	Common::Rect quitBox(73, 119, 245, 133);
 
 	Common::Event event;
+	Common::Point mousePos;
 	byte *palette;
 	Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 5, &palette);
 	loadPalette(palette, 0, 256);
@@ -105,6 +111,8 @@ void BoyzEngine::runRetryMenu(Code *code) {
 	bool cont = true;
 	while (!shouldQuit() && cont) {
 		while (g_system->getEventManager()->pollEvent(event)) {
+			mousePos = g_system->getEventManager()->getMousePos();
+
 			// Events
 			switch (event.type) {
 
@@ -112,6 +120,19 @@ void BoyzEngine::runRetryMenu(Code *code) {
 			case Common::EVENT_RETURN_TO_LAUNCHER:
 				break;
 
+			case Common::EVENT_LBUTTONDOWN:
+				if (retryMissionBox.contains(mousePos)) {
+					_nextLevel = _checkpoint;
+					cont = false;
+				} else if (restartTerritoryBox.contains(mousePos)) {
+					// Restore initial health for the team
+					_health = _maxHealth;
+					_nextLevel = firstLevelTerritory(_checkpoint);
+					cont = false;
+				} else if (quitBox.contains(mousePos))
+					quitGame();
+				break;
+
 			case Common::EVENT_KEYDOWN:
 				if (event.kbd.keycode == Common::KEYCODE_s) {
 					_nextLevel = _checkpoint;
@@ -119,12 +140,10 @@ void BoyzEngine::runRetryMenu(Code *code) {
 				} else if (event.kbd.keycode == Common::KEYCODE_t) {
 					// Restore initial health for the team
 					_health = _maxHealth;
-
 					_nextLevel = firstLevelTerritory(_checkpoint);
 					cont = false;
-				} else if (event.kbd.keycode == Common::KEYCODE_q) {
+				} else if (event.kbd.keycode == Common::KEYCODE_q)
 					quitGame();
-				}
 				break;
 
 			default:
diff --git a/engines/hypno/cursors.cpp b/engines/hypno/cursors.cpp
index 881b926e112..e4d3971778e 100644
--- a/engines/hypno/cursors.cpp
+++ b/engines/hypno/cursors.cpp
@@ -72,6 +72,21 @@ static const byte targetCursor[] = {
 	0, 0, 1, 0, 0, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0,
 	0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0};
 
+static const byte crosshairCursor[] = {
+	0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
+	0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0,
+	0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+	0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+	0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
+	2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
+	0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
+	0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+	0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+	0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 1, 0,
+	0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0};
+
 static const byte cursorPalette[] = {
 	0x00, 0x00, 0x00, // Black / Transparent
 	0x00, 0x00, 0xff, // Blue
@@ -92,6 +107,7 @@ static const CursorTable cursorTable[] = {
 	{"default", MOUSECURSOR_SCI, 11, 16, 0, 0},
 	{"arcade", circleCursor, 13, 11, 7, 5},
 	{"target", targetCursor, 15, 13, 8, 6},
+	{"crosshair", crosshairCursor, 15, 13, 8, 6},
 	{nullptr, nullptr, 0, 0, 0, 0}};
 
 void HypnoEngine::disableCursor() {


Commit: 7793754c33408f397f122a873d6fb38e62805434
    https://github.com/scummvm/scummvm/commit/7793754c33408f397f122a873d6fb38e62805434
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: add code to show game credits in boyz

Changed paths:
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index b4091b70ef7..67daeff65c8 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -159,6 +159,18 @@ void BoyzEngine::runRetryMenu(Code *code) {
 	delete menu;
 }
 
+void BoyzEngine::endCredits(Code *code) {
+	showCredits();
+	_nextLevel = "<main_menu>";
+}
+
+void BoyzEngine::showCredits() {
+	MVideo c1("intro/sbcred1.smk", Common::Point(0, 0), false, true, false);
+	runIntro(c1);
+	MVideo c2("intro/sbcred2.smk", Common::Point(0, 0), false, true, false);
+	runIntro(c2);
+}
+
 Common::String BoyzEngine::firstLevelTerritory(const Common::String &level) {
 	if (Common::matchString(level.c_str(), "c1#.mi_"))
 		return "c19.mi_";
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index 4dc803b9cbe..4b534c48eed 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -550,6 +550,7 @@ public:
 	void drawCursorArcade(const Common::Point &mousePos) override;
 	bool shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary) override;
 	bool clickedSecondaryShoot(const Common::Point &mousePos) override;
+	void showCredits() override;
 
 	void missedTarget(Shoot *s, ArcadeShooting *arc) override;
 	void drawHealth() override;
@@ -567,6 +568,7 @@ public:
 	private:
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);
+	void endCredits(Code *code);
 	Common::String firstLevelTerritory(const Common::String &level);
 
 


Commit: 430c703c0395ed5899df14056b942b1262dac66f
    https://github.com/scummvm/scummvm/commit/430c703c0395ed5899df14056b942b1262dac66f
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: implement basic difficulty selection menu in boyz

Changed paths:
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 86a266eba85..bbd94c77330 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -85,9 +85,13 @@ void BoyzEngine::loadAssets() {
 	logos->intros.push_back("intro/sblogos.smk");
 	_levels["<start>"] = logos;
 
-	Code *menu = new Code("<main_menu>");
-	_levels["<main_menu>"] = menu;
-	_levels["<main_menu>"]->levelIfWin = "<select_boyz>";
+	Code *main_menu = new Code("<main_menu>");
+	_levels["<main_menu>"] = main_menu;
+	_levels["<main_menu>"]->levelIfWin = "<difficulty_menu>";
+
+	Code *difficulty_menu = new Code("<difficulty_menu>");
+	_levels["<difficulty_menu>"] = difficulty_menu;
+	_levels["<difficulty_menu>"]->levelIfWin = "<select_boyz>";
 
 	Code *retry = new Code("<retry_menu>");
 	_levels["<retry_menu>"] = retry;
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 67daeff65c8..9787a3ee634 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -32,6 +32,8 @@ namespace Hypno {
 void BoyzEngine::runCode(Code *code) {
 	if (code->name == "<main_menu>")
 		runMainMenu(code);
+	else if (code->name == "<difficulty_menu>")
+		runDifficultyMenu(code);
 	else if (code->name == "<retry_menu>")
 		runRetryMenu(code);
 	else
@@ -88,6 +90,79 @@ void BoyzEngine::runMainMenu(Code *code) {
 	delete menu;
 }
 
+void BoyzEngine::runDifficultyMenu(Code *code) {
+	changeCursor("crosshair");
+	_difficulty.clear();
+	Common::Rect chumpBox(121, 62, 199, 77);
+	Common::Rect punkBox(121, 81, 199, 96);
+	Common::Rect badAssBox(121, 100, 199, 115);
+	Common::Rect cancelBox(121, 138, 245, 153);
+
+	Common::Event event;
+	Common::Point mousePos;
+	byte *palette;
+	Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 1, &palette);
+	loadPalette(palette, 0, 256);
+	drawImage(*menu, 0, 0, false);
+	bool cont = true;
+	while (!shouldQuit() && cont) {
+		while (g_system->getEventManager()->pollEvent(event)) {
+			mousePos = g_system->getEventManager()->getMousePos();
+
+			// Events
+			switch (event.type) {
+
+			case Common::EVENT_QUIT:
+			case Common::EVENT_RETURN_TO_LAUNCHER:
+				break;
+
+			case Common::EVENT_LBUTTONDOWN:
+				if (chumpBox.contains(mousePos)) {
+					_difficulty = "chump";
+					cont = false;
+				} else if (punkBox.contains(mousePos)) {
+					_difficulty = "punk";
+					cont = false;
+				} else if (badAssBox.contains(mousePos)) {
+					_difficulty = "bad ass";
+					cont = false;
+				} else if (cancelBox.contains(mousePos)) {
+					cont = false;
+				}
+				break;
+
+			case Common::EVENT_KEYDOWN:
+				if (event.kbd.keycode == Common::KEYCODE_c) {
+					_difficulty = "chump";
+					cont = false;
+				} else if (event.kbd.keycode == Common::KEYCODE_p) {
+					_difficulty = "punk";
+					cont = false;
+				} else if (event.kbd.keycode == Common::KEYCODE_b) {
+					_difficulty = "bad ass";
+					cont = false;
+				} else if (event.kbd.keycode == Common::KEYCODE_a) {
+					cont = false;
+				}
+				break;
+
+			default:
+				break;
+			}
+		}
+
+		drawScreen();
+		g_system->delayMillis(10);
+	}
+
+	if (_difficulty.empty())
+		_nextLevel = "<main_menu>";
+	else
+		_nextLevel = code->levelIfWin;
+	menu->free();
+	delete menu;
+}
+
 void BoyzEngine::runRetryMenu(Code *code) {
 	_lives--;
 
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index 4b534c48eed..a654bc8f922 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -568,6 +568,7 @@ public:
 	private:
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);
+	void runDifficultyMenu(Code *code);
 	void endCredits(Code *code);
 	Common::String firstLevelTerritory(const Common::String &level);
 


Commit: 55a9e96b3df4be55d20444226def2ae00c38097b
    https://github.com/scummvm/scummvm/commit/55a9e96b3df4be55d20444226def2ae00c38097b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: implement save and load of player profiles in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h
    engines/hypno/wet/wet.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index f7a3c376263..1b3dc7bcf9b 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -28,6 +28,7 @@ namespace Hypno {
 
 void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
 	_checkpoint = _currentLevel;
+	saveProfile(_name, int(arc->id));
 	assert(!arc->player.empty());
 	_playerFrames = decodeFrames(arc->player);
 	_playerFrameSep = 0;
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index bbd94c77330..32d3b9a0770 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -26,14 +26,34 @@
 
 namespace Hypno {
 
+static const chapterEntry rawChapterTable[] = {
+	{19, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{11, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{12, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{13, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{14, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{15, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{16, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{17, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{18, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{0,  {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor}
+};
+
 BoyzEngine::BoyzEngine(OSystem *syst, const ADGameDescription *gd) : HypnoEngine(syst, gd) {
 	_screenW = 320;
 	_screenH = 200;
-	_lives = 2;
+	_lives = 0; // This counts the number of lives used
 	_currentWeapon = 0;
 	_currentActor = 0;
 	_currentMode = NonInteractive;
 	_crosshairsPalette = nullptr;
+	_lastLevel = 0;
+
+    const chapterEntry *entry = rawChapterTable;
+    while (entry->id) {
+		_ids.push_back(entry->id);
+		entry++;
+    }
 
 	for (int i = 0; i < 6; i++) {
 		_weaponMaxAmmo[i] = 0;
@@ -405,6 +425,79 @@ void BoyzEngine::drawString(const Common::String &font, const Common::String &st
 		error("Invalid font: '%s'", font.c_str());
 }
 
+void BoyzEngine::saveProfile(const Common::String &name, int levelId) {
+	SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
+
+	// Find the correct level index to before saving
+	for (uint32 i = 0; i < _ids.size(); i++) {
+		if (levelId == _ids[i]) {
+			if (_lastLevel < int(i))
+				_lastLevel = int(i);
+			break;
+		}
+	}
+
+	uint32 slot = 0;
+	for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
+		if (save->getDescription() == name)
+			break;
+		slot++;
+	}
+	debugC(1, kHypnoDebugMedia, "Saving profile %s with last level %d", name.c_str(), _lastLevel);
+	saveGameState(slot, name, false);
+}
+
+bool BoyzEngine::loadProfile(const Common::String &name) {
+	SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
+	uint32 slot = 0;
+	for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
+		if (save->getDescription() == name)
+			break;
+		slot++;
+	}
+
+	if (slot == saves.size()) {
+		debugC(1, kHypnoDebugMedia, "Failed to load %s", name.c_str());
+		return false;
+	}
+
+	loadGameState(slot);
+	return true;
+}
+
+Common::Error BoyzEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
+	if (isAutosave)
+		return Common::kNoError;
+
+	if (_lastLevel < 0 || _lastLevel >= 20)
+		error("Invalid last level!");
+
+	stream->writeString(_name);
+	stream->writeByte(0);
+
+	stream->writeString(_difficulty);
+	stream->writeByte(0);
+
+	stream->writeUint32LE(_lives);
+	stream->writeUint32LE(_previousHealth);
+	stream->writeUint32LE(_score);
+
+	stream->writeUint32LE(_lastLevel);
+	return Common::kNoError;
+}
+
+Common::Error BoyzEngine::loadGameStream(Common::SeekableReadStream *stream) {
+	_name = stream->readString();
+	_difficulty = stream->readString();
+	_lives = stream->readUint32LE();
+	_previousHealth = stream->readUint32LE();
+	_score = stream->readUint32LE();
+	_lastLevel = stream->readUint32LE();
+
+	_nextLevel = Common::String::format("c%d.mi_", _ids[_lastLevel]);
+	return Common::kNoError;
+}
+
 
 Common::String BoyzEngine::findNextLevel(const Transition *trans) {
 	if (trans->nextLevel.empty())
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 9787a3ee634..3e3f963f4bf 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -82,12 +82,17 @@ void BoyzEngine::runMainMenu(Code *code) {
 		drawScreen();
 		g_system->delayMillis(10);
 	}
+	menu->free();
+	delete menu;
 
 	_name.toLowercase();
+	bool found = loadProfile(_name);
+	if (!found) {
+		saveProfile(_name, 0);
+		_nextLevel = code->levelIfWin;
+	}
+	assert(!_nextLevel.empty());
 
-	_nextLevel = code->levelIfWin;
-	menu->free();
-	delete menu;
 }
 
 void BoyzEngine::runDifficultyMenu(Code *code) {
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index a654bc8f922..aa449f0ed58 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -538,6 +538,8 @@ class BoyzEngine : public HypnoEngine {
 public:
 	BoyzEngine(OSystem *syst, const ADGameDescription *gd);
 	Common::String _name;
+	Common::Array<int> _ids;
+	int _lastLevel;
 	void loadAssets() override;
 	void runCode(Code *code) override;
 	Common::String findNextLevel(const Common::String &level) override;
@@ -565,6 +567,12 @@ public:
 	void loadFonts() override;
 	void drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c) override;
 
+	// Saves
+	Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
+	Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
+	bool loadProfile(const Common::String &name);
+	void saveProfile(const Common::String &name, int levelId);
+
 	private:
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);
diff --git a/engines/hypno/wet/wet.cpp b/engines/hypno/wet/wet.cpp
index ae559e9de83..61c81f31912 100644
--- a/engines/hypno/wet/wet.cpp
+++ b/engines/hypno/wet/wet.cpp
@@ -70,12 +70,12 @@ WetEngine::WetEngine(OSystem *syst, const ADGameDescription *gd) : HypnoEngine(s
 	_c50LeftTurns = 0;
 	_c50RigthTurns = 0;
 
-    const chapterEntry *entry = rawChapterTable;
-    while (entry->id) {
+	const chapterEntry *entry = rawChapterTable;
+	while (entry->id) {
 		_ids.push_back(entry->id);
 		_chapterTable[entry->id] = entry;
 		entry++;
-    }
+	}
 
 	_healthString = getLocalizedString("health");
 	_scoreString = getLocalizedString("score");


Commit: 9c720c8c60042d8b428c0f71dda87bce4609fb97
    https://github.com/scummvm/scummvm/commit/9c720c8c60042d8b428c0f71dda87bce4609fb97
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: count the number of used lives in boyz

Changed paths:
    engines/hypno/boyz/boyz.cpp


diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 32d3b9a0770..75ecad3a1d6 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -42,7 +42,7 @@ static const chapterEntry rawChapterTable[] = {
 BoyzEngine::BoyzEngine(OSystem *syst, const ADGameDescription *gd) : HypnoEngine(syst, gd) {
 	_screenW = 320;
 	_screenH = 200;
-	_lives = 0; // This counts the number of lives used
+	_lives = uint32(-1); // This counts the number of lives used
 	_currentWeapon = 0;
 	_currentActor = 0;
 	_currentMode = NonInteractive;


Commit: 4420f6ccf97da0e1cb0fc5319c432b72772754c8
    https://github.com/scummvm/scummvm/commit/4420f6ccf97da0e1cb0fc5319c432b72772754c8
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: show game profiles in main menu in boyz

Changed paths:
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 75ecad3a1d6..64379d9cc3f 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -447,6 +447,17 @@ void BoyzEngine::saveProfile(const Common::String &name, int levelId) {
 	saveGameState(slot, name, false);
 }
 
+Common::Array<Common::String> BoyzEngine::listProfiles() {
+	Common::Array<Common::String> profiles;
+	SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
+	for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
+		Common::String profile = save->getDescription();
+		profile.toUppercase();
+		profiles.push_back(profile);
+	}
+	return profiles;
+}
+
 bool BoyzEngine::loadProfile(const Common::String &name) {
 	SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
 	uint32 slot = 0;
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 3e3f963f4bf..2d3f9ff1677 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -50,6 +50,12 @@ void BoyzEngine::runMainMenu(Code *code) {
 	_name.clear();
 	bool cont = true;
     uint32 c = kHypnoColorWhiteOrBlue; // white
+	uint32 posY = 105;
+	Common::StringArray profiles = listProfiles();
+	for (Common::StringArray::iterator it = profiles.begin(); it != profiles.end(); ++it) {
+		drawString("block05.fgx", *it, 130, posY, 170, c);
+		posY = posY + 10;
+	}
 	while (!shouldQuit() && cont) {
 		while (g_system->getEventManager()->pollEvent(event)) {
 			// Events
@@ -71,7 +77,14 @@ void BoyzEngine::runMainMenu(Code *code) {
 				}
 
 				drawImage(*menu, 0, 0, false);
-				drawString("block05.fgx", _name, 130, 57, 170, c);
+				drawString("block05.fgx", _name, 130, 58, 170, c);
+				posY = 105;
+				for (Common::StringArray::iterator it = profiles.begin(); it != profiles.end(); ++it) {
+					drawString("block05.fgx", *it, 130, posY, 170, c);
+					posY = posY + 10;
+					if (posY >= 185)
+						break;
+				}
 				break;
 
 			default:
@@ -88,7 +101,6 @@ void BoyzEngine::runMainMenu(Code *code) {
 	_name.toLowercase();
 	bool found = loadProfile(_name);
 	if (!found) {
-		saveProfile(_name, 0);
 		_nextLevel = code->levelIfWin;
 	}
 	assert(!_nextLevel.empty());
@@ -162,8 +174,11 @@ void BoyzEngine::runDifficultyMenu(Code *code) {
 
 	if (_difficulty.empty())
 		_nextLevel = "<main_menu>";
-	else
+	else {
+		saveProfile(_name, 0);
 		_nextLevel = code->levelIfWin;
+	}
+
 	menu->free();
 	delete menu;
 }
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index aa449f0ed58..3093139829b 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -570,6 +570,7 @@ public:
 	// Saves
 	Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
 	Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
+	Common::StringArray listProfiles();
 	bool loadProfile(const Common::String &name);
 	void saveProfile(const Common::String &name, int levelId);
 


Commit: d034cc1ba211d135d430e458ac3cfea172df9361
    https://github.com/scummvm/scummvm/commit/d034cc1ba211d135d430e458ac3cfea172df9361
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: improved profile saving in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 1b3dc7bcf9b..bbb57a6339d 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -28,7 +28,8 @@ namespace Hypno {
 
 void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
 	_checkpoint = _currentLevel;
-	saveProfile(_name, int(arc->id));
+	if (!_name.empty()) // if name is name, then we are testing some level
+		saveProfile(_name, int(arc->id));
 	assert(!arc->player.empty());
 	_playerFrames = decodeFrames(arc->player);
 	_playerFrameSep = 0;
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 64379d9cc3f..799d2c78168 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -36,6 +36,12 @@ static const chapterEntry rawChapterTable[] = {
 	{16, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
 	{17, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
 	{18, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{21, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{22, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{31, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{32, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{33, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{34, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
 	{0,  {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor}
 };
 


Commit: bae1dffdde31251c53fe958811af38f74db6cd2b
    https://github.com/scummvm/scummvm/commit/bae1dffdde31251c53fe958811af38f74db6cd2b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: skip level is captor is not killed in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index bbb57a6339d..fca2662d8f1 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -415,7 +415,9 @@ void BoyzEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
 		MVideo video(_warningHostage, Common::Point(0, 0), false, true, false);
 		disableCursor();
 		runIntro(video);
-		_health = 0; // TODO: not sure about this
+		hitPlayer();
+		if (_health > 0)
+			_skipLevel = true;
 		return;
 	} else if (s->name.hasPrefix("ALARM")) {
 		if (_background->decoder->getCurFrame() > int(s->missedAnimation))


Commit: 6a16c8bbb5c8ef97833dd1d8490a02aa9d57bb26
    https://github.com/scummvm/scummvm/commit/6a16c8bbb5c8ef97833dd1d8490a02aa9d57bb26
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: added basic implementation for selection in specific scenes in boyz

Changed paths:
  A engines/hypno/boyz/scene.cpp
    engines/hypno/actions.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/grammar.h
    engines/hypno/hypno.h
    engines/hypno/module.mk


diff --git a/engines/hypno/actions.cpp b/engines/hypno/actions.cpp
index 6764e636c45..58f527c9ccd 100644
--- a/engines/hypno/actions.cpp
+++ b/engines/hypno/actions.cpp
@@ -31,9 +31,6 @@ namespace Hypno {
 void HypnoEngine::runMenu(Hotspots *hs, bool only_menu) {
 	Hotspot *h = hs->begin();
 	assert(h->type == MakeMenu);
-	if (!h->background.empty()) {
-		loadImage(h->background, 0, 0, false, true);
-	}
 
 	debugC(1, kHypnoDebugScene, "hotspot actions size: %d", h->actions.size());
 	for (Actions::const_iterator itt = h->actions.begin(); !only_menu && itt != h->actions.end(); ++itt) {
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 799d2c78168..bc81bc2ff6d 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -157,11 +157,58 @@ void BoyzEngine::loadAssets() {
 	loadArcadeLevel("c58.mi_", "c59.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c59.mi_", "<credits>", "<retry_menu>", "");
 
+	Global *gl;
+	ChangeLevel *cl;
+	Cutscene *cs;
+	Highlight *hl;
+
 	loadSceneLevel(selectBoyz, "<select_boyz>", "", "");
 	Scene *sc = (Scene *) _levels["<select_boyz>"];
 	sc->resolution = "320x200";
 
-	ChangeLevel *cl = new ChangeLevel("c19.mi_");
+	hl = new Highlight("GS_SWITCH1");
+	sc->hots[1].actions.push_back(hl);
+	gl = new Global("GS_SWITCH1", "TURNON");
+	sc->hots[1].actions.push_back(gl);
+	cs = new Cutscene("intro/c0i01s.smk");
+	sc->hots[1].actions.push_back(cs);
+
+	hl = new Highlight("GS_SWITCH2");
+	sc->hots[2].actions.push_back(hl);
+	gl = new Global("GS_SWITCH2", "TURNON");
+	sc->hots[2].actions.push_back(gl);
+	cs = new Cutscene("intro/c0i02s.smk");
+	sc->hots[2].actions.push_back(cs);
+
+	hl = new Highlight("GS_SWITCH3");
+	sc->hots[3].actions.push_back(hl);
+	gl = new Global("GS_SWITCH3", "TURNON");
+	sc->hots[3].actions.push_back(gl);
+	cs = new Cutscene("intro/c0i03s.smk");
+	sc->hots[3].actions.push_back(cs);
+
+	hl = new Highlight("GS_SWITCH4");
+	sc->hots[4].actions.push_back(hl);
+	gl = new Global("GS_SWITCH4", "TURNON");
+	sc->hots[4].actions.push_back(gl);
+	cs = new Cutscene("intro/c0i04s.smk");
+	sc->hots[4].actions.push_back(cs);
+
+	hl = new Highlight("GS_SWITCH5");
+	sc->hots[5].actions.push_back(hl);
+	gl = new Global("GS_SWITCH5", "TURNON");
+	sc->hots[5].actions.push_back(gl);
+	cs = new Cutscene("intro/c0i05s.smk");
+	sc->hots[5].actions.push_back(cs);
+
+	hl = new Highlight("GS_SWITCH6");
+	sc->hots[6].actions.push_back(hl);
+	gl = new Global("GS_SWITCH6", "TURNON");
+	sc->hots[6].actions.push_back(gl);
+	cs = new Cutscene("intro/c0i06s.smk");
+	sc->hots[6].actions.push_back(cs);
+
+	cl = new ChangeLevel("c19.mi_");
 	sc->hots[7].actions.push_back(cl);
 
 	loadSceneLevel(selectC3, "<select_c3>", "", "");
diff --git a/engines/hypno/boyz/scene.cpp b/engines/hypno/boyz/scene.cpp
new file mode 100644
index 00000000000..2e7b3b06393
--- /dev/null
+++ b/engines/hypno/boyz/scene.cpp
@@ -0,0 +1,103 @@
+/* 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/events.h"
+
+#include "hypno/hypno.h"
+
+namespace Hypno {
+
+void BoyzEngine::runMenu(Hotspots *hs, bool only_menu) {
+	Hotspot *h = hs->begin();
+	assert(h->type == MakeMenu);
+	if (!h->background.empty()) {
+		loadImage(h->background, 0, 0, false, true, 1);
+		if (h->backgroundFrames.empty()) {
+			h->backgroundFrames = decodeFrames(h->background);
+		}
+	}
+	renderHighlights(hs);
+}
+
+void BoyzEngine::renderHighlights(Hotspots *hs) {
+	Hotspot *menu = hs->begin();
+	if (menu->type != MakeMenu || menu->background.empty())
+		return;
+
+	for (Hotspots::const_iterator it = hs->begin(); it != hs->end(); ++it) {
+		if (it->type == MakeMenu)
+			continue;
+
+		Highlight *hl;
+		for (Actions::const_iterator itt = it->actions.begin(); itt != it->actions.end(); ++itt) {
+			Action *action = *itt;
+			switch (action->type) {
+			case HighlightAction:
+				hl = (Highlight *)action;
+				if (_sceneState[hl->condition]) {
+					Graphics::Surface sub = menu->backgroundFrames[0]->getSubArea(it->rect);
+					drawImage(sub, it->rect.left, it->rect.top, false);
+				}
+				break;
+
+			default:
+				break;
+			}
+		}
+	}
+}
+
+bool BoyzEngine::hoverHotspot(Common::Point mousePos) {
+	if (_rnd->getRandomBit())
+		return false; // Dirty trick to avoid updating the screen too often
+	Hotspots *hots = stack.back();
+	Hotspot selected(MakeHotspot);
+	bool found = false;
+	int rs = 100000000;
+	for (Hotspots::const_iterator it = hots->begin(); it != hots->end(); ++it) {
+		const Hotspot h = *it;
+		if (h.type != MakeHotspot)
+			continue;
+
+		int cs = h.rect.width() * h.rect.height();
+		if (h.rect.contains(mousePos)) {
+			if (cs < rs) {
+				selected = h;
+				found = true;
+				rs = cs;
+			}
+		}
+	}
+	if (found) {
+		Hotspot *menu = hots->begin();
+		if (menu->type == MakeMenu && !menu->background.empty()) { // Hihghlight
+			Graphics::Surface sub = menu->backgroundFrames[2]->getSubArea(selected.rect);
+			drawImage(*menu->backgroundFrames[1], 0, 0, false);
+            drawImage(sub, selected.rect.left, selected.rect.top, false);
+			renderHighlights(hots);
+			drawScreen();
+		}
+		return true;
+	}
+	return false;
+}
+
+} // End of namespace Hypno
\ No newline at end of file
diff --git a/engines/hypno/grammar.h b/engines/hypno/grammar.h
index d73e146f11b..eb380f62394 100644
--- a/engines/hypno/grammar.h
+++ b/engines/hypno/grammar.h
@@ -65,6 +65,7 @@ enum ActionType {
 	TimerAction,
 	PaletteAction,
 	BackgroundAction,
+	HighlightAction,
 	OverlayAction,
 	EscapeAction,
 	SaveAction,
@@ -94,6 +95,7 @@ class Hotspot;
 
 typedef Common::Array<Hotspot> Hotspots;
 typedef Common::Array<Hotspots *> HotspotsStack;
+typedef Common::Array<Graphics::Surface *> Frames;
 
 class Hotspot {
 public:
@@ -106,7 +108,8 @@ public:
 	Common::String flags[3];
 	Common::Rect rect;
 	Common::String setting;
-	Common::String background;
+	Filename background;
+	Frames backgroundFrames;
 	Actions actions;
 	Hotspots *smenu;
 };
@@ -149,6 +152,15 @@ public:
 	Filename path;
 };
 
+class Highlight : public Action {
+public:
+	Highlight(Common::String condition_) {
+		type = HighlightAction;
+		condition = condition_;
+	}
+	Common::String condition;
+};
+
 class Background : public Action {
 public:
 	Background(Filename path_, Common::Point origin_, Common::String condition_, Common::String flag1_, Common::String flag2_) {
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index 3093139829b..bfddc3cf2db 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -57,8 +57,6 @@ enum {
 	kHypnoDebugScene = 1 << 3
 };
 
-typedef Common::Array<Graphics::Surface *> Frames;
-
 // Player positions
 
 enum PlayerPosition {
@@ -141,7 +139,7 @@ public:
 
 	// User input
 	void clickedHotspot(Common::Point);
-	bool hoverHotspot(Common::Point);
+	virtual bool hoverHotspot(Common::Point);
 
 	// Cursors
 	bool cursorPauseMovie(Common::Point);
@@ -178,7 +176,7 @@ public:
 	void changeCursor(const Graphics::Surface &entry, byte *palette, bool centerCursor = false);
 
 	// Actions
-	void runMenu(Hotspots *hs, bool only_menu = false);
+	virtual void runMenu(Hotspots *hs, bool only_menu = false);
 	void runBackground(Background *a);
 	void runOverlay(Overlay *a);
 	void runMice(Mice *a);
@@ -545,6 +543,11 @@ public:
 	Common::String findNextLevel(const Common::String &level) override;
 	Common::String findNextLevel(const Transition *trans) override;
 
+	// Scenes
+	void runMenu(Hotspots *hs, bool only_menu = false) override;
+	bool hoverHotspot(Common::Point) override;
+
+	// Arcade
 	void runBeforeArcade(ArcadeShooting *arc) override;
 	void runAfterArcade(ArcadeShooting *arc) override;
 	void pressedKey(const int keycode) override;
@@ -575,6 +578,8 @@ public:
 	void saveProfile(const Common::String &name, int levelId);
 
 	private:
+	void renderHighlights(Hotspots *hs);
+
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);
 	void runDifficultyMenu(Code *code);
diff --git a/engines/hypno/module.mk b/engines/hypno/module.mk
index 898a0c859fd..c6f7b9eccea 100644
--- a/engines/hypno/module.mk
+++ b/engines/hypno/module.mk
@@ -4,8 +4,9 @@ MODULE_OBJS := \
 	actions.o \
 	arcade.o \
 	boyz/arcade.o \
-	boyz/hard.o \
 	boyz/boyz.o \
+	boyz/hard.o \
+	boyz/scene.o \
 	cursors.o \
 	grammar_mis.o \
 	grammar_arc.o \


Commit: f6b018140b5f49ec11ddf09a453e8f085b595398
    https://github.com/scummvm/scummvm/commit/f6b018140b5f49ec11ddf09a453e8f085b595398
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: corrected default cursor in boyz

Changed paths:
    engines/hypno/boyz/boyz.cpp
    engines/hypno/cursors.cpp


diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index bc81bc2ff6d..b75d05d876b 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -406,6 +406,8 @@ void BoyzEngine::loadAssets() {
 
 	loadLib("", "misc/fonts.lib", true);
 	loadFonts();
+	_defaultCursor = "crosshair";
+	_defaultCursorIdx = uint32(-1);
 
 	_nextLevel = "<start>";
 }
diff --git a/engines/hypno/cursors.cpp b/engines/hypno/cursors.cpp
index e4d3971778e..bc178902234 100644
--- a/engines/hypno/cursors.cpp
+++ b/engines/hypno/cursors.cpp
@@ -83,8 +83,8 @@ static const byte crosshairCursor[] = {
 	0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
 	0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
 	0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
-	0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 1, 0,
-	0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0,
+	0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0,
+	0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0};
 
 static const byte cursorPalette[] = {
@@ -115,9 +115,12 @@ void HypnoEngine::disableCursor() {
 }
 
 void HypnoEngine::defaultCursor() {
-	if (!_defaultCursor.empty())
-		changeCursor(_defaultCursor, _defaultCursorIdx);
-	else
+	if (!_defaultCursor.empty()) {
+		if (_defaultCursorIdx == uint32(-1))
+			changeCursor(_defaultCursor);
+		else
+			changeCursor(_defaultCursor, _defaultCursorIdx);
+	} else
 		changeCursor("default");
 }
 


Commit: c443f2e93fc7c5c9a3c14a8b6d831ea829117051
    https://github.com/scummvm/scummvm/commit/c443f2e93fc7c5c9a3c14a8b6d831ea829117051
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: partial implementation of the select screen in level c3 in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/scene.cpp
    engines/hypno/hypno.h
    engines/hypno/scene.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index fca2662d8f1..d39cdd57987 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -73,9 +73,11 @@ void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
 		MVideo video(_deathDay[_currentActor], Common::Point(0, 0), false, true, false);
 		disableCursor();
 		runIntro(video);
-	} else
-		_previousHealth = _health;
+		return;
+	}
 
+	_previousHealth = _health;
+	_sceneState[Common::String::format("GS_SEQ_%d", _levelId)] = 1;
 }
 
 void BoyzEngine::pressedKey(const int keycode) {
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index b75d05d876b..504673e4702 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -133,16 +133,16 @@ void BoyzEngine::loadAssets() {
 	loadArcadeLevel("c18.mi_", "c21.mi_", "<retry_menu>", "");
 
 	loadArcadeLevel("c21.mi_", "c22.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c22.mi_", "c31.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c31.mi_", "c32.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c32.mi_", "c33.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c33.mi_", "c34.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c34.mi_", "c35.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c35.mi_", "c352.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c352.mi_", "c353.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c353.mi_", "c354.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c354.mi_", "c355.mi_", "<retry_menu>", "");
-	loadArcadeLevel("c355.mi_", "c36.mi_", "<retry_menu>", "");
+	loadArcadeLevel("c22.mi_", "<select_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c31.mi_", "<select_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c32.mi_", "<select_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c33.mi_", "<select_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c34.mi_", "<select_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c35.mi_", "???", "<retry_menu>", "");
+	loadArcadeLevel("c352.mi_", "???", "<retry_menu>", "");
+	loadArcadeLevel("c353.mi_", "???", "<retry_menu>", "");
+	loadArcadeLevel("c354.mi_", "???", "<retry_menu>", "");
+	loadArcadeLevel("c355.mi_", "???", "<retry_menu>", "");
 	loadArcadeLevel("c36.mi_", "c41.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c41.mi_", "c42.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c42.mi_", "c51.mi_", "<retry_menu>", "");
@@ -215,6 +215,41 @@ void BoyzEngine::loadAssets() {
 	sc = (Scene *) _levels["<select_c3>"];
 	sc->resolution = "320x200";
 
+	hl = new Highlight("GS_SEQ_31");
+	sc->hots[1].actions.push_back(hl);
+	gl = new Global("GS_SEQ_31", "NCHECK");
+	sc->hots[1].actions.push_back(gl);
+	cl = new ChangeLevel("c31.mi_");
+	sc->hots[1].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_32");
+	sc->hots[2].actions.push_back(hl);
+	gl = new Global("GS_SEQ_32", "NCHECK");
+	sc->hots[2].actions.push_back(gl);
+	cl = new ChangeLevel("c32.mi_");
+	sc->hots[2].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_33");
+	sc->hots[3].actions.push_back(hl);
+	gl = new Global("GS_SEQ_33", "NCHECK");
+	sc->hots[3].actions.push_back(gl);
+	cl = new ChangeLevel("c33.mi_");
+	sc->hots[3].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_34");
+	sc->hots[4].actions.push_back(hl);
+	gl = new Global("GS_SEQ_34", "NCHECK");
+	sc->hots[4].actions.push_back(gl);
+	cl = new ChangeLevel("c34.mi_");
+	sc->hots[4].actions.push_back(cl);
+
+	hl = new Highlight("GS_WONSHELLGAME");
+	sc->hots[5].actions.push_back(hl);
+	gl = new Global("GS_WONSHELLGAME", "NCHECK");
+	sc->hots[5].actions.push_back(gl);
+	cl = new ChangeLevel("c35.mi_");
+	sc->hots[5].actions.push_back(cl);
+
 	loadLib("sound/", "misc/sound.lib", true);
 
 	_weaponShootSound[0] = "";
@@ -408,7 +443,7 @@ void BoyzEngine::loadAssets() {
 	loadFonts();
 	_defaultCursor = "crosshair";
 	_defaultCursorIdx = uint32(-1);
-
+	resetSceneState();
 	_nextLevel = "<start>";
 }
 
diff --git a/engines/hypno/boyz/scene.cpp b/engines/hypno/boyz/scene.cpp
index 2e7b3b06393..d642ebf47b2 100644
--- a/engines/hypno/boyz/scene.cpp
+++ b/engines/hypno/boyz/scene.cpp
@@ -25,6 +25,71 @@
 
 namespace Hypno {
 
+const char *sceneVariablesBoyz[] = {
+	"GS_NONE",
+	"GS_SCTEXT",
+	"GS_AMBIENT",
+	"GS_MUSIC",
+	"GS_VOLUME",
+	"GS_LEVELCOMPLETE",
+	"GS_LEVELWON",
+	"GS_HOLDMOUSE",
+	"GS_DIFFICULTY",
+	"GS_TERRITORY",
+	"GS_SECTOR",
+	"GS_HITPOINTS",
+	"GS_TERRITORY1_RAND",
+	"GS_C5MAP",
+	"GS_WONSHELLGAME",
+	"GS_C36_READY",
+	"GS_MINEMAP",
+	"GS_MINEMAP_VIEWED",
+	"GS_HOTELDONE",
+	"GS_SEQ_11",
+	"GS_SEQ_12",
+	"GS_SEQ_13",
+	"GS_SEQ_14",
+	"GS_SEQ_15",
+	"GS_SEQ_16",
+	"GS_SEQ_17",
+	"GS_SEQ_18",
+	"GS_SEQ_19",
+	"GS_SEQ_21",
+	"GS_SEQ_22",
+	"GS_SEQ_31",
+	"GS_SEQ_32",
+	"GS_SEQ_33",
+	"GS_SEQ_34",
+	"GS_SEQ_35",
+	"GS_SEQ_351",
+	"GS_SEQ_352",
+	"GS_SEQ_353",
+	"GS_SEQ_354",
+	"GS_SEQ_355",
+	"GS_SEQ_36",
+	"GS_SEQ_41",
+	"GS_SEQ_42",
+	"GS_SEQ_51",
+	"GS_SEQ_52",
+	"GS_SEQ_53",
+	"GS_SEQ_54",
+	"GS_SEQ_55",
+	"GS_SEQ_56",
+	"GS_SEQ_57",
+	"GS_SEQ_58",
+	"GS_SEQ_59",
+	nullptr
+};
+
+void BoyzEngine::resetSceneState() {
+	uint32 i = 0;
+	while (sceneVariablesBoyz[i]) {
+		_sceneState[sceneVariablesBoyz[i]] = 0;
+		i++;
+	}
+	_intros.clear();
+}
+
 void BoyzEngine::runMenu(Hotspots *hs, bool only_menu) {
 	Hotspot *h = hs->begin();
 	assert(h->type == MakeMenu);
@@ -52,6 +117,7 @@ void BoyzEngine::renderHighlights(Hotspots *hs) {
 			switch (action->type) {
 			case HighlightAction:
 				hl = (Highlight *)action;
+				assert(_sceneState.contains(hl->condition));
 				if (_sceneState[hl->condition]) {
 					Graphics::Surface sub = menu->backgroundFrames[0]->getSubArea(it->rect);
 					drawImage(sub, it->rect.left, it->rect.top, false);
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index bfddc3cf2db..e65169114bc 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -109,7 +109,7 @@ public:
 	Common::Error run() override;
 	Levels _levels;
 	Common::HashMap<Common::String, int> _sceneState;
-	void resetSceneState();
+	virtual void resetSceneState();
 	bool checkSceneCompleted();
 	bool checkLevelWon();
 	void runLevel(Common::String &name);
@@ -544,6 +544,7 @@ public:
 	Common::String findNextLevel(const Transition *trans) override;
 
 	// Scenes
+	void resetSceneState() override;
 	void runMenu(Hotspots *hs, bool only_menu = false) override;
 	bool hoverHotspot(Common::Point) override;
 
diff --git a/engines/hypno/scene.cpp b/engines/hypno/scene.cpp
index 5a2888b23f5..9760e56bdf7 100644
--- a/engines/hypno/scene.cpp
+++ b/engines/hypno/scene.cpp
@@ -55,7 +55,8 @@ const char *sceneVariables[] = {
 	"GS_COMBATJSON",
 	"GS_COMBATLEVEL",
 	"GS_PUZZLELEVEL",
-	nullptr};
+	nullptr
+};
 
 void HypnoEngine::loadSceneLevel(const Common::String &current, const Common::String &next, const Common::String &prefix) {
 	debugC(1, kHypnoDebugParser, "Parsing %s", current.c_str());


Commit: ffdefe757d3988cb656ae7ff307ca1066704cd7e
    https://github.com/scummvm/scummvm/commit/ffdefe757d3988cb656ae7ff307ca1066704cd7e
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: save/load game state variables and some fixes in boyz

Changed paths:
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/boyz/scene.cpp


diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 504673e4702..24be9731703 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -584,6 +584,21 @@ Common::Error BoyzEngine::saveGameStream(Common::WriteStream *stream, bool isAut
 	stream->writeUint32LE(_score);
 
 	stream->writeUint32LE(_lastLevel);
+
+	stream->writeUint32LE(_sceneState["GS_C5MAP"]);
+	stream->writeUint32LE(_sceneState["GS_WONSHELLGAME"]);
+	stream->writeUint32LE(_sceneState["GS_C36_READY"]);
+	stream->writeUint32LE(_sceneState["GS_MINEMAP"]);
+	stream->writeUint32LE(_sceneState["GS_MINEMAP_VIEWED"]);
+	stream->writeUint32LE(_sceneState["GS_HOTELDONE"]);
+
+	stream->writeUint32LE(_sceneState["GS_SEQ_31"]);
+	stream->writeUint32LE(_sceneState["GS_SEQ_32"]);
+	stream->writeUint32LE(_sceneState["GS_SEQ_33"]);
+	stream->writeUint32LE(_sceneState["GS_SEQ_34"]);
+	stream->writeUint32LE(_sceneState["GS_SEQ_35"]);
+	stream->writeUint32LE(_sceneState["GS_SEQ_36"]);
+
 	return Common::kNoError;
 }
 
@@ -595,6 +610,19 @@ Common::Error BoyzEngine::loadGameStream(Common::SeekableReadStream *stream) {
 	_score = stream->readUint32LE();
 	_lastLevel = stream->readUint32LE();
 
+	_sceneState["GS_C5MAP"] = stream->readUint32LE();
+	_sceneState["GS_WONSHELLGAME"] = stream->readUint32LE();
+	_sceneState["GS_C36_READY"] = stream->readUint32LE();
+	_sceneState["GS_MINEMAP"] = stream->readUint32LE();
+	_sceneState["GS_MINEMAP_VIEWED"] = stream->readUint32LE();
+	_sceneState["GS_HOTELDONE"] = stream->readUint32LE();
+
+	_sceneState["GS_SEQ_31"] = stream->readUint32LE();
+	_sceneState["GS_SEQ_32"] = stream->readUint32LE();
+	_sceneState["GS_SEQ_33"] = stream->readUint32LE();
+	_sceneState["GS_SEQ_34"] = stream->readUint32LE();
+	_sceneState["GS_SEQ_35"] = stream->readUint32LE();
+
 	_nextLevel = Common::String::format("c%d.mi_", _ids[_lastLevel]);
 	return Common::kNoError;
 }
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 2d3f9ff1677..5f2c9e0d13c 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -41,6 +41,7 @@ void BoyzEngine::runCode(Code *code) {
 }
 
 void BoyzEngine::runMainMenu(Code *code) {
+	resetSceneState();
 	Common::Event event;
 	byte *palette;
 	Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 0, &palette);
diff --git a/engines/hypno/boyz/scene.cpp b/engines/hypno/boyz/scene.cpp
index d642ebf47b2..3535141cd85 100644
--- a/engines/hypno/boyz/scene.cpp
+++ b/engines/hypno/boyz/scene.cpp
@@ -45,6 +45,19 @@ const char *sceneVariablesBoyz[] = {
 	"GS_MINEMAP",
 	"GS_MINEMAP_VIEWED",
 	"GS_HOTELDONE",
+	"GS_SWITCH0",
+	"GS_SWITCH1",
+	"GS_SWITCH2",
+	"GS_SWITCH3",
+	"GS_SWITCH4",
+	"GS_SWITCH5",
+	"GS_SWITCH6",
+	"GS_SWITCH7",
+	"GS_SWITCH8",
+	"GS_SWITCH9",
+	"GS_SWITCH10",
+	"GS_SWITCH11",
+	"GS_SWITCH12",
 	"GS_SEQ_11",
 	"GS_SEQ_12",
 	"GS_SEQ_13",


Commit: bbbf96a166fc12ea1c1c9f5ab8741633917f7953
    https://github.com/scummvm/scummvm/commit/bbbf96a166fc12ea1c1c9f5ab8741633917f7953
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: implement select_ho level in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index d39cdd57987..6c4c7120b9b 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -78,6 +78,13 @@ void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
 
 	_previousHealth = _health;
 	_sceneState[Common::String::format("GS_SEQ_%d", _levelId)] = 1;
+
+	if (_sceneState["GS_SEQ_351"] && _sceneState["GS_SEQ_352"] &&\
+	    _sceneState["GS_SEQ_353"] && _sceneState["GS_SEQ_354"] &&\
+		_sceneState["GS_SEQ_355"]) {
+		_sceneState["GS_HOTELDONE"] = 1;
+		_nextLevel = "<select_c3>";
+	}
 }
 
 void BoyzEngine::pressedKey(const int keycode) {
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 24be9731703..87d627c1fb3 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -98,6 +98,20 @@ HOTS /BBOX= 190 4 292 76\n\
 SOND tollamb1.raw  22K\n\
 END\n";
 
+static const char *selectHo = "\
+MENU preload\\slct_ho.smk\n\
+HOTS /BBOX= 19  18  85  199\n\
+SOND tien1bb.raw 22K\n\
+HOTS /BBOX= 87  36  143 199\n\
+SOND lan1.raw  22K\n\
+HOTS /BBOX= 144 36  193 199\n\
+SOND mai1.raw 22K\n\
+HOTS /BBOX= 195 55  249 199\n\
+SOND hoa1b.raw 22K\n\
+HOTS /BBOX= 250 32  301 199\n\
+SOND van2.raw 22K\n\
+END\n";
+
 void BoyzEngine::loadAssets() {
 	LibFile *missions = loadLib("", "preload/missions.lib", true);
 	Common::ArchiveMemberList files;
@@ -138,11 +152,16 @@ void BoyzEngine::loadAssets() {
 	loadArcadeLevel("c32.mi_", "<select_c3>", "<retry_menu>", "");
 	loadArcadeLevel("c33.mi_", "<select_c3>", "<retry_menu>", "");
 	loadArcadeLevel("c34.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c35.mi_", "???", "<retry_menu>", "");
-	loadArcadeLevel("c352.mi_", "???", "<retry_menu>", "");
-	loadArcadeLevel("c353.mi_", "???", "<retry_menu>", "");
-	loadArcadeLevel("c354.mi_", "???", "<retry_menu>", "");
-	loadArcadeLevel("c355.mi_", "???", "<retry_menu>", "");
+	loadArcadeLevel("c35.mi_", "<select_ho>", "<retry_menu>", "");
+
+	loadArcadeLevel("c351.mi_", "<select_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c352.mi_", "<select_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c353.mi_", "<select_ho>", "<retry_menu>", "");
+	ArcadeShooting *ar = (ArcadeShooting *) _levels["c353.mi_"];
+	ar->id = 353; // This corrects a mistake in the game scripts
+	loadArcadeLevel("c354.mi_", "<select_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c355.mi_", "<select_ho>", "<retry_menu>", "");
+
 	loadArcadeLevel("c36.mi_", "c41.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c41.mi_", "c42.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c42.mi_", "c51.mi_", "<retry_menu>", "");
@@ -246,10 +265,50 @@ void BoyzEngine::loadAssets() {
 	hl = new Highlight("GS_WONSHELLGAME");
 	sc->hots[5].actions.push_back(hl);
 	gl = new Global("GS_WONSHELLGAME", "NCHECK");
+	gl = new Global("GS_HOTELDONE", "NCHECK");
 	sc->hots[5].actions.push_back(gl);
 	cl = new ChangeLevel("c35.mi_");
 	sc->hots[5].actions.push_back(cl);
 
+	loadSceneLevel(selectHo, "<select_ho>", "", "");
+	sc = (Scene *) _levels["<select_ho>"];
+	sc->resolution = "320x200";
+
+	hl = new Highlight("GS_SEQ_351");
+	sc->hots[1].actions.push_back(hl);
+	gl = new Global("GS_SEQ_351", "NCHECK");
+	sc->hots[1].actions.push_back(gl);
+	cl = new ChangeLevel("c351.mi_");
+	sc->hots[1].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_352");
+	sc->hots[2].actions.push_back(hl);
+	gl = new Global("GS_SEQ_352", "NCHECK");
+	sc->hots[2].actions.push_back(gl);
+	cl = new ChangeLevel("c352.mi_");
+	sc->hots[2].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_353");
+	sc->hots[3].actions.push_back(hl);
+	gl = new Global("GS_SEQ_353", "NCHECK");
+	sc->hots[3].actions.push_back(gl);
+	cl = new ChangeLevel("c353.mi_");
+	sc->hots[3].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_354");
+	sc->hots[4].actions.push_back(hl);
+	gl = new Global("GS_SEQ_354", "NCHECK");
+	sc->hots[4].actions.push_back(gl);
+	cl = new ChangeLevel("c354.mi_");
+	sc->hots[4].actions.push_back(cl);
+
+	hl = new Highlight("GS_SEQ_355");
+	sc->hots[5].actions.push_back(hl);
+	gl = new Global("GS_SEQ_355", "NCHECK");
+	sc->hots[5].actions.push_back(gl);
+	cl = new ChangeLevel("c355.mi_");
+	sc->hots[5].actions.push_back(cl);
+
 	loadLib("sound/", "misc/sound.lib", true);
 
 	_weaponShootSound[0] = "";


Commit: d76aac78309d3ce0e3e2d7823b54d8634c01ad75
    https://github.com/scummvm/scummvm/commit/d76aac78309d3ce0e3e2d7823b54d8634c01ad75
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: allow to run level c35 with no weapon in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 6c4c7120b9b..27cfab24a63 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -30,22 +30,30 @@ void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
 	_checkpoint = _currentLevel;
 	if (!_name.empty()) // if name is name, then we are testing some level
 		saveProfile(_name, int(arc->id));
-	assert(!arc->player.empty());
-	_playerFrames = decodeFrames(arc->player);
-	_playerFrameSep = 0;
 
-	Common::Rect healthBarBox(0, 3, 107, 18);
-	Common::Rect ammoBarBox(0, 20, 103, 34);
-	Common::Rect portraitBox(0, 40, 57, 94);
+	if (arc->mode == "YM") {
+		assert(!arc->player.empty());
+		_playerFrames = decodeFrames(arc->player);
+		_playerFrameSep = 0;
 
-	for (int i = 0; i < int(_playerFrames.size()); i++) {
-		_healthBar[i+1] = _playerFrames[i]->getSubArea(healthBarBox);
-		_ammoBar[i+1] = _playerFrames[i]->getSubArea(ammoBarBox);
-		_portrait[i+1] = _playerFrames[i]->getSubArea(portraitBox);
-	}
+		Common::Rect healthBarBox(0, 3, 107, 18);
+		Common::Rect ammoBarBox(0, 20, 103, 34);
+		Common::Rect portraitBox(0, 40, 57, 94);
 
-	_playerFrameSep = _playerFrames.size();
-	_playerFrameIdx = -1;
+		for (int i = 0; i < int(_playerFrames.size()); i++) {
+			_healthBar[i+1] = _playerFrames[i]->getSubArea(healthBarBox);
+			_ammoBar[i+1] = _playerFrames[i]->getSubArea(ammoBarBox);
+			_portrait[i+1] = _playerFrames[i]->getSubArea(portraitBox);
+		}
+
+		_playerFrameSep = _playerFrames.size();
+		_playerFrameIdx = -1;
+	} else {
+		_playerFrameSep = 0;
+		_playerFrameIdx = -1;
+		if (arc->mode != "YS")
+			error("Invalid mode: %s", arc->mode.c_str());
+	}
 
 	if (!arc->beforeVideo.empty()) {
 		MVideo video(arc->beforeVideo, Common::Point(0, 0), false, true, false);
@@ -140,6 +148,8 @@ void BoyzEngine::drawPlayer() {
 
 void BoyzEngine::drawHealth() {
 	updateFromScript();
+	if(_arcadeMode == "YS")
+		return;
 
 	float w = float(_health) / float(_maxHealth);
 	Common::Rect healthBarBox(0, 0, int((_healthBar[_currentActor].w - 3) * w), _healthBar[_currentActor].h / 2);
@@ -157,6 +167,8 @@ void BoyzEngine::drawHealth() {
 
 void BoyzEngine::drawAmmo() {
 	updateFromScript();
+	if(_arcadeMode == "YS")
+		return;
 
 	float w = float(_ammoBar[_currentActor].w) / float(_weaponMaxAmmo[_currentWeapon]);
 
@@ -172,6 +184,9 @@ void BoyzEngine::drawAmmo() {
 }
 
 void BoyzEngine::hitPlayer() {
+	if(_arcadeMode == "YS")
+		return; // Should never happen?
+
 	uint32 c = kHypnoColorRed; // red
 	_compositeSurface->fillRect(Common::Rect(0, 0, _screenW, _screenH), c);
 	drawScreen();
@@ -267,7 +282,7 @@ int BoyzEngine::detectTarget(const Common::Point &mousePos) {
 
 	int i = 0;
 	for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
-		if (_background->decoder->getCurFrame() > int(it->bodyFrames.back().start)) {
+		if (!it->bodyFrames.empty() && _background->decoder->getCurFrame() > int(it->bodyFrames.back().start)) {
 			i++;
 			continue;  // This shoot is old!
 		}
@@ -287,7 +302,7 @@ bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool
 		return false;
 	}
 
-	if (!secondary) {
+	if (!secondary && _currentWeapon > 0) {
 		if (_ammo == 0) {
 			if (!arc->noAmmoSound.empty())
 				playSound(_soundPath + arc->noAmmoSound, 1, arc->noAmmoSoundRate);
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 87d627c1fb3..e0902854561 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -361,7 +361,20 @@ void BoyzEngine::loadAssets() {
 
 	Common::Rect cursorBox;
 
-	// Pistol?
+	// No weapon, same as pistol
+	cursorBox = Common::Rect(62, 6, 83, 26);
+	_crosshairsInactive[0].create(cursorBox.width(), cursorBox.height(), _pixelFormat);
+	_crosshairsInactive[0].copyRectToSurface(*targets, 0, 0, cursorBox);
+
+	cursorBox = Common::Rect(62, 38, 83, 58);
+	_crosshairsActive[0].create(cursorBox.width(), cursorBox.height(), _pixelFormat);
+	_crosshairsActive[0].copyRectToSurface(*targets, 0, 0, cursorBox);
+
+	cursorBox = Common::Rect(62, 70, 83, 90);
+	_crosshairsTarget[0].create(cursorBox.width(), cursorBox.height(), _pixelFormat);
+	_crosshairsTarget[0].copyRectToSurface(*targets, 0, 0, cursorBox);
+
+	// Pistol
 	cursorBox = Common::Rect(62, 6, 83, 26);
 	_crosshairsInactive[1].create(cursorBox.width(), cursorBox.height(), _pixelFormat);
 	_crosshairsInactive[1].copyRectToSurface(*targets, 0, 0, cursorBox);


Commit: a62e363ab830c6a8b9bd887e5c9de7bbbb6eb291
    https://github.com/scummvm/scummvm/commit/a62e363ab830c6a8b9bd887e5c9de7bbbb6eb291
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:10+02:00

Commit Message:
HYPNO: initial implementation of level c35 in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 27cfab24a63..b1f56aa2558 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -49,6 +49,8 @@ void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
 		_playerFrameSep = _playerFrames.size();
 		_playerFrameIdx = -1;
 	} else {
+		uint32 r = 1 + _rnd->getRandomNumber(1);
+		arc->backgroundVideo = Common::String::format("c3/c35c0%ds.smk", r);
 		_playerFrameSep = 0;
 		_playerFrameIdx = -1;
 		if (arc->mode != "YS")
@@ -77,7 +79,11 @@ void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
 		delete _playerFrames[i];
 	}
 
+
 	if (_health <= 0) {
+		if (_arcadeMode == "YS")
+			return;
+
 		MVideo video(_deathDay[_currentActor], Common::Point(0, 0), false, true, false);
 		disableCursor();
 		runIntro(video);
@@ -356,6 +362,8 @@ bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool
 			return false;
 		} else if (_shoots[i].nonHostile && !secondary) {
 
+			if (checkCup(_shoots[i].name))
+				return false;
 			Common::String filename = _warningVideosDay[_shoots[i].warningVideoIdx];
 			_civiliansShoot++;
 
@@ -477,6 +485,37 @@ void BoyzEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
 		hitPlayer();
 }
 
+bool BoyzEngine::checkCup(const Common::String &name) {
+	if (name == "CUP1") {
+		if (_background->path == "c3/c35c01s.smk") {
+			MVideo video("c3/c35c07s.smk", Common::Point(0, 0), false, true, false);
+			disableCursor();
+			runIntro(video);
+			_skipLevel = true;
+		} else {
+			MVideo video("c3/c35c06s.smk", Common::Point(0, 0), false, true, false);
+			disableCursor();
+			runIntro(video);
+			_health = 0;
+		}
+		return true;
+	} else if (name == "CUP2") {
+		if (_background->path == "c3/c35c02s.smk") {
+			MVideo video("c3/c35c07s.smk", Common::Point(0, 0), false, true, false);
+			disableCursor();
+			runIntro(video);
+			_skipLevel = true;
+		} else {
+			MVideo video("c3/c35c06s.smk", Common::Point(0, 0), false, true, false);
+			disableCursor();
+			runIntro(video);
+			_health = 0;
+		}
+		return true;
+	}
+	return false;
+}
+
 bool BoyzEngine::clickedSecondaryShoot(const Common::Point &mousePos) {
 	if (_currentMode == NonInteractive) {
 		return false;
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index e0902854561..1673dfac761 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -152,12 +152,14 @@ void BoyzEngine::loadAssets() {
 	loadArcadeLevel("c32.mi_", "<select_c3>", "<retry_menu>", "");
 	loadArcadeLevel("c33.mi_", "<select_c3>", "<retry_menu>", "");
 	loadArcadeLevel("c34.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c35.mi_", "<select_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c35.mi_", "<select_ho>", "<select_c3>", "");
+	ArcadeShooting *ar = (ArcadeShooting *) _levels["c35.mi_"];
+	ar->backgroundVideo = ""; // This will be manually populated
 
 	loadArcadeLevel("c351.mi_", "<select_ho>", "<retry_menu>", "");
 	loadArcadeLevel("c352.mi_", "<select_ho>", "<retry_menu>", "");
 	loadArcadeLevel("c353.mi_", "<select_ho>", "<retry_menu>", "");
-	ArcadeShooting *ar = (ArcadeShooting *) _levels["c353.mi_"];
+	ar = (ArcadeShooting *) _levels["c353.mi_"];
 	ar->id = 353; // This corrects a mistake in the game scripts
 	loadArcadeLevel("c354.mi_", "<select_ho>", "<retry_menu>", "");
 	loadArcadeLevel("c355.mi_", "<select_ho>", "<retry_menu>", "");
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index e65169114bc..d3a842af730 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -606,6 +606,7 @@ public:
 	Graphics::Surface _crosshairsTarget[8];
 
 	void updateFromScript();
+	bool checkCup(const Common::String &name);
 
 	Script _currentScript;
 	ScriptMode _currentMode;


Commit: 7c9ff5842c205ee506a1952bc9225ab15f8519d8
    https://github.com/scummvm/scummvm/commit/7c9ff5842c205ee506a1952bc9225ab15f8519d8
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:11+02:00

Commit Message:
HYPNO: refactor check conditions for c3 levels in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/boyz/boyz.cpp
    engines/hypno/boyz/hard.cpp
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index b1f56aa2558..515d036cdbb 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -92,13 +92,6 @@ void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
 
 	_previousHealth = _health;
 	_sceneState[Common::String::format("GS_SEQ_%d", _levelId)] = 1;
-
-	if (_sceneState["GS_SEQ_351"] && _sceneState["GS_SEQ_352"] &&\
-	    _sceneState["GS_SEQ_353"] && _sceneState["GS_SEQ_354"] &&\
-		_sceneState["GS_SEQ_355"]) {
-		_sceneState["GS_HOTELDONE"] = 1;
-		_nextLevel = "<select_c3>";
-	}
 }
 
 void BoyzEngine::pressedKey(const int keycode) {
diff --git a/engines/hypno/boyz/boyz.cpp b/engines/hypno/boyz/boyz.cpp
index 1673dfac761..f86370ad342 100644
--- a/engines/hypno/boyz/boyz.cpp
+++ b/engines/hypno/boyz/boyz.cpp
@@ -42,6 +42,10 @@ static const chapterEntry rawChapterTable[] = {
 	{32, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
 	{33, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
 	{34, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{3591, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{3592, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{36, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
+	{41, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor},
 	{0,  {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoNoColor}
 };
 
@@ -148,21 +152,21 @@ void BoyzEngine::loadAssets() {
 
 	loadArcadeLevel("c21.mi_", "c22.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c22.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c31.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c32.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c33.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c34.mi_", "<select_c3>", "<retry_menu>", "");
-	loadArcadeLevel("c35.mi_", "<select_ho>", "<select_c3>", "");
+	loadArcadeLevel("c31.mi_", "<check_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c32.mi_", "<check_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c33.mi_", "<check_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c34.mi_", "<check_c3>", "<retry_menu>", "");
+	loadArcadeLevel("c35.mi_", "<check_ho>", "<select_c3>", "");
 	ArcadeShooting *ar = (ArcadeShooting *) _levels["c35.mi_"];
 	ar->backgroundVideo = ""; // This will be manually populated
 
-	loadArcadeLevel("c351.mi_", "<select_ho>", "<retry_menu>", "");
-	loadArcadeLevel("c352.mi_", "<select_ho>", "<retry_menu>", "");
-	loadArcadeLevel("c353.mi_", "<select_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c351.mi_", "<check_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c352.mi_", "<check_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c353.mi_", "<check_ho>", "<retry_menu>", "");
 	ar = (ArcadeShooting *) _levels["c353.mi_"];
 	ar->id = 353; // This corrects a mistake in the game scripts
-	loadArcadeLevel("c354.mi_", "<select_ho>", "<retry_menu>", "");
-	loadArcadeLevel("c355.mi_", "<select_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c354.mi_", "<check_ho>", "<retry_menu>", "");
+	loadArcadeLevel("c355.mi_", "<check_ho>", "<retry_menu>", "");
 
 	loadArcadeLevel("c36.mi_", "c41.mi_", "<retry_menu>", "");
 	loadArcadeLevel("c41.mi_", "c42.mi_", "<retry_menu>", "");
@@ -311,6 +315,12 @@ void BoyzEngine::loadAssets() {
 	cl = new ChangeLevel("c355.mi_");
 	sc->hots[5].actions.push_back(cl);
 
+	Code *check_c3 = new Code("<check_c3>");
+	_levels["<check_c3>"] = check_c3;
+
+	Code *check_ho = new Code("<check_ho>");
+	_levels["<check_ho>"] = check_ho;
+
 	loadLib("sound/", "misc/sound.lib", true);
 
 	_weaponShootSound[0] = "";
@@ -697,7 +707,13 @@ Common::Error BoyzEngine::loadGameStream(Common::SeekableReadStream *stream) {
 	_sceneState["GS_SEQ_34"] = stream->readUint32LE();
 	_sceneState["GS_SEQ_35"] = stream->readUint32LE();
 
-	_nextLevel = Common::String::format("c%d.mi_", _ids[_lastLevel]);
+
+	if (_ids[_lastLevel] == 3591)
+		_nextLevel = "<select_c3>";
+	else if (_ids[_lastLevel] == 3592)
+		_nextLevel = "<select_ho>";
+	else
+		_nextLevel = Common::String::format("c%d.mi_", _ids[_lastLevel]);
 	return Common::kNoError;
 }
 
diff --git a/engines/hypno/boyz/hard.cpp b/engines/hypno/boyz/hard.cpp
index 5f2c9e0d13c..edeccfba7b5 100644
--- a/engines/hypno/boyz/hard.cpp
+++ b/engines/hypno/boyz/hard.cpp
@@ -36,6 +36,10 @@ void BoyzEngine::runCode(Code *code) {
 		runDifficultyMenu(code);
 	else if (code->name == "<retry_menu>")
 		runRetryMenu(code);
+	else if (code->name == "<check_c3>")
+		runCheckC3(code);
+	else if (code->name == "<check_ho>")
+		runCheckHo(code);
 	else
 		error("invalid hardcoded level: %s", code->name.c_str());
 }
@@ -255,6 +259,37 @@ void BoyzEngine::runRetryMenu(Code *code) {
 	delete menu;
 }
 
+void BoyzEngine::runCheckC3(Code *code) {
+	Common::String nextLevel;
+	if (_sceneState["GS_SEQ_31"] && _sceneState["GS_SEQ_32"] &&\
+		_sceneState["GS_SEQ_33"] && _sceneState["GS_SEQ_34"] &&\
+		_sceneState["GS_HOTELDONE"]) {
+		nextLevel = "c36.mi_";
+	}
+
+	if (nextLevel.empty())
+		nextLevel = "<select_c3>";
+
+	_nextLevel = nextLevel;
+	saveProfile(_name, 3591);
+}
+
+void BoyzEngine::runCheckHo(Code *code) {
+	Common::String nextLevel;
+	if (_sceneState["GS_SEQ_351"] && _sceneState["GS_SEQ_352"] &&\
+		_sceneState["GS_SEQ_353"] && _sceneState["GS_SEQ_354"] &&\
+		_sceneState["GS_SEQ_355"]) {
+		_sceneState["GS_HOTELDONE"] = 1;
+		nextLevel = "<check_c3>";
+	}
+
+	if (nextLevel.empty())
+		nextLevel = "<select_ho>";
+
+	_nextLevel = nextLevel;
+	saveProfile(_name, 3592);
+}
+
 void BoyzEngine::endCredits(Code *code) {
 	showCredits();
 	_nextLevel = "<main_menu>";
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index d3a842af730..b4b36480dc0 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -583,6 +583,8 @@ public:
 
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);
+	void runCheckC3(Code *code);
+	void runCheckHo(Code *code);
 	void runDifficultyMenu(Code *code);
 	void endCredits(Code *code);
 	Common::String firstLevelTerritory(const Common::String &level);


Commit: 78a96a91c438f4345060af69a145a9f890f37d16
    https://github.com/scummvm/scummvm/commit/78a96a91c438f4345060af69a145a9f890f37d16
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:11+02:00

Commit Message:
HYPNO: update game state when player wins the cup game in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 515d036cdbb..50bdb55a95e 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -485,6 +485,7 @@ bool BoyzEngine::checkCup(const Common::String &name) {
 			disableCursor();
 			runIntro(video);
 			_skipLevel = true;
+			_sceneState["GS_WONSHELLGAME"] = 1;
 		} else {
 			MVideo video("c3/c35c06s.smk", Common::Point(0, 0), false, true, false);
 			disableCursor();
@@ -498,6 +499,7 @@ bool BoyzEngine::checkCup(const Common::String &name) {
 			disableCursor();
 			runIntro(video);
 			_skipLevel = true;
+			_sceneState["GS_WONSHELLGAME"] = 1;
 		} else {
 			MVideo video("c3/c35c06s.smk", Common::Point(0, 0), false, true, false);
 			disableCursor();


Commit: 5e321a0e66825fbafe8c20ea64a11156fec6cf84
    https://github.com/scummvm/scummvm/commit/5e321a0e66825fbafe8c20ea64a11156fec6cf84
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:11+02:00

Commit Message:
HYPNO: allow to stop and wait for a user action in the middle of arcade sequence in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp
    engines/hypno/grammar.h
    engines/hypno/grammar_arc.cpp
    engines/hypno/grammar_arc.y
    engines/hypno/hypno.h


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 50bdb55a95e..e78cda3185b 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -296,6 +296,33 @@ int BoyzEngine::detectTarget(const Common::Point &mousePos) {
 	error("Invalid mask state (%d)!", m);
 }
 
+void BoyzEngine::waitForUserClick(uint32 timeout) {
+	Common::Event event;
+	bool cont = true;
+	Common::Rect button(252, 158, 315, 195);
+	while (!shouldQuit() && cont) {
+		while (g_system->getEventManager()->pollEvent(event)) {
+			Common::Point mousePos = g_system->getEventManager()->getMousePos();
+			switch (event.type) {
+				case Common::EVENT_QUIT:
+				case Common::EVENT_RETURN_TO_LAUNCHER:
+					cont = false;
+					break;
+
+				case Common::EVENT_LBUTTONDOWN:
+					if (button.contains(mousePos))
+						cont = false;
+					break;
+
+				default:
+					break;
+			}
+		}
+		drawScreen();
+		g_system->delayMillis(10);
+	}
+}
+
 bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary) {
 	if (_currentMode == NonInteractive) {
 		return false;
@@ -329,9 +356,14 @@ bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool
 				MVideo video(_shoots[i].additionalVideo, Common::Point(0, 0), false, true, false);
 				disableCursor();
 				runIntro(video);
+				defaultCursor();
+
+				if (_shoots[i].waitForClickAfterInteraction > 0) {
+					waitForUserClick(_shoots[i].waitForClickAfterInteraction);
+				}
+
 				loadPalette(_currentPalette);
 				_background->decoder->pauseVideo(false);
-
 				// Skip the rest of the interaction
 				_background->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
 				_masks->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
diff --git a/engines/hypno/grammar.h b/engines/hypno/grammar.h
index eb380f62394..2c0f3773f5b 100644
--- a/engines/hypno/grammar.h
+++ b/engines/hypno/grammar.h
@@ -445,6 +445,7 @@ public:
 		animalSound = "";
 		jumpToTimeAfterKilled = 0;
 		warningVideoIdx = 0;
+		waitForClickAfterInteraction = 0;
 	}
 	Common::String name;
 	Filename animation;
@@ -492,6 +493,7 @@ public:
 	bool isAnimal;
 	Common::String checkIfDestroyed;
 	int jumpToTimeAfterKilled;
+	uint32 waitForClickAfterInteraction;
 	uint32 warningVideoIdx;
 };
 
diff --git a/engines/hypno/grammar_arc.cpp b/engines/hypno/grammar_arc.cpp
index 69a2d65e5db..9d1ea93502c 100644
--- a/engines/hypno/grammar_arc.cpp
+++ b/engines/hypno/grammar_arc.cpp
@@ -631,8 +631,8 @@ static const yytype_int16 yyrline[] =
      403,   407,   411,   415,   419,   423,   427,   431,   435,   439,
      443,   447,   451,   455,   458,   462,   467,   472,   475,   480,
      485,   489,   495,   499,   502,   503,   504,   507,   511,   514,
-     519,   522,   523,   527,   534,   538,   549,   553,   554,   558,
-     562,   566,   569,   572,   574
+     519,   522,   523,   527,   534,   538,   549,   553,   554,   560,
+     564,   568,   571,   574,   576
 };
 #endif
 
@@ -2244,65 +2244,67 @@ yyreduce:
 #line 554 "engines/hypno/grammar_arc.y"
                            {
 		shoot->interactionFrame = (yyvsp[-2].i);
+		assert((yyvsp[-1].i) == 0);
+		shoot->waitForClickAfterInteraction = (yyvsp[0].i);
 		debugC(1, kHypnoDebugParser, "T %d %d %d", (yyvsp[-2].i), (yyvsp[-1].i), (yyvsp[0].i));
 	}
-#line 2250 "engines/hypno/grammar_arc.cpp"
+#line 2252 "engines/hypno/grammar_arc.cpp"
     break;
 
   case 109: /* bline: TTOK NUM  */
-#line 558 "engines/hypno/grammar_arc.y"
+#line 560 "engines/hypno/grammar_arc.y"
                    {
 		shoot->interactionFrame = (yyvsp[0].i);
 		debugC(1, kHypnoDebugParser, "T %d", (yyvsp[0].i));
 	}
-#line 2259 "engines/hypno/grammar_arc.cpp"
+#line 2261 "engines/hypno/grammar_arc.cpp"
     break;
 
   case 110: /* bline: TTOK  */
-#line 562 "engines/hypno/grammar_arc.y"
+#line 564 "engines/hypno/grammar_arc.y"
                {
 		shoot->isAnimal = true;
 		debugC(1, kHypnoDebugParser, "T");
 	}
-#line 2268 "engines/hypno/grammar_arc.cpp"
+#line 2270 "engines/hypno/grammar_arc.cpp"
     break;
 
   case 111: /* bline: MTOK  */
-#line 566 "engines/hypno/grammar_arc.y"
+#line 568 "engines/hypno/grammar_arc.y"
                {
 		debugC(1, kHypnoDebugParser, "M");
 	}
-#line 2276 "engines/hypno/grammar_arc.cpp"
+#line 2278 "engines/hypno/grammar_arc.cpp"
     break;
 
   case 112: /* bline: NTOK  */
-#line 569 "engines/hypno/grammar_arc.y"
+#line 571 "engines/hypno/grammar_arc.y"
                {
 		shoot->noEnemySound = true;
 		debugC(1, kHypnoDebugParser, "N"); }
-#line 2284 "engines/hypno/grammar_arc.cpp"
+#line 2286 "engines/hypno/grammar_arc.cpp"
     break;
 
   case 113: /* bline: NRTOK  */
-#line 572 "engines/hypno/grammar_arc.y"
+#line 574 "engines/hypno/grammar_arc.y"
                 {
 		debugC(1, kHypnoDebugParser, "NR"); }
-#line 2291 "engines/hypno/grammar_arc.cpp"
+#line 2293 "engines/hypno/grammar_arc.cpp"
     break;
 
   case 114: /* bline: ZTOK  */
-#line 574 "engines/hypno/grammar_arc.y"
+#line 576 "engines/hypno/grammar_arc.y"
                {
 		g_parsedArc->shoots.push_back(*shoot);
 		//delete shoot;
 		//shoot = nullptr;
 		debugC(1, kHypnoDebugParser, "Z");
 	}
-#line 2302 "engines/hypno/grammar_arc.cpp"
+#line 2304 "engines/hypno/grammar_arc.cpp"
     break;
 
 
-#line 2306 "engines/hypno/grammar_arc.cpp"
+#line 2308 "engines/hypno/grammar_arc.cpp"
 
       default: break;
     }
diff --git a/engines/hypno/grammar_arc.y b/engines/hypno/grammar_arc.y
index 8749e590af4..a2b3573c949 100644
--- a/engines/hypno/grammar_arc.y
+++ b/engines/hypno/grammar_arc.y
@@ -553,6 +553,8 @@ bline: FNTOK FILENAME {
 	| GTOK { debugC(1, kHypnoDebugParser, "G"); }
 	| TTOK NUM NUM NUM {
 		shoot->interactionFrame = $2;
+		assert($3 == 0);
+		shoot->waitForClickAfterInteraction = $4;
 		debugC(1, kHypnoDebugParser, "T %d %d %d", $2, $3, $4);
 	}
 	| TTOK NUM {
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index b4b36480dc0..24942326800 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -580,6 +580,7 @@ public:
 
 	private:
 	void renderHighlights(Hotspots *hs);
+	void waitForUserClick(uint32 timeout);
 
 	void runMainMenu(Code *code);
 	void runRetryMenu(Code *code);


Commit: 382b7b0ff67f3cddc7e4a87d48bb5932017519e7
    https://github.com/scummvm/scummvm/commit/382b7b0ff67f3cddc7e4a87d48bb5932017519e7
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:11+02:00

Commit Message:
HYPNO: fixes for level c51 in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index e78cda3185b..f22c33d1c98 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -218,7 +218,9 @@ bool BoyzEngine::checkTransition(ArcadeTransitions &transitions, ArcadeShooting
 	ArcadeTransition at = *transitions.begin();
 	int ttime = at.time;
 	if (_background->decoder->getCurFrame() > ttime) {
-		if (at.video == "NONE") {
+		if (_background->decoder->getCurFrame() > ttime + 3) {
+			debugC(1, kHypnoDebugArcade, "Skipped transition of %d at %d", ttime, _background->decoder->getCurFrame());
+		} else if (at.video == "NONE") {
 			if (!at.palette.empty()) {
 				_background->decoder->pauseVideo(true);
 				_currentPalette = at.palette;
@@ -234,6 +236,8 @@ bool BoyzEngine::checkTransition(ArcadeTransitions &transitions, ArcadeShooting
 					_health = 0;
 					// Not sure how to handle this
 				}
+			} else if (_levelId == 51) {
+				waitForUserClick(1);
 			}
 		} else if (!at.video.empty()) {
 			_background->decoder->pauseVideo(true);
@@ -389,7 +393,9 @@ bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool
 
 			if (checkCup(_shoots[i].name))
 				return false;
-			Common::String filename = _warningVideosDay[_shoots[i].warningVideoIdx];
+			uint32 idx = _shoots[i].warningVideoIdx;
+			idx = idx == 0 ? 2 : idx;
+			Common::String filename = _warningVideosDay[idx];
 			_civiliansShoot++;
 
 			_background->decoder->pauseVideo(true);
@@ -495,8 +501,8 @@ void BoyzEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
 	} else if (s->missedAnimation == uint32(-1000)) {
 		_health = 0;
 	} else {
-		int missedAnimation = s->missedAnimation + 3;
-		if (missedAnimation > int(_background->decoder->getFrameCount()) - 1) {
+		int missedAnimation = s->missedAnimation;
+		if (missedAnimation + 3 > int(_background->decoder->getFrameCount()) - 1) {
 			_skipLevel = true;
 			return;
 		}
@@ -506,7 +512,7 @@ void BoyzEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
 		_background->decoder->forceSeekToFrame(missedAnimation);
 		_masks->decoder->forceSeekToFrame(missedAnimation);
 	}
-	if (s->interactionFrame == 0)
+	if (!s->nonHostile)
 		hitPlayer();
 }
 


Commit: f30fb8706b25d711d97a6ed5cec9de1b0287b83b
    https://github.com/scummvm/scummvm/commit/f30fb8706b25d711d97a6ed5cec9de1b0287b83b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:11+02:00

Commit Message:
HYPNO: correctly finish level c353 in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index f22c33d1c98..95b77971fe2 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -369,14 +369,18 @@ bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool
 				loadPalette(_currentPalette);
 				_background->decoder->pauseVideo(false);
 				// Skip the rest of the interaction
-				_background->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
-				_masks->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
-				_shoots[i].destroyed = true;
-				_shootsDestroyed[_shoots[i].name] = true;
-				updateScreen(*_background);
-				drawScreen();
-				if (!_music.empty())
-					playSound(_music, 0, arc->musicRate); // restore music
+				if (_shoots[i].explosionFrames[0].start == uint32(-1))
+					_skipLevel = true;
+				else {
+					_background->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
+					_masks->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
+					_shoots[i].destroyed = true;
+					_shootsDestroyed[_shoots[i].name] = true;
+					updateScreen(*_background);
+					drawScreen();
+					if (!_music.empty())
+						playSound(_music, 0, arc->musicRate); // restore music
+				}
 			} else if (_shoots[i].interactionFrame > 0) {
 				_background->decoder->forceSeekToFrame(_shoots[i].interactionFrame);
 				_masks->decoder->forceSeekToFrame(_shoots[i].interactionFrame);


Commit: 22a87016add2f81697cbe7e54b96a1418b976a94
    https://github.com/scummvm/scummvm/commit/22a87016add2f81697cbe7e54b96a1418b976a94
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2022-05-25T13:00:11+02:00

Commit Message:
HYPNO: correctly finish levels c352 and c355 in boyz

Changed paths:
    engines/hypno/boyz/arcade.cpp


diff --git a/engines/hypno/boyz/arcade.cpp b/engines/hypno/boyz/arcade.cpp
index 95b77971fe2..44128ed729d 100644
--- a/engines/hypno/boyz/arcade.cpp
+++ b/engines/hypno/boyz/arcade.cpp
@@ -236,6 +236,9 @@ bool BoyzEngine::checkTransition(ArcadeTransitions &transitions, ArcadeShooting
 					_health = 0;
 					// Not sure how to handle this
 				}
+			} else if (_levelId == 352) {
+				// Objectives are never checked here, for some reason
+				_skipLevel = true;
 			} else if (_levelId == 51) {
 				waitForUserClick(1);
 			}
@@ -487,7 +490,7 @@ void BoyzEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
 			_skipLevel = true;
 		return;
 	} else if (s->name.hasPrefix("ALARM")) {
-		if (_background->decoder->getCurFrame() > int(s->missedAnimation))
+		if (s->missedAnimation != uint32(-1) && uint32(_background->decoder->getCurFrame()) > s->missedAnimation)
 			return;
 		_background->decoder->pauseVideo(true);
 		MVideo video(_warningAlarmVideos.front(), Common::Point(0, 0), false, true, false);




More information about the Scummvm-git-logs mailing list