diff --git a/source/games/sw/src/actor.cpp b/source/games/sw/src/actor.cpp
index b48984be2..4c36dd38c 100644
--- a/source/games/sw/src/actor.cpp
+++ b/source/games/sw/src/actor.cpp
@@ -1091,11 +1091,11 @@ bool DSWActor::hasState(FName label, int subl)
     return getLegacyState(a, label, subl) != nullptr;
 }
 
-void DSWActor::setActionDecide() { user.__legacyState.ActorActionFunc = DoActorDecide; }
+void DSWActor::setActionDecide() { user.__legacyState.ActorActionFunc = *AF(DoActorDecide); }
 
 void DSWActor::callAction()
 {
-    (*user.__legacyState.ActorActionFunc)(this);
+    callFunction(user.__legacyState.ActorActionFunc);
 }
 
 void DSWActor::callStateAction()
@@ -1104,13 +1104,14 @@ void DSWActor::callStateAction()
 		callFunction(*user.__legacyState.State->Animator);
 }
 
-void DSWActor::callFunction(VMFunction* func)
+int DSWActor::callFunction(VMFunction* func)
 {
     if (func)
     {
         VMValue param[] = { this };
         VMCall(func, param, 1, nullptr, 0);
     }
+    return 0;
 }
 
 END_SW_NS
diff --git a/source/games/sw/src/ai.cpp b/source/games/sw/src/ai.cpp
index 47b95ea43..dd95f19aa 100644
--- a/source/games/sw/src/ai.cpp
+++ b/source/games/sw/src/ai.cpp
@@ -687,7 +687,7 @@ int DoActorDecide(DSWActor* actor)
 
 int InitActorMoveCloser(DSWActor* actor)
 {
-    actor->user.__legacyState.ActorActionFunc = DoActorMoveCloser;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoActorMoveCloser);
 
     if (!actor->checkStateGroup(NAME_Run))
         actor->setStateGroup(NAME_Run);
@@ -1040,7 +1040,7 @@ int InitActorAttack(DSWActor* actor)
         return 0;
     }
 
-    actor->user.__legacyState.ActorActionFunc = DoActorAttack;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoActorAttack);
 
     // move into standing frame
     //actor->setStateGroup(NAME_Stand);
@@ -1211,7 +1211,7 @@ int InitActorDuck(DSWActor* actor)
         return 0;
     }
 
-    actor->user.__legacyState.ActorActionFunc = DoActorDuck;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoActorDuck);
     actor->setStateGroup(NAME_Duck);
 
 	double dist = (actor->spr.pos.XY() - actor->user.targetActor->spr.pos.XY()).LengthSquared();
@@ -1562,7 +1562,7 @@ int InitActorReposition(DSWActor* actor)
     }
 
 
-    actor->user.__legacyState.ActorActionFunc = DoActorReposition;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoActorReposition);
     if (!(actor->user.Flags & SPR_SWIMMING))
         actor->setStateGroup(NAME_Run);
 
@@ -1608,7 +1608,7 @@ int DoActorReposition(DSWActor* actor)
 
 int InitActorPause(DSWActor* actor)
 {
-    actor->user.__legacyState.ActorActionFunc = DoActorPause;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoActorPause);
 
     actor->callAction();
 
diff --git a/source/games/sw/src/bunny.cpp b/source/games/sw/src/bunny.cpp
index 342b4047c..fb80ae677 100644
--- a/source/games/sw/src/bunny.cpp
+++ b/source/games/sw/src/bunny.cpp
@@ -1171,7 +1171,7 @@ void BunnyHatch(DSWActor* actor)
         actorNew->user.ShellNum = 0; // Not Pregnant right now
 
         actorNew->setStateGroup(NAME_Jump);
-        actorNew->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+        actorNew->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
         DoActorSetSpeed(actorNew, FAST_SPEED);
         PickJumpMaxSpeed(actorNew, -600);
 
@@ -1219,7 +1219,7 @@ DSWActor* BunnyHatch2(DSWActor* actor)
     actorNew->user.ShellNum = 0; // Not Pregnant right now
 
     actorNew->setStateGroup(NAME_Jump);
-    actorNew->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+    actorNew->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
     DoActorSetSpeed(actorNew, FAST_SPEED);
     if (TEST_BOOL3(actor))
     {
@@ -1308,7 +1308,7 @@ int DoBunnyMove(DSWActor* actor)
 			actor->spr.Angles.Yaw = RandomAngle();
             actor->user.jump_speed = -350;
             DoActorBeginJump(actor);
-            actor->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
         }
     }
 
diff --git a/source/games/sw/src/coolg.cpp b/source/games/sw/src/coolg.cpp
index 369d4327e..e6803b27c 100644
--- a/source/games/sw/src/coolg.cpp
+++ b/source/games/sw/src/coolg.cpp
@@ -695,7 +695,7 @@ int DoCoolgMatchPlayerZ(DSWActor* actor)
 
 int InitCoolgCircle(DSWActor* actor)
 {
-    actor->user.__legacyState.ActorActionFunc = DoCoolgCircle;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoCoolgCircle);
 
     actor->setStateGroup(NAME_Run);
 
diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h
index 6b58afd60..89eab0cd5 100644
--- a/source/games/sw/src/game.h
+++ b/source/games/sw/src/game.h
@@ -341,7 +341,6 @@ struct PANEL_SPRITE;
 struct ANIM;
 class DSWActor;
 
-typedef int ANIMATOR (DSWActor* actor);
 typedef void pANIMATOR (PANEL_SPRITE*);
 typedef void (*soANIMATORp) (SECTOR_OBJECT*);
 
@@ -711,7 +710,7 @@ struct USER
         STATE** StateFallOverride; // a bit kludgy - override std fall state
         ACTOR_ACTION_SET* ActorActionSet;
         int16_t RotNum;
-        ANIMATOR* ActorActionFunc;
+        VMFunction* ActorActionFunc;
         PERSONALITY* Personality;
         ATTRIBUTE* Attrib;
 
@@ -1437,8 +1436,6 @@ void StopPlayerSound(PLAYER* pp, int which = -1);
  bool SoundValidAndActive(DSWActor* spr, int channel);
 
 
-ANIMATOR DoActorBeginJump,DoActorJump,DoActorBeginFall,DoActorFall,DoActorDeathMove;
-
 struct BREAK_INFO;
 int SpawnShrap(DSWActor*, DSWActor*, int = -1, BREAK_INFO* breakinfo = nullptr);
 
@@ -2446,6 +2443,31 @@ DEF_ANIMATOR(InitRipper2Hang)
 DEF_ANIMATOR(InitRipperHang)
 DEF_ANIMATOR(InitActorRunToward)
 DEF_ANIMATOR(InitActorSetDecide)
+DEF_ANIMATOR(DoActorDecide)
+DEF_ANIMATOR(DoActorMoveJump)
+DEF_ANIMATOR(DoActorDuck)
+DEF_ANIMATOR(NinjaJumpActionFunc)
+DEF_ANIMATOR(DoActorMoveCloser)
+DEF_ANIMATOR(DoActorAttack)
+DEF_ANIMATOR(DoActorReposition)
+DEF_ANIMATOR(DoCoolgCircle)
+DEF_ANIMATOR(DoHornetCircle)
+DEF_ANIMATOR(GenerateDrips)
+DEF_ANIMATOR(DoSpawnSpot)
+DEF_ANIMATOR(DoGrating)
+DEF_ANIMATOR(DoVator)
+DEF_ANIMATOR(DoVatorAuto)
+DEF_ANIMATOR(DoRotator)
+DEF_ANIMATOR(DoActorPause)
+DEF_ANIMATOR(DoSlidor)
+DEF_ANIMATOR(DoSpike)
+DEF_ANIMATOR(DoSpikeAuto)
+DEF_ANIMATOR(DoLavaErupt)
+DEF_ANIMATOR(SpawnVehicleSmoke)
+DEF_ANIMATOR(DoLaserStart)
+DEF_ANIMATOR(DoTracerStart)
+DEF_ANIMATOR(DoRailStart)
+
 END_SW_NS
 
 #endif
diff --git a/source/games/sw/src/hornet.cpp b/source/games/sw/src/hornet.cpp
index 8d2c2e3be..c76988a54 100644
--- a/source/games/sw/src/hornet.cpp
+++ b/source/games/sw/src/hornet.cpp
@@ -413,7 +413,7 @@ int DoHornetMatchPlayerZ(DSWActor* actor)
 
 int InitHornetCircle(DSWActor* actor)
 {
-    actor->user.__legacyState.ActorActionFunc = DoHornetCircle;
+    actor->user.__legacyState.ActorActionFunc = *AF(DoHornetCircle);
 
     actor->setStateGroup(NAME_Run);
 
diff --git a/source/games/sw/src/jsector.cpp b/source/games/sw/src/jsector.cpp
index d9c676044..c8f766879 100644
--- a/source/games/sw/src/jsector.cpp
+++ b/source/games/sw/src/jsector.cpp
@@ -135,8 +135,6 @@ short CheckTileSound(short picnum)
     return sndnum;
 }
 
-ANIMATOR GenerateDrips;
-
 /////////////////////////////////////////////////////
 //  Initialize any of my special use sprites
 /////////////////////////////////////////////////////
@@ -185,7 +183,7 @@ void JS_SpriteSetup(void)
                 itActor->user.__legacyState.RotNum = 0;
                 itActor->user.WaitTics = itActor->spr.lotag * 120;
 
-                itActor->user.__legacyState.ActorActionFunc = GenerateDrips;
+                itActor->user.__legacyState.ActorActionFunc = *AF(GenerateDrips);
 
                 change_actor_stat(itActor, STAT_NO_STATE);
                 itActor->spr.cstat |= CSTAT_SPRITE_INVISIBLE;
diff --git a/source/games/sw/src/jweapon.cpp b/source/games/sw/src/jweapon.cpp
index 71e1375fb..60914db55 100644
--- a/source/games/sw/src/jweapon.cpp
+++ b/source/games/sw/src/jweapon.cpp
@@ -1275,7 +1275,7 @@ int PlayerInitChemBomb(PLAYER* pp)
     plActor->clipdist = 0;
     actorNew->clipdist = 0;
 
-    MissileSetPos(actorNew, DoChemBomb, 1000);
+    MissileSetPos(actorNew, *AF(DoChemBomb), 1000);
 
     plActor->clipdist = oclipdist;
     actorNew->clipdist = 5;
@@ -1645,7 +1645,7 @@ int PlayerInitCaltrops(PLAYER* pp)
     plActor->clipdist = 0;
     actorNew->clipdist = 0;
 
-    MissileSetPos(actorNew, DoCaltrops, 1000);
+    MissileSetPos(actorNew, *AF(DoCaltrops), 1000);
 
     plActor->clipdist = oclipdist;
     actorNew->clipdist = 5;
diff --git a/source/games/sw/src/misc.h b/source/games/sw/src/misc.h
index a91b03987..5346eaf2d 100644
--- a/source/games/sw/src/misc.h
+++ b/source/games/sw/src/misc.h
@@ -39,11 +39,15 @@ void PlaceSectorObjectsOnTracks(void);
 void PlaceActorsOnTracks(void);
 void SetupSectorObject(sectortype* sect, short tag);
 void PostSetupSectorObject(void);
-void VehicleSetSmoke(SECTOR_OBJECT* sop, ANIMATOR* animator);
+void VehicleSetSmoke(SECTOR_OBJECT* sop, VMFunction* animator);
 void CollapseSectorObject(SECTOR_OBJECT* sop, const DVector2& pos);
 void KillSectorObjectSprites(SECTOR_OBJECT* sop);
 void MoveSectorObjects(SECTOR_OBJECT* sop, short locktics);
 
+int DoActorBeginJump(DSWActor* actor);
+int DoActorBeginFall(DSWActor* actor);
+int DoActorFall(DSWActor* actor);
+
 #define TEXT_INFO_TIME (3)
 #define TEXT_INFO_Y (40)
 #define TEXT_INFO_YOFF (10)
diff --git a/source/games/sw/src/panel.cpp b/source/games/sw/src/panel.cpp
index e542968e2..2fb4f3417 100644
--- a/source/games/sw/src/panel.cpp
+++ b/source/games/sw/src/panel.cpp
@@ -95,8 +95,6 @@ pANIMATOR pNullAnimator;
 int InitStar(PLAYER*);
 int ChangeWeapon(PLAYER*);
 
-ANIMATOR InitFire;
-
 int NullAnimator(DSWActor*)
 {
     return 0;
diff --git a/source/games/sw/src/ripper.cpp b/source/games/sw/src/ripper.cpp
index 6c5071117..38b1c2686 100644
--- a/source/games/sw/src/ripper.cpp
+++ b/source/games/sw/src/ripper.cpp
@@ -1227,7 +1227,7 @@ void RipperHatch(DSWActor* actor)
         actorNew->user.Flags |= (SPR_ACTIVE);
 
         actorNew->setStateGroup(NAME_Jump);
-        actorNew->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+        actorNew->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
         DoActorSetSpeed(actorNew, FAST_SPEED);
         PickJumpMaxSpeed(actorNew, -600);
 
diff --git a/source/games/sw/src/ripper2.cpp b/source/games/sw/src/ripper2.cpp
index 494b34c24..3cf5fc8d0 100644
--- a/source/games/sw/src/ripper2.cpp
+++ b/source/games/sw/src/ripper2.cpp
@@ -1235,7 +1235,7 @@ void Ripper2Hatch(DSWActor* actor)
         actorNew->user.Flags |= (SPR_ACTIVE);
 
         actorNew->setStateGroup(NAME_Jump);
-        actorNew->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+        actorNew->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
         DoActorSetSpeed(actorNew, FAST_SPEED);
         PickJumpMaxSpeed(actorNew, -600);
 
diff --git a/source/games/sw/src/sector.cpp b/source/games/sw/src/sector.cpp
index a82b89908..434b72df4 100644
--- a/source/games/sw/src/sector.cpp
+++ b/source/games/sw/src/sector.cpp
@@ -1006,7 +1006,7 @@ void DoSpawnSpotsForKill(short match)
         if (actor->spr.hitag == SPAWN_SPOT && actor->spr.lotag == match)
         {
             change_actor_stat(actor, STAT_NO_STATE);
-            actor->user.__legacyState.ActorActionFunc = DoSpawnSpot;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoSpawnSpot);
             actor->user.WaitTics = SP_TAG5(actor) * 15;
             SetActorZ(actor, actor->spr.pos);
             // setting for Killed
@@ -1033,7 +1033,7 @@ void DoSpawnSpotsForDamage(short match)
         if (actor->spr.hitag == SPAWN_SPOT && actor->spr.lotag == match)
         {
             change_actor_stat(actor, STAT_NO_STATE);
-            actor->user.__legacyState.ActorActionFunc = DoSpawnSpot;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoSpawnSpot);
             actor->user.WaitTics = SP_TAG7(actor) * 15;
             // setting for Damaged
             actor->user.LastDamage = 0;
@@ -1776,7 +1776,7 @@ int OperateSprite(DSWActor* actor, short player_is_operating)
 
         SpawnUser(actor, 0, nullptr);
 
-        actor->user.__legacyState.ActorActionFunc = DoGrating;
+        actor->user.__legacyState.ActorActionFunc = *AF(DoGrating);
 
         actor->spr.lotag = 0;
         actor->spr.hitag /= 2;
diff --git a/source/games/sw/src/sprite.cpp b/source/games/sw/src/sprite.cpp
index ab9a3e5fa..15a0260b3 100644
--- a/source/games/sw/src/sprite.cpp
+++ b/source/games/sw/src/sprite.cpp
@@ -85,11 +85,6 @@ int SetupPachinko2(DSWActor*);
 int SetupPachinko3(DSWActor*);
 int SetupPachinko4(DSWActor*);
 int SetupGirlNinja(DSWActor*);
-ANIMATOR DoVator, DoVatorAuto;
-ANIMATOR DoRotator;
-ANIMATOR DoSlidor;
-ANIMATOR DoSpike, DoSpikeAuto;
-ANIMATOR DoLavaErupt;
 int DoSlidorInstantClose(DSWActor*);
 
 void InitWeaponRocket(PLAYER*);
@@ -1473,7 +1468,7 @@ void SpriteSetupPost(void)
             jActor->user.ceiling_dist = 4;
             jActor->user.floor_dist = -2;
 
-            jActor->user.__legacyState.ActorActionFunc = DoActorDebris;
+            jActor->user.__legacyState.ActorActionFunc = *AF(DoActorDebris);
 
             jActor->spr.cstat |= CSTAT_SPRITE_BREAKABLE;
             jActor->spr.extra |= SPRX_BREAKABLE;
@@ -1965,18 +1960,18 @@ void SpriteSetup(void)
                     {
                     case 0:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoVator;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoVator);
                         break;
                     case 1:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoVator;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoVator);
                         break;
                     case 2:
-                        actor->user.__legacyState.ActorActionFunc = DoVatorAuto;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoVatorAuto);
                         break;
                     case 3:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoVatorAuto;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoVatorAuto);
                         break;
                     }
 
@@ -2073,11 +2068,11 @@ void SpriteSetup(void)
                     {
                     case 0:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoRotator;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoRotator);
                         break;
                     case 1:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoRotator;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoRotator);
                         break;
                     }
 
@@ -2118,11 +2113,11 @@ void SpriteSetup(void)
                     {
                     case 0:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoSlidor;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoSlidor);
                         break;
                     case 1:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoSlidor;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoSlidor);
                         break;
                     }
 
@@ -2166,18 +2161,18 @@ void SpriteSetup(void)
                     {
                     case 0:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoSpike;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoSpike);
                         break;
                     case 1:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoSpike;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoSpike);
                         break;
                     case 2:
-                        actor->user.__legacyState.ActorActionFunc = DoSpikeAuto;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoSpikeAuto);
                         break;
                     case 3:
                         actor->user.Flags &= ~(SPR_ACTIVE);
-                        actor->user.__legacyState.ActorActionFunc = DoSpikeAuto;
+                        actor->user.__legacyState.ActorActionFunc = *AF(DoSpikeAuto);
                         break;
                     }
 
@@ -2354,7 +2349,7 @@ void SpriteSetup(void)
                     SpawnUser(actor, ST1, nullptr);
 
                     change_actor_stat(actor, STAT_NO_STATE);
-                    actor->user.__legacyState.ActorActionFunc = DoLavaErupt;
+                    actor->user.__legacyState.ActorActionFunc = *AF(DoLavaErupt);
 
                     // interval between erupts
                     if (SP_TAG10(actor) == 0)
@@ -5914,8 +5909,7 @@ int  StateControl(DSWActor* actor)
 
     if (!actor->user.__legacyState.State)
     {
-        ASSERT(actor->user.__legacyState.ActorActionFunc);
-        (actor->user.__legacyState.ActorActionFunc)(actor);
+        actor->callAction();
         return 0;
     }
 
@@ -6084,8 +6078,7 @@ void SpriteControl(void)
     it.Reset(STAT_NO_STATE);
     while (auto actor = it.Next())
     {
-        if (actor->hasU() && actor->user.__legacyState.ActorActionFunc)
-            actor->user.__legacyState.ActorActionFunc(actor);
+        if (actor->hasU()) actor->callAction();
     }
 
     if (MoveSkip8 == 0)
@@ -6124,7 +6117,7 @@ void SpriteControl(void)
         if (!(actor->user.Flags & SPR_ACTIVE))
             continue;
 
-        actor->user.__legacyState.ActorActionFunc(actor);
+        actor->callAction();
     }
 
     it.Reset(STAT_SPIKE);
@@ -6141,7 +6134,7 @@ void SpriteControl(void)
         if (!(actor->user.Flags & SPR_ACTIVE))
             continue;
 
-        actor->user.__legacyState.ActorActionFunc(actor);
+        actor->callAction();
     }
 
     it.Reset(STAT_ROTATOR);
@@ -6158,7 +6151,7 @@ void SpriteControl(void)
         if (!(actor->user.Flags & SPR_ACTIVE))
             continue;
 
-        actor->user.__legacyState.ActorActionFunc(actor);
+        actor->callAction();
     }
 
     it.Reset(STAT_SLIDOR);
@@ -6175,7 +6168,7 @@ void SpriteControl(void)
         if (!(actor->user.Flags & SPR_ACTIVE))
             continue;
 
-        actor->user.__legacyState.ActorActionFunc(actor);
+        actor->callAction();
     }
 
     it.Reset(STAT_SUICIDE);
diff --git a/source/games/sw/src/swactor.h b/source/games/sw/src/swactor.h
index 0a2710967..7006bc027 100644
--- a/source/games/sw/src/swactor.h
+++ b/source/games/sw/src/swactor.h
@@ -54,7 +54,7 @@ public:
 	bool hasState(FName label, int substate = 0);
 	void callAction();
 	void callStateAction();
-	void callFunction(VMFunction* func);
+	int callFunction(VMFunction* func);
 
 
 };
diff --git a/source/games/sw/src/track.cpp b/source/games/sw/src/track.cpp
index db3fd4bcd..36a8b80f3 100644
--- a/source/games/sw/src/track.cpp
+++ b/source/games/sw/src/track.cpp
@@ -46,7 +46,6 @@ void DoAutoTurretObject(SECTOR_OBJECT* sop);
 void DoTornadoObject(SECTOR_OBJECT* sop);
 int PickJumpSpeed(DSWActor*, int pix_height);
 DSWActor* FindNearSprite(DSWActor, short);
-ANIMATOR NinjaJumpActionFunc;
 
 #define ACTOR_STD_JUMP (-384)
 DAngle GlobSpeedSO;
@@ -1288,7 +1287,7 @@ void SetupSectorObject(sectortype* sectp, short tag)
         sectp->hitag = 0;
 
         if (sop->max_damage <= 0)
-            VehicleSetSmoke(sop, SpawnVehicleSmoke);
+            VehicleSetSmoke(sop, *AF(SpawnVehicleSmoke));
 
         break;
     }
@@ -2565,7 +2564,7 @@ void PlaceSectorObject(SECTOR_OBJECT* sop, const DVector2& pos)
     RefreshPoints(sop, pos - sop->pmid.XY(), false);
 }
 
-void VehicleSetSmoke(SECTOR_OBJECT* sop, ANIMATOR* animator)
+void VehicleSetSmoke(SECTOR_OBJECT* sop, VMFunction* animator)
 {
     sectortype* *sectp;
 
@@ -2911,7 +2910,7 @@ bool ActorTrackDecide(TRACK_POINT* tpoint, DSWActor* actor)
                 actor->user.jump_speed = -tpoint->tag_high;
 
             DoActorBeginJump(actor);
-            actor->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
         }
 
         break;
@@ -2957,7 +2956,7 @@ bool ActorTrackDecide(TRACK_POINT* tpoint, DSWActor* actor)
             }
 
             DoActorBeginJump(actor);
-            actor->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
 
             return false;
         }
@@ -2982,7 +2981,7 @@ bool ActorTrackDecide(TRACK_POINT* tpoint, DSWActor* actor)
             }
 
             DoActorBeginJump(actor);
-            actor->user.__legacyState.ActorActionFunc = DoActorMoveJump;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoActorMoveJump);
             return false;
         }
 
@@ -3012,7 +3011,7 @@ bool ActorTrackDecide(TRACK_POINT* tpoint, DSWActor* actor)
                 actor->user.WaitTics = tpoint->tag_high * 128;
 
             InitActorDuck(actor);
-            actor->user.__legacyState.ActorActionFunc = DoActorDuck;
+            actor->user.__legacyState.ActorActionFunc = *AF(DoActorDuck);
             return false;
         }
 
@@ -3436,7 +3435,7 @@ int ActorFollowTrack(DSWActor* actor, short locktics)
                 actor->spr.pos.Z += actor->user.pos.Y;
 
                 DoActorSetSpeed(actor, SLOW_SPEED);
-                actor->user.__legacyState.ActorActionFunc = NinjaJumpActionFunc;
+                actor->user.__legacyState.ActorActionFunc = *AF(NinjaJumpActionFunc);
                 actor->user.jump_speed = -650;
                 DoActorBeginJump(actor);
 
diff --git a/source/games/sw/src/weapon.cpp b/source/games/sw/src/weapon.cpp
index 956e10287..af2fdb6b4 100644
--- a/source/games/sw/src/weapon.cpp
+++ b/source/games/sw/src/weapon.cpp
@@ -55,7 +55,6 @@ struct MISSILE_PLACEMENT
 void SpawnZombie2(DSWActor*);
 Collision move_ground_missile(DSWActor* actor, const DVector2& change, double ceildist, double flordist, uint32_t cliptype, int numtics);
 void DoPlayerBeginDie(PLAYER*);
-void VehicleSetSmoke(SECTOR_OBJECT* sop, ANIMATOR* animator);
 
 void ScaleSpriteVector(DSWActor* actor, int scalex, int scaley, int scalez);
 void ScaleSpriteVector(DSWActor* actor, int scale);
@@ -4961,7 +4960,7 @@ int SopCheckKill(SECTOR_OBJECT* sop)
         killed = TestKillSectorObject(sop);
         if (!killed)
         {
-            VehicleSetSmoke(sop, SpawnVehicleSmoke);
+            VehicleSetSmoke(sop, *AF(SpawnVehicleSmoke));
             sop->flags |= (SOBJ_BROKEN);
         }
     }
@@ -11145,7 +11144,7 @@ int DoMirv(DSWActor* actor)
 //
 //---------------------------------------------------------------------------
 
-bool MissileSetPos(DSWActor* actor, ANIMATOR* DoWeapon, int dist)
+bool MissileSetPos(DSWActor* actor, VMFunction* DoWeapon, int dist)
 {
     bool retval = false;
 
@@ -11162,7 +11161,7 @@ bool MissileSetPos(DSWActor* actor, ANIMATOR* DoWeapon, int dist)
 	UpdateChange(actor);
 
     actor->user.Flags |= (SPR_SET_POS_DONT_KILL);
-    if ((*DoWeapon)(actor))
+    if (actor->callFunction(DoWeapon))
         retval = true;
     actor->user.Flags &= ~(SPR_SET_POS_DONT_KILL);
 
@@ -11183,7 +11182,7 @@ bool MissileSetPos(DSWActor* actor, ANIMATOR* DoWeapon, int dist)
 //
 //---------------------------------------------------------------------------
 
-bool TestMissileSetPos(DSWActor* actor, ANIMATOR* DoWeapon, int dist, double zvel)
+bool TestMissileSetPos(DSWActor* actor, VMFunction* DoWeapon, int dist, double zvel)
 {
     bool retval = false;
 
@@ -11201,7 +11200,7 @@ bool TestMissileSetPos(DSWActor* actor, ANIMATOR* DoWeapon, int dist, double zve
     actor->user.change.Z = zvel;
 
     actor->user.Flags |= (SPR_SET_POS_DONT_KILL);
-    if ((*DoWeapon)(actor))
+    if (actor->callFunction(DoWeapon))
         retval = true;
     actor->user.Flags &= ~(SPR_SET_POS_DONT_KILL);
 
@@ -11540,7 +11539,7 @@ int InitLavaThrow(DSWActor* actor)
 
 	UpdateChange(actorNew);
 
-    MissileSetPos(actorNew, DoLavaBoulder, 1200);
+    MissileSetPos(actorNew, *AF(DoLavaBoulder), 1200);
 
     // find the distance to the target (player)
     SetZVelFromTarget(actorNew, actor, true);
@@ -11754,7 +11753,7 @@ void InitSpellNapalm(PLAYER* pp)
 
 		UpdateChange(actor);
 
-        if (MissileSetPos(actor, DoNapalm, mp[i].dist_out))
+        if (MissileSetPos(actor, *AF(DoNapalm), mp[i].dist_out))
         {
             plActor->clipdist = oclipdist;
             KillActor(actor);
@@ -11832,7 +11831,7 @@ int InitEnemyNapalm(DSWActor* actor)
 
 		UpdateChange(actorNew);
 
-        MissileSetPos(actorNew, DoNapalm, mp[i].dist_out);
+        MissileSetPos(actorNew, *AF(DoNapalm), mp[i].dist_out);
 
         actor->clipdist = oclipdist;
 
@@ -11877,7 +11876,7 @@ int InitSpellMirv(PLAYER* pp)
 
 	UpdateChange(actorNew);
 
-    MissileSetPos(actorNew, DoMirv, 600);
+    MissileSetPos(actorNew, *AF(DoMirv), 600);
     plActor->clipdist = oclipdist;
 
     actorNew->user.Counter = 0;
@@ -11913,7 +11912,7 @@ int InitEnemyMirv(DSWActor* actor)
 
 	UpdateChange(actorNew);
 
-    MissileSetPos(actorNew, DoMirv, 600);
+    MissileSetPos(actorNew, *AF(DoMirv), 600);
 
     // find the distance to the target (player)
     SetZVelFromTarget(actorNew, actor, true);
@@ -12343,7 +12342,7 @@ int InitSumoNapalm(DSWActor* actor)
 
 			UpdateChange(actorNew);
 
-            MissileSetPos(actorNew, DoNapalm, mp[i].dist_out);
+            MissileSetPos(actorNew, *AF(DoNapalm), mp[i].dist_out);
 
             actor->clipdist = oclipdist;
 
@@ -12751,7 +12750,7 @@ int InitStar(PLAYER* pp)
     // the horizon was tilted.  Never figured out why.
     actorNew->vel.Z = zvel * 0.5;
     double act2zvel = actorNew->vel.Z;
-    if (MissileSetPos(actorNew, DoStar, 1000))
+    if (MissileSetPos(actorNew, *AF(DoStar), 1000))
     {
         KillActor(actorNew);
         return 0;
@@ -12791,7 +12790,7 @@ int InitStar(PLAYER* pp)
 
         actorNew2->vel.Z = act2zvel;
 
-        if (MissileSetPos(actorNew2, DoStar, 1000))
+        if (MissileSetPos(actorNew2, *AF(DoStar), 1000))
         {
             KillActor(actorNew2);
             return 0;
@@ -12851,7 +12850,7 @@ void InitHeartAttack(PLAYER* pp)
 
 	UpdateChange(actorNew);
 
-    MissileSetPos(actorNew, DoBloodWorm, mp[i].dist_out);
+    MissileSetPos(actorNew, *AF(DoBloodWorm), mp[i].dist_out);
 
     plActor->clipdist = oclipdist;
     actorNew->user.Counter = 0;
@@ -13164,25 +13163,25 @@ int InitLaser(PLAYER* pp)
 
     // the slower the missile travels the less of a zvel it needs
     // move it 1200 dist in increments - works better
-    if (MissileSetPos(actorNew, DoLaserStart, 300))
+    if (MissileSetPos(actorNew, *AF(DoLaserStart), 300))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
         return 0;
     }
-    if (MissileSetPos(actorNew, DoLaserStart, 300))
+    if (MissileSetPos(actorNew, *AF(DoLaserStart), 300))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
         return 0;
     }
-    if (MissileSetPos(actorNew, DoLaserStart, 300))
+    if (MissileSetPos(actorNew, *AF(DoLaserStart), 300))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
         return 0;
     }
-    if (MissileSetPos(actorNew, DoLaserStart, 300))
+    if (MissileSetPos(actorNew, *AF(DoLaserStart), 300))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -13261,7 +13260,7 @@ int InitRail(PLAYER* pp)
     if (pp->Flags & (PF_DIVING) || SpriteInUnderwaterArea(actorNew))
         actorNew->user.Flags |= (SPR_UNDERWATER);
 
-    if (TestMissileSetPos(actorNew, DoRailStart, 1200, zvel))
+    if (TestMissileSetPos(actorNew, *AF(DoRailStart), 1200, zvel))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -13334,7 +13333,7 @@ int InitZillaRail(DSWActor* actor)
     if (SpriteInUnderwaterArea(actorNew))
         actorNew->user.Flags |= (SPR_UNDERWATER);
 
-    if (TestMissileSetPos(actorNew, DoRailStart, 1200, zvel))
+    if (TestMissileSetPos(actorNew, *AF(DoRailStart), 1200, zvel))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -13442,7 +13441,7 @@ int InitRocket(PLAYER* pp)
 
     // cancel smoke trail
     actorNew->user.Counter = 1;
-    if (TestMissileSetPos(actorNew, DoRocket, 1200, zvel))
+    if (TestMissileSetPos(actorNew, *AF(DoRocket), 1200, zvel))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -13546,7 +13545,7 @@ int InitBunnyRocket(PLAYER* pp)
 
     // cancel smoke trail
     actorNew->user.Counter = 1;
-    if (TestMissileSetPos(actorNew, DoRocket, 1200, zvel))
+    if (TestMissileSetPos(actorNew, *AF(DoRocket), 1200, zvel))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -13639,7 +13638,7 @@ int InitNuke(PLAYER* pp)
 
     // cancel smoke trail
     actorNew->user.Counter = 1;
-    if (TestMissileSetPos(actorNew, DoRocket, 1200, zvel))
+    if (TestMissileSetPos(actorNew, *AF(DoRocket), 1200, zvel))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -13716,7 +13715,7 @@ int InitEnemyNuke(DSWActor* actor)
 
     // cancel smoke trail
     actorNew->user.Counter = 1;
-    if (TestMissileSetPos(actorNew, DoRocket, 1200, zvel))
+    if (TestMissileSetPos(actorNew, *AF(DoRocket), 1200, zvel))
     {
         KillActor(actorNew);
         return 0;
@@ -13827,7 +13826,7 @@ int InitMicro(PLAYER* pp)
 
         // cancel smoke trail
         actorNew->user.Counter = 1;
-        if (MissileSetPos(actorNew, DoMicro, 700))
+        if (MissileSetPos(actorNew, *AF(DoMicro), 700))
         {
             actor->clipdist = oclipdist;
             KillActor(actorNew);
@@ -14236,7 +14235,7 @@ int InitSerpSpell(DSWActor* actor)
 
 		UpdateChange(actorNew);
 
-        MissileSetPos(actorNew, DoMirvMissile, 400);
+        MissileSetPos(actorNew, *AF(DoMirvMissile), 400);
         actor->clipdist = oclipdist;
 
         if (actor->user.Flags & (SPR_UNDERWATER))
@@ -14338,7 +14337,7 @@ int InitSerpMonstSpell(DSWActor* actor)
 
 		UpdateChange(actorNew);
 
-        MissileSetPos(actorNew, DoMirvMissile, 400);
+        MissileSetPos(actorNew, *AF(DoMirvMissile), 400);
         actor->clipdist = oclipdist;
 
         if (actor->user.Flags & (SPR_UNDERWATER))
@@ -14410,7 +14409,7 @@ int InitEnemyRocket(DSWActor* actor)
         actorNew->spr.pal = actorNew->user.spal = 20; // Yellow
     }
 
-    MissileSetPos(actorNew, DoBoltThinMan, 400);
+    MissileSetPos(actorNew, *AF(DoBoltThinMan), 400);
 
     // find the distance to the target (player)
     SetZVelFromTarget(actorNew, actor, true);
@@ -14483,7 +14482,7 @@ int InitEnemyRail(DSWActor* actor)
 
 	UpdateChange(actorNew);
 
-    if (TestMissileSetPos(actorNew, DoRailStart, 600, actorNew->vel.Z))
+    if (TestMissileSetPos(actorNew, *AF(DoRailStart), 600, actorNew->vel.Z))
     {
         KillActor(actorNew);
         return 0;
@@ -14558,7 +14557,7 @@ int InitZillaRocket(DSWActor* actor)
             actorNew->spr.Angles.Yaw -= mp[i].ang;
         }
 
-        MissileSetPos(actorNew, DoBoltThinMan, mp[i].dist_out);
+        MissileSetPos(actorNew, *AF(DoBoltThinMan), mp[i].dist_out);
 
         // find the distance to the target (player)
         SetZVelFromTarget(actorNew, actor, true);
@@ -14593,7 +14592,7 @@ int InitEnemyStar(DSWActor* actor)
 
 	UpdateChange(actorNew);
 
-    MissileSetPos(actorNew, DoStar, 400);
+    MissileSetPos(actorNew, *AF(DoStar), 400);
 
     // find the distance to the target (player)
     SetZVelFromTarget(actorNew, actor, true);
@@ -14633,7 +14632,7 @@ int InitEnemyCrossbow(DSWActor* actor)
 
     actorNew->user.Flags |= (SPR_XFLIP_TOGGLE);
 
-    MissileSetPos(actorNew, DoStar, 400);
+    MissileSetPos(actorNew, *AF(DoStar), 400);
 
     // find the distance to the target (player)
     SetZVelFromTarget(actorNew, actor, true);
@@ -14673,7 +14672,7 @@ int InitSkelSpell(DSWActor* actor)
     // find the distance to the target (player)
     SetZVelFromTarget(actorNew, actor, false, ActorSizeZ(actor) * 0.5);
 	UpdateChange(actorNew);
-    MissileSetPos(actorNew, DoElectro, 400);
+    MissileSetPos(actorNew, *AF(DoElectro), 400);
 
     return 0;
 }
@@ -15002,7 +15001,7 @@ int InitTracerUzi(PLAYER* pp)
         HelpMissileLateral(actorNew, lat_dist[0]);
     actorNew->spr.Angles.Yaw -= DAngle90;
 
-    if (MissileSetPos(actorNew, DoTracerStart, 800))
+    if (MissileSetPos(actorNew, *AF(DoTracerStart), 800))
     {
         plActor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -16455,7 +16454,7 @@ int InitGrenade(PLAYER* pp)
 
     // don't do smoke for this movement
     actorNew->user.Flags |= (SPR_BOUNCE);
-    MissileSetPos(actorNew, DoGrenade, 1000);
+    MissileSetPos(actorNew, *AF(DoGrenade), 1000);
     actorNew->user.Flags &= ~(SPR_BOUNCE);
 
     actor->clipdist = oclipdist;
@@ -16526,7 +16525,7 @@ int InitSpriteGrenade(DSWActor* actor)
 
     // don't do smoke for this movement
     actorNew->user.Flags |= (SPR_BOUNCE);
-    MissileSetPos(actorNew, DoGrenade, 400);
+    MissileSetPos(actorNew, *AF(DoGrenade), 400);
     actorNew->user.Flags &= ~(SPR_BOUNCE);
 
     return 0;
@@ -16573,7 +16572,7 @@ int InitMine(PLAYER* pp)
     if (pp->Flags & (PF_DIVING) || SpriteInUnderwaterArea(actorNew))
         actorNew->user.Flags |= (SPR_UNDERWATER);
 
-    MissileSetPos(actorNew, DoMine, 800);
+    MissileSetPos(actorNew, *AF(DoMine), 800);
 
 	UpdateChange(actorNew, 0.5);
 
@@ -16622,9 +16621,9 @@ int InitEnemyMine(DSWActor* actor)
     if (SpriteInUnderwaterArea(actorNew))
         actorNew->user.Flags |= (SPR_UNDERWATER);
 
-    MissileSetPos(actorNew, DoMine, 300);
+    MissileSetPos(actorNew, *AF(DoMine), 300);
     actorNew->spr.Angles.Yaw -= DAngle90;
-    MissileSetPos(actorNew, DoMine, 300);
+    MissileSetPos(actorNew, *AF(DoMine), 300);
     actorNew->spr.Angles.Yaw += DAngle90;
 
     actorNew->user.change. Z = -5000 / 256.;
@@ -16709,7 +16708,7 @@ int InitFireball(PLAYER* pp)
     if (pp->Flags & (PF_DIVING) || SpriteInUnderwaterArea(actorNew))
         actorNew->user.Flags |= (SPR_UNDERWATER);
 
-    if (TestMissileSetPos(actorNew, DoFireball, 1200, zvel * (1375. / 2048.)))
+    if (TestMissileSetPos(actorNew, *AF(DoFireball), 1200, zvel * (1375. / 2048.)))
     {
         actor->clipdist = oclipdist;
         KillActor(actorNew);
@@ -16776,7 +16775,7 @@ int InitEnemyFireball(DSWActor* actor)
 
         actorNew->user.change.XY() = change;
 
-        MissileSetPos(actorNew, DoFireball, 700);
+        MissileSetPos(actorNew, *AF(DoFireball), 700);
 
         if (i == 0)
         {
diff --git a/source/games/sw/src/weapon.h b/source/games/sw/src/weapon.h
index 38c53632c..4ee4593a8 100644
--- a/source/games/sw/src/weapon.h
+++ b/source/games/sw/src/weapon.h
@@ -97,7 +97,7 @@ void SpawnGrenadeExp(DSWActor*);
 DSWActor* SpawnSectorExp(DSWActor*);
 int DoShrapVelocity(DSWActor*);
 int ShrapKillSprite(DSWActor*);
-bool MissileSetPos(DSWActor*,ANIMATOR* DoWeapon,int dist);
+bool MissileSetPos(DSWActor*,VMFunction* DoWeapon,int dist);
 int ActorPain(DSWActor*);
 int SpawnBreakFlames(DSWActor*);
 bool PlayerTakeDamage(PLAYER* pp, DSWActor* weapActor);