Skip to content

Commit c3dead0

Browse files
committed
Engine: a more thorough simulation of pre-3.6.0 Wait with edge cases
An older commit 6777dad had introduced some fixes for older games, but did not cover all the edge cases properly. This is a second attempt.
1 parent a9bf79e commit c3dead0

File tree

1 file changed

+54
-11
lines changed

1 file changed

+54
-11
lines changed

Engine/ac/global_game.cpp

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,18 +1024,36 @@ void SetGraphicalVariable (const char *varName, int p_value) {
10241024
theVar->Value = p_value;
10251025
}
10261026

1027-
int WaitImpl(int skip_type, int nloops)
1027+
// Wait* implementation specific to pre-3.6.0 games, which had number of accidental effects.
1028+
static int WaitImplPre360(int skip_type, int nloops)
10281029
{
1029-
// if skipping cutscene and expecting user input: don't wait at all
1030-
if (play.fast_forward && ((skip_type & ~SKIP_AUTOTIMER) != 0))
1030+
// Negative nloops was forbidden in < 3.6.0, but here we just return instantly
1031+
if (nloops < 0)
1032+
{
10311033
return 0;
1034+
}
10321035

1033-
// < 3.6.0 scripts treated negative nloops as "no time";
1034-
// also old engine let nloops to overflow into neg when assigned to wait_counter...
1035-
if (game.options[OPT_BASESCRIPTAPI] < kScriptAPI_v360)
1036+
// < 3.6.0 implementation of Wait* did not have a value range check when assigning
1037+
// int32 parameter to a int16 wait counter.
1038+
// Values above INT16_MAX caused wait counter overflow. If the resulting int16 value
1039+
// appeared negative, then Wait would skip after the very first update,
1040+
// returning "1", as if it was skipped by a player input (this was not intentional,
1041+
// but pure accident due to a bad program logic). If the resulting int16 value
1042+
// appeared positive, then game would wait for that amount normally.
1043+
// We simulate this here, because, unfortunately, it's required to keep some old games run correctly.
1044+
bool force_retval1 = false;
1045+
if (nloops > INT16_MAX)
10361046
{
1037-
if (nloops < 0 || nloops > INT16_MAX)
1038-
nloops = 0;
1047+
int16_t overflown_value = static_cast<int16_t>(nloops);
1048+
if (overflown_value < 0)
1049+
{
1050+
nloops = 1;
1051+
force_retval1 = true;
1052+
}
1053+
else
1054+
{
1055+
nloops = overflown_value;
1056+
}
10391057
}
10401058

10411059
// Zero loops make no sense, however very old engines seem to
@@ -1049,19 +1067,44 @@ int WaitImpl(int skip_type, int nloops)
10491067
return 0;
10501068
}
10511069

1052-
// clamp to int16
10531070
play.wait_counter = static_cast<int16_t>(Math::Clamp<int>(nloops, -1, INT16_MAX));
10541071
play.wait_skipped_by = SKIP_NONE;
10551072
play.wait_skipped_by_data = 0;
10561073
play.key_skip_wait = skip_type;
10571074

10581075
GameLoopUntilValueIsZero(&play.wait_counter);
10591076

1077+
if (force_retval1)
1078+
return 1;
1079+
1080+
// < 3.6.0 return 1 if skipped by user input, otherwise 0
1081+
return ((play.wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK)) != 0) ? 1 : 0;
1082+
}
1083+
1084+
int WaitImpl(int skip_type, int nloops)
1085+
{
1086+
// if skipping cutscene and expecting user input: don't wait at all
1087+
if (play.fast_forward && ((skip_type & ~SKIP_AUTOTIMER) != 0))
1088+
return 0;
1089+
10601090
if (game.options[OPT_BASESCRIPTAPI] < kScriptAPI_v360)
10611091
{
1062-
// < 3.6.0 return 1 if skipped by user input, otherwise 0
1063-
return ((play.wait_skipped_by & (SKIP_KEYPRESS | SKIP_MOUSECLICK)) != 0) ? 1 : 0;
1092+
return WaitImplPre360(skip_type, nloops);
1093+
}
1094+
1095+
// Zero loops make no sense, so return instantly
1096+
if (nloops == 0)
1097+
{
1098+
return 0;
10641099
}
1100+
1101+
play.wait_counter = static_cast<int16_t>(Math::Clamp<int>(nloops, -1, INT16_MAX));
1102+
play.wait_skipped_by = SKIP_NONE;
1103+
play.wait_skipped_by_data = 0;
1104+
play.key_skip_wait = skip_type;
1105+
1106+
GameLoopUntilValueIsZero(&play.wait_counter);
1107+
10651108
// >= 3.6.0 return skip (input) type flags with keycode
10661109
return play.GetWaitSkipResult();
10671110
}

0 commit comments

Comments
 (0)