[Scummvm-git-logs] scummvm master -> d33776efd2c1c24223211398d1dcc11cbc27d926
sev-
noreply at scummvm.org
Wed Jun 3 21:12:28 UTC 2026
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
922426f320 DIRECTOR: DT: Cast window now loads shared cast
0ea5066c06 DIRECTOR: DT: fix crash and add script viewing from cast details
d33776efd2 DIRECTOR: DT: fix null dereferences, OOB accesses, and memory leaks
Commit: 922426f320ab585c04a890dd0869757cb3bc9818
https://github.com/scummvm/scummvm/commit/922426f320ab585c04a890dd0869757cb3bc9818
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-06-03T23:12:22+02:00
Commit Message:
DIRECTOR: DT: Cast window now loads shared cast
Changed paths:
engines/director/debugger/dt-cast.cpp
diff --git a/engines/director/debugger/dt-cast.cpp b/engines/director/debugger/dt-cast.cpp
index 9994701e4cd..029bb37b033 100644
--- a/engines/director/debugger/dt-cast.cpp
+++ b/engines/director/debugger/dt-cast.cpp
@@ -109,6 +109,93 @@ Common::String getDisplayName(CastMember *castMember) {
return Common::String::format("%u", castMember->getID());
}
+void drawCastRow(Cast* cast) {
+ assert(cast);
+ for (auto castMember : *cast->_loadedCast) {
+ castMember._value->load();
+
+ Common::String name(getDisplayName(castMember._value));
+ if (!_state->_cast._nameFilter.PassFilter(name.c_str()))
+ continue;
+ if ((castMember._value->_type != kCastTypeAny) &&
+ !(_state->_cast._typeFilter & (1 << (int)castMember._value->_type)))
+ continue;
+
+ ImGui::TableNextRow();
+
+ // Make the entire row selectable/clickable
+ ImGui::TableSetColumnIndex(0);
+ if (ImGui::Selectable(
+ Common::String::format("##row%d", castMember._key).c_str(),
+ false,
+ ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap,
+ ImVec2(0, 32.f) // match row height
+ )) {
+ castMember._value->load();
+ _state->_castDetails._castMember = castMember._value;
+ _state->_w.castDetails = true;
+ }
+ ImGui::SameLine();
+
+ ImGui::Text("%s %s", toIcon(castMember._value->_type), name.c_str());
+
+ ImGui::TableNextColumn();
+ ImGui::Text("%d", castMember._key);
+
+ ImGui::TableNextColumn();
+ if (castMember._value->_type == CastType::kCastLingoScript) {
+ ScriptCastMember *scriptMember = (ScriptCastMember *)castMember._value;
+ ImGui::Text("%s", toString(scriptMember->_scriptType));
+ }
+ ImGui::TableNextColumn();
+ ImGui::Text("%s", toString(castMember._value->_type));
+
+ ImGui::TableNextColumn();
+ float columnWidth = ImGui::GetColumnWidth();
+
+ ImGuiImage imgID = {};
+ switch (castMember._value->_type) {
+ case kCastBitmap:
+ {
+ imgID = getImageID(castMember._value);
+ if (imgID.id) {
+ float offsetX = (columnWidth - 32.f) * 0.5f;
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
+ showImage(imgID, name.c_str(), 32.f);
+ }
+ }
+ break;
+
+ case kCastText:
+ case kCastRichText:
+ case kCastButton:
+ {
+ imgID = getTextID(castMember._value);
+ if (imgID.id) {
+ float offsetX = (columnWidth - 32.f) * 0.5f;
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
+ showImage(imgID, name.c_str(), 32.f);
+ }
+ }
+ break;
+
+ case kCastShape:
+ {
+ imgID = getShapeID(castMember._value);
+ if (imgID.id) {
+ float offsetX = (columnWidth - 32.f) * 0.5f;
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
+ showImage(imgID, name.c_str(), 32.f);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
void showCast() {
if (!_state->_w.cast)
return;
@@ -164,89 +251,13 @@ void showCast() {
Cast *cast = it._value;
if (!cast->_loadedCast)
continue;
+ drawCastRow(cast);
+ }
- for (auto castMember : *cast->_loadedCast) {
- castMember._value->load();
-
- Common::String name(getDisplayName(castMember._value));
- if (!_state->_cast._nameFilter.PassFilter(name.c_str()))
- continue;
- if ((castMember._value->_type != kCastTypeAny) && !(_state->_cast._typeFilter & (1 << (int)castMember._value->_type)))
- continue;
-
- ImGui::TableNextRow();
-
- // Make the entire row selectable/clickable
- ImGui::TableSetColumnIndex(0);
- if (ImGui::Selectable(
- Common::String::format("##row%d", castMember._key).c_str(),
- false,
- ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap,
- ImVec2(0, 32.f) // match row height
- )) {
- castMember._value->load();
- _state->_castDetails._castMember = castMember._value;
- _state->_w.castDetails = true;
- }
- ImGui::SameLine();
-
- ImGui::Text("%s %s", toIcon(castMember._value->_type), name.c_str());
-
- ImGui::TableNextColumn();
- ImGui::Text("%d", castMember._key);
-
- ImGui::TableNextColumn();
- if (castMember._value->_type == CastType::kCastLingoScript) {
- ScriptCastMember *scriptMember = (ScriptCastMember *)castMember._value;
- ImGui::Text("%s", toString(scriptMember->_scriptType));
- }
- ImGui::TableNextColumn();
- ImGui::Text("%s", toString(castMember._value->_type));
-
- ImGui::TableNextColumn();
- float columnWidth = ImGui::GetColumnWidth();
-
- ImGuiImage imgID = {};
- switch (castMember._value->_type) {
- case kCastBitmap:
- {
- imgID = getImageID(castMember._value);
- if (imgID.id) {
- float offsetX = (columnWidth - 32.f) * 0.5f;
- ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
- showImage(imgID, name.c_str(), 32.f);
- }
- }
- break;
-
- case kCastText:
- case kCastRichText:
- case kCastButton:
- {
- imgID = getTextID(castMember._value);
- if (imgID.id) {
- float offsetX = (columnWidth - 32.f) * 0.5f;
- ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
- showImage(imgID, name.c_str(), 32.f);
- }
- }
- break;
+ Cast *sharedCast = movie->getSharedCast();
+ if(sharedCast && sharedCast->_loadedCast)
+ drawCastRow(sharedCast);
- case kCastShape:
- {
- imgID = getShapeID(castMember._value);
- if (imgID.id) {
- float offsetX = (columnWidth - 32.f) * 0.5f;
- ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX);
- showImage(imgID, name.c_str(), 32.f);
- }
- }
- break;
- default:
- break;
- }
- }
- }
ImGui::EndTable();
}
} else {
Commit: 0ea5066c062a20b52f3f3882eb42d680502548b2
https://github.com/scummvm/scummvm/commit/0ea5066c062a20b52f3f3882eb42d680502548b2
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-06-03T23:12:22+02:00
Commit Message:
DIRECTOR: DT: fix crash and add script viewing from cast details
Changed paths:
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-castdetails.cpp
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 733d3c04d9f..f9bb8840a3d 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -127,7 +127,7 @@ ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::
ScriptContext *getScriptContext(CastMemberID id) {
const Director::Movie *movie = g_director->getCurrentMovie();;
- const Cast *cast = movie->getCasts()->getVal(id.castLib);
+ const Cast *cast;
if (id.castLib == SHARED_CAST_LIB)
cast = movie->getSharedCast();
diff --git a/engines/director/debugger/dt-castdetails.cpp b/engines/director/debugger/dt-castdetails.cpp
index d275b5e460c..bd0939442bc 100644
--- a/engines/director/debugger/dt-castdetails.cpp
+++ b/engines/director/debugger/dt-castdetails.cpp
@@ -38,6 +38,7 @@
#include "director/score.h"
#include "director/sound.h"
+#include "director/movie.h"
#include "director/types.h"
namespace Director {
@@ -544,10 +545,16 @@ void drawBaseCMprops(CastMember *member) {
ImGui::Text("scriptText");
ImGui::TableSetColumnIndex(1);
if (info && !info->script.empty()) {
- ImGui::TextColored(ImVec4(0.7f, 0.7f, 1.0f, 1.0f), "...");
+ CastMemberID scriptCastId(member->getID(), cast->_castLibID);
+ bool hasCastScript = g_director->getCurrentMovie()->getScriptContext(kCastScript, scriptCastId) != nullptr;
+ ImGui::TextColored(hasCastScript ? ImVec4(0.4f, 0.8f, 0.4f, 1.0f) : ImVec4(0.7f, 0.7f, 1.0f, 1.0f), "...");
if (ImGui::IsItemHovered()) {
- ImGui::SetTooltip("%s", info->script.c_str());
+ ImGui::SetTooltip(hasCastScript ? "%s\n\n(click to open script)" : "%s", info->script.c_str());
+ if (hasCastScript)
+ ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
}
+ if (hasCastScript && ImGui::IsItemClicked(0))
+ displayScriptRef(scriptCastId);
} else {
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "...");
}
Commit: d33776efd2c1c24223211398d1dcc11cbc27d926
https://github.com/scummvm/scummvm/commit/d33776efd2c1c24223211398d1dcc11cbc27d926
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-06-03T23:12:22+02:00
Commit Message:
DIRECTOR: DT: fix null dereferences, OOB accesses, and memory leaks
Changed paths:
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-castdetails.cpp
engines/director/debugger/dt-controlpanel.cpp
engines/director/debugger/dt-internal.h
engines/director/debugger/dt-save-state.cpp
engines/director/debugger/dt-score.cpp
engines/director/debugger/dt-script-d2.cpp
engines/director/debugger/dt-script-d4.cpp
engines/director/debugger/dt-scripts.cpp
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index f9bb8840a3d..6512c3e3eaf 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -82,13 +82,16 @@ const LingoDec::Handler *getHandler(CastMemberID id, const Common::String &handl
if (id.castLib == SHARED_CAST_LIB)
return getHandler(movie->getSharedCast(), id, handlerId);
- const Cast *cast = movie->getCasts()->getVal(id.castLib);
+ const Cast *cast = movie->getCasts()->getValOrDefault(id.castLib, nullptr);
const LingoDec::Handler *handler = getHandler(cast, id, handlerId);
if (handler)
return handler;
- return getHandler(movie->getSharedCast(), id, handlerId);
+ Cast *sharedCast = movie->getSharedCast();
+ if (!sharedCast)
+ return nullptr;
+ return getHandler(sharedCast, id, handlerId);
}
ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId) {
@@ -101,7 +104,11 @@ ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::
if (!handler) {
const ScriptContext *ctx;
if (id.castLib == SHARED_CAST_LIB) {
- ctx = g_director->getCurrentMovie()->getSharedCast()->_lingoArchive->getScriptContext(scriptType, id.member);
+ // null guard
+ Cast *sharedCast = g_director->getCurrentMovie()->getSharedCast();
+ if (!sharedCast)
+ return result;
+ ctx = sharedCast->_lingoArchive->getScriptContext(scriptType, id.member);
} else {
ctx = g_director->getCurrentMovie()->getScriptContext(scriptType, id);
}
@@ -144,10 +151,17 @@ ScriptContext *getScriptContext(CastMemberID id) {
ScriptContext *getScriptContext(uint32 nameIndex, CastMemberID id, Common::String handlerName) {
Movie *movie = g_director->getCurrentMovie();
- Cast *cast = movie->getCasts()->getVal(id.castLib);
+ Cast *cast;
+ if (id.castLib == SHARED_CAST_LIB)
+ cast = movie->getSharedCast();
+ else
+ cast = movie->getCasts()->getValOrDefault(id.castLib, nullptr);
+
+ if (!cast)
+ return nullptr;
// If the name at nameIndex is not the same as handler name, means its a local script (in the same Lscr resource)
- if (cast && cast->_lingoArchive->names[nameIndex] != handlerName) {
+ if (cast->_lingoArchive->names[nameIndex] != handlerName) {
return cast->_lingoArchive->findScriptContext(id.member);
}
@@ -299,6 +313,8 @@ static void setToolTipImage(const ImGuiImage &image, const char *name) {
}
void showImage(const ImGuiImage &image, const char *name, float thumbnailSize) {
+ if (!image.width || !image.height)
+ return;
ImVec2 size;
if (image.width > image.height) {
size = {thumbnailSize - 2, (thumbnailSize - 2) * image.height / image.width};
@@ -320,6 +336,8 @@ void showImage(const ImGuiImage &image, const char *name, float thumbnailSize) {
}
void showImageWrappedBorder(const ImGuiImage &image, const char *name, float imageSize) {
+ if (!image.width || !image.height)
+ return;
ImVec2 size;
if (image.width > image.height) {
size = {imageSize, imageSize * image.height / image.width};
@@ -424,8 +442,11 @@ ImGuiImage getTextID(CastMember *castMember) {
Graphics::MacWidget *widget = castMember->createWidget(bbox, channel, kTextSprite);
Graphics::Surface surface;
- if (!widget || !widget->getSurface() || !widget->getSurface()->getPixels())
- return {};
+ if (!widget || !widget->getSurface() || !widget->getSurface()->getPixels()) {
+ delete channel;
+ delete sprite;
+ return {};
+ }
surface.copyFrom(*widget->getSurface());
diff --git a/engines/director/debugger/dt-castdetails.cpp b/engines/director/debugger/dt-castdetails.cpp
index bd0939442bc..1999dddddfa 100644
--- a/engines/director/debugger/dt-castdetails.cpp
+++ b/engines/director/debugger/dt-castdetails.cpp
@@ -300,7 +300,7 @@ void showImageViewer() {
}
// text tab
- if (!state->cachedNormalized.empty() && ImGui::BeginTabItem("Text")) {
+ if (!state->cachedNormalized.empty() && state->buffer && ImGui::BeginTabItem("Text")) {
ImGui::BeginChild("##textPanel", ImGui::GetContentRegionAvail(), false,
ImGuiWindowFlags_HorizontalScrollbar);
diff --git a/engines/director/debugger/dt-controlpanel.cpp b/engines/director/debugger/dt-controlpanel.cpp
index d0fd862aec2..094dc8d97bc 100644
--- a/engines/director/debugger/dt-controlpanel.cpp
+++ b/engines/director/debugger/dt-controlpanel.cpp
@@ -34,7 +34,7 @@ static uint32 getLineFromPC() {
ScriptData *scriptData = &_state->_functions._windowScriptData.getOrCreateVal(g_director->getCurrentWindow());
const uint pc = g_lingo->_state->pc;
- if (scriptData->_scripts.empty())
+ if (scriptData->_scripts.empty() || scriptData->_current >= scriptData->_scripts.size())
return 0;
const Common::Array<uint> &offsets = scriptData->_scripts[scriptData->_current].startOffsets;
for (uint i = 0; i < offsets.size(); i++) {
@@ -128,7 +128,12 @@ void showControlPanel() {
ImGui::SetNextWindowSize(ImVec2(200, 103), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Control Panel", &_state->_w.controlPanel, ImGuiWindowFlags_NoDocking)) {
+ // null guard
Movie *movie = g_director->getCurrentMovie();
+ if (!movie) {
+ ImGui::End();
+ return;
+ }
Score *score = movie->getScore();
ImDrawList *dl = ImGui::GetWindowDrawList();
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index cf5e1d0c981..998f4795286 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -224,7 +224,7 @@ typedef struct ImGuiState {
Common::HashMap<Window *, ScriptData> _windowScriptData;
} _functions;
struct {
- CastMember *_castMember;
+ CastMember *_castMember = nullptr;
Common::HashMap<CastMember *, int> _filmLoopCurrentFrame;
} _castDetails;
diff --git a/engines/director/debugger/dt-save-state.cpp b/engines/director/debugger/dt-save-state.cpp
index 0180968d6ee..e8088fc94e0 100644
--- a/engines/director/debugger/dt-save-state.cpp
+++ b/engines/director/debugger/dt-save-state.cpp
@@ -140,6 +140,16 @@ void loadSavedState() {
debugC(7, kDebugImGui, "ImGui::loaded state: %s", saved->stringify(true).c_str());
// Load open/closed window flags
+ if (!saved->asObject()["Windows"] || !saved->asObject()["Window Settings"] ||
+ !saved->asObject()["Log"] || !saved->asObject()["ScoreWindow"] ||
+ !saved->asObject()["ChannelsWindow"] || !saved->asObject()["CastWindow"] ||
+ !saved->asObject()["IgnoreMouse"] || !saved->asObject()["EnableMultiViewport"]) {
+ warning("ImGui::loadSavedState(): save file is missing required fields, ignoring");
+ free(data);
+ delete saved;
+ delete savedState;
+ return;
+ }
int64 openFlags = saved->asObject()["Windows"]->asIntegerNumber();
Common::Array<WindowFlag> windows = getWindowFlags();
@@ -157,8 +167,8 @@ void loadSavedState() {
}
// Load window settings
- const char *windowSettings = saved->asObject()["Window Settings"]->asString().c_str();
- ImGui::LoadIniSettingsFromMemory(windowSettings);
+ Common::String windowSettingsStr = saved->asObject()["Window Settings"]->asString();
+ ImGui::LoadIniSettingsFromMemory(windowSettingsStr.c_str());
// Load the log
Common::JSONArray log = saved->asObject()["Log"]->asArray();
diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index ae11f63cbc9..fcc05364f08 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -150,6 +150,9 @@ static void buildContinuationData(Window *window) {
Score *score = window->getCurrentMovie()->getScore();
uint numFrames = score->_scoreCache.size();
+ if (numFrames == 0)
+ return;
+
uint numChannels = score->_scoreCache[0]->_sprites.size();
_state->_continuationData.resize(numChannels);
@@ -391,7 +394,9 @@ static void drawSpriteInspector(Score *score, Cast *cast, uint numFrames) {
CastMember *castMember = nullptr;
bool shape = false;
- if (_state->_selectedScoreCast.frame != -1 && !_state->_selectedScoreCast.isMainChannel)
+ if (_state->_selectedScoreCast.frame != -1 && !_state->_selectedScoreCast.isMainChannel
+ && _state->_selectedScoreCast.frame < (int)score->_scoreCache.size()
+ && _state->_selectedScoreCast.channel < (int)score->_scoreCache[_state->_selectedScoreCast.frame]->_sprites.size())
sprite = score->_scoreCache[_state->_selectedScoreCast.frame]->_sprites[_state->_selectedScoreCast.channel];
if (sprite) {
@@ -975,6 +980,8 @@ static void drawMainChannelGrid(ImDrawList *dl, ImVec2 startPos, Score *score) {
case kChScript: // open script in script editor
if (mc.actionId.member) {
ScriptContext *ctx = getScriptContext(mc.actionId);
+ if (!ctx)
+ break;
for (auto &handler : ctx->_functionHandlers) {
ImGuiScript script = toImGuiScript(kScoreScript, mc.actionId, handler._key);
script.byteOffsets = ctx->_functionByteOffsets[script.handlerId];
@@ -1138,6 +1145,11 @@ void showScore() {
buildContinuationData(selectedWindow);
+ if (!selectedWindow->getCurrentMovie()) {
+ ImGui::Text("No movie loaded");
+ ImGui::End();
+ return;
+ }
Score *score = selectedWindow->getCurrentMovie()->getScore();
uint numFrames = score->_scoreCache.size();
Cast *cast = selectedWindow->getCurrentMovie()->getCast();
@@ -1191,6 +1203,11 @@ void showChannels() {
if (ImGui::Begin("Channels", &_state->_w.channels)) {
Window *selectedWindow = windowListCombo(&_state->_scoreWindow);
+ if (!selectedWindow->getCurrentMovie()) {
+ ImGui::Text("No movie loaded");
+ ImGui::End();
+ return;
+ }
Score *score = selectedWindow->getCurrentMovie()->getScore();
const Frame &frame = *score->_currentFrame;
@@ -1410,8 +1427,10 @@ void showChannels() {
if (sprite._spriteListIdx) {
Common::MemoryReadStreamEndian *stream = score->getSpriteDetailsStream(sprite._spriteListIdx + 2);
Common::String name;
- if (stream)
+ if (stream) {
name = stream->readPascalString();
+ delete stream;
+ }
ImGui::Text("%s", name.c_str());
} else {
ImGui::Text(" ");
diff --git a/engines/director/debugger/dt-script-d2.cpp b/engines/director/debugger/dt-script-d2.cpp
index 2e07fb5c042..6e732985fde 100644
--- a/engines/director/debugger/dt-script-d2.cpp
+++ b/engines/director/debugger/dt-script-d2.cpp
@@ -48,7 +48,8 @@ public:
Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
if (!callstack.empty()) {
CFrame *head = callstack[callstack.size() - 1];
- _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
+ if (head->sp.ctx)
+ _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
}
_script.startOffsets.clear();
}
diff --git a/engines/director/debugger/dt-script-d4.cpp b/engines/director/debugger/dt-script-d4.cpp
index 5d7cc2d1627..e47661be2a5 100644
--- a/engines/director/debugger/dt-script-d4.cpp
+++ b/engines/director/debugger/dt-script-d4.cpp
@@ -41,7 +41,8 @@ public:
Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
if (!callstack.empty()) {
CFrame *head = callstack[callstack.size() - 1];
- _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
+ if (head->sp.ctx)
+ _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
}
_script.startOffsets.clear();
}
@@ -1128,6 +1129,8 @@ private:
void renderLine(uint p) {
bool showCurrentStatement = false;
+ if (_script.byteOffsets.empty())
+ return;
p = MIN(p, _script.byteOffsets.size() - 1);
uint pc = _script.byteOffsets[p];
_script.startOffsets.push_back(pc);
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index 1690e10f034..402f96376cf 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -130,7 +130,8 @@ static void renderCallStack(uint pc) {
if (frame->sp.type != VOIDSYM) {
stackFrame = Common::String::format("#%d ", i);
- stackFrame += Common::String::format("%d ", frame->sp.ctx->_scriptId);
+ if (frame->sp.ctx)
+ stackFrame += Common::String::format("%d ", frame->sp.ctx->_scriptId);
if (frame->sp.ctx && frame->sp.ctx->_id != -1) {
stackFrame += Common::String::format("(%d): ", frame->sp.ctx->_id);
@@ -155,6 +156,8 @@ static void renderCallStack(uint pc) {
if (ImGui::Selectable(stackFrame.c_str())) {
CFrame *head = callstack[callstack.size() - i - 1];
ScriptContext *scriptContext = head->sp.ctx;
+ if (!scriptContext || !movie->getCast())
+ continue;
int castLibID = movie->getCast()->_castLibID;
int castId = head->sp.ctx->_id;
bool childScript = false;
@@ -183,13 +186,13 @@ static bool showScriptCast(CastMemberID &id) {
bool closed = true;
if (ImGui::Begin(wName.c_str(), &closed)) {
- Cast *cast = g_director->getCurrentMovie()->getCasts()->getVal(id.castLib);
+ Cast *cast = g_director->getCurrentMovie()->getCasts()->getValOrDefault(id.castLib, nullptr);
ScriptContext *ctx = g_director->getCurrentMovie()->getScriptContext(kScoreScript, id);
if (ctx) {
for (auto &handler : ctx->_functionHandlers)
renderCastScript(handler._value);
- } else if (cast->_lingoArchive->factoryContexts.contains(id.member)) {
+ } else if (cast && cast->_lingoArchive->factoryContexts.contains(id.member)) {
for (auto &it : *cast->_lingoArchive->factoryContexts.getVal(id.member)) {
for (auto &handler : it._value->_functionHandlers)
renderCastScript(handler._value);
@@ -272,11 +275,13 @@ void showHandlers() {
return;
}
+ Common::Array<uint32> toClose;
for (auto handler : _state->_openHandlers) {
- if (!showHandler(handler._value)) {
- _state->_openHandlers.erase(handler._value.id.member);
- }
+ if (!showHandler(handler._value))
+ toClose.push_back(handler._value.id.member);
}
+ for (uint32 key : toClose)
+ _state->_openHandlers.erase(key);
}
static void updateCurrentScript() {
@@ -291,6 +296,8 @@ static void updateCurrentScript() {
CFrame *head = callstack[callstack.size() - 1];
const Director::Movie *movie = g_director->getCurrentMovie();
ScriptContext *scriptContext = head->sp.ctx;
+ if (!scriptContext || !movie->getCast())
+ return;
int castLibID = movie->getCast()->_castLibID;
int castId = head->sp.ctx->_id;
bool childScript = false;
@@ -573,7 +580,7 @@ void showExecutionContext() {
ScriptData *scriptData = &_state->_functions._windowScriptData.getOrCreateVal(stage);
updateCurrentScript();
- if (scriptData->_showScript) {
+ if (scriptData->_showScript && !scriptData->_scripts.empty() && scriptData->_current < scriptData->_scripts.size()) {
// disable highlighting while rendering scripts in Execution Context
bool oldSuppress = _state->_dbg._suppressHighlight;
_state->_dbg._suppressHighlight = true;
@@ -693,7 +700,7 @@ void showExecutionContext() {
scriptData = &_state->_functions._windowScriptData.getOrCreateVal(window);
updateCurrentScript();
- if (scriptData->_showScript) {
+ if (scriptData->_showScript && !scriptData->_scripts.empty() && scriptData->_current < scriptData->_scripts.size()) {
bool oldSuppress = _state->_dbg._suppressHighlight;
_state->_dbg._suppressHighlight = true;
ImGuiScript ¤t = scriptData->_scripts[scriptData->_current];
More information about the Scummvm-git-logs
mailing list