WIP more backend work on battle logic

This commit is contained in:
Stephen Seo 2018-09-06 17:08:36 +09:00
parent 2aec173e80
commit 0520e163f8
10 changed files with 716 additions and 129 deletions

View 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()

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

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

View 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 */ }
}

View 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))
{

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

View file

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

View file

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

View file

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

View file

@ -28,12 +28,18 @@
<!-- 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>
@ -41,6 +47,11 @@
<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>
@ -48,6 +59,11 @@
<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>
@ -55,24 +71,44 @@
<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>
@ -80,12 +116,22 @@
<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>
@ -93,6 +139,11 @@
<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>
@ -100,60 +151,110 @@
<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>
@ -163,6 +264,11 @@
</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>
@ -170,24 +276,44 @@
<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>
@ -195,6 +321,11 @@
<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>
@ -205,24 +336,44 @@
<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>
@ -232,102 +383,187 @@
</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>
@ -335,6 +571,11 @@
<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>