From 6bac3331e2b79287b3ade569b2302acc3a0c3cc0 Mon Sep 17 00:00:00 2001 From: Ananim353 Date: Sun, 9 Aug 2026 03:54:11 +0300 Subject: [PATCH 1/2] Read built-in variables in the multi-dim array chain The V17 first step of a multi-dimensional access (VARTYPE_ARRAYPUSHAF/POPAF) resolved the variable only through selfVars and localVars. Built-ins live in neither: argument[] is the call frame, not a member. So the chain fell through to getOrInsertUndefined, found nothing, materialised a FRESH EMPTY array in that slot and drilled into it -- argument[0][i] came back undefined, while plain argument[0] (which goes through resolveVariableRead) was correct. Both opcode forms are fixed. handlePush has the first index on the stack and reads the variable at it; handlePushBltn carries no index, so it reads the variable whole. Only a borrowed array becomes a weak ref: freeing an owned one there would leave the stack pointing at released memory, and anything else keeps the old path, so this cannot turn a working case into an abort. Found in DELTARUNE Chapter 5, where the platforming floor passes its tile layer names as scr_floortex_setFloorLayers(["TILES_Grass", ...]) and reads them back as argument[0][i]: layer_get_id received the string "undefined", the floor layer list stayed empty, and the untrimmed floor covered the party. snd_play_random reads its sound bank the same way. --- src/vm.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/vm.c b/src/vm.c index bfb841611..61ba92708 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1153,6 +1153,28 @@ static void handlePush(VMContext* ctx, uint32_t instr, const uint8_t* extraData, scope = resolveInstanceStackTop(ctx); } + // Built-in variables do NOT live in selfVars: argument[] is the call frame, not a + // member. Falling through would call getOrInsertUndefined, find nothing, materialise + // a FRESH EMPTY array in that slot and drill into it -- so argument[0][i] came back + // undefined while argument[0] (which goes through resolveVariableRead) was correct. + // Read the real value and hand out a weak ref to it instead. + if (varDef->builtinVarId >= 0) { + Instance* builtinInst = (scope == INSTANCE_OTHER && ctx->otherInstance != nullptr) + ? (Instance*) ctx->otherInstance + : (scope == INSTANCE_GLOBAL) ? ctx->globalScopeInstance + : (scope >= 0) ? VM_findInstanceByTarget(ctx, scope) + : (Instance*) ctx->currentInstance; + RValue builtinVal = VMBuiltins_getVariable(ctx, builtinInst, varDef->builtinVarId, varDef->name, firstIndex); + // Only a borrowed array can become a weak ref: freeing an owned one here would + // leave the stack pointing at released memory. Anything else keeps the old path, + // so this cannot turn a working case into an abort. + if (builtinVal.type == RVALUE_ARRAY && builtinVal.array != nullptr && !builtinVal.ownsReference) { + stackPush(ctx, RValue_makeArrayWeak(builtinVal.array)); + break; + } + RValue_free(&builtinVal); + } + // Resolve the slot for this scope. RValue* slot = nullptr; switch (scope) { @@ -1276,6 +1298,18 @@ static void handlePushBltn(VMContext* ctx, uint32_t instr, const uint8_t* extraD logError("VM: PushBltn ARRAYPUSHAF: no instance for scope %d varID=%d\n", scope, varDef->varID); abort(); } + // Same trap as in handlePush: a built-in has no selfVars slot, and materialising one there + // would replace the real value with an empty array. PushBltn only ever names built-ins, but + // the index of the first step is NOT on the stack here -- this opcode form carries no array + // index, so read the variable whole (arrayIndex -1) and hand out a weak ref to it. + if (varDef->builtinVarId >= 0) { + RValue builtinVal = VMBuiltins_getVariable(ctx, inst, varDef->builtinVarId, varDef->name, -1); + if (builtinVal.type == RVALUE_ARRAY && builtinVal.array != nullptr && !builtinVal.ownsReference) { + stackPush(ctx, RValue_makeArrayWeak(builtinVal.array)); + return; + } + RValue_free(&builtinVal); + } RValue* slot = IntRValueHashMap_getOrInsertUndefined(&inst->selfVars, varDef->varID); pushTopLevelArrayRef(ctx, slot, varType == VARTYPE_ARRAYPOPAF); return; From f07e5ae6ae176cdfe15694e4435fd5813e5ac1e3 Mon Sep 17 00:00:00 2001 From: Ananim353 Date: Sun, 9 Aug 2026 03:54:12 +0300 Subject: [PATCH 2/2] Take colours as 32 bits, and round the blend A GML colour lives in an RValue as a double and is quite happily wider than a signed int32: DELTARUNE Chapter 5 stores 4294967295 (0xFFFFFFFF) in the tint of the platforming floor. Casting that through int32 saturates to INT32_MIN (0x80000000), whose three colour bytes are all zero, so merge_color(c_white, 4294967295, 1) returned 0 and the wall behind the floor came out black. RValue_toColour takes the bits instead of the sign: values inside the int32 range behave exactly as before, negative ones keep their bit pattern. Applied to every colour argument in vm_builtins.c, since the defect belonged to the drawing API as a whole and the floor simply happened to feed it such a value first. Color_lerp rounds now instead of truncating: merge_color(c_black, c_white, 0.5) is 0x808080 in GameMaker, and truncation gave 0x7F7F7F -- every half-and-half blend came out one step dark per channel. Not to be confused with vertex alpha in floatToUnormByte, where the runtime does truncate; that one is left alone. --- src/rvalue.h | 15 ++++++ src/utils.h | 9 ++-- src/vm_builtins.c | 120 +++++++++++++++++++++++----------------------- 3 files changed, 81 insertions(+), 63 deletions(-) diff --git a/src/rvalue.h b/src/rvalue.h index 20b5a5093..b0b7160af 100644 --- a/src/rvalue.h +++ b/src/rvalue.h @@ -463,6 +463,21 @@ static inline int32_t RValue_toInt32(RValue val) { } } +// A GML colour lives in an RValue as a double, and it is quite happily 32-bit wide: DELTARUNE +// Chapter 5 stores 4294967295 (0xFFFFFFFF) in the platforming floor's tint. Casting that through +// a signed int32 saturates to INT32_MIN (0x80000000), whose three colour bytes are all zero -- the +// white wall behind the floor came out black, and merge_color(c_white, 4294967295, 1) returned 0. +// Take the bits, not the sign: values inside the int32 range behave exactly as before, and negative +// ones keep their bit pattern. +static inline uint32_t RValue_toColour(RValue val) { + if (val.type == RVALUE_REAL) { + double d = (double) val.real; + if (d >= 0.0) return (d >= 4294967295.0) ? 0xFFFFFFFFu : (uint32_t) d; + return (uint32_t) (int32_t) RValue_toInt32(val); + } + return (uint32_t) RValue_toInt32(val); +} + static inline int64_t RValue_toInt64(RValue val) { switch (val.type) { case RVALUE_REAL: return (int64_t) val.real; diff --git a/src/utils.h b/src/utils.h index a6842352a..eca71eab4 100644 --- a/src/utils.h +++ b/src/utils.h @@ -173,9 +173,12 @@ static inline int32_t Color_lerp(int32_t color1, int32_t color2, float blending) int32_t r1 = BGR_R(color1), g1 = BGR_G(color1), b1 = BGR_B(color1); int32_t r2 = BGR_R(color2), g2 = BGR_G(color2), b2 = BGR_B(color2); float inv = 1.0f - blending; - int32_t r = (int32_t)((float) r2 * blending + (float) r1 * inv) & 0xFF; - int32_t g = (int32_t)((float) g2 * blending + (float) g1 * inv) & 0xFF; - int32_t b = (int32_t)((float) b2 * blending + (float) b1 * inv) & 0xFF; + // Rounded, not truncated: merge_color(c_black, c_white, 0.5) is 0x808080 in GameMaker, while + // truncation gave 0x7F7F7F -- every half-and-half blend came out one step dark per channel. + // (Not to be confused with vertex alpha in floatToUnormByte, where the runtime does truncate.) + int32_t r = (int32_t)((float) r2 * blending + (float) r1 * inv + 0.5f) & 0xFF; + int32_t g = (int32_t)((float) g2 * blending + (float) g1 * inv + 0.5f) & 0xFF; + int32_t b = (int32_t)((float) b2 * blending + (float) b1 * inv + 0.5f) & 0xFF; return r | (g << 8) | (b << 16); } diff --git a/src/vm_builtins.c b/src/vm_builtins.c index 28a4b576b..923b6e2bd 100644 --- a/src/vm_builtins.c +++ b/src/vm_builtins.c @@ -1730,7 +1730,7 @@ void VMBuiltins_setVariable(VMContext* ctx, Instance* inst, int16_t builtinVarId return; case BUILTIN_VAR_BACKGROUND_COLOR: case BUILTIN_VAR_BACKGROUND_COLOUR: - runner->backgroundColor = (uint32_t) RValue_toInt32(val); + runner->backgroundColor = RValue_toColour(val); return; // Room properties @@ -9616,7 +9616,7 @@ static RValue builtin_draw_sprite_ext(VMContext* ctx, RValue* args, MAYBE_UNUSED float xscale = (float) RValue_toReal(args[4]); float yscale = (float) RValue_toReal(args[5]); float rot = (float) RValue_toReal(args[6]); - uint32_t color = (uint32_t) RValue_toInt32(args[7]); + uint32_t color = RValue_toColour(args[7]); float alpha = (float) RValue_toReal(args[8]); if (0 > subimg && ctx->currentInstance != nullptr) { @@ -9656,7 +9656,7 @@ static RValue builtin_draw_sprite_tiled_ext(VMContext* ctx, RValue* args, MAYBE_ float y = (float) RValue_toReal(args[3]); float xscale = (float) RValue_toReal(args[4]); float yscale = (float) RValue_toReal(args[5]); - uint32_t color = (uint32_t) RValue_toInt32(args[6]); + uint32_t color = RValue_toColour(args[6]); float alpha = (float) RValue_toReal(args[7]); if (0 > subimg && ctx->currentInstance != nullptr) { @@ -9698,7 +9698,7 @@ static RValue builtin_draw_sprite_stretched_ext(VMContext* ctx, RValue* args, MA float y = (float) RValue_toReal(args[3]); float w = (float) RValue_toReal(args[4]); float h = (float) RValue_toReal(args[5]); - uint32_t color = (uint32_t) RValue_toInt32(args[6]); + uint32_t color = RValue_toColour(args[6]); float alpha = (float) RValue_toReal(args[7]); if (0 > subimg && ctx->currentInstance != nullptr) { @@ -9745,7 +9745,7 @@ static RValue builtin_draw_sprite_part_ext(VMContext* ctx, RValue* args, MAYBE_U float y = (float) RValue_toReal(args[7]); float xscale = (float) RValue_toReal(args[8]); float yscale = (float) RValue_toReal(args[9]); - uint32_t color = (uint32_t) RValue_toInt32(args[10]); + uint32_t color = RValue_toColour(args[10]); float alpha = (float) RValue_toReal(args[11]); if (0 > subimg && ctx->currentInstance != nullptr) { @@ -9772,7 +9772,7 @@ static RValue builtin_draw_sprite_general(VMContext* ctx, RValue* args, MAYBE_UN float xscale = (float) RValue_toReal(args[8]); float yscale = (float) RValue_toReal(args[9]); float rot = (float) RValue_toReal(args[10]); - uint32_t c1 = (uint32_t) RValue_toInt32(args[11]); + uint32_t c1 = RValue_toColour(args[11]); float alpha = (float) RValue_toReal(args[15]); if (0 > subimg && ctx->currentInstance != nullptr) { @@ -9835,10 +9835,10 @@ static RValue builtin_draw_rectangle_color(VMContext* ctx, RValue* args, MAYBE_U float y1 = (float) RValue_toReal(args[1]); float x2 = (float) RValue_toReal(args[2]); float y2 = (float) RValue_toReal(args[3]); - uint32_t color1 = (uint32_t) RValue_toInt32(args[4]); - uint32_t color2 = (uint32_t) RValue_toInt32(args[5]); - uint32_t color3 = (uint32_t) RValue_toInt32(args[6]); - uint32_t color4 = (uint32_t) RValue_toInt32(args[7]); + uint32_t color1 = RValue_toColour(args[4]); + uint32_t color2 = RValue_toColour(args[5]); + uint32_t color3 = RValue_toColour(args[6]); + uint32_t color4 = RValue_toColour(args[7]); bool outline = RValue_toBool(args[8]); if (runner->applyOffsetForPrimitives) { x2 += 1.0f; y2 += 1.0f; @@ -9863,9 +9863,9 @@ static RValue builtin_draw_healthbar(VMContext* ctx, RValue* args, MAYBE_UNUSED float healthbarX = (x1 * (1-amount) + x2 * amount); //float healthbarY = (y1 * (1-amount) + y2 * amount); - uint32_t backCol = (uint32_t) RValue_toInt32(args[5]); - uint32_t minCol = (uint32_t) RValue_toInt32(args[6]); - uint32_t maxCol = (uint32_t) RValue_toInt32(args[7]); + uint32_t backCol = RValue_toColour(args[5]); + uint32_t minCol = RValue_toColour(args[6]); + uint32_t maxCol = RValue_toColour(args[7]); uint32_t intermediateColor = (uint32_t) Color_lerp((int32_t) minCol, (int32_t) maxCol, amount); bool showBack = RValue_toBool(args[9]); @@ -9881,7 +9881,7 @@ static RValue builtin_draw_healthbar(VMContext* ctx, RValue* args, MAYBE_UNUSED static RValue builtin_draw_set_color(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Runner* runner = ctx->runner; if (runner->renderer != nullptr) { - runner->renderer->drawColor = (uint32_t) RValue_toInt32(args[0]); + runner->renderer->drawColor = RValue_toColour(args[0]); } return RValue_makeUndefined(); } @@ -9889,7 +9889,7 @@ static RValue builtin_draw_set_color(VMContext* ctx, RValue* args, MAYBE_UNUSED static RValue builtin_draw_clear(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Runner* runner = ctx->runner; if (runner->renderer != nullptr) { - uint32_t color = (uint32_t) RValue_toInt32(args[0]); + uint32_t color = RValue_toColour(args[0]); runner->renderer->vtable->clearScreen(runner->renderer, color, 1.0f); } return RValue_makeUndefined(); @@ -9898,7 +9898,7 @@ static RValue builtin_draw_clear(VMContext* ctx, RValue* args, MAYBE_UNUSED int3 static RValue builtin_draw_clear_alpha(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Runner* runner = ctx->runner; if (runner->renderer != nullptr) { - uint32_t color = (uint32_t) RValue_toInt32(args[0]); + uint32_t color = RValue_toColour(args[0]); float alpha = RValue_toReal(args[1]); runner->renderer->vtable->clearScreen(runner->renderer, color, alpha); } @@ -10034,10 +10034,10 @@ static RValue builtin_draw_text_color(VMContext* ctx, RValue* args, MAYBE_UNUSED float x = (float) RValue_toReal(args[0]); float y = (float) RValue_toReal(args[1]); char* str = RValue_toString(args[2]); - int32_t c1 = RValue_toInt32(args[3]); - int32_t c2 = RValue_toInt32(args[4]); - int32_t c3 = RValue_toInt32(args[5]); - int32_t c4 = RValue_toInt32(args[6]); + int32_t c1 = (int32_t) RValue_toColour(args[3]); + int32_t c2 = (int32_t) RValue_toColour(args[4]); + int32_t c3 = (int32_t) RValue_toColour(args[5]); + int32_t c4 = (int32_t) RValue_toColour(args[6]); float alpha = (float) RValue_toReal(args[7]); PreprocessedText processedText = TextUtils_preprocessGmlTextIfNeeded(runner, str); @@ -10057,10 +10057,10 @@ static RValue builtin_draw_text_color_transformed(VMContext* ctx, RValue* args, float xscale = (float) RValue_toReal(args[3]); float yscale = (float) RValue_toReal(args[4]); float angle = (float) RValue_toReal(args[5]); - int32_t c1 = RValue_toInt32(args[6]); - int32_t c2 = RValue_toInt32(args[7]); - int32_t c3 = RValue_toInt32(args[8]); - int32_t c4 = RValue_toInt32(args[9]); + int32_t c1 = (int32_t) RValue_toColour(args[6]); + int32_t c2 = (int32_t) RValue_toColour(args[7]); + int32_t c3 = (int32_t) RValue_toColour(args[8]); + int32_t c4 = (int32_t) RValue_toColour(args[9]); float alpha = (float) RValue_toReal(args[10]); PreprocessedText processedText = TextUtils_preprocessGmlTextIfNeeded(runner, str); @@ -10092,10 +10092,10 @@ static RValue builtin_draw_text_color_ext(VMContext* ctx, RValue* args, MAYBE_UN char* str = RValue_toString(args[2]); int32_t separation = RValue_toInt32(args[3]); int32_t width = RValue_toInt32(args[4]); - int32_t c1 = RValue_toInt32(args[5]); - int32_t c2 = RValue_toInt32(args[6]); - int32_t c3 = RValue_toInt32(args[7]); - int32_t c4 = RValue_toInt32(args[8]); + int32_t c1 = (int32_t) RValue_toColour(args[5]); + int32_t c2 = (int32_t) RValue_toColour(args[6]); + int32_t c3 = (int32_t) RValue_toColour(args[7]); + int32_t c4 = (int32_t) RValue_toColour(args[8]); float alpha = (float) RValue_toReal(args[9]); drawTextColorExtCommon(runner, str, x, y, 1.0f, 1.0f, 0.0f, separation, width, c1, c2, c3, c4, alpha); @@ -10115,10 +10115,10 @@ static RValue builtin_draw_text_color_ext_transformed(VMContext* ctx, RValue* ar float xscale = (float) RValue_toReal(args[5]); float yscale = (float) RValue_toReal(args[6]); float angle = (float) RValue_toReal(args[7]); - int32_t c1 = RValue_toInt32(args[8]); - int32_t c2 = RValue_toInt32(args[9]); - int32_t c3 = RValue_toInt32(args[10]); - int32_t c4 = RValue_toInt32(args[11]); + int32_t c1 = (int32_t) RValue_toColour(args[8]); + int32_t c2 = (int32_t) RValue_toColour(args[9]); + int32_t c3 = (int32_t) RValue_toColour(args[10]); + int32_t c4 = (int32_t) RValue_toColour(args[11]); float alpha = (float) RValue_toReal(args[12]); drawTextColorExtCommon(runner, str, x, y, xscale, yscale, angle, separation, width, c1, c2, c3, c4, alpha); @@ -10151,7 +10151,7 @@ static RValue builtin_draw_background_ext(VMContext* ctx, RValue* args, MAYBE_UN float xscale = (float) RValue_toReal(args[3]); float yscale = (float) RValue_toReal(args[4]); float rot = (float) RValue_toReal(args[5]); - uint32_t color = (uint32_t) RValue_toInt32(args[6]); + uint32_t color = RValue_toColour(args[6]); float alpha = (float) RValue_toReal(args[7]); int32_t tpagIndex = Renderer_resolveBackgroundTPAGIndex(runner->dataWin, bgIndex); @@ -10214,7 +10214,7 @@ static RValue builtin_draw_background_part_ext(VMContext* ctx, RValue* args, MAY float y = (float) RValue_toReal(args[6]); float xscale = (float) RValue_toReal(args[7]); float yscale = (float) RValue_toReal(args[8]); - uint32_t color = (uint32_t) RValue_toInt32(args[9]); + uint32_t color = RValue_toColour(args[9]); float alpha = (float) RValue_toReal(args[10]); int32_t tpagIndex = Renderer_resolveBackgroundTPAGIndex(runner->dataWin, bgIndex); @@ -10250,7 +10250,7 @@ static RValue builtin_draw_background_tiled_ext(VMContext* ctx, RValue* args, MA float y = (float) RValue_toReal(args[2]); float xscale = (float) RValue_toReal(args[3]); float yscale = (float) RValue_toReal(args[4]); - uint32_t color = (uint32_t) RValue_toInt32(args[5]); + uint32_t color = RValue_toColour(args[5]); float alpha = (float) RValue_toReal(args[6]); int32_t tpagIndex = Renderer_resolveBackgroundTPAGIndex(runner->dataWin, bgIndex); @@ -10304,7 +10304,7 @@ static RValue builtin_draw_point_color(VMContext* ctx, RValue* args, MAYBE_UNUSE if (runner->renderer == nullptr) return RValue_makeUndefined(); float x = (float) RValue_toReal(args[0]); float y = (float) RValue_toReal(args[1]); - uint32_t col = (uint32_t) RValue_toInt32(args[2]); + uint32_t col = RValue_toColour(args[2]); if (runner->applyOffsetForPrimitives) { x += 1.0f; y += 1.0f; } runner->renderer->vtable->drawRectangle(runner->renderer, x, y, x + 1.0f, y + 1.0f, col, runner->renderer->drawAlpha, false); @@ -10374,8 +10374,8 @@ static RValue builtin_draw_line_width_colour(VMContext* ctx, RValue* args, MAYBE float x2 = (float) RValue_toReal(args[2]); float y2 = (float) RValue_toReal(args[3]); float w = (float) RValue_toReal(args[4]); - uint32_t col1 = (uint32_t) RValue_toInt32(args[5]); - uint32_t col2 = (uint32_t) RValue_toInt32(args[6]); + uint32_t col1 = RValue_toColour(args[5]); + uint32_t col2 = RValue_toColour(args[6]); if (runner->applyOffsetForPrimitives) { x1 += 1.0f; y1 += 1.0f; x2 += 1.0f; y2 += 1.0f; @@ -10417,9 +10417,9 @@ static RValue builtin_draw_triangle_color(VMContext* ctx, RValue* args, MAYBE_UN float y2 = (float) RValue_toReal(args[3]); float x3 = (float) RValue_toReal(args[4]); float y3 = (float) RValue_toReal(args[5]); - uint32_t col1 = (uint32_t) RValue_toInt32(args[6]); - uint32_t col2 = (uint32_t) RValue_toInt32(args[7]); - uint32_t col3 = (uint32_t) RValue_toInt32(args[8]); + uint32_t col1 = RValue_toColour(args[6]); + uint32_t col2 = RValue_toColour(args[7]); + uint32_t col3 = RValue_toColour(args[8]); bool outline = RValue_toBool(args[9]); if (runner->applyOffsetForPrimitives) { x1 += 1.0f; y1 += 1.0f; @@ -10454,8 +10454,8 @@ static RValue builtin_draw_circle_color(VMContext* ctx, RValue* args, MAYBE_UNUS float x = (float) RValue_toReal(args[0]); float y = (float) RValue_toReal(args[1]); float r = (float) RValue_toReal(args[2]); - uint32_t col1 = (uint32_t) RValue_toInt32(args[3]); - uint32_t col2 = (uint32_t) RValue_toInt32(args[4]); + uint32_t col1 = RValue_toColour(args[3]); + uint32_t col2 = RValue_toColour(args[4]); bool outline = RValue_toBool(args[5]); Renderer_drawCircleColor(runner->renderer, x, y, r, col1, col2, outline); } @@ -10489,8 +10489,8 @@ static RValue builtin_draw_ellipse_color(VMContext* ctx, RValue* args, MAYBE_UNU float y1 = (float) RValue_toReal(args[1]); float x2 = (float) RValue_toReal(args[2]); float y2 = (float) RValue_toReal(args[3]); - uint32_t col1 = (uint32_t) RValue_toInt32(args[4]); - uint32_t col2 = (uint32_t) RValue_toInt32(args[5]); + uint32_t col1 = RValue_toColour(args[4]); + uint32_t col2 = RValue_toColour(args[5]); bool outline = RValue_toBool(args[6]); if (runner->applyOffsetForPrimitives) { x1 += 1.0f; y1 += 1.0f; @@ -10522,7 +10522,7 @@ static RValue builtin_draw_get_circle_precision(VMContext* ctx, MAYBE_UNUSED RVa static RValue builtin_draw_set_colour(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Runner* runner = ctx->runner; if (runner->renderer != nullptr) { - runner->renderer->drawColor = (uint32_t) RValue_toInt32(args[0]); + runner->renderer->drawColor = RValue_toColour(args[0]); } return RValue_makeUndefined(); } @@ -10594,8 +10594,8 @@ static RValue builtin_motion_add(VMContext* ctx, RValue* args, int32_t argCount) // merge_color(col1, col2, amount) - lerps between two colors static RValue builtin_merge_color(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { - int32_t col1 = RValue_toInt32(args[0]); - int32_t col2 = RValue_toInt32(args[1]); + int32_t col1 = (int32_t) RValue_toColour(args[0]); + int32_t col2 = (int32_t) RValue_toColour(args[1]); float amount = (float) RValue_toReal(args[2]); return RValue_makeReal((GMLReal) Color_lerp(col1, col2, amount)); } @@ -10722,7 +10722,7 @@ static RValue builtin_draw_surface_ext(VMContext* ctx, RValue* args, MAYBE_UNUSE float xscale = (float) RValue_toReal(args[3]); float yscale = (float) RValue_toReal(args[4]); float rot = (float) RValue_toReal(args[5]); - uint32_t color = (uint32_t) RValue_toInt32(args[6]); + uint32_t color = RValue_toColour(args[6]); float alpha = (float) RValue_toReal(args[7]); @@ -10766,7 +10766,7 @@ static RValue builtin_draw_surface_part_ext(VMContext* ctx, RValue* args, MAYBE_ float xscale = (float) RValue_toReal(args[7]); float yscale = (float) RValue_toReal(args[8]); - uint32_t color = (uint32_t) RValue_toInt32(args[9]); + uint32_t color = RValue_toColour(args[9]); float alpha = (float) RValue_toReal(args[10]); Runner* runner = ctx->runner; if (runner->renderer != nullptr) { @@ -10800,7 +10800,7 @@ static RValue builtin_draw_surface_stretched_ext(VMContext* ctx, RValue* args, M float y = (float) RValue_toReal(args[2]); float width = (float) RValue_toReal(args[3]); float height = (float) RValue_toReal(args[4]); - uint32_t color = (uint32_t) RValue_toInt32(args[5]); + uint32_t color = RValue_toColour(args[5]); float alpha = (float) RValue_toReal(args[6]); Runner* runner = ctx->runner; if (runner->renderer != nullptr) { @@ -10832,7 +10832,7 @@ static RValue builtin_draw_surface_tiled_ext(VMContext* ctx, RValue* args, MAYBE float y = (float) RValue_toReal(args[2]); float xscale = (float) RValue_toReal(args[3]); float yscale = (float) RValue_toReal(args[4]); - uint32_t color = (uint32_t) RValue_toInt32(args[5]); + uint32_t color = RValue_toColour(args[5]); float alpha = (float) RValue_toReal(args[6]); Runner* runner = ctx->runner; if (runner->renderer != nullptr) { @@ -11204,21 +11204,21 @@ static void Color_RGBtoHSV(int32_t col, GMLReal* outH, GMLReal* outS, GMLReal* o static RValue builtin_color_get_hue(MAYBE_UNUSED VMContext* ctx, RValue* args, int32_t argCount) { if (1 > argCount) return RValue_makeReal(0.0); GMLReal h, s, v; - Color_RGBtoHSV(RValue_toInt32(args[0]), &h, &s, &v); + Color_RGBtoHSV((int32_t) RValue_toColour(args[0]), &h, &s, &v); return RValue_makeReal(h); } static RValue builtin_color_get_saturation(MAYBE_UNUSED VMContext* ctx, RValue* args, int32_t argCount) { if (1 > argCount) return RValue_makeReal(0.0); GMLReal h, s, v; - Color_RGBtoHSV(RValue_toInt32(args[0]), &h, &s, &v); + Color_RGBtoHSV((int32_t) RValue_toColour(args[0]), &h, &s, &v); return RValue_makeReal(s); } static RValue builtin_color_get_value(MAYBE_UNUSED VMContext* ctx, RValue* args, int32_t argCount) { if (1 > argCount) return RValue_makeReal(0.0); GMLReal h, s, v; - Color_RGBtoHSV(RValue_toInt32(args[0]), &h, &s, &v); + Color_RGBtoHSV((int32_t) RValue_toColour(args[0]), &h, &s, &v); return RValue_makeReal(v); } @@ -12673,7 +12673,7 @@ static RValue builtin_action_sprite_set(VMContext* ctx, RValue* args, MAYBE_UNUS static RValue builtin_action_sprite_color(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Instance* inst = ctx->currentInstance; if (inst == nullptr) return RValue_makeUndefined(); - inst->imageBlend = (uint32_t) RValue_toInt32(args[0]); + inst->imageBlend = RValue_toColour(args[0]); inst->imageAlpha = (float) RValue_toReal(args[1]); return RValue_makeUndefined(); } @@ -12734,7 +12734,7 @@ static RValue builtin_action_reverse_ydir(VMContext* ctx, MAYBE_UNUSED RValue* a static RValue builtin_action_color(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Runner* runner = ctx->runner; if (runner->renderer != nullptr) { - runner->renderer->drawColor = (uint32_t) RValue_toInt32(args[0]); + runner->renderer->drawColor = RValue_toColour(args[0]); } return RValue_makeUndefined(); } @@ -13468,7 +13468,7 @@ static RValue builtin_layer_background_stretch(VMContext* ctx, RValue* args, MAY static RValue builtin_layer_background_blend(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) { Runner* runner = ctx->runner; int32_t id = RValue_toInt32(args[0]); - uint32_t blend = (uint32_t) RValue_toInt32(args[1]) & 0x00FFFFFF; + uint32_t blend = RValue_toColour(args[1]) & 0x00FFFFFF; RuntimeBackgroundElement* bg = findBackgroundElement(runner, id); if (bg != nullptr) bg->blend = blend; @@ -16497,10 +16497,10 @@ static RValue builtin_gpu_set_fog(VMContext* ctx, RValue* args, int32_t argCount if (argCount == 1 && args[0].type == RVALUE_ARRAY && args[0].array != nullptr && GMLArray_length1D(args[0].array) >= 2) { GMLArray* arr = args[0].array; enable = RValue_toBool(*GMLArray_slot(arr, 0)); - color = RValue_toInt32(*GMLArray_slot(arr, 1)); + color = (int32_t) RValue_toColour(*GMLArray_slot(arr, 1)); } else if (argCount >= 2) { enable = RValue_toBool(args[0]); - color = RValue_toInt32(args[1]); + color = (int32_t) RValue_toColour(args[1]); } else { return RValue_makeUndefined(); }