[Scummvm-git-logs] scummvm master -> f1ce81461e40dcf924c9d63aef8e0744bc5b74ce
tag2015
noreply at scummvm.org
Sat Sep 2 12:48:08 UTC 2023
This automated email contains information about 10 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
f5511afa82 AGS: Engine: also ignore special keys for skipping video and InventoryScreen
40e79d9e20 AGS: Engine: in legacy read save functions take game data ver as an argument
cca0be77a1 AGS: Engine: a config hint to assume data version when reading a legacy save
7cd860207d AGS: Engine: add object and char assertions in Get/SetProperty functions
94a8518dd7 AGS: Engine: don't reset idle animation during speech with no speech view
4f069b677a AGS: Engine: fixed characters sometimes wait after moving before idle anim
947acb21ec AGS: Engine: fixed improper cleanup of scrGUI array in unload_game_file()
57e9963b2e AGS: Engine: fixed game package test when loading an old save
1c520e25a3 AGS: Engine: add proper asserts for number of GUI controls for legacy saves
f1ce81461e AGS: Engine: hotfix game.top_inv_item script variable not working
Commit: f5511afa82c609feced1fbf588524c82841aa718
https://github.com/scummvm/scummvm/commit/f5511afa82c609feced1fbf588524c82841aa718
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T13:23:58+02:00
Commit Message:
AGS: Engine: also ignore special keys for skipping video and InventoryScreen
>From upstream 7987e670fd58691de106f21d03c07fbc4094718c
Changed paths:
engines/ags/engine/ac/inv_window.cpp
engines/ags/engine/media/video/video.cpp
diff --git a/engines/ags/engine/ac/inv_window.cpp b/engines/ags/engine/ac/inv_window.cpp
index 239a0b7a568..93a68e42ec0 100644
--- a/engines/ags/engine/ac/inv_window.cpp
+++ b/engines/ags/engine/ac/inv_window.cpp
@@ -350,7 +350,7 @@ bool InventoryScreen::Run() {
bool do_break = false;
while (ags_keyevent_ready()) {
KeyInput ki;
- if (run_service_key_controls(ki) && !_GP(play).IsIgnoringInput()) {
+ if (run_service_key_controls(ki) && !_GP(play).IsIgnoringInput() && !IsAGSServiceKey(ki.Key)) {
ags_clear_input_buffer();
do_break = true; // end inventory screen loop
}
diff --git a/engines/ags/engine/media/video/video.cpp b/engines/ags/engine/media/video/video.cpp
index f98c8654c73..befd6f1c5ca 100644
--- a/engines/ags/engine/media/video/video.cpp
+++ b/engines/ags/engine/media/video/video.cpp
@@ -114,14 +114,14 @@ static bool play_video(Video::VideoDecoder *decoder, const char *name, int flags
if (skip != VideoSkipNone) {
// Check for whether user aborted video
- KeyInput key;
+ KeyInput ki;
eAGSMouseButton mbut;
int mwheelz;
// Handle all the buffered key events
bool do_break = false;
while (ags_keyevent_ready()) {
- if (run_service_key_controls(key)) {
- if ((key.Key == eAGSKeyCodeEscape) && (skip == VideoSkipEscape))
+ if (run_service_key_controls(ki) && !IsAGSServiceKey(ki.Key)) {
+ if ((ki.Key == eAGSKeyCodeEscape) && (skip == VideoSkipEscape))
do_break = true;
if (skip >= VideoSkipAnyKey)
do_break = true; // skip on any key
Commit: 40e79d9e20131850c76971b23fdc9fa9b1f39ced
https://github.com/scummvm/scummvm/commit/40e79d9e20131850c76971b23fdc9fa9b1f39ced
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T13:23:59+02:00
Commit Message:
AGS: Engine: in legacy read save functions take game data ver as an argument
>From upstream 8e280225f2c73980034db6866696f40d7bb63ad8
Changed paths:
engines/ags/engine/ac/game_state.cpp
engines/ags/engine/ac/game_state.h
engines/ags/engine/ac/room_status.cpp
engines/ags/engine/ac/room_status.h
engines/ags/engine/game/savegame.cpp
engines/ags/engine/game/savegame_components.cpp
engines/ags/engine/game/savegame_v321.cpp
engines/ags/shared/ac/game_setup_struct.cpp
engines/ags/shared/ac/game_setup_struct.h
engines/ags/shared/ac/game_setup_struct_base.cpp
engines/ags/shared/ac/game_setup_struct_base.h
engines/ags/shared/game/main_game_file.cpp
diff --git a/engines/ags/engine/ac/game_state.cpp b/engines/ags/engine/ac/game_state.cpp
index 641341b7ead..9ac84747603 100644
--- a/engines/ags/engine/ac/game_state.cpp
+++ b/engines/ags/engine/ac/game_state.cpp
@@ -409,8 +409,9 @@ bool GameState::ShouldPlayVoiceSpeech() const {
(_GP(play).speech_mode != kSpeech_TextOnly) && (_GP(play).voice_avail);
}
-void GameState::ReadFromSavegame(Shared::Stream *in, GameStateSvgVersion svg_ver, RestoredData &r_data) {
+void GameState::ReadFromSavegame(Shared::Stream *in, GameDataVersion data_ver, GameStateSvgVersion svg_ver, RestoredData &r_data) {
const bool old_save = svg_ver < kGSSvgVersion_Initial;
+ const bool extended_old_save = old_save && (data_ver >= kGameVersion_340_4);
score = in->ReadInt32();
usedmode = in->ReadInt32();
disabled_user_interface = in->ReadInt32();
@@ -568,7 +569,7 @@ void GameState::ReadFromSavegame(Shared::Stream *in, GameStateSvgVersion svg_ver
rtint_blue = in->ReadInt32();
rtint_level = in->ReadInt32();
rtint_light = in->ReadInt32();
- if (!old_save || _G(loaded_game_file_version) >= kGameVersion_340_4)
+ if (!old_save || extended_old_save)
rtint_enabled = in->ReadBool();
else
rtint_enabled = rtint_level > 0;
@@ -850,8 +851,8 @@ void GameState::FreeViewportsAndCameras() {
_scCameraHandles.clear();
}
-void GameState::ReadCustomProperties_v340(Shared::Stream *in) {
- if (_G(loaded_game_file_version) >= kGameVersion_340_4) {
+void GameState::ReadCustomProperties_v340(Shared::Stream *in, GameDataVersion data_ver) {
+ if (data_ver >= kGameVersion_340_4) {
// After runtime property values were read we also copy missing default,
// because we do not keep defaults in the saved game, and also in case
// this save is made by an older game version which had different
@@ -863,8 +864,8 @@ void GameState::ReadCustomProperties_v340(Shared::Stream *in) {
}
}
-void GameState::WriteCustomProperties_v340(Shared::Stream *out) const {
- if (_G(loaded_game_file_version) >= kGameVersion_340_4) {
+void GameState::WriteCustomProperties_v340(Shared::Stream *out, GameDataVersion data_ver) const {
+ if (data_ver >= kGameVersion_340_4) {
// We temporarily remove properties that kept default values
// just for the saving data time to avoid getting lots of
// redundant data into saved games
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index 95591f24172..5f07e2326b5 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -385,9 +385,9 @@ struct GameState {
// Serialization
//
void ReadQueuedAudioItems_Aligned(Shared::Stream *in);
- void ReadCustomProperties_v340(Shared::Stream *in);
- void WriteCustomProperties_v340(Shared::Stream *out) const;
- void ReadFromSavegame(Shared::Stream *in, GameStateSvgVersion svg_ver, AGS::Engine::RestoredData &r_data);
+ void ReadCustomProperties_v340(Shared::Stream *in, GameDataVersion data_ver);
+ void WriteCustomProperties_v340(Shared::Stream *out, GameDataVersion data_ver) const;
+ void ReadFromSavegame(Shared::Stream *in, GameDataVersion data_ver, GameStateSvgVersion svg_ver, AGS::Engine::RestoredData &r_data);
void WriteForSavegame(Shared::Stream *out) const;
void FreeProperties();
void FreeViewportsAndCameras();
diff --git a/engines/ags/engine/ac/room_status.cpp b/engines/ags/engine/ac/room_status.cpp
index 47ee11312b8..7ca2d283a18 100644
--- a/engines/ags/engine/ac/room_status.cpp
+++ b/engines/ags/engine/ac/room_status.cpp
@@ -71,7 +71,7 @@ void RoomStatus::FreeProperties() {
objProps.clear();
}
-void RoomStatus::ReadFromFile_v321(Stream *in) {
+void RoomStatus::ReadFromFile_v321(Stream *in, GameDataVersion data_ver) {
FreeScriptData();
FreeProperties();
@@ -103,7 +103,7 @@ void RoomStatus::ReadFromFile_v321(Stream *in) {
in->ReadArrayOfInt16(walkbehind_base, MAX_WALK_BEHINDS);
in->ReadArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
- if (_G(loaded_game_file_version) >= kGameVersion_340_4) {
+ if (data_ver >= kGameVersion_340_4) {
Properties::ReadValues(roomProps, in);
for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
Properties::ReadValues(hsProps[i], in);
@@ -122,7 +122,7 @@ void RoomStatus::ReadRoomObjects_Aligned(Shared::Stream *in) {
}
}
-void RoomStatus::ReadFromSavegame(Stream *in, RoomStatSvgVersion save_ver) {
+void RoomStatus::ReadFromSavegame(Stream *in, GameDataVersion data_ver, RoomStatSvgVersion save_ver) {
FreeScriptData();
FreeProperties();
@@ -134,18 +134,18 @@ void RoomStatus::ReadFromSavegame(Stream *in, RoomStatSvgVersion save_ver) {
for (uint32_t i = 0; i < numobj; ++i) {
obj[i].ReadFromSavegame(in, save_ver);
Properties::ReadValues(objProps[i], in);
- if (_G(loaded_game_file_version) <= kGameVersion_272)
+ if (data_ver <= kGameVersion_272)
SavegameComponents::ReadInteraction272(intrObject[i], in);
}
for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
hotspot[i].ReadFromSavegame(in, save_ver);
Properties::ReadValues(hsProps[i], in);
- if (_G(loaded_game_file_version) <= kGameVersion_272)
+ if (data_ver <= kGameVersion_272)
SavegameComponents::ReadInteraction272(intrHotspot[i], in);
}
for (int i = 0; i < MAX_ROOM_REGIONS; ++i) {
region_enabled[i] = in->ReadInt8();
- if (_G(loaded_game_file_version) <= kGameVersion_272)
+ if (data_ver <= kGameVersion_272)
SavegameComponents::ReadInteraction272(intrRegion[i], in);
}
for (int i = 0; i < MAX_WALK_BEHINDS; ++i) {
@@ -153,7 +153,7 @@ void RoomStatus::ReadFromSavegame(Stream *in, RoomStatSvgVersion save_ver) {
}
Properties::ReadValues(roomProps, in);
- if (_G(loaded_game_file_version) <= kGameVersion_272) {
+ if (data_ver <= kGameVersion_272) {
SavegameComponents::ReadInteraction272(intrRoom, in);
in->ReadArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
}
@@ -173,24 +173,24 @@ void RoomStatus::ReadFromSavegame(Stream *in, RoomStatSvgVersion save_ver) {
}
}
-void RoomStatus::WriteToSavegame(Stream *out) const {
+void RoomStatus::WriteToSavegame(Stream *out, GameDataVersion data_ver) const {
out->WriteInt8(beenhere);
out->WriteInt32(numobj);
for (uint32_t i = 0; i < numobj; ++i) {
obj[i].WriteToSavegame(out);
Properties::WriteValues(objProps[i], out);
- if (_G(loaded_game_file_version) <= kGameVersion_272)
+ if (data_ver <= kGameVersion_272)
SavegameComponents::WriteInteraction272(intrObject[i], out);
}
for (int i = 0; i < MAX_ROOM_HOTSPOTS; ++i) {
hotspot[i].WriteToSavegame(out);
Properties::WriteValues(hsProps[i], out);
- if (_G(loaded_game_file_version) <= kGameVersion_272)
+ if (data_ver <= kGameVersion_272)
SavegameComponents::WriteInteraction272(intrHotspot[i], out);
}
for (int i = 0; i < MAX_ROOM_REGIONS; ++i) {
out->WriteInt8(region_enabled[i]);
- if (_G(loaded_game_file_version) <= kGameVersion_272)
+ if (data_ver <= kGameVersion_272)
SavegameComponents::WriteInteraction272(intrRegion[i], out);
}
for (int i = 0; i < MAX_WALK_BEHINDS; ++i) {
@@ -198,7 +198,7 @@ void RoomStatus::WriteToSavegame(Stream *out) const {
}
Properties::WriteValues(roomProps, out);
- if (_G(loaded_game_file_version) <= kGameVersion_272) {
+ if (data_ver <= kGameVersion_272) {
SavegameComponents::WriteInteraction272(intrRoom, out);
out->WriteArrayOfInt32(interactionVariableValues, MAX_GLOBAL_VARIABLES);
}
diff --git a/engines/ags/engine/ac/room_status.h b/engines/ags/engine/ac/room_status.h
index 2df4b7567d0..0d1c5cc0656 100644
--- a/engines/ags/engine/ac/room_status.h
+++ b/engines/ags/engine/ac/room_status.h
@@ -98,10 +98,10 @@ struct RoomStatus {
void FreeScriptData();
void FreeProperties();
- void ReadFromFile_v321(Shared::Stream *in);
+ void ReadFromFile_v321(Shared::Stream *in, GameDataVersion data_ver);
void ReadRoomObjects_Aligned(Shared::Stream *in);
- void ReadFromSavegame(Shared::Stream *in, RoomStatSvgVersion save_ver);
- void WriteToSavegame(Shared::Stream *out) const;
+ void ReadFromSavegame(Shared::Stream *in, GameDataVersion data_ver, RoomStatSvgVersion save_ver);
+ void WriteToSavegame(Shared::Stream *out, GameDataVersion data_ver) const;
};
// Replaces all accesses to the roomstats array
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 7345993e1a4..48b199248fc 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -73,7 +73,7 @@ using namespace Shared;
using namespace Engine;
// function is currently implemented in savegame_v321.cpp
-HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, RestoredData &r_data);
+HSaveError restore_save_data_v321(Stream *in, GameDataVersion data_ver, const PreservedParams &pp, RestoredData &r_data);
namespace AGS {
namespace Engine {
@@ -656,7 +656,7 @@ HSaveError RestoreGameState(Stream *in, SavegameVersion svg_version) {
if (svg_version >= kSvgVersion_Components)
err = SavegameComponents::ReadAll(in, svg_version, pp, r_data);
else
- err = restore_save_data_v321(in, pp, r_data);
+ err = restore_save_data_v321(in, _G(loaded_game_file_version), pp, r_data);
if (!err)
return err;
return DoAfterRestore(pp, r_data);
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 02e4d5e524c..ccbe7edad1c 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -292,7 +292,7 @@ HSaveError ReadGameState(Stream *in, int32_t cmp_ver, const PreservedParams & /*
}
// Game state
- _GP(play).ReadFromSavegame(in, svg_ver, r_data);
+ _GP(play).ReadFromSavegame(in, _G(loaded_game_file_version), svg_ver, r_data);
// Other dynamic values
r_data.FPS = in->ReadInt32();
@@ -863,7 +863,7 @@ HSaveError WriteRoomStates(Stream *out) {
if (roomstat->beenhere) {
out->WriteInt32(i);
WriteFormatTag(out, "RoomState", true);
- roomstat->WriteToSavegame(out);
+ roomstat->WriteToSavegame(out, _G(loaded_game_file_version));
WriteFormatTag(out, "RoomState", false);
} else
out->WriteInt32(-1);
@@ -885,7 +885,7 @@ HSaveError ReadRoomStates(Stream *in, int32_t cmp_ver, const PreservedParams & /
if (!AssertFormatTagStrict(err, in, "RoomState", true))
return err;
RoomStatus *roomstat = getRoomStatus(id);
- roomstat->ReadFromSavegame(in, (RoomStatSvgVersion)cmp_ver);
+ roomstat->ReadFromSavegame(in, _G(loaded_game_file_version), (RoomStatSvgVersion)cmp_ver);
if (!AssertFormatTagStrict(err, in, "RoomState", false))
return err;
}
@@ -933,7 +933,7 @@ HSaveError WriteThisRoom(Stream *out) {
out->WriteBool(persist);
// write the current troom state, in case they save in temporary room
if (!persist)
- _GP(troom).WriteToSavegame(out);
+ _GP(troom).WriteToSavegame(out, _G(loaded_game_file_version));
return HSaveError::None();
}
@@ -979,7 +979,7 @@ HSaveError ReadThisRoom(Stream *in, int32_t cmp_ver, const PreservedParams & /*p
// read the current troom state, in case they saved in temporary room
if (!in->ReadBool())
- _GP(troom).ReadFromSavegame(in, (RoomStatSvgVersion)cmp_ver);
+ _GP(troom).ReadFromSavegame(in, _G(loaded_game_file_version), (RoomStatSvgVersion)cmp_ver);
return HSaveError::None();
}
diff --git a/engines/ags/engine/game/savegame_v321.cpp b/engines/ags/engine/game/savegame_v321.cpp
index 31f4a6b75a8..3be8887ffc0 100644
--- a/engines/ags/engine/game/savegame_v321.cpp
+++ b/engines/ags/engine/game/savegame_v321.cpp
@@ -115,27 +115,23 @@ static HSaveError restore_game_scripts(Stream *in, const PreservedParams &pp, Re
return HSaveError::None();
}
-static void ReadRoomStatus_Aligned(RoomStatus *roomstat, Stream *in) {
+static void ReadRoomStatus_Aligned(RoomStatus *roomstat, Stream *in, GameDataVersion data_ver) {
AlignedStream align_s(in, Shared::kAligned_Read);
- roomstat->ReadFromFile_v321(&align_s);
+ roomstat->ReadFromFile_v321(&align_s, data_ver);
}
-static void restore_game_room_state(Stream *in) {
- int vv;
-
+static void restore_game_room_state(Stream *in, GameDataVersion data_ver) {
_G(displayed_room) = in->ReadInt32();
// read the room state for all the rooms the player has been in
- RoomStatus *roomstat;
- int beenhere;
- for (vv = 0; vv < MAX_ROOMS; vv++) {
- beenhere = in->ReadByte();
+ for (int vv = 0; vv < MAX_ROOMS; vv++) {
+ int beenhere = in->ReadByte();
if (beenhere) {
- roomstat = getRoomStatus(vv);
+ RoomStatus *roomstat = getRoomStatus(vv);
roomstat->beenhere = beenhere;
if (roomstat->beenhere) {
- ReadRoomStatus_Aligned(roomstat, in);
+ ReadRoomStatus_Aligned(roomstat, in, data_ver);
if (roomstat->tsdatasize > 0) {
roomstat->tsdata.resize(roomstat->tsdatasize);
in->Read(roomstat->tsdata.data(), roomstat->tsdatasize);
@@ -145,9 +141,9 @@ static void restore_game_room_state(Stream *in) {
}
}
-static void ReadGameState_Aligned(Stream *in, RestoredData &r_data) {
+static void ReadGameState_Aligned(Stream *in, GameDataVersion data_ver, RestoredData &r_data) {
AlignedStream align_s(in, Shared::kAligned_Read);
- _GP(play).ReadFromSavegame(&align_s, kGSSvgVersion_OldFormat, r_data);
+ _GP(play).ReadFromSavegame(&align_s, data_ver, kGSSvgVersion_OldFormat, r_data);
}
static void restore_game_play_ex_data(Stream *in) {
@@ -160,11 +156,11 @@ static void restore_game_play_ex_data(Stream *in) {
in->Seek(_GP(game).numgui * sizeof(int32_t)); // gui_draw_order
}
-static void restore_game_play(Stream *in, RestoredData &r_data) {
+static void restore_game_play(Stream *in, GameDataVersion data_ver, RestoredData &r_data) {
int screenfadedout_was = _GP(play).screen_is_faded_out;
int roomchanges_was = _GP(play).room_changes;
- ReadGameState_Aligned(in, r_data);
+ ReadGameState_Aligned(in, data_ver, r_data);
r_data.Cameras[0].Flags = r_data.Camera0_Flags;
_GP(play).screen_is_faded_out = screenfadedout_was;
@@ -181,9 +177,9 @@ static void ReadMoveList_Aligned(Stream *in) {
}
}
-static void ReadGameSetupStructBase_Aligned(Stream *in) {
+static void ReadGameSetupStructBase_Aligned(Stream *in, GameDataVersion data_ver) {
AlignedStream align_s(in, Shared::kAligned_Read);
- _GP(game).GameSetupStructBase::ReadFromFile(&align_s);
+ _GP(game).GameSetupStructBase::ReadFromFile(&align_s, data_ver);
}
static void ReadCharacterExtras_Aligned(Stream *in) {
@@ -305,7 +301,7 @@ static void restore_game_dynamic_surfaces(Stream *in, RestoredData &r_data) {
}
}
-static void restore_game_displayed_room_status(Stream *in, RestoredData &r_data) {
+static void restore_game_displayed_room_status(Stream *in, GameDataVersion data_ver, RestoredData &r_data) {
int bb;
for (bb = 0; bb < MAX_ROOM_BGFRAMES; bb++)
r_data.RoomBkgScene[bb].reset();
@@ -324,7 +320,7 @@ static void restore_game_displayed_room_status(Stream *in, RestoredData &r_data)
_G(raw_saved_screen) = read_serialized_bitmap(in);
// get the current troom, in case they save in room 600 or whatever
- ReadRoomStatus_Aligned(&_GP(troom), in);
+ ReadRoomStatus_Aligned(&_GP(troom), in, data_ver);
if (_GP(troom).tsdatasize > 0) {
_GP(troom).tsdata.resize(_GP(troom).tsdatasize);
@@ -361,7 +357,7 @@ static HSaveError restore_game_views(Stream *in) {
return HSaveError::None();
}
-static HSaveError restore_game_audioclips_and_crossfade(Stream *in, RestoredData &r_data) {
+static HSaveError restore_game_audioclips_and_crossfade(Stream *in, GameDataVersion data_ver, RestoredData &r_data) {
if ((uint32_t)in->ReadInt32() != _GP(game).audioClips.size()) {
return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Audio Clips.");
}
@@ -385,7 +381,7 @@ static HSaveError restore_game_audioclips_and_crossfade(Stream *in, RestoredData
chan_info.VolAsPercent = in->ReadInt32();
chan_info.Pan = in->ReadInt32();
chan_info.Speed = 1000;
- if (_G(loaded_game_file_version) >= kGameVersion_340_2)
+ if (data_ver >= kGameVersion_340_2)
chan_info.Speed = in->ReadInt32();
}
}
@@ -396,7 +392,7 @@ static HSaveError restore_game_audioclips_and_crossfade(Stream *in, RestoredData
return HSaveError::None();
}
-HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, RestoredData &r_data) {
+HSaveError restore_save_data_v321(Stream *in, GameDataVersion data_ver, const PreservedParams &pp, RestoredData &r_data) {
HSaveError err = restore_game_head_dynamic_values(in, r_data);
if (!err)
return err;
@@ -405,8 +401,8 @@ HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, Restore
err = restore_game_scripts(in, pp, r_data);
if (!err)
return err;
- restore_game_room_state(in);
- restore_game_play(in, r_data);
+ restore_game_room_state(in, data_ver);
+ restore_game_play(in, data_ver, r_data);
ReadMoveList_Aligned(in);
// save pointer members before reading
@@ -423,7 +419,7 @@ HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, Restore
int numviewswas = _GP(game).numviews;
int numGuisWas = _GP(game).numgui;
- ReadGameSetupStructBase_Aligned(in);
+ ReadGameSetupStructBase_Aligned(in, data_ver);
// Delete unneeded data
// TODO: reorganize this (may be solved by optimizing safe format too)
@@ -443,10 +439,10 @@ HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, Restore
return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Views.");
}
- _GP(game).ReadFromSaveGame_v321(in, gswas, compsc, chwas, olddict, mesbk);
+ _GP(game).ReadFromSaveGame_v321(in, data_ver, gswas, compsc, chwas, olddict, mesbk);
// Modified custom properties are read separately to keep existing save format
- _GP(play).ReadCustomProperties_v340(in);
+ _GP(play).ReadCustomProperties_v340(in, data_ver);
ReadCharacterExtras_Aligned(in);
restore_game_palette(in);
@@ -462,7 +458,7 @@ HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, Restore
restore_game_ambientsounds(in, r_data);
restore_game_overlays(in);
restore_game_dynamic_surfaces(in, r_data);
- restore_game_displayed_room_status(in, r_data);
+ restore_game_displayed_room_status(in, data_ver, r_data);
err = restore_game_globalvars(in);
if (!err)
return err;
@@ -474,7 +470,7 @@ HSaveError restore_save_data_v321(Stream *in, const PreservedParams &pp, Restore
return new SavegameError(kSvgErr_InconsistentFormat, "MAGICNUMBER not found before Audio Clips.");
}
- err = restore_game_audioclips_and_crossfade(in, r_data);
+ err = restore_game_audioclips_and_crossfade(in, data_ver, r_data);
if (!err)
return err;
diff --git a/engines/ags/shared/ac/game_setup_struct.cpp b/engines/ags/shared/ac/game_setup_struct.cpp
index fa56c19947d..ec3eb66fd21 100644
--- a/engines/ags/shared/ac/game_setup_struct.cpp
+++ b/engines/ags/shared/ac/game_setup_struct.cpp
@@ -343,12 +343,12 @@ void GameSetupStruct::ReadAudioClips_Aligned(Shared::Stream *in, size_t count) {
}
}
-void GameSetupStruct::ReadFromSaveGame_v321(Stream *in, char *gswas, ccScript *compsc, CharacterInfo *chwas,
+void GameSetupStruct::ReadFromSaveGame_v321(Stream *in, GameDataVersion data_ver, char *gswas, ccScript *compsc, CharacterInfo *chwas,
WordsDictionary *olddict, std::vector<String> &mesbk) {
ReadInvInfo_Aligned(in);
ReadMouseCursors_Aligned(in);
- if (_G(loaded_game_file_version) <= kGameVersion_272) {
+ if (data_ver <= kGameVersion_272) {
for (int i = 0; i < numinvitems; ++i)
intrInv[i]->ReadTimesRunFromSave_v321(in);
for (int i = 0; i < numcharacters; ++i)
diff --git a/engines/ags/shared/ac/game_setup_struct.h b/engines/ags/shared/ac/game_setup_struct.h
index 8518fa96f9c..31adfa497c1 100644
--- a/engines/ags/shared/ac/game_setup_struct.h
+++ b/engines/ags/shared/ac/game_setup_struct.h
@@ -159,7 +159,7 @@ struct GameSetupStruct : public GameSetupStructBase {
//--------------------------------------------------------------------
// Functions for reading and writing appropriate data from/to save game
- void ReadFromSaveGame_v321(Shared::Stream *in, char *gswas, ccScript *compsc, CharacterInfo *chwas,
+ void ReadFromSaveGame_v321(Shared::Stream *in, GameDataVersion data_ver, char *gswas, ccScript *compsc, CharacterInfo *chwas,
WordsDictionary *olddict, std::vector<String> &mesbk);
void ReadFromSavegame(Shared::Stream *in);
diff --git a/engines/ags/shared/ac/game_setup_struct_base.cpp b/engines/ags/shared/ac/game_setup_struct_base.cpp
index 4fd318a0d14..6d79add7151 100644
--- a/engines/ags/shared/ac/game_setup_struct_base.cpp
+++ b/engines/ags/shared/ac/game_setup_struct_base.cpp
@@ -142,17 +142,17 @@ void GameSetupStructBase::OnResolutionSet() {
_relativeUIMult = IsLegacyHiRes() ? HIRES_COORD_MULTIPLIER : 1;
}
-void GameSetupStructBase::ReadFromFile(Stream *in) {
+void GameSetupStructBase::ReadFromFile(Stream *in, GameDataVersion game_ver) {
in->Read(&gamename[0], GAME_NAME_LENGTH);
in->ReadArrayOfInt32(options, MAX_OPTIONS);
- if (_G(loaded_game_file_version) < kGameVersion_340_4) { // TODO: this should probably be possible to deduce script API level
+ if (game_ver < kGameVersion_340_4) { // TODO: this should probably be possible to deduce script API level
// using game data version and other options like OPT_STRICTSCRIPTING
options[OPT_BASESCRIPTAPI] = kScriptAPI_Undefined;
options[OPT_SCRIPTCOMPATLEV] = kScriptAPI_Undefined;
}
- in->Read(&paluses[0], 256);
+ in->Read(&paluses[0], sizeof(paluses));
// colors are an array of chars
- in->Read(&defpal[0], sizeof(RGB) * 256);
+ in->Read(&defpal[0], sizeof(defpal));
numviews = in->ReadInt32();
numcharacters = in->ReadInt32();
playercharacter = in->ReadInt32();
@@ -171,7 +171,7 @@ void GameSetupStructBase::ReadFromFile(Stream *in) {
numcursors = in->ReadInt32();
GameResolutionType resolution_type = (GameResolutionType)in->ReadInt32();
Size game_size;
- if (resolution_type == kGameResolution_Custom && _G(loaded_game_file_version) >= kGameVersion_330) {
+ if (resolution_type == kGameResolution_Custom && game_ver >= kGameVersion_330) {
game_size.Width = in->ReadInt32();
game_size.Height = in->ReadInt32();
}
@@ -191,12 +191,12 @@ void GameSetupStructBase::ReadFromFile(Stream *in) {
load_compiled_script = in->ReadInt32() != 0;
}
-void GameSetupStructBase::WriteToFile(Stream *out) {
- out->Write(&gamename[0], 50);
- out->WriteArrayOfInt32(options, 100);
- out->Write(&paluses[0], 256);
+void GameSetupStructBase::WriteToFile(Stream *out) const {
+ out->Write(&gamename[0], GAME_NAME_LENGTH);
+ out->WriteArrayOfInt32(options, MAX_OPTIONS);
+ out->Write(&paluses[0], sizeof(paluses));
// colors are an array of chars
- out->Write(&defpal[0], sizeof(RGB) * 256);
+ out->Write(&defpal[0], sizeof(defpal));
out->WriteInt32(numviews);
out->WriteInt32(numcharacters);
out->WriteInt32(playercharacter);
@@ -266,7 +266,7 @@ const char *GetScriptAPIName(ScriptAPIVersion v) {
case kScriptAPI_v360: return "v3.6.0-alpha";
case kScriptAPI_v36026: return "v3.6.0-final";
default: return "unknown";
- }
+ }
}
} // namespace AGS3
diff --git a/engines/ags/shared/ac/game_setup_struct_base.h b/engines/ags/shared/ac/game_setup_struct_base.h
index 0a23078aa9a..30501e96476 100644
--- a/engines/ags/shared/ac/game_setup_struct_base.h
+++ b/engines/ags/shared/ac/game_setup_struct_base.h
@@ -92,9 +92,8 @@ struct GameSetupStructBase {
void SetDefaultResolution(Size game_res);
void SetGameResolution(GameResolutionType type);
void SetGameResolution(Size game_res);
- void ReadFromFile(Shared::Stream *in);
- void WriteToFile(Shared::Stream *out);
-
+ void ReadFromFile(Shared::Stream *in, GameDataVersion game_ver);
+ void WriteToFile(Shared::Stream *out) const;
//
// ** On game resolution.
diff --git a/engines/ags/shared/game/main_game_file.cpp b/engines/ags/shared/game/main_game_file.cpp
index d933390479d..f827e815f52 100644
--- a/engines/ags/shared/game/main_game_file.cpp
+++ b/engines/ags/shared/game/main_game_file.cpp
@@ -750,7 +750,7 @@ HGameFileError ReadGameData(LoadedGameEntities &ents, Stream *in, GameDataVersio
//-------------------------------------------------------------------------
{
AlignedStream align_s(in, Shared::kAligned_Read);
- game.GameSetupStructBase::ReadFromFile(&align_s);
+ game.GameSetupStructBase::ReadFromFile(&align_s, data_ver);
}
Debug::Printf(kDbgMsg_Info, "Game title: '%s'", game.gamename);
@@ -859,7 +859,7 @@ HGameFileError UpdateGameData(LoadedGameEntities &ents, GameDataVersion data_ver
void PreReadGameData(GameSetupStruct &game, Stream *in, GameDataVersion data_ver) {
{
AlignedStream align_s(in, Shared::kAligned_Read);
- _GP(game).ReadFromFile(&align_s);
+ _GP(game).ReadFromFile(&align_s, data_ver);
}
// Discard game messages we do not need here
delete[] _GP(game).load_messages;
Commit: cca0be77a1530331ff04dc2fa83d2e57a879691b
https://github.com/scummvm/scummvm/commit/cca0be77a1530331ff04dc2fa83d2e57a879691b
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T13:23:59+02:00
Commit Message:
AGS: Engine: a config hint to assume data version when reading a legacy save
I did a terribly stupid mistake when was expanding the old save format in the
past (in pre-3.5.0 engines). Instead of checking for the save format,
I've been checking for the game's data format.
This causes following problem: if a game made in a particular range of versions
(something like 3.2.1 to 3.4.4) gets upgraded to a newer version (say 3.6.0),
then all the old saves made in a pre-3.5.0 game version will not load correctly,
as they are relying on the new compiled game data format.
Unfortunately there's no *proper* way to fix this, as the old save format
had been in use for years, nothing can be done about it.
Hence the workaround that I may think of is to provide a config hint,
that would tell the engine: whenever you load a legacy save format,
assume that it was written by a game of particular data version.
>From upstream 0a2a0177dd8eaad817b39905bf0471663c431f96
Changed paths:
engines/ags/engine/ac/game_setup.h
engines/ags/engine/game/savegame.cpp
engines/ags/engine/main/config.cpp
diff --git a/engines/ags/engine/ac/game_setup.h b/engines/ags/engine/ac/game_setup.h
index e772ae06667..f5b58c86309 100644
--- a/engines/ags/engine/ac/game_setup.h
+++ b/engines/ags/engine/ac/game_setup.h
@@ -23,6 +23,7 @@
#define AGS_ENGINE_AC_GAME_SETUP_H
#include "ags/engine/main/graphics_mode.h"
+#include "ags/shared/ac/game_version.h"
#include "ags/shared/util/string.h"
namespace AGS3 {
@@ -101,7 +102,8 @@ struct GameSetup {
int override_script_os; // pretend engine is running on this eScriptSystemOSID
char override_multitasking; // -1 for none, 0 or 1 to lock in the on/off mode
bool override_upscale; // whether upscale old games that supported that
-
+ // assume game data version when restoring legacy save format
+ GameDataVersion dataver_for_legacysavs = kGameVersion_Undefined;
// Optional keys for calling built-in save/restore dialogs;
// primarily meant for the test runs of the games where save functionality
// is not implemented (or does not work correctly).
diff --git a/engines/ags/engine/game/savegame.cpp b/engines/ags/engine/game/savegame.cpp
index 48b199248fc..c55b35c9e64 100644
--- a/engines/ags/engine/game/savegame.cpp
+++ b/engines/ags/engine/game/savegame.cpp
@@ -653,10 +653,13 @@ HSaveError RestoreGameState(Stream *in, SavegameVersion svg_version) {
RestoredData r_data;
DoBeforeRestore(pp);
HSaveError err;
- if (svg_version >= kSvgVersion_Components)
+ if (svg_version >= kSvgVersion_Components) {
err = SavegameComponents::ReadAll(in, svg_version, pp, r_data);
- else
- err = restore_save_data_v321(in, _G(loaded_game_file_version), pp, r_data);
+ } else {
+ GameDataVersion use_dataver = _GP(usetup).dataver_for_legacysavs != kGameVersion_Undefined ? _GP(usetup).dataver_for_legacysavs
+ : _G(loaded_game_file_version);
+ err = restore_save_data_v321(in, use_dataver, pp, r_data);
+ }
if (!err)
return err;
return DoAfterRestore(pp, r_data);
diff --git a/engines/ags/engine/main/config.cpp b/engines/ags/engine/main/config.cpp
index 3b0b3e7300f..0365d673eb4 100644
--- a/engines/ags/engine/main/config.cpp
+++ b/engines/ags/engine/main/config.cpp
@@ -370,6 +370,7 @@ void apply_config(const ConfigTree &cfg) {
_GP(usetup).override_script_os = eOS_Mac;
}
_GP(usetup).override_upscale = CfgReadBoolInt(cfg, "override", "upscale", _GP(usetup).override_upscale);
+ _GP(usetup).dataver_for_legacysavs = static_cast<GameDataVersion>(CfgReadInt(cfg, "override", "dataver_for_legacysaves", kGameVersion_Undefined));
_GP(usetup).key_save_game = CfgReadInt(cfg, "override", "save_game_key", 0);
_GP(usetup).key_restore_game = CfgReadInt(cfg, "override", "restore_game_key", 0);
}
Commit: 7cd860207dabce3d9a85c318ae7049b45e815d6f
https://github.com/scummvm/scummvm/commit/7cd860207dabce3d9a85c318ae7049b45e815d6f
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T13:23:59+02:00
Commit Message:
AGS: Engine: add object and char assertions in Get/SetProperty functions
Since older commit 5f3b8eb the properties are stored in vectors,
strictly resized to the number of characters and objects.
But the script functions that access these do not do any assertion
whether the object or char is valid, which could cause bad mem
access in case script loops over a array of objects of MAX_OBJECTS
size, or tries to access something using Object* pointer from another room.
>From upstream 6ad4b220d75a32ea8df959e9a7b7f1ecb21d0c26
Changed paths:
engines/ags/engine/ac/character.cpp
engines/ags/engine/ac/character.h
engines/ags/engine/ac/global_object.cpp
engines/ags/engine/ac/object.cpp
engines/ags/engine/ac/object.h
diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index f08009a5358..2d30af01232 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -78,6 +78,17 @@ namespace AGS3 {
using namespace AGS::Shared;
+bool is_valid_character(int char_id) {
+ return ((char_id >= 0) && (char_id < _GP(game).numcharacters));
+}
+
+bool AssertCharacter(const char *apiname, int char_id) {
+ if ((char_id >= 0) && (char_id < _GP(game).numcharacters))
+ return true;
+ debug_script_warn("%s: invalid character id %d (range is 0..%d)", apiname, char_id, _GP(game).numcharacters - 1);
+ return false;
+}
+
void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addIndex) {
int ee;
@@ -984,22 +995,32 @@ void Character_RunInteraction(CharacterInfo *chaa, int mood) {
// **** CHARACTER: PROPERTIES ****
int Character_GetProperty(CharacterInfo *chaa, const char *property) {
-
+ if (!AssertCharacter("Character.GetProperty", chaa->index_id))
+ return 0;
return get_int_property(_GP(game).charProps[chaa->index_id], _GP(play).charProps[chaa->index_id], property);
-
}
+
void Character_GetPropertyText(CharacterInfo *chaa, const char *property, char *bufer) {
+ if (!AssertCharacter("Character.GetPropertyText", chaa->index_id))
+ return;
get_text_property(_GP(game).charProps[chaa->index_id], _GP(play).charProps[chaa->index_id], property, bufer);
}
+
const char *Character_GetTextProperty(CharacterInfo *chaa, const char *property) {
+ if (!AssertCharacter("Character.GetTextProperty", chaa->index_id))
+ return nullptr;
return get_text_property_dynamic_string(_GP(game).charProps[chaa->index_id], _GP(play).charProps[chaa->index_id], property);
}
bool Character_SetProperty(CharacterInfo *chaa, const char *property, int value) {
+ if (!AssertCharacter("Character.SetProperty", chaa->index_id))
+ return false;
return set_int_property(_GP(play).charProps[chaa->index_id], property, value);
}
bool Character_SetTextProperty(CharacterInfo *chaa, const char *property, const char *value) {
+ if (!AssertCharacter("Character.SetTextProperty", chaa->index_id))
+ return false;
return set_text_property(_GP(play).charProps[chaa->index_id], property, value);
}
@@ -1930,11 +1951,6 @@ void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int
}
-int is_valid_character(int newchar) {
- if ((newchar < 0) || (newchar >= _GP(game).numcharacters)) return 0;
- return 1;
-}
-
int wantMoveNow(CharacterInfo *chi, CharacterExtras *chex) {
// check most likely case first
if ((chex->zoom == 100) || ((chi->flags & CHF_SCALEMOVESPEED) == 0))
diff --git a/engines/ags/engine/ac/character.h b/engines/ags/engine/ac/character.h
index 61e52bb963c..7c6c589edc3 100644
--- a/engines/ags/engine/ac/character.h
+++ b/engines/ags/engine/ac/character.h
@@ -34,6 +34,11 @@ namespace AGS3 {
// **** CHARACTER: FUNCTIONS ****
+bool is_valid_character(int char_id);
+// Asserts the character ID is valid,
+// if not then prints a warning to the log; returns assertion result
+bool AssertCharacter(const char *apiname, int char_id);
+
void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addIndex);
void Character_AddWaypoint(CharacterInfo *chaa, int x, int y);
void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction);
@@ -199,7 +204,6 @@ int find_nearest_walkable_area_within(int *xx, int *yy, int range, int step);
void find_nearest_walkable_area(int *xx, int *yy);
void FindReasonableLoopForCharacter(CharacterInfo *chap);
void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int direct, bool isWalk);
-int is_valid_character(int newchar);
int wantMoveNow(CharacterInfo *chi, CharacterExtras *chex);
void setup_player_character(int charid);
void CheckViewFrameForCharacter(CharacterInfo *chi);
diff --git a/engines/ags/engine/ac/global_object.cpp b/engines/ags/engine/ac/global_object.cpp
index 6480b661eb2..bc3e927f3f5 100644
--- a/engines/ags/engine/ac/global_object.cpp
+++ b/engines/ags/engine/ac/global_object.cpp
@@ -534,6 +534,8 @@ int GetObjectProperty(int hss, const char *property) {
}
void GetObjectPropertyText(int item, const char *property, char *bufer) {
+ if (!AssertObject("GetObjectPropertyText", item))
+ return;
get_text_property(_GP(thisroom).Objects[item].Properties, _G(croom)->objProps[item], property, bufer);
}
diff --git a/engines/ags/engine/ac/object.cpp b/engines/ags/engine/ac/object.cpp
index c91b4b8f4b3..7a5cc0341d4 100644
--- a/engines/ags/engine/ac/object.cpp
+++ b/engines/ags/engine/ac/object.cpp
@@ -56,6 +56,17 @@ namespace AGS3 {
using namespace AGS::Shared;
+AGS_INLINE bool is_valid_object(int obj_id) {
+ return (obj_id >= 0) && (static_cast<uint32_t>(obj_id) < _G(croom)->numobj);
+}
+
+bool AssertObject(const char *apiname, int obj_id) {
+ if ((obj_id >= 0) && (static_cast<uint32_t>(obj_id) < _G(croom)->numobj))
+ return true;
+ debug_script_warn("%s: invalid object id %d (range is 0..%d)", apiname, obj_id, _G(croom)->numobj - 1);
+ return false;
+}
+
int Object_IsCollidingWithObject(ScriptObject *objj, ScriptObject *obj2) {
return AreObjectsColliding(objj->id, obj2->id);
}
@@ -74,11 +85,6 @@ ScriptObject *GetObjectAtRoom(int x, int y) {
return &_G(scrObj)[hsnum];
}
-AGS_INLINE int is_valid_object(int obtest) {
- if ((obtest < 0) || (static_cast<uint32_t>(obtest) >= _G(croom)->numobj)) return 0;
- return 1;
-}
-
void Object_Tint(ScriptObject *objj, int red, int green, int blue, int saturation, int luminance) {
SetObjectTint(objj->id, red, green, blue, saturation, luminance);
}
@@ -436,14 +442,20 @@ void Object_GetPropertyText(ScriptObject *objj, const char *property, char *bufe
}
const char *Object_GetTextProperty(ScriptObject *objj, const char *property) {
+ if (!AssertObject("Object.GetTextProperty", objj->id))
+ return nullptr;
return get_text_property_dynamic_string(_GP(thisroom).Objects[objj->id].Properties, _G(croom)->objProps[objj->id], property);
}
bool Object_SetProperty(ScriptObject *objj, const char *property, int value) {
+ if (!AssertObject("Object.SetProperty", objj->id))
+ return false;
return set_int_property(_G(croom)->objProps[objj->id], property, value);
}
bool Object_SetTextProperty(ScriptObject *objj, const char *property, const char *value) {
+ if (!AssertObject("Object.SetTextProperty", objj->id))
+ return false;
return set_text_property(_G(croom)->objProps[objj->id], property, value);
}
diff --git a/engines/ags/engine/ac/object.h b/engines/ags/engine/ac/object.h
index 1e38ce63817..7423ebf93c7 100644
--- a/engines/ags/engine/ac/object.h
+++ b/engines/ags/engine/ac/object.h
@@ -43,7 +43,10 @@ class Bitmap;
using namespace AGS; // FIXME later
-extern AGS_INLINE int is_valid_object(int obtest);
+extern AGS_INLINE bool is_valid_object(int obj_id);
+// Asserts the object ID is valid in the current room,
+// if not then prints a warning to the log; returns assertion result
+bool AssertObject(const char *apiname, int obj_id);
int Object_IsCollidingWithObject(ScriptObject *objj, ScriptObject *obj2);
ScriptObject *GetObjectAtScreen(int xx, int yy);
ScriptObject *GetObjectAtRoom(int x, int y);
Commit: 94a8518dd72d50cb02ce91e1c4ec81ff4376e4d7
https://github.com/scummvm/scummvm/commit/94a8518dd72d50cb02ce91e1c4ec81ff4376e4d7
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T14:02:10+02:00
Commit Message:
AGS: Engine: don't reset idle animation during speech with no speech view
This fixes idle animation getting reset to frame 0 at the blocking speech start
if there's no speech view set. In such case the idle anim is expected to continue
playing seamlessly.
From upstream 7b399933a291a05e868cd9589b02d83d05f33314
Changed paths:
engines/ags/engine/ac/character.cpp
diff --git a/engines/ags/engine/ac/character.cpp b/engines/ags/engine/ac/character.cpp
index 2d30af01232..27c81a96a9a 100644
--- a/engines/ags/engine/ac/character.cpp
+++ b/engines/ags/engine/ac/character.cpp
@@ -2390,10 +2390,9 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
if (_GP(game).options[OPT_SPEECHTYPE] == 0)
allowShrink = 1;
- if (speakingChar->idleleft < 0) {
- // if idle anim in progress for the character, stop it
+ // If has a valid speech view, and idle anim in progress for the character, then stop it
+ if (useview >= 0 && speakingChar->idleleft < 0) {
ReleaseCharacterView(aschar);
- // speakingChar->idleleft = speakingChar->idletime;
}
bool overlayPositionFixed = false;
@@ -2402,9 +2401,6 @@ void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int
if (speakingChar->flags & CHF_FIXVIEW)
viewWasLocked = 1;
- /*if ((speakingChar->room == _G(displayed_room)) ||
- ((useview >= 0) && (_GP(game).options[OPT_SPEECHTYPE] > 0)) ) {*/
-
if (speakingChar->room == _G(displayed_room)) {
// If the character is in this room, go for it - otherwise
// run the "else" clause which does text in the middle of
Commit: 4f069b677a175265813d44290e5afab201e5e013
https://github.com/scummvm/scummvm/commit/4f069b677a175265813d44290e5afab201e5e013
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T14:02:21+02:00
Commit Message:
AGS: Engine: fixed characters sometimes wait after moving before idle anim
Apparently "doing_nothing" flag was set too late, resetting previously set value.
>From upstream bba8e84307e263953520a39bc5a31014e3bd04cf
Changed paths:
engines/ags/engine/ac/character_info_engine.cpp
diff --git a/engines/ags/engine/ac/character_info_engine.cpp b/engines/ags/engine/ac/character_info_engine.cpp
index 1b82c201a97..0b116640f1e 100644
--- a/engines/ags/engine/ac/character_info_engine.cpp
+++ b/engines/ags/engine/ac/character_info_engine.cpp
@@ -223,7 +223,10 @@ void CharacterInfo::update_character_moving(int &char_index, CharacterExtras *ch
quitprintf("Unable to render character %d (%s) because there are no frames in loop %d", index_id, name, loop);
}
+ doing_nothing = 0; // still walking?
+
if (walking < 1) {
+ // Finished walking, stop and reset state
chex->process_idle_this_time = 1;
doing_nothing = 1;
walkwait = 0;
@@ -234,8 +237,9 @@ void CharacterInfo::update_character_moving(int &char_index, CharacterExtras *ch
frame = 0;
CheckViewFrameForCharacter(this);
}
- } else if (chex->animwait > 0) chex->animwait--;
- else {
+ } else if (chex->animwait > 0) {
+ chex->animwait--;
+ } else {
if (flags & CHF_ANTIGLIDE)
walkwaitcounter++;
@@ -259,7 +263,6 @@ void CharacterInfo::update_character_moving(int &char_index, CharacterExtras *ch
CheckViewFrameForCharacter(this);
}
}
- doing_nothing = 0;
}
}
Commit: 947acb21ec387914476d6459ddcde099ae228b84
https://github.com/scummvm/scummvm/commit/947acb21ec387914476d6459ddcde099ae228b84
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T14:02:52+02:00
Commit Message:
AGS: Engine: fixed improper cleanup of scrGUI array in unload_game_file()
>From upstream 045b4a6ed1e09a2d563ee5ad0addf601f700173d
Changed paths:
engines/ags/engine/ac/game.cpp
engines/ags/engine/game/game_init.cpp
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index c7440a3398b..e7448251c94 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -429,7 +429,8 @@ void unload_game_file() {
_G(scrDialog) = nullptr;
_GP(guis).clear();
- free(_G(scrGui));
+ delete[] _G(scrGui);
+ _G(scrGui) = nullptr;
free_all_fonts();
diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index 49c6092c728..b3d32b94c88 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -152,7 +152,7 @@ void InitAndRegisterDialogOptions() {
// Initializes gui and registers them in the script system
HError InitAndRegisterGUI(GameSetupStruct &game) {
- _G(scrGui) = (ScriptGUI *)malloc(sizeof(ScriptGUI) * game.numgui);
+ _G(scrGui) = new ScriptGUI[game.numgui];
for (int i = 0; i < game.numgui; ++i) {
_G(scrGui)[i].id = -1;
}
Commit: 57e9963b2e4e5edc0996fae891f68706fa87a440
https://github.com/scummvm/scummvm/commit/57e9963b2e4e5edc0996fae891f68706fa87a440
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T14:03:04+02:00
Commit Message:
AGS: Engine: fixed game package test when loading an old save
>From upstream 40b679d25cd4ca41fc297ae37effac631d066bd3
Changed paths:
engines/ags/engine/ac/game.cpp
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index e7448251c94..82aa85ce50f 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -991,7 +991,7 @@ HSaveError load_game(const String &path, int slotNumber, bool &data_overwritten)
loadDesc = &desc;
String gamefile = FindGameData(_GP(ResPaths).DataDir, TestGame);
- if (Shared::File::TestReadFile(gamefile)) {
+ if (!gamefile.IsEmpty()) {
RunAGSGame(gamefile.GetCStr(), 0, 0);
_G(load_new_game_restore) = slotNumber;
return HSaveError::None();
@@ -1003,7 +1003,7 @@ HSaveError load_game(const String &path, int slotNumber, bool &data_overwritten)
// TODO: remove filename test after deprecating old saves
else if (desc.MainDataFilename.Compare(_GP(ResPaths).GamePak.Name)) {
String gamefile = Path::ConcatPaths(_GP(ResPaths).DataDir, desc.MainDataFilename);
- if (Shared::File::TestReadFile(gamefile)) {
+ if (IsMainGameLibrary(gamefile)) {
RunAGSGame(desc.MainDataFilename, 0, 0);
_G(load_new_game_restore) = slotNumber;
return HSaveError::None();
Commit: 1c520e25a37c921bf4d58ad295adbf595ba133aa
https://github.com/scummvm/scummvm/commit/1c520e25a37c921bf4d58ad295adbf595ba133aa
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T14:05:29+02:00
Commit Message:
AGS: Engine: add proper asserts for number of GUI controls for legacy saves
>From upstream ea34dd3e1758c6de4c8fc09d8d65dabc60c35b0f
Changed paths:
engines/ags/engine/game/savegame_v321.cpp
diff --git a/engines/ags/engine/game/savegame_v321.cpp b/engines/ags/engine/game/savegame_v321.cpp
index 3be8887ffc0..12cd6a9fbb0 100644
--- a/engines/ags/engine/game/savegame_v321.cpp
+++ b/engines/ags/engine/game/savegame_v321.cpp
@@ -49,6 +49,12 @@
#include "ags/engine/game/savegame_internal.h"
#include "ags/engine/gui/animating_gui_button.h"
#include "ags/shared/gui/gui_main.h"
+#include "ags/shared/gui/gui_button.h"
+#include "ags/shared/gui/gui_inv.h"
+#include "ags/shared/gui/gui_label.h"
+#include "ags/shared/gui/gui_listbox.h"
+#include "ags/shared/gui/gui_slider.h"
+#include "ags/shared/gui/gui_textbox.h"
#include "ags/engine/media/audio/audio.h"
#include "ags/plugins/ags_plugin.h"
#include "ags/plugins/plugin_engine.h"
@@ -64,6 +70,21 @@ using namespace AGS::Engine;
static const uint32_t MAGICNUMBER = 0xbeefcafe;
+// List of game objects, used to compare with the save contents
+struct ObjectCounts {
+ int CharacterCount = 0;
+ int DialogCount = 0;
+ int InvItemCount = 0;
+ int ViewCount = 0;
+ int GUICount = 0;
+ int GUILabelCount = 0;
+ int GUIButtonCount = 0;
+ int GUIInvWindowCount = 0;
+ int GUIListBoxCount = 0;
+ int GUISliderCount = 0;
+ int GUITextBoxCount = 0;
+};
+
static HSaveError restore_game_head_dynamic_values(Stream *in, RestoredData &r_data) {
r_data.FPS = in->ReadInt32();
r_data.CursorMode = in->ReadInt32();
@@ -217,16 +238,30 @@ void ReadAnimatedButtons_Aligned(Stream *in, int num_abuts) {
}
}
-static HSaveError restore_game_gui(Stream *in, int numGuisWas) {
- HError err = GUI::ReadGUI(in, true);
- if (!err)
- return new SavegameError(kSvgErr_GameObjectInitFailed, err);
- _GP(game).numgui = _GP(guis).size();
-
- if (numGuisWas != _GP(game).numgui) {
- return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of GUI.");
+inline bool AssertGameContent(HSaveError &err, int new_val, int original_val, const char *content_name) {
+ if (new_val != original_val) {
+ err = new SavegameError(kSvgErr_GameContentAssertion,
+ String::FromFormat("Mismatching number of %s (game: %d, save: %d).",
+ content_name, original_val, new_val));
}
+ return new_val == original_val;
+}
+
+static HSaveError restore_game_gui(Stream *in, const ObjectCounts &guiwas) {
+ HError guierr = GUI::ReadGUI(in, true);
+ if (!guierr)
+ return new SavegameError(kSvgErr_GameObjectInitFailed, guierr);
+ _GP(game).numgui = _GP(guis).size();
+ HSaveError err;
+ if (!AssertGameContent(err, _GP(game).numgui, guiwas.GUICount, "GUIs") ||
+ !AssertGameContent(err, _GP(guibuts).size(), guiwas.GUIButtonCount, "GUI Buttons") ||
+ !AssertGameContent(err, _GP(guiinv).size(), guiwas.GUIInvWindowCount, "GUI InvWindows") ||
+ !AssertGameContent(err, _GP(guilabels).size(), guiwas.GUILabelCount, "GUI Labels") ||
+ !AssertGameContent(err, _GP(guilist).size(), guiwas.GUIListBoxCount, "GUI ListBoxes") ||
+ !AssertGameContent(err, _GP(guislider).size(), guiwas.GUISliderCount, "GUI Sliders") ||
+ !AssertGameContent(err, _GP(guitext).size(), guiwas.GUITextBoxCount, "GUI TextBoxes"))
+ return err;
RemoveAllButtonAnimations();
int anim_count = in->ReadInt32();
ReadAnimatedButtons_Aligned(in, anim_count);
@@ -411,13 +446,21 @@ HSaveError restore_save_data_v321(Stream *in, GameDataVersion data_ver, const Pr
CharacterInfo *chwas = _GP(game).chars;
WordsDictionary *olddict = _GP(game).dict;
std::vector<String> mesbk(MAXGLOBALMES);
- int numchwas = _GP(game).numcharacters;
for (size_t i = 0; i < MAXGLOBALMES; ++i)
mesbk[i] = _GP(game).messages[i];
- int numdiwas = _GP(game).numdialog;
- int numinvwas = _GP(game).numinvitems;
- int numviewswas = _GP(game).numviews;
- int numGuisWas = _GP(game).numgui;
+
+ ObjectCounts objwas;
+ objwas.CharacterCount = _GP(game).numcharacters;
+ objwas.DialogCount = _GP(game).numdialog;
+ objwas.InvItemCount = _GP(game).numinvitems;
+ objwas.ViewCount = _GP(game).numviews;
+ objwas.GUICount = _GP(game).numgui;
+ objwas.GUIButtonCount = _GP(guibuts).size();
+ objwas.GUIInvWindowCount = _GP(guiinv).size();
+ objwas.GUILabelCount = _GP(guilabels).size();
+ objwas.GUIListBoxCount = _GP(guilist).size();
+ objwas.GUISliderCount = _GP(guislider).size();
+ objwas.GUITextBoxCount = _GP(guitext).size();
ReadGameSetupStructBase_Aligned(in, data_ver);
@@ -426,18 +469,11 @@ HSaveError restore_save_data_v321(Stream *in, GameDataVersion data_ver, const Pr
delete[] _GP(game).load_messages;
_GP(game).load_messages = nullptr;
- if (_GP(game).numdialog != numdiwas) {
- return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Dialogs.");
- }
- if (numchwas != _GP(game).numcharacters) {
- return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Characters.");
- }
- if (numinvwas != _GP(game).numinvitems) {
- return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Inventory Items.");
- }
- if (_GP(game).numviews != numviewswas) {
- return new SavegameError(kSvgErr_GameContentAssertion, "Mismatching number of Views.");
- }
+ if (!AssertGameContent(err, _GP(game).numcharacters, objwas.CharacterCount, "Characters") ||
+ !AssertGameContent(err, _GP(game).numdialog, objwas.DialogCount, "Dialogs") ||
+ !AssertGameContent(err, _GP(game).numinvitems, objwas.InvItemCount, "Inventory Items") ||
+ !AssertGameContent(err, _GP(game).numviews, objwas.ViewCount, "Views"))
+ return err;
_GP(game).ReadFromSaveGame_v321(in, data_ver, gswas, compsc, chwas, olddict, mesbk);
@@ -448,7 +484,7 @@ HSaveError restore_save_data_v321(Stream *in, GameDataVersion data_ver, const Pr
restore_game_palette(in);
restore_game_dialogs(in);
restore_game_more_dynamic_values(in);
- err = restore_game_gui(in, numGuisWas);
+ err = restore_game_gui(in, objwas);
if (!err)
return err;
err = restore_game_audiocliptypes(in);
Commit: f1ce81461e40dcf924c9d63aef8e0744bc5b74ce
https://github.com/scummvm/scummvm/commit/f1ce81461e40dcf924c9d63aef8e0744bc5b74ce
Author: Walter Agazzi (walter.agazzi at protonmail.com)
Date: 2023-09-02T14:05:41+02:00
Commit Message:
AGS: Engine: hotfix game.top_inv_item script variable not working
Reimplemented from upstream a526a401cbf716ac7c0fc09eed92d24d60b54471
(branch 2.6.1)
This fixes the inventory scrolling in King's Quest 3 (Infamous Adventures)
and possibly other games of the era
Changed paths:
engines/ags/engine/ac/game_state.h
engines/ags/engine/ac/gui_inv.cpp
engines/ags/engine/ac/statobj/ags_static_object.cpp
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index 5f07e2326b5..13b58ac29a2 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -226,7 +226,7 @@ struct GameState {
int next_screen_transition = 0;
int gamma_adjustment = 0;
short temporarily_turned_off_character = 0; // Hide Player Charactr ticked
- short inv_backwards_compatibility = 0;
+ short inv_backwards_compatibility = 0; // tells to use legacy inv_* variables
std::vector<int> gui_draw_order; // used only for hit detection now
std::vector<AGS::Shared::String> do_once_tokens;
int text_min_display_time_ms = 0;
diff --git a/engines/ags/engine/ac/gui_inv.cpp b/engines/ags/engine/ac/gui_inv.cpp
index f424cf636d8..d80e71955e9 100644
--- a/engines/ags/engine/ac/gui_inv.cpp
+++ b/engines/ags/engine/ac/gui_inv.cpp
@@ -51,12 +51,12 @@ void GUIInvWindow::Draw(Bitmap *ds, int x, int y) {
return;
// backwards compatibility
+ // TODO: find a way to not have this inside GUIInvWindow::Draw!
_GP(play).inv_numinline = ColCount;
_GP(play).inv_numdisp = RowCount * ColCount;
_GP(play).obsolete_inv_numorder = _GP(charextra)[_GP(game).playercharacter].invorder_count;
- // if the user changes top_inv_item, switch into backwards
- // compatibiltiy mode
- if (_GP(play).inv_top)
+ // if the user changes top_inv_item, switch into backwards compat mode
+ if (_GP(play).inv_top != 0)
_GP(play).inv_backwards_compatibility = 1;
if (_GP(play).inv_backwards_compatibility)
TopItem = _GP(play).inv_top;
diff --git a/engines/ags/engine/ac/statobj/ags_static_object.cpp b/engines/ags/engine/ac/statobj/ags_static_object.cpp
index 01db2ea2656..f2021249536 100644
--- a/engines/ags/engine/ac/statobj/ags_static_object.cpp
+++ b/engines/ags/engine/ac/statobj/ags_static_object.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/statobj/ags_static_object.h"
#include "ags/engine/ac/game.h"
#include "ags/engine/ac/game_state.h"
@@ -26,6 +27,8 @@
namespace AGS3 {
+using namespace AGS::Shared;
+
const char *AGSStaticObject::GetFieldPtr(const char *address, intptr_t offset) {
return address + offset;
}
@@ -74,6 +77,9 @@ void AGSStaticObject::WriteFloat(const char *address, intptr_t offset, float val
void StaticGame::WriteInt32(const char *address, intptr_t offset, int32_t val) {
if (offset == 4 * sizeof(int32_t)) {
set_debug_mode(val != 0);
+ } else if (offset == 57 * sizeof(int32_t)) {
+ _GP(play).inv_top = val;
+ GUI::MarkInventoryForUpdate(_GP(game).playercharacter, true);
} else if (offset == 99 * sizeof(int32_t) || offset == 112 * sizeof(int32_t)) {
*(int32_t *)(const_cast<char *>(address) + offset) = ReadScriptAlignment(val);
} else {
More information about the Scummvm-git-logs
mailing list