Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1550,9 +1550,14 @@ static void handleDiv(VMContext* ctx, uint32_t instr) {
static void handleRem(VMContext* ctx, uint32_t instr) {
RValue b = stackPop(ctx);
RValue a = stackPop(ctx);
int64_t divisor = RValue_toInt64(b);
requireMessageFormatted(__FILE__, __LINE__, divisor != 0, "VM: [%s] DoRem :: Divide by zero", ctx->currentCodeName);
int64_t result = RValue_toInt64(a) / divisor;
uint8_t type1 = instrType1(instr);
uint8_t type2 = instrType2(instr);
GMLReal divisor = RValue_toReal(b);
// Ditto
if ((type1 == GML_TYPE_INT32 || type1 == GML_TYPE_INT64) && (type2 == GML_TYPE_INT32 || type2 == GML_TYPE_INT64)) {
requireMessageFormatted(__FILE__, __LINE__, divisor != 0.0, "VM: [%s] DoRem :: Divide by zero", ctx->currentCodeName);
}
GMLReal result = GMLReal_fmod(RValue_toReal(a), divisor);
RValue_free(&a);
RValue_free(&b);
stackPushTyped(ctx, RValue_makeInt64(result), instrType2(instr));
Expand Down
98 changes: 93 additions & 5 deletions src/vm_builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -7866,6 +7866,12 @@ static RValue builtin_window_get_cursor(VMContext* ctx, MAYBE_UNUSED RValue* arg
return RValue_makeReal(runner->currentCursor);
}

// ===[ Date Functions ]===
static RValue builtin_date_current_datetime(VMContext* ctx, MAYBE_UNUSED RValue* args, MAYBE_UNUSED int32_t argCount) {
time_t now = time(NULL);
return RValue_makeReal((GMLReal)now / (GMLReal)86400 + (GMLReal)25569);
}

// ===[ Game State Functions ]===
static RValue builtin_game_restart(VMContext* ctx, MAYBE_UNUSED RValue* args, MAYBE_UNUSED int32_t argCount) {
ctx->runner->pendingRoom = ROOM_RESTARTGAME;
Expand Down Expand Up @@ -13536,9 +13542,8 @@ static RValue builtin_layer_tile_visible(VMContext* ctx, RValue* args, MAYBE_UNU
}

static bool isValidLayerSpriteElement(RuntimeLayerElement* element) {
bool isValid = element != nullptr && element->type == RuntimeLayerElementType_Sprite;
requireNotNull(element->spriteElement); // If this crashes then something went DEEPLY wrong
return isValid;
return element != nullptr && element->spriteElement != nullptr && \
element->type == RuntimeLayerElementType_Sprite;
}

static RValue builtin_layer_sprite_get_id(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
Expand Down Expand Up @@ -14086,14 +14091,14 @@ static RValue builtin_tile_get_index(MAYBE_UNUSED VMContext* ctx, RValue* args,
// (see GameMaker-HTML5 Function_Layers.js)
static RValue builtin_tile_get_mirror(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
if (1 > argCount) return RValue_makeBool(false);
return RValue_makeBool((RValue_toInt32(args[0]) & (1 << 28)) != 0);
return RValue_makeBool((RValue_toInt32(args[0]) & TILEMIRROR_MASK) != 0);
}

// tile_get_flip(tiledata): returns whether the vertical-flip bit is set on a raw tile cell value.
// (see GameMaker-HTML5 Function_Layers.js)
static RValue builtin_tile_get_flip(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
if (1 > argCount) return RValue_makeBool(false);
return RValue_makeBool((RValue_toInt32(args[0]) & (1 << 29)) != 0);
return RValue_makeBool((RValue_toInt32(args[0]) & TILEFLIP_MASK) != 0);
}

// tile_get_rotate(tiledata): returns whether the 90-degree-rotate bit is set on a raw tile cell value.
Expand All @@ -14110,6 +14115,42 @@ static RValue builtin_tile_set_empty(MAYBE_UNUSED VMContext* ctx, RValue* args,
return RValue_makeReal((GMLReal) (RValue_toInt32(args[0]) & ~TILEINDEX_SHIFTEDMASK));
}

// tile_set_mirror(tiledata): sets the horizontal-mirror bit on a raw tile cell value.
// (see GameMaker-HTML5 Function_Layers.js)
static RValue builtin_tile_set_mirror(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
if (2 > argCount) return RValue_makeReal(-1.0);
int32_t cell = RValue_toInt32(args[0]);
if (RValue_toBool(args[1]))
cell |= TILEMIRROR_MASK;
else
cell &= ~TILEMIRROR_MASK;
return RValue_makeReal((GMLReal) cell);
}

// tile_set_flip(tiledata): sets the vertical-flip bit on a raw tile cell value.
// (see GameMaker-HTML5 Function_Layers.js)
static RValue builtin_tile_set_flip(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
if (2 > argCount) return RValue_makeReal(-1.0);
int32_t cell = RValue_toInt32(args[0]);
if (RValue_toBool(args[1]))
cell |= TILEFLIP_MASK;
else
cell &= ~TILEFLIP_MASK;
return RValue_makeReal((GMLReal) cell);
}

// tile_set_rotate(tiledata): sets the 90-degree-rotate bit on a raw tile cell value.
// (see GameMaker-HTML5 Function_Layers.js)
static RValue builtin_tile_set_rotate(MAYBE_UNUSED VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
if (2 > argCount) return RValue_makeReal(-1.0);
int32_t cell = RValue_toInt32(args[0]);
if (RValue_toBool(args[1]))
cell |= TILEROTATE_MASK;
else
cell &= ~TILEROTATE_MASK;
return RValue_makeReal((GMLReal) cell);
}

static RValue builtin_layer_get_all(VMContext* ctx, MAYBE_UNUSED RValue* args, MAYBE_UNUSED int32_t argCount) {
Runner* runner = ctx->runner;
size_t count = arrlenu(runner->runtimeLayers);
Expand Down Expand Up @@ -14338,6 +14379,46 @@ static GamePath* getPath(Runner* runner, int32_t pathIdx) {
return &runner->dataWin->path.paths[pathIdx];
}

// draw_path(index, x, y, absolute) - draws a path outline using the current draw color/alpha
static RValue builtin_draw_path(VMContext* ctx, RValue* args, MAYBE_UNUSED int32_t argCount) {
Runner* runner = ctx->runner;
if (runner->renderer == nullptr) return RValue_makeUndefined();

int32_t index = RValue_toInt32(args[0]);
GMLReal x = RValue_toReal(args[1]);
GMLReal y = RValue_toReal(args[2]);
bool absolute = RValue_toBool(args[3]);

GamePath* path = getPath(runner, index);
if (path == nullptr) return RValue_makeUndefined();

PathPositionResult origin = GamePath_getPosition(path, 0.0f);

float xoff = absolute ? 0.0f : x - origin.x;
float yoff = absolute ? 0.0f : y - origin.y;

if (runner->applyOffsetForPrimitives) {
xoff += 1.0f;
yoff += 1.0f;
}

int maxsteps = (int) roundf(path->length / 4.0f);
if (maxsteps <= 0) return RValue_makeUndefined();

PathPositionResult prev = GamePath_getPosition(path, 0.0f);
for (int i = 1; i <= maxsteps; i++) {
float t = (float) i / (float) maxsteps;
PathPositionResult cur = GamePath_getPosition(path, t);
runner->renderer->vtable->drawLine(runner->renderer,
xoff + prev.x, yoff + prev.y,
xoff + cur.x, yoff + cur.y,
1.0f, runner->renderer->drawColor, runner->renderer->drawAlpha);
prev = cur;
}

return RValue_makeUndefined();
}

// path_add() - create a new empty path, return its index
static RValue builtin_path_add(VMContext* ctx, MAYBE_UNUSED RValue* args, MAYBE_UNUSED int32_t argCount) {
Runner* runner = ctx->runner;
Expand Down Expand Up @@ -16718,6 +16799,9 @@ void VMBuiltins_registerAll(VMContext* ctx) {
VM_registerBuiltin(ctx, "window_set_cursor", builtin_window_set_cursor);
VM_registerBuiltin(ctx, "window_get_cursor", builtin_window_get_cursor);

// Date
VM_registerBuiltin(ctx, "date_current_datetime", builtin_date_current_datetime);

// Game
VM_registerBuiltin(ctx, "game_restart", builtin_game_restart);
VM_registerBuiltin(ctx, "game_end", builtin_game_end);
Expand Down Expand Up @@ -16887,6 +16971,7 @@ void VMBuiltins_registerAll(VMContext* ctx) {
VM_registerBuiltin(ctx, "draw_ellipse_color", builtin_draw_ellipse_color);
VM_registerBuiltin(ctx, "draw_set_circle_precision", builtin_draw_set_circle_precision);
VM_registerBuiltin(ctx, "draw_get_circle_precision", builtin_draw_get_circle_precision);
VM_registerBuiltin(ctx, "draw_path", builtin_draw_path);
VM_registerBuiltin(ctx, "draw_set_colour", builtin_draw_set_colour);
VM_registerBuiltin(ctx, "draw_get_colour", builtin_draw_get_colour);
VM_registerBuiltin(ctx, "draw_get_color", builtin_draw_get_color);
Expand Down Expand Up @@ -17079,6 +17164,9 @@ void VMBuiltins_registerAll(VMContext* ctx) {
VM_registerBuiltin(ctx, "tile_get_flip", builtin_tile_get_flip);
VM_registerBuiltin(ctx, "tile_get_rotate", builtin_tile_get_rotate);
VM_registerBuiltin(ctx, "tile_set_empty", builtin_tile_set_empty);
VM_registerBuiltin(ctx, "tile_set_mirror", builtin_tile_set_mirror);
VM_registerBuiltin(ctx, "tile_set_flip", builtin_tile_set_flip);
VM_registerBuiltin(ctx, "tile_set_rotate", builtin_tile_set_rotate);
VM_registerBuiltin(ctx, "tilemap_set", builtin_tilemap_set);
VM_registerBuiltin(ctx, "tilemap_set_at_pixel", builtin_tilemap_set_at_pixel);
#endif
Expand Down
Loading