From 35ec0e6456e84e299f7ca4de904df7952f74a2e4 Mon Sep 17 00:00:00 2001 From: Xanadu13 Date: Sat, 30 Dec 2023 00:25:04 +0800 Subject: [PATCH] add command and exp loot --- .../enderdragon/config/FileUpdater.java | 128 +++++++++++++----- .../listener/DragonDeathListener.java | 25 ++++ .../enderdragon/manager/DamageManager.java | 11 ++ .../enderdragon/manager/DragonManager.java | 61 +++++++++ .../enderdragon/manager/GroovyManager.java | 1 - .../xanadu/enderdragon/metadata/MyDragon.java | 3 + .../enderdragon/reward/SpecialLoot.java | 8 ++ .../pers/xanadu/enderdragon/util/Version.java | 2 +- src/main/resources/setting/default-zhcn.yml | 35 ++++- src/main/resources/setting/default.yml | 35 ++++- src/main/resources/setting/special-zhcn.yml | 35 ++++- src/main/resources/setting/special.yml | 34 ++++- 12 files changed, 335 insertions(+), 43 deletions(-) create mode 100644 src/main/java/pers/xanadu/enderdragon/reward/SpecialLoot.java diff --git a/src/main/java/pers/xanadu/enderdragon/config/FileUpdater.java b/src/main/java/pers/xanadu/enderdragon/config/FileUpdater.java index 3bca5d5..e23084f 100644 --- a/src/main/java/pers/xanadu/enderdragon/config/FileUpdater.java +++ b/src/main/java/pers/xanadu/enderdragon/config/FileUpdater.java @@ -9,40 +9,104 @@ import static pers.xanadu.enderdragon.EnderDragon.*; public class FileUpdater { public static void update() throws IOException { - FileConfiguration config_old = plugin.getConfig(); - if("2.2.0".equals(config_old.getString("version"))){ - Config.saveResource("config.yml","new/config.yml",true); - File config_new_F = new File(plugin.getDataFolder(),"new/config.yml"); - FileConfiguration config_new = YamlConfiguration.loadConfiguration(config_new_F); - config_new.set("lang",config_old.getString("lang")); - config_new.set("damage_visible_mode",config_old.getString("damage_visible_mode")); - config_new.set("damage_statistics.limit",config_old.getInt("damage_statistics.limit")); - String judge_mode = config_old.getString("special_dragon_jude_mode"); - if("edge".equals(judge_mode)) judge_mode = "weight";//"edge" is deprecated - config_new.set("special_dragon_jude_mode",judge_mode); - config_new.set("dragon_setting_file",config_old.getStringList("dragon_setting_file")); - // auto_respawn - config_new.set("auto_respawn",config_old.getConfigurationSection("auto_respawn")); - - config_new.set("respawn_cd.enable",config_old.getBoolean("respawn_cd.enable")); - config_new.set("crystal_invulnerable",config_old.getBoolean("crystal_invulnerable")); - config_new.set("resist_player_respawn",config_old.getBoolean("resist_player_respawn")); - config_new.set("resist_dragon_breath_gather",config_old.getBoolean("resist_dragon_breath_gather")); - config_new.set("main_gui",config_old.getString("main_gui")); - config_new.set("blacklist_worlds",config_old.getStringList("blacklist_worlds")); - config_new.set("item_format.reward",config_old.getString("item_format.reward")); - config_new.set("hook_plugins.MythicLib",config_old.getBoolean("hook_plugins.MythicLib")); - config_new.set("expansion.groovy",config_old.getBoolean("expansion.groovy")); - config_new.set("debug",config_old.getBoolean("debug")); - config_new.set("advanced_setting.world_env_fix",config_old.getBoolean("advanced_setting.world_env_fix")); - config_new.set("advanced_setting.save_respawn_status",config_old.getBoolean("advanced_setting.save_respawn_status")); - config_new.set("save_bossbar",config_old.getBoolean("save_bossbar")); - config_new.set("backslash_split.reward",config_old.getBoolean("backslash_split.reward")); - config_new.save(config_new_F); + boolean chinese = "Chinese".equals(config_old.getString("lang")); + File folder = new File(plugin.getDataFolder(),"setting"); + if(folder.exists()){ + File[] files = folder.listFiles(); + if(files != null){ + for(File file : files){ + FileConfiguration config = YamlConfiguration.loadConfiguration(file); + String ver = config.getString("version"); + if(!"2.2.0".equals(ver)) { + Lang.error("The version of setting/"+file.getName()+" is not supported!"); + continue; + } + String name = file.getName(); + Config.copyFile("setting/"+name,"new/setting/"+name,true); + } + File new_folder = new File(plugin.getDataFolder(),"new/setting/"); + files = new_folder.listFiles(); + if(files != null){ + for(File file : files){ + FileOutputStream out = new FileOutputStream(file,true); + if (chinese){ + out.write(("\n\n" + + "# 一些特殊的战利品\n" + + "special_loot:\n" + + " # 你可以按格式添加更多条目,但是名称不能重复\n" + + " # 如果找不到执行目标(target),所在战利品条目会被忽略\n" + + " # 目前支持的type: exp(经验), command(执行指令,可解析伤害排名)\n" + + " loot1:\n" + + " # [true/false]\n" + + " enable: false\n" + + " type: command\n" + + " # %attacker% -> 所有参与屠龙的玩家\n" + + " target: \"%attacker%\"\n" + + " # %player% -> 目标, %damage% -> 该玩家造成的总伤害\n" + + " data:\n" + + " - 'give %player% stone 1'\n" + + " - 'ed action %player% tell: 你获得了保底奖励.'\n" + + " loot2:\n" + + " enable: false\n" + + " type: command\n" + + " # %attacker_top_% -> 在屠龙中取得此排名的玩家\n" + + " target: \"%attacker_top_1%\"\n" + + " data:\n" + + " - 'ed action %player% tell: 你的伤害占比是最高的!'\n" + + " - 'ed action %player% tell: 你造成的伤害: %damage%'\n" + + " loot_exp1:\n" + + " enable: false\n" + + " type: exp\n" + + " target: \"%attacker_top_2%\"\n" + + " data:\n" + + " # 给予排名第二的玩家20点经验\n" + + " amount: 20\n" + + "\n\n" + ).getBytes()); + } + else{ + out.write(("\n\n" + + "special_loot:\n" + + " # You can add more entries with DIFFERENT name according to the format.\n" + + " # If such target not exists, this option will be ignored.\n" + + " # type: exp, command\n" + + " loot1:\n" + + " # [true/false]\n" + + " enable: false\n" + + " type: command\n" + + " # %attacker% -> all participants in dragon slaying\n" + + " target: \"%attacker%\"\n" + + " # %player% -> target, %damage% -> this player's damage to EnderDragon\n" + + " data:\n" + + " - 'give %player% stone 1'\n" + + " - 'ed action %player% tell: This is a guaranteed reward.'\n" + + " loot2:\n" + + " enable: false\n" + + " type: command\n" + + " # %attacker_top_% -> the player with exactly this rank\n" + + " target: \"%attacker_top_1%\"\n" + + " data:\n" + + " - 'ed action %player% tell: You are the one who causes the highest damage!'\n" + + " - 'ed action %player% tell: Your damage: %damage%'\n" + + " loot_exp1:\n" + + " enable: false\n" + + " type: exp\n" + + " target: \"%attacker_top_2%\"\n" + + " data:\n" + + " # add 20 exp for the rank_2 player\n" + + " amount: 20\n" + + "\n\n" + ).getBytes()); + } + out.close(); + FileConfiguration fc = YamlConfiguration.loadConfiguration(file); + fc.set("version","2.4.0"); + fc.save(file); + } + } + } } - else Lang.error("The version of config.yml is not supported!"); - Lang.info("New config files are generated in plugins/EnderDragon/new."); Lang.warn("Attention: Please confirm the accuracy before using new config!"); } diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java index ca46647..4bc73a7 100644 --- a/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java @@ -20,11 +20,14 @@ import pers.xanadu.enderdragon.manager.DamageManager; import pers.xanadu.enderdragon.manager.DragonManager; import pers.xanadu.enderdragon.manager.TimerManager; import pers.xanadu.enderdragon.metadata.MyDragon; +import pers.xanadu.enderdragon.reward.SpecialLoot; import pers.xanadu.enderdragon.util.Pair; import java.io.IOException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import static pers.xanadu.enderdragon.EnderDragon.*; @@ -80,6 +83,7 @@ public class DragonDeathListener implements Listener { } } handleBroadcast(processed,myDragon,dragon); + handleSpecialLoot(myDragon,dragon); } DamageManager.data.remove(dragon.getUniqueId()); Lang.runCommands(myDragon.death_cmd,p); @@ -90,6 +94,27 @@ public class DragonDeathListener implements Listener { } TimerManager.startTimer(dragon.getWorld().getName()); } + private static void handleSpecialLoot(final MyDragon myDragon, final EnderDragon dragon){ + List> list = DamageManager.getDamageList(dragon.getUniqueId()); + list.sort(DamageManager::sortByDamage); + Set online_players = new HashSet<>(); + Bukkit.getOnlinePlayers().forEach(player -> online_players.add(player.getName())); + List participants = myDragon.lootMap.get(0); + boolean tag = participants != null; + int size = list.size(); + for(int i=0;i pair = list.get(i); + String name = pair.first; + //玩家不在线 + if(!online_players.contains(name)) continue; + String damage = String.format("%.2f",pair.second); + //所有参与者 + if(tag) participants.forEach(loot -> loot.accept(name,damage)); + //针对特殊名次 + List loots = myDragon.lootMap.get(i+1); + if(loots!=null) loots.forEach(loot -> loot.accept(name,damage)); + } + } public static void handleBroadcast(final List list,final MyDragon myDragon,final EnderDragon dragon){ boolean find = false; for(String str : list){ diff --git a/src/main/java/pers/xanadu/enderdragon/manager/DamageManager.java b/src/main/java/pers/xanadu/enderdragon/manager/DamageManager.java index 0c2e265..a9cc278 100644 --- a/src/main/java/pers/xanadu/enderdragon/manager/DamageManager.java +++ b/src/main/java/pers/xanadu/enderdragon/manager/DamageManager.java @@ -1,5 +1,7 @@ package pers.xanadu.enderdragon.manager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; import pers.xanadu.enderdragon.util.Pair; import java.util.ArrayList; @@ -22,4 +24,13 @@ public class DamageManager { return -1; } + + + public static void gc(){ + for(UUID uuid : DamageManager.data.keySet()){ + Entity entity = Bukkit.getEntity(uuid); + if(entity == null || entity.isDead()) DamageManager.data.remove(uuid); + } + } + } diff --git a/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java b/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java index cd179e6..eb32b0c 100644 --- a/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java +++ b/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java @@ -6,6 +6,7 @@ import org.bukkit.attribute.AttributeInstance; import org.bukkit.attribute.AttributeModifier; import org.bukkit.boss.DragonBattle; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.*; @@ -17,6 +18,7 @@ import pers.xanadu.enderdragon.config.Config; import pers.xanadu.enderdragon.config.Lang; import pers.xanadu.enderdragon.metadata.DragonInfo; import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.reward.SpecialLoot; import pers.xanadu.enderdragon.util.ExtraPotionEffect; import pers.xanadu.enderdragon.metadata.MyDragon; import pers.xanadu.enderdragon.util.Version; @@ -26,6 +28,8 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ThreadLocalRandom; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static pers.xanadu.enderdragon.EnderDragon.*; @@ -44,6 +48,7 @@ public class DragonManager { private static Method getX; private static Method getY; private static Method getZ; + private static final Pattern pattern_attacker_top = Pattern.compile("%attacker_top_(\\d+)%"); public static void reload(){ new BukkitRunnable(){ @@ -263,11 +268,67 @@ public class DragonManager { } myDragon.effect_cloud_potion = effectCloudPotions; myDragon.reward_dist = RewardDist.parse(f.getConfigurationSection("reward_dist")); + ConfigurationSection loots = f.getConfigurationSection("special_loot"); + Map> loot_mp = new HashMap<>(); + if(loots != null){ + for (String key : loots.getKeys(false)) { + ConfigurationSection loot = loots.getConfigurationSection(key); + if(loot == null || !loot.getBoolean("enable")) continue; + String type = loot.getString("type"); + SpecialLoot specialLoot; + if("command".equals(type)){ + List commands = loot.getStringList("data"); + specialLoot = (player, damage) -> handleCommandLoot(commands,player,damage); + } + else if("exp".equals(type)){ + int amount = loot.getInt("data"+f.options().pathSeparator()+"amount"); + specialLoot = (player, __) -> { + Player p = Bukkit.getPlayer(player); + if(p != null) p.giveExp(amount); + }; + } + else{ + Lang.error("Unknown special_loot type: "+type); + continue; + } + String target = loot.getString("target"); + if(target == null) continue; + if("%attacker%".equals(target)){ + loot_mp.compute(0,(k,v)->{ + if(v==null) return Collections.singletonList(specialLoot); + v.add(specialLoot); + return v; + }); + } + else{ + Matcher matcher = pattern_attacker_top.matcher(target); + if (matcher.find()) { + Integer rank = Integer.parseInt(matcher.group(1)); + loot_mp.compute(rank,(k,v)->{ + if(v==null) return Collections.singletonList(specialLoot); + v.add(specialLoot); + return v; + }); + } else { + Lang.error("Wrong special_loot target: "+target); + continue; + } + } + } + } + myDragon.lootMap = loot_mp; dragons.add(myDragon); mp.put(myDragon.unique_name,myDragon); dragon_names.add(myDragon.unique_name); sum += edge; } + private static void handleCommandLoot(List list, String name, String damage){ + if(list == null) return; + for (String cmd : list) { + if(cmd.equals("")) continue; + plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(),cmd.replaceAll("%player%",name).replaceAll("%damage%",damage)); + } + } public static void disable(){ dragons.clear(); mp.clear(); diff --git a/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java b/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java index 1cc85f3..f21163e 100644 --- a/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java +++ b/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java @@ -63,7 +63,6 @@ public class GroovyManager { binding.setVariable("itemStack",player.getItemInHand()); binding.setVariable("world",player.getWorld()); GroovyShell shell = new GroovyShell(GroovyManager.class.getClassLoader(),binding,compilerConfig); - //Bukkit.broadcastMessage(lib); return shell.evaluate(lib+expression); } diff --git a/src/main/java/pers/xanadu/enderdragon/metadata/MyDragon.java b/src/main/java/pers/xanadu/enderdragon/metadata/MyDragon.java index e6de4e8..036a6d6 100644 --- a/src/main/java/pers/xanadu/enderdragon/metadata/MyDragon.java +++ b/src/main/java/pers/xanadu/enderdragon/metadata/MyDragon.java @@ -4,10 +4,12 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import pers.xanadu.enderdragon.reward.Reward; import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.reward.SpecialLoot; import pers.xanadu.enderdragon.util.ExtraPotionEffect; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class MyDragon implements Comparable{ public ItemStack icon; @@ -54,6 +56,7 @@ public class MyDragon implements Comparable{ public List effect_cloud_potion; public List datum = new ArrayList<>(); public RewardDist reward_dist; + public Map> lootMap; @Override public int compareTo(final MyDragon o) { diff --git a/src/main/java/pers/xanadu/enderdragon/reward/SpecialLoot.java b/src/main/java/pers/xanadu/enderdragon/reward/SpecialLoot.java new file mode 100644 index 0000000..e9c61a5 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/SpecialLoot.java @@ -0,0 +1,8 @@ +package pers.xanadu.enderdragon.reward; + +import java.util.function.BiConsumer; + +@FunctionalInterface +public interface SpecialLoot extends BiConsumer { + +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/Version.java b/src/main/java/pers/xanadu/enderdragon/util/Version.java index f662a54..c48f29f 100644 --- a/src/main/java/pers/xanadu/enderdragon/util/Version.java +++ b/src/main/java/pers/xanadu/enderdragon/util/Version.java @@ -9,7 +9,7 @@ import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; import static org.bukkit.Bukkit.getServer; public class Version { - public static final String setting_dragon = "2.2.0"; + public static final String setting_dragon = "2.4.0"; public static final String lang = "2.2.0"; public static final String config = "2.3.0"; public static final String data = "2.2.0"; diff --git a/src/main/resources/setting/default-zhcn.yml b/src/main/resources/setting/default-zhcn.yml index ee010c5..8ad3818 100644 --- a/src/main/resources/setting/default-zhcn.yml +++ b/src/main/resources/setting/default-zhcn.yml @@ -1,5 +1,5 @@ #文件版本,请勿修改 -version: 2.2.0 +version: 2.4.0 #用于插件内部识别,每一种末影龙的unique_name都需要设为不同值! unique_name: 'default' @@ -200,4 +200,35 @@ reward_dist: max_num: 1 rank: # 排名前几可获得奖励 - max_num: 1 \ No newline at end of file + max_num: 1 + +# 一些特殊的战利品 +special_loot: + # 你可以按格式添加更多条目,但是名称不能重复 + # 如果找不到执行目标(target),所在战利品条目会被忽略 + # 目前支持的type: exp(经验), command(执行指令,可解析伤害排名) + loot1: + # [true/false] + enable: false + type: command + # %attacker% -> 所有参与屠龙的玩家 + target: "%attacker%" + # %player% -> 目标, %damage% -> 该玩家造成的总伤害 + data: + - 'give %player% stone 1' + - 'ed action %player% tell: 你获得了保底奖励.' + loot2: + enable: false + type: command + # %attacker_top_% -> 在屠龙中取得此排名的玩家 + target: "%attacker_top_1%" + data: + - 'ed action %player% tell: 你的伤害占比是最高的!' + - 'ed action %player% tell: 你造成的伤害: %damage%' + loot_exp1: + enable: false + type: exp + target: "%attacker_top_2%" + data: + # 给予排名第二的玩家20点经验 + amount: 20 diff --git a/src/main/resources/setting/default.yml b/src/main/resources/setting/default.yml index cb54d79..08c3505 100644 --- a/src/main/resources/setting/default.yml +++ b/src/main/resources/setting/default.yml @@ -1,4 +1,4 @@ -version: 2.2.0 +version: 2.4.0 #This is used for plugin internal identification. #Please make sure the value is unique among all the types of dragons @@ -154,7 +154,7 @@ effect_cloud: #All the settings below can be disabled with a "[]".(Ex: spawn_cmd: [] ) #commands that server will run when this dragon spawn -#Attention: You shouldn't add “/” at the beginning of each command! +#Attention: Please DON'T add “/” at the beginning of each command! spawn_cmd: - '' - '' @@ -198,7 +198,7 @@ reward_dist: # killer: Only give to the final killer. # pack: Pack all items that trigger drop and distribute them to players weighted based on their damage percentage. # rank: Strictly based on player damage ranking, give the top few players with the highest damage. - # termwise: Assign the items that trigger the drop ONE BY ONE to the player based on the weighted proportion of damage. + # termwise: Assign items that trigger the drop ONE BY ONE to the player based on the weighted proportion of damage. type: killer drop: # Whether the dropped item glows. @@ -211,3 +211,32 @@ reward_dist: # Top few can receive rewards max_num: 1 +special_loot: + # You can add more entries with DIFFERENT name according to the format. + # If such target not exists, this option will be ignored. + # type: exp, command + loot1: + # [true/false] + enable: false + type: command + # %attacker% -> all participants in dragon slaying + target: "%attacker%" + # %player% -> target, %damage% -> this player's damage to EnderDragon + data: + - 'give %player% stone 1' + - 'ed action %player% tell: This is a guaranteed reward.' + loot2: + enable: false + type: command + # %attacker_top_% -> the player with exactly this rank + target: "%attacker_top_1%" + data: + - 'ed action %player% tell: You are the one who causes the highest damage!' + - 'ed action %player% tell: Your damage: %damage%' + loot_exp1: + enable: false + type: exp + target: "%attacker_top_2%" + data: + # add 20 exp for the rank_2 player + amount: 20 diff --git a/src/main/resources/setting/special-zhcn.yml b/src/main/resources/setting/special-zhcn.yml index 761613c..993daae 100644 --- a/src/main/resources/setting/special-zhcn.yml +++ b/src/main/resources/setting/special-zhcn.yml @@ -1,5 +1,5 @@ #文件版本,请勿修改 -version: 2.2.0 +version: 2.4.0 #用于插件内部识别,每一种末影龙的unique_name都需要设为不同值! unique_name: 'special001' @@ -193,4 +193,35 @@ reward_dist: max_num: 1 rank: # 排名前几可获得奖励 - max_num: 1 \ No newline at end of file + max_num: 1 + +# 一些特殊的战利品 +special_loot: + # 你可以按格式添加更多条目,但是名称不能重复 + # 如果找不到执行目标(target),所在战利品条目会被忽略 + # 目前支持的type: exp(经验), command(执行指令,可解析伤害排名) + loot1: + # [true/false] + enable: false + type: command + # %attacker% -> 所有参与屠龙的玩家 + target: "%attacker%" + # %player% -> 目标, %damage% -> 该玩家造成的总伤害 + data: + - 'give %player% stone 1' + - 'ed action %player% tell: 你获得了保底奖励.' + loot2: + enable: false + type: command + # %attacker_top_% -> 在屠龙中取得此排名的玩家 + target: "%attacker_top_1%" + data: + - 'ed action %player% tell: 你的伤害占比是最高的!' + - 'ed action %player% tell: 你造成的伤害: %damage%' + loot_exp1: + enable: false + type: exp + target: "%attacker_top_2%" + data: + # 给予排名第二的玩家20点经验 + amount: 20 diff --git a/src/main/resources/setting/special.yml b/src/main/resources/setting/special.yml index 157e92e..496b3ed 100644 --- a/src/main/resources/setting/special.yml +++ b/src/main/resources/setting/special.yml @@ -1,7 +1,7 @@ ## Special thanks to Phaxius for the translation # File version, do not edit -version: 2.2.0 +version: 2.4.0 # Unique ID used by plugin to identify each type of dragon # unique_name needs to be different in each dragon settings file @@ -229,4 +229,34 @@ reward_dist: max_num: 1 rank: # Top few can receive rewards - max_num: 1 \ No newline at end of file + max_num: 1 + +special_loot: + # You can add more entries with DIFFERENT name according to the format. + # If such target not exists, this option will be ignored. + # type: exp, command + loot1: + # [true/false] + enable: false + type: command + # %attacker% -> all participants in dragon slaying + target: "%attacker%" + # %player% -> target, %damage% -> this player's damage to EnderDragon + data: + - 'give %player% stone 1' + - 'ed action %player% tell: This is a guaranteed reward.' + loot2: + enable: false + type: command + # %attacker_top_% -> the player with exactly this rank + target: "%attacker_top_1%" + data: + - 'ed action %player% tell: You are the one who causes the highest damage!' + - 'ed action %player% tell: Your damage: %damage%' + loot_exp1: + enable: false + type: exp + target: "%attacker_top_2%" + data: + # add 20 exp for the rank_2 player + amount: 20