diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackEventHandler.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackEventHandler.java index 485e8ee..01ac49e 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackEventHandler.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackEventHandler.java @@ -1,10 +1,60 @@ package com.seodisparate.TurnBasedMinecraft.common; +import java.util.ArrayDeque; +import java.util.Queue; + +import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleMessage; + import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class AttackEventHandler { + private boolean isAttackerValid(LivingAttackEvent event) + { + if(event.getSource().getTrueSource() == null) + { + return false; + } + else if(event.getSource().getTrueSource().equals(TurnBasedMinecraftMod.attackingEntity)) + { + return true; + } + else + { + Queue removeQueue = new ArrayDeque(); + final long now = System.nanoTime(); + boolean isValid = false; + synchronized(TurnBasedMinecraftMod.attackerViaBow) + { + for(AttackerViaBow attacker : TurnBasedMinecraftMod.attackerViaBow) + { + if(now - attacker.attackTime >= AttackerViaBow.ATTACK_TIMEOUT) + { + removeQueue.add(attacker); + } + else if(event.getSource().getTrueSource().equals(attacker.entity) && event.getSource().isProjectile()) + { + removeQueue.add(attacker); + isValid = true; + Battle b = TurnBasedMinecraftMod.battleManager.getBattleByID(attacker.battleID); + if(b != null) + { + b.sendMessageToAllPlayers(PacketBattleMessage.MessageType.ARROW_HIT, attacker.entity.getEntityId(), event.getEntity().getEntityId(), 0); + } + } + } + AttackerViaBow next = removeQueue.poll(); + while(next != null) + { + TurnBasedMinecraftMod.attackerViaBow.remove(next); + next = removeQueue.poll(); + } + } + return isValid; + } + } + @SubscribeEvent public void entityAttacked(LivingAttackEvent event) { @@ -17,7 +67,7 @@ public class AttackEventHandler TurnBasedMinecraftMod.battleManager = new BattleManager(TurnBasedMinecraftMod.logger); } - if(!(event.getSource().getTrueSource() == null || event.getSource().getTrueSource().equals(TurnBasedMinecraftMod.attackingEntity)) && TurnBasedMinecraftMod.battleManager.checkAttack(event)) + if(!isAttackerValid(event) && event.getEntity() != null && event.getSource().getTrueSource() != null && TurnBasedMinecraftMod.battleManager.checkAttack(event)) { // TurnBasedMinecraftMod.logger.debug("Canceled LivingAttackEvent between " + TurnBasedMinecraftMod.attackingEntity + " and " + event.getEntity()); event.setCanceled(true); diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackerViaBow.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackerViaBow.java new file mode 100644 index 0000000..7cdaca7 --- /dev/null +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/AttackerViaBow.java @@ -0,0 +1,26 @@ +package com.seodisparate.TurnBasedMinecraft.common; + +import net.minecraft.entity.Entity; + +public class AttackerViaBow +{ + public static long ATTACK_TIMEOUT = 10000000000L; + + public Entity entity; + public long attackTime; + public int battleID; + + public AttackerViaBow() + { + entity = null; + attackTime = 0; + battleID = -1; + } + + public AttackerViaBow(Entity entity, int battleID) + { + this.entity = entity; + attackTime = System.nanoTime(); + this.battleID = battleID; + } +} diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Battle.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Battle.java index 5ae47bc..ee2e2b4 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Battle.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Battle.java @@ -20,6 +20,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Items; import net.minecraft.item.Item; +import net.minecraft.item.ItemBow; import net.minecraft.item.ItemFood; import net.minecraft.item.ItemLingeringPotion; import net.minecraft.item.ItemPotion; @@ -135,6 +136,7 @@ public class Battle } Combatant newCombatant = new Combatant(e, entityInfo); newCombatant.isSideA = true; + newCombatant.battleID = getId(); this.sideA.put(e.getEntityId(), newCombatant); if(e instanceof EntityPlayer) { @@ -155,6 +157,7 @@ public class Battle } Combatant newCombatant = new Combatant(e, entityInfo); newCombatant.isSideA = false; + newCombatant.battleID = getId(); this.sideB.put(e.getEntityId(), newCombatant); if(e instanceof EntityPlayer) { @@ -236,6 +239,7 @@ public class Battle } Combatant newCombatant = new Combatant(e, entityInfo); newCombatant.isSideA = true; + newCombatant.battleID = getId(); sideA.put(e.getEntityId(), newCombatant); if(e instanceof EntityPlayer) { @@ -267,6 +271,7 @@ public class Battle } Combatant newCombatant = new Combatant(e, entityInfo); newCombatant.isSideA = false; + newCombatant.battleID = getId(); sideB.put(e.getEntityId(), newCombatant); if(e instanceof EntityPlayer) { @@ -404,7 +409,7 @@ public class Battle } } - private void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount) + protected void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount) { if(!isServer) { @@ -419,7 +424,7 @@ public class Battle } } - private void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount, String custom) + protected void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount, String custom) { if(!isServer) { @@ -631,6 +636,32 @@ public class Battle { break; } + ItemStack heldItemStack = ((EntityPlayer)next.entity).getHeldItemMainhand(); + if(heldItemStack.getItem() instanceof ItemBow) + { + if(Utility.doesPlayerHaveArrows((EntityPlayer)next.entity)) + { + final Entity nextEntity = next.entity; + final Entity targetEntity = target.entity; + next.entity.getServer().addScheduledTask(() -> { + // have player look at attack target + ((EntityPlayerMP)nextEntity).connection.setPlayerLocation(nextEntity.posX, nextEntity.posY, nextEntity.posZ, Utility.yawDirection(nextEntity.posX, nextEntity.posZ, targetEntity.posX, targetEntity.posZ), Utility.pitchDirection(nextEntity.posX, nextEntity.posY, nextEntity.posZ, targetEntity.posX, targetEntity.posY, targetEntity.posZ)); + ItemBow itemBow = (ItemBow)heldItemStack.getItem(); + synchronized(TurnBasedMinecraftMod.attackerViaBow) + { + TurnBasedMinecraftMod.attackerViaBow.add(new AttackerViaBow(nextEntity, getId())); + } + itemBow.onPlayerStoppedUsing(((EntityPlayer)nextEntity).getHeldItemMainhand(), nextEntity.getEntityWorld(), (EntityLivingBase)nextEntity, (int)(Math.random() * (itemBow.getMaxItemUseDuration(heldItemStack)) / 3)); + sendMessageToAllPlayers(PacketBattleMessage.MessageType.FIRED_ARROW, nextEntity.getEntityId(), targetEntity.getEntityId(), 0); + }); + } + else + { + sendMessageToAllPlayers(PacketBattleMessage.MessageType.BOW_NO_AMMO, next.entity.getEntityId(), 0, 0); + } + next = turnOrderQueue.poll(); + continue; + } int hitChance = TurnBasedMinecraftMod.config.getPlayerAttackProbability(); if(target.entity instanceof EntityPlayer) { @@ -649,12 +680,11 @@ public class Battle if(target.remainingDefenses <= 0) { // attack - // TODO damage via bow and arrow - // have player look at attack target final Entity nextEntity = next.entity; final Entity targetEntity = target.entity; final EntityInfo targetEntityInfo = target.entityInfo; next.entity.getServer().addScheduledTask(() -> { + // have player look at attack target ((EntityPlayerMP)nextEntity).connection.setPlayerLocation(nextEntity.posX, nextEntity.posY, nextEntity.posZ, Utility.yawDirection(nextEntity.posX, nextEntity.posZ, targetEntity.posX, targetEntity.posZ), Utility.pitchDirection(nextEntity.posX, nextEntity.posY, nextEntity.posZ, targetEntity.posX, targetEntity.posY, targetEntity.posZ)); TurnBasedMinecraftMod.attackingEntity = nextEntity; TurnBasedMinecraftMod.attackingDamage = 0; diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Combatant.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Combatant.java index 6490e26..80f2c1f 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Combatant.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Combatant.java @@ -18,6 +18,7 @@ public class Combatant public int targetEntityID; public boolean isSideA; public int remainingDefenses; + public int battleID; public Combatant() { diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java index 62d9086..7efc7f2 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java @@ -1,8 +1,5 @@ package com.seodisparate.TurnBasedMinecraft.common; -import java.util.ArrayList; -import java.util.List; - import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.MobEffects; import net.minecraft.potion.PotionEffect; diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/TurnBasedMinecraftMod.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/TurnBasedMinecraftMod.java index 8d3d2a3..966602f 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/TurnBasedMinecraftMod.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/TurnBasedMinecraftMod.java @@ -1,6 +1,8 @@ package com.seodisparate.TurnBasedMinecraft.common; import java.time.Duration; +import java.util.HashSet; +import java.util.Set; import org.apache.logging.log4j.Logger; @@ -45,6 +47,7 @@ public class TurnBasedMinecraftMod private static int packetHandlerID = 0; protected static Entity attackingEntity; protected static int attackingDamage = 0; + protected static Set attackerViaBow; protected static Config config; public static Battle currentBattle = null; @@ -64,6 +67,7 @@ public class TurnBasedMinecraftMod { currentBattle = null; battleManager = null; + attackerViaBow = new HashSet(); commonProxy.setLogger(logger); // register packets diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Utility.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Utility.java index 9fc88c7..73a66d9 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Utility.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Utility.java @@ -1,5 +1,8 @@ package com.seodisparate.TurnBasedMinecraft.common; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemArrow; + public class Utility { public static float yawDirection(double posX, double posZ, double targetX, double targetZ) @@ -28,4 +31,16 @@ public class Utility return (float)(-Math.atan(diffY / distance) * 180.0 / Math.PI); } } + + public static boolean doesPlayerHaveArrows(EntityPlayer player) + { + for(int i = 0; i < player.inventory.getSizeInventory(); ++i) + { + if(player.inventory.getStackInSlot(i).getItem() instanceof ItemArrow) + { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java index 2de9f30..a88b7b4 100644 --- a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java +++ b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/networking/PacketBattleMessage.java @@ -34,7 +34,10 @@ public class PacketBattleMessage implements IMessage TURN_END(12), SWITCHED_ITEM(13), WAS_AFFECTED(14), - BECAME_CREATIVE(15); + BECAME_CREATIVE(15), + FIRED_ARROW(16), + ARROW_HIT(17), + BOW_NO_AMMO(18); private int value; private static Map map = new HashMap(); @@ -326,6 +329,15 @@ public class PacketBattleMessage implements IMessage case BECAME_CREATIVE: TurnBasedMinecraftMod.commonProxy.displayString(from + " entered creative mode and left battle!"); break; + case FIRED_ARROW: + TurnBasedMinecraftMod.commonProxy.displayString(from + " let loose an arrow towards " + to + "!"); + break; + case ARROW_HIT: + TurnBasedMinecraftMod.commonProxy.displayString(to + " was hit by " + from + "'s arrow!"); + break; + case BOW_NO_AMMO: + TurnBasedMinecraftMod.commonProxy.displayString(from + " tried to use their bow but ran out of ammo!"); + break; } return null; }