Skip to content

argument[0][i] and 32bit colour fix (Platformer mode fix) - #385

Open
Ananim353 wants to merge 2 commits into
ButterscotchRunner:mainfrom
Ananim353:vm-array-index-and-32bit-colour
Open

argument[0][i] and 32bit colour fix (Platformer mode fix)#385
Ananim353 wants to merge 2 commits into
ButterscotchRunner:mainfrom
Ananim353:vm-array-index-and-32bit-colour

Conversation

@Ananim353

Copy link
Copy Markdown

Fix 1: argument[0][i] returned undefined (src/vm.c)

Fix 2: colours that do not fit a signed int32 turned black (rvalue.h, utils.h, vm_builtins.c)

Also fix Color_lerp truncated instead of rounding (0x7F7F7F vs GameMaker's 0x808080 at t = 0.5),

image

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.
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant