--- orig/rpggame/rpgent.h
+++ mod/rpggame/rpgent.h
@@ -40,7 +40,7 @@
 
     void tryattackobj(rpgobj &eo, rpgobj &weapon)
     {
-        if (!eo.s_ai) return; // not a character
+        if (!(eo.s_ai & eo.AI_CHAR)) return; // not a character
         if (!(ro->checkenemy(eo.s_aigroup))) return; // not an enemy
 
         rpgent &e = *eo.ent;
@@ -221,12 +221,15 @@
 
     void update(int curtime, float playerdist)
     {
+        ro->st_update(cl.lastmillis);
         maxspeed = ro->eff_movespeed()*40/100 + 5;
 
         updateprojectile(curtime);
 
         if(state==CS_DEAD) { stopmoving(); return; };
 
+        if(ro->s_ai & ro->AI_SCRIPT) return;
+
         if(blocked && npcstate!=R_BLOCKED && npcstate!=R_SEEK)
         {
             blocked = false;


--- orig/rpggame/rpgobj.h
+++ mod/rpggame/rpgobj.h
@@ -58,6 +58,14 @@
         MENU_SELL
     };
 
+    enum
+    {
+        AI_CHAR      = 1,   // NPC or player
+        AI_NOGUI     = 2,   // don't show GUI
+        AI_NOTAKE    = 4,   // cannot be taken (even if AI_CHAR is not set)
+        AI_SCRIPT    = 8,   // controlled by script
+    };
+
     int itemflags;
 
     rpgaction *actions, action_use;
@@ -152,7 +160,7 @@
 
     void render()
     {
-        if(s_ai)
+        if(s_ai & AI_CHAR)
         {
             float sink = 0;
             if(ent->physstate>=PHYS_SLIDE)
@@ -172,11 +180,11 @@
     void update(int curtime)
     {
         float dist = ent->o.dist(os.cl.player1.o);
-        if(s_ai) { ent->update(curtime, dist); st_update(ent->cl.lastmillis); };
+        if(s_ai & AI_CHAR) { ent->update(curtime, dist); st_update(ent->cl.lastmillis); };
         moveplayer(ent, 10, false, curtime);    // 10 or above gets blocked less, because physics accuracy doesn't need extra tests
         //ASSERT(!(ent->o.x<0 || ent->o.y<0 || ent->o.z<0 || ent->o.x>4096 || ent->o.y>4096 || ent->o.z>4096));
-        if(!menutime && dist<(s_ai ? 40 : 24) && ent->state==CS_ALIVE && s_ai<2) { menutime = starttime(); menuwhich = MENU_DEFAULT; }
-        else if(dist>(s_ai ? 96 : 48)) menutime = 0;
+        if(!menutime && dist<(s_ai ? 40 : 24) && ent->state==CS_ALIVE && !(s_ai & AI_NOGUI)) { menutime = starttime(); menuwhich = MENU_DEFAULT; }
+        else if(dist>((s_ai & AI_CHAR) ? 96 : 48)) menutime = 0;
     }
 
     void addaction(char *initiate, char *script, bool startquest)
@@ -305,7 +313,7 @@
             if (target==os.playerobj) conoutf("\f2using: %s", name);
             target->selected = this;
         }
-        else
+        else if (target->s_ai & AI_CHAR)
         {
             useaction(*target, *(target->ent), true);
         }
@@ -335,7 +343,7 @@
 
                 guiaction(g, actions);
 
-                if(s_ai)
+                if(s_ai & AI_CHAR)
                 {
                     bool trader = false;
                     loopinventorytype(IF_TRADE) trader = true;
@@ -345,7 +353,7 @@
                         if(g.button("sell", 0xFFFFFF, "coins")&G3D_UP) menuwhich = MENU_SELL;
                     }
                 }
-                else
+                else if (!(s_ai & AI_NOTAKE))
                 {
                     s_sprintfd(wtext)("worth %d", s_worth);
                     g.text(wtext, 0xAAAAAA, "coins");



