diff --git a/src/SB/Game/zNPCHazard.h b/src/SB/Game/zNPCHazard.h
index 4e7be300..f36b4938 100644
--- a/src/SB/Game/zNPCHazard.h
+++ b/src/SB/Game/zNPCHazard.h
@@ -25,6 +25,8 @@ struct UVAModelInfo
     S32 GetUV(RwTexCoords*& coords, S32& numVertices, RpAtomic* model);
     void SetColor(iColor_tag);
     void Update(F32, xVec2*);
+    S32 Valid();
+    S32 Init(RpAtomic*, S32);
 };
 
 struct NPCHazard;
diff --git a/src/SB/Game/zNPCTypeCommon.h b/src/SB/Game/zNPCTypeCommon.h
index 81b7e497..0af7764d 100644
--- a/src/SB/Game/zNPCTypeCommon.h
+++ b/src/SB/Game/zNPCTypeCommon.h
@@ -388,6 +388,7 @@ struct zNPCCommon : xNPCBasic
     F32 ThrottleAccel(F32 dt, S32 speedup, F32 pct_max);
     F32 ThrottleAdjust(F32 dt, F32 spd_want, F32 accel);
 
+    F32 BoundAsRadius(int useCfg);
     void VelStop();
     static void ConfigSceneDone();
     U32 LassoInit();
diff --git a/src/SB/Game/zNPCTypeRobot.cpp b/src/SB/Game/zNPCTypeRobot.cpp
index c8d58edb..9d3511a1 100644
--- a/src/SB/Game/zNPCTypeRobot.cpp
+++ b/src/SB/Game/zNPCTypeRobot.cpp
@@ -10,6 +10,7 @@
 #include "xFactory.h"
 #include "xMath.h"
 #include "xAnim.h"
+#include "xBehaviour.h"
 
 #include <string.h>
 
@@ -691,6 +692,118 @@ void zNPCRobot::DuploOwner(zNPCCommon* duper)
     }
 }
 
+void zNPCRobot::AddLassoing
+(
+    xPsyche* psyche,
+    xGoalProcessCallback cb1,
+    xGoalProcessCallback cb2,
+    xGoalProcessCallback cb3,
+    xGoalProcessCallback cb4,
+    xGoalProcessCallback cb5
+)
+{
+    if (!(flg_vuln & 0x1000000))
+    {
+        return;
+    }
+
+    xGoal* goal;
+    goal = psyche->AddGoal(NPC_GOAL_LASSOBASE, NULL);
+    goal->SetCallbacks(cb1, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_LASSOGRAB, NULL);
+    goal->SetCallbacks(cb2, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_LASSOTHROW, NULL);
+    goal->SetCallbacks(cb3, NULL, NULL, NULL);
+
+}
+
+void zNPCRobot::AddMiscTypical
+(
+    xPsyche* psyche,
+    xGoalProcessCallback cb1,
+    xGoalProcessCallback cb2,
+    xGoalProcessCallback cb3
+)
+{
+    xGoal* goal;
+
+    goal = psyche->AddGoal(NPC_GOAL_NOTICE, NULL);
+    goal->SetCallbacks(cb1, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_TAUNT, NULL);
+    goal->SetCallbacks(cb2, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_NOMANLAND, NULL);
+    goal->SetCallbacks(cb3, NULL, NULL, NULL);
+}
+
+void zNPCRobot::AddStunThrow
+(
+    xPsyche* psyche,
+    xGoalProcessCallback cb1,
+    xGoalProcessCallback cb2,
+    xGoalProcessCallback cb3,
+    xGoalProcessCallback cb4
+)
+{
+    xGoal* goal;
+
+    goal = psyche->AddGoal(NPC_GOAL_EVILPAT, NULL);
+    goal->SetCallbacks(cb1, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_STUNNED, NULL);
+    goal->SetCallbacks(cb2, NULL, NULL, NULL);
+
+    if (cfg_npc->pts_damage < 2)
+    {
+        goal = psyche->AddGoal(NPC_GOAL_PATCARRY, NULL);
+        goal->SetCallbacks(cb3, NULL, NULL, NULL);
+
+        goal = psyche->AddGoal(NPC_GOAL_PATTHROW, NULL);
+        goal->SetCallbacks(cb4, NULL, NULL, NULL);
+    }
+}
+
+void zNPCRobot::AddDamage
+(
+    xPsyche* psyche,
+    xGoalProcessCallback cb1,
+    xGoalProcessCallback cb2,
+    xGoalProcessCallback cb3,
+    xGoalProcessCallback cb4,
+    xGoalProcessCallback cb5
+)
+{
+    xGoal* goal;
+
+    goal = psyche->AddGoal(NPC_GOAL_DAMAGE, NULL);
+    goal->SetCallbacks(cb1, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_KNOCK, NULL);
+    goal->SetCallbacks(cb2, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_BASHED, NULL);
+    goal->SetCallbacks(cb3, NULL, NULL, NULL);
+}
+
+void zNPCRobot::AddSpawning
+(
+    xPsyche* psyche,
+    xGoalProcessCallback cb1,
+    xGoalProcessCallback cb2
+)
+{
+    xGoal* goal;
+
+    goal = psyche->AddGoal(NPC_GOAL_AFTERLIFE, NULL);
+    goal->SetCallbacks(cb1, NULL, NULL, NULL);
+
+    goal = psyche->AddGoal(NPC_GOAL_RESPAWN, NULL);
+    goal->SetCallbacks(cb2, NULL, NULL, NULL);
+}
+
 void zNPCFodBzzt::DiscoReset()
 {
     tmr_discoLight = -1.0f;
@@ -1573,6 +1686,106 @@ void zNPCTubeSlave::Reset()
     zNPCTubeSlave::WeGotAGig();
 }
 
+F32 zNPCRobot::GenShadCacheRad()
+{
+    F32 fac_use;
+    F32 rad_cache;
+
+    switch (xNPCBasic::SelfType())
+    {
+    case NPC_TYPE_HAMMER:    // 0x4e545230:
+    case NPC_TYPE_HAMSPIN:   // 0x4e545231:
+    case NPC_TYPE_TARTAR:    // 0x4e545232:
+    case NPC_TYPE_GLOVE:     // 0x4e545233:
+    case NPC_TYPE_MONSOON:   // 0x4e545234:
+    case NPC_TYPE_SLEEPY:    // 0x4e545235:
+    case NPC_TYPE_ARFARF:    // 0x4e545237:
+    case NPC_TYPE_TUBELET:   // 0x4e545239:
+    case NPC_TYPE_TUBESLAVE: // 0x4e54523a:
+        fac_use = 2.4f;
+        break;
+    case NPC_TYPE_ARFDOG:  // 0x4e545236:
+    case NPC_TYPE_CHUCK:   // 0x4e545238:
+    case NPC_TYPE_FODDER:  // 0x4e54523c:
+    case NPC_TYPE_FODBOMB: // 0x4e54523d:
+    case NPC_TYPE_FODBZZT: // 0x4e54523e:
+    case NPC_TYPE_CHOMPER: // 0x4e54523f:
+    case NPC_TYPE_CRITTER: // 0x4e545240:
+        fac_use = 1.5f;
+        break;
+    case NPC_TYPE_SLICK:
+        fac_use = 2.5f;
+        break;
+    default:
+        fac_use = 2.0f;
+        break;
+    }
+    rad_cache = zNPCCommon::BoundAsRadius(0);
+    return (fac_use * rad_cache);
+}
+
+void zNPCSleepy::Init(xEntAsset* asset)
+{
+    zNPCRobot::Init(asset);
+
+    flg_move |= 2;
+
+    flg_vuln &= 0x8fffffff;
+
+    idx_neckBone = -1;
+
+    rast_detectcone = NULL;
+    rast_killcone = NULL;
+
+    // Weirdness related to this line.
+    g_cnt_sleepy++;
+
+    NPAR_PartySetup(NPAR_TYP_SLEEPYZEEZ, NULL, NULL);
+}
+
+void zNPCSlick::Init(xEntAsset* asset)
+{
+    zNPCRobot::Init(asset);
+
+    flg_move &= 0xfffffffd;
+    flg_move |= 4;
+
+    flg_vuln &= 0x9fffffff;
+    flg_vuln |= 0x1000000;
+
+    idx_neckBone = -1;
+
+    if (!g_uvaShield.Valid())
+    {
+        xModelInstance* mdl = zNPCCommon::ModelAtomicFind(1, -1, NULL);
+        if ((mdl != NULL) && (mdl->Data != NULL))
+        {
+            g_uvaShield.Init(mdl->Data, 0);
+            g_uvaShield.UVVelSet(0.0f, -0.7f);
+        }
+    }
+    NPAR_PartySetup(NPAR_TYP_OILBUB, NULL, NULL);
+}
+
+void zNPCSleepy::NewTime(xScene* sc, F32 dt)
+{
+    if (!IsDead())
+    {
+        xModelInstance* nightlight = zNPCCommon::ModelAtomicFind(4, -1, NULL);
+        if (nightlight == NULL)
+        {
+            return;
+        }
+        NightLightPos((xVec3*)(&nightlight->Mat->pos));
+    }
+    zNPCRobot::NewTime(sc, dt);
+}
+
+void zNPCMonsoon::NewTime(xScene* sc, F32 dt)
+{
+    zNPCRobot::NewTime(sc, dt);
+}
+
 U32 zNPCSleepy::AnimPick(int gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal)
 {
     U32 uVar1 = 0;
@@ -1599,9 +1812,93 @@ U32 zNPCSleepy::AnimPick(int gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal)
     return uVar1;
 }
 
+S32 FODR_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTFODDER;
+}
+
+S32 BOMB_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTFODBOMB;
+}
+
+S32 BZZT_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTFODBZZT;
+}
+
+S32 CHMP_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTCHOMPER;
+}
+
+S32 HAMR_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTHAMMER;
+}
+
+S32 TART_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTTARTAR;
+}
+
+S32 GLOV_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTGLOVE;
+}
+
+S32 MOON_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTMONSOON;
+}
+
+S32 SLEP_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTSLEEPY;
+}
+
+S32 ARFY_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTARF;
+}
+
+S32 PUPY_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTPUPPY;
+}
+
+S32 CHUK_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTCHUCK;
+}
+
+S32 TUBE_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTTUBELET;
+}
+
+S32 SLCK_grul_alert(xGoal* goal, void*, en_trantype* trantype, float, void*)
+{
+    *trantype = GOAL_TRAN_PUSH;
+    return NPC_GOAL_ALERTSLICK;
+}
+
 S32 xEntIsEnabled(xEnt* ent)
 {
-    return xBaseIsEnabled((xBase*)ent) & 0xff;
+    return xBaseIsEnabled(ent);
 }
 
 void xMat3x3RMulVec(xVec3* o, const xMat3x3* m, const xVec3* v)
diff --git a/src/SB/Game/zNPCTypeRobot.h b/src/SB/Game/zNPCTypeRobot.h
index 388709ba..640c77f1 100644
--- a/src/SB/Game/zNPCTypeRobot.h
+++ b/src/SB/Game/zNPCTypeRobot.h
@@ -71,7 +71,10 @@ struct zNPCRobot : zNPCCommon
     zNPCLassoInfo raw_lassoinfo;
     xEntDrive raw_drvdata;
 
-    zNPCRobot(S32);
+    zNPCRobot(S32 myType) : zNPCCommon(myType)
+    {
+        hitpoints = 1;
+    }
 
     S32 LaunchProjectile(en_npchaz haztyp, F32 spd_proj, F32 dst_minRange, en_mdlvert idx_mvtx,
                          F32 tym_predictMax, F32 hyt_offset);
@@ -155,7 +158,11 @@ struct zNPCRobot : zNPCCommon
 
 struct zNPCFodder : zNPCRobot
 {
-    zNPCFodder(S32 myType);
+    zNPCFodder(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     void Stun(F32 stuntime);
     U32 AnimPick(S32 gid, en_NPC_GOAL_SPOT gspot, xGoal* rawgoal);
     void SelfSetup();
@@ -172,7 +179,11 @@ struct zNPCFodBomb : zNPCRobot
 
     NPCBlinker blinker;
 
-    zNPCFodBomb(S32 myType);
+    zNPCFodBomb(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     zNPCLassoInfo* PRIV_GetLassoData();
     void Reset();
     void Init(xEntAsset*);
@@ -191,7 +202,11 @@ struct zNPCFodBzzt : zNPCRobot
     xVec3 pos_discoLight;
     F32 uv_discoLight[2];
 
-    zNPCFodBzzt(S32 myType);
+    zNPCFodBzzt(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     zNPCLassoInfo* PRIV_GetLassoData();
     void Reset();
     void DiscoReset();
@@ -204,7 +219,11 @@ struct zNPCChomper : zNPCRobot
     S32 cnt_spurt;
     S32 cnt_skipEmit;
 
-    zNPCChomper(S32 myType);
+    zNPCChomper(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     zNPCLassoInfo* PRIV_GetLassoData();
     void Reset();
     void ParseINI();
@@ -213,7 +232,11 @@ struct zNPCChomper : zNPCRobot
 
 struct zNPCCritter : zNPCRobot
 {
-    zNPCCritter(S32 myType);
+    zNPCCritter(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     zNPCLassoInfo* PRIV_GetLassoData();
     void Reset();
     void Init(xEntAsset*);
@@ -222,7 +245,11 @@ struct zNPCCritter : zNPCRobot
 
 struct zNPCHammer : zNPCRobot
 {
-    zNPCHammer(S32 myType);
+    zNPCHammer(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     void Init(xEntAsset*);
     void Reset();
     void ParseINI();
@@ -230,7 +257,11 @@ struct zNPCHammer : zNPCRobot
 
 struct zNPCTarTar : zNPCRobot
 {
-    zNPCTarTar(S32 myType);
+    zNPCTarTar(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     void Reset();
     void Init(xEntAsset*);
     void ParseINI();
@@ -238,23 +269,34 @@ struct zNPCTarTar : zNPCRobot
 
 struct zNPCGlove : zNPCRobot
 {
-    zNPCGlove(S32 myType);
+    zNPCGlove(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     void Init(xEntAsset*);
     void ParseINI();
 };
 
 struct zNPCMonsoon : zNPCRobot
 {
-    zNPCMonsoon(S32 myType);
+    zNPCMonsoon(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     U8 FoulWeather(float);
     void Reset();
     void ParseINI();
     void Init(xEntAsset* asset);
+    void NewTime(xScene*, F32);
 };
 
 struct zNPCSleepy : zNPCRobot
 {
     static S8 init;
+    static RwRaster* rast_detectcone;
+    static RwRaster* rast_killcone;
     volatile static F32 hyt_NightLightCurrent;
 
     S32 flg_sleepy;
@@ -265,12 +307,18 @@ struct zNPCSleepy : zNPCRobot
     F32 tmr_emitzeez;
     F32 cnt_grpzeez;
 
-    zNPCSleepy(S32 myType);
+    zNPCSleepy(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     void Reset();
     void ParseINI();
     U32 AnimPick(int, en_NPC_GOAL_SPOT, xGoal*);
     S32 RepelMissile(float);
     void NightLightPos(xVec3*);
+    void NewTime(xScene* sc, F32 dt);
+    void Init(xEntAsset* asset);
 };
 
 struct zNPCArfDog : zNPCRobot
@@ -280,7 +328,11 @@ struct zNPCArfDog : zNPCRobot
     NPCBlinker blinkHead;
     NPCBlinker blinkTail;
 
-    zNPCArfDog(S32 myType);
+    zNPCArfDog(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     zNPCLassoInfo* PRIV_GetLassoData();
     void Reset();
     void BlinkReset();
@@ -294,7 +346,11 @@ struct zNPCArfArf : zNPCRobot
     S32 flg_puppy[5];
     zNPCArfDog* pup_kennel[5];
 
-    zNPCArfArf(S32 myType);
+    zNPCArfArf(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     zMovePoint* GetTelepoint(S32 unk);
     void Reset();
     void Init(xEntAsset* asset);
@@ -305,7 +361,11 @@ struct zNPCChuck : zNPCRobot
 {
     xVec3 dir_attack;
 
-    zNPCChuck(S32 myType);
+    zNPCChuck(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     //    0x00000000; // 0x0
     //    0x00000000; // 0x4
     /*
@@ -401,7 +461,11 @@ struct zNPCTubelet : zNPCRobot
     S32 pete_attack_last;
     TubeNotice psynote;
 
-    zNPCTubelet(S32 myType);
+    zNPCTubelet(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     void ParseINI();
     void Reset();
     S32 IsDying();
@@ -428,7 +492,11 @@ struct zNPCTubeSlave : zNPCRobot
     en_tubespot tubespot;
     zNPCTubelet* tub_pete;
 
-    zNPCTubeSlave(S32 myType);
+    zNPCTubeSlave(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
+
     U8 PhysicsFlags() const;
     U8 ColPenByFlags() const;
     U8 ColChkByFlags() const;
@@ -455,7 +523,10 @@ struct zNPCSlick : zNPCRobot
     F32 alf_shieldCurrent;
     F32 alf_shieldDesired;
 
-    zNPCSlick(S32 myType);
+    zNPCSlick(S32 myType) : zNPCRobot(myType)
+    {
+
+    }
 
     zNPCSlick* YouOwnSlipFX();
     void BUpdate(xVec3* pos);