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

mgerhardy martin.gerhardy at gmail.com
Thu Feb 18 22:53:57 UTC 2021


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

Summary:
5670e59e3d TWINE: support dotemu enhanced edition save games
cab620551e TWINE: added steam achievement support


Commit: 5670e59e3da2cfa00d7b928413cde2e73bfdcea1
    https://github.com/scummvm/scummvm/commit/5670e59e3da2cfa00d7b928413cde2e73bfdcea1
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-02-18T23:52:24+01:00

Commit Message:
TWINE: support dotemu enhanced edition save games

Changed paths:
    engines/twine/scene/gamestate.cpp


diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index ab2c18ed73..850f53ca80 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -152,7 +152,9 @@ bool GameState::loadGame(Common::SeekableReadStream *file) {
 	}
 
 	debug(2, "Load game");
-	if (file->readByte() != 0x03) {
+	const byte saveFileVersion = file->readByte();
+	// 4 is dotemu enhanced version of lba1
+	if (saveFileVersion != 3 && saveFileVersion != 4) {
 		warning("Could not load savegame - wrong magic byte");
 		return false;
 	}
@@ -216,6 +218,12 @@ bool GameState::loadGame(Common::SeekableReadStream *file) {
 	inventoryNumLeafs = file->readByte();
 	usingSabre = file->readByte();
 
+	if (saveFileVersion == 4) {
+		// the time the game was played
+		file->readUint32LE();
+		file->readUint32LE();
+	}
+
 	_engine->_scene->currentSceneIdx = -1;
 	_engine->_scene->heroPositionType = ScenePositionType::kReborn;
 	return true;


Commit: cab620551efd401cbb4c1613ee14efb62e9d6296
    https://github.com/scummvm/scummvm/commit/cab620551efd401cbb4c1613ee14efb62e9d6296
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2021-02-18T23:52:24+01:00

Commit Message:
TWINE: added steam achievement support

Not all achievements are implemented yet

Changed paths:
  A engines/twine/achievements_tables.h
    engines/twine/metaengine.cpp
    engines/twine/scene/actor.cpp
    engines/twine/scene/actor.h
    engines/twine/scene/extra.cpp
    engines/twine/scene/gamestate.cpp
    engines/twine/scene/gamestate.h
    engines/twine/scene/scene.cpp
    engines/twine/script/script_life_v1.cpp
    engines/twine/script/script_move_v1.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/achievements_tables.h b/engines/twine/achievements_tables.h
new file mode 100644
index 0000000000..6e5d1609a4
--- /dev/null
+++ b/engines/twine/achievements_tables.h
@@ -0,0 +1,78 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TWINE_ACHIEVEMENTS_H
+#define TWINE_ACHIEVEMENTS_H
+
+#include "common/achievements.h"
+
+namespace TwinE {
+
+struct AchievementDescriptionList {
+	const char *gameId;
+	Common::AchievementsPlatform platform;
+	const char *appId;
+	const Common::AchievementDescription descriptions[64];
+};
+
+#define ACHIEVEMENT_SIMPLE_ENTRY(id, title, comment) \
+	{ id, false, title, comment }
+#define ACHIEVEMENT_NODESC_ENTRY(id, title) \
+	{ id, false, title, "" }
+#define ACHIEVEMENT_HIDDEN_ENTRY(id, title) \
+	{ id, true, title, "" }
+#define ACHIEVEMENTS_LISTEND \
+	{ 0, 0, 0, 0 }
+
+static const AchievementDescriptionList achievementDescriptionList[] = {
+	{
+		// https://steamdb.info/app/397330/stats/
+		"lba",
+		Common::STEAM_ACHIEVEMENTS,
+		"397330",
+		{
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_001", "Victory!", "Finish the game."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_002", "Heavily armed", "Get the magic saber."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_003", "Collector", "Unlock all the clover boxes."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_004", "FIRE !", "Fire the canon in the museum."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_005", "New record", "Finish the game in less than 4h."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_006", "Double vision", "Get into the meca-pinguin room."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_007", "I do what I want!", "Get the syrup in the pharmacy before going to Twinsen's house."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_008", "Fanboy", "Talk to the Star Wars fanboy."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_009", "Secret breaker", "Find the secret passage in the museum."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_010", "Seasickness", "Unlock the second video of the ferry trip."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_011", "Croesus", "Have at least 500 Kashes in your wallet."),
+			ACHIEVEMENT_SIMPLE_ENTRY("LBA_ACH_012", "In your face", "Unlock the 4 videos in which Twinsen gets a slap."),
+			ACHIEVEMENTS_LISTEND
+		}
+	},
+
+	{0, Common::UNK_ACHIEVEMENTS, 0, {ACHIEVEMENTS_LISTEND}}};
+
+} // namespace TwinE
+
+#undef ACHIEVEMENT_SIMPLE_ENTRY
+#undef ACHIEVEMENT_NODESC_ENTRY
+#undef ACHIEVEMENT_HIDDEN_ENTRY
+#undef ACHIEVEMENTS_LISTEND
+
+#endif // TWINE_ACHIEVEMENTS_H
diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index 06c48774ec..56b6308c8f 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -29,7 +29,7 @@
 #include "common/translation.h"
 #include "engines/advancedDetector.h"
 #include "twine/detection.h"
-
+#include "twine/achievements_tables.h"
 #include "twine/input.h"
 #include "twine/twine.h"
 
@@ -60,6 +60,8 @@ public:
 	Common::Array<Common::Keymap *> initKeymaps(const char *target) const override;
 
 	const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override;
+
+	const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const override;
 };
 
 static const ExtraGuiOption OptWallCollision = {
@@ -165,6 +167,30 @@ const ExtraGuiOptions TwinEMetaEngine::getExtraGuiOptions(const Common::String &
 	return options;
 }
 
+const Common::AchievementsInfo TwinEMetaEngine::getAchievementsInfo(const Common::String &target) const {
+	Common::String gameId = ConfMan.get("gameid", target);
+
+	Common::AchievementsPlatform platform = Common::UNK_ACHIEVEMENTS;
+	Common::String extra = ConfMan.get("extra", target);
+	if (extra.contains("Steam")) {
+		platform = Common::STEAM_ACHIEVEMENTS;
+	}
+
+	// "(gameId, platform) -> result" search
+	Common::AchievementsInfo result;
+	for (const TwinE::AchievementDescriptionList *i = TwinE::achievementDescriptionList; i->gameId; ++i) {
+		if (i->gameId == gameId && i->platform == platform) {
+			result.platform = i->platform;
+			result.appId = i->appId;
+			for (const Common::AchievementDescription *it = i->descriptions; it->id; ++it) {
+				result.descriptions.push_back(*it);
+			}
+			break;
+		}
+	}
+	return result;
+}
+
 //
 // unused:
 // JOY_LEFT_TRIGGER
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index e30e7baca2..392ba6970e 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -350,6 +350,7 @@ void Actor::initActor(int16 actorIdx) {
 void Actor::resetActor(int16 actorIdx) {
 	ActorStruct *actor = _engine->_scene->getActor(actorIdx);
 
+	actor->actorIdx = actorIdx;
 	actor->body = BodyType::btNormal;
 	actor->anim = AnimationTypes::kStanding;
 	actor->x = 0;
diff --git a/engines/twine/scene/actor.h b/engines/twine/scene/actor.h
index 074afa4bcc..707de2bc1d 100644
--- a/engines/twine/scene/actor.h
+++ b/engines/twine/scene/actor.h
@@ -195,6 +195,7 @@ public:
 	bool isAttackAnimationActive() const;
 	bool isJumpAnimationActive() const;
 
+	int16 actorIdx = 0; // own actor index
 	int32 x = 0;
 	int32 y = 0;
 	int32 z = 0;
diff --git a/engines/twine/scene/extra.cpp b/engines/twine/scene/extra.cpp
index cad2fdefea..95527d8348 100644
--- a/engines/twine/scene/extra.cpp
+++ b/engines/twine/scene/extra.cpp
@@ -883,6 +883,9 @@ void Extra::processExtras() {
 					if (_engine->_gameState->inventoryNumKashes > 999) {
 						_engine->_gameState->inventoryNumKashes = 999;
 					}
+					if (_engine->_gameState->inventoryNumKashes >= 500) {
+						_engine->unlockAchievement("LBA_ACH_011");
+					}
 				} else if (extra->info0 == SPRITEHQR_LIFEPOINTS) {
 					_engine->_scene->sceneHero->life += extra->info1;
 					if (_engine->_scene->sceneHero->life > 50) {
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 850f53ca80..828f268e06 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -284,6 +284,27 @@ bool GameState::saveGame(Common::WriteStream *file) {
 	return true;
 }
 
+void GameState::setGameFlag(uint8 index, uint8 value) {
+	debug(2, "Set gameStateFlags[%u]=%u", index, value);
+	_gameStateFlags[index] = value;
+
+	// all 4 slap videos
+	if ((index == 200 || index == 201 || index == 202 || index == 215) &&
+		_gameStateFlags[200] != 0 && _gameStateFlags[201] != 0 && _gameStateFlags[202] != 0 && _gameStateFlags[215] != 0) {
+		_engine->unlockAchievement("LBA_ACH_012");
+	}
+	// second video of ferry trip
+	if (index == 209) {
+		_engine->unlockAchievement("LBA_ACH_010");
+	}
+	if (index == (int)InventoryItems::kiUseSabre) {
+		_engine->unlockAchievement("LBA_ACH_002");
+	}
+	if (index == (int)InventoryItems::kBottleOfSyrup) {
+		_engine->unlockAchievement("LBA_ACH_007");
+	}
+}
+
 void GameState::processFoundItem(int32 item) {
 	_engine->_grid->newCameraX = (_engine->_scene->sceneHero->x + BRICK_HEIGHT) / BRICK_SIZE;
 	_engine->_grid->newCameraY = (_engine->_scene->sceneHero->y + BRICK_HEIGHT) / BRICK_HEIGHT;
diff --git a/engines/twine/scene/gamestate.h b/engines/twine/scene/gamestate.h
index e95362508d..1f621789f1 100644
--- a/engines/twine/scene/gamestate.h
+++ b/engines/twine/scene/gamestate.h
@@ -146,10 +146,7 @@ public:
 		return _gameStateFlags[index];
 	}
 
-	inline void setGameFlag(uint8 index, uint8 value) {
-		debug(2, "Set gameStateFlags[%u]=%u", index, value);
-		_gameStateFlags[index] = value;
-	}
+	void setGameFlag(uint8 index, uint8 value);
 
 	/**
 	 * LBA engine chapter
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 2179e73a7a..f40847a920 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -465,6 +465,14 @@ void Scene::changeScene() {
 	previousSceneIdx = currentSceneIdx;
 	currentSceneIdx = needChangeScene;
 
+	if (needChangeScene == LBA1SceneId::Polar_Island_end_scene) {
+		_engine->unlockAchievement("LBA_ACH_001");
+		// TODO: if you finish in under 4 hours - unlock the achievement - see version 4 savegames
+		// _engine->unlockAchievment("LBA_ACH_005");
+	} else if (needChangeScene == LBA1SceneId::Brundle_Island_Secret_room) {
+		_engine->unlockAchievement("LBA_ACH_006");
+	}
+
 	_engine->_sound->stopSamples();
 
 	resetScene();
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 9af9f08db6..fe1d5c466d 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -652,6 +652,9 @@ static int32 lMESSAGE(TwinEEngine *engine, LifeScriptContext &ctx) {
 	engine->_text->setFontCrossColor(ctx.actor->talkColor);
 	engine->_scene->talkingActor = ctx.actorIdx;
 	engine->_text->drawTextProgressive(textIdx);
+	if (engine->_scene->currentSceneIdx == LBA1SceneId::Principal_Island_Library && engine->_scene->talkingActor == 8)/* && (*(short *)lifeScriptPosition == 0xe2 [226])*/ {
+		engine->unlockAchievement("LBA_ACH_008");
+	}
 	engine->unfreezeTime();
 	engine->_redraw->redrawEngineActions(true);
 
@@ -1242,6 +1245,9 @@ static int32 lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
 static int32 lINC_CLOVER_BOX(TwinEEngine *engine, LifeScriptContext &ctx) {
 	if (engine->_gameState->inventoryNumLeafsBox < 10) {
 		engine->_gameState->inventoryNumLeafsBox++;
+		if (engine->_gameState->inventoryNumLeafsBox == 5) {
+			engine->unlockAchievement("LBA_ACH_003");
+		}
 	}
 	return 0;
 }
diff --git a/engines/twine/script/script_move_v1.cpp b/engines/twine/script/script_move_v1.cpp
index 63c2d67c15..a0003c917e 100644
--- a/engines/twine/script/script_move_v1.cpp
+++ b/engines/twine/script/script_move_v1.cpp
@@ -211,6 +211,10 @@ static int32 mPOS_POINT(TwinEEngine *engine, MoveScriptContext &ctx) {
 static int32 mLABEL(TwinEEngine *engine, MoveScriptContext &ctx) {
 	ctx.actor->labelIdx = ctx.stream.readByte();
 	ctx.actor->currentLabelPtr = ctx.stream.pos() - 2;
+	if (engine->_scene->currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->actorIdx == 2 &&
+		(ctx.actor->labelIdx == 0 || ctx.actor->labelIdx == 1)) {
+		engine->unlockAchievement("LBA_ACH_004");
+	}
 	return 0;
 }
 
@@ -438,6 +442,9 @@ static int32 mOPEN_LEFT(TwinEEngine *engine, MoveScriptContext &ctx) {
 		ctx.actor->speed = 1000;
 		engine->_movements->setActorAngle(ANGLE_0, ANGLE_351, ANGLE_17, &ctx.actor->move);
 	}
+	if (engine->_scene->currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->actorIdx == 16) {
+		engine->unlockAchievement("LBA_ACH_009");
+	}
 	return 0;
 }
 
@@ -454,6 +461,9 @@ static int32 mOPEN_RIGHT(TwinEEngine *engine, MoveScriptContext &ctx) {
 		ctx.actor->speed = 1000;
 		engine->_movements->setActorAngle(ANGLE_0, ANGLE_351, ANGLE_17, &ctx.actor->move);
 	}
+	if (engine->_scene->currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->actorIdx == 16) {
+		engine->unlockAchievement("LBA_ACH_009");
+	}
 	return 0;
 }
 
@@ -470,6 +480,9 @@ static int32 mOPEN_UP(TwinEEngine *engine, MoveScriptContext &ctx) {
 		ctx.actor->speed = 1000;
 		engine->_movements->setActorAngle(ANGLE_0, ANGLE_351, ANGLE_17, &ctx.actor->move);
 	}
+	if (engine->_scene->currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->actorIdx == 16) {
+		engine->unlockAchievement("LBA_ACH_009");
+	}
 	return 0;
 }
 
@@ -486,6 +499,9 @@ static int32 mOPEN_DOWN(TwinEEngine *engine, MoveScriptContext &ctx) {
 		ctx.actor->speed = 1000;
 		engine->_movements->setActorAngle(ANGLE_0, ANGLE_351, ANGLE_17, &ctx.actor->move);
 	}
+	if (engine->_scene->currentSceneIdx == LBA1SceneId::Proxima_Island_Museum && ctx.actor->actorIdx == 16) {
+		engine->unlockAchievement("LBA_ACH_009");
+	}
 	return 0;
 }
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 3aa749bbe4..022e90b881 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -1167,4 +1167,27 @@ void TwinEEngine::drawText(int32 x, int32 y, const char *string, int32 center) {
 	                 center ? Graphics::kTextAlignCenter : Graphics::kTextAlignLeft);
 }
 
+const char *TwinEEngine::getGameId() const {
+	if (isLBA1()) {
+		return "lba";
+	}
+	assert(isLBA2());
+	return "lba2";
+}
+
+bool TwinEEngine::unlockAchievement(const Common::String &id) {
+	const MetaEngine &meta = getMetaEngine();
+	const Common::AchievementsInfo &achievementsInfo = meta.getAchievementsInfo(getGameId());
+
+	Common::String msg = id;
+	for (uint32 i = 0; i < achievementsInfo.descriptions.size(); i++) {
+		if (id == achievementsInfo.descriptions[i].id) {
+			msg = achievementsInfo.descriptions[i].title;
+			break;
+		}
+	}
+
+	return AchMan.setAchievement(id, msg);
+}
+
 } // namespace TwinE
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index ec843c1204..e375fdbca7 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -228,6 +228,9 @@ public:
 
 	bool isLBA1() const { return _gameType == TwineGameType::GType_LBA; }
 	bool isLBA2() const { return _gameType == TwineGameType::GType_LBA2; }
+	const char *getGameId() const;
+
+	bool unlockAchievement(const Common::String &id);
 
 	Actor *_actor;
 	Animations *_animations;




More information about the Scummvm-git-logs mailing list