diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index c781bfa4619..4e7910f7cc9 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1675,7 +1675,7 @@ void prepare_room_sprites() {
if (_G(walkBehindMethod) == DrawAsSeparateSprite) {
for (int wb = 1 /* 0 is "no area" */;
- (wb < MAX_WALK_BEHINDS) && (wb < _GP(walkbehindobj).size()); ++wb) {
+ (wb < MAX_WALK_BEHINDS) && (wb < (int)_GP(walkbehindobj).size()); ++wb) {
const auto &wbobj = _GP(walkbehindobj)[wb];
if (wbobj.Ddb) {
add_to_sprite_list(wbobj.Ddb, wbobj.Pos.X, wbobj.Pos.Y,
diff --git a/engines/ags/engine/debugging/debug.cpp b/engines/ags/engine/debugging/debug.cpp
index 9b9076ac584..3b0644d8c32 100644
--- a/engines/ags/engine/debugging/debug.cpp
+++ b/engines/ags/engine/debugging/debug.cpp
@@ -315,24 +315,13 @@ void debug_script_log(const char *msg, ...) {
debug_script_print_impl(full_msg, kDbgMsg_Debug);
}
-
-String get_cur_script(int numberOfLinesOfCallStack) {
- String callstack;
- ccInstance *sci = ccInstance::GetCurrentInstance();
- if (sci)
- callstack = sci->GetCallStack(numberOfLinesOfCallStack);
- if (callstack.IsEmpty())
- callstack = cc_get_error().CallStack;
- return callstack;
-}
-
struct Breakpoint {
char scriptName[80];
int lineNumber;
};
bool send_message_to_editor(const char *msg, const char *errorMsg) {
- String callStack = get_cur_script(25);
+ String callStack = cc_get_error().CallStack;
if (callStack.IsEmpty())
return false;
diff --git a/engines/ags/engine/debugging/debugger.h b/engines/ags/engine/debugging/debugger.h
index 0929797b366..60ad55026e8 100644
--- a/engines/ags/engine/debugging/debugger.h
+++ b/engines/ags/engine/debugging/debugger.h
@@ -32,8 +32,6 @@ struct ScriptPosition;
int check_for_messages_from_editor();
bool send_message_to_editor(const char *msg);
bool send_exception_to_editor(const char *qmsg);
-// Returns current script's location and callstack
-AGS::Shared::String get_cur_script(int numberOfLinesOfCallStack);
void check_debug_keys();
#define DBG_NOIFACE 1
diff --git a/engines/ags/engine/main/quit.cpp b/engines/ags/engine/main/quit.cpp
index ae73e19bd00..77a8413ad45 100644
--- a/engines/ags/engine/main/quit.cpp
+++ b/engines/ags/engine/main/quit.cpp
@@ -48,6 +48,7 @@
#include "ags/engine/platform/base/ags_platform_driver.h"
#include "ags/engine/platform/base/sys_main.h"
#include "ags/plugins/plugin_engine.h"
+#include "ags/shared/script/cc_common.h"
#include "ags/engine/media/audio/audio_system.h"
#include "ags/globals.h"
#include "ags/ags.h"
@@ -114,7 +115,7 @@ QuitReason quit_check_for_error_state(const char *&qmsg, String &alertis) {
"(ACI version %s)\n\n", _G(EngineVersion).LongString.GetCStr());
}
- alertis.Append(get_cur_script(5));
+ alertis.Append(cc_get_error().CallStack);
if (qreason != kQuit_UserAbort)
alertis.Append("\nError: ");
@@ -125,7 +126,7 @@ QuitReason quit_check_for_error_state(const char *&qmsg, String &alertis) {
qmsg++;
alertis.Format("A warning has been generated. This is not normally fatal, but you have selected "
"to treat warnings as errors.\n"
- "(ACI version %s)\n\n%s\n", _G(EngineVersion).LongString.GetCStr(), get_cur_script(5).GetCStr());
+ "(ACI version %s)\n\n%s\n", _G(EngineVersion).LongString.GetCStr(), cc_get_error().CallStack.GetCStr());
return kQuit_GameWarning;
} else {
alertis.Format("An internal error has occurred. Please note down the following information.\n"
diff --git a/engines/ags/engine/script/cc_instance.cpp b/engines/ags/engine/script/cc_instance.cpp
index d80377b54e5..3a0217bca5e 100644
--- a/engines/ags/engine/script/cc_instance.cpp
+++ b/engines/ags/engine/script/cc_instance.cpp
@@ -157,6 +157,18 @@ const char *regnames[] = { "null", "sp", "mar", "ax", "bx", "cx", "op", "dx" };
const char *fixupnames[] = { "null", "fix_gldata", "fix_func", "fix_string", "fix_import", "fix_datadata", "fix_stack" };
+String cc_get_callstack(int max_lines) {
+ String callstack;
+ for (auto sci = _GP(InstThreads).crbegin(); sci != _GP(InstThreads).crend(); ++sci) {
+ if (callstack.IsEmpty())
+ callstack.Append("in the active script:\n");
+ else
+ callstack.Append("in the waiting script:\n");
+ callstack.Append((*sci)->GetCallStack(max_lines));
+ }
+ return callstack;
+}
+
// Function call stack is used to temporarily store
// values before passing them to script function
#define MAX_FUNC_PARAMS 20
@@ -181,7 +193,7 @@ struct FunctionCallStack {
ccInstance *ccInstance::GetCurrentInstance() {
- return _GP(InstThreads).size() > 0 ? _GP(InstThreads).top() : nullptr;
+ return _GP(InstThreads).size() > 0 ? _GP(InstThreads).back() : nullptr;
}
ccInstance *ccInstance::CreateFromScript(PScript scri) {
@@ -335,14 +347,14 @@ int ccInstance::CallScriptFunction(const char *funcname, int32_t numargs, const
}
PushValueToStack(RuntimeScriptValue().SetInt32(0)); // return address on stack
- _GP(InstThreads).push(this); // push instance thread
+ _GP(InstThreads).push_back(this); // push instance thread
runningInst = this;
int reterr = Run(startat);
// Cleanup before returning, even if error
ASSERT_STACK_SIZE(numargs);
PopValuesFromStack(numargs);
pc = 0;
- _GP(InstThreads).pop(); // pop instance thread
+ _GP(InstThreads).pop_back(); // pop instance thread
if (reterr != 0)
return reterr;
@@ -1198,7 +1210,7 @@ int ccInstance::Run(int32_t curpc) {
}
}
-String ccInstance::GetCallStack(int maxLines) {
+String ccInstance::GetCallStack(int maxLines) const {
String buffer = String::FromFormat("in \"%s\", line %d\n", runningInst->instanceof->GetSectionName(pc), line_number);
int linesDone = 0;
@@ -1212,13 +1224,13 @@ String ccInstance::GetCallStack(int maxLines) {
return buffer;
}
-void ccInstance::GetScriptPosition(ScriptPosition &script_pos) {
+void ccInstance::GetScriptPosition(ScriptPosition &script_pos) const {
script_pos.Section = runningInst->instanceof->GetSectionName(pc);
script_pos.Line = line_number;
}
// get a pointer to a variable or function exported by the script
-RuntimeScriptValue ccInstance::GetSymbolAddress(const char *symname) {
+RuntimeScriptValue ccInstance::GetSymbolAddress(const char *symname) const {
int k;
char altName[200];
snprintf(altName, sizeof(altName), "%s$", symname);
@@ -1234,7 +1246,7 @@ RuntimeScriptValue ccInstance::GetSymbolAddress(const char *symname) {
return rval_null;
}
-void ccInstance::DumpInstruction(const ScriptOperation &op) {
+void ccInstance::DumpInstruction(const ScriptOperation &op) const {
// line_num local var should be shared between all the instances
static int line_num = 0;
diff --git a/engines/ags/engine/script/cc_instance.h b/engines/ags/engine/script/cc_instance.h
index 423bef9f738..3895d68ed14 100644
--- a/engines/ags/engine/script/cc_instance.h
+++ b/engines/ags/engine/script/cc_instance.h
@@ -159,12 +159,12 @@ public:
int CallScriptFunction(const char *funcname, int32_t num_params, const RuntimeScriptValue *params);
// Get the script's execution position and callstack as human-readable text
- Shared::String GetCallStack(int maxLines);
+ Shared::String GetCallStack(int max_lines = INT_MAX) const;
// Get the script's execution position
- void GetScriptPosition(ScriptPosition &script_pos);
+ void GetScriptPosition(ScriptPosition &script_pos) const;
// Get the address of an exported symbol (function or variable) in the script
- RuntimeScriptValue GetSymbolAddress(const char *symname);
- void DumpInstruction(const ScriptOperation &op);
+ RuntimeScriptValue GetSymbolAddress(const char *symname) const;
+ void DumpInstruction(const ScriptOperation &op) const;
// Tells whether this instance is in the process of executing the byte-code
bool IsBeingRun() const;
diff --git a/engines/ags/engine/script/script.cpp b/engines/ags/engine/script/script.cpp
index 3a89de31303..19d190e4f8e 100644
--- a/engines/ags/engine/script/script.cpp
+++ b/engines/ags/engine/script/script.cpp
@@ -564,7 +564,7 @@ void quit_with_script_error(const char *functionName) {
quitprintf("!Error running function '%s':\n%s", functionName, error.ErrorString.GetCStr());
else
quitprintf("Error running function '%s':\n%s\n\n%s", functionName,
- error.ErrorString.GetCStr(), get_cur_script(5).GetCStr());
+ error.ErrorString.GetCStr(), error.CallStack.GetCStr());
}
int get_nivalue(InteractionCommandList *nic, int idx, int parm) {
diff --git a/engines/ags/engine/script/script_engine.cpp b/engines/ags/engine/script/script_engine.cpp
deleted file mode 100644
index 92478a37643..00000000000
--- a/engines/ags/engine/script/script_engine.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* 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 .
- *
- */
-
-//=============================================================================
-//
-// Script Editor run-time engine component (c) 1998 Chris Jones
-// script chunk format:
-// 00h 1 dword version - should be 2
-// 04h 1 dword sizeof(scriptblock)
-// 08h 1 dword number of ScriptBlocks
-// 0Ch n STRUCTs ScriptBlocks
-//
-//=============================================================================
-
-#include "ags/lib/std/utility.h"
-#include "ags/engine/script/cc_instance.h"
-#include "ags/shared/script/cc_common.h"
-#include "ags/shared/util/file.h"
-#include "ags/shared/util/stream.h"
-#include "ags/globals.h"
-
-namespace AGS3 {
-
-namespace AGS {
-namespace Shared {
-class RoomStruct;
-} // namespace Shared
-} // namespace AGS
-
-using namespace AGS::Shared;
-
-std::pair cc_error_at_line(const char *error_msg) {
- ccInstance *sci = ccInstance::GetCurrentInstance();
- if (!sci) {
- return std::make_pair(String::FromFormat("Error (line %d): %s", _G(currentline), error_msg), String());
- } else {
- return std::make_pair(String::FromFormat("Error: %s\n", error_msg), ccInstance::GetCurrentInstance()->GetCallStack(5));
- }
-}
-
-String cc_error_without_line(const char *error_msg) {
- return String::FromFormat("Runtime error: %s", error_msg);
-}
-
-} // namespace AGS3
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index cee427f6d65..8c835dc464f 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -129,7 +129,7 @@ Globals::Globals() {
_animbuts = new std::vector();
// cc_instance.cpp globals
- _InstThreads = new std::stack();
+ _InstThreads = new std::deque();
_GlobalReturnValue = new RuntimeScriptValue();
// cc_options.cpp globals
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index a5aa0b1ee7a..a3f5a7082f5 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -25,7 +25,7 @@
#include "ags/shared/core/platform.h"
#define AGS_PLATFORM_DEFINES_PSP_VARS (AGS_PLATFORM_OS_IOS || AGS_PLATFORM_OS_ANDROID)
-#include "ags/lib/std/stack.h"
+#include "ags/lib/std/queue.h"
#include "ags/shared/ac/game_version.h"
#include "ags/shared/util/stdio_compat.h"
#include "ags/shared/util/string.h"
@@ -369,7 +369,7 @@ public:
// In AGS currently only one thread is running, others are waiting in the queue.
// An example situation is repeatedly_execute_always callback running while
// another instance is waiting at the blocking action or Wait().
- std::stack *_InstThreads;
+ std::deque *_InstThreads;
// [IKM] 2012-10-21:
// NOTE: This is temporary solution (*sigh*, one of many) which allows certain
// exported functions return value as a RuntimeScriptValue object;
diff --git a/engines/ags/lib/std/queue.h b/engines/ags/lib/std/queue.h
index ead08567d02..1617c2a5b01 100644
--- a/engines/ags/lib/std/queue.h
+++ b/engines/ags/lib/std/queue.h
@@ -63,6 +63,80 @@ public:
}
};
+template
+class deque {
+private:
+ vector _intern;
+public:
+ deque() = default;
+ typedef typename vector::iterator iterator;
+ typedef typename const vector::const_iterator const_iterator;
+ typedef typename vector::reverse_iterator reverse_iterator;
+ typedef typename const vector::const_reverse_iterator const_reverse_iterator;
+
+ void clear() {
+ _intern.clear();
+ }
+ void insert(const T &item) {
+ _intern.push_back(item);
+ }
+ void push_back(const T &item) {
+ _intern.push_back(item);
+ }
+ void push_front(const T &item) {
+ _intern.push_front(item);
+ }
+ void pop_back() {
+ _intern.pop_back();
+ }
+ void pop_front() {
+ _intern.remove_at(0);
+ }
+ const T &front() const {
+ return _intern.front();
+ }
+ const T &back() const {
+ return _intern.back();
+ }
+
+ void resize(size_t newSize) {
+ _intern.resize(newSize);
+ }
+
+ size_t size() const {
+ return _intern.size();
+ }
+
+ T at(size_t idx) {
+ return _intern[idx];
+ }
+
+ const_iterator cbegin() {
+ return _intern.cbegin();
+ }
+ const_iterator cend() {
+ return _intern.cend();
+ }
+ reverse_iterator rbegin() {
+ return _intern.rbegin();
+ }
+ reverse_iterator rend() {
+ return _intern.rend();
+ }
+ const_reverse_iterator rbegin() const {
+ return _intern.rbegin();
+ }
+ const_reverse_iterator rend() const {
+ return _intern.rend();
+ }
+ const_reverse_iterator crbegin() const {
+ return _intern.crbegin();
+ }
+ const_reverse_iterator crend() const {
+ return _intern.crend();
+ }
+};
+
} // namespace std
} // namespace AGS3
diff --git a/engines/ags/module.mk b/engines/ags/module.mk
index 50ba7cc75c1..13c73481072 100644
--- a/engines/ags/module.mk
+++ b/engines/ags/module.mk
@@ -279,7 +279,6 @@ MODULE_OBJS = \
engine/script/runtime_script_value.o \
engine/script/script.o \
engine/script/script_api.o \
- engine/script/script_engine.o \
engine/script/script_runtime.o \
engine/script/system_imports.o \
plugins/ags_plugin.o \
diff --git a/engines/ags/shared/script/cc_common.cpp b/engines/ags/shared/script/cc_common.cpp
index 054c8b20a32..3e7dfa97158 100644
--- a/engines/ags/shared/script/cc_common.cpp
+++ b/engines/ags/shared/script/cc_common.cpp
@@ -42,10 +42,8 @@ int ccGetOption(int optbit) {
return 0;
}
-// Returns full script error message and callstack (if possible)
-extern std::pair cc_error_at_line(const char *error_msg);
-// Returns script error message without location or callstack
-extern String cc_error_without_line(const char *error_msg);
+// Returns current running script callstack as a human-readable text
+extern String cc_get_callstack(int max_lines = INT_MAX);
void cc_clear_error() {
_GP(ccError) = ScriptError();
@@ -71,15 +69,12 @@ void cc_error(const char *descr, ...) {
String displbuf = String::FromFormatV(descr, ap);
va_end(ap);
- if (_G(currentline) > 0) {
- // [IKM] Implementation is project-specific
- std::pair errinfo = cc_error_at_line(displbuf.GetCStr());
- _GP(ccError).ErrorString = errinfo.first;
- _GP(ccError).CallStack = errinfo.second;
- } else {
- _GP(ccError).ErrorString = cc_error_without_line(displbuf.GetCStr());
- _GP(ccError).CallStack = "";
- }
+ String callstack = cc_get_callstack();
+ if ((_G(currentline) > 0) && callstack.IsEmpty())
+ _GP(ccError).ErrorString = String::FromFormat("Error (line %d): %s", _G(currentline), displbuf.GetCStr());
+ else
+ _GP(ccError).ErrorString = String::FromFormat("Error: %s", displbuf.GetCStr());
+ _GP(ccError).CallStack = callstack;
_GP(ccError).HasError = 1;
_GP(ccError).Line = _G(currentline);