WIP more work on setup and Battle logic

This commit is contained in:
Stephen Seo 2018-09-04 15:21:49 +09:00
parent 26c3356147
commit c8ce401e4d
8 changed files with 368 additions and 55 deletions

View 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;

View 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

View 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;

View file

@ -1,31 +1,126 @@
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;
}
}
}
}

View 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;
}
}

View 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;
}

View 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;
}

View file

@ -1,116 +1,152 @@
<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>
@ -119,33 +155,39 @@
<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>
@ -155,21 +197,25 @@
</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>
@ -178,92 +224,110 @@
<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>