]> git.seodisparate.com - TurnBasedMinecraftMod/commitdiff
WIP more work on setup and Battle logic
authorStephen Seo <seo.disparate@gmail.com>
Tue, 4 Sep 2018 06:21:49 +0000 (15:21 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 4 Sep 2018 06:21:49 +0000 (15:21 +0900)
src/main/java/com/seodisparate/TurnBasedMinecraft/TurnBasedMinecraftMod.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/Battle.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/BattleManager.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/Combatant.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/networking/PacketBattleDecision.java
src/main/resources/TBM_Config.xml

index e4a3a045d9136a14f439ed0f87f43e8adb46cd33..708975528db6365f7d9ca9a5ec4b18023bb66de5 100644 (file)
@@ -39,7 +39,7 @@ public class TurnBasedMinecraftMod
     private static BattleManager battleManager;
     private static int packetHandlerID = 0;
     public static Entity attackingEntity;
-    private static Config config;
+    public static Config config;
     
     public static Battle currentBattle;
 
index 78cf6e8a9be115c678102080470de8adbfb2ec5b..526f5ae9663119f38801f252db7aac06b0fefa10 100644 (file)
@@ -7,6 +7,11 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleInfo;
@@ -21,12 +26,13 @@ public class Battle
     private final int id;
     private Map<Integer, Combatant> sideA;
     private Map<Integer, Combatant> sideB;
-    private Map<Integer, EntityPlayer> players;
+    private Map<Integer, Combatant> players;
+    private PriorityQueue<Combatant> turnOrderQueue;
     
     private Instant lastUpdated;
     private State state;
-    private int playerCount;
-    private int undecidedCount;
+    private AtomicInteger playerCount;
+    private AtomicInteger undecidedCount;
     private Duration timer;
     
     public enum State
@@ -76,17 +82,26 @@ public class Battle
         this.id = id;
         this.sideA = new Hashtable<Integer, Combatant>();
         this.sideB = new Hashtable<Integer, Combatant>();
-        players = new HashMap<Integer, EntityPlayer>();
-        playerCount = 0;
+        players = new Hashtable<Integer, Combatant>();
+        turnOrderQueue = new PriorityQueue<Combatant>(new Combatant.CombatantComparator());
+        playerCount = new AtomicInteger(0);
+        undecidedCount = new AtomicInteger(0);
         if(sideA != null)
         {
             for(Entity e : sideA)
             {
-                this.sideA.put(e.getEntityId(), new Combatant(e));
+                EntityInfo entityInfo = TurnBasedMinecraftMod.config.getMatchingEntityInfo(e);
+                if(entityInfo == null && !(e instanceof EntityPlayer))
+                {
+                    continue;
+                }
+                Combatant newCombatant = new Combatant(e, entityInfo);
+                this.sideA.put(e.getEntityId(), newCombatant);
                 if(e instanceof EntityPlayer)
                 {
-                    ++playerCount;
-                    players.put(e.getEntityId(), (EntityPlayer)e);
+                    newCombatant.recalcSpeedOnCompare = true;
+                    playerCount.incrementAndGet();
+                    players.put(e.getEntityId(), newCombatant);
                 }
             }
         }
@@ -94,18 +109,25 @@ public class Battle
         {
             for(Entity e : sideB)
             {
-                this.sideB.put(e.getEntityId(), new Combatant(e));
+                EntityInfo entityInfo = TurnBasedMinecraftMod.config.getMatchingEntityInfo(e);
+                if(entityInfo == null && !(e instanceof EntityPlayer))
+                {
+                    continue;
+                }
+                Combatant newCombatant = new Combatant(e, entityInfo);
+                this.sideB.put(e.getEntityId(), newCombatant);
                 if(e instanceof EntityPlayer)
                 {
-                    ++playerCount;
-                    players.put(e.getEntityId(), (EntityPlayer)e);
+                    newCombatant.recalcSpeedOnCompare = true;
+                    playerCount.incrementAndGet();
+                    players.put(e.getEntityId(), newCombatant);
                 }
             }
         }
         
         lastUpdated = null;
         state = State.DECISION;
-        undecidedCount = playerCount;
+        undecidedCount.set(playerCount.get());
         timer = TurnBasedMinecraftMod.BattleDecisionTime;
     }
 
@@ -126,28 +148,42 @@ public class Battle
     
     public void addCombatantToSideA(Entity e)
     {
-        sideA.put(e.getEntityId(), new Combatant(e));
+        EntityInfo entityInfo = TurnBasedMinecraftMod.config.getMatchingEntityInfo(e);
+        if(entityInfo == null && !(e instanceof EntityPlayer))
+        {
+            return;
+        }
+        Combatant newCombatant = new Combatant(e, entityInfo);
+        sideA.put(e.getEntityId(), newCombatant);
         if(e instanceof EntityPlayer)
         {
-            ++playerCount;
-            players.put(e.getEntityId(), (EntityPlayer)e);
+            newCombatant.recalcSpeedOnCompare = true;
+            playerCount.incrementAndGet();
+            players.put(e.getEntityId(), newCombatant);
             if(state == State.DECISION)
             {
-                ++undecidedCount;
+                undecidedCount.incrementAndGet();
             }
         }
     }
     
     public void addCombatantToSideB(Entity e)
     {
-        sideB.put(e.getEntityId(), new Combatant(e));
+        EntityInfo entityInfo = TurnBasedMinecraftMod.config.getMatchingEntityInfo(e);
+        if(entityInfo == null && !(e instanceof EntityPlayer))
+        {
+            return;
+        }
+        Combatant newCombatant = new Combatant(e, entityInfo);
+        sideB.put(e.getEntityId(), newCombatant);
         if(e instanceof EntityPlayer)
         {
-            ++playerCount;
-            players.put(e.getEntityId(), (EntityPlayer)e);
+            newCombatant.recalcSpeedOnCompare = true;
+            playerCount.incrementAndGet();
+            players.put(e.getEntityId(), newCombatant);
             if(state == State.DECISION)
             {
-                ++undecidedCount;
+                undecidedCount.incrementAndGet();
             }
         }
     }
@@ -157,8 +193,8 @@ public class Battle
         sideA.clear();
         sideB.clear();
         players.clear();
-        playerCount = 0;
-        undecidedCount = 0;
+        playerCount.set(0);
+        undecidedCount.set(0);
     }
     
     public Collection<Combatant> getSideA()
@@ -201,27 +237,20 @@ public class Battle
         return combatant;
     }
     
-    public void setDecision(int entityID, Decision decision)
+    public void setDecision(int entityID, Decision decision, int targetEntityID)
     {
         if(state != State.DECISION)
         {
             return;
         }
-        Combatant combatant = sideA.get(entityID);
+        Combatant combatant = players.get(entityID);
         if(combatant == null)
         {
-            combatant = sideB.get(entityID);
-            if(combatant == null)
-            {
-                return;
-            }
-        }
-        
-        if(combatant.entity instanceof EntityPlayer)
-        {
-            combatant.decision = decision;
-            --undecidedCount;
+            return;
         }
+        combatant.decision = decision;
+        combatant.targetEntityID = targetEntityID;
+        undecidedCount.decrementAndGet();
     }
     
     public State getState()
@@ -236,9 +265,9 @@ public class Battle
             return;
         }
         PacketBattleInfo infoPacket = new PacketBattleInfo(getSideAIDs(), getSideBIDs());
-        for(EntityPlayer p : players.values())
+        for(Combatant p : players.values())
         {
-            PacketHandler.INSTANCE.sendTo(infoPacket, (EntityPlayerMP)p);
+            PacketHandler.INSTANCE.sendTo(infoPacket, (EntityPlayerMP)p.entity);
         }
     }
     
@@ -263,15 +292,29 @@ public class Battle
         {
         case DECISION:
             timer = timer.minus(dt);
-            if(timer.isNegative() || timer.isZero() || undecidedCount <= 0)
+            if(timer.isNegative() || timer.isZero() || undecidedCount.get() <= 0)
             {
                 state = State.ATTACK;
                 timer = TurnBasedMinecraftMod.BattleDecisionTime;
+                turnOrderQueue.clear();
+                for(Combatant c : sideA.values())
+                {
+                    turnOrderQueue.add(c);
+                }
+                for(Combatant c : sideB.values())
+                {
+                    turnOrderQueue.add(c);
+                }
                 update(Duration.ZERO);
             }
             break;
         case ATTACK:
-            // TODO
+            Combatant next = turnOrderQueue.poll();
+            while(next != null)
+            {
+                // TODO attack per entity here
+                next = turnOrderQueue.poll();
+            }
             break;
         case HEALTH_CHECK:
             // TODO
index 40dcd12019cc1e98018dc1ef75c2d3d87389f497..18ddcbd14e35a3103f816f8c9c981a502c4dc316 100644 (file)
@@ -5,6 +5,7 @@ import java.util.Collection;
 import java.util.Hashtable;
 import java.util.Map;
 
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleEntered;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketHandler;
 
@@ -36,6 +37,12 @@ public class BattleManager
      */
     public boolean checkAttack(final LivingAttackEvent event)
     {
+        // verify that both entities are EntityPlayer or has a corresponding EntityInfo
+        if(!(event.getEntity() instanceof EntityPlayer || TurnBasedMinecraftMod.config.getEntityInfoReference(event.getEntity().getClass().getName()) != null)
+            || !(event.getSource().getTrueSource() instanceof EntityPlayer || TurnBasedMinecraftMod.config.getEntityInfoReference(event.getSource().getTrueSource().getClass().getName()) != null))
+        {
+            return false;
+        }
         // check if one is in battle
         Entity inBattle = null;
         Entity notInBattle = null;
index e32bb92180f578e1fcb3fbac40498440c4b8eb34..a25db37413748cd7f7840c865803d8018dbb3d4a 100644 (file)
 package com.seodisparate.TurnBasedMinecraft.common;
 
+import java.util.Comparator;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+
 import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.MobEffects;
+import net.minecraft.potion.PotionEffect;
 
 public class Combatant
 {
     public Entity entity;
     public Battle.Decision decision;
     public int itemToUse;
-    public float speed;
+    public EntityInfo entityInfo;
+    public boolean recalcSpeedOnCompare;
+    public int targetEntityID;
     
     public Combatant()
     {
         decision = Battle.Decision.UNDECIDED;
-        speed = 0.5f;
+        recalcSpeedOnCompare = false;
     }
     
-    public Combatant(Entity e)
+    public Combatant(Entity e, EntityInfo entityInfo)
     {
         entity = e;
         decision = Battle.Decision.UNDECIDED;
-        speed = 0.5f;
+        this.entityInfo = entityInfo;
+        recalcSpeedOnCompare = false;
     }
     
-    public Combatant(Entity e, float speed)
+    /**
+     * Provided in reverse order of speed because PriorityQueue has least first.
+     */
+    public static class CombatantComparator implements Comparator<Combatant>
     {
-        entity = e;
-        decision = Battle.Decision.UNDECIDED;
-        this.speed = speed;
+        @Override
+        public int compare(Combatant c0, Combatant c1)
+        {
+            if(c0.entity instanceof EntityPlayer && c0.recalcSpeedOnCompare)
+            {
+                EntityLivingBase c0Entity = (EntityLivingBase)c0.entity;
+                boolean isHaste = false;
+                boolean isSlow = false;
+                for(PotionEffect e : c0Entity.getActivePotionEffects())
+                {
+                    if(e.getEffectName().equals(MobEffects.HASTE.getName()))
+                    {
+                        isHaste = true;
+                    }
+                    else if(e.getEffectName().equals(MobEffects.SLOWNESS.getName()))
+                    {
+                        isSlow = true;
+                    }
+                }
+                if(c0.entityInfo == null)
+                {
+                    c0.entityInfo = new EntityInfo();
+                }
+                if(isHaste && !isSlow)
+                {
+                    c0.entityInfo.speed = TurnBasedMinecraftMod.config.getPlayerHasteSpeed();
+                }
+                else if(isSlow && !isHaste)
+                {
+                    c0.entityInfo.speed = TurnBasedMinecraftMod.config.getPlayerSlowSpeed();
+                }
+                else
+                {
+                    c0.entityInfo.speed = TurnBasedMinecraftMod.config.getPlayerSpeed();
+                }
+            }
+            
+            if(c1.entity instanceof EntityPlayer && c1.recalcSpeedOnCompare)
+            {
+                EntityLivingBase c1Entity = (EntityLivingBase)c1.entity;
+                boolean isHaste = false;
+                boolean isSlow = false;
+                for(PotionEffect e : c1Entity.getActivePotionEffects())
+                {
+                    if(e.getEffectName().equals(MobEffects.HASTE.getName()))
+                    {
+                        isHaste = true;
+                    }
+                    else if(e.getEffectName().equals(MobEffects.SLOWNESS.getName()))
+                    {
+                        isSlow = true;
+                    }
+                }
+                if(c1.entityInfo == null)
+                {
+                    c1.entityInfo = new EntityInfo();
+                }
+                if(isHaste && !isSlow)
+                {
+                    c1.entityInfo.speed = TurnBasedMinecraftMod.config.getPlayerHasteSpeed();
+                }
+                else if(isSlow && !isHaste)
+                {
+                    c1.entityInfo.speed = TurnBasedMinecraftMod.config.getPlayerSlowSpeed();
+                }
+                else
+                {
+                    c1.entityInfo.speed = TurnBasedMinecraftMod.config.getPlayerSpeed();
+                }
+            }
+            
+            if(c0.entityInfo.speed > c1.entityInfo.speed)
+            {
+                return -1;
+            }
+            else if(c0.entityInfo.speed < c1.entityInfo.speed)
+            {
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
     }
 }
index 1d8897f25206c06aa9683934a87f0cb029a86014..1e24996369251c26d0048145971ea03e9edaa60f 100644 (file)
@@ -24,9 +24,12 @@ import com.seodisparate.TurnBasedMinecraft.common.EntityInfo.Category;
 
 public class Config
 {
-    private Map<Class, EntityInfo> entityInfoMap;
+    private Map<String, EntityInfo> entityInfoMap;
     private Set<EntityInfo.Category> ignoreBattleTypes;
     private Logger logger;
+    private int playerSpeed;
+    private int playerHasteSpeed;
+    private int playerSlowSpeed;
     
     private enum ConfigParseResult
     {
@@ -36,7 +39,7 @@ public class Config
     
     public Config(Logger logger)
     {
-        entityInfoMap = new HashMap<Class, EntityInfo>();
+        entityInfoMap = new HashMap<String, EntityInfo>();
         ignoreBattleTypes = new HashSet<EntityInfo.Category>();
         this.logger = logger;
         
@@ -65,6 +68,7 @@ public class Config
             ConfigParseResult result = parseConfig(configFile);
             if(result == ConfigParseResult.IS_OLD)
             {
+                logger.warn("Config file " + TurnBasedMinecraftMod.CONFIG_FILENAME + " is older version, renaming...");
                 moveOldConfig();
                 writeConfig();
                 ConfigParseResult resultSecond = parseConfig(configFile);
@@ -109,8 +113,10 @@ public class Config
         File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
         if(configFile.exists())
         {
-            configFile.renameTo(new File(TurnBasedMinecraftMod.CONFIG_DIRECTORY + "_"
-                    + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(Instant.now())));
+            configFile.renameTo(new File(TurnBasedMinecraftMod.CONFIG_DIRECTORY
+                    + "TBM_Config_"
+                    + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(Instant.now())
+                    + ".xml"));
         }
     }
     
@@ -149,6 +155,28 @@ public class Config
                         }
                     } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("IgnoreBattleTypes")));
                 }
+                else if(xmlReader.getLocalName().equals("PlayerStats"))
+                {
+                    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());
+                            }
+                        }
+                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("PlayerStats")));
+                }
                 else if(xmlReader.getLocalName().equals("EntityStats"))
                 {
                     do
@@ -179,6 +207,10 @@ public class Config
                                             {
                                                 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());
                                     }
@@ -230,9 +262,20 @@ public class Config
                                             }
                                         } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("Conflicts")));
                                     }
+                                    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());
+                                    }
                                 }
                             } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals(classType)));
-                            entityInfoMap.put(eInfo.classType, eInfo);
+                            entityInfoMap.put(eInfo.classType.getName(), eInfo);
                         }
                     } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("EntityStats")));
                 }
@@ -242,4 +285,51 @@ public class Config
         fis.close();
         return ConfigParseResult.SUCCESS;
     }
+    
+    public int getPlayerSpeed()
+    {
+        return playerSpeed;
+    }
+
+    public int getPlayerHasteSpeed()
+    {
+        return playerHasteSpeed;
+    }
+
+    public int getPlayerSlowSpeed()
+    {
+        return playerSlowSpeed;
+    }
+
+    /**
+     * Returns a clone of an EntityInfo (to prevent editing it).
+     * @param classFullName
+     * @return a clone of the stored EntityInfo or null if invalid String
+     */
+    public EntityInfo getEntityInfo(String classFullName)
+    {
+        return entityInfoMap.get(classFullName).clone();
+    }
+    
+    protected EntityInfo getEntityInfoReference(String classFullName)
+    {
+        return entityInfoMap.get(classFullName);
+    }
+    
+    protected EntityInfo getMatchingEntityInfo(Object entity)
+    {
+        EntityInfo matching = entityInfoMap.get(entity.getClass().getName());
+        if(matching.classType.isInstance(entity))
+        {
+            for(Class c : matching.conflictingTypes)
+            {
+                if(c.isInstance(entity))
+                {
+                    return entityInfoMap.get(c.getName());
+                }
+            }
+            return matching;
+        }
+        return null;
+    }
 }
index a0685756f93c9dc0ae2ba945629cd1360315773b..e4a6ae290006c1c13fb135a2d3fd30ba65daa03a 100644 (file)
@@ -1,19 +1,23 @@
 package com.seodisparate.TurnBasedMinecraft.common;
 
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 
 public class EntityInfo
 {
     public Class classType;
     public List<Class> conflictingTypes;
+    public boolean ignoreBattle;
     public int attackPower;
     public int attackProbability;
+    public int attackVariance;
     public Effect attackEffect;
     public int attackEffectProbability;
     public int defenseDamage;
     public int defenseDamageProbability;
     public int evasion;
+    public int speed;
     public Category category;
     
     public enum Category
@@ -193,13 +197,16 @@ public class EntityInfo
     {
         classType = null;
         conflictingTypes = new ArrayList<Class>();
+        ignoreBattle = false;
         attackPower = 0;
         attackProbability = 70;
+        attackVariance = 0;
         attackEffect = Effect.UNKNOWN;
         attackEffectProbability = 50;
         defenseDamage = 0;
         defenseDamageProbability = 0;
         evasion = 15;
+        speed = 50;
         category = Category.UNKNOWN;
     }
     
@@ -212,13 +219,16 @@ public class EntityInfo
         {
             newEntityInfo.conflictingTypes.add(c);
         }
+        newEntityInfo.ignoreBattle = ignoreBattle;
         newEntityInfo.attackPower = attackPower;
         newEntityInfo.attackProbability = attackProbability;
+        newEntityInfo.attackVariance = attackVariance;
         newEntityInfo.attackEffect = attackEffect;
         newEntityInfo.attackEffectProbability = attackEffectProbability;
         newEntityInfo.defenseDamage = defenseDamage;
         newEntityInfo.defenseDamageProbability = defenseDamageProbability;
         newEntityInfo.evasion = evasion;
+        newEntityInfo.speed = speed;
         newEntityInfo.category = category;
         return newEntityInfo;
     }
index 71ca9259f7b01d9d269651620229e79b23a33221..6e3d622a2449a477a566e94b6bd1cc282a4c0c93 100644 (file)
@@ -14,13 +14,15 @@ public class PacketBattleDecision implements IMessage
 {
     private int battleID;
     private Battle.Decision decision;
+    private int targetEntityID;
     
     public PacketBattleDecision() {}
     
-    public PacketBattleDecision(int battleID, Battle.Decision decision)
+    public PacketBattleDecision(int battleID, Battle.Decision decision, int targetEntityID)
     {
         this.battleID = battleID;
         this.decision = decision;
+        this.targetEntityID = targetEntityID;
     }
 
     @Override
@@ -28,6 +30,7 @@ public class PacketBattleDecision implements IMessage
     {
         battleID = buf.readInt();
         decision = Decision.valueOf(buf.readInt());
+        targetEntityID = buf.readInt();
     }
 
     @Override
@@ -35,6 +38,7 @@ public class PacketBattleDecision implements IMessage
     {
         buf.writeInt(battleID);
         buf.writeInt(decision.getValue());
+        buf.writeInt(targetEntityID);
     }
 
     public static class HandleBattleDecision implements IMessageHandler<PacketBattleDecision, IMessage>
@@ -46,7 +50,7 @@ public class PacketBattleDecision implements IMessage
             if(b != null)
             {
                 EntityPlayerMP player = ctx.getServerHandler().player;
-                b.setDecision(player.getEntityId(), message.decision);
+                b.setDecision(player.getEntityId(), message.decision, message.targetEntityID);
             }
             return null;
         }
index 937660fab9ceca68b0469164ea0c15a6eb1d5e8b..3dc684e0d6c00ce22a6a4f206047ff5cb8c8cb71 100644 (file)
 <TurnBasedMinecraftConfig>
+       <!-- If the mod has a newer version config, it will rename the existing config and place the new config -->
        <Version>1</Version>
+       <!-- Types that will not initiate battle with player. They are listed as "Category" per EntiytStats entity. -->
        <IgnoreBattleTypes>
                <Passive></Passive>
                <Boss></Boss>
        </IgnoreBattleTypes>
+       <PlayerStats>
+               <Speed>50</Speed>
+               <HasteSpeed>80</HasteSpeed>
+               <SlowSpeed>20</SlowSpeed>
+       </PlayerStats>
+       <!-- Battle stats for entities should be specified here. If an entity is not listed it cannot enter battle. -->
        <EntityStats>
+               <!-- 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. -->
+               <!-- 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. -->
+               <!-- Conflicts: (Optional) Tells the mod that this entity should not be mistaken for the listed entities (possible because some entities derive from others; CaveSpiders are also Spiders). -->
                <net.minecraft.entity.monster.EntityBlaze>
                        <AttackPower Probability="50">5</AttackPower>
                        <AttackEffect Probability="75">fire</AttackEffect>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
+                       <Speed>45</Speed>
                </net.minecraft.entity.monster.EntityBlaze>
                <net.minecraft.entity.monster.EntityCaveSpider>
                        <AttackPower Probability="75">2</AttackPower>
                        <AttackEffect Probability="90">poison</AttackEffect>
                        <Evasion>35</Evasion>
                        <Category>monster</Category>
+                       <Speed>75</Speed>
                </net.minecraft.entity.monster.EntityCaveSpider>
                <net.minecraft.entity.monster.EntityCreeper>
                        <IgnoreBattle>true</IgnoreBattle>
                        <AttackPower Probability="17" Variance="7">15</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
+                       <Speed>25</Speed>
                </net.minecraft.entity.monster.EntityCreeper>
                <net.minecraft.entity.monster.EntityElderGuardian>
                        <AttackPower Probability="65">8</AttackPower>
                        <DefenseDamage Probability="35">2</DefenseDamage>
                        <Evasion>25</Evasion>
                        <Category>monster</Category>
+                       <Speed>45</Speed>
                </net.minecraft.entity.monster.EntityElderGuardian>
                <net.minecraft.entity.monster.EntityEnderman>
                        <AttackPower Probability="80">7</AttackPower>
                        <Evasion>40</Evasion>
                        <Category>monster</Category>
+                       <Speed>70</Speed>
                </net.minecraft.entity.monster.EntityEnderman>
                <net.minecraft.entity.monster.EntityEndermite>
                        <AttackPower Probability="80">2</AttackPower>
                        <Evasion>40</Evasion>
                        <Category>monster</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntityEndermite>
                <net.minecraft.entity.monster.EntityEvoker>
                        <AttackPower Probability="60">6</AttackPower>
                        <Evasion>35</Evasion>
                        <Category>monster</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntityEvoker>
                <net.minecraft.entity.monster.EntityGhast>
                        <IgnoreBattle>true</IgnoreBattle>
                        <AttackPower Probability="20">13</AttackPower>
                        <Evasion>35</Evasion>
                        <Category>monster</Category>
+                       <Speed>60</Speed>
                </net.minecraft.entity.monster.EntityGhast>
                <net.minecraft.entity.monster.EntityGiantZombie>
                        <AttackPower Probability="35">11</AttackPower>
                        <Evasion>2</Evasion>
                        <Category>monster</Category>
+                       <Speed>45</Speed>
                </net.minecraft.entity.monster.EntityGiantZombie>
                <net.minecraft.entity.monster.EntityGuardian>
                        <AttackPower Probability="55">6</AttackPower>
                        <DefenseDamage Probability="30">2</DefenseDamage>
                        <Evasion>25</Evasion>
                        <Category>monster</Category>
+                       <Speed>50</Speed>
                </net.minecraft.entity.monster.EntityGuardian>
                <net.minecraft.entity.monster.EntityHusk>
                        <AttackPower Probability="70">3</AttackPower>
                        <AttackEffect Probability="95">hunger</AttackEffect>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
+                       <Speed>25</Speed>
                </net.minecraft.entity.monster.EntityHusk>
                <net.minecraft.entity.monster.EntityIronGolem>
                        <AttackPower Probability="85" Variance="7">14</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
+                       <Speed>45</Speed>
                </net.minecraft.entity.monster.EntityIronGolem>
                <net.minecraft.entity.monster.EntityMagmaCube>
                        <AttackPower Probability="35">3</AttackPower>
                        <Evasion>12</Evasion>
                        <Category>monster</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntityMagmaCube>
                <net.minecraft.entity.monster.EntityPigZombie>
                        <AttackPower Probability="70">8</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>monster</Category>
+                       <Speed>50</Speed>
                </net.minecraft.entity.monster.EntityPigZombie>
                <net.minecraft.entity.monster.EntityPolarBear>
                        <AttackPower Probability="67">6</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>animal</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntityPolarBear>
                <net.minecraft.entity.monster.EntityShulker>
                        <AttackPower Probability="80">4</AttackPower>
                        <Evasion>15</Evasion>
                        <Category>monster</Category>
+                       <Speed>10</Speed>
                </net.minecraft.entity.monster.EntityShulker>
                <net.minecraft.entity.monster.EntitySilverFish>
                        <AttackPower Probability="85">1</AttackPower>
                        <Evasion>37</Evasion>
                        <Category>monster</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntitySilverFish>
                <net.minecraft.entity.monster.EntitySkeleton>
                        <AttackPower Probability="75" Variance="1">3</AttackPower>
                        <Evasion>13</Evasion>
                        <Category>monster</Category>
+                       <Speed>30</Speed>
                </net.minecraft.entity.monster.EntitySkeleton>
                <net.minecraft.entity.monster.EntitySlime>
                        <AttackPower Probability="35">2</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>monster</Category>
+                       <Speed>30</Speed>
                </net.minecraft.entity.monster.EntitySlime>
                <net.minecraft.entity.monster.EntitySnowman>
                        <AttackPower Probability="80">0</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>passive</Category>
+                       <Speed>60</Speed>
                </net.minecraft.entity.monster.EntitySnowman>
                <net.minecraft.entity.monster.EntitySpider>
                        <AttackPower Probability="70">2</AttackPower>
                                <net.minecraft.entity.monster.EntityCaveSpider></net.minecraft.entity.monster.EntityCaveSpider>
                        </Conflicts>
                        <Category>monster</Category>
+                       <Speed>70</Speed>
                </net.minecraft.entity.monster.EntitySpider>
                <net.minecraft.entity.monster.EntityStray>
                        <AttackPower Probability="75" Variance="1">3</AttackPower>
                        <AttackEffect Probability="90">slow</AttackEffect>
                        <Evasion>13</Evasion>
                        <Category>monster</Category>
+                       <Speed>30</Speed>
                </net.minecraft.entity.monster.EntityStray>
                <net.minecraft.entity.monster.EntityVex>
                        <AttackPower Probability="65">9</AttackPower>
                        <Evasion>30</Evasion>
                        <Category>monster</Category>
+                       <Speed>80</Speed>
                </net.minecraft.entity.monster.EntityVex>
                <net.minecraft.entity.monster.EntityVindicator>
                        <AttackPower Probability="70">13</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>monster</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntityVindicator>
                <net.minecraft.entity.monster.EntityWitch>
                        <AttackPower Probability="75" Variance="1">5</AttackPower>
                        <Evasion>8</Evasion>
                        <Category>monster</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.monster.EntityWitch>
                <net.minecraft.entity.monster.EntityWitherSkeleton>
                        <AttackPower Probability="70">8</AttackPower>
                        <AttackEffect Probability="90">wither</AttackEffect>
                        <Evasion>7</Evasion>
                        <Category>monster</Category>
+                       <Speed>65</Speed>
                </net.minecraft.entity.monster.EntityWitherSkeleton>
                <net.minecraft.entity.monster.EntityZombie>
                        <AttackPower Probability="70">3</AttackPower>
                        </Conflicts>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
+                       <Speed>25</Speed>
                </net.minecraft.entity.monster.EntityZombie>
                <net.minecraft.entity.monster.EntityZombieVillager>
                        <AttackPower Probability="70">3</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
+                       <Speed>25</Speed>
                </net.minecraft.entity.monster.EntityZombieVillager>
                <net.minecraft.entity.passive.EntityBat>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>35</Evasion>
                        <Category>passive</Category>
+                       <Speed>75</Speed>
                </net.minecraft.entity.passive.EntityBat>
                <net.minecraft.entity.passive.EntityChicken>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.passive.EntityChicken>
                <net.minecraft.entity.passive.EntityCow>
                        <AttackPower Probability="50">0</AttackPower>
                                <net.minecraft.entity.passive.EntityMooshroom></net.minecraft.entity.passive.EntityMooshroom>
                        </Conflicts>
                        <Category>passive</Category>
+                       <Speed>20</Speed>
                </net.minecraft.entity.passive.EntityCow>
                <net.minecraft.entity.passive.EntityDonkey>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>65</Speed>
                </net.minecraft.entity.passive.EntityDonkey>
                <net.minecraft.entity.passive.EntityHorse>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>65</Speed>
                </net.minecraft.entity.passive.EntityHorse>
                <net.minecraft.entity.passive.EntityLlama>
                        <AttackPower Probability="70">1</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>50</Speed>
                </net.minecraft.entity.passive.EntityLlama>
                <net.minecraft.entity.passive.EntityMooshroom>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>1</Evasion>
                        <Category>passive</Category>
+                       <Speed>20</Speed>
                </net.minecraft.entity.passive.EntityMooshroom>
                <net.minecraft.entity.passive.EntityMule>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>50</Speed>
                </net.minecraft.entity.passive.EntityMule>
                <net.minecraft.entity.passive.EntityOcelot>
                        <AttackPower Probability="70" Variance="1">1</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>75</Speed>
                </net.minecraft.entity.passive.EntityOcelot>
                <net.minecraft.entity.passive.EntityParrot>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>35</Evasion>
                        <Category>passive</Category>
+                       <Speed>70</Speed>
                </net.minecraft.entity.passive.EntityParrot>
                <net.minecraft.entity.passive.EntityPig>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
                        <Category>passive</Category>
+                       <Speed>30</Speed>
                </net.minecraft.entity.passive.EntityPig>
                <net.minecraft.entity.passive.EntityRabbit>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>40</Evasion>
                        <Category>passive</Category>
+                       <Speed>75</Speed>
                </net.minecraft.entity.passive.EntityRabbit>
                <net.minecraft.entity.passive.EntitySheep>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>passive</Category>
+                       <Speed>30</Speed>
                </net.minecraft.entity.passive.EntitySheep>
                <net.minecraft.entity.passive.EntitySkeletonHorse>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>passive</Category>
+                       <Speed>65</Speed>
                </net.minecraft.entity.passive.EntitySkeletonHorse>
                <net.minecraft.entity.passive.EntitySquid>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>15</Evasion>
                        <Category>passive</Category>
+                       <Speed>40</Speed>
                </net.minecraft.entity.passive.EntitySquid>
                <net.minecraft.entity.passive.EntityVillager>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>5</Evasion>
                        <Category>passive</Category>
+                       <Speed>35</Speed>
                </net.minecraft.entity.passive.EntityVillager>
                <net.minecraft.entity.passive.EntityWolf>
                        <AttackPower Probability="70">4</AttackPower>
                        <Evasion>20</Evasion>
                        <Category>animal</Category>
+                       <Speed>70</Speed>
                </net.minecraft.entity.passive.EntityWolf>
                <net.minecraft.entity.passive.EntityZombieHorse>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>8</Evasion>
                        <Category>passive</Category>
+                       <Speed>65</Speed>
                </net.minecraft.entity.passive.EntityZombieHorse>
                <net.minecraft.entity.boss.EntityDragon>
                        <AttackPower Probability="70" Variance="2">10</AttackPower>
                        <Evasion>27</Evasion>
                        <Category>boss</Category>
+                       <Speed>63</Speed>
                </net.minecraft.entity.boss.EntityDragon>
                <net.minecraft.entity.boss.EntityWither>
                        <AttackPower Probability="70">8</AttackPower>
                        <Evasion>20</Evasion>
                        <AttackEffect Probability="90">wither</AttackEffect>
                        <Category>boss</Category>
+                       <Speed>68</Speed>
                </net.minecraft.entity.boss.EntityWither>
        </EntityStats>
 </TurnBasedMinecraftConfig>
\ No newline at end of file