--- orig/rpggame/rpgent.h
+++ mod/rpggame/rpgent.h
@@ -40,7 +40,8 @@
 
     void tryattackobj(rpgobj &eo, rpgobj &weapon)
     {
-        if(!eo.s_ai || (eo.s_ai==ro->s_ai && eo.ent!=enemy)) return;
+        if (!eo.s_ai) return; // not a character
+        if (!(ro->checkenemy(eo.s_aigroup))) return; // not an enemy
 
         rpgent &e = *eo.ent;
         if(e.state!=CS_ALIVE) return;
@@ -217,8 +218,8 @@
             case R_STARE:
                 ifplayerclose
                 {
-                    if(ro->s_ai==2) { gotopos(cl.player1.o, R_SEEK,  1, 200); enemy = &cl.player1; }
-                    else            { gotopos(cl.player1.o, R_STARE, 0, 500); }
+                    if(ro->checkenemy(cl.player1.ro->s_aigroup)) { gotopos(cl.player1.o, R_SEEK,  1, 200); enemy = &cl.player1; }
+                    else                                         { gotopos(cl.player1.o, R_STARE, 0, 500); }
                 }
                 else ifnextstate stareorroam();
                 break;


--- orig/rpggame/rpgobj.h
+++ mod/rpggame/rpgobj.h
@@ -202,6 +202,16 @@
         return 0;
     }
 
+    bool checkenemy(unsigned int aigroup)
+    {
+        return os.checkenemy(s_aigroup, aigroup);
+    }
+
+    bool checkfriend(unsigned int aigroup)
+    {
+        return os.checkfriend(s_aigroup, aigroup);
+    }
+
     void takedamage(int damage, rpgobj &attacker)
     {
         ent->enemy = attacker.ent;


--- orig/rpggame/rpgobjset.h
+++ mod/rpggame/rpgobjset.h
@@ -1,3 +1,9 @@
+struct rpgaigroup
+{
+    unsigned int enemies; // bitmap of aigroups
+    unsigned int friends;
+};
+
 struct rpgobjset
 {
     rpgclient &cl;
@@ -9,6 +15,8 @@
     rpgobj *playerobj;
     rpgobj *selected;
 
+    vector<rpgaigroup> aigroups;
+
     rpgquest *quests;
     rpgquest *currentquest;
 
@@ -39,6 +47,12 @@
         CCOMMAND(r_applydamage, "i",   (rpgobjset *self, int *d), { self->stack[0]->takedamage(*d, *self->stack[1]); });
         CCOMMAND(r_get_name,    "",    (rpgobjset *self), { if (self->stack[0]->name) result(self->stack[0]->name); });
         CCOMMAND(r_check_inv,   "s",   (rpgobjset *self, char *name), { intret(self->playerobj->checkinv(name)); });
+        CCOMMAND(r_add_enemy,   "ii",  (rpgobjset *self, unsigned int *owngroup, unsigned int *enemygroup),  { self->addenemy(*owngroup, *enemygroup); });
+        CCOMMAND(r_del_enemy,   "ii",  (rpgobjset *self, unsigned int *owngroup, unsigned int *enemygroup),  { self->delenemy(*owngroup, *enemygroup); });
+        CCOMMAND(r_add_friend,  "ii",  (rpgobjset *self, unsigned int *owngroup, unsigned int *friendgroup), { self->addfriend(*owngroup, *friendgroup); });
+        CCOMMAND(r_del_friend,  "ii",  (rpgobjset *self, unsigned int *owngroup, unsigned int *friendgroup), { self->delfriend(*owngroup, *friendgroup); });
+        CCOMMAND(r_check_enemy, "ii",  (rpgobjset *self, unsigned int *owngroup, unsigned int *enemygroup),  { intret(self->checkenemy(*owngroup, *enemygroup)?1:0); });
+        CCOMMAND(r_check_friend,"ii",  (rpgobjset *self, unsigned int *owngroup, unsigned int *friendgroup), { intret(self->checkfriend(*owngroup, *friendgroup)?1:0); });
         clearworld();
     }
 
@@ -48,6 +62,17 @@
         loopi(10) stack.add(playerobj);     // determines the stack depth
     }
 
+    void resetaigroups()
+    {
+        // fixed number of 32 groups
+        aigroups.setsize(0);
+        loopi(32) aigroups.add((rpgaigroup){0, 0});
+
+        // default group settings
+        aigroups[1] = (rpgaigroup){/*enemies*/(1 << 2), /*friends*/(1 << 1)};
+        aigroups[2] = (rpgaigroup){/*enemies*/(1 << 1), /*friends*/(1 << 2)};
+    }
+
     void clearworld()
     {
         if(playerobj) { playerobj->ent = NULL; delete playerobj; }
@@ -58,6 +83,7 @@
         pointingat = NULL;
         set.deletecontentsp();
         resetstack();
+        resetaigroups();
 
         playerobj->scriptinit();            // will fail when this is called from emptymap(), which is ok
     }
@@ -157,6 +183,44 @@
         }
     }
 
+#define checkaigroups(g1, g2) { if ((g1 > 31) || (g2 > 31)) { conoutf("Invalid aigroup"); return; } }
+    void addenemy(unsigned int owngroup, unsigned int enemygroup)
+    {
+        checkaigroups(owngroup, enemygroup)
+        aigroups[owngroup].enemies |= (1 << enemygroup);
+    }
+
+    void delenemy(unsigned int owngroup, unsigned int enemygroup)
+    {
+        checkaigroups(owngroup, enemygroup)
+        aigroups[owngroup].enemies &= ~(1 << enemygroup);
+    }
+
+    void addfriend(unsigned int owngroup, unsigned int friendgroup)
+    {
+        checkaigroups(owngroup, friendgroup)
+        aigroups[owngroup].friends |= (1 << friendgroup);
+    }
+
+    void delfriend(unsigned int owngroup, unsigned int friendgroup)
+    {
+        checkaigroups(owngroup, friendgroup)
+        aigroups[owngroup].friends &= ~(1 << friendgroup);
+    }
+
+#define checkaigroupsi(g1, g2) { if ((g1 > 31) || (g2 > 31)) { conoutf("Invalid aigroup"); return false; } }
+    bool checkenemy(unsigned int owngroup, unsigned int enemygroup)
+    {
+        checkaigroupsi(owngroup, enemygroup)
+        return (aigroups[owngroup].enemies & (1 << enemygroup));
+    }
+
+    bool checkfriend(unsigned int owngroup, unsigned int friendgroup)
+    {
+        checkaigroupsi(owngroup, friendgroup)
+        return (aigroups[owngroup].friends & (1 << friendgroup));
+    }
+
     char *stringpool(char *name)
     {
         char **n = names.access(name);


--- orig/rpggame/stats.h
+++ mod/rpggame/stats.h
@@ -34,6 +34,7 @@
 
 #define RPGATTRNAMES \
     N(ai) \
+    N(aigroup) \
     N(hp) \
     N(mana) \
     N(gold) \



