瀏覽代碼

Adds support for sharing battle-type Achievements (#5021)

* Fixes #5018.
* Adds support for sharing battle-type Achievements when killing monsters.
* The behavior mimics Quest objectives.
* Adds a battle_config to easily toggle (off by default until confirmed on kRO).
Thanks to @MccloudBR's suggestion!
Aleos 5 年之前
父節點
當前提交
5647c875d6
共有 6 個文件被更改,包括 41 次插入2 次删除
  1. 4 0
      conf/battle/monster.conf
  2. 28 0
      src/map/achievement.cpp
  3. 1 0
      src/map/achievement.hpp
  4. 1 0
      src/map/battle.cpp
  5. 1 0
      src/map/battle.hpp
  6. 6 2
      src/map/mob.cpp

+ 4 - 0
conf/battle/monster.conf

@@ -276,3 +276,7 @@ boss_nopc_idleskill_rate: 100
 // To switch it off, set it to 0.
 mob_nopc_move_rate: 100
 boss_nopc_move_rate: 100
+
+// When killing a monster, do AG_BATTLE type achievements trigger for everyone in the same party within the area?
+// Area is limited to area_size battle config.
+achievement_mob_share: no

+ 28 - 0
src/map/achievement.cpp

@@ -1040,6 +1040,34 @@ void achievement_update_objective(struct map_session_data *sd, enum e_achievemen
 	}
 }
 
+/**
+ * Map iterator subroutine to update achievement objectives for a party after killing a monster.
+ * @see map_foreachinrange
+ * @param ap: Argument list, expecting:
+ *   int Party ID
+ *   int Mob ID
+ */
+int achievement_update_objective_sub(block_list *bl, va_list ap)
+{
+	map_session_data *sd;
+	int mob_id, party_id;
+
+	nullpo_ret(bl);
+	nullpo_ret(sd = (map_session_data *)bl);
+
+	party_id = va_arg(ap, int);
+	mob_id = va_arg(ap, int);
+
+	if (sd->achievement_data.achievements == nullptr)
+		return 0;
+	if (sd->status.party_id != party_id)
+		return 0;
+
+	achievement_update_objective(sd, AG_BATTLE, 1, mob_id);
+
+	return 1;
+}
+
 /**
  * Loads achievements from the achievement db.
  */

+ 1 - 0
src/map/achievement.hpp

@@ -140,6 +140,7 @@ int *achievement_level(struct map_session_data *sd, bool flag);
 bool achievement_check_condition(struct script_code* condition, struct map_session_data* sd);
 void achievement_get_titles(uint32 char_id);
 void achievement_update_objective(struct map_session_data *sd, enum e_achievement_group group, uint8 arg_count, ...);
+int achievement_update_objective_sub(block_list *bl, va_list ap);
 void achievement_read_db(void);
 void achievement_db_reload(void);
 

+ 1 - 0
src/map/battle.cpp

@@ -8951,6 +8951,7 @@ static const struct _battle_data {
 	{ "ping_timer_inverval",                &battle_config.ping_timer_interval,             30,     0,      99999999,       },
 	{ "ping_time",                          &battle_config.ping_time,                       20,     0,      99999999,       },
 	{ "show_skill_scale",                   &battle_config.show_skill_scale,                1,      0,      1,              },
+	{ "achievement_mob_share",              &battle_config.achievement_mob_share,           0,      0,      1,              },
 
 #include "../custom/battle_config_init.inc"
 };

+ 1 - 0
src/map/battle.hpp

@@ -681,6 +681,7 @@ struct Battle_Config
 	int ping_timer_interval;
 	int ping_time;
 	int show_skill_scale;
+	int achievement_mob_share;
 
 #include "../custom/battle_config_struct.inc"
 };

+ 6 - 2
src/map/mob.cpp

@@ -3006,8 +3006,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 			else if (sd->avail_quests)
 				quest_update_objective(sd, md->mob_id);
 
-			if (achievement_db.mobexists(md->mob_id))
-				achievement_update_objective(sd, AG_BATTLE, 1, md->mob_id);
+			if (achievement_db.mobexists(md->mob_id)) {
+				if (battle_config.achievement_mob_share > 0 && sd->status.party_id > 0)
+					map_foreachinallrange(achievement_update_objective_sub, &md->bl, AREA_SIZE, BL_PC, sd->status.party_id, md->mob_id);
+				else
+					achievement_update_objective(sd, AG_BATTLE, 1, md->mob_id);
+			}
 
 			// The master or Mercenary can increase the kill count
 			if (sd->md && src && (src->type == BL_PC || src->type == BL_MER) && mob_db(md->mob_id)->lv > sd->status.base_level / 2)