diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c
index 4316e04..c13a5fc 100644
--- a/src/engine/behavior_script.c
+++ b/src/engine/behavior_script.c
@@ -11,6 +11,7 @@
 #include "game/obj_behaviors_2.h"
 #include "game/object_helpers.h"
 #include "game/object_list_processor.h"
+#include "game/level_update.h" // Frameskip
 #include "graph_node.h"
 #include "surface_collision.h"
 
@@ -919,6 +920,14 @@ void cur_obj_update(void) {
     f32 distanceFromMario;
     BhvCommandProc bhvCmdProc;
     s32 bhvProcResult;
+#ifdef TARGET_N64
+    s32 hasAnimation = (gCurrentObject->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0;
+    // frameskip
+    if ((doneSkipped >= 0) && hasAnimation && gCurrentObject->header.gfx.animInfo.curAnim != NULL) {
+        gCurrentObject->header.gfx.animInfo.animFrame = geo_update_animation_frame(
+            &gCurrentObject->header.gfx.animInfo, &gCurrentObject->header.gfx.animInfo.animFrameAccelAssist);
+    }
+#endif
 
     // Calculate the distance from the object to Mario.
     if (objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) {
@@ -1014,4 +1023,12 @@ void cur_obj_update(void) {
             }
         }
     }
+
+#ifdef TARGET_N64
+    // frameskip
+    if (gCurrentObject->header.gfx.animInfo.animFrame < 0) {
+        gCurrentObject->header.gfx.animInfo.animFrame = 0;
+    }
+#endif
+
 }
diff --git a/src/game/level_update.c b/src/game/level_update.c
index 8f28b73..fe837a2 100644
--- a/src/game/level_update.c
+++ b/src/game/level_update.c
@@ -213,6 +213,14 @@ s8 sWarpCheckpointActive = FALSE;
 u8 unused2[4];
 u8 unused3[2];
 
+#ifdef TARGET_N64
+// Frameskip
+u64 deltaTime = 0;
+u64 newTime = 0;
+u64 oldTime = 0;
+s8 doneSkipped;
+#endif
+
 u16 level_control_timer(s32 timerOp) {
     switch (timerOp) {
         case TIMER_CONTROL_SHOW:
@@ -1008,6 +1016,31 @@ void basic_update(UNUSED s16 *arg) {
     }
 }
 
+#ifdef TARGET_N64
+void delta_time_handle(void) {
+    OSTime newTime = osGetTime();
+    
+    doneSkipped = -1;
+    deltaTime += newTime - oldTime;
+    oldTime = newTime;
+    while (deltaTime > 1562744) {
+        deltaTime -= 1562744;
+        if (sTimerRunning && gHudDisplay.timer < 17999) {
+            gHudDisplay.timer += 1;
+        }
+        area_update_objects();
+        doneSkipped++;
+    }
+}  
+#endif
+
+static void delta_time_reset(void) {
+#ifdef TARGET_N64
+    deltaTime = 0;
+    oldTime = osGetTime();
+#endif
+}
+
 s32 play_mode_normal(void) {
     if (gCurrDemoInput != NULL) {
         print_intro_text();
@@ -1023,11 +1056,19 @@ s32 play_mode_normal(void) {
     warp_area();
     check_instant_warp();
 
+// Only N64 - shouldn't be necessary in pc-port
+#ifdef TARGET_N64
+    delta_time_handle();
+#else
     if (sTimerRunning && gHudDisplay.timer < 17999) {
         gHudDisplay.timer++;
     }
 
     area_update_objects();
+    // put fast64's scroll_textures() function here for pc-port
+    // scroll_textures();
+#endif
+
     update_hud_values();
 
     if (gCurrentArea != NULL) {
@@ -1207,15 +1248,19 @@ s32 update_level(void) {
             break;
         case PLAY_MODE_PAUSED:
             changeLevel = play_mode_paused();
+            delta_time_reset();
             break;
         case PLAY_MODE_CHANGE_AREA:
             changeLevel = play_mode_change_area();
+            delta_time_reset();
             break;
         case PLAY_MODE_CHANGE_LEVEL:
             changeLevel = play_mode_change_level();
+            delta_time_reset();
             break;
         case PLAY_MODE_FRAME_ADVANCE:
             changeLevel = play_mode_frame_advance();
+            delta_time_reset();
             break;
 #if QOL_FIX_UNUSED_PLAY_MODE
         default:
@@ -1320,6 +1365,7 @@ s32 lvl_init_or_update(s16 initOrUpdate, UNUSED s32 unused) {
     switch (initOrUpdate) {
         case 0:
             result = init_level();
+            delta_time_reset();
             break;
         case 1:
             result = update_level();
diff --git a/src/game/level_update.h b/src/game/level_update.h
index 2ca79e1..05c54c3 100644
--- a/src/game/level_update.h
+++ b/src/game/level_update.h
@@ -71,6 +71,11 @@ extern s16 sTransitionTimer;
 extern void (*sTransitionUpdate)(s16 *);
 extern u8 unused2[4];
 
+#ifdef TARGET_N64
+// Frameskip
+extern s8 doneSkipped;
+#endif
+
 struct WarpDest {
     u8 type;
     u8 levelNum;
diff --git a/src/game/mario.c b/src/game/mario.c
index fd3a4b5..7daa056 100644
--- a/src/game/mario.c
+++ b/src/game/mario.c
@@ -1405,6 +1405,12 @@ void update_mario_inputs(struct MarioState *m) {
     m->collidedObjInteractTypes = m->marioObj->collidedObjInteractTypes;
     m->flags &= 0xFFFFFF;
 
+#ifdef TARGET_N64
+    if (doneSkipped >= 0) {
+        m->controller->buttonPressed = 0;
+    }
+#endif
+
     update_mario_button_inputs(m);
     update_mario_joystick_inputs(m);
     update_mario_geometry_inputs(m);