]> git.seodisparate.com - TurnBasedMinecraftMod/commitdiff
Use .toml instead of .xml for config
authorStephen Seo <seo.disparate@gmail.com>
Sat, 20 Oct 2018 08:54:32 +0000 (17:54 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 25 Oct 2018 05:31:06 +0000 (14:31 +0900)
Changelog.md
build.gradle
src/main/java/com/seodisparate/TurnBasedMinecraft/client/ClientProxy.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackerViaBow.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/Config.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/PlayerJoinEventHandler.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/TurnBasedMinecraftMod.java
src/main/resources/assets/TurnBasedMinecraft/TBM_Config.toml [new file with mode: 0644]
src/main/resources/assets/TurnBasedMinecraft/TBM_Config.xml [deleted file]

index 193d87e85a7ced08bce0094a74da63fbe4657b56..ff42673b9636d186462cdc1002ef21b1c292e887 100644 (file)
@@ -1,3 +1,11 @@
+# Version 1.6
+
+Fix bug where player can start battle with self.
+
+Change config to use ".toml" instead of ".xml".
+
+Change how battle info text is displayed.
+
 # Version 1.5
 
 Fix proper consumption of food/potion items in battle.
index 2ea243c3c8ab8f7c6bbf6008a46f7cdd951a0c15..80ecc87b825e6d9eedd6f7688af0efb70b04b58c 100644 (file)
@@ -5,13 +5,14 @@ buildscript {
     }\r
     dependencies {\r
         classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'\r
+        classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.1'\r
     }\r
 }\r
 apply plugin: 'net.minecraftforge.gradle.forge'\r
-//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.\r
+apply plugin: 'com.github.johnrengelman.shadow'\r
 \r
-version = "1.5"\r
-group = "com.seodisparate.TurnBasedMinecraft" // http://maven.apache.org/guides/mini/guide-naming-conventions.html\r
+version = "1.6"\r
+group = "com.seodisparate.TurnBasedMinecraft"\r
 archivesBaseName = "TurnBasedMinecraft"\r
 \r
 sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.\r
@@ -37,6 +38,7 @@ dependencies {
     // or you may define them like so..\r
     //compile "some.group:artifact:version:classifier"\r
     //compile "some.group:artifact:version"\r
+    compile "net.consensys.cava:cava-toml:0.3.1"\r
       \r
     // real examples\r
     //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev'  // adds buildcraft to the dev env\r
@@ -74,3 +76,14 @@ processResources {
         exclude 'mcmod.info'\r
     }\r
 }\r
+\r
+shadowJar {\r
+       classifier ""\r
+\r
+       relocate 'net.consensys.cava', 'shadow.turnbasedmc.net.consensys.cava'\r
+       relocate 'org.antlr.v4', 'shadow.turnbasedmc.org.antlr.v4'\r
+       relocate 'javax.annotation', 'shadow.turnbasedmc.javax.annotation'\r
+}\r
+\r
+reobf { shadowJar { mappingType = "SEARGE" } }\r
+tasks.reobfShadowJar.mustRunAfter shadowJar\r
index 3089355eb8b102f8ef596657156b8e48888c31fe..c71788c32cd3e358c65f44c1890361c700c14d81 100644 (file)
@@ -7,7 +7,9 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.settings.GameSettings;
 import net.minecraft.entity.Entity;
 import net.minecraft.util.SoundCategory;
+import net.minecraft.util.text.ITextComponent;
 import net.minecraft.util.text.TextComponentString;
+import net.minecraft.util.text.TextFormatting;
 
 public class ClientProxy extends CommonProxy
 {
@@ -158,7 +160,12 @@ public class ClientProxy extends CommonProxy
     @Override
     public void displayString(String message)
     {
-        Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(message));
+        ITextComponent prefix = new TextComponentString("TBM: ");
+        prefix.getStyle().setColor(TextFormatting.GREEN).setBold(true);
+        ITextComponent text = new TextComponentString(message);
+        prefix.appendSibling(text);
+        text.getStyle().setColor(TextFormatting.WHITE).setBold(false);
+        Minecraft.getMinecraft().player.sendMessage(prefix);
     }
 
     @Override
index 7cdaca7cce94b67fc16525dd923e6e01f9c966a1..eb4497f5210d929562788f4b9d67afdecb626b31 100644 (file)
@@ -5,18 +5,18 @@ import net.minecraft.entity.Entity;
 public class AttackerViaBow
 {
     public static long ATTACK_TIMEOUT = 10000000000L;
-    
+
     public Entity entity;
     public long attackTime;
     public int battleID;
-    
+
     public AttackerViaBow()
     {
         entity = null;
         attackTime = 0;
         battleID = -1;
     }
-    
+
     public AttackerViaBow(Entity entity, int battleID)
     {
         this.entity = entity;
index 057153d9924c7ae37a642dba5fd27349505d0083..bb04d96246cedef4de2ce5f3f1e7c2c7ee23ce90 100644 (file)
@@ -1,23 +1,16 @@
 package com.seodisparate.TurnBasedMinecraft.common;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
-import javax.xml.stream.FactoryConfigurationError;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-
+import net.consensys.cava.toml.*;
 import org.apache.logging.log4j.Logger;
 
 public class Config
@@ -36,8 +29,8 @@ public class Config
     private int playerEvasion = 10;
     private int defenseDuration = 1;
     private int fleeGoodProbability = 90;
-    private int fleeBadProbability = 40;
-    private int minimumHitPercentage = 1;
+    private int fleeBadProbability = 35;
+    private int minimumHitPercentage = 4;
     private int maxInBattle = 8;
     private Set<String> musicBattleTypes;
     private Set<String> musicSillyTypes;
@@ -50,7 +43,7 @@ public class Config
     private boolean oldBattleBehaviorEnabled = false;
     private int leaveBattleCooldownSeconds = 5;
     private int aggroStartBattleDistance = 8;
-    
+
     public Config(Logger logger)
     {
         entityInfoMap = new HashMap<String, EntityInfo>();
@@ -59,21 +52,9 @@ public class Config
         musicBattleTypes = new HashSet<String>();
         musicSillyTypes = new HashSet<String>();
         battleIgnoringPlayers = new HashSet<Integer>();
-        
-        int internalVersion = 0;
-        try
-        {
-            InputStream is = getClass().getResourceAsStream(TurnBasedMinecraftMod.CONFIG_INTERNAL_PATH);
-            if(is == null)
-            {
-                logger.error("Internal resource is null");
-            }
-            else
-            {
-                internalVersion = getConfigFileVersion(is);
-            }
-        } catch (Throwable t) {}
-        
+
+        int internalVersion = getConfigFileVersion(getClass().getResourceAsStream(TurnBasedMinecraftMod.CONFIG_INTERNAL_PATH));
+
         if(internalVersion == 0)
         {
             logger.error("Failed to check version of internal config file");
@@ -82,7 +63,7 @@ public class Config
         {
             configVersion = internalVersion;
         }
-        
+
         try
         {
             File testLoad = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
@@ -95,15 +76,15 @@ public class Config
         {
             logger.error("Failed to check/create-new config file");
         }
-        
-        // parse xml
+
+        // parse config
         File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
         if(!configFile.exists() || !configFile.canRead())
         {
             logger.error("Failed to read/parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
             return;
         }
-        
+
         int configVersion = getConfigFileVersion(configFile);
         if(configVersion < this.configVersion)
         {
@@ -125,7 +106,7 @@ public class Config
             logger.error("Failed to parse config file!");
         }
     }
-    
+
     private void writeConfig() throws IOException
     {
         File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
@@ -146,7 +127,7 @@ public class Config
         configStream.close();
         configOutput.close();
     }
-    
+
     private void moveOldConfig()
     {
         File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
@@ -155,316 +136,604 @@ public class Config
             configFile.renameTo(new File(TurnBasedMinecraftMod.CONFIG_DIRECTORY
                     + "TBM_Config_"
                     + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())
-                    + ".xml"));
+                    + ".toml"));
         }
     }
-    
-    private boolean parseConfig(File configFile) throws XMLStreamException, FactoryConfigurationError, IOException
+
+    private boolean parseConfig(File configFile) throws IOException
     {
-        FileInputStream fis = new FileInputStream(configFile);
-        XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(fis);
-        while(xmlReader.hasNext())
+        TomlParseResult parseResult = Toml.parse(configFile.toPath(), TomlVersion.V0_5_0);
+
+        // client_config
+        {
+            TomlArray battleMusicCategories = parseResult.getArray("client_config.battle_music");
+            if(battleMusicCategories != null)
+            {
+                for (int i = 0; i < battleMusicCategories.size(); ++i)
+                {
+                    musicBattleTypes.add(battleMusicCategories.getString(i));
+                }
+            }
+            else
+            {
+                musicBattleTypes.add("monster");
+                musicBattleTypes.add("animal");
+                musicBattleTypes.add("boss");
+                musicBattleTypes.add("player");
+                logNotFound("client_config.battle_music");
+            }
+        }
+        {
+            TomlArray sillyMusicCategories = parseResult.getArray("client_config.silly_music");
+            if(sillyMusicCategories != null)
+            {
+                for (int i = 0; i < sillyMusicCategories.size(); ++i)
+                {
+                    musicSillyTypes.add(sillyMusicCategories.getString(i));
+                }
+            }
+            else
+            {
+                musicSillyTypes.add("passive");
+                logNotFound("client_config.silly_music");
+            }
+        }
+
+        try
+        {
+            sillyMusicThreshold = parseResult.getLong("client_config.silly_music_threshold").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            sillyMusicThreshold = 40;
+            logNotFound("client_config.silly_music_threshold", "40");
+        }
+
+        // server_config
+        try
+        {
+            leaveBattleCooldownSeconds = parseResult.getLong("server_config.leave_battle_cooldown").intValue();
+            if (leaveBattleCooldownSeconds < 1)
+            {
+                leaveBattleCooldownSeconds = 1;
+            } else if (leaveBattleCooldownSeconds > 10)
+            {
+                leaveBattleCooldownSeconds = 10;
+            }
+        }
+        catch (NullPointerException e)
+        {
+            leaveBattleCooldownSeconds = 5;
+            logNotFound("server_config.leave_battle_cooldown", "5");
+        }
+
+        try
+        {
+            aggroStartBattleDistance = parseResult.getLong("server_config.aggro_start_battle_max_distance").intValue();
+            if (aggroStartBattleDistance < 5)
+            {
+                aggroStartBattleDistance = 5;
+            } else if (aggroStartBattleDistance > 50)
+            {
+                aggroStartBattleDistance = 50;
+            }
+        }
+        catch (NullPointerException e)
+        {
+            aggroStartBattleDistance = 8;
+            logNotFound("server_config.aggro_start_battle_max_distance", "8");
+        }
+
+        try
+        {
+            oldBattleBehaviorEnabled = parseResult.getBoolean("server_config.old_battle_behavior");
+        }
+        catch (NullPointerException e)
+        {
+            oldBattleBehaviorEnabled = false;
+            logNotFound("server_config.old_battle_behavior", "false");
+        }
+
+        try
+        {
+            onlyOPsSelfDisableTB = !parseResult.getBoolean("server_config.anyone_can_disable_tbm_for_self");
+        }
+        catch (NullPointerException e)
+        {
+            onlyOPsSelfDisableTB = true;
+            logNotFound("server_config.anyone_can_disable_tbm_for_self", "false");
+        }
+
+        try
+        {
+            maxInBattle = parseResult.getLong("server_config.max_in_battle").intValue();
+            if (maxInBattle < 2)
+            {
+                maxInBattle = 2;
+            }
+        }
+        catch (NullPointerException e)
+        {
+            maxInBattle = 8;
+            logNotFound("server_config.max_in_battle", "8");
+        }
+
+        try
+        {
+            freezeCombatantsInBattle = parseResult.getBoolean("server_config.freeze_battle_combatants");
+        }
+        catch (NullPointerException e)
         {
-            xmlReader.next();
-            if(xmlReader.isStartElement())
+            freezeCombatantsInBattle = false;
+            logNotFound("server_config.freeze_battle_combatants", "false");
+        }
+
+        try
+        {
+            TomlArray ignoreTypes = parseResult.getArray("server_config.ignore_battle_types");
+            for(int i = 0; i < ignoreTypes.size(); ++i)
+            {
+                ignoreBattleTypes.add(ignoreTypes.getString(i));
+            }
+        }
+        catch (NullPointerException e)
+        {
+            ignoreBattleTypes.add("passive");
+            ignoreBattleTypes.add("boss");
+            logNotFound("server_config.ignore_battle_types");
+        }
+
+        try
+        {
+            playerSpeed = parseResult.getLong("server_config.player_speed").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            playerSpeed = 50;
+            logNotFound("server_config.player_speed", "50");
+        }
+        try
+        {
+            playerHasteSpeed = parseResult.getLong("server_config.player_haste_speed").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            playerHasteSpeed = 80;
+            logNotFound("server_config.player_haste_speed", "80");
+        }
+        try
+        {
+            playerSlowSpeed = parseResult.getLong("server_config.player_slow_speed").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            playerSlowSpeed = 20;
+            logNotFound("server_config.player_slow_speed", "20");
+        }
+        try
+        {
+            playerAttackProbability = parseResult.getLong("server_config.player_attack_probability").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            playerAttackProbability = 90;
+            logNotFound("server_config.player_attack_probability", "90");
+        }
+        try
+        {
+            playerEvasion = parseResult.getLong("server_config.player_evasion").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            playerEvasion = 10;
+            logNotFound("server_config.player_evasion", "10");
+        }
+
+        try
+        {
+            defenseDuration = parseResult.getLong("server_config.defense_duration").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            defenseDuration = 1;
+            logNotFound("server_config.defense_duration", "1");
+        }
+
+        try
+        {
+            fleeGoodProbability = parseResult.getLong("server_config.flee_good_probability").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            fleeGoodProbability = 90;
+            logNotFound("server_config.flee_good_probability", "90");
+        }
+        try
+        {
+            fleeBadProbability = parseResult.getLong("server_config.flee_bad_probability").intValue();
+        }
+        catch (NullPointerException e)
+        {
+            fleeBadProbability = 35;
+            logNotFound("server_config.flee_bad_probability", "35");
+        }
+
+        try
+        {
+            minimumHitPercentage = parseResult.getLong("server_config.minimum_hit_percentage").intValue();
+            if (minimumHitPercentage < 1)
+            {
+                minimumHitPercentage = 1;
+            }
+        }
+        catch (NullPointerException e)
+        {
+            minimumHitPercentage = 4;
+            logNotFound("server_config.minimum_hit_percentage", "4");
+        }
+
+        try
+        {
+            battleDecisionDurationNanos = parseResult.getLong("server_config.battle_turn_time_seconds") * 1000000000L;
+            if(battleDecisionDurationNanos < BATTLE_DECISION_DURATION_NANO_MIN)
             {
-                if(xmlReader.getLocalName().equals("TurnBasedMinecraftConfig"))
+                battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_MIN;
+                logger.warn("Config \"server_config.battle_turn_time_seconds\" too low, defaulting to minimum \"5\"");
+            }
+            else if(battleDecisionDurationNanos > BATTLE_DECISION_DURATION_NANO_MAX)
+            {
+                battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_MAX;
+                logger.warn("Config \"server_config.battle_turn_time_seconds\" too high, defaulting to maximum \"60\"");
+            }
+        }
+        catch (NullPointerException e)
+        {
+            battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_DEFAULT;
+            logNotFound("server_config.battle_turn_time_seconds", "15");
+        }
+
+        // entities
+        TomlArray entityArray = parseResult.getArray("server_config.entity");
+        if(entityArray != null)
+        {
+            for(int i = 0; i < entityArray.size(); ++i)
+            {
+                TomlTable entity = entityArray.getTable(i);
+                EntityInfo eInfo = new EntityInfo();
+                try
+                {
+                    eInfo.classType = Class.forName(entity.getString("name"));
+                }
+                catch (ClassNotFoundException e)
                 {
+                    logger.error("Entity with class name \"" + entity.getString("name") + "\" not found, skipping...");
                     continue;
                 }
-                else if(xmlReader.getLocalName().equals("Version"))
+                catch (NullPointerException e)
                 {
+                    logger.error("Entity does not have \"name\", skipping...");
                     continue;
                 }
-                else if(xmlReader.getLocalName().equals("LeaveBattleCooldown"))
+
+                try
                 {
-                    leaveBattleCooldownSeconds = Integer.parseInt(xmlReader.getElementText());
-                    if(leaveBattleCooldownSeconds <= 0)
+                    eInfo.attackPower = entity.getLong("attack_power").intValue();
+                    if(eInfo.attackPower < 0)
                     {
-                        leaveBattleCooldownSeconds = 1;
+                        eInfo.attackPower = 0;
+                        logEntityInvalidValue("attack_power", eInfo.classType.getName(), "0");
                     }
-                    else if(leaveBattleCooldownSeconds > 10)
+                }
+                catch (NullPointerException e)
+                {
+                    logEntityMissingRequiredValue("attack_power", eInfo.classType.getName());
+                    continue;
+                }
+
+                try
+                {
+                    eInfo.attackProbability = entity.getLong("attack_probability").intValue();
+                    if(eInfo.attackProbability < 0 || eInfo.attackProbability > 100)
                     {
-                        leaveBattleCooldownSeconds = 10;
+                        eInfo.attackProbability = 35;
+                        logEntityInvalidValue("attack_probability", eInfo.classType.getName(), "35");
                     }
                 }
-                else if(xmlReader.getLocalName().equals("AggroStartBattleDistance"))
+                catch (NullPointerException e)
+                {
+                    logEntityMissingRequiredValue("attack_probability", eInfo.classType.getName());
+                    continue;
+                }
+
+                try
                 {
-                    aggroStartBattleDistance = Integer.parseInt(xmlReader.getElementText());
-                    if(aggroStartBattleDistance < 5)
+                    eInfo.attackEffect = EntityInfo.Effect.fromString(entity.getString("attack_effect"));
+                    if(eInfo.attackEffect != EntityInfo.Effect.UNKNOWN)
                     {
-                        aggroStartBattleDistance = 5;
+                        eInfo.attackEffectProbability = entity.getLong("attack_effect_probability").intValue();
+                        if(eInfo.attackEffectProbability < 0 || eInfo.attackEffectProbability > 100)
+                        {
+                            eInfo.attackEffectProbability = 35;
+                            logEntityInvalidValue("attack_effect", eInfo.classType.getName(), "35");
+                        }
                     }
-                    else if(aggroStartBattleDistance > 50)
+                }
+                catch (NullPointerException e)
+                {
+                    eInfo.attackEffect = EntityInfo.Effect.UNKNOWN;
+                }
+
+                try
+                {
+                    eInfo.attackVariance = entity.getLong("attack_variance").intValue();
+                    if(eInfo.attackVariance < 0)
                     {
-                        aggroStartBattleDistance = 50;
+                        eInfo.attackVariance = 0;
+                        logEntityInvalidValue("attack_variance", eInfo.classType.getName(), "0");
                     }
                 }
-                else if(xmlReader.getLocalName().equals("OldBattleBehavior"))
+                catch (NullPointerException e)
+                {
+                    eInfo.attackVariance = 0;
+                }
+
+                try
                 {
-                    if(xmlReader.getElementText().toLowerCase().equals("false"))
+                    eInfo.defenseDamage = entity.getLong("defense_damage").intValue();
+                    if(eInfo.defenseDamage < 0)
                     {
-                        oldBattleBehaviorEnabled = false;
+                        eInfo.defenseDamage = 0;
+                        logEntityInvalidValue("defense_damage", eInfo.classType.getName(), "0");
                     }
                     else
                     {
-                        oldBattleBehaviorEnabled = true;
+                        eInfo.defenseDamageProbability = entity.getLong("defense_damage_probability").intValue();
+                        if(eInfo.defenseDamageProbability < 0 || eInfo.defenseDamageProbability > 100)
+                        {
+                            eInfo.defenseDamageProbability = 35;
+                            logEntityInvalidValue("defense_damage_probability", eInfo.classType.getName(), "35");
+                        }
                     }
                 }
-                else if(xmlReader.getLocalName().equals("WhoCanDisableTurnBasedForSelf"))
+                catch (NullPointerException e)
                 {
-                    if(xmlReader.getElementText().toLowerCase().equals("any"))
-                    {
-                        onlyOPsSelfDisableTB = false;
-                    }
-                    else
+                    eInfo.defenseDamage = 0;
+                }
+
+                try
+                {
+                    eInfo.evasion = entity.getLong("evasion").intValue();
+                    if(eInfo.evasion < 0 || eInfo.evasion > 100)
                     {
-                        onlyOPsSelfDisableTB = true;
+                        eInfo.evasion = 20;
+                        logEntityInvalidValue("evasion", eInfo.classType.getName(), "20");
                     }
                 }
-                else if(xmlReader.getLocalName().equals("MaxInBattle"))
+                catch (NullPointerException e)
                 {
-                    maxInBattle = Integer.parseInt(xmlReader.getElementText());
+                    logEntityMissingRequiredValue("evasion", eInfo.classType.getName());
+                    continue;
                 }
-                else if(xmlReader.getLocalName().equals("FreezeBattleCombatants"))
+
+                try
                 {
-                    freezeCombatantsInBattle = !xmlReader.getElementText().toLowerCase().equals("false");
+                    eInfo.speed = entity.getLong("speed").intValue();
                 }
-                else if(xmlReader.getLocalName().equals("IgnoreBattleTypes"))
+                catch (NullPointerException e)
                 {
-                    do
-                    {
-                        xmlReader.next();
-                        if(xmlReader.isStartElement())
-                        {
-                            ignoreBattleTypes.add(xmlReader.getLocalName().toLowerCase());
-                        }
-                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("IgnoreBattleTypes")));
+                    logEntityMissingRequiredValue("speed", eInfo.classType.getName());
                 }
-                else if(xmlReader.getLocalName().equals("BattleMusic"))
+
+                try
                 {
-                    do
-                    {
-                        xmlReader.next();
-                        if(xmlReader.isStartElement())
-                        {
-                            if(xmlReader.getLocalName().equals("Normal"))
-                            {
-                                do
-                                {
-                                    xmlReader.next();
-                                    if(xmlReader.isStartElement())
-                                    {
-                                        musicBattleTypes.add(xmlReader.getLocalName().toLowerCase());
-                                    }
-                                } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("Normal")));
-                            }
-                            else if(xmlReader.getLocalName().equals("Silly"))
-                            {
-                                do
-                                {
-                                    xmlReader.next();
-                                    if(xmlReader.isStartElement())
-                                    {
-                                        musicSillyTypes.add(xmlReader.getLocalName().toLowerCase());
-                                    }
-                                } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("Silly")));
-                            }
-                        }
-                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("BattleMusic")));
+                    eInfo.ignoreBattle = entity.getBoolean("ignore_battle");
                 }
-                else if(xmlReader.getLocalName().equals("PlayerStats"))
+                catch (NullPointerException e)
                 {
-                    do
-                    {
-                        xmlReader.next();
-                        if(xmlReader.isStartElement())
-                        {
-                            if(xmlReader.getLocalName().equals("Speed"))
-                            {
-                                playerSpeed = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("HasteSpeed"))
-                            {
-                                playerHasteSpeed = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("SlowSpeed"))
-                            {
-                                playerSlowSpeed = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("AttackProbability"))
-                            {
-                                playerAttackProbability = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("Evasion"))
-                            {
-                                playerEvasion = Integer.parseInt(xmlReader.getElementText());
-                            }
-                        }
-                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("PlayerStats")));
+                    eInfo.ignoreBattle = false;
                 }
-                else if(xmlReader.getLocalName().equals("DefenseDuration"))
+
+                eInfo.category = entity.getString("category");
+                if(eInfo.category == null)
                 {
-                    defenseDuration = Integer.parseInt(xmlReader.getElementText());
+                    logEntityMissingRequiredValue("category", eInfo.classType.getName());
+                    continue;
                 }
-                else if(xmlReader.getLocalName().equals("FleeGoodProbability"))
+
+                try
                 {
-                    fleeGoodProbability = Integer.parseInt(xmlReader.getElementText());
+                    eInfo.decisionAttack = entity.getLong("decision_attack_probability").intValue();
                 }
-                else if(xmlReader.getLocalName().equals("FleeBadProbability"))
+                catch (NullPointerException e)
                 {
-                    fleeBadProbability = Integer.parseInt(xmlReader.getElementText());
+                    logEntityMissingRequiredValue("decision_attack_probability", eInfo.classType.getName());
+                    continue;
                 }
-                else if(xmlReader.getLocalName().equals("MinimumHitPercentage"))
+
+                try
                 {
-                    minimumHitPercentage = Integer.parseInt(xmlReader.getElementText());
-                    if(minimumHitPercentage < 1)
-                    {
-                        minimumHitPercentage = 1;
-                    }
+                    eInfo.decisionDefend = entity.getLong("decision_defend_probability").intValue();
                 }
-                else if(xmlReader.getLocalName().equals("BattleTurnTimeSeconds"))
+                catch (NullPointerException e)
                 {
-                    try
-                    {
-                        int seconds = Integer.parseInt(xmlReader.getElementText());
-                        battleDecisionDurationNanos = (long)(seconds) * 1000000000L;
-                        if(battleDecisionDurationNanos < BATTLE_DECISION_DURATION_NANO_MIN)
-                        {
-                            battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_MIN;
-                        }
-                        else if(battleDecisionDurationNanos > BATTLE_DECISION_DURATION_NANO_MAX)
-                        {
-                            battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_MAX;
-                        }
-                    } catch (Throwable t)
-                    {
-                        logger.warn("Unable to get value for \"BattleTurnTimeSeconds\" from config, using default");
-                        battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_DEFAULT;
-                    }
+                    logEntityMissingRequiredValue("decision_defend_probability", eInfo.classType.getName());
+                    continue;
+                }
+
+                try
+                {
+                    eInfo.decisionFlee = entity.getLong("decision_flee_probability").intValue();
+                }
+                catch (NullPointerException e)
+                {
+                    logEntityMissingRequiredValue("decision_flee_probability", eInfo.classType.getName());
+                    continue;
+                }
+
+                entityInfoMap.put(eInfo.classType.getName(), eInfo);
+            }
+        }
+        return true;
+    }
+
+    private void logNotFound(String option)
+    {
+        logger.warn("Config option \"" + option + "\" not found, setting defaults");
+    }
+
+    private void logNotFound(String option, String defaultValue)
+    {
+        logger.warn("Config option \"" + option + "\" not found, defaulting to \"" + defaultValue + "\"");
+    }
+
+    private void logEntityInvalidValue(String option, String name, String defaultValue)
+    {
+        logger.warn("Invalid \"" + option + "\" for \"" + name + "\", defaulting to " + defaultValue);
+    }
+
+    private void logEntityMissingRequiredValue(String option, String name)
+    {
+        logger.error("Entity \"" + name + "\" does not have option \"" + option + "\", skipping...");
+    }
+
+    private String getRegexEntityName(String name)
+    {
+        String regex = "^\\s*name\\s*=\\s*";
+        regex += "(\"" + name + "\"";
+        regex += "|'" + name + "')";
+        return regex;
+    }
+
+    private boolean addEntityEntry(EntityInfo eInfo)
+    {
+        try
+        {
+            File config = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+            FileWriter fw = new FileWriter(config, true);
+            fw.write("[[server_config.entity]]\n");
+            fw.write("name = \"" + eInfo.classType.getName() + "\"\n");
+            fw.write("attack_power = " + eInfo.attackPower + "\n");
+            fw.write("attack_probability = " + eInfo.attackProbability + "\n");
+            if(eInfo.attackVariance > 0)
+            {
+                fw.write("attack_variance = " + eInfo.attackVariance + "\n");
+            }
+            if(eInfo.attackEffect != EntityInfo.Effect.UNKNOWN && eInfo.attackEffectProbability > 0)
+            {
+                fw.write("attack_effect = \"" + eInfo.attackEffect.toString() + "\"\n");
+                fw.write("attack_effect_probability = " + eInfo.attackEffectProbability + "\n");
+            }
+            if(eInfo.defenseDamage > 0 && eInfo.defenseDamageProbability > 0)
+            {
+                fw.write("defense_damage = " + eInfo.defenseDamage + "\n");
+                fw.write("defense_damage_probability = " + eInfo.defenseDamageProbability + "\n");
+            }
+            fw.write("evasion = " + eInfo.evasion + "\n");
+            fw.write("speed = " + eInfo.speed + "\n");
+            if(eInfo.ignoreBattle)
+            {
+                fw.write("ignoreBattle = true\n");
+            }
+            fw.write("category = \"" + eInfo.category + "\"\n");
+            fw.write("decision_attack_probability = " + eInfo.decisionAttack + "\n");
+            fw.write("decision_defend_probability = " + eInfo.decisionDefend + "\n");
+            fw.write("decision_flee_probability = " + eInfo.decisionFlee + "\n");
+            fw.close();
+
+            entityInfoMap.put(eInfo.classType.getName(), eInfo);
+        }
+        catch (Throwable t)
+        {
+            logger.error("Failed to add entity entry (name = \"" + eInfo.classType.getName() + "\")");
+            return false;
+        }
+        return true;
+    }
+
+    protected boolean editEntityEntry(EntityInfo eInfo)
+    {
+        try
+        {
+            String cached = new String();
+            char buf[] = new char[1024];
+            int read = 0;
+            File config = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+            {
+                FileReader fr = new FileReader(config);
+                read = fr.read(buf);
+                while (read != -1)
+                {
+                    cached += String.valueOf(buf, 0, read);
+                    read = fr.read(buf);
+                }
+                fr.close();
+            }
+
+            int nameIndex = -1;
+            {
+                Pattern p = Pattern.compile(getRegexEntityName(eInfo.classType.getName()), Pattern.MULTILINE);
+                Matcher m = p.matcher(cached);
+                if(m.find())
+                {
+                    nameIndex = m.start();
                 }
-                else if(xmlReader.getLocalName().equals("SillyMusicThreshold"))
+            }
+            int entryIndex = -1;
+            int nextIndex = -1;
+            if(nameIndex != -1)
+            {
                 {
-                    sillyMusicThreshold = Integer.parseInt(xmlReader.getElementText());
-                    if(sillyMusicThreshold < 0)
+                    Pattern p = Pattern.compile("^\\s*\\[\\[\\s*server_config\\s*\\.\\s*entity\\s*]]", Pattern.MULTILINE);
+                    Matcher m = p.matcher(cached.substring(0, nameIndex));
+                    while(m.find())
                     {
-                        sillyMusicThreshold = 0;
+                        entryIndex = m.start();
                     }
-                    else if(sillyMusicThreshold > 100)
+                    if(entryIndex == -1)
                     {
-                        sillyMusicThreshold = 100;
+                        logger.warn("editEntityEntry: could not find header for entry \"" + eInfo.classType.getName() + "\", skipping to adding it...");
+                        return addEntityEntry(eInfo);
                     }
                 }
-                else if(xmlReader.getLocalName().equals("EntityEntry"))
                 {
-                    EntityInfo eInfo = new EntityInfo();
-                    do
+                    Pattern p = Pattern.compile("^\\s*\\[", Pattern.MULTILINE);
+                    Matcher m = p.matcher(cached.substring(nameIndex));
+                    if(m.find())
                     {
-                        xmlReader.next();
-                        if(xmlReader.isStartElement())
-                        {
-                            if(xmlReader.getLocalName().equals("Name"))
-                            {
-                                try
-                                {
-                                    eInfo.classType = Class.forName(xmlReader.getElementText());
-                                } catch (ClassNotFoundException e)
-                                {
-                                    logger.error("Failed to get class of name " + xmlReader.getElementText());
-                                }
-                            }
-                            else if(xmlReader.getLocalName().equals("AttackPower"))
-                            {
-                                for(int i = 0; i < xmlReader.getAttributeCount(); ++i)
-                                {
-                                    if(xmlReader.getAttributeLocalName(i).equals("Probability"))
-                                    {
-                                        eInfo.attackProbability = Integer.parseInt(xmlReader.getAttributeValue(i));
-                                    }
-                                    else if(xmlReader.getAttributeLocalName(i).equals("Variance"))
-                                    {
-                                        eInfo.attackVariance = Integer.parseInt(xmlReader.getAttributeValue(i));
-                                    }
-                                }
-                                eInfo.attackPower = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("AttackEffect"))
-                            {
-                                for(int i = 0; i < xmlReader.getAttributeCount(); ++i)
-                                {
-                                    if(xmlReader.getAttributeLocalName(i).equals("Probability"))
-                                    {
-                                        eInfo.attackEffectProbability = Integer.parseInt(xmlReader.getAttributeValue(i));
-                                    }
-                                }
-                                eInfo.attackEffect = EntityInfo.Effect.fromString(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("Evasion"))
-                            {
-                                eInfo.evasion = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("DefenseDamage"))
-                            {
-                                for(int i = 0; i < xmlReader.getAttributeCount(); ++i)
-                                {
-                                    if(xmlReader.getAttributeLocalName(i).equals("Probability"))
-                                    {
-                                        eInfo.defenseDamageProbability = Integer.parseInt(xmlReader.getAttributeValue(i));
-                                    }
-                                }
-                                eInfo.defenseDamage = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("Category"))
-                            {
-                                eInfo.category = xmlReader.getElementText().toLowerCase();
-                            }
-                            else if(xmlReader.getLocalName().equals("IgnoreBattle"))
-                            {
-                                if(xmlReader.getElementText().toLowerCase().equals("true"))
-                                {
-                                    eInfo.ignoreBattle = true;
-                                }
-                            }
-                            else if(xmlReader.getLocalName().equals("Speed"))
-                            {
-                                eInfo.speed = Integer.parseInt(xmlReader.getElementText());
-                            }
-                            else if(xmlReader.getLocalName().equals("Decision"))
-                            {
-                                do
-                                {
-                                    xmlReader.next();
-                                    if(xmlReader.isStartElement())
-                                    {
-                                        if(xmlReader.getLocalName().equals("Attack"))
-                                        {
-                                            eInfo.decisionAttack = Integer.parseInt(xmlReader.getElementText());
-                                        }
-                                        else if(xmlReader.getLocalName().equals("Defend"))
-                                        {
-                                            eInfo.decisionDefend = Integer.parseInt(xmlReader.getElementText());
-                                        }
-                                        else if(xmlReader.getLocalName().equals("Flee"))
-                                        {
-                                            eInfo.decisionFlee = Integer.parseInt(xmlReader.getElementText());
-                                        }
-                                    }
-                                } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("Decision")));
-                            }
-                        }
-                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("EntityEntry")));
-                    if(eInfo.classType != null)
-                    {
-                        entityInfoMap.put(eInfo.classType.getName(), eInfo);
+                        nextIndex = m.start() + nameIndex;
                     }
                 }
             }
+            else
+            {
+                logger.warn("editEntityEntry: could not find entry for \"" + eInfo.classType.getName() + "\", skipping to adding it...");
+                return addEntityEntry(eInfo);
+            }
+
+            String cut = null;
+            if(nextIndex != -1)
+            {
+                cut = cached.substring(0, entryIndex) + cached.substring(nextIndex);
+            }
+            else
+            {
+                cut = cached.substring(0, entryIndex);
+            }
+
+            {
+                FileWriter fw = new FileWriter(config);
+                fw.write(cut);
+                fw.close();
+            }
+
+            return addEntityEntry(eInfo);
+        }
+        catch (Throwable t)
+        {
+            return false;
         }
-        xmlReader.close();
-        fis.close();
-        return true;
     }
-    
+
     public int getPlayerSpeed()
     {
         return playerSpeed;
@@ -479,7 +748,7 @@ public class Config
     {
         return playerSlowSpeed;
     }
-    
+
     public int getPlayerAttackProbability()
     {
         return playerAttackProbability;
@@ -489,22 +758,22 @@ public class Config
     {
         return playerEvasion;
     }
-    
+
     public int getDefenseDuration()
     {
         return defenseDuration;
     }
-    
+
     public int getFleeGoodProbability()
     {
         return fleeGoodProbability;
     }
-    
+
     public int getFleeBadProbability()
     {
         return fleeBadProbability;
     }
-    
+
     /**
      * Returns a clone of an EntityInfo (to prevent editing it).
      * @param classFullName
@@ -514,12 +783,12 @@ public class Config
     {
         return entityInfoMap.get(classFullName).clone();
     }
-    
+
     protected EntityInfo getEntityInfoReference(String classFullName)
     {
         return entityInfoMap.get(classFullName);
     }
-    
+
     protected EntityInfo getMatchingEntityInfo(Object entity)
     {
         if(entity == null)
@@ -533,103 +802,97 @@ public class Config
         }
         return null;
     }
-    
-    private int getConfigFileVersion(File configFile)
+
+    private int getConfigFileVersion(InputStream io)
     {
+        int version = 0;
         try
         {
-            return getConfigFileVersion(new FileInputStream(configFile));
-        } catch(FileNotFoundException e)
+            TomlParseResult result = Toml.parse(io, TomlVersion.V0_5_0);
+            version = result.getLong("version").intValue();
+        }
+        catch (Throwable t)
         {
-            return 0;
+            // ignored
         }
+        return version;
     }
-    
-    private int getConfigFileVersion(InputStream configStream)
-    {
-        int configVersion = 1;
 
+    private int getConfigFileVersion(File configFile)
+    {
+        int version = 0;
         try
         {
-            XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(configStream);
-            while(xmlReader.hasNext())
-            {
-                xmlReader.next();
-                if(xmlReader.isStartElement() && xmlReader.getLocalName().equals("Version"))
-                {
-                    configVersion = Integer.parseInt(xmlReader.getElementText());
-                    break;
-                }
-            }
-            xmlReader.close();
-        } catch (Throwable t)
+            TomlParseResult result = Toml.parse(configFile.toPath(), TomlVersion.V0_5_0);
+            version = result.getLong("version").intValue();
+        }
+        catch (Throwable t)
         {
-            return 0;
+            // ignored
         }
-        
-        return configVersion;
+        return version;
     }
-    
+
     public boolean isIgnoreBattleType(String type)
     {
         return ignoreBattleTypes.contains(type);
     }
-    
+
     public int getMinimumHitPercentage()
     {
         return minimumHitPercentage;
     }
-    
+
     public int getMaxInBattle()
     {
         return maxInBattle;
     }
-    
+
     public boolean isBattleMusicType(String type)
     {
         return musicBattleTypes.contains(type.toLowerCase());
     }
-    
+
     public boolean isSillyMusicType(String type)
     {
         return musicSillyTypes.contains(type.toLowerCase());
     }
-    
+
     public boolean isFreezeCombatantsEnabled()
     {
         return freezeCombatantsInBattle;
     }
-    
+
     public int getSillyMusicThreshold()
     {
         return sillyMusicThreshold;
     }
-    
+
     public int getConfigVersion()
     {
         return configVersion;
     }
-    
+
     public long getDecisionDurationNanos()
     {
         return battleDecisionDurationNanos;
     }
-    
+
     public int getDecisionDurationSeconds()
     {
         return (int)(battleDecisionDurationNanos / 1000000000L);
     }
-    
+
     protected void addBattleIgnoringPlayer(int id)
     {
         battleIgnoringPlayers.add(id);
     }
-    
+
     protected void removeBattleIgnoringPlayer(int id)
     {
         battleIgnoringPlayers.remove(id);
     }
-    
+
     protected void clearBattleIgnoringPlayers()
     {
         battleIgnoringPlayers.clear();
@@ -639,37 +902,37 @@ public class Config
     {
         return battleIgnoringPlayers;
     }
-    
+
     public boolean getIfOnlyOPsCanDisableTurnBasedForSelf()
     {
         return onlyOPsSelfDisableTB;
     }
-    
+
     protected void setBattleDisabledForAll(boolean isDisabled)
     {
         battleDisabledForAll = isDisabled;
     }
-    
+
     protected boolean getBattleDisabledForAll()
     {
         return battleDisabledForAll;
     }
-    
+
     public boolean isOldBattleBehaviorEnabled()
     {
         return oldBattleBehaviorEnabled;
     }
-    
+
     public int getLeaveBattleCooldownSeconds()
     {
         return leaveBattleCooldownSeconds;
     }
-    
+
     public long getLeaveBattleCooldownNanos()
     {
         return (long)leaveBattleCooldownSeconds * 1000000000L;
     }
-    
+
     public int getAggroStartBattleDistance()
     {
         return aggroStartBattleDistance;
index 7efc7f26a3d23638cdbdf1ec6e09b04c65f26543..06f27c480af3156c39a52cb1e8171d34ba139b70 100644 (file)
@@ -159,6 +159,65 @@ public class EntityInfo
                 return UNKNOWN;
             }
         }
+
+        public String toString()
+        {
+            switch(this)
+            {
+            case SPEED:
+                return "speed";
+            case SLOW:
+                return "slow";
+            case HASTE:
+                return "haste";
+            case MINING_FATIGUE:
+                return "mining_fatigue";
+            case STRENGTH:
+                return "strength";
+            case JUMP_BOOST:
+                return "jump_boost";
+            case NAUSEA:
+                return "nausea";
+            case REGENERATION:
+                return "regeneration";
+            case RESISTANCE:
+                return "resistance";
+            case FIRE_RESISTANCE:
+                return "fire_resistance";
+            case WATER_BREATHING:
+                return "water_breathing";
+            case INVISIBILITY:
+                return "invisibility";
+            case BLINDNESS:
+                return "blindness";
+            case NIGHT_VISION:
+                return "night_vision";
+            case HUNGER:
+                return "hunger";
+            case WEAKNESS:
+                return "weakness";
+            case POISON:
+                return "poison";
+            case WITHER:
+                return "wither";
+            case ABSORPTION:
+                return "absorption";
+            case SATURATION:
+                return "saturation";
+            case GLOWING:
+                return "glowing";
+            case LEVITATION:
+                return "levitation";
+            case LUCK:
+                return "luck";
+            case UNLUCK:
+                return "unluck";
+            case FIRE:
+                return "fire";
+            default:
+                return "unknown";
+            }
+        }
         
         public PotionEffect getPotionEffect()
         {
index ba3f35cae12bca928675c1b8d2c0512f3b889887..be06c384f5bb1f4c1bbe3ef0b8bdcc7ac896217f 100644 (file)
@@ -9,7 +9,7 @@ public class PlayerJoinEventHandler
     @SubscribeEvent
     public void entityJoinHandler(EntityJoinWorldEvent event)
     {
-        if(event.getEntity().world.isRemote)
+        if(event.getWorld().isRemote)
         {
             return;
         }
index 26a17ddc65420ef9c7c9e47fdee41f17e54a59b0..e9fb8b142becb7f08b5f5a6233f1f370099fe78b 100644 (file)
@@ -26,8 +26,8 @@ public class TurnBasedMinecraftMod
 {
     public static final String MODID = "com.seodisparate.turnbasedminecraft";
     public static final String NAME = "Turn Based Minecraft Mod";
-    public static final String VERSION = "1.5";
-    public static final String CONFIG_FILENAME = "TBM_Config.xml";
+    public static final String VERSION = "1.6";
+    public static final String CONFIG_FILENAME = "TBM_Config.toml";
     public static final String CONFIG_DIRECTORY = "config/TurnBasedMinecraft/";
     public static final String CONFIG_FILE_PATH = CONFIG_DIRECTORY + CONFIG_FILENAME;
     public static final String CONFIG_INTERNAL_PATH = "/assets/TurnBasedMinecraft/" + CONFIG_FILENAME;
diff --git a/src/main/resources/assets/TurnBasedMinecraft/TBM_Config.toml b/src/main/resources/assets/TurnBasedMinecraft/TBM_Config.toml
new file mode 100644 (file)
index 0000000..dd0c7ed
--- /dev/null
@@ -0,0 +1,636 @@
+# Please do not change this option, the mod uses this to keep track of what new
+# changes to add to the config.
+version = 1
+
+[client_config]
+
+# determines what categories use what type of music.
+# Unknown categories sent by the server will default to "battle_music".
+battle_music = ["monster", "animal", "boss", "player"]
+silly_music = ["passive"]
+
+# Minimum percentage of silly entities in battle to use silly music.
+silly_music_threshold = 40
+
+
+[server_config]
+
+# Number of seconds that an entity cannot enter battle after having just left
+# one. Minimum 1, maximum 10.
+leave_battle_cooldown = 5
+
+# Maximum distance for a monster to start battle by targeting a player or other
+# entity in turn-based-battle. Minimum 5, maximum 50.
+aggro_start_battle_max_distance = 8
+
+# If true, only initiate battle on attack. If false, monsters targeting players
+# also trigger battle.
+old_battle_behavior = false
+
+# If true, any player can disable/enable turn-based-battle for themselves with
+# the commands "/tbm-enable" and "/tbm-disable".
+anyone_can_disable_tbm_for_self = false
+
+# Maximum amount of entities in one battle. If max is reached, no more entities
+# will be added to battle until there are less than max entities.
+max_in_battle = 8
+
+# If true, all entities in battle will be frozen in place
+freeze_battle_combatants = false
+
+# Entity categories that will not initiate battle.
+ignore_battle_types = ["passive", "boss"]
+
+# Stats that apply to all players
+player_speed = 50
+player_haste_speed = 80
+player_slow_speed = 20
+player_attack_probability = 90
+player_evasion = 10
+
+# Number of attacks that a "defend" move will block
+defense_duration = 1
+
+# If speed is greater than fastest speed of entity on opposing side, good
+# probability is used.
+flee_good_probability = 90
+flee_bad_probability = 40
+
+# Minimum hit percentage for everyone. If option is set to less than 1,
+# config will assume option of "1" anyway.
+minimum_hit_percentage = 4
+
+# Number of seconds to wait in battle for all players to make a decision.
+# Minimum 5, maximum 60.
+battle_turn_time_seconds = 15
+
+
+# Each "server_config.entity" entry uses the following options:
+# name: full class name of the entity
+# attack_power: how much damage an entity does on successful attack
+# attack_probability: percentage of attack success. (Usually calculated with enemy's evasion to determine actual percentage)
+# attack_variance (optional): determines how much a successful attack's damage varies.
+# attack_effect (optional): applies effect on hit success
+# attack_effect_probability (optional): percentage of attack_effect being applied on hit success.
+# defense_damage (optional): damage dealt to attacker when hit.
+# defense_damage_probability (optional): percentage of defense_damage being applied on received hit.
+# evasion: percentage of evading hit.
+# speed: used to determine turn-order, and flee success rates.
+# ignore_battle (optional): per-entity setting that causes that entity to not enter turn-based-battle.
+# category: Determines type of entity. Used for server config for what groups do not enter turn-based-battle, and for client config for determining what type of battle music to play.
+# decision_attack_probability: Percentage of entity choosing to attack on turn.
+# decision_defend_probability: Percentage of entity choosing to defend on turn.
+# decision_flee_probability: Percentage of entity choosing to flee on turn.
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityBlaze"
+attack_power = 5
+attack_probability = 50
+attack_effect = "fire"
+attack_effect_probability = 75
+evasion = 5
+category = "monster"
+speed = 45
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityCaveSpider"
+attack_power = 2
+attack_probability = 75
+attack_effect = "poison"
+attack_effect_probability = 90
+evasion = 35
+category = "monster"
+speed = 75
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityCreeper"
+ignore_battle = true
+attack_power = 15
+attack_probability = 17
+attack_variance = 7
+evasion = 5
+category = "monster"
+speed = 25
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityElderGuardian"
+attack_power = 8
+attack_probability = 65
+defense_damage = 2
+defense_damage_probability = 35
+evasion = 25
+category = "monster"
+speed = 45
+decision_attack_probability = 80
+decision_defend_probability = 20
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityEnderman"
+attack_power = 7
+attack_probability = 80
+evasion = 40
+category = "monster"
+speed = 70
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityEndermite"
+attack_power = 2
+attack_probability = 80
+evasion = 40
+category = "monster"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityEvoker"
+attack_power = 6
+attack_probability = 60
+evasion = 35
+category = "monster"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityGhast"
+ignore_battle = true
+attack_power = 13
+attack_probability = 20
+evasion = 35
+category = "monster"
+speed = 60
+decision_attack_probability = 75
+decision_defend_probability = 0
+decision_flee_probability = 25
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityGiantZombie"
+attack_power = 11
+attack_probability = 35
+evasion = 2
+category = "monster"
+speed = 45
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityGuardian"
+attack_power = 6
+attack_probability = 55
+defense_damage = 2
+defense_damage_probability = 30
+evasion = 25
+category = "monster"
+speed = 50
+decision_attack_probability = 80
+decision_defend_probability = 20
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityHusk"
+attack_power = 3
+attack_probability = 70
+attack_effect = "hunger"
+attack_effect_probability = 95
+evasion = 5
+category = "monster"
+speed = 25
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityIronGolem"
+attack_power = 14
+attack_probability = 85
+attack_variance = 7
+evasion = 5
+category = "monster"
+speed = 45
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityMagmaCube"
+attack_power = 3
+attack_probability = 35
+evasion = 12
+category = "monster"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityPigZombie"
+attack_power = 8
+attack_probability = 70
+evasion = 10
+category = "monster"
+speed = 50
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityPolarBear"
+attack_power = 6
+attack_probability = 67
+evasion = 5
+category = "animal"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityShulker"
+attack_power = 4
+attack_probability = 80
+evasion = 15
+category = "monster"
+speed = 10
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntitySilverfish"
+attack_power = 1
+attack_probability = 85
+evasion = 37
+category = "monster"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntitySkeleton"
+attack_power = 3
+attack_probability = 75
+attack_variance = 1
+evasion = 13
+category = "monster"
+speed = 30
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntitySlime"
+attack_power = 2
+attack_probability = 35
+evasion = 10
+category = "monster"
+speed = 30
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntitySnowman"
+attack_power = 0
+attack_probability = 80
+evasion = 5
+category = "passive"
+speed = 60
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntitySpider"
+attack_power = 2
+attack_probability = 70
+evasion = 25
+category = "monster"
+speed = 70
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityStray"
+attack_power = 3
+attack_probability = 75
+attack_variance = 1
+attack_effect = "slow"
+attack_effect_probability = 90
+evasion = 13
+category = "monster"
+speed = 30
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityVex"
+attack_power = 9
+attack_probability = 65
+evasion = 30
+category = "monster"
+speed = 80
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityVindicator"
+attack_power = 13
+attack_probability = 70
+evasion = 10
+category = "monster"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityWitch"
+attack_power = 5
+attack_probability = 75
+attack_variance = 1
+evasion = 8
+category = "monster"
+speed = 35
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityWitherSkeleton"
+attack_power = 8
+attack_probability = 70
+attack_effect = "wither"
+attack_effect_probability = 90
+evasion = 7
+category = "monster"
+speed = 65
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityZombie"
+attack_power = 3
+attack_probability = 70
+evasion = 5
+category = "monster"
+speed = 25
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.monster.EntityZombieVillager"
+attack_power = 3
+attack_probability = 70
+evasion = 5
+category = "monster"
+speed = 25
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityBat"
+attack_power = 0
+attack_probability = 70
+evasion = 35
+category = "passive"
+speed = 75
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityChicken"
+attack_power = 0
+attack_probability = 70
+evasion = 10
+category = "passive"
+speed = 35
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityCow"
+attack_power = 0
+attack_probability = 50
+evasion = 1
+category = "passive"
+speed = 20
+decision_attack_probability = 0
+decision_defend_probability = 10
+decision_flee_probability = 80
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityDonkey"
+attack_power = 0
+attack_probability = 70
+evasion = 10
+category = "passive"
+speed = 65
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityHorse"
+attack_power = 0
+attack_probability = 70
+evasion = 10
+category = "passive"
+speed = 65
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityLlama"
+attack_power = 1
+attack_probability = 70
+evasion = 10
+category = "passive"
+speed = 50
+decision_attack_probability = 65
+decision_defend_probability = 0
+decision_flee_probability = 25
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityMooshroom"
+attack_power = 0
+attack_probability = 70
+evasion = 1
+category = "passive"
+speed = 20
+decision_attack_probability = 0
+decision_defend_probability = 10
+decision_flee_probability = 80
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityMule"
+attack_power = 0
+attack_probability = 70
+evasion = 10
+category = "passive"
+speed = 50
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityOcelot"
+attack_power = 1
+attack_probability = 70
+attack_variance = 1
+evasion = 10
+category = "passive"
+speed = 75
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityParrot"
+attack_power = 0
+attack_probability = 70
+evasion = 35
+category = "passive"
+speed = 70
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityPig"
+attack_power = 0
+attack_probability = 70
+evasion = 10
+category = "passive"
+speed = 30
+decision_attack_probability = 0
+decision_defend_probability = 5
+decision_flee_probability = 85
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityRabbit"
+attack_power = 0
+attack_probability = 70
+evasion = 40
+category = "passive"
+speed = 75
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 100
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntitySheep"
+attack_power = 0
+attack_probability = 70
+evasion = 5
+category = "passive"
+speed = 30
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntitySkeletonHorse"
+attack_power = 0
+attack_probability = 70
+evasion = 5
+category = "passive"
+speed = 65
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntitySquid"
+attack_power = 0
+attack_probability = 70
+evasion = 15
+category = "passive"
+speed = 40
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityVillager"
+attack_power = 0
+attack_probability = 70
+evasion = 5
+category = "passive"
+speed = 35
+decision_attack_probability = 0
+decision_defend_probability = 10
+decision_flee_probability = 80
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityWolf"
+attack_power = 4
+attack_probability = 70
+evasion = 20
+category = "animal"
+speed = 70
+decision_attack_probability = 80
+decision_defend_probability = 15
+decision_flee_probability = 5
+
+[[server_config.entity]]
+name = "net.minecraft.entity.passive.EntityZombieHorse"
+attack_power = 0
+attack_probability = 70
+evasion = 8
+category = "passive"
+speed = 65
+decision_attack_probability = 0
+decision_defend_probability = 0
+decision_flee_probability = 90
+
+[[server_config.entity]]
+name = "net.minecraft.entity.boss.EntityDragon"
+attack_power = 10
+attack_probability = 70
+attack_variance = 2
+evasion = 27
+category = "boss"
+speed = 63
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
+
+[[server_config.entity]]
+name = "net.minecraft.entity.boss.EntityWither"
+attack_power = 8
+attack_probability = 70
+attack_effect = "wither"
+attack_effect_probability = 90
+evasion = 20
+category = "boss"
+speed = 68
+decision_attack_probability = 100
+decision_defend_probability = 0
+decision_flee_probability = 0
diff --git a/src/main/resources/assets/TurnBasedMinecraft/TBM_Config.xml b/src/main/resources/assets/TurnBasedMinecraft/TBM_Config.xml
deleted file mode 100644 (file)
index 582c1c1..0000000
+++ /dev/null
@@ -1,653 +0,0 @@
-<TurnBasedMinecraftConfig>
-       <!-- If the mod has a newer version config, it will rename the existing config and place the new config -->
-       <Version>6</Version>
-       <!-- Number of seconds that an entity cannot enter battle after having just left one. Minimum 1, maximum 10-->
-       <LeaveBattleCooldown>5</LeaveBattleCooldown>
-       <!-- Maximum distance for a monster to start battle by targeting a player or other entity in turn-based-battle.
-       Minimum 5, maximum 50. -->
-       <AggroStartBattleDistance>8</AggroStartBattleDistance>
-       <!-- If not "false", uses old battle behavior where battles only start on attack/hit. Otherwise, battles can
-       start when a hostile mob targets a player or another entity in battle. -->
-       <OldBattleBehavior>false</OldBattleBehavior>
-       <!-- Determines who can disable turn-based-battle for themselves via command. Must be "op" or "any". If neither, defaults to "op"-->
-       <WhoCanDisableTurnBasedForSelf>op</WhoCanDisableTurnBasedForSelf>
-       <!-- If there are "MaxInBattle" amount of entities in battle, other entities cannot join until combatants leave battle. -->
-       <MaxInBattle>8</MaxInBattle>
-       <!-- If not set to "false", then when battle starts all combatants will remain in their starting position. -->
-       <FreezeBattleCombatants>false</FreezeBattleCombatants>
-       <!-- Types that will not initiate battle with player. They are listed as "Category" per EntiytStats entity.
-                Note that items listed in "IgnoreBattleTypes" and "Category" are converted to lowercase before being compared. -->
-       <IgnoreBattleTypes>
-               <passive></passive>
-               <boss></boss>
-       </IgnoreBattleTypes>
-       <!-- BattleMusic determines what categories a type will play music for. -->
-       <!-- Music is placed in "config/TurnBasedMinecraft/Music/battle/" and "config/TurnBasedMinecraft/Music/silly/" -->
-       <BattleMusic>
-               <Normal>
-                       <monster></monster>
-                       <animal></animal>
-                       <boss></boss>
-                       <player></player>
-               </Normal>
-               <Silly>
-                       <passive></passive>
-               </Silly>
-       </BattleMusic>
-       <PlayerStats>
-               <Speed>50</Speed>
-               <HasteSpeed>80</HasteSpeed> <!-- Speed used if the player entity has "speed" or "haste" effects -->
-               <SlowSpeed>20</SlowSpeed> <!-- Speed used if the player entity has "slow" effect -->
-               <AttackProbability>90</AttackProbability>
-               <Evasion>10</Evasion>
-       </PlayerStats>
-       <!-- Determines how many attacks a "defense" move can block before that entity's next turn. -->
-       <DefenseDuration>1</DefenseDuration>
-       <!-- Probability of escaping battle. If entity's speed is greater than the enemy team's speediest entity, then good probability is used. -->
-       <FleeGoodProbability>90</FleeGoodProbability>
-       <FleeBadProbability>40</FleeBadProbability>
-       <!-- Minimum hit percentage for every entity. If less than 1, it will be stored as 1 anyways. -->
-       <MinimumHitPercentage>4</MinimumHitPercentage>
-       <!-- Number of seconds to wait in battle for all players to make a decision. Minimum of 5 and maximum of 60. -->
-       <BattleTurnTimeSeconds>15</BattleTurnTimeSeconds>
-       <!-- Minimum percentage of silly entities in battle to use silly music -->
-       <SillyMusicThreshold>40</SillyMusicThreshold>
-       
-       <!-- Battle stats for entities should be specified here. If an entity is not listed it cannot enter battle. -->
-       <!-- Name: The full class name of an entity. -->
-       <!-- AttackPower: How much damage an entity does per attack. Usually has a "Probability" attribute between 0 and 100. Also may have a "Variance" attribute that varies the attack power by the specified amount randomly. -->
-       <!-- AttackEffect: (Optional) Applies effect to target entity with "Probability" success rate. -->
-       <!-- DefenseDamage: (Optional) Applies damage to an attacker when attacked with "Probability" success rate. -->
-       <!-- Evasion: Determines the percentage of evading attacks between 0 and 100. -->
-       <!-- Note that if the hit probability and evasion result in a percentage less than 1%, the hit chance will be changed ti 1% -->
-       <!-- Speed: Value in range of 0 to 100 that determines the order entities act in battle. Higher is sooner. Entities with same speed will take their turn as a group in random order (not at the same time). -->
-       <!-- IgnoreBattle: (Optional) Per entity setting to not enter turn-based-battle if value is "true". If "true" these stats will not apply to the entity as they are only used in turn-based-battle. -->
-       <!-- Category: Sets the type of the entity, used by "IgnoreBattleTypes" to determine what types ignore battle. -->
-       <!-- Decision: Lists percentages of what action taken by the entity, one of Attack, Defend, or Flee. If the sum is less than 100, the mob has a chance to do nothing with the remaining percentage -->
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityBlaze</Name>
-               <AttackPower Probability="50">5</AttackPower>
-               <AttackEffect Probability="75">fire</AttackEffect>
-               <Evasion>5</Evasion>
-               <Category>monster</Category>
-               <Speed>45</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityCaveSpider</Name>
-               <AttackPower Probability="75">2</AttackPower>
-               <AttackEffect Probability="90">poison</AttackEffect>
-               <Evasion>35</Evasion>
-               <Category>monster</Category>
-               <Speed>75</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityCreeper</Name>
-               <IgnoreBattle>true</IgnoreBattle>
-               <AttackPower Probability="17" Variance="7">15</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>monster</Category>
-               <Speed>25</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityElderGuardian</Name>
-               <AttackPower Probability="65">8</AttackPower>
-               <DefenseDamage Probability="35">2</DefenseDamage>
-               <Evasion>25</Evasion>
-               <Category>monster</Category>
-               <Speed>45</Speed>
-               <Decision>
-                       <Attack>80</Attack>
-                       <Defend>20</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityEnderman</Name>
-               <AttackPower Probability="80">7</AttackPower>
-               <Evasion>40</Evasion>
-               <Category>monster</Category>
-               <Speed>70</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityEndermite</Name>
-               <AttackPower Probability="80">2</AttackPower>
-               <Evasion>40</Evasion>
-               <Category>monster</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityEvoker</Name>
-               <AttackPower Probability="60">6</AttackPower>
-               <Evasion>35</Evasion>
-               <Category>monster</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityGhast</Name>
-               <IgnoreBattle>true</IgnoreBattle>
-               <AttackPower Probability="20">13</AttackPower>
-               <Evasion>35</Evasion>
-               <Category>monster</Category>
-               <Speed>60</Speed>
-               <Decision>
-                       <Attack>75</Attack>
-                       <Defend>0</Defend>
-                       <Flee>25</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityGiantZombie</Name>
-               <AttackPower Probability="35">11</AttackPower>
-               <Evasion>2</Evasion>
-               <Category>monster</Category>
-               <Speed>45</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityGuardian</Name>
-               <AttackPower Probability="55">6</AttackPower>
-               <DefenseDamage Probability="30">2</DefenseDamage>
-               <Evasion>25</Evasion>
-               <Category>monster</Category>
-               <Speed>50</Speed>
-               <Decision>
-                       <Attack>80</Attack>
-                       <Defend>20</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityHusk</Name>
-               <AttackPower Probability="70">3</AttackPower>
-               <AttackEffect Probability="95">hunger</AttackEffect>
-               <Evasion>5</Evasion>
-               <Category>monster</Category>
-               <Speed>25</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityIronGolem</Name>
-               <AttackPower Probability="85" Variance="7">14</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>monster</Category>
-               <Speed>45</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityMagmaCube</Name>
-               <AttackPower Probability="35">3</AttackPower>
-               <Evasion>12</Evasion>
-               <Category>monster</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityPigZombie</Name>
-               <AttackPower Probability="70">8</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>monster</Category>
-               <Speed>50</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityPolarBear</Name>
-               <AttackPower Probability="67">6</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>animal</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityShulker</Name>
-               <AttackPower Probability="80">4</AttackPower>
-               <Evasion>15</Evasion>
-               <Category>monster</Category>
-               <Speed>10</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntitySilverfish</Name>
-               <AttackPower Probability="85">1</AttackPower>
-               <Evasion>37</Evasion>
-               <Category>monster</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntitySkeleton</Name>
-               <AttackPower Probability="75" Variance="1">3</AttackPower>
-               <Evasion>13</Evasion>
-               <Category>monster</Category>
-               <Speed>30</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntitySlime</Name>
-               <AttackPower Probability="35">2</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>monster</Category>
-               <Speed>30</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntitySnowman</Name>
-               <AttackPower Probability="80">0</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>passive</Category>
-               <Speed>60</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntitySpider</Name>
-               <AttackPower Probability="70">2</AttackPower>
-               <Evasion>25</Evasion>
-               <Category>monster</Category>
-               <Speed>70</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityStray</Name>
-               <AttackPower Probability="75" Variance="1">3</AttackPower>
-               <AttackEffect Probability="90">slow</AttackEffect>
-               <Evasion>13</Evasion>
-               <Category>monster</Category>
-               <Speed>30</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityVex</Name>
-               <AttackPower Probability="65">9</AttackPower>
-               <Evasion>30</Evasion>
-               <Category>monster</Category>
-               <Speed>80</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityVindicator</Name>
-               <AttackPower Probability="70">13</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>monster</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityWitch</Name>
-               <AttackPower Probability="75" Variance="1">5</AttackPower>
-               <Evasion>8</Evasion>
-               <Category>monster</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityWitherSkeleton</Name>
-               <AttackPower Probability="70">8</AttackPower>
-               <AttackEffect Probability="90">wither</AttackEffect>
-               <Evasion>7</Evasion>
-               <Category>monster</Category>
-               <Speed>65</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityZombie</Name>
-               <AttackPower Probability="70">3</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>monster</Category>
-               <Speed>25</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.monster.EntityZombieVillager</Name>
-               <AttackPower Probability="70">3</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>monster</Category>
-               <Speed>25</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityBat</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>35</Evasion>
-               <Category>passive</Category>
-               <Speed>75</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityChicken</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityCow</Name>
-               <AttackPower Probability="50">0</AttackPower>
-               <Evasion>1</Evasion>
-               <Category>passive</Category>
-               <Speed>20</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>10</Defend>
-                       <Flee>80</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityDonkey</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>65</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityHorse</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>65</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityLlama</Name>
-               <AttackPower Probability="70">1</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>50</Speed>
-               <Decision>
-                       <Attack>65</Attack>
-                       <Defend>0</Defend>
-                       <Flee>25</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityMooshroom</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>1</Evasion>
-               <Category>passive</Category>
-               <Speed>20</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>10</Defend>
-                       <Flee>80</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityMule</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>50</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityOcelot</Name>
-               <AttackPower Probability="70" Variance="1">1</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>75</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityParrot</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>35</Evasion>
-               <Category>passive</Category>
-               <Speed>70</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityPig</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>10</Evasion>
-               <Category>passive</Category>
-               <Speed>30</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>5</Defend>
-                       <Flee>85</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityRabbit</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>40</Evasion>
-               <Category>passive</Category>
-               <Speed>75</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>100</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntitySheep</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>passive</Category>
-               <Speed>30</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntitySkeletonHorse</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>passive</Category>
-               <Speed>65</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntitySquid</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>15</Evasion>
-               <Category>passive</Category>
-               <Speed>40</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityVillager</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>5</Evasion>
-               <Category>passive</Category>
-               <Speed>35</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>10</Defend>
-                       <Flee>80</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityWolf</Name>
-               <AttackPower Probability="70">4</AttackPower>
-               <Evasion>20</Evasion>
-               <Category>animal</Category>
-               <Speed>70</Speed>
-               <Decision>
-                       <Attack>80</Attack>
-                       <Defend>15</Defend>
-                       <Flee>5</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.passive.EntityZombieHorse</Name>
-               <AttackPower Probability="70">0</AttackPower>
-               <Evasion>8</Evasion>
-               <Category>passive</Category>
-               <Speed>65</Speed>
-               <Decision>
-                       <Attack>0</Attack>
-                       <Defend>0</Defend>
-                       <Flee>90</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.boss.EntityDragon</Name>
-               <AttackPower Probability="70" Variance="2">10</AttackPower>
-               <Evasion>27</Evasion>
-               <Category>boss</Category>
-               <Speed>63</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-       <EntityEntry>
-               <Name>net.minecraft.entity.boss.EntityWither</Name>
-               <AttackPower Probability="70">8</AttackPower>
-               <Evasion>20</Evasion>
-               <AttackEffect Probability="90">wither</AttackEffect>
-               <Category>boss</Category>
-               <Speed>68</Speed>
-               <Decision>
-                       <Attack>100</Attack>
-                       <Defend>0</Defend>
-                       <Flee>0</Flee>
-               </Decision>
-       </EntityEntry>
-</TurnBasedMinecraftConfig>
\ No newline at end of file