From ac0d6abbcce17a9e2ed51a82271a618433e450e5 Mon Sep 17 00:00:00 2001
From: gumi <git@gumi.ca>
Date: Mon, 26 Aug 2019 18:27:03 -0400
Subject: fix mob slaves not attacking

---
 src/map/atcommand.cpp  |  1 -
 src/map/battle.cpp     | 30 ++++++++++-------------
 src/map/mob.cpp        | 65 ++++++++++++++++++++++++++++++++++----------------
 src/map/script-fun.cpp |  1 -
 4 files changed, 56 insertions(+), 41 deletions(-)

diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index 868daa6..a5eb69b 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -4572,7 +4572,6 @@ ATCE atcommand_summon(Session *s, dumb_ptr<map_session_data> sd,
             tick_t tick = gettick();
 
             md->master_id = sd->bl_id;
-            md->state.special_mob_ai = 1;
             md->mode = get_mob_db(md->mob_class).mode | MobMode::AGGRESSIVE;
             md->deletetimer = Timer(tick + (std::max(minutes, 120) * 1_min),
                                 std::bind(mob_timer_delete, ph::_1, ph::_2,
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index a4596e9..6379b60 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -2072,28 +2072,22 @@ int battle_check_target(dumb_ptr<block_list> src, dumb_ptr<block_list> target,
         dumb_ptr<mob_data> md = src->is_mob();
         if (md && (md->master_id || md->parent_id))
         {
-            if (md->master_id == target->bl_id || md->parent_id == target->bl_id)    // 主なら肯定
+            if (md->master_id == target->bl_id || md->parent_id == target->bl_id) // can't attack my master or my parent
                 return 1;
-            if (md->state.special_mob_ai)
+
+            if (target->bl_type == BL::MOB)
             {
-                if (target->bl_type == BL::MOB)
-                {               //special_mob_aiで対象がMob
-                    dumb_ptr<mob_data> tmd = target->is_mob();
-                    if (tmd)
-                    {
-                        if (tmd->master_id != md->master_id)    //召喚主が一緒でなければ否定
-                            return 0;
-                        else
-                        {       //召喚主が一緒なので肯定したいけど自爆は否定
-                            if (md->state.special_mob_ai > 2)
-                                return 0;
-                            else
-                                return 1;
-                        }
-                    }
+                dumb_ptr<mob_data> tmd = target->is_mob();
+                if (tmd)
+                {
+                    if (tmd->master_id != md->master_id && tmd->parent_id != md->parent_id) // different master and parent
+                        return 0;
+                    else
+                        return 1; // can't attack a mob that has the same master or parent as me
                 }
             }
-            if ((ss = map_id2bl(md->master_id)) == nullptr)
+
+            if ((ss = map_id2bl(md->parent_id)) == nullptr)
                 return -1;
         }
     }
diff --git a/src/map/mob.cpp b/src/map/mob.cpp
index 1614fe5..4c689d9 100644
--- a/src/map/mob.cpp
+++ b/src/map/mob.cpp
@@ -1679,7 +1679,8 @@ int mob_ai_sub_hard_slavemob(dumb_ptr<mob_data> md, tick_t tick)
                     || race == Race::_insect
                     || race == Race::_demon))
             {                   // 妨害がないか判定
-
+                md->master_id = mmd->master_id;
+                md->mode |= mmd->mode ^ get_mob_db(mmd->mob_class).mode;
                 md->target_id = sd->bl_id;
                 md->state.attackable = true;
                 md->min_chase =
@@ -1857,20 +1858,19 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick)
 
     md->state.master_check = 0;
     // Processing of summoned monster attacked by owner
-    if (md->last_master_id && md->state.special_mob_ai)
+    if (md->last_master_id)
     {
         if (((bl = map_id2bl(md->last_master_id)) != nullptr && md->bl_m != bl->bl_m) || (bl = map_id2bl(md->last_master_id)) == nullptr)
         {
             md->last_master_id = BlockId();
             md->parent_id = BlockId();
-            md->state.special_mob_ai = 0;
             md->mode = get_mob_db(md->mob_class).mode;
             md->target_id = BlockId();
             md->attacked_id = BlockId();
         }
     }
     // Processing of slave monster
-    if (md->parent_id && md->state.special_mob_ai == 0)
+    if (md->parent_id)
         mob_ai_sub_hard_slavemob(md, tick);
 
     // アクティヴモンスターの策敵 (?? of a bitter taste TIVU monster)
@@ -1879,7 +1879,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick)
         && battle_config.monster_active_enable == 1)
     {
         i = 0;
-        if (md->state.special_mob_ai)
+        if (md->master_id)
         {
             map_foreachinarea(std::bind(mob_ai_sub_hard_activesearch, ph::_1, md, &i),
                     md->bl_m,
@@ -2073,8 +2073,7 @@ void mob_ai_sub_hard(dumb_ptr<block_list> bl, tick_t tick)
     // mobs that are not slaves can random-walk
     if (bool(mode & MobMode::CAN_MOVE)
         && mob_can_move(md)
-        && (!md->parent_id || md->state.special_mob_ai
-            || md->master_dist > 10))
+        && (!md->parent_id || md->master_dist > 10))
     {
         // if walktime is more than 7 seconds in the future,
         // set it to somewhere between 3 and 5 seconds
@@ -2383,11 +2382,20 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
     {
         /* If the master hits a monster, have the monster turn against him */
         md->last_master_id = md->master_id;
-        //md->parent_id = BlockId();
         md->master_id = BlockId();
-        md->mode = MobMode::war;        /* Regular war mode */
         md->target_id = src->bl_id;
         md->attacked_id = src->bl_id;
+
+        if (md->parent_id) {
+            dumb_ptr<mob_data> p_md = map_id_is_mob(md->parent_id);
+
+            if (p_md != nullptr) {
+                // turn the parent against the master
+                p_md->last_master_id = p_md->master_id;
+                p_md->master_id = BlockId();
+                mob_aggravate(p_md, src);
+            }
+        }
     }
 
     max_hp = battle_get_max_hp(md);
@@ -2452,11 +2460,11 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
             }
         damage_logged_pc:
 
-            if (!md->attacked_id && md->state.special_mob_ai == 0)
+            if (!md->attacked_id)
                 md->attacked_id = sd->bl_id;
         }
         if (src && src->bl_type == BL::MOB
-            && src->is_mob()->state.special_mob_ai)
+            && src->is_mob()->master_id)
         {
             dumb_ptr<mob_data> md2 = src->is_mob();
             dumb_ptr<block_list> master_bl = map_id2bl(md2->master_id);
@@ -2484,7 +2492,7 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
                 app.dmg = damage;
                 md->dmglogv.push_back(app);
 
-                if (!md->attacked_id && md->state.special_mob_ai == 0)
+                if (!md->attacked_id)
                     md->attacked_id = md2->master_id;
             }
         damage_logged_slave:
@@ -2535,6 +2543,17 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
         std::vector<DmgLogParty> ptv;
 
         int mvp_dmg = 0, second_dmg = 0, third_dmg = 0;
+        bool summoned_by_nongm = false;
+
+        if (md->master_id && battle_config.alchemist_summon_reward != 1)
+        {
+            dumb_ptr<map_session_data> m_sd = map_id_is_player(md->master_id);
+
+            if (!m_sd || !pc_isGM(m_sd).satisfies(GmLevel::from(60_u32))) {
+                summoned_by_nongm = true;
+            }
+        }
+
         for (mob_data::DmgLogEntry& dle : md->dmglogv)
         {
             dumb_ptr<map_session_data> tmpsdi = map_id2sd(dle.id);
@@ -2594,9 +2613,10 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
             {
                 base_exp *= 1.15;   // pk_mode additional exp if monster >20 levels [Valaris]
             }
-            if (md->state.special_mob_ai >= 1
-                && battle_config.alchemist_summon_reward != 1)
-                base_exp = 0;   // Added [Valaris]
+            if (summoned_by_nongm)
+            {
+                    base_exp = 0; // no exp for mobs summoned by non-GMs
+            }
             job_exp = get_mob_db(md->mob_class).job_exp * per / 256;
             if (job_exp < 1)
                 job_exp = 1;
@@ -2605,9 +2625,10 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
             {
                 job_exp *= 1.15;    // pk_mode additional exp if monster >20 levels [Valaris]
             }
-            if (md->state.special_mob_ai >= 1
-                && battle_config.alchemist_summon_reward != 1)
-                job_exp = 0;    // Added [Valaris]
+            if (summoned_by_nongm)
+            {
+                    job_exp = 0; // no exp for mobs summoned by non-GMs
+            }
 
             PartyId pid = tmpsdi->status.party_id;
             if (pid)
@@ -2652,8 +2673,8 @@ int mob_damage(dumb_ptr<block_list> src, dumb_ptr<mob_data> md, int damage,
         {
             for (int i = 0; i < 8; i++)
             {
-                if (md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1)    // Added [Valaris]
-                    break;      // End
+                if (summoned_by_nongm)
+                    break; // no drops for mobs spawned by non-GMs
 
                 if (!get_mob_db(md->mob_class).dropitem[i].nameid)
                     continue;
@@ -2975,6 +2996,8 @@ int mob_summonslave(dumb_ptr<mob_data> md2, int *value_, int amount, int flag)
             if (flag) {
                 md->master_id = md2->master_id; // tell the subslave who actually owns them
                 md->parent_id = md2->bl_id; // tell the subslave who spawned them
+                md->mode = get_mob_db(md->mob_class).mode;
+                md->mode |= md2->mode ^ get_mob_db(md2->mob_class).mode; // if our mode has special flags, hand them to our children too
             }
         }
     }
@@ -3297,7 +3320,7 @@ int mobskill_use(dumb_ptr<mob_data> md, tick_t tick,
     if (battle_config.mob_skill_use == 0 || md->skilltimer)
         return 0;
 
-    if (md->state.special_mob_ai && md->parent_id)
+    if (md->master_id && md->parent_id) // slaves of summoned mobs
         return 0;
 
     for (mob_skill& msii : ms)
diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp
index 8c90052..3becf10 100644
--- a/src/map/script-fun.cpp
+++ b/src/map/script-fun.cpp
@@ -2547,7 +2547,6 @@ void builtin_summon(ScriptState *st)
         switch (monster_attitude)
         {
             case MonsterAttitude::SERVANT:
-                mob->state.special_mob_ai = 1;
                 mob->mode |= MobMode::AGGRESSIVE;
                 break;
 
-- 
cgit v1.2.3-70-g09d2