@@ -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