]> git.seodisparate.com - TurnBasedMinecraftMod/commitdiff
WIP more backend work on battle logic
authorStephen Seo <seo.disparate@gmail.com>
Thu, 6 Sep 2018 08:08:36 +0000 (17:08 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 6 Sep 2018 08:08:36 +0000 (17:08 +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/BattleUpdater.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/PacketBattleEntered.java [deleted file]
src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleExited.java [deleted file]
src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java [new file with mode: 0644]
src/main/resources/TBM_Config.xml

index 708975528db6365f7d9ca9a5ec4b18023bb66de5..73e17bcc32434430110912a29ac6faed27fa2274 100644 (file)
@@ -8,9 +8,8 @@ import com.seodisparate.TurnBasedMinecraft.common.Battle;
 import com.seodisparate.TurnBasedMinecraft.common.BattleManager;
 import com.seodisparate.TurnBasedMinecraft.common.Config;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleDecision;
-import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleEntered;
-import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleExited;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleInfo;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleMessage;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleRequestInfo;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketHandler;
 
@@ -39,6 +38,7 @@ public class TurnBasedMinecraftMod
     private static BattleManager battleManager;
     private static int packetHandlerID = 0;
     public static Entity attackingEntity;
+    public static int attackingDamage = 0;
     public static Config config;
     
     public static Battle currentBattle;
@@ -63,16 +63,6 @@ public class TurnBasedMinecraftMod
         }
         
         // register packets
-        PacketHandler.INSTANCE.registerMessage(
-            PacketBattleEntered.HandlerBattleEntered.class,
-            PacketBattleEntered.class,
-            packetHandlerID++,
-            Side.CLIENT);
-        PacketHandler.INSTANCE.registerMessage(
-            PacketBattleExited.HandlerBattleExited.class,
-            PacketBattleExited.class,
-            packetHandlerID++,
-            Side.CLIENT);
         PacketHandler.INSTANCE.registerMessage(
             PacketBattleInfo.HandlerBattleInfo.class,
             PacketBattleInfo.class,
@@ -88,6 +78,11 @@ public class TurnBasedMinecraftMod
             PacketBattleDecision.class,
             packetHandlerID++,
             Side.SERVER);
+        PacketHandler.INSTANCE.registerMessage(
+            PacketBattleMessage.HandlerBattleMessage.class,
+            PacketBattleMessage.class,
+            packetHandlerID++,
+            Side.CLIENT);
     }
     
     @EventHandler
@@ -111,6 +106,7 @@ public class TurnBasedMinecraftMod
             logger.debug("Canceled LivingAttackEvent between " + attackingEntity + " and " + event.getEntity());
             event.setCanceled(true);
         }
+        attackingDamage = (int) event.getAmount();
     }
     
     public static BattleManager getBattleManager()
index 3c2d0688f9921df2064a530e2ba4793ad75c3630..3dc054af36989d8d129734220666c7dc5792523c 100644 (file)
@@ -2,19 +2,19 @@ package com.seodisparate.TurnBasedMinecraft.common;
 
 import java.time.Duration;
 import java.time.Instant;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 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.Queue;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleInfo;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleMessage;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketHandler;
 
 import net.minecraft.entity.Entity;
@@ -37,6 +37,9 @@ public class Battle
     private AtomicInteger undecidedCount;
     private Duration timer;
     
+    private boolean isServer;
+    private boolean battleEnded;
+    
     public enum State
     {
         DECISION,
@@ -79,8 +82,9 @@ public class Battle
         }
     }
 
-    public Battle(int id, Collection<Entity> sideA, Collection<Entity> sideB)
+    public Battle(int id, Collection<Entity> sideA, Collection<Entity> sideB, boolean isServer)
     {
+        this.isServer = isServer;
         this.id = id;
         this.sideA = new Hashtable<Integer, Combatant>();
         this.sideB = new Hashtable<Integer, Combatant>();
@@ -129,10 +133,22 @@ public class Battle
             }
         }
         
+        for(Combatant c : this.sideA.values())
+        {
+            sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENTERED, c.entity.getEntityId(), 0, id);
+        }
+        for(Combatant c : this.sideB.values())
+        {
+            sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENTERED, c.entity.getEntityId(), 0, id);
+        }
+        
         lastUpdated = null;
         state = State.DECISION;
         undecidedCount.set(playerCount.get());
         timer = TurnBasedMinecraftMod.BattleDecisionTime;
+        battleEnded = false;
+        
+        notifyPlayersBattleInfo();
     }
 
     public int getId()
@@ -140,6 +156,21 @@ public class Battle
         return id;
     }
     
+    public Entity getCombatantEntity(int entityID)
+    {
+        Combatant c = sideA.get(entityID);
+        if(c != null)
+        {
+            return c.entity;
+        }
+        c = sideB.get(entityID);
+        if(c != null)
+        {
+            return c.entity;
+        }
+        return null;
+    }
+    
     public boolean hasCombatant(int entityID)
     {
         return sideA.containsKey(entityID) || sideB.containsKey(entityID);
@@ -170,6 +201,8 @@ public class Battle
                 undecidedCount.incrementAndGet();
             }
         }
+        sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENTERED, newCombatant.entity.getEntityId(), 0, id);
+        notifyPlayersBattleInfo();
     }
     
     public void addCombatantToSideB(Entity e)
@@ -192,6 +225,8 @@ public class Battle
                 undecidedCount.incrementAndGet();
             }
         }
+        sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENTERED, newCombatant.entity.getEntityId(), 0, id);
+        notifyPlayersBattleInfo();
     }
     
     public void clearCombatants()
@@ -271,9 +306,9 @@ public class Battle
         return state;
     }
     
-    public void notifyPlayersBattleInfo()
+    protected void notifyPlayersBattleInfo()
     {
-        if(TurnBasedMinecraftMod.getBattleManager() == null)
+        if(!isServer)
         {
             return;
         }
@@ -284,29 +319,95 @@ public class Battle
         }
     }
     
-    public void update()
+    /**
+     * @return True if battle has ended
+     */
+    public boolean update()
     {
+        if(battleEnded)
+        {
+            return true;
+        }
         if(lastUpdated == null)
         {
             lastUpdated = Instant.now();
-            update(Duration.ZERO);
+            return update(Duration.ZERO);
         }
         else
         {
             Instant now = Instant.now();
-            update(Duration.between(lastUpdated, now));
+            Duration dt = Duration.between(lastUpdated, now);
             lastUpdated = now;
+            return update(dt);
         }
     }
     
-    private void update(final Duration dt)
+    private void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount)
     {
+        if(!isServer)
+        {
+            return;
+        }
+        for(Combatant p : players.values())
+        {
+            if(p.entity.isEntityAlive())
+            {
+                PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(type, from, to, amount), (EntityPlayerMP)p.entity);
+            }
+        }
+    }
+    
+    private boolean update(final Duration dt)
+    {
+        if(battleEnded)
+        {
+            return true;
+        }
         switch(state)
         {
         case DECISION:
             timer = timer.minus(dt);
             if(timer.isNegative() || timer.isZero() || undecidedCount.get() <= 0)
             {
+                for(Combatant c : sideA.values())
+                {
+                    // picking decision for sideA non-players
+                    if(!(c.entity instanceof EntityPlayer) && c.decision == Decision.UNDECIDED && c.entityInfo != null)
+                    {
+                        int percentage = (int)(Math.random() * 100);
+                        if(percentage < c.entityInfo.decisionAttack)
+                        {
+                            c.decision = Decision.ATTACK;
+                        }
+                        else if(percentage - c.entityInfo.decisionAttack < c.entityInfo.decisionDefend)
+                        {
+                            c.decision = Decision.DEFEND;
+                        }
+                        else if(percentage - c.entityInfo.decisionAttack - c.entityInfo.decisionDefend < c.entityInfo.decisionFlee)
+                        {
+                            c.decision = Decision.FLEE;
+                        }
+                    }
+                }
+                for(Combatant c : sideB.values())
+                {
+                    if(!(c.entity instanceof EntityPlayer) && c.decision == Decision.UNDECIDED && c.entityInfo != null)
+                    {
+                        int percentage = (int)(Math.random() * 100);
+                        if(percentage < c.entityInfo.decisionAttack)
+                        {
+                            c.decision = Decision.ATTACK;
+                        }
+                        else if(percentage - c.entityInfo.decisionAttack < c.entityInfo.decisionDefend)
+                        {
+                            c.decision = Decision.DEFEND;
+                        }
+                        else if(percentage - c.entityInfo.decisionAttack - c.entityInfo.decisionDefend < c.entityInfo.decisionFlee)
+                        {
+                            c.decision = Decision.FLEE;
+                        }
+                    }
+                }
                 state = State.ACTION;
                 timer = TurnBasedMinecraftMod.BattleDecisionTime;
                 turnOrderQueue.clear();
@@ -319,7 +420,6 @@ public class Battle
                     turnOrderQueue.add(c);
                 }
                 update(Duration.ZERO);
-                // TODO assign decisions to non-players
             }
             break;
         case ACTION:
@@ -335,6 +435,7 @@ public class Battle
                 switch(next.decision)
                 {
                 case UNDECIDED:
+                    sendMessageToAllPlayers(PacketBattleMessage.MessageType.DID_NOTHING, next.entity.getEntityId(), 0, 0);
                     next = turnOrderQueue.poll();
                     continue;
                 case ATTACK:
@@ -372,6 +473,7 @@ public class Battle
                                 TurnBasedMinecraftMod.attackingEntity = next.entity;
                                 ((EntityPlayer)next.entity).attackTargetEntityWithCurrentItem(target.entity);
                                 TurnBasedMinecraftMod.attackingEntity = null;
+                                sendMessageToAllPlayers(PacketBattleMessage.MessageType.ATTACK, next.entity.getEntityId(), target.entity.getEntityId(), TurnBasedMinecraftMod.attackingDamage);
                                 if(!(target.entity instanceof EntityPlayer) && target.entityInfo.defenseDamage > 0)
                                 {
                                     if((int)(Math.random() * 100) < target.entityInfo.defenseDamageProbability)
@@ -381,6 +483,7 @@ public class Battle
                                         TurnBasedMinecraftMod.attackingEntity = target.entity;
                                         next.entity.attackEntityFrom(defenseDamageSource, target.entityInfo.defenseDamage);
                                         TurnBasedMinecraftMod.attackingEntity = null;
+                                        sendMessageToAllPlayers(PacketBattleMessage.MessageType.DEFENSE_DAMAGE, target.entity.getEntityId(), next.entity.getEntityId(), target.entityInfo.defenseDamage);
                                     }
                                 }
                             }
@@ -388,11 +491,13 @@ public class Battle
                             {
                                 // blocked
                                 --target.remainingDefenses;
+                                sendMessageToAllPlayers(PacketBattleMessage.MessageType.DEFEND, target.entity.getEntityId(), next.entity.getEntityId(), 0);
                             }
                         }
                         else
                         {
                             // miss
+                            sendMessageToAllPlayers(PacketBattleMessage.MessageType.MISS, next.entity.getEntityId(), target.entity.getEntityId(), 0);
                         }
                     }
                     else
@@ -447,8 +552,9 @@ public class Battle
                                 }
                                 // attack
                                 TurnBasedMinecraftMod.attackingEntity = next.entity;
-                                target.entity.attackEntityFrom(damageSource, next.entityInfo.attackPower);
+                                target.entity.attackEntityFrom(damageSource, damageAmount);
                                 TurnBasedMinecraftMod.attackingEntity = null;
+                                sendMessageToAllPlayers(PacketBattleMessage.MessageType.ATTACK, next.entity.getEntityId(), target.entity.getEntityId(), damageAmount);
                                 if(!(target.entity instanceof EntityPlayer) && target.entityInfo.defenseDamage > 0)
                                 {
                                     if((int)(Math.random() * 100) < target.entityInfo.defenseDamageProbability)
@@ -458,6 +564,7 @@ public class Battle
                                         TurnBasedMinecraftMod.attackingEntity = target.entity;
                                         next.entity.attackEntityFrom(defenseDamageSource, target.entityInfo.defenseDamage);
                                         TurnBasedMinecraftMod.attackingEntity = null;
+                                        sendMessageToAllPlayers(PacketBattleMessage.MessageType.DEFENSE_DAMAGE, target.entity.getEntityId(), next.entity.getEntityId(), target.entityInfo.defenseDamage);
                                     }
                                 }
                             }
@@ -465,16 +572,19 @@ public class Battle
                             {
                                 // blocked
                                 --target.remainingDefenses;
+                                sendMessageToAllPlayers(PacketBattleMessage.MessageType.DEFEND, target.entity.getEntityId(), next.entity.getEntityId(), 0);
                             }
                         }
                         else
                         {
                             // miss
+                            sendMessageToAllPlayers(PacketBattleMessage.MessageType.MISS, next.entity.getEntityId(), target.entity.getEntityId(), 0);
                         }
                     }
                     break;
                 case DEFEND:
                     next.remainingDefenses = TurnBasedMinecraftMod.config.getDefenseDuration();
+                    sendMessageToAllPlayers(PacketBattleMessage.MessageType.DEFENDING, next.entity.getEntityId(), 0, 0);
                     break;
                 case FLEE:
                     int fastestEnemySpeed = 0;
@@ -552,13 +662,19 @@ public class Battle
                         {
                             sideB.remove(next.entity.getEntityId());
                         }
+                        sendMessageToAllPlayers(PacketBattleMessage.MessageType.FLEE, next.entity.getEntityId(), 0, 1);
                         if(next.entity instanceof EntityPlayer)
                         {
                             players.remove(next.entity.getEntityId());
                             playerCount.decrementAndGet();
-                            // TODO notify player exited battle
+                            PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, 0, 0, 0), (EntityPlayerMP)next.entity);
                         }
                     }
+                    else
+                    {
+                        // flee fail
+                        sendMessageToAllPlayers(PacketBattleMessage.MessageType.FLEE, next.entity.getEntityId(), 0, 0);
+                    }
                     break;
                 case USE_ITEM:
                     break;
@@ -578,8 +694,57 @@ public class Battle
             break;
         }
         case HEALTH_CHECK:
-            // TODO
+            Queue<Integer> removeQueue = new ArrayDeque<Integer>();
+            for(Combatant c : sideA.values())
+            {
+                if(!c.entity.isEntityAlive())
+                {
+                    removeQueue.add(c.entity.getEntityId());
+                    if(c.entity instanceof EntityPlayer)
+                    {
+                        PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, c.entity.getEntityId(), 0, 0), (EntityPlayerMP)c.entity);
+                    }
+                    sendMessageToAllPlayers(PacketBattleMessage.MessageType.DIED, c.entity.getEntityId(), 0, 0);
+                }
+            }
+            for(Combatant c : sideB.values())
+            {
+                if(!c.entity.isEntityAlive())
+                {
+                    removeQueue.add(c.entity.getEntityId());
+                    if(c.entity instanceof EntityPlayer)
+                    {
+                        PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, c.entity.getEntityId(), 0, 0), (EntityPlayerMP)c.entity);
+                    }
+                    sendMessageToAllPlayers(PacketBattleMessage.MessageType.DIED, c.entity.getEntityId(), 0, 0);
+                }
+            }
+            boolean didRemove = !removeQueue.isEmpty();
+            Integer toRemove = removeQueue.poll();
+            while(toRemove != null)
+            {
+                sideA.remove(toRemove);
+                sideB.remove(toRemove);
+                if(players.remove(toRemove) != null)
+                {
+                    playerCount.decrementAndGet();
+                }
+                toRemove = removeQueue.poll();
+            }
+            if(players.isEmpty() || sideA.isEmpty() || sideB.isEmpty())
+            {
+                battleEnded = true;
+                sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENDED, 0, 0, 0);
+            }
+            else if(didRemove)
+            {
+                notifyPlayersBattleInfo();
+            }
+            state = State.DECISION;
+            undecidedCount.set(playerCount.get());
+            timer = TurnBasedMinecraftMod.BattleDecisionTime;
             break;
         }
+        return battleEnded;
     }
 }
index 18ddcbd14e35a3103f816f8c9c981a502c4dc316..756614047baf7ad3ee3db4b7d00204dde6ba7108 100644 (file)
@@ -6,12 +6,9 @@ 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;
 
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraftforge.event.entity.living.LivingAttackEvent;
 
 public class BattleManager
@@ -104,13 +101,7 @@ public class BattleManager
         {
             battle.addCombatantToSideA(notInBattle);
         }
-        
-        if(notInBattle instanceof EntityPlayerMP)
-        {
-            PacketHandler.INSTANCE.sendTo(new PacketBattleEntered(IDCounter), (EntityPlayerMP)notInBattle);
-        }
-        
-        battle.notifyPlayersBattleInfo();
+
         return true;
     }
     
@@ -120,22 +111,8 @@ public class BattleManager
         {
             ++IDCounter;
         }
-        Battle newBattle = new Battle(IDCounter, sideA, sideB);
+        Battle newBattle = new Battle(IDCounter, sideA, sideB, true);
         battleMap.put(IDCounter, newBattle);
-        for(Entity e : sideA)
-        {
-            if(e instanceof EntityPlayerMP)
-            {
-                PacketHandler.INSTANCE.sendTo(new PacketBattleEntered(IDCounter), (EntityPlayerMP)e);
-            }
-        }
-        for(Entity e : sideB)
-        {
-            if(e instanceof EntityPlayerMP)
-            {
-                PacketHandler.INSTANCE.sendTo(new PacketBattleEntered(IDCounter), (EntityPlayerMP)e);
-            }
-        }
         newBattle.notifyPlayersBattleInfo();
         return newBattle;
     }
index aa8732a684d83f476bf6d82b30e90bdb3dbbb0dd..eb0931cca1750bdf934ae36b52b5119d0541656e 100644 (file)
@@ -1,5 +1,8 @@
 package com.seodisparate.TurnBasedMinecraft.common;
 
+import java.util.ArrayDeque;
+import java.util.Queue;
+
 public class BattleUpdater implements Runnable
 {
     private BattleManager manager;
@@ -14,11 +17,22 @@ public class BattleUpdater implements Runnable
     @Override
     public void run()
     {
+        Queue<Integer> endedQueue = new ArrayDeque<Integer>();
+        Integer ended;
         while(isRunning)
         {
             for(Battle e : manager.battleMap.values())
             {
-                e.update();
+                if(e.update())
+                {
+                    endedQueue.add(e.getId());
+                }
+            }
+            ended = endedQueue.poll();
+            while(ended != null)
+            {
+                manager.battleMap.remove(ended);
+                ended = endedQueue.poll();
             }
             try { Thread.sleep(250); } catch (Exception e) { /* ignored */ }
         }
index 1eb2325765e1424b6e37f1490341caf8591b1b41..4164d2415394d42bb4294b1795ed991fc7ed1fa4 100644 (file)
@@ -27,9 +27,9 @@ public class Config
     private Map<String, EntityInfo> entityInfoMap;
     private Set<EntityInfo.Category> ignoreBattleTypes;
     private Logger logger;
-    private int playerSpeed;
-    private int playerHasteSpeed;
-    private int playerSlowSpeed;
+    private int playerSpeed = 50;
+    private int playerHasteSpeed = 80;
+    private int playerSlowSpeed = 20;
     private int playerAttackProbability = 100;
     private int playerEvasion = 10;
     private int defenseDuration = 1;
@@ -298,6 +298,28 @@ public class Config
                                     {
                                         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(classType)));
                             entityInfoMap.put(eInfo.classType.getName(), eInfo);
@@ -368,6 +390,10 @@ public class Config
     
     protected EntityInfo getMatchingEntityInfo(Object entity)
     {
+        if(entity == null)
+        {
+            return null;
+        }
         EntityInfo matching = entityInfoMap.get(entity.getClass().getName());
         if(matching.classType.isInstance(entity))
         {
index e4a6ae290006c1c13fb135a2d3fd30ba65daa03a..1f7aebe72884866454590a30688fcf52a6a433dc 100644 (file)
@@ -19,6 +19,9 @@ public class EntityInfo
     public int evasion;
     public int speed;
     public Category category;
+    public int decisionAttack;
+    public int decisionDefend;
+    public int decisionFlee;
     
     public enum Category
     {
@@ -208,6 +211,9 @@ public class EntityInfo
         evasion = 15;
         speed = 50;
         category = Category.UNKNOWN;
+        decisionAttack = 70;
+        decisionDefend = 20;
+        decisionFlee = 10;
     }
     
     public EntityInfo clone()
@@ -230,6 +236,9 @@ public class EntityInfo
         newEntityInfo.evasion = evasion;
         newEntityInfo.speed = speed;
         newEntityInfo.category = category;
+        newEntityInfo.decisionAttack = decisionAttack;
+        newEntityInfo.decisionDefend = decisionDefend;
+        newEntityInfo.decisionFlee = decisionFlee;
         return newEntityInfo;
     }
 }
diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleEntered.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleEntered.java
deleted file mode 100644 (file)
index 35ad906..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.seodisparate.TurnBasedMinecraft.common.networking;
-
-import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
-import com.seodisparate.TurnBasedMinecraft.common.Battle;
-
-import io.netty.buffer.ByteBuf;
-import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
-import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
-import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
-
-public class PacketBattleEntered implements IMessage
-{
-    private int battleID;
-    
-    public PacketBattleEntered() {}
-    
-    public PacketBattleEntered(int battleID)
-    {
-        this.battleID = battleID;
-    }
-
-    @Override
-    public void fromBytes(ByteBuf buf)
-    {
-        battleID = buf.readInt();
-    }
-
-    @Override
-    public void toBytes(ByteBuf buf)
-    {
-        buf.writeInt(battleID);
-    }
-
-    public static class HandlerBattleEntered implements IMessageHandler<PacketBattleEntered, IMessage>
-    {
-        @Override
-        public IMessage onMessage(PacketBattleEntered message, MessageContext ctx)
-        {
-            TurnBasedMinecraftMod.currentBattle = new Battle(message.battleID, null, null);
-            return null;
-        }
-    }
-}
diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleExited.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleExited.java
deleted file mode 100644 (file)
index e89e061..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.seodisparate.TurnBasedMinecraft.common.networking;
-
-import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
-
-import io.netty.buffer.ByteBuf;
-import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
-import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
-import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
-
-public class PacketBattleExited implements IMessage
-{
-    @Override
-    public void fromBytes(ByteBuf buf)
-    {
-    }
-
-    @Override
-    public void toBytes(ByteBuf buf)
-    {
-    }
-
-    public static class HandlerBattleExited implements IMessageHandler<PacketBattleExited, IMessage>
-    {
-        @Override
-        public IMessage onMessage(PacketBattleExited message, MessageContext ctx)
-        {
-            TurnBasedMinecraftMod.currentBattle = null;
-            return null;
-        }
-    }
-}
diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java
new file mode 100644 (file)
index 0000000..a34b796
--- /dev/null
@@ -0,0 +1,233 @@
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+import com.seodisparate.TurnBasedMinecraft.common.Battle;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLiving;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.scoreboard.ScorePlayerTeam;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+
+public class PacketBattleMessage implements IMessage
+{
+    public enum MessageType
+    {
+        ENTERED(0),
+        FLEE(1),
+        DIED(2),
+        ENDED(3),
+        ATTACK(4),
+        DEFEND(5),
+        DEFENSE_DAMAGE(6),
+        MISS(7),
+        DEFENDING(8),
+        DID_NOTHING(9);
+        
+        private int value;
+        private static Map<Integer, MessageType> map = new HashMap<Integer, MessageType>();
+        
+        private MessageType(int value)
+        {
+            this.value = value;
+        }
+        
+        public int getValue()
+        {
+            return value;
+        }
+        
+        static
+        {
+            for(MessageType type : MessageType.values())
+            {
+                map.put(type.getValue(), type);
+            }
+        }
+        
+        public static MessageType valueOf(int value)
+        {
+            return map.get(value);
+        }
+    }
+    
+    MessageType messageType;
+    int entityIDFrom;
+    int entityIDTo;
+    int amount;
+    
+    public PacketBattleMessage() {}
+    
+    public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, int amount)
+    {
+        this.messageType = messageType;
+        this.entityIDFrom = entityIDFrom;
+        this.entityIDTo = entityIDTo;
+        this.amount = amount;
+    }
+
+    @Override
+    public void fromBytes(ByteBuf buf)
+    {
+        messageType = MessageType.valueOf(buf.readInt());
+        entityIDFrom = buf.readInt();
+        entityIDTo = buf.readInt();
+        amount = buf.readInt();
+    }
+
+    @Override
+    public void toBytes(ByteBuf buf)
+    {
+        buf.writeInt(messageType.getValue());
+        buf.writeInt(entityIDFrom);
+        buf.writeInt(entityIDTo);
+        buf.writeInt(amount);
+    }
+
+    public static class HandlerBattleMessage implements IMessageHandler<PacketBattleMessage, IMessage>
+    {
+        @Override
+        public IMessage onMessage(PacketBattleMessage message, MessageContext ctx)
+        {
+            Entity fromEntity = Minecraft.getMinecraft().world.getEntityByID(message.entityIDFrom);
+            String from = "Unknown";
+            if(fromEntity != null)
+            {
+                if(fromEntity.hasCustomName())
+                {
+                    from = fromEntity.getCustomNameTag();
+                }
+                else if(fromEntity instanceof EntityPlayer)
+                {
+                    from = ScorePlayerTeam.formatPlayerName(fromEntity.getTeam(), fromEntity.getName());
+                }
+                else
+                {
+                    from = fromEntity.getName();
+                }
+            }
+            else if(TurnBasedMinecraftMod.currentBattle != null)
+            {
+                fromEntity = TurnBasedMinecraftMod.currentBattle.getCombatantEntity(message.entityIDFrom);
+                if(fromEntity != null)
+                {
+                    if(fromEntity.hasCustomName())
+                    {
+                        from = fromEntity.getCustomNameTag();
+                    }
+                    else if(fromEntity instanceof EntityPlayer)
+                    {
+                        from = ScorePlayerTeam.formatPlayerName(fromEntity.getTeam(), fromEntity.getName());
+                    }
+                    else
+                    {
+                        from = fromEntity.getName();
+                    }
+                }
+            }
+            Entity toEntity = Minecraft.getMinecraft().world.getEntityByID(message.entityIDTo);
+            String to = "Unknown";
+            if(toEntity != null)
+            {
+                if(toEntity.hasCustomName())
+                {
+                    to = toEntity.getCustomNameTag();
+                }
+                else if(toEntity instanceof EntityPlayer)
+                {
+                    to = ScorePlayerTeam.formatPlayerName(toEntity.getTeam(), toEntity.getName());
+                }
+                else
+                {
+                    to = toEntity.getName();
+                }
+            }
+            else if(TurnBasedMinecraftMod.currentBattle != null)
+            {
+                toEntity = TurnBasedMinecraftMod.currentBattle.getCombatantEntity(message.entityIDTo);
+                if(toEntity != null)
+                {
+                    if(toEntity.hasCustomName())
+                    {
+                        to = toEntity.getCustomNameTag();
+                    }
+                    else if(toEntity instanceof EntityPlayer)
+                    {
+                        to = ScorePlayerTeam.formatPlayerName(toEntity.getTeam(), toEntity.getName());
+                    }
+                    else
+                    {
+                        to = toEntity.getName();
+                    }
+                }
+            }
+            
+            switch(message.messageType)
+            {
+            case ENTERED:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " entered battle!"));
+                if(TurnBasedMinecraftMod.currentBattle == null || TurnBasedMinecraftMod.currentBattle.getId() != message.amount)
+                {
+                    TurnBasedMinecraftMod.currentBattle = new Battle(message.amount, null, null, false);
+                }
+                break;
+            case FLEE:
+                if(message.amount != 0)
+                {
+                    Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                        from + " fled battle!"));
+                }
+                else
+                {
+                    Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                        from + " tried to flee battle but failed!"));
+                }
+                break;
+            case DIED:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " died in battle!"));
+                break;
+            case ENDED:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                        "Battle has ended!"));
+                TurnBasedMinecraftMod.currentBattle = null;
+                // TODO kick player out of battle
+                break;
+            case ATTACK:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " attacked " + to + " and dealt " + message.amount + " damage!"));
+                break;
+            case DEFEND:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " blocked " + to + "'s attack!"));
+                break;
+            case DEFENSE_DAMAGE:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " retaliated from " + to + "'s attack and dealt " + message.amount + " damage!"));
+                break;
+            case MISS:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " attacked " + to + " but missed!"));
+                break;
+            case DEFENDING:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " is defending!"));
+                break;
+            case DID_NOTHING:
+                Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
+                    from + " did nothing!"));
+                break;
+            }
+            return null;
+        }
+    }
+}
index fedad3917a3e3e013e47ea9478176f29c7b6d99f..e0828adff0379f2686a9d22e66cd40aaca48970e 100644 (file)
                <!-- 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). -->
+               <!-- 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 -->
                <net.minecraft.entity.monster.EntityBlaze>
                        <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>
                </net.minecraft.entity.monster.EntityBlaze>
                <net.minecraft.entity.monster.EntityCaveSpider>
                        <AttackPower Probability="75">2</AttackPower>
                        <Evasion>35</Evasion>
                        <Category>monster</Category>
                        <Speed>75</Speed>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityCaveSpider>
                <net.minecraft.entity.monster.EntityCreeper>
                        <IgnoreBattle>true</IgnoreBattle>
                        <Evasion>5</Evasion>
                        <Category>monster</Category>
                        <Speed>25</Speed>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityCreeper>
                <net.minecraft.entity.monster.EntityElderGuardian>
                        <AttackPower Probability="65">8</AttackPower>
                        <Evasion>25</Evasion>
                        <Category>monster</Category>
                        <Speed>45</Speed>
+                       <Decision>
+                               <Attack>80</Attack>
+                               <Defend>20</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityElderGuardian>
                <net.minecraft.entity.monster.EntityEnderman>
                        <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>
                </net.minecraft.entity.monster.EntityEnderman>
                <net.minecraft.entity.monster.EntityEndermite>
                        <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>
                </net.minecraft.entity.monster.EntityEndermite>
                <net.minecraft.entity.monster.EntityEvoker>
                        <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>
                </net.minecraft.entity.monster.EntityEvoker>
                <net.minecraft.entity.monster.EntityGhast>
                        <IgnoreBattle>true</IgnoreBattle>
                        <Evasion>35</Evasion>
                        <Category>monster</Category>
                        <Speed>60</Speed>
+                       <Decision>
+                               <Attack>75</Attack>
+                               <Defend>0</Defend>
+                               <Flee>25</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityGhast>
                <net.minecraft.entity.monster.EntityGiantZombie>
                        <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>
                </net.minecraft.entity.monster.EntityGiantZombie>
                <net.minecraft.entity.monster.EntityGuardian>
                        <AttackPower Probability="55">6</AttackPower>
                        <Evasion>25</Evasion>
                        <Category>monster</Category>
                        <Speed>50</Speed>
+                       <Decision>
+                               <Attack>80</Attack>
+                               <Defend>20</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityGuardian>
                <net.minecraft.entity.monster.EntityHusk>
                        <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>
                </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>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityIronGolem>
                <net.minecraft.entity.monster.EntityMagmaCube>
                        <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>
                </net.minecraft.entity.monster.EntityMagmaCube>
                <net.minecraft.entity.monster.EntityPigZombie>
                        <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>
                </net.minecraft.entity.monster.EntityPigZombie>
                <net.minecraft.entity.monster.EntityPolarBear>
                        <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>
                </net.minecraft.entity.monster.EntityPolarBear>
                <net.minecraft.entity.monster.EntityShulker>
                        <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>
                </net.minecraft.entity.monster.EntityShulker>
                <net.minecraft.entity.monster.EntitySilverFish>
                        <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>
                </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>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntitySkeleton>
                <net.minecraft.entity.monster.EntitySlime>
                        <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>
                </net.minecraft.entity.monster.EntitySlime>
                <net.minecraft.entity.monster.EntitySnowman>
                        <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>
                </net.minecraft.entity.monster.EntitySnowman>
                <net.minecraft.entity.monster.EntitySpider>
                        <AttackPower Probability="70">2</AttackPower>
                        </Conflicts>
                        <Category>monster</Category>
                        <Speed>70</Speed>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntitySpider>
                <net.minecraft.entity.monster.EntityStray>
                        <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>
                </net.minecraft.entity.monster.EntityStray>
                <net.minecraft.entity.monster.EntityVex>
                        <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>
                </net.minecraft.entity.monster.EntityVex>
                <net.minecraft.entity.monster.EntityVindicator>
                        <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>
                </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>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityWitch>
                <net.minecraft.entity.monster.EntityWitherSkeleton>
                        <AttackPower Probability="70">8</AttackPower>
                        <Evasion>7</Evasion>
                        <Category>monster</Category>
                        <Speed>65</Speed>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.monster.EntityWitherSkeleton>
                <net.minecraft.entity.monster.EntityZombie>
                        <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>
                </net.minecraft.entity.monster.EntityZombie>
                <net.minecraft.entity.monster.EntityZombieVillager>
                        <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>
                </net.minecraft.entity.monster.EntityZombieVillager>
                <net.minecraft.entity.passive.EntityBat>
                        <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>
                </net.minecraft.entity.passive.EntityBat>
                <net.minecraft.entity.passive.EntityChicken>
                        <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>
                </net.minecraft.entity.passive.EntityChicken>
                <net.minecraft.entity.passive.EntityCow>
                        <AttackPower Probability="50">0</AttackPower>
                        </Conflicts>
                        <Category>passive</Category>
                        <Speed>20</Speed>
+                       <Decision>
+                               <Attack>0</Attack>
+                               <Defend>10</Defend>
+                               <Flee>80</Flee>
+                       </Decision>
                </net.minecraft.entity.passive.EntityCow>
                <net.minecraft.entity.passive.EntityDonkey>
                        <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>
                </net.minecraft.entity.passive.EntityDonkey>
                <net.minecraft.entity.passive.EntityHorse>
                        <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>
                </net.minecraft.entity.passive.EntityHorse>
                <net.minecraft.entity.passive.EntityLlama>
                        <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>
                </net.minecraft.entity.passive.EntityLlama>
                <net.minecraft.entity.passive.EntityMooshroom>
                        <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>
                </net.minecraft.entity.passive.EntityMooshroom>
                <net.minecraft.entity.passive.EntityMule>
                        <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>
                </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>
+                       <Decision>
+                               <Attack>0</Attack>
+                               <Defend>0</Defend>
+                               <Flee>90</Flee>
+                       </Decision>
                </net.minecraft.entity.passive.EntityOcelot>
                <net.minecraft.entity.passive.EntityParrot>
                        <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>
                </net.minecraft.entity.passive.EntityParrot>
                <net.minecraft.entity.passive.EntityPig>
                        <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>
                </net.minecraft.entity.passive.EntityPig>
                <net.minecraft.entity.passive.EntityRabbit>
                        <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>
                </net.minecraft.entity.passive.EntityRabbit>
                <net.minecraft.entity.passive.EntitySheep>
                        <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>
                </net.minecraft.entity.passive.EntitySheep>
                <net.minecraft.entity.passive.EntitySkeletonHorse>
                        <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>
                </net.minecraft.entity.passive.EntitySkeletonHorse>
                <net.minecraft.entity.passive.EntitySquid>
                        <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>
                </net.minecraft.entity.passive.EntitySquid>
                <net.minecraft.entity.passive.EntityVillager>
                        <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>
                </net.minecraft.entity.passive.EntityVillager>
                <net.minecraft.entity.passive.EntityWolf>
                        <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>
                </net.minecraft.entity.passive.EntityWolf>
                <net.minecraft.entity.passive.EntityZombieHorse>
                        <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>
                </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>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.boss.EntityDragon>
                <net.minecraft.entity.boss.EntityWither>
                        <AttackPower Probability="70">8</AttackPower>
                        <AttackEffect Probability="90">wither</AttackEffect>
                        <Category>boss</Category>
                        <Speed>68</Speed>
+                       <Decision>
+                               <Attack>100</Attack>
+                               <Defend>0</Defend>
+                               <Flee>0</Flee>
+                       </Decision>
                </net.minecraft.entity.boss.EntityWither>
        </EntityStats>
 </TurnBasedMinecraftConfig>
\ No newline at end of file