From eef65c4399d8bc0c1d7b498f2f7547eb203cdc34 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Mon, 7 Feb 2022 20:35:58 +0200 Subject: [PATCH 01/25] big minigames update added 2 new packets for changing class without rechanging team --- .../network/PacketGetPlayerClasses.java | 55 ++++++++ .../common/network/PacketHandler.java | 3 + .../network/PacketSendPlayerClasses.java | 120 +++++++++--------- 3 files changed, 118 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java diff --git a/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java b/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java new file mode 100644 index 00000000..acb5f7dd --- /dev/null +++ b/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java @@ -0,0 +1,55 @@ +package com.flansmod.common.network; + +import com.flansmod.common.FlansMod; +import com.flansmod.common.PlayerData; +import com.flansmod.common.PlayerHandler; +import com.flansmod.common.guns.ItemGun; +import com.flansmod.common.guns.ShootableType; +import com.flansmod.common.teams.PlayerClass; +import com.flansmod.common.teams.PlayerInfo; +import com.flansmod.common.teams.TeamsManager; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; + +public class PacketGetPlayerClasses extends PacketBase { + +// @SuppressWarnings("unused") + public PacketGetPlayerClasses() { + } + + + @Override + public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { + + } + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { + + } + + @Override + public void handleServerSide(EntityPlayerMP playerEntity) { + System.out.println("recievedGPC"); + if(TeamsManager.instance.currentRound!=null&&TeamsManager.instance.currentRound.teams!=null){ + PlayerData data = PlayerHandler.getPlayerData(playerEntity); + if(data!=null&data.team!=null){ + FlansMod.getPacketHandler().sendTo(new PacketSendPlayerClasses(data.team.classes.toArray(new PlayerClass[data.team.classes.size()])),playerEntity); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void handleClientSide(EntityPlayer clientPlayer) { + FlansMod.log("Received set preferred ammo packet on client. Skipping."); + } +} + diff --git a/src/main/java/com/flansmod/common/network/PacketHandler.java b/src/main/java/com/flansmod/common/network/PacketHandler.java index 799e54fd..9a20a4d1 100644 --- a/src/main/java/com/flansmod/common/network/PacketHandler.java +++ b/src/main/java/com/flansmod/common/network/PacketHandler.java @@ -169,6 +169,9 @@ public void initialise() { registerPacket(PacketMuzzleFlash.class); registerPacket(PacketHitMarker.class); registerPacket(PacketSetPreferredAmmo.class); + registerPacket(PacketGetPlayerClasses.class); + registerPacket(PacketSendPlayerClasses.class); + } /** diff --git a/src/main/java/com/flansmod/common/network/PacketSendPlayerClasses.java b/src/main/java/com/flansmod/common/network/PacketSendPlayerClasses.java index a9ca562f..76815ed3 100644 --- a/src/main/java/com/flansmod/common/network/PacketSendPlayerClasses.java +++ b/src/main/java/com/flansmod/common/network/PacketSendPlayerClasses.java @@ -1,60 +1,60 @@ -package com.flansmod.common.network; - -import com.flansmod.client.gui.GuiTeamSelect; -import com.flansmod.common.FlansMod; -import com.flansmod.common.PlayerData; -import com.flansmod.common.PlayerHandler; -import com.flansmod.common.driveables.mechas.MechaInventory; -import com.flansmod.common.teams.PlayerClass; -import com.flansmod.common.teams.TeamsManager; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import net.minecraft.client.Minecraft; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import scala.collection.parallel.ParIterableLike; - -public class PacketSendPlayerClasses extends PacketBase { - public PlayerClass[] classes; - - @SuppressWarnings("unused") - public PacketSendPlayerClasses() { - } - - public PacketSendPlayerClasses(PlayerClass[] classes) { - this.classes = classes; - } - - @Override - public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { - - data.writeByte(classes.length); - for (PlayerClass playerClass : classes) { - writeUTF(data, playerClass.shortName); - } - } - - @Override - public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { - byte numClasses = data.readByte(); - classes = new PlayerClass[numClasses]; - for(int i = 0; i < numClasses; i++) - { - classes[i] = PlayerClass.getClass(readUTF(data)); - } - } - - @Override - public void handleServerSide(EntityPlayerMP playerEntity) { - - } - - @Override - @SideOnly(Side.CLIENT) - public void handleClientSide(EntityPlayer clientPlayer) { - Minecraft.getMinecraft().displayGuiScreen(new GuiTeamSelect(classes)); - } -} - +package com.flansmod.common.network; + +import com.flansmod.client.gui.GuiTeamSelect; +import com.flansmod.common.FlansMod; +import com.flansmod.common.PlayerData; +import com.flansmod.common.PlayerHandler; +import com.flansmod.common.driveables.mechas.MechaInventory; +import com.flansmod.common.teams.PlayerClass; +import com.flansmod.common.teams.TeamsManager; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import scala.collection.parallel.ParIterableLike; + +public class PacketSendPlayerClasses extends PacketBase { + public PlayerClass[] classes; + + @SuppressWarnings("unused") + public PacketSendPlayerClasses() { + } + + public PacketSendPlayerClasses(PlayerClass[] classes) { + this.classes = classes; + } + + @Override + public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) { + + data.writeByte(classes.length); + for (PlayerClass playerClass : classes) { + writeUTF(data, playerClass.shortName); + } + } + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { + byte numClasses = data.readByte(); + classes = new PlayerClass[numClasses]; + for(int i = 0; i < numClasses; i++) + { + classes[i] = PlayerClass.getClass(readUTF(data)); + } + } + + @Override + public void handleServerSide(EntityPlayerMP playerEntity) { + + } + + @Override + @SideOnly(Side.CLIENT) + public void handleClientSide(EntityPlayer clientPlayer) { + Minecraft.getMinecraft().displayGuiScreen(new GuiTeamSelect(classes)); + } +} + From 18d09dd79ace7d08b39b42fcc33485e0f926e6ab Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Mon, 7 Feb 2022 20:40:21 +0200 Subject: [PATCH 02/25] big minigames update handling destroy vehicles for global player stats --- .../flansmod/common/driveables/EntityDriveable.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index b3874f06..aa56a774 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -449,6 +449,12 @@ public boolean isMountedEntity(Entity entity) { @Override public void setDead() { + + TeamsManager teamsManager = TeamsManager.instance; + if(teamsManager.currentRound!=null){ + + } + super.setDead(); //Unregister to Radar @@ -2386,6 +2392,10 @@ public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingP if (!worldObj.isRemote) { checkParts(); //If it hit, send a damage update packet + if(part.type.equals(EnumDriveablePart.core) && part.dead){ + if(TeamsManager.instance.currentRound!=null) + TeamsManager.instance.currentRound.gametype.vehicleDestroyed(part.owner, bullet); + } FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); } From b7979aff1948ca5fb043368f7a33e438cb0df6be Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Mon, 7 Feb 2022 20:42:34 +0200 Subject: [PATCH 03/25] big minigames update added keyBind(default key "O") renamed old keyBinds --- .../java/com/flansmod/client/KeyInputHandler.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/flansmod/client/KeyInputHandler.java b/src/main/java/com/flansmod/client/KeyInputHandler.java index 38ed90e2..4b72c830 100644 --- a/src/main/java/com/flansmod/client/KeyInputHandler.java +++ b/src/main/java/com/flansmod/client/KeyInputHandler.java @@ -1,6 +1,7 @@ package com.flansmod.client; import com.flansmod.client.gui.GuiSelectAmmo; +import com.flansmod.common.network.PacketGetPlayerClasses; import org.lwjgl.input.Keyboard; import com.flansmod.api.IControllable; @@ -40,8 +41,9 @@ public class KeyInputHandler { public static KeyBinding reloadKey = new KeyBinding("Reload key", Keyboard.KEY_R, "Flan's Mod"); public static KeyBinding selectPreferredAmmo = new KeyBinding("Select Preferred Ammo key", Keyboard.KEY_P, "Flan's Mod"); public static KeyBinding gunModeKey = new KeyBinding("Gun Mode key", Keyboard.KEY_F, "Flan's Mod"); - public static KeyBinding teamsMenuKey = new KeyBinding("Teams Menu Key", Keyboard.KEY_G, "Flan's Mod"); - public static KeyBinding teamsScoresKey = new KeyBinding("Teams Scores Key", Keyboard.KEY_H, "Flan's Mod"); + public static KeyBinding teamsMenuKey = new KeyBinding("Minigames Select Team Key", Keyboard.KEY_G, "Flan's Mod"); + public static KeyBinding teamsScoresKey = new KeyBinding("Minigames Scores Key", Keyboard.KEY_H, "Flan's Mod"); + public static KeyBinding teamsSelectClassKey = new KeyBinding("Minigames Select Class Key", Keyboard.KEY_O, "Flan's Mod"); public static KeyBinding leftRollKey = new KeyBinding("Roll Left Key", Keyboard.KEY_Z, "Flan's Mod"); public static KeyBinding rightRollKey = new KeyBinding("Roll Right Key", Keyboard.KEY_X, "Flan's Mod"); public static KeyBinding gearKey = new KeyBinding("Gear Up / Down Key", Keyboard.KEY_L, "Flan's Mod"); @@ -74,6 +76,7 @@ public KeyInputHandler() { ClientRegistry.registerKeyBinding(gunModeKey); ClientRegistry.registerKeyBinding(teamsMenuKey); ClientRegistry.registerKeyBinding(teamsScoresKey); + ClientRegistry.registerKeyBinding(teamsSelectClassKey); ClientRegistry.registerKeyBinding(leftRollKey); ClientRegistry.registerKeyBinding(rightRollKey); ClientRegistry.registerKeyBinding(gearKey); @@ -107,6 +110,10 @@ public void onKeyInput(KeyInputEvent event) { mc.displayGuiScreen(new GuiTeamScores()); return; } + if(teamsSelectClassKey.isPressed()){ + FlansMod.getPacketHandler().sendToServer(new PacketGetPlayerClasses()); + return; + } if (reloadKey.isPressed() && FlansModClient.shootTime(false) <= 0) { FlansMod.getPacketHandler().sendToServer(new PacketReload(false)); return; From 6ffdb61d3080f4e0deba947bbe165169e36e37f8 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 11:03:43 +0200 Subject: [PATCH 04/25] big minigames update. part 1 --- .../com/flansmod/common/PlayerHandler.java | 30 ++++---- .../common/driveables/EntityDriveable.java | 7 -- .../network/PacketGetPlayerClasses.java | 7 -- .../com/flansmod/common/teams/GameType.java | 15 ++-- .../flansmod/common/teams/GameTypeCTF.java | 19 ++--- .../com/flansmod/common/teams/GameTypeDM.java | 12 +-- .../flansmod/common/teams/GameTypeTDM.java | 14 ++-- .../{PlayerInfo.java => PlayerStats.java} | 75 +++++-------------- .../flansmod/common/teams/TeamsManager.java | 1 - 9 files changed, 62 insertions(+), 118 deletions(-) rename src/main/java/com/flansmod/common/teams/{PlayerInfo.java => PlayerStats.java} (69%) diff --git a/src/main/java/com/flansmod/common/PlayerHandler.java b/src/main/java/com/flansmod/common/PlayerHandler.java index ccecb294..14e5e4d9 100644 --- a/src/main/java/com/flansmod/common/PlayerHandler.java +++ b/src/main/java/com/flansmod/common/PlayerHandler.java @@ -7,7 +7,7 @@ import com.flansmod.common.guns.EntityGrenade; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.network.PacketRequestDebug; -import com.flansmod.common.teams.PlayerInfo; +import com.flansmod.common.teams.PlayerStats; import com.flansmod.common.teams.TeamsManager; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.eventhandler.SubscribeEvent; @@ -38,8 +38,8 @@ public class PlayerHandler { private static final Random rand = new Random(); public static Map serverSideData = new HashMap(); public static Map clientSideData = new HashMap(); - public static Map serverSideInfo = new HashMap(); - public static Map clientSideInfo = new HashMap(); + public static Map serverSidePlayerStats = new HashMap(); + public static Map clientSidePlayerStats = new HashMap(); public static ArrayList clientsToRemoveAfterThisRound = new ArrayList(); public PlayerHandler() { @@ -144,22 +144,22 @@ public static PlayerData getPlayerData(String username, Side side) { //--- - public static PlayerInfo getPlayerInfo(EntityPlayerMP player) { + public static PlayerStats getPlayerStats(EntityPlayerMP player) { if (player == null) return null; - return getPlayerInfo(player, player.worldObj.isRemote ? Side.CLIENT : Side.SERVER); + return getPlayerStats(player, player.worldObj.isRemote ? Side.CLIENT : Side.SERVER); } - public static PlayerInfo getPlayerInfo(EntityPlayerMP player, Side side) { + public static PlayerStats getPlayerStats(EntityPlayerMP player, Side side) { String username = player.getCommandSenderName(); if (side.isClient()) { - if (!clientSideInfo.containsKey(username)) - clientSideInfo.put(username, new PlayerInfo(player.worldObj, player)); + if (!clientSidePlayerStats.containsKey(username)) + clientSidePlayerStats.put(username, new PlayerStats(player.worldObj, player)); } else { - if (!serverSideInfo.containsKey(username)) - serverSideInfo.put(username, new PlayerInfo(player.worldObj, player)); + if (!serverSidePlayerStats.containsKey(username)) + serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, player)); } - return side.isClient() ? clientSideInfo.get(username) : serverSideInfo.get(username); + return side.isClient() ? clientSidePlayerStats.get(username) : serverSidePlayerStats.get(username); } @SubscribeEvent @@ -174,8 +174,8 @@ public void onPlayerEvent(PlayerEvent event) { if (!serverSideData.containsKey(username)) serverSideData.put(username, new PlayerData(username)); clientsToRemoveAfterThisRound.remove(username); - if (!serverSideInfo.containsKey(username)) - serverSideInfo.put(username, new PlayerInfo(player.worldObj, (EntityPlayerMP)player)); + if (!serverSidePlayerStats.containsKey(username)) + serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, (EntityPlayerMP)player)); } else if (event instanceof PlayerLoggedOutEvent) { EntityPlayer player = event.player; @@ -188,8 +188,8 @@ public void onPlayerEvent(PlayerEvent event) { String username = player.getCommandSenderName(); if (!serverSideData.containsKey(username)) serverSideData.put(username, new PlayerData(username)); - if (!serverSideInfo.containsKey(username)) - serverSideInfo.put(username, new PlayerInfo(player.worldObj, (EntityPlayerMP)player)); + if (!serverSidePlayerStats.containsKey(username)) + serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, (EntityPlayerMP)player)); } } diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index aa56a774..28976ef3 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -449,14 +449,7 @@ public boolean isMountedEntity(Entity entity) { @Override public void setDead() { - - TeamsManager teamsManager = TeamsManager.instance; - if(teamsManager.currentRound!=null){ - - } - super.setDead(); - //Unregister to Radar //RadarRegistry.unregister(this); if (worldObj.isRemote) diff --git a/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java b/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java index acb5f7dd..38efb433 100644 --- a/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java +++ b/src/main/java/com/flansmod/common/network/PacketGetPlayerClasses.java @@ -3,10 +3,7 @@ import com.flansmod.common.FlansMod; import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; -import com.flansmod.common.guns.ItemGun; -import com.flansmod.common.guns.ShootableType; import com.flansmod.common.teams.PlayerClass; -import com.flansmod.common.teams.PlayerInfo; import com.flansmod.common.teams.TeamsManager; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -14,9 +11,6 @@ import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.EnumChatFormatting; public class PacketGetPlayerClasses extends PacketBase { @@ -37,7 +31,6 @@ public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) { @Override public void handleServerSide(EntityPlayerMP playerEntity) { - System.out.println("recievedGPC"); if(TeamsManager.instance.currentRound!=null&&TeamsManager.instance.currentRound.teams!=null){ PlayerData data = PlayerHandler.getPlayerData(playerEntity); if(data!=null&data.team!=null){ diff --git a/src/main/java/com/flansmod/common/teams/GameType.java b/src/main/java/com/flansmod/common/teams/GameType.java index 058e8b1a..efdd94c3 100644 --- a/src/main/java/com/flansmod/common/teams/GameType.java +++ b/src/main/java/com/flansmod/common/teams/GameType.java @@ -143,26 +143,25 @@ public void vehicleDestroyed(EntityDriveable driveable2, EntityBullet bullet){ // if(driveable.riddenByEntity!=null && // driveable.riddenByEntity instanceof EntityPlayer && // !getPlayerData((EntityPlayerMP) driveable.riddenByEntity).team.equals(getPlayerData(attacker).team)) { - if(true){ + if(true){ //this if() need for next changes getPlayerInfo(attacker).vehiclesDestroyed++; - FlansMod.log("Minigames: "+driveable.getDriveableType().name + " destroyed by "+attacker+" with using "+bullet.firedFrom.name); if (driveable instanceof EntityPlane) { EntityPlane plane = (EntityPlane) driveable; if (plane.mode == EnumPlaneMode.PLANE || plane.mode == EnumPlaneMode.VTOL) { getPlayerInfo(attacker).addExp(100); - getPlayerInfo(attacker).savePlayerInfoData(); + getPlayerInfo(attacker).savePlayerStats(); } else if (plane.mode == EnumPlaneMode.HELI) { getPlayerInfo(attacker).addExp(75); - getPlayerInfo(attacker).savePlayerInfoData(); + getPlayerInfo(attacker).savePlayerStats(); } } else if (driveable instanceof EntityVehicle) { EntityVehicle vehicle = (EntityVehicle) driveable; if (vehicle.getVehicleType().tank) { getPlayerInfo(attacker).addExp(75); - getPlayerInfo(attacker).savePlayerInfoData(); + getPlayerInfo(attacker).savePlayerStats(); } else { getPlayerInfo(attacker).addExp(50); - getPlayerInfo(attacker).savePlayerInfoData(); + getPlayerInfo(attacker).savePlayerStats(); } } } @@ -192,8 +191,8 @@ public static PlayerData getPlayerData(EntityPlayerMP player) { return PlayerHandler.getPlayerData(player); } - public static PlayerInfo getPlayerInfo(EntityPlayerMP player) { - return PlayerHandler.getPlayerInfo(player); + public static PlayerStats getPlayerInfo(EntityPlayerMP player) { + return PlayerHandler.getPlayerStats(player); } public static void sendPacketToPlayer(PacketBase packet, EntityPlayerMP player) { diff --git a/src/main/java/com/flansmod/common/teams/GameTypeCTF.java b/src/main/java/com/flansmod/common/teams/GameTypeCTF.java index 352dd607..5f1ac274 100644 --- a/src/main/java/com/flansmod/common/teams/GameTypeCTF.java +++ b/src/main/java/com/flansmod/common/teams/GameTypeCTF.java @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; -import com.flansmod.common.PlayerHandler; -import ibxm.Player; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; @@ -17,7 +15,6 @@ public class GameTypeCTF extends GameType public boolean friendlyFire = false; public boolean autoBalance = true; public int time; - public int autoBalanceInterval = 1200; public int flagReturnTime = 60; public GameTypeCTF() @@ -43,12 +40,12 @@ public void roundEnd() for(String name : teamA.members){ getPlayerInfo(getPlayer(name)).playedRounds++; getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerInfoData(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); } for(String name : teamB.members){ getPlayerInfo(getPlayer(name)).playedRounds++; getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerInfoData(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); } for(String name : teamA.members){ PlayerData data = getPlayerData(getPlayer(name)); @@ -71,8 +68,8 @@ public void roundEnd() getPlayerInfo(bestPlayerB).addExp(250); getPlayerInfo(bestPlayerA).MVPCount++; getPlayerInfo(bestPlayerB).MVPCount++; - getPlayerInfo(bestPlayerA).savePlayerInfoData(); - getPlayerInfo(bestPlayerB).savePlayerInfoData(); + getPlayerInfo(bestPlayerA).savePlayerStats(); + getPlayerInfo(bestPlayerB).savePlayerStats(); } } @@ -178,7 +175,7 @@ public void playerKilled(EntityPlayerMP player, DamageSource source) if(player.riddenByEntity instanceof EntityFlag){ getPlayerInfo(attacker).addExp(10); } - getPlayerInfo(attacker).savePlayerInfoData(); + getPlayerInfo(attacker).savePlayerStats(); } } else @@ -187,7 +184,7 @@ public void playerKilled(EntityPlayerMP player, DamageSource source) } getPlayerData(player).deaths++; getPlayerInfo(player).deaths++; - getPlayerInfo(player).savePlayerInfoData(); + getPlayerInfo(player).savePlayerStats(); if(player.riddenByEntity instanceof EntityFlag) { Team flagTeam = teamsManager.getTeam(((EntityFlag)player.riddenByEntity).getBase().getOwnerID()); @@ -244,7 +241,7 @@ public void objectClickedByPlayer(ITeamObject object, EntityPlayerMP player) playerData.score += 2; getPlayerInfo(player).savedFlags++; getPlayerInfo(player).addExp(10); - getPlayerInfo(player).savePlayerInfoData(); + getPlayerInfo(player).savePlayerStats(); TeamsManager.messageAll("\u00a7f" + player.getCommandSenderName() + " returned the \u00a7" + flagTeam.textColour + flagTeam.name + "\u00a7f flag"); } @@ -261,7 +258,7 @@ else if(player.riddenByEntity instanceof EntityFlag) playerTeam.score++; playerData.score += 10; getPlayerInfo(player).capturedFlags++; - getPlayerInfo(player).savePlayerInfoData(); + getPlayerInfo(player).savePlayerStats(); getPlayerInfo(player).addExp(20); otherFlag.reset(); TeamsManager.messageAll("\u00a7f" + player.getCommandSenderName() + " captured the \u00a7" + otherFlagTeam.textColour + otherFlagTeam.name + "\u00a7f flag"); diff --git a/src/main/java/com/flansmod/common/teams/GameTypeDM.java b/src/main/java/com/flansmod/common/teams/GameTypeDM.java index c62781f6..c187824b 100644 --- a/src/main/java/com/flansmod/common/teams/GameTypeDM.java +++ b/src/main/java/com/flansmod/common/teams/GameTypeDM.java @@ -40,12 +40,12 @@ public void roundEnd() for(String name : teamA.members){ getPlayerInfo(getPlayer(name)).playedRounds++; getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerInfoData(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); } for(String name : teamB.members){ getPlayerInfo(getPlayer(name)).playedRounds++; getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerInfoData(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); } for(String name : teamA.members){ PlayerData data = getPlayerData(getPlayer(name)); @@ -66,11 +66,11 @@ public void roundEnd() if(getPlayerData(bestPlayerA).score>getPlayerData(bestPlayerB).score){ getPlayerInfo(bestPlayerA).addExp(250); getPlayerInfo(bestPlayerA).MVPCount++; - getPlayerInfo(bestPlayerA).savePlayerInfoData(); + getPlayerInfo(bestPlayerA).savePlayerStats(); } else if(getPlayerData(bestPlayerA).score= 10) break; } @@ -246,8 +211,8 @@ public static void printLeaderboardExp(ICommandSender sender) { class ComparatorExp implements Comparator { @Override public int compare(String a, String b) { - PlayerInfo info1 = PlayerInfo.getPlayerInfoFromFile(a); - PlayerInfo info2 = PlayerInfo.getPlayerInfoFromFile(b); + PlayerStats info1 = PlayerStats.getPlayerStatsFromFile(a); + PlayerStats info2 = PlayerStats.getPlayerStatsFromFile(b); if (info1 == null || info2 == null) return 0; return info2.totalExp - info1.totalExp; diff --git a/src/main/java/com/flansmod/common/teams/TeamsManager.java b/src/main/java/com/flansmod/common/teams/TeamsManager.java index af2f73fb..002654bf 100644 --- a/src/main/java/com/flansmod/common/teams/TeamsManager.java +++ b/src/main/java/com/flansmod/common/teams/TeamsManager.java @@ -1012,7 +1012,6 @@ public void resetInventory(EntityPlayer player) { for (int i = 0; i < player.inventory.getSizeInventory(); i++) { ItemStack stack = player.inventory.getStackInSlot(i); if (stack != null && stack.getItem() instanceof ItemGun) { - new ItemStack(GunType.getGun("mtar").getItem()); ((ItemGun) stack.getItem()).reload(stack, ((ItemGun) stack.getItem()).type, player.worldObj, player, true, false); } } From 3f513619efb0a53de139582e2238b28dc5d2ad54 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 15:30:31 +0200 Subject: [PATCH 05/25] big minigames update. part 1 --- .../com/flansmod/common/teams/CommandTeams.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/CommandTeams.java b/src/main/java/com/flansmod/common/teams/CommandTeams.java index 0c884890..a4d81386 100644 --- a/src/main/java/com/flansmod/common/teams/CommandTeams.java +++ b/src/main/java/com/flansmod/common/teams/CommandTeams.java @@ -267,17 +267,27 @@ public void processCommand(ICommandSender sender, String[] split) { sender.addChatMessage(new ChatComponentText("Autobalance is now " + (TeamsManager.autoBalance ? "enabled" : "disabled"))); return; } + if (split[0].equals("useRotation")) { + if (split.length != 2) { + sender.addChatMessage(new ChatComponentText("Incorrect Usage : Should be /teams " + split[0] + " ")); + return; + } + TeamsManager.voting = !Boolean.parseBoolean(split[1]); + sender.addChatMessage(new ChatComponentText("Voting is now " + (TeamsManager.voting ? "enabled" : "disabled"))); + return; + } if (split[0].equalsIgnoreCase("stats")) { if (split.length != 2) { sender.addChatMessage(new ChatComponentText("Incorrect Usage : Should be /teams " + split[0] + " ")); return; } - PlayerInfo info = PlayerInfo.getPlayerInfoFromFile(split[1]); + PlayerStats info = PlayerStats.getPlayerStatsFromFile(split[1]); if(info==null){ sender.addChatMessage(new ChatComponentText("Player not found/Error reading player info")); return; } + sender.addChatMessage(new ChatComponentText("\u00a74\u00a7lUsername: "+"\u00a7a\u00a7l"+info.nickname)); sender.addChatMessage(new ChatComponentText("\u00a74\u00a7lKills: "+"\u00a7a\u00a7l"+info.kills)); sender.addChatMessage(new ChatComponentText("\u00a74\u00a7lDeaths: "+"\u00a7a\u00a7l"+info.deaths)); sender.addChatMessage(new ChatComponentText("\u00a74\u00a7lK/D Ratio: "+"\u00a7a\u00a7l"+(double)info.kills/info.deaths)); @@ -292,7 +302,7 @@ public void processCommand(ICommandSender sender, String[] split) { sender.addChatMessage(new ChatComponentText("\u00a74\u00a7lVehicles Destroyed: "+"\u00a7a\u00a7l"+info.kills)); } if(split[0].equalsIgnoreCase("leaderboard")){ - PlayerInfo.printLeaderboardExp(sender); + PlayerStats.printLeaderboardExp(sender); } if (split[0].equals("voting")) { From f9db22670a1a38b39ddd5e3385976dc61dc1f1d9 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 15:31:34 +0200 Subject: [PATCH 06/25] big minigames update --- src/main/java/com/flansmod/common/teams/PlayerStats.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/PlayerStats.java b/src/main/java/com/flansmod/common/teams/PlayerStats.java index 122a81e8..a682c1fe 100644 --- a/src/main/java/com/flansmod/common/teams/PlayerStats.java +++ b/src/main/java/com/flansmod/common/teams/PlayerStats.java @@ -199,10 +199,12 @@ public static void printLeaderboardExp(ICommandSender sender) { case 9: sender.addChatMessage(new ChatComponentText("\u00a7l10. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); break; + case 10: + sender.addChatMessage(new ChatComponentText("\u00a7b\u00a7l"+nameList.indexOf(sender.getCommandSenderName())+1+". " + sender.getCommandSenderName() + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; } - sender.addChatMessage(new ChatComponentText("\u00a7b\u00a7l"+nameList.indexOf(sender.getCommandSenderName())+1 + sender.getCommandSenderName() + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); counter1++; - if (counter1 >= 10) break; + if (counter1 >= 11) break; } counter1 = 0; } From 6d06115a291e17f7d403852d551cb0c15a19b8f6 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 16:29:03 +0200 Subject: [PATCH 07/25] big minigames update. part 1 handling destroying vehicles by all --- .../common/driveables/EntityDriveable.java | 2835 +---------------- 1 file changed, 133 insertions(+), 2702 deletions(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index 28976ef3..740b55b3 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -1,2802 +1,233 @@ -package com.flansmod.common.driveables; +package com.flansmod.common.teams; -import cofh.api.energy.IEnergyContainerItem; -import com.flansmod.api.IControllable; -import com.flansmod.api.IExplodeable; -import com.flansmod.client.EntityCamera; -import com.flansmod.client.FlansModClient; -import com.flansmod.client.debug.EntityDebugVector; -import com.flansmod.common.FlansMod; -import com.flansmod.common.RotatedAxes; -import com.flansmod.common.driveables.DriveableType.ParticleEmitter; -import com.flansmod.common.driveables.DriveableType.ShootParticle; -import com.flansmod.common.driveables.collisions.CollisionPlane; -import com.flansmod.common.driveables.collisions.CollisionShapeBox; -import com.flansmod.common.driveables.collisions.CollisionTest; -import com.flansmod.common.driveables.mechas.EntityMecha; -import com.flansmod.common.guns.*; -import com.flansmod.common.guns.raytracing.BulletHit; -import com.flansmod.common.guns.raytracing.DriveableHit; -import com.flansmod.common.network.PacketDriveableDamage; -import com.flansmod.common.network.PacketDriveableKeyHeld; -import com.flansmod.common.network.PacketParticle; -import com.flansmod.common.network.PacketPlaySound; -import com.flansmod.common.parts.ItemPart; -import com.flansmod.common.parts.PartType; -import com.flansmod.common.teams.TeamsManager; -import com.flansmod.common.vector.Vector3f; -import cpw.mods.fml.common.network.ByteBufUtils; -import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; -import io.netty.buffer.ByteBuf; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +import com.flansmod.common.driveables.EntityDriveable; +import com.flansmod.common.driveables.EntityPlane; +import com.flansmod.common.driveables.EntityVehicle; +import com.flansmod.common.driveables.EnumPlaneMode; +import com.flansmod.common.guns.EntityBullet; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.*; -import net.minecraft.util.MovingObjectPosition.MovingObjectType; -import net.minecraft.world.World; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EntityDamageSource; +import net.minecraft.util.Vec3; -import java.util.ArrayList; - -public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData { - public boolean syncFromServer = true; - /** - * Ticks since last server update. Use to smoothly transition to new position - */ - public int serverPositionTransitionTicker; - /** - * Server side position, as synced by PacketVehicleControl packets - */ - public double serverPosX, serverPosY, serverPosZ; - /** - * Server side rotation, as synced by PacketVehicleControl packets - */ - public double serverYaw, serverPitch, serverRoll; +import com.flansmod.common.FlansMod; +import com.flansmod.common.PlayerData; +import com.flansmod.common.PlayerHandler; +import com.flansmod.common.network.PacketBase; +import com.flansmod.common.types.InfoType; - /** - * The driveable data which contains the inventory, the engine and the fuel - */ - public DriveableData driveableData; - /** - * The shortName of the driveable type, used to obtain said type - */ - public String driveableType; +public abstract class GameType { + public static HashMap gameTypes = new HashMap<>(); + public static TeamsManager teamsManager = TeamsManager.getInstance(); + public static Random rand = new Random(); - /** - * The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to obtain the thrust - */ - public float throttle; - /** - * The wheels on this plane - */ - public EntityWheel[] wheels; + public static GameType getGameType(String type) { + return gameTypes.get(type); + } - public boolean fuelling; - /** - * Extra prevRotation field for smoothness in all 3 rotational axes - */ - public float prevRotationRoll; - /** - * Angular velocity - */ - public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F); + public String name; + public String shortName; + public int numTeamsRequired; - /** - * Whether each mouse button is held - */ - public boolean leftMouseHeld = false, rightMouseHeld = false; + public GameType(String name, String shortName, int numTeams) { + this.name = name; + this.shortName = shortName; + numTeamsRequired = numTeams; + gameTypes.put(this.shortName, this); + } /** - * Shoot delay variables - */ - public float shootDelayPrimary, shootDelaySecondary; - /** - * Minigun speed variables + * Called when a round starts */ - public float minigunSpeedPrimary, minigunSpeedSecondary; - /** - * Current gun variables for alternating weapons. - */ - public int currentGunPrimary, currentGunSecondary; + public abstract void roundStart(); /** - * Angle of harvester aesthetic piece + * Called when a round ends. (The point at which scoreboards are displayed) */ - public float harvesterAngle; - - public RotatedAxes prevAxes; - public RotatedAxes axes; - - public EntitySeat[] seats; - - public int lockOnSoundDelay; - - private int[] emitterTimers; - - public int animCountLeft = 0; - public int animFrameLeft = 0; - public int animCountRight = 0; - public int animFrameRight = 0; - - public boolean leftTurnHeld = false; - public boolean rightTurnHeld = false; - - - public boolean isShowedPosition = false; - - public int tickCount = 0; - - //Gun recoil - public boolean isRecoil = false; - public float recoilPos = 0; - public float lastRecoilPos = 0; - public int recoilTimer = 0; - - public Vector3f lastPos = new Vector3f(0, 0, 0); - public boolean hugeBoat = false; - public boolean onDeck = false; - public double deckHeight = 0; - public int deckCheck = 0; - public int prevDeckCheck = 0; - - public boolean isMecha = false; - public boolean disabled = false; + public abstract void roundEnd(); /** - * The angle of the propeller for the renderer + * Called when the scoreboards and voting are finished */ - public float propAngle = 0; - public float prevPropAngle = 0; - - public float rotorAngle = 0; - public float prevRotorAngle = 0; - - //Flares - public int flareDelay = 0; - public int ticksFlareUsing = 0; - public boolean varFlare; - - //IT1 stuff - public float drakonDoorAngle = 0; - public float drakonArmAngle = 0; - public float drakonRailAngle = 0; - - public float prevDrakonDoorAngle = 0; - public float prevDrakonArmAngle = 0; - public float prevDrakonRailAngle = 0; - - public boolean reloadingDrakon = false; - public boolean canFireIT1 = true; - - public int stage = 1; - public int reloadAnimTime = 0; - - public boolean toDeactivate = false; - public int timeTillDeactivate = 0; - - // - public boolean canFire = true; - - - @SideOnly(Side.CLIENT) - public EntityLivingBase camera; - - protected int invulnerableUnmountCount; - - private ItemStack[][] prevInventoryItems = new ItemStack[][]{null, null}; - - public Entity lastAtkEntity = null; - - public Float collisionHardness = 0F; - - public int engineStartDelay; - - //public ArrayList playerIDs = new ArrayList(); - - public EntityDriveable(World world) { - super(world); - axes = new RotatedAxes(); - prevAxes = new RotatedAxes(); - preventEntitySpawning = true; - if (FlansMod.driveableHitboxes) { - setSize(1F, 1F); - } else { - setSize(0F, 0F); - } - yOffset = 6F / 16F; - ignoreFrustumCheck = true; - renderDistanceWeight = 20000D; - } - - - public EntityDriveable(World world, DriveableType t, DriveableData d) { - this(world); - driveableType = t.shortName; - driveableData = d; - } + public abstract void roundCleanup(); - protected void initType(DriveableType type, boolean clientSide) { - if (type == null) return; - seats = new EntitySeat[type.numPassengers + 1]; - for (int i = 0; i < type.numPassengers + 1; i++) { - if (!clientSide) { - seats[i] = new EntitySeat(worldObj, this, i); - worldObj.spawnEntityInWorld(seats[i]); - } - } - wheels = new EntityWheel[type.wheelPositions.length]; - for (int i = 0; i < wheels.length; i++) { - if (!clientSide) { - wheels[i] = new EntityWheel(worldObj, this, i); - worldObj.spawnEntityInWorld(wheels[i]); - } - } - stepHeight = type.wheelStepHeight; - yOffset = type.yOffset; - - emitterTimers = new int[type.emitters.size()]; - for (int i = 0; i < type.emitters.size(); i++) { - emitterTimers[i] = rand.nextInt(type.emitters.get(i).emitRate); - } - - getEntityData().setBoolean("CanMountEntity", type.canMountEntity); - - //Register Plane to Radar on Spawning - //if(type.onRadar == true) - // RadarRegistry.register(this); - - for (int ps = 0; ps < 2; ps++) { - EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; - if (weaponType == EnumWeaponType.GUN) { - weaponType = EnumWeaponType.NONE; - } - int istart = getInventoryStart(weaponType); - if (istart == driveableData.getAmmoInventoryStart()) { - istart += type.numPassengerGunners; - } - final int isize = getInventorySize(weaponType); - if (istart >= 0 || isize > 0) { - prevInventoryItems[ps] = new ItemStack[isize]; - for (int i = 0; i < isize; i++) { - prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); - } - } - } - - engineStartDelay = type.engineStartTime; - } + public abstract boolean teamHasWon(Team team); - @Override - protected void writeEntityToNBT(NBTTagCompound tag) { - driveableData.writeToNBT(tag); - tag.setString("Type", driveableType); - tag.setFloat("RotationYaw", axes.getYaw()); - tag.setFloat("RotationPitch", axes.getPitch()); - tag.setFloat("RotationRoll", axes.getRoll()); + public void tick() { } - @Override - protected void readEntityFromNBT(NBTTagCompound tag) { - driveableType = tag.getString("Type"); - driveableData = new DriveableData(tag); - initType(DriveableType.getDriveable(driveableType), false); - - prevRotationYaw = tag.getFloat("RotationYaw"); - prevRotationPitch = tag.getFloat("RotationPitch"); - prevRotationRoll = tag.getFloat("RotationRoll"); - axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll); - } - - @Override - public void writeSpawnData(ByteBuf data) { - ByteBufUtils.writeUTF8String(data, driveableType); - - NBTTagCompound tag = new NBTTagCompound(); - driveableData.writeToNBT(tag); - ByteBufUtils.writeTag(data, tag); - - data.writeFloat(axes.getYaw()); - data.writeFloat(axes.getPitch()); - data.writeFloat(axes.getRoll()); - - //Write damage - for (EnumDriveablePart ep : EnumDriveablePart.values()) { - DriveablePart part = getDriveableData().parts.get(ep); - data.writeFloat(part.health); - data.writeBoolean(part.onFire); - } + public Team[] getTeamsCanSpawnAs(TeamsRound currentRound, EntityPlayer player) { + return currentRound.teams; } - @Override - public void readSpawnData(ByteBuf data) { - try { - driveableType = ByteBufUtils.readUTF8String(data); - driveableData = new DriveableData(ByteBufUtils.readTag(data)); - initType(getDriveableType(), true); - - axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat()); - prevRotationYaw = axes.getYaw(); - prevRotationPitch = axes.getPitch(); - prevRotationRoll = axes.getRoll(); - - //Read damage - for (EnumDriveablePart ep : EnumDriveablePart.values()) { - DriveablePart part = getDriveableData().parts.get(ep); - part.health = data.readFloat(); - part.onFire = data.readBoolean(); - } - - } catch (Exception e) { - FlansMod.log("Failed to retrieve plane type from server."); - super.setDead(); - e.printStackTrace(); - } - - camera = new EntityCamera(worldObj, this); - worldObj.spawnEntityInWorld(camera); + public void playerJoined(EntityPlayerMP player) { } - /** - * Called with the movement of the mouse. Used in controlling vehicles if need be. - * - * @param deltaY change in Y - * @param deltaX change in X - * @return if mouse movement was handled. - */ - @Override - public abstract void onMouseMoved(int deltaX, int deltaY); - - @Override - @SideOnly(Side.CLIENT) - public EntityLivingBase getCamera() { - return camera; + public void playerRespawned(EntityPlayerMP player) { } - protected boolean canSit(int seat) { - return getDriveableType().numPassengers >= seat && seats[seat].riddenByEntity == null; + public void playerQuit(EntityPlayerMP player) { } - @Override - protected boolean canTriggerWalking() { - return false; + //Return true if damage should be dealt. + public boolean playerAttacked(EntityPlayerMP player, DamageSource source) { + return true; } - @Override - protected void entityInit() { + public void playerKilled(EntityPlayerMP player, DamageSource source) { } - - @Override - public AxisAlignedBB getCollisionBox(Entity entity) { - if (getDriveableType().collisionDamageEnable) { - if (throttle > getDriveableType().collisionDamageThrottle) { - if (entity instanceof EntityLiving) { - entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } else if (entity instanceof EntityPlayer) { - entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } - } - } - return boundingBox; + public void baseAttacked(ITeamBase base, DamageSource source) { } - @Override - public AxisAlignedBB getBoundingBox() { - return boundingBox; + public void objectAttacked(ITeamObject object, DamageSource source) { } - @Override - public boolean canBePushed() { - return false; + public void baseClickedByPlayer(ITeamBase base, EntityPlayerMP player) { } - @Override - public double getMountedYOffset() { - return -0.3D; + public void objectClickedByPlayer(ITeamObject object, EntityPlayerMP player) { } - /** - * Pass generic damage to the core - */ - @Override - public boolean attackEntityFrom(DamageSource damagesource, float i) { - if (worldObj.isRemote || isDead) return true; -// if(damagesource.getDamageType().indexOf("explosion") < 0) - { - if (isMountedEntity(damagesource.getEntity())) { - return false; - } - } - -// FlansMod.log(String.format("EntityDriveable.attackEntityFrom %.1f: %s : %s : %s", i, -// damagesource.getDamageType(), damagesource.getEntity(), damagesource.getSourceOfDamage())); - - boolean broken = attackPart(EnumDriveablePart.core, damagesource, i); - if (i > 0) { - //checkParts(); - checkPartsWhenAttacked(); - //If it hit, send a damage update packet - FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); - } + public boolean playerCanLoot(ItemStack stack, InfoType infoType, EntityPlayer player, Team playerTeam) { return true; } - public boolean isMountedEntity(Entity entity) { - if (entity != null) { - Entity entity2 = this.worldObj.getEntityByID(entity.getEntityId()); - for (Entity seat : seats) { - if (seat.riddenByEntity != null) { - if (seat.riddenByEntity == entity || seat.riddenByEntity == entity2) { - return true; - } - } - } - } + public abstract Vec3 getSpawnPoint(EntityPlayerMP player); + //Return whether or not the variable exists + public boolean setVariable(String variable, String value) { return false; } - @Override - public void setDead() { - super.setDead(); - //Unregister to Radar - //RadarRegistry.unregister(this); - if (worldObj.isRemote) - camera.setDead(); - - for (EntitySeat seat : seats) - if (seat != null) - seat.setDead(); - } + public abstract void readFromNBT(NBTTagCompound tags); - @Override - public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) { - } + public abstract void saveToNBT(NBTTagCompound tags); - @Override - public boolean canBeCollidedWith() { + public boolean sortScoreboardByTeam() { return true; } - @Override - public void applyEntityCollision(Entity entity) { - //if(!isPartOfThis(entity)) - //super.applyEntityCollision(entity); - } - - @Override - public void setPositionAndRotation2(double d, double d1, double d2, float f, float f1, int i) { - if (ticksExisted > 1) - return; - if (!(riddenByEntity instanceof EntityPlayer) || !FlansMod.proxy.isThePlayer((EntityPlayer) riddenByEntity)) { - if (syncFromServer) { - serverPositionTransitionTicker = i + 5; - } else { - double var10 = d - posX; - double var12 = d1 - posY; - double var14 = d2 - posZ; - double var16 = var10 * var10 + var12 * var12 + var14 * var14; - - if (var16 <= 1.0D) { - return; - } - - serverPositionTransitionTicker = 3; - } - serverPosX = d; - serverPosY = d1; - serverPosZ = d2; - serverYaw = f; - serverPitch = f1; - } - } - - public void setIT1(boolean canFire, boolean reloading, int stag, int stageTime) { - if (worldObj.isRemote && ticksExisted % 5 == 0) { - canFireIT1 = canFire; - reloadingDrakon = reloading; - stage = stag; - reloadAnimTime = stageTime; - } - } - - public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw) { - if (worldObj.isRemote) { - serverPosX = x; - serverPosY = y; - serverPosZ = z; - serverYaw = yaw; - serverPitch = pitch; - serverRoll = roll; - serverPositionTransitionTicker = 5; - } else { - setPosition(x, y, z); - prevRotationYaw = yaw; - prevRotationPitch = pitch; - prevRotationRoll = roll; - setRotation(yaw, pitch, roll); - } - //Set the motions regardless of side. - motionX = motX; - motionY = motY; - motionZ = motZ; - angularVelocity = new Vector3f(velYaw, velPitch, velRoll); - throttle = throt; - } - - - @Override - public void setVelocity(double d, double d1, double d2) { - motionX = d; - motionY = d1; - motionZ = d2; - } - - @Override - public boolean pressKey(int key, EntityPlayer player) { - if (!worldObj.isRemote && key == 9 && getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) //Primary - { - shoot(false); - return true; - } else if (!worldObj.isRemote && key == 8 && getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) //Secondary - { - shoot(true); - return true; - } + public boolean showZombieScore() { return false; } - @Override - public void updateKeyHeldState(int key, boolean held) { - if (worldObj.isRemote) { - FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); - - if (key == 2) { - leftTurnHeld = true; - rightTurnHeld = false; - } else if (key == 3) { - rightTurnHeld = true; - leftTurnHeld = false; - } else { - leftTurnHeld = false; - rightTurnHeld = false; - } - } - switch (key) { - case 9: - leftMouseHeld = held; - break; - case 8: - rightMouseHeld = held; - break; - } - } - /** - * Shoot method called by pressing / holding shoot buttons + * Whether "attacker" can attack "victim" */ - public void shoot(boolean secondary) { - DriveableType type = getDriveableType(); - if (seats[0] == null) - return; - - if (type.IT1 && !canFireIT1 && type.weaponType(secondary) == EnumWeaponType.MISSILE) return; - - if (!canFire || (isUnderWater() && !type.worksUnderWater)) return; - - //Check shoot delay - if (getShootDelay(secondary) <= 0) { - //We can shoot, so grab the available shoot points and the weaponType - ArrayList shootPoints = type.shootPoints(secondary); - EnumWeaponType weaponType = type.weaponType(secondary); - //If there are no shoot points, return - if (shootPoints.size() == 0) - return; - //For alternating guns, move on to the next one - int currentGun = getCurrentGun(secondary); - if (type.alternate(secondary)) { - currentGun = (currentGun + 1) % shootPoints.size(); - setCurrentGun(currentGun, secondary); - shootEach(type, shootPoints.get(currentGun), currentGun, secondary, weaponType); - } else for (int i = 0; i < shootPoints.size(); i++) - shootEach(type, shootPoints.get(i), i, secondary, weaponType); - } - } - - public boolean driverIsCreative() { - return seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode; + public boolean playerCanAttack(EntityPlayerMP attacker, Team attackerTeam, EntityPlayerMP victim, Team victimTeam) { + return true; } - public void spawnParticle(ArrayList list, ShootPoint shootPoint, Vector3f v) { - for (ShootParticle s : list) { - float bkx = shootPoint.rootPos.position.x; - float bky = shootPoint.rootPos.position.y; - float bkz = shootPoint.rootPos.position.z; - - Vector3f velocity = new Vector3f(s.x, s.y, s.z); - - //if(shootPoint.rootPos.part == EnumDriveablePart.turret){ - velocity = getDirection(shootPoint, velocity); - //} - - //Vector3f v = getFiringPosition(shootPoint); - - if (shootPoint.rootPos.part == EnumDriveablePart.core) { - Vector3f v2 = axes.findLocalVectorGlobally(shootPoint.rootPos.position); - Vector3f v3 = rotate(seats[0].looking.findLocalVectorGlobally(shootPoint.offPos)); - Vector3f.add(v2, v3, v); - } - - FlansMod.getPacketHandler().sendToAllAround( - new PacketParticle(s.name, posX + v.x, posY + v.y, posZ + v.z, velocity.x, velocity.y, velocity.z), - posX + v.x, posY + v.y, posZ + v.z, 150, dimension); + /** + * Called when any entity is killed. This allows one to track mob deaths too + */ + public void entityKilled(Entity entity, DamageSource source) { - shootPoint.rootPos.position.x = bkx; - shootPoint.rootPos.position.y = bky; - shootPoint.rootPos.position.z = bkz; - } } - - private void shootEach(DriveableType type, ShootPoint shootPoint, int currentGun, boolean secondary, EnumWeaponType weaponType) { - //Rotate the gun vector to global axes - Vector3f gunVec = getFiringPosition(shootPoint); - Vector3f lookVector = getLookVector(shootPoint); - - if (!secondary && type.fixedPrimaryFire) { - lookVector = axes.findLocalVectorGlobally(type.primaryFireAngle); - if (shootPoint.rootPos.part == EnumDriveablePart.turret) { - lookVector = getPositionOnTurret(type.primaryFireAngle, false); - } - if (shootPoint.rootPos.part == EnumDriveablePart.barrel) { - lookVector = getPositionOnTurret(type.primaryFireAngle, true); - } - } - - if (weaponType == EnumWeaponType.SHELL) - isRecoil = true; - if (shootPoint.rootPos.part == null) return; - if (!isPartIntact(shootPoint.rootPos.part)) return; - - if (disabled) return; - float damageMultiplier = secondary ? type.damageMultiplierSecondary : type.damageMultiplierPrimary; - //If its a pilot gun, then it is using a gun type, so do the following - if (shootPoint.rootPos instanceof PilotGun && ((PilotGun) shootPoint.rootPos).type != null) { - PilotGun pilotGun = (PilotGun) shootPoint.rootPos; - //Get the gun from the plane type and the ammo from the data - GunType gunType = pilotGun.type; - float shellSpeed = gunType.bulletSpeed; - if (type.rangingGun) - shellSpeed = type.bulletSpeed; - ItemStack bulletItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + currentGun]; - //Check that neither is null and that the bullet item is actually a bullet - if (bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable && TeamsManager.bulletsEnabled) { - ShootableType bullet = ((ItemShootable) bulletItemStack.getItem()).type; - if (gunType.isAmmo(bullet)) { - //spawnParticle(gunType, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY,V (float)posZ), null)); - - spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); - //Spawn a new bullet item - worldObj.spawnEntityInWorld(((ItemShootable) bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, gunType.bulletSpread / 2, gunType.damage * damageMultiplier, shellSpeed, bulletItemStack.getItemDamage(), type)); - //Play the shoot sound - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); - //Get the bullet item damage and increment it - int damage = bulletItemStack.getItemDamage(); - bulletItemStack.setItemDamage(damage + 1); - //If the bullet item is completely damaged (empty) - if (damage + 1 == bulletItemStack.getMaxDamage()) { - //Set the damage to 0 and consume one ammo item (unless in creative) - bulletItemStack.setItemDamage(0); - if (!driverIsCreative()) { - bulletItemStack.stackSize--; - if (bulletItemStack.stackSize <= 0) { - onWeaponInventoryChanged(secondary); - bulletItemStack = null; - } - driveableData.setInventorySlotContents(getDriveableType().numPassengerGunners + currentGun, bulletItemStack); - } - } - if (type.shootDelay(secondary) == -1) { - setShootDelay(gunType.getShootDelay(), secondary); - } else { - setShootDelay(type.shootDelay(secondary), secondary); - } - //Reset the shoot delay - } - } - } else //One of the other modes - { - switch (weaponType) { - case BOMB: { - if (TeamsManager.bombsEnabled) { - int slot = -1; - for (int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) { - ItemStack bomb = driveableData.getStackInSlot(i); - if (bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) bomb.getItem()).type, weaponType)) { - slot = i; - } - } - - if (slot != -1) { - int spread = 0; - float shellSpeed = 0F; - - ItemStack bulletStack = driveableData.getStackInSlot(slot); - ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); - if (shootPoint.rootPos instanceof PilotGun) { - PilotGun pilotGun = (PilotGun) shootPoint.rootPos; - //Get the gun from the plane type and the ammo from the data - GunType gunType = pilotGun.type; - } - - EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vec3.createVectorHelper(gunVec.x + posX, gunVec.y + posY, gunVec.z + posZ), axes.getYaw(), axes.getPitch(), motionX, motionY, motionZ, (EntityLivingBase) seats[0].riddenByEntity, damageMultiplier, driveableData.getStackInSlot(slot).getItemDamage(), type); - worldObj.spawnEntityInWorld(bulletEntity); - - spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); - - - if (type.shootSound(secondary) != null) - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); - if (!driverIsCreative()) { - bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); - if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { - bulletStack.setItemDamage(0); - bulletStack.stackSize--; - if (bulletStack.stackSize == 0) { - onWeaponInventoryChanged(secondary); - bulletStack = null; - } - } - driveableData.setInventorySlotContents(slot, bulletStack); - } - if (type.shootDelay(secondary) == -1) { - setShootDelay(1, secondary); - } else { - setShootDelay(type.shootDelay(secondary), secondary); - } - } - } - break; - } - case MISSILE: //These two are actually almost identical - case SHELL: { - //int numnum = driveableData.getMissileInventoryStart(); - /*ItemStack AmmoPlaced = driveableData.getStackInSlot(1); - if(AmmoPlaced == null && type.enableReloadTime){ - isAmmoPlaced = false; - break; - } - isAmmoPlaced = true; - setShootDelay(type.shootDelay(secondary), secondary);*/ - tryRecoil(); - - if (TeamsManager.shellsEnabled) { - int slot = -1; - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, weaponType)) { - slot = i; - } + public void vehicleDestroyed(EntityDriveable driveable2, EntityPlayerMP attacker){ + if (driveable2!=null) { + if (attacker != null) { + EntityDriveable driveable = driveable2; +// if(driveable.riddenByEntity!=null && +// driveable.riddenByEntity instanceof EntityPlayer && +// !getPlayerData((EntityPlayerMP) driveable.riddenByEntity).team.equals(getPlayerData(attacker).team)) { + if(true){ //this if() need for next changes + getPlayerInfo(attacker).vehiclesDestroyed++; + if (driveable instanceof EntityPlane) { + EntityPlane plane = (EntityPlane) driveable; + if (plane.mode == EnumPlaneMode.PLANE || plane.mode == EnumPlaneMode.VTOL) { + getPlayerInfo(attacker).addExp(100); + getPlayerInfo(attacker).savePlayerStats(); + } else if (plane.mode == EnumPlaneMode.HELI) { + getPlayerInfo(attacker).addExp(75); + getPlayerInfo(attacker).savePlayerStats(); } - - if (slot != -1) { - //int spread = 0; - //float shellSpeed = 3F; - float spread = type.bulletSpread; - float shellSpeed = type.bulletSpeed; - ItemStack bulletStack = driveableData.getStackInSlot(slot); - ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); - EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); - //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY, (float)posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, bulletStack.getItemDamage(), type); - //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); - worldObj.spawnEntityInWorld(bulletEntity); //SHELL - spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); - isRecoil = true; - - if (type.shootSound(secondary) != null) - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); - if (!driverIsCreative()) { - bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); - if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { - bulletStack.setItemDamage(0); - bulletStack.stackSize--; - if (bulletStack.stackSize == 0) { - onWeaponInventoryChanged(secondary); - bulletStack = null; - } - } - driveableData.setInventorySlotContents(slot, bulletStack); - } - if (type.shootDelay(secondary) == -1) { - setShootDelay(1, secondary); - } else { - setShootDelay(type.shootDelay(secondary), secondary); - } - canFireIT1 = false; + } else if (driveable instanceof EntityVehicle) { + EntityVehicle vehicle = (EntityVehicle) driveable; + if (vehicle.getVehicleType().tank) { + getPlayerInfo(attacker).addExp(75); + getPlayerInfo(attacker).savePlayerStats(); + } else { + getPlayerInfo(attacker).addExp(50); + getPlayerInfo(attacker).savePlayerStats(); } } - break; } - case GUN: //Handled above - break; - case MINE: - case NONE: - break; } } } - public Vector3f getOrigin(ShootPoint dp) { - //Rotate the gun vector to global axes - Vector3f localGunVec = new Vector3f(dp.rootPos.position); - - if (dp.rootPos.part == EnumDriveablePart.turret) { - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); - //Rotate by the turret angles - localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - //Translate by the turret origin - Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); - } - - return rotate(localGunVec); + public void playerChoseTeam(EntityPlayerMP player, Team team, Team newTeam) { } - public Vector3f getPositionOnTurret(Vector3f vecIn, boolean barrel) { - Vector3f transform = vecIn; - RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); - if (barrel) yawOnlyLooking = seats[0].looking; - - //Calculate the root of the gun - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(transform, getDriveableType().turretOrigin, transform); - //Rotate by the turret angles - transform = yawOnlyLooking.findLocalVectorGlobally(transform); - //Translate by the turret origin - Vector3f.add(transform, getDriveableType().turretOrigin, transform); - Vector3f turretOriginOffset = new Vector3f(getDriveableType().turretOriginOffset); - turretOriginOffset = yawOnlyLooking.findLocalVectorGloballyYaw(turretOriginOffset); - Vector3f.add(transform, turretOriginOffset, transform); - - return rotate(transform); + public void playerChoseNewClass(EntityPlayerMP player, PlayerClass playerClass) { } - public Vector3f getDirection(ShootPoint dp, Vector3f vIn) { - //Rotate the gun vector to global axes - Vector3f localGunVec = new Vector3f(vIn); - - //if(dp.rootPos.part == EnumDriveablePart.turret) - //{ - //localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - //} - - localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - - return rotate(localGunVec); + public void playerDefected(EntityPlayerMP player, Team team, Team newTeam) { } - public Vector3f getLookVector(ShootPoint dp) { - return axes.getXAxis(); + public void playerEnteredTheGame(EntityPlayerMP player, Team team, PlayerClass playerClass) { } - public Vector3f getFiringPosition(ShootPoint dp) { - Vector3f rootVector = new Vector3f(dp.rootPos.position); - Vector3f offsetVector = new Vector3f(dp.offPos); - Vector3f localGunVec = new Vector3f(dp.rootPos.position); + //-------------------------------------- + // Helper methods - Do not override + //-------------------------------------- - if (dp.rootPos.part == EnumDriveablePart.turret) { - if (offsetVector.x == 0 && offsetVector.y == 0 && offsetVector.z == 0) { - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); - //Rotate by the turret angles - localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - //Translate by the turret origin - Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); - } else { - RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); - //Calculate the root of the gun - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(rootVector, getDriveableType().turretOrigin, rootVector); - //Rotate by the turret angles - rootVector = yawOnlyLooking.findLocalVectorGlobally(rootVector); - //Translate by the turret origin - Vector3f.add(rootVector, getDriveableType().turretOrigin, rootVector); - //Calculate the tip of the gun - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(offsetVector, getDriveableType().turretOrigin, offsetVector); - //Rotate by the turret angles - offsetVector = seats[0].looking.findLocalVectorGlobally(offsetVector); - //Translate by the turret origin - - Vector3f.add(rootVector, offsetVector, localGunVec); - } - } - - return rotate(localGunVec); + public static PlayerData getPlayerData(EntityPlayerMP player) { + return PlayerHandler.getPlayerData(player); } - public boolean isEngineActive() { - return (driverIsCreative() || driveableData.fuelInTank > 0) && engineStartDelay == 0 || getDriveableType().fuelTankSize < 0; + public static PlayerStats getPlayerInfo(EntityPlayerMP player) { + return PlayerHandler.getPlayerStats(player); } - public void correctWheelPos() { - if (this.ticksExisted % (10 * 20) == 0) { - for (EntityWheel wheel : wheels) { - if (wheel == null) continue; - - Vector3f target = axes.findLocalVectorGlobally(getDriveableType().wheelPositions[wheel.ID].position); - target.x += posX; - target.y += posY; - target.z += posZ; - - int tf = 1; - int cf = 1; - int range = 5; - - if (MathHelper.abs(target.x - (float) wheel.posX) > range) { - wheel.posX = (target.x * tf + (float) wheel.posX * cf) / (tf + cf); - } - if (MathHelper.abs(target.y - (float) wheel.posY) > range) { - wheel.posY = (target.y * tf + (float) wheel.posY * cf) / (tf + cf); - } - if (MathHelper.abs(target.z - (float) wheel.posZ) > range) { - wheel.posZ = (target.z * tf + (float) wheel.posZ * cf) / (tf + cf); - } - } - } + public static void sendPacketToPlayer(PacketBase packet, EntityPlayerMP player) { + FlansMod.getPacketHandler().sendTo(packet, player); } - @Override - public void onUpdate() { - super.onUpdate(); - //playerIDs.clear(); - DriveableType type = getDriveableType(); - DriveableData data = getDriveableData(); - //if(type.fancyCollision) - //checkCollsionBox(); - hugeBoat = (getDriveableType().floatOnWater && getDriveableType().wheelStepHeight == 0); - //hugeBoat = true; - - if (hugeBoat) { - for (int i = 0; i < worldObj.loadedEntityList.size(); i++) { - Object obj = worldObj.loadedEntityList.get(i); - if (obj instanceof EntityPlayer && !isPartOfThis((Entity) obj)) { - moveRiders((Entity) obj); - } - - if (obj instanceof EntityWheel && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { - //moveRiders((Entity)obj); - } - - if (obj instanceof EntityDriveable && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { - //moveRiders((Entity)obj); - } - } - } - - onDeck = deckCheck != prevDeckCheck; - - //Aesthetics - if (type.IT1 && !disabled) { - boolean fireButtonHeld = false; - if (type.weaponType(false) == EnumWeaponType.MISSILE) fireButtonHeld = leftMouseHeld; - if (type.weaponType(true) == EnumWeaponType.MISSILE) fireButtonHeld = rightMouseHeld; - - prevDrakonDoorAngle = drakonDoorAngle; - prevDrakonArmAngle = drakonArmAngle; - prevDrakonRailAngle = drakonRailAngle; - if (canFireIT1) reloadingDrakon = false; - if (stage == 0) stage = 1; - - if (stage == 8 && fireButtonHeld) { - stage = 1; - timeTillDeactivate = 5; - toDeactivate = true; - } - if (timeTillDeactivate <= 0 && toDeactivate) { - canFireIT1 = false; - toDeactivate = false; - } - - if (reloadAnimTime <= 0) - IT1Reload(); - - reloadAnimTime--; - timeTillDeactivate--; - } - - //Aesthetics - prevPropAngle = propAngle; - prevRotorAngle = rotorAngle; - if (throttle != 0) { - propAngle += (Math.pow(Math.abs(throttle), 0.4)) * 1.5; - rotorAngle += throttle / 7F; - } - - - //Gun recoil - if (leftMouseHeld && !disabled) { - tryRecoil(); - setRecoilTimer(); - } - lastRecoilPos = recoilPos; - - if (recoilPos > 180 - (180 / type.recoilTime)) { - recoilPos = 0; - isRecoil = false; - } - - if (isRecoil) - recoilPos = recoilPos + (180 / type.recoilTime); - - if (recoilTimer >= 0) - recoilTimer--; - - checkInventoryChanged(); - - if (isUnderWater() && !type.worksUnderWater && !hugeBoat) { - throttle = 0; - //this.driveableData.parts.get(EnumDriveablePart.core).health -= 1; - disabled = true; - } else disabled = false; - - - if (type.lockOnToLivings || type.lockOnToMechas || type.lockOnToPlanes || type.lockOnToPlayers || type.lockOnToVehicles) { - if (!worldObj.isRemote && this.seats.length > 0 && lockOnSoundDelay <= 0) { - if (this.seats[0] != null && this.seats[0].riddenByEntity instanceof EntityPlayer) { - // int currentGun = getCurrentGun(false); - // Vector3f playerVec = getOrigin(type.shootPoints(false).get(currentGun)); - Vector3f playerVecRelToVehicle = seats[0].playerLooking.findGlobalVectorLocally(new Vector3f(-1, 0, 0)); - Vector3f playerVec = axes.findGlobalVectorLocally(playerVecRelToVehicle); - - for (Object obj : worldObj.loadedEntityList) { - Entity entity = (Entity) obj; - if ((type.lockOnToMechas && entity instanceof EntityMecha) || - (type.lockOnToVehicles && entity instanceof EntityVehicle) || - (type.lockOnToPlanes && entity instanceof EntityPlane) || - (type.lockOnToPlayers && entity instanceof EntityPlayer) || - (type.lockOnToLivings && entity instanceof EntityLivingBase)) { - if (getDistanceSqToEntity(entity) < type.maxRangeLockOn * type.maxRangeLockOn) { - // Some heckery with vectors rotating about themselves or something - Vector3f relPosVec = new Vector3f(-entity.posX + seats[0].posX, -entity.posY + seats[0].posY, entity.posZ - seats[0].posZ); - float angle = Math.abs(Vector3f.angle(playerVec, relPosVec)); - if (angle < Math.toRadians(type.canLockOnAngle)) { - PacketPlaySound.sendSoundPacket(seats[0].posX, seats[0].posY, seats[0].posZ, 10, dimension, type.lockOnSound, false); - if (entity instanceof EntityDriveable) - PacketPlaySound.sendSoundPacket(entity.posX, entity.posY, entity.posZ, ((EntityDriveable) entity).getDriveableType().lockedOnSoundRange, entity.dimension, ((EntityDriveable) entity).getDriveableType().lockingOnSound, false); - lockOnSoundDelay = type.lockOnSoundTime; - break; - } - } - } - } - } - } - } - if (lockOnSoundDelay > 0) - lockOnSoundDelay--; - + public static String[] getPlayerNames() { + return MinecraftServer.getServer().getAllUsernames(); + } - if (this.ridingEntity != null) { - invulnerableUnmountCount = 20 * 4; - } else if (invulnerableUnmountCount > 0) { - invulnerableUnmountCount--; - } + @SuppressWarnings("unchecked") + public static List getPlayers() { + return MinecraftServer.getServer().getConfigurationManager().playerEntityList; + } - if (!worldObj.isRemote) { - for (int i = 0; i < getDriveableType().numPassengers + 1; i++) { - if (seats[i] == null || !seats[i].addedToChunk) { - seats[i] = new EntitySeat(worldObj, this, i); - worldObj.spawnEntityInWorld(seats[i]); - } - } - for (int i = 0; i < type.wheelPositions.length; i++) { - if (wheels[i] == null || !wheels[i].addedToChunk) { - wheels[i] = new EntityWheel(worldObj, this, i); - worldObj.spawnEntityInWorld(wheels[i]); - } - } - } + public static void givePoints(EntityPlayerMP player, int points) { + PlayerData data = getPlayerData(player); + data.score += points; + if (data.team != null) + data.team.score += points; + } - //Harvest stuff - //Aesthetics - if (hasEnoughFuel() && isEngineActive()) { - harvesterAngle += throttle / 5F; + public static EntityPlayerMP getPlayerFromDamageSource(DamageSource source) { + EntityPlayerMP attacker = null; + if (source instanceof EntityDamageSource) { + if (source.getEntity() instanceof EntityPlayerMP) + attacker = (EntityPlayerMP) source.getEntity(); } - //Actual harvesting - if (type.harvestBlocks && type.harvestBoxSize != null && type.harvestBoxPos != null && TeamsManager.driveablesBreakBlocks) { - Vector3f size = new Vector3f(type.harvestBoxSize.x / 16F, type.harvestBoxSize.y / 16F, type.harvestBoxSize.z / 16F); - Vector3f pos = new Vector3f(type.harvestBoxPos.x / 16F, type.harvestBoxPos.y / 16F, type.harvestBoxPos.z / 16F); - for (float x = pos.x; x <= pos.x + size.x; x++) { - for (float y = pos.y; y <= pos.y + size.y; y++) { - for (float z = pos.z; z <= pos.z + size.z; z++) { - Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); + return attacker; + } - int blockX = (int) Math.round(posX + v.x); - int blockY = (int) Math.round(posY + v.y); - int blockZ = (int) Math.round(posZ + v.z); - Block block = worldObj.getBlock(blockX, blockY, blockZ); + public EntityPlayerMP getPlayer(String username) { + return MinecraftServer.getServer().getConfigurationManager().func_152612_a(username); + } - if (type.materialsHarvested.contains(block.getMaterial()) && block.getBlockHardness(worldObj, blockX, blockY, blockZ) >= 0F) { - if (type.collectHarvest) { - //Add the itemstack to mecha inventory - ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); - for (ItemStack stack : stacks) { - if (!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative()) && !worldObj.isRemote && worldObj.getGameRules().getGameRuleBooleanValue("doTileDrops")) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); - } - } - } else if (type.dropHarvest) { - ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); - for (ItemStack stack : stacks) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); - } - } - //Destroy block - worldObj.func_147480_a(blockX, blockY, blockZ, false); - } - } - } - } - } - - /*if(this.isLockedOn && soundTime <= 0 && !this.worldObj.isRemote) - { - PacketPlaySound.sendSoundPacket(posX,posY,posZ, 5, dimension, type.lockedOnSound, false); - soundTime = type.soundTime; - }*/ - - for (DriveablePart part : getDriveableData().parts.values()) { - if (part.box != null) { - - part.update(this); - //Client side particles - if (worldObj.isRemote) { - if (part.onFire) { - //Pick a random position within the bounding box and spawn a flame there - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); - worldObj.spawnParticle("flame", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); - } - if (part.health > 0 && part.health < part.maxHealth / 2) { - //Pick a random position within the bounding box and spawn a flame there - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); - worldObj.spawnParticle(part.health < part.maxHealth / 4 ? "largesmoke" : "smoke", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); - } - } - //Server side fire handling - if (part.onFire) { - //Rain can put out fire - if (worldObj.isRaining() && rand.nextInt(40) == 0) - part.onFire = false; - //Also water blocks - //Get the centre point of the part - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + part.box.w / 2F, part.box.y + part.box.h / 2F, part.box.z + part.box.d / 2F)); - if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.water) { - part.onFire = false; - } - } else { - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); - if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.lava) { - part.onFire = true; - } - } - } - } - - for (int i = 0; i < type.emitters.size(); i++) { - ParticleEmitter emitter = type.emitters.get(i); - emitterTimers[i]--; - boolean canEmit; - boolean inThrottle = false; - DriveablePart part = getDriveableData().parts.get(EnumDriveablePart.getPart(emitter.part)); - float healthPercentage = part.health / part.maxHealth; - canEmit = isPartIntact(EnumDriveablePart.getPart(emitter.part)) && healthPercentage >= emitter.minHealth && healthPercentage <= emitter.maxHealth; - - if ((throttle >= emitter.minThrottle && throttle <= emitter.maxThrottle)) - inThrottle = true; - if (isMecha) - inThrottle = true; - - if (emitterTimers[i] <= 0) { - if (inThrottle && canEmit) { - //Emit! - Vector3f velocity = new Vector3f(0, 0, 0); - - Vector3f pos = new Vector3f(0, 0, 0); - if (seats != null && seats[0] != null) { - if (EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.turret && EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.barrel) { - Vector3f localPosition = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, - emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, - emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); - - pos = axes.findLocalVectorGlobally(localPosition); - velocity = axes.findLocalVectorGlobally(emitter.velocity); - } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.turret || EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.head && !emitter.part.equals("barrel")) { - - Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, - emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, - emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); - pos = getPositionOnTurret(localPosition2, false); - velocity = getPositionOnTurret(emitter.velocity, false); - } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.barrel) { - Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, - emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, - emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); - - - pos = getPositionOnTurret(localPosition2, true); - velocity = getPositionOnTurret(emitter.velocity, true); - } - //FlansMod.proxy.spawnParticle(emitter.effectType, posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z); - - FlansMod.getPacketHandler().sendToAllAround( - new PacketParticle(emitter.effectType, - posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z), - posX + pos.x, posY + pos.y, posZ + pos.z, 150, dimension); - - } - } - emitterTimers[i] = emitter.emitRate; - } - } - - checkParts(); - - prevRotationYaw = axes.getYaw(); - prevRotationPitch = axes.getPitch(); - prevRotationRoll = axes.getRoll(); - prevAxes = axes.clone(); - - if (riddenByEntity != null && riddenByEntity.isDead) { - riddenByEntity = null; - } - if (riddenByEntity != null && isDead) { - riddenByEntity.mountEntity(null); - } - if (riddenByEntity != null) - riddenByEntity.fallDistance = 0F; - - //If there's no player in the driveable or it cannot thrust, slow the plane and turn off mouse held actions - if ((seats != null && seats[0] != null && seats[0].riddenByEntity == null) || !isEngineActive() && getDriveableType().maxThrottle != 0 && getDriveableType().maxNegativeThrottle != 0) { - throttle *= 0.99F; - } - if (seats != null && seats[0] != null && seats[0].riddenByEntity == null) { - rightMouseHeld = leftMouseHeld = false; - } - - //Check if shooting - if (shootDelayPrimary > 0) - shootDelayPrimary--; - if (shootDelaySecondary > 0) - shootDelaySecondary--; - if (getDriveableType().reloadSoundTick != 15214541 && shootDelayPrimary == getDriveableType().reloadSoundTick) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootReloadSound, false); - } -// on first update - if (this.ticksExisted == 1) { - setShootDelay(getDriveableType().placeTimePrimary, false); - setShootDelay(getDriveableType().placeTimeSecondary, true); - if (!this.worldObj.isRemote) { - if (!getDriveableType().placeSoundPrimary.isEmpty()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().placeSoundPrimary, false); - } - if (!getDriveableType().placeSoundSecondary.isEmpty()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().placeSoundSecondary, false); - } - } - } - if (seats[0] != null && seats[0].riddenByEntity != null && seats[0].riddenByEntity instanceof EntityPlayer && worldObj.isRemote) { - EntityPlayer p = (EntityPlayer) seats[0].riddenByEntity; - if (this.ticksExisted < getDriveableType().placeTimePrimary && (getShootDelay(false) % 100) == 0 ) { - p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use in " + getShootDelay(false)/20 + " seconds.")); - } else if (this.ticksExisted == getDriveableType().placeTimePrimary) { - p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use!")); - } - - if (this.ticksExisted < getDriveableType().placeTimeSecondary && (getShootDelay(true) % 100) == 0) { - p.addChatComponentMessage( - new ChatComponentText("Secondary gun ready to use in " + getShootDelay(true)/20 + " seconds.")); - } else if (this.ticksExisted == getDriveableType().placeTimeSecondary) { - p.addChatComponentMessage(new ChatComponentText("Secondary gun ready to use!")); - } - - if (engineStartDelay > 0 && engineStartDelay % (2.5*20) == 0) { - p.addChatComponentMessage(new ChatComponentText("Engine starting.. " + (float)engineStartDelay/20 + " seconds remaining.")); - } else if (engineStartDelay == 1) { - p.addChatComponentMessage(new ChatComponentText("Engine started!")); - } - } - - if (!worldObj.isRemote) { - if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO) - shoot(false); - if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO) - shoot(true); - minigunSpeedPrimary *= 0.9F; - minigunSpeedSecondary *= 0.9F; - if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN) { - minigunSpeedPrimary += 0.1F; - if (minigunSpeedPrimary > 1F) - shoot(false); - } - if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN) { - minigunSpeedSecondary += 0.1F; - if (minigunSpeedSecondary > 1F) - shoot(true); - } - } - - prevDeckCheck = deckCheck; - - if (engineStartDelay > 0) { engineStartDelay--; } - //Handle fuel - - int fuelMultiplier = 2; - - //The tank is currently full, so do nothing - if (data.fuelInTank >= type.fuelTankSize) - return; - - //Look through the entire inventory for fuel cans, buildcraft fuel buckets and RedstoneFlux power sources - for (int i = 0; i < data.getSizeInventory(); i++) { - ItemStack stack = data.getStackInSlot(i); - if (stack == null || stack.stackSize <= 0) - continue; - Item item = stack.getItem(); - //If we have an electric engine, look for RedstoneFlux power source items, such as power cubes - if (data.engine.useRFPower) { - if (item instanceof IEnergyContainerItem) { - IEnergyContainerItem energy = (IEnergyContainerItem) item; - data.fuelInTank += (fuelMultiplier * energy.extractEnergy(stack, data.engine.RFDrawRate, false)) / data.engine.RFDrawRate; - } - } else { - //Check for Flan's Mod fuel items - if (item instanceof ItemPart) { - PartType part = ((ItemPart) item).type; - //Check it is a fuel item - if (part.category == 9) { - //Put 2 points of fuel - data.fuelInTank += fuelMultiplier; - - //Damage the fuel item to indicate being used up - int damage = stack.getItemDamage(); - stack.setItemDamage(damage + 1); - - //If we have finished this fuel item - if (damage >= stack.getMaxDamage()) { - //Reset the damage to 0 - stack.setItemDamage(0); - //Consume one item - stack.stackSize--; - //If we consumed the last one, destroy the stack - if (stack.stackSize <= 0) - data.setInventorySlotContents(i, null); - } - - //We found a fuel item and consumed some, so we are done - break; - } - } - //Check for Buildcraft oil and fuel buckets - else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftOilBucket) && data.fuelInTank + 1000 * fuelMultiplier <= type.fuelTankSize) { - data.fuelInTank += 1000 * fuelMultiplier; - data.setInventorySlotContents(i, new ItemStack(Items.bucket)); - } else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftFuelBucket) && data.fuelInTank + 2000 * fuelMultiplier <= type.fuelTankSize) { - data.fuelInTank += 2000 * fuelMultiplier; - data.setInventorySlotContents(i, new ItemStack(Items.bucket)); - } - - prevPosX = posX; - prevPosY = posY; - prevPosZ = posZ; - } - } - } - - public void checkInventoryChanged() { - DriveableType type = getDriveableType(); - if (type == null) return; - - if (worldObj.isRemote) return; - - if (!driveableData.inventoryChanged) return; - - driveableData.inventoryChanged = false; - - try { - for (int ps = 0; ps < 2; ps++) { - EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; - if (weaponType == EnumWeaponType.GUN) { - weaponType = EnumWeaponType.NONE; - } - int istart = getInventoryStart(weaponType); - if (istart == driveableData.getAmmoInventoryStart()) { - istart += type.numPassengerGunners; - } - final int isize = getInventorySize(weaponType); - if (istart >= 0 || isize > 0) { - if (prevInventoryItems[ps] == null) { - prevInventoryItems[ps] = new ItemStack[isize]; - } - - for (int i = 0; i < isize; i++) { - ItemStack itemStack = driveableData.getStackInSlot(istart + i); - if (itemStack != null && itemStack.getItem() instanceof ItemBullet) { - if (prevInventoryItems[ps][i] == null || !ItemStack.areItemStacksEqual(itemStack, prevInventoryItems[ps][i])) { - if (type.isValidAmmo(((ItemBullet) itemStack.getItem()).type, weaponType)) { - onWeaponInventoryChanged(ps == 1); - break; - } - } - } - } - - for (int i = 0; i < isize; i++) { - prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void onWeaponInventoryChanged(boolean secondary) { - DriveableType type = getDriveableType(); - if (!secondary) { - if (type.reloadTimePrimary > 0 && getShootDelay(secondary) <= 0) { - setShootDelay(type.reloadTimePrimary, secondary); - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().reloadSoundPrimary, false); - } - } else { - if (type.reloadTimeSecondary > 0 && getShootDelay(secondary) <= 0) { - setShootDelay(type.reloadTimeSecondary, secondary); - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().reloadSoundSecondary, false); - } - } - } - - public int getInventoryStart(EnumWeaponType wt) { - switch (wt) { - case NONE: - case GUN: - return driveableData.getAmmoInventoryStart(); - - case MISSILE: - case SHELL: - return driveableData.getMissileInventoryStart(); - - case BOMB: - case MINE: - return driveableData.getBombInventoryStart(); - - default: - break; - } - return -1; - } - - public int getInventorySize(EnumWeaponType wt) { - switch (wt) { - case NONE: - case GUN: - return driveableData.ammo.length; - - case MISSILE: - case SHELL: - return driveableData.missiles.length; - - case BOMB: - case MINE: - return driveableData.bombs.length; - - default: - break; - } - return -1; - } - - public void checkForCollisions() { - boolean damagePart = false; - boolean crashInWater = false; - double speed = getSpeedXYZ(); - for (DriveablePosition p : getDriveableType().collisionPoints) { - if (driveableData.parts.get(p.part).dead) - continue; - Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position); - Vec3 lastPos = Vec3.createVectorHelper(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z); - - Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position); - Vec3 currentPos = Vec3.createVectorHelper(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z); - - if (FlansMod.DEBUG && worldObj.isRemote) { - worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F)); - } - - MovingObjectPosition hit = worldObj.rayTraceBlocks(lastPos, currentPos, crashInWater); - if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { - int x = hit.blockX; - int y = hit.blockY; - int z = hit.blockZ; - Block blockHit = worldObj.getBlock(x, y, z); - int meta = worldObj.getBlockMetadata(x, y, z); - - float blockHardness = blockHit.getBlockHardness(worldObj, x, y, z); - - float damage = 0; - if (blockHardness > 0.2) { - damage = blockHardness * blockHardness * (float) speed; - } - - if (null == blockHit.getCollisionBoundingBoxFromPool(this.worldObj, x, y, z)) { - damage = 0; - } - - if (damage > 0) { - damagePart = true; - if (!attackPart(p.part, DamageSource.inWall, damage) && TeamsManager.driveablesBreakBlocks) { - // And if it didn't die from the attack, break the block - worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(blockHit) + (meta << 12)); - - if (!worldObj.isRemote) { - blockHit.dropBlockAsItem(worldObj, x, y, z, meta, 1); - worldObj.setBlockToAir(x, y, z); - } - } else { - // The part died! - worldObj.createExplosion(this, currentPos.xCoord, currentPos.yCoord, currentPos.zCoord, 1F, - false); - } - } - } - - } - - if (FlansMod.seatCollisions) { - // This is for preventing vehicle glitching. It makes seats collideable, and stops their motion if - for (EntitySeat seat : seats) { - if (seat == null || wheels == null ||wheels[0] == null || wheels[1] == null || seat.riddenByEntity == null) - continue; - DriveablePosition p = seat.getAsDriveablePosition(); - if (driveableData.parts.get(p.part).dead) - continue; - Vector3f fwd = axes.getXAxis(); - float a = 0F; - if (getSpeedXZ() > 1) { - if (getSpeedXZ() > 2) { - a = 6F; - } else { - a = 3F; - } - } - - double checkY = Math.max((wheels[0].posY + wheels[1].posY)/2F + (this instanceof EntityVehicle ? 1.5 : 0), seat.posY); - Vec3 seatPos = Vec3.createVectorHelper(seat.posX + fwd.x * a, checkY + fwd.y * a, seat.posZ + fwd.z * a); - Vec3 wheelMidPos = Vec3.createVectorHelper((wheels[0].posX + wheels[1].posX)/2F, checkY, (wheels[0].posZ + wheels[1].posZ)/2F); - - MovingObjectPosition hit = worldObj.rayTraceBlocks(seatPos, wheelMidPos, crashInWater); - if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { - int x = hit.blockX; - int y = hit.blockY; - int z = hit.blockZ; - Block blockHit = worldObj.getBlock(x, y, z); - - collisionHardness = blockHit.getBlockHardness(worldObj, x, y, z); - } - } - } - - if (damagePart) { - //This is server side bsns - if (!worldObj.isRemote) { -// checkParts(); - //If it hit, send a damage update packet - FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); - } - } - } - - @Override - protected void fall(float k) { - double fallDist = ((this.posY - this.prevPosY) + this.motionY) / 2; - float damage = (float) (fallDist < -0.3 ? -fallDist * 50 : 0); - - boolean noDamage = true; - if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20) { - DriveableType type = getDriveableType(); - damage = (int) (damage * type.fallDamageFactor); - attackPart(EnumDriveablePart.core, DamageSource.fall, damage); - if (type.wheelPositions.length > 0) { - attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5); - } - - noDamage = false; - } - // FlansMod.log("fall%s : tick=%d damage=%.1f, posY-prevPosY=%.3f, mY=%.3f, fallDist=%.2f", - // noDamage? " no damage":"", this.ticksExisted, damage, this.posY - this.prevPosY, - // this.motionY, fallDist); - } - - /** - * Attack a certain part of a driveable and return whether it broke or not - */ - public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage) { - if (ep == EnumDriveablePart.core) { - if (source.getSourceOfDamage() instanceof EntityLivingBase) { - this.lastAtkEntity = source.getSourceOfDamage(); - } else if (source.getEntity() instanceof EntityLivingBase) { - this.lastAtkEntity = source.getEntity(); - } else { - this.lastAtkEntity = null; - } - } - DriveablePart part = driveableData.parts.get(ep); - // FlansMod.log("EntityDriveable.attackPart %s : %s : damage=%.1f : %s : health=%d", ep.name(), ep.getName(), damage, - // part.type.name(), part.health); - return part.attack(damage, source.isFireDamage()); - } - - /** - * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates - */ - public Vector3f rotate(Vector3f inVec) { - return axes.findLocalVectorGlobally(inVec); - } - - /** - * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates - */ - public Vector3f rotate(Vec3 inVec) { - return rotate(inVec.xCoord, inVec.yCoord, inVec.zCoord); - } - - /** - * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates - */ - public Vector3f rotate(double x, double y, double z) { - return rotate(new Vector3f((float) x, (float) y, (float) z)); - } - - //Rotate the plane locally by some angle about the yaw axis - public void rotateYaw(float rotateBy) { - if (Math.abs(rotateBy) < 0.01F) - return; - axes.rotateLocalYaw(rotateBy); - updatePrevAngles(); - } - - //Rotate the plane locally by some angle about the pitch axis - public void rotatePitch(float rotateBy) { - if (Math.abs(rotateBy) < 0.01F) - return; - axes.rotateLocalPitch(rotateBy); - updatePrevAngles(); - } - - //Rotate the plane locally by some angle about the roll axis - public void rotateRoll(float rotateBy) { - if (Math.abs(rotateBy) < 0.01F) - return; - axes.rotateLocalRoll(rotateBy); - updatePrevAngles(); - } - - public void updatePrevAngles() { - //Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick. - double dYaw = axes.getYaw() - prevRotationYaw; - if (dYaw > 180) - prevRotationYaw += 360F; - if (dYaw < -180) - prevRotationYaw -= 360F; - - double dPitch = axes.getPitch() - prevRotationPitch; - if (dPitch > 180) - prevRotationPitch += 360F; - if (dPitch < -180) - prevRotationPitch -= 360F; - - double dRoll = axes.getRoll() - prevRotationRoll; - if (dRoll > 180) - prevRotationRoll += 360F; - if (dRoll < -180) - prevRotationRoll -= 360F; - } - - public void setRotation(float rotYaw, float rotPitch, float rotRoll) { - axes.setAngles(rotYaw, rotPitch, rotRoll); - } - - //Used to stop self collision - public boolean isPartOfThis(Entity ent) { - for (EntitySeat seat : seats) { - if (seat == null) - continue; - if (ent == seat) - return true; - if (seat.riddenByEntity == ent) - return true; - } - return ent == this; - } - - @Override - public float getShadowSize() { - return 0.0F; - } - - public DriveableType getDriveableType() { - return DriveableType.getDriveable(driveableType); - } - - public DriveableData getDriveableData() { - return driveableData; - } - - @Override - public boolean isDead() { - return isDead; - } - - @Override - public Entity getControllingEntity() { - return seats[0].getControllingEntity(); - } - - @Override - public ItemStack getPickedResult(MovingObjectPosition target) { - ItemStack stack = new ItemStack(getDriveableType().item, 1, 0); - stack.stackTagCompound = new NBTTagCompound(); - driveableData.writeToNBT(stack.stackTagCompound); - return stack; - } - - public boolean hasEnoughFuel() { - //if (seats == null || seats[0] == null || seats[0].riddenByEntity == null) - //return false; - return driverIsCreative() || driveableData.fuelInTank > Math.abs(driveableData.engine.fuelConsumption * throttle) || getDriveableType().fuelTankSize < 0; - } - - //Physics time! Oooh yeah - - public double getSpeedXYZ() { - return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); - } - - public double getSpeedXZ() { - return Math.sqrt(motionX * motionX + motionZ * motionZ); - } - - public double getHackySpeedXYZ() { - double dx = (posX - lastTickPosX); - double dy = (posY - lastTickPosY); - double dz = (posZ - lastTickPosZ); - return Math.sqrt(dx * dx + dy * dy + dz * dz); - // Blocks per tick. - } - - /** - * To be overriden by vehicles to get alternate collision system - */ - public boolean landVehicle() { - return false; - } - - /** - * Overriden by planes for wheel parts - */ - public boolean gearDown() { - return true; - } - - /** - * Whether or not the plane is on the ground - * TODO : Replace with proper check based on wheels - */ - public boolean onGround() { - return onGround; - } - - - //Collision mechanism mkII - @SuppressWarnings("unused") - public void moveRiders(Entity rider) { - if (isPartOfThis(rider)) return; - boolean isHuman = false; - boolean isDriveable = false; - if (!(rider instanceof EntityPlayer)) return; - - - Vector3f riderPos = new Vector3f(rider.posX, rider.posY, rider.posZ); - Vector3f riderMotion = new Vector3f(rider.motionX, rider.motionY, rider.motionY); - Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); - if (rider instanceof EntityVehicle) vehicleMotion = ((EntityVehicle) rider).lastPos; - //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); - Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); - Vector3f relativePos = Vector3f.sub(riderPos, vehiclePos, null); - if (rider instanceof EntityPlayer) isHuman = true; - if (rider instanceof EntityDriveable) isDriveable = true; - relativePos = new Vector3f(relativePos.x, relativePos.y - ((isHuman) ? 0.55F : 0), relativePos.z); - - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); - Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(riderMotion); - - Vector3f ellipsoid = new Vector3f(rider.width / 2, rider.height, rider.width / 2); - - CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), riderMotion); - test.collisionRecursiveDepth = 0; - - Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); - Vector3f eSpaceVelocity = test.velocity; - - //Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); - DriveableType type = getDriveableType(); - //Check parts for collision - if (type.fancyCollision) { - //checkCollision(test, getDriveableType().colbox); - for (CollisionShapeBox sbox : type.collisionBox) { - checkCollision(test, sbox); - } - } else { - for (DriveablePart ppart : getDriveableData().parts.values()) { - ppart.rayTraceRider(this, test); - } - } - - if (test.didCollide) { - Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); - - if (finalPos == null) { - finalPos = new Vector3f(0, 0, 0); - if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [1]"); - } - - Vector3f velocity = Vector3f.sub(finalPos, test.basePoint, null); - test.ConvertESpaceToR3(velocity); - finalPos = new Vector3f(finalPos.x * test.eRad.x, finalPos.y * test.eRad.y, finalPos.z * test.eRad.z); - // TODO: Better way to check this - if (finalPos == null) { - finalPos = new Vector3f(0, 0, 0); - if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [2]"); - } - Vector3f diff = Vector3f.sub(finalPos, vehiclePos, null); - - - if (rider.onGround && (posY + finalPos.y + 10 / 16F) < riderPos.y) { - //finalPos = new Vector3f(finalPos.x, 0, finalPos.z); - } - //boolean onTop = (rider.posY + 0.65 > test.intersectionPoint.y); - - boolean stationary = (throttle == 0); - - //If finalPos returns null, do something about it. Probably not the best way to handle this. - //if(finalPos == null) finalPos = new Vector3f(0,0,0); - - test.ConvertESpaceToR3(finalPos); - boolean onTop = (test.collisionPlaneNormal.y >= 0.5F); - if (posY + finalPos.y + 10 / 16F < riderPos.y) finalPos.y = (riderPos.y - (float) posY - 10F / 16F); - if (!hugeBoat) - rider.setPosition((!onTop) ? riderPos.x + finalPos.x / (48 * Math.abs(relativePos.x)) : riderPos.x, (onTop) ? posY + finalPos.y + 10 / 16F : riderPos.y, (!onTop) ? riderPos.z + finalPos.z / (48 * Math.abs(relativePos.z)) : riderPos.z); - //test.ConvertESpaceToR3(test.intersectionPoint); - //FlansMod.proxy.spawnParticle("flame", test.intersectionPoint.x + posX, test.intersectionPoint.y + posY - 1, test.intersectionPoint.z + posZ, 0, 0, 0); - - if (hugeBoat && !stationary) { - rider.setPosition(riderPos.x, posY + finalPos.y + 9.5 / 16F, riderPos.z); - } else if (hugeBoat && stationary) { - rider.setPosition(riderPos.x, posY + finalPos.y + 10 / 16F, riderPos.z); - } - finalPos = Vector3f.sub(finalPos, riderPos, null); - finalPos.normalise(); - - //rider.motionX = rider.motionX * finalPos.x; - rider.motionY = 0; - //rider.motionZ = rider.motionZ * finalPos.z; - - - //Vector3f intersect = test.intersectionPoint; - //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX + intersect.x, posY + intersect.y, posZ + intersect.z, 0,1,0); - //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX, posY, posZ, 0,1,0); - //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", riderPos.x, riderPos.y, riderPos.z, 0,1,0); - - //worldObj.spawnParticle("crit", posX + finalPos.x, posY + finalPos.y, posZ + finalPos.z, 0,0,0); - //worldObj.spawnParticle("reddust", riderPos.x, riderPos.y - 0.65, riderPos.z, 0,0,0); - - - updateRiderPos(rider, test, finalPos, riderMotion); - - if (getDriveableType().collisionDamageEnable && !test.isOnTop) { - if (throttle > getDriveableType().collisionDamageThrottle) { - boolean canDamage = true; - if (TeamsManager.getInstance() != null && TeamsManager.getInstance().currentRound != null && rider instanceof EntityPlayerMP && seats[0].riddenByEntity instanceof EntityPlayer) { - EntityPlayerMP attacker = (EntityPlayerMP) seats[0].riddenByEntity; - EntityPlayerMP player = (EntityPlayerMP) rider; - if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team != null) { - if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team != null) { - if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team == TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team) { - canDamage = false; - } - } - } - } - for (EntitySeat seat : seats) { - if (rider == seat.lastRiddenByEntity) { - canDamage = false; - break; - } - } - - if (canDamage) { - if (rider instanceof EntityLiving) { - rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } else if (rider instanceof EntityPlayer) { - rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } - } - } - } - if (rider instanceof EntityPlayer) { - EntityPlayer player = (EntityPlayer) rider; - //playerIDs.add(player); - player.onGround = true; - player.isAirBorne = false; - player.fallDistance = 0; - } - - } else { - if (rider instanceof EntityDriveable) { - //((EntityDriveable)rider).onDeck = false; - ((EntityDriveable) rider).deckHeight = 0; - } - } - - - } - - /** - * @SubscribeEvent public void updateRiders(LivingUpdateEvent event){ - *

- * for(EntityPlayer player: playerIDs){ - * Entity p = (Entity)player; - * if(p == event.entity){ - * player.onGround = true; - * player.isAirBorne = false; - * player.fallDistance = 0; - * playerIDs.remove(player); - * } - * } - * } - */ - - public DamageSource getBulletDamage(boolean headshot) { - DriveableType type = getDriveableType(); - EntityLivingBase owner = (EntityLivingBase) seats[0].riddenByEntity; - if (owner instanceof EntityPlayer) - return (new EntityDamageSourceFlans(getDriveableType().shortName, this, (EntityPlayer) owner, type, headshot, false)).setProjectile(); - else return (new EntityDamageSourceIndirect(type.shortName, this, owner)).setProjectile(); - } - - public void checkCollision(CollisionTest tester, CollisionShapeBox box) { - { - double distance = tester.nearestDistance; - Vector3f collisionPoint = new Vector3f(0, 0, 0); - int surface = 0; - - Vector3f pos = new Vector3f(this.posX, this.posY, this.posZ); - - RotatedAxes shift = axes; - - float f4 = box.pos.x + box.size.x; - float f5 = -box.pos.y + box.size.y; - float f6 = box.pos.z + box.size.z; - - box.pos = new Vector3f(box.pos.x, box.pos.y, box.pos.z); - //if(EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret) return; - //Define box verticies, where z > 0 is right. See shapeboxes in the toolbox for a visual reference - Vector3f p1 = new Vector3f(box.pos.x - box.p1.x, box.pos.y + box.size.y + box.p1.y - box.size.y + 0.625F, box.pos.z - box.p1.z); - Vector3f p2 = new Vector3f(box.pos.x + box.size.x + box.p2.x, box.pos.y + box.size.y + box.p2.y - box.size.y + 0.625F, box.pos.z - box.p2.z); - Vector3f p3 = new Vector3f(box.pos.x + box.size.x + box.p3.x, box.pos.y + box.size.y + box.p3.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p3.z); - Vector3f p4 = new Vector3f(box.pos.x - box.p4.x, box.pos.y + box.size.y + box.p4.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p4.z); - Vector3f p5 = new Vector3f(box.pos.x - box.p5.x, box.pos.y - box.p5.y - box.size.y + 0.625F, box.pos.z - box.p5.z); - Vector3f p6 = new Vector3f(box.pos.x + box.size.x + box.p6.x, box.pos.y - box.p6.y - box.size.y + 0.625F, box.pos.z - box.p6.z); - Vector3f p7 = new Vector3f(box.pos.x + box.size.x + box.p7.x, box.pos.y - box.p7.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p7.z); - Vector3f p8 = new Vector3f(box.pos.x - box.p8.x, box.pos.y - box.p8.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p8.z); - - if (EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret && seats[0] != null) { - p1 = getPositionOnTurret(p1, false); //Front upper left - p2 = getPositionOnTurret(p2, false); //Front upper right - p3 = getPositionOnTurret(p3, false); //Rear upper right - p4 = getPositionOnTurret(p4, false); //Rear upper left - p5 = getPositionOnTurret(p5, false); //Front lower left - p6 = getPositionOnTurret(p6, false); //Front lower right - p7 = getPositionOnTurret(p7, false); //Rear lower right - p8 = getPositionOnTurret(p8, false); //Rear lower left - } else { - p1 = shift.findLocalVectorGlobally(p1); - p2 = shift.findLocalVectorGlobally(p2); - p3 = shift.findLocalVectorGlobally(p3); - p4 = shift.findLocalVectorGlobally(p4); - p5 = shift.findLocalVectorGlobally(p5); - p6 = shift.findLocalVectorGlobally(p6); - p7 = shift.findLocalVectorGlobally(p7); - p8 = shift.findLocalVectorGlobally(p8); - } - - - //Check top face - double topFaceDist = 100; - - tester.checkTriangle(tester, p3, p2, p1); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); - } - - tester.checkTriangle(tester, p4, p3, p1); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); - } - - if (tester.didCollide) { - tester.isOnTop = true; - topFaceDist = tester.nearestDistance; - } - - //Check front face - tester.checkTriangle(tester, p6, p7, p3); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 2; - tester.part = EnumDriveablePart.getPart(box.part); - } - tester.checkTriangle(tester, p3, p2, p6); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 2; - tester.part = EnumDriveablePart.getPart(box.part); - } - - - //Check rear face - tester.checkTriangle(tester, p4, p1, p5); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 3; - tester.part = EnumDriveablePart.getPart(box.part); - } - tester.checkTriangle(tester, p5, p8, p4); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 3; - tester.part = EnumDriveablePart.getPart(box.part); - } - - //Check Left Face - tester.checkTriangle(tester, p6, p5, p1); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 4; - tester.part = EnumDriveablePart.getPart(box.part); - } - tester.checkTriangle(tester, p1, p2, p6); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 4; - tester.part = EnumDriveablePart.getPart(box.part); - } - - //Check right face - tester.checkTriangle(tester, p8, p7, p3); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 5; - tester.part = EnumDriveablePart.getPart(box.part); - } - tester.checkTriangle(tester, p3, p4, p8); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 5; - tester.part = EnumDriveablePart.getPart(box.part); - } - - //Check bottom face - tester.checkTriangle(tester, p5, p6, p7); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); - } - - tester.checkTriangle(tester, p8, p7, p5); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); - } - - if (tester.didCollide) { - tester.isOnTop = true; - topFaceDist = tester.nearestDistance; - } - - Vector3f.add(p1, pos, p1); - Vector3f.add(p2, pos, p2); - Vector3f.add(p3, pos, p3); - Vector3f.add(p4, pos, p4); - Vector3f.add(p5, pos, p5); - Vector3f.add(p6, pos, p6); - Vector3f.add(p7, pos, p7); - Vector3f.add(p8, pos, p8); - - String particleType = "crit"; - - - if (FlansMod.DEBUG) { - FlansMod.proxy.spawnParticle(particleType, p1.x, p1.y, p1.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p2.x, p2.y, p2.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p3.x, p3.y, p3.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p4.x, p4.y, p4.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p5.x, p5.y, p5.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p6.x, p6.y, p6.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p7.x, p7.y, p7.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p8.x, p8.y, p8.z, 0, 0, 0); - - renderTri(p1, p2, p3); - renderTri(p3, p4, p1); - } - - if (tester.nearestDistance < topFaceDist) tester.isOnTop = false; - - - if (surface == 1) tester.isOnTop = true; - } - - } - - public void renderTri(Vector3f p1, Vector3f p2, Vector3f p3) { - Vector3f pos = new Vector3f(posX, posY, posZ); - Vector3f p1a = Vector3f.add(p1, pos, null); - Vector3f p2a = Vector3f.add(p2, pos, null); - Vector3f p3a = Vector3f.add(p3, pos, null); - - renderLine(p1a, p2a); - renderLine(p2a, p3a); - renderLine(p3a, p1a); - } - - public void renderLine(Vector3f in, Vector3f out) { - float dx = out.x - in.x; - float dy = out.y - in.y; - float dz = out.z - in.z; - Vector3f diff = Vector3f.sub(out, in, null); - diff.normalise(); - float distance = (float) Math.sqrt((dx * dx) + (dy * dy) + (dz * dz)); - for (int i = 0; i < 10; i++) { - float dist2 = (distance / 10) * i; - Vector3f newVec = new Vector3f(in.x + (dist2 * diff.x), in.y + (dist2 * diff.y), in.z + (dist2 * diff.z)); - FlansMod.proxy.spawnParticle("reddust", newVec.x, newVec.y, newVec.z, 0, 0, 0); - } - } - - - public Vector3f collideWithDriveable(CollisionTest tester, Vector3f Pos, Vector3f vel) { - float unitScale = 1 / 16F; - float veryCloseDistance = 0.005F * unitScale; - - if (tester.collisionRecursiveDepth > 2) return Pos; - - tester.basePoint = Pos; - tester.didCollide = false; - - if (getDriveableType().fancyCollision) { - //checkCollision(tester, getDriveableType().colbox); - for (CollisionShapeBox sbox : getDriveableType().collisionBox) { - checkCollision(tester, sbox); - } - } else { - for (DriveablePart ppart : getDriveableData().parts.values()) { - ppart.rayTraceRider(this, tester); - } - } - - //If no collision, we just move along the velocity - if (tester.didCollide = false) return Vector3f.add(Pos, vel, null); - - - //Collision occurred, time to sort this out - Vector3f destinationPoint = Vector3f.add(Pos, vel, null); - Vector3f newBasePoint = Pos; - - if (tester.nearestDistance >= veryCloseDistance) { - vel.normalise(); - vel.scale((float) (tester.nearestDistance - veryCloseDistance)); - newBasePoint = Vector3f.add(tester.basePoint, vel, null); - - if (vel.normalise().equals(new Vector3f(0, 0, 0))) return Vector3f.add(Pos, vel, null); - - vel.normalise(); - - //Change polygon intersection point so that the sliding plane is unaffected by the fact we move slightly less than collision tells us - Vector3f.sub(tester.intersectionPoint, new Vector3f(vel.x * veryCloseDistance, vel.y * veryCloseDistance, vel.z * veryCloseDistance), tester.intersectionPoint); - } - - //Determine the sliding plane - Vector3f slidePlaneOrigin = tester.intersectionPoint; - if (tester.intersectionPoint == null) return Vector3f.add(Pos, vel, null); - Vector3f slidePlaneNormal = Vector3f.sub(newBasePoint, tester.intersectionPoint, null); - slidePlaneNormal.normalise(); - - tester.collisionPlaneNormal = slidePlaneNormal; - CollisionPlane plane = new CollisionPlane(slidePlaneOrigin, slidePlaneNormal); - - double sDV = plane.signedDistanceTo(destinationPoint); - Vector3f scaledNormal = new Vector3f(slidePlaneNormal.x * sDV, slidePlaneNormal.y * sDV, slidePlaneNormal.z * sDV); - Vector3f newDestPoint = Vector3f.sub(destinationPoint, scaledNormal, null); - - //Generate slide vector - Vector3f newVelocityVector = Vector3f.sub(newDestPoint, tester.intersectionPoint, null); - - if (newVelocityVector.length() < veryCloseDistance) { - return newBasePoint; - } - - tester.collisionRecursiveDepth++; - - return collideWithDriveable(tester, newBasePoint, newVelocityVector); - } - - @SuppressWarnings("unused") - public void updateRiderPos(Entity rider, CollisionTest test, Vector3f pos, Vector3f motion) { - boolean isDriveable = rider instanceof EntityDriveable; - Vector3f vehicleMotion = lastPos; - - Vector3f riderMountPoint = new Vector3f(rider.posX - posX, rider.posY - posY, rider.posZ - posZ); - - float yawDiff = axes.getYaw() - prevAxes.getYaw(); - float pitchDiff = axes.getPitch() - prevAxes.getPitch(); - float rollDiff = axes.getRoll() - prevAxes.getRoll(); - - RotatedAxes velAxes = new RotatedAxes(axes.getYaw() + yawDiff, axes.getPitch() + pitchDiff, axes.getRoll() + rollDiff); - - Vector3f currentLocalPos = axes.findGlobalVectorLocally(riderMountPoint); - Vector3f nextGlobalPos = velAxes.findLocalVectorGlobally(currentLocalPos); - - Vector3f diff = new Vector3f(0, 0, 0); - - //Some rubbish null checks - if (nextGlobalPos == null) nextGlobalPos = new Vector3f(0, 0, 0); - - Vector3f.add(vehicleMotion, diff, diff); - rider.setPosition(nextGlobalPos.x + posX + ((hugeBoat) ? diff.x / (1.5) : 0), (!isDriveable) ? rider.posY : ((EntityDriveable) rider).deckHeight, nextGlobalPos.z + posZ + ((hugeBoat) ? diff.z / (1.5) : 0)); - - - if (hugeBoat) { - if (lastPos.x == 0 && lastPos.y == 0 && lastPos.z == 0) { - if (rider.motionY < 0) rider.motionY = 0; - } - } else { - if (lastPos.x != 0 || lastPos.y != 0 || lastPos.z != 0) { - rider.motionX = diff.x; - rider.motionY = diff.y; - rider.motionZ = diff.z; - } - } - } - - /** - * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit - */ - public ArrayList attackFromBullet(Vector3f origin, Vector3f motion) { - //Make an array to contain the hits - ArrayList hits = new ArrayList(); - //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates - Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); - Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); - //Check each part - for (DriveablePart part : getDriveableData().parts.values()) { - //Ray trace the bullet - DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector); - if (hit != null) - hits.add(hit); - } - return hits; - } - - /** - * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit - */ - public ArrayList attackFromBulletButBetter(Vector3f origin, Vector3f motion, float size) { - ArrayList hits = new ArrayList(); - - - Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); - //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); - Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); - Vector3f relativePos = Vector3f.sub(origin, vehiclePos, null); - - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); - Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(motion); - - Vector3f ellipsoid = new Vector3f(size, size, size); - - CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), motion); - test.collisionRecursiveDepth = 0; - - Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); - Vector3f eSpaceVelocity = test.velocity; - - for (DriveablePart ppart : getDriveableData().parts.values()) { - ppart.rayTraceRider(this, test); - } - - if (test.didCollide) { - Vector3f hitPos = new Vector3f(0, 0, 0); - Vector3f intersect2 = new Vector3f(test.ConvertESpaceToR3(test.intersectionPoint)); - Vector3f.sub(origin, intersect2, hitPos); - float f = (hitPos.length() / motion.length()); - DriveableHit hit = new DriveableHit(this, test.part, f); - hits.add(hit); - } - - return hits; - - } - - /** - * Called if the bullet actually hit the part returned by the raytrace - * - * @param penetratingPower - */ - public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower) { - DriveablePart part = getDriveableData().parts.get(hit.part); - if (bullet != null) - penetratingPower = part.hitByBullet(bullet, hit, penetratingPower); - else - penetratingPower -= 5F; - - //This is server side bsns - if (!worldObj.isRemote) { - checkParts(); - //If it hit, send a damage update packet - if(part.type.equals(EnumDriveablePart.core) && part.dead){ - if(TeamsManager.instance.currentRound!=null) - TeamsManager.instance.currentRound.gametype.vehicleDestroyed(part.owner, bullet); - } - FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); - } - - return penetratingPower; - } - - /** - * A simple raytracer for the driveable. Called by tools - */ - public DriveablePart raytraceParts(Vector3f origin, Vector3f motion) { - //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates - Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); - Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); - //Check each part - for (DriveablePart part : getDriveableData().parts.values()) { - //Ray trace the bullet - if (part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null) { - return part; - } - } - return null; - } - - /** - * For overriding for toggles such as gear up / down on planes - */ - public boolean canHitPart(EnumDriveablePart part) { + public boolean shouldAutobalance() { return true; } - - /** - * Internal method for checking that all parts are ok, destroying broken ones, dropping items and making sure that child parts are destroyed when their parents are - */ - public void checkParts() { - for (DriveablePart part : getDriveableData().parts.values()) { - if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { - killPart(part); - } - } - - //If the core was destroyed, kill the driveable - if (getDriveableData().parts.get(EnumDriveablePart.core).dead) { - int seatNum = seats.length; - - DriveableType type = getDriveableType(); - - if (!worldObj.isRemote) { - for (EntitySeat seat : seats) { - if (seat.riddenByEntity instanceof EntityPlayer) { -// ((EntityPlayer)seats[i].riddenByEntity).addPotionEffect(new PotionEffect(Potion.harm.id, 10, 5)); - Entity entity = seat.riddenByEntity; - seat.riddenByEntity.setInvisible(false); - seat.riddenByEntity.mountEntity(null); - if (this.lastAtkEntity instanceof EntityPlayer) { - entity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) this.lastAtkEntity), 10000000); - } else if (this.lastAtkEntity instanceof EntityLivingBase) { - entity.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) this.lastAtkEntity), 10000000); - } - } - } - - if (type.isExplosionWhenDestroyed) -//Create a flans mod explosion rather than a standard MC one. allows control over death boom - { - new FlansModExplosion(worldObj, this, null, type, posX, posY, posZ, - type.deathExplosionRadius, type.deathExplosionPower,TeamsManager.explosions && type.deathExplosionBreaksBlocks, - type.deathExplosionDamageVsLiving, type.deathExplosionDamageVsPlayer, type.deathExplosionDamageVsPlane, type.deathExplosionDamageVsVehicle, seatNum, seatNum); - - } - if(!worldObj.isRemote && type.deathFireRadius > 0.1F) - { - for(float i = -type.deathFireRadius; i < type.deathFireRadius; i++) - { - for(float j = -type.deathFireRadius; j < type.deathFireRadius; j++) - { - for(float k = -type.deathFireRadius; k < type.deathFireRadius; k++) - { - int x = MathHelper.floor_double(i + posX); - int y = MathHelper.floor_double(j + posY); - int z = MathHelper.floor_double(k + posZ); - if(i * i + j * j + k * k <= type.deathFireRadius * type.deathFireRadius && worldObj.getBlock(x, y, z) == Blocks.air && rand.nextBoolean()) - { - worldObj.setBlock(x, y, z, Blocks.fire, 0, 3); - } - } - } - } - } - - for (DriveablePart part : driveableData.parts.values()) { - if (part.health > 0 && !part.dead) - killPart(part); - } - } - setDead(); - - } - - } - - public void checkPartsWhenAttacked() { - for (DriveablePart part : getDriveableData().parts.values()) { - if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { - killPart(part); - } - } - } - - /** - * Internal method for killing driveable parts - */ - private void killPart(DriveablePart part) { - if (part.dead) - return; - part.health = 0; - part.dead = true; - - //Drop items - DriveableType type = getDriveableType(); - if (!worldObj.isRemote) { - Vector3f pos = new Vector3f(0, 0, 0); - - //Get the midpoint of the part - if (part.box != null) - pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); - - ArrayList drops = type.getItemsRequired(part, getDriveableData().engine); - if (drops != null) { - //Drop each ItemStack - for (ItemStack stack : drops) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy())); - } - } - dropItemsOnPartDeath(pos, part); - - //Inventory is in the core, so drop it if the core is broken - if (part.type == EnumDriveablePart.core) { - for (int i = 0; i < getDriveableData().getSizeInventory(); i++) { - ItemStack stack = getDriveableData().getStackInSlot(i); - if (stack != null) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack)); - } - } - } - } - - //Kill all child parts to stop things floating unconnected - for (EnumDriveablePart child : part.type.getChildren()) { - killPart(getDriveableData().parts.get(child)); - } - } - - /** - * Method for planes, vehicles and whatnot to drop their own specific items if they wish - */ - protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part); - - @Override - public float getPlayerRoll() { - return axes.getRoll(); - } - - @Override - public void explode() { - - } - - @Override - public float getCameraDistance() { - return getDriveableType().cameraDistance; - } - - public boolean isPartIntact(EnumDriveablePart part) { - DriveablePart thisPart = getDriveableData().parts.get(part); - return thisPart.maxHealth == 0 || thisPart.health > 0; - } - - public abstract boolean hasMouseControlMode(); - - public abstract String getBombInventoryName(); - - public abstract String getMissileInventoryName(); - - public boolean rotateWithTurret(Seat seat) { - return seat.part == EnumDriveablePart.turret; - } - - @Override - public String getCommandSenderName() { - return getDriveableType().name; - } - - @SideOnly(Side.CLIENT) - public boolean showInventory(int seat) { - return seat != 0 || !FlansModClient.controlModeMouse; - } - - //------------------------------------- - // Getters and setters for dual fields - //------------------------------------- - - public float getShootDelay(boolean secondary) { - return secondary ? shootDelaySecondary : shootDelayPrimary; - } - - public boolean canLaunchIT1() { - return canFireIT1; - } - - public float getMinigunSpeed(boolean secondary) { - return secondary ? minigunSpeedSecondary : minigunSpeedPrimary; - } - - public int getCurrentGun(boolean secondary) { - return secondary ? currentGunSecondary : currentGunPrimary; - } - - public void setShootDelay(float i, boolean secondary) { - setRecoilTimer(); - // If current delay is greater than i, use that. If current delay is less than 0, add that to new shoot delay - if (secondary) - shootDelaySecondary = i > shootDelaySecondary ? (shootDelaySecondary < 0 ? i + shootDelaySecondary : i) : shootDelaySecondary; - else - shootDelayPrimary = i > shootDelayPrimary ? (shootDelayPrimary < 0 ? i + shootDelayPrimary : i) : shootDelayPrimary; - } - - public void setMinigunSpeed(float f, boolean secondary) { - if (secondary) - minigunSpeedSecondary = f; - else minigunSpeedPrimary = f; - } - - public void setCurrentGun(int i, boolean secondary) { - if (secondary) - currentGunSecondary = i; - else currentGunPrimary = i; - } - - public void setEntityMarker(int tick) { - this.isShowedPosition = true; - this.tickCount = tick; - } - - public void IT1Reload() { - DriveableType type = getDriveableType(); - - - if (stage == 1) { - //canFireIT1 = false; - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 5); - - if (drakonRailAngle == -10) stage++; - } - - - if (stage == 2) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonDoorAngle == -90) stage++; - } - - if (stage == 3) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 179, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonArmAngle == 179) stage++; - } - - if (stage == 4) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonDoorAngle == 0) { - if (IT1Loaded()) { - stage++; - reloadAnimTime = 60; - } - } - } - - if (stage == 5) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - reloadingDrakon = true; - - if (drakonDoorAngle == -90) stage++; - } - - if (stage == 6) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonArmAngle == 0) stage++; - } - - if (stage == 7) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, 0, 1); - - if (drakonRailAngle == 0 && drakonDoorAngle == 0) { - stage++; - canFireIT1 = true; - reloadingDrakon = false; - } - } - - if (stage == 8) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - if (worldObj.isRemote && this.ticksExisted > 2) - drakonRailAngle = moveToTarget(drakonRailAngle, -seats[0].looking.getPitch(), seats[0].seatInfo.aimingSpeed.y); - //reloadAnimTime = 60; - - if (!IT1Loaded()) { - stage = 1; - canFireIT1 = false; - } - } - } - - public float moveToTarget(float current, float target, float speed) { - - float pitchToMove = (float) ((Math.sqrt(target * target)) - Math.sqrt((current * current))); - for (; pitchToMove > 180F; pitchToMove -= 360F) { - } - for (; pitchToMove <= -180F; pitchToMove += 360F) { - } - - float signDeltaY = 0; - if (pitchToMove > speed) { - signDeltaY = 1; - } else if (pitchToMove < -speed) { - signDeltaY = -1; - } else { - signDeltaY = 0; - return target; - } - - - if (current > target) { - current = current - speed; - } else if (current < target) { - current = current + speed; - } - - return current; - } - - public boolean IT1Loaded() { - DriveableType type = getDriveableType(); - boolean loaded = false; - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.MISSILE)) { - loaded = true; - } - } - - return loaded; - } - - public void tryRecoil() { - int slot = -1; - DriveableType type = getDriveableType(); - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { - slot = i; - } - } - - if (recoilTimer <= 0 && slot != -1) - isRecoil = true; - } - - public void setRecoilTimer() { - int slot = -1; - DriveableType type = getDriveableType(); - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { - slot = i; - } - } - - if (recoilTimer <= 0 && slot != -1) - recoilTimer = (int) getDriveableType().shootDelayPrimary; - } - - @Override - public boolean isInRangeToRenderDist(double d) { - double d1 = this.renderDistanceWeight; - return d < d1 * d1; - } - - // Returns if the bounding box is under the - public boolean isUnderWater() { - return worldObj.isAnyLiquid(this.boundingBox.copy().offset(0, getDriveableType().maxDepth, 0)); - } } - From 41245367b7eddebf8ae2750826ddd055e7a8c62c Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 16:32:15 +0200 Subject: [PATCH 08/25] big minigames update. part 1 handling destroying vehicles by all --- .../common/driveables/EntityVehicle.java | 3611 ++++++++++++----- 1 file changed, 2532 insertions(+), 1079 deletions(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityVehicle.java b/src/main/java/com/flansmod/common/driveables/EntityVehicle.java index 7e815bab..9d9916d1 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityVehicle.java +++ b/src/main/java/com/flansmod/common/driveables/EntityVehicle.java @@ -1,1349 +1,2802 @@ package com.flansmod.common.driveables; +import cofh.api.energy.IEnergyContainerItem; +import com.flansmod.api.IControllable; import com.flansmod.api.IExplodeable; -import com.flansmod.client.model.AnimTankTrack; -import com.flansmod.client.model.AnimTrackLink; +import com.flansmod.client.EntityCamera; +import com.flansmod.client.FlansModClient; +import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.common.FlansMod; -import com.flansmod.common.PlayerData; -import com.flansmod.common.PlayerHandler; import com.flansmod.common.RotatedAxes; -import com.flansmod.common.driveables.VehicleType.SmokePoint; -import com.flansmod.common.network.PacketDriveableKey; +import com.flansmod.common.driveables.DriveableType.ParticleEmitter; +import com.flansmod.common.driveables.DriveableType.ShootParticle; +import com.flansmod.common.driveables.collisions.CollisionPlane; +import com.flansmod.common.driveables.collisions.CollisionShapeBox; +import com.flansmod.common.driveables.collisions.CollisionTest; +import com.flansmod.common.driveables.mechas.EntityMecha; +import com.flansmod.common.guns.*; +import com.flansmod.common.guns.raytracing.BulletHit; +import com.flansmod.common.guns.raytracing.DriveableHit; +import com.flansmod.common.network.PacketDriveableDamage; +import com.flansmod.common.network.PacketDriveableKeyHeld; import com.flansmod.common.network.PacketParticle; import com.flansmod.common.network.PacketPlaySound; -import com.flansmod.common.network.PacketVehicleControl; -import com.flansmod.common.teams.Team; +import com.flansmod.common.parts.ItemPart; +import com.flansmod.common.parts.PartType; import com.flansmod.common.teams.TeamsManager; -import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Vector3f; +import cpw.mods.fml.common.network.ByteBufUtils; +import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; -import net.minecraft.client.Minecraft; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.passive.EntityBat; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.*; +import net.minecraft.util.MovingObjectPosition.MovingObjectType; import net.minecraft.world.World; -import java.util.List; +import java.util.ArrayList; +public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData { + public boolean syncFromServer = true; + /** + * Ticks since last server update. Use to smoothly transition to new position + */ + public int serverPositionTransitionTicker; + /** + * Server side position, as synced by PacketVehicleControl packets + */ + public double serverPosX, serverPosY, serverPosZ; + /** + * Server side rotation, as synced by PacketVehicleControl packets + */ + public double serverYaw, serverPitch, serverRoll; + + /** + * The driveable data which contains the inventory, the engine and the fuel + */ + public DriveableData driveableData; + /** + * The shortName of the driveable type, used to obtain said type + */ + public String driveableType; + + /** + * The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to obtain the thrust + */ + public float throttle; + /** + * The wheels on this plane + */ + public EntityWheel[] wheels; -public class EntityVehicle extends EntityDriveable implements IExplodeable { + public boolean fuelling; /** - * Weapon delays + * Extra prevRotation field for smoothness in all 3 rotational axes */ - public int shellDelay, gunDelay; + public float prevRotationRoll; /** - * Position of looping sounds + * Angular velocity */ - public int soundPosition; - public int idlePosition; + public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F); + /** - * Front wheel yaw, used to control the vehicle steering + * Whether each mouse button is held */ - public float wheelsYaw; + public boolean leftMouseHeld = false, rightMouseHeld = false; + /** - * Despawn time + * Shoot delay variables */ - private int ticksSinceUsed = 0; + public float shootDelayPrimary, shootDelaySecondary; /** - * Aesthetic door switch + * Minigun speed variables */ - public boolean varDoor; + public float minigunSpeedPrimary, minigunSpeedSecondary; /** - * Wheel rotation angle. Only applies to vehicles that set a rotating wheels flag + * Current gun variables for alternating weapons. */ - public float wheelsAngle; + public int currentGunPrimary, currentGunSecondary; + /** - * Delayer for door button + * Angle of harvester aesthetic piece */ - public int toggleTimer = 0; + public float harvesterAngle; + + public RotatedAxes prevAxes; + public RotatedAxes axes; - public float yaw = 0; - public float pitch = 0; - public float roll = 0; + public EntitySeat[] seats; - public float yawSpeed = 0; + public int lockOnSoundDelay; - // Used for better falling - private float fallVelocity = 0; + private int[] emitterTimers; + + public int animCountLeft = 0; + public int animFrameLeft = 0; + public int animCountRight = 0; + public int animFrameRight = 0; - //Handling stuff - public int keyHeld = 0; public boolean leftTurnHeld = false; public boolean rightTurnHeld = false; - public boolean allWheelsOnGround; - //Some nonsense - boolean lockTurretForward = false; - //Animation vectors - public Vector3f doorPos = new Vector3f(0, 0, 0); - public Vector3f doorRot = new Vector3f(0, 0, 0); - public Vector3f door2Pos = new Vector3f(0, 0, 0); - public Vector3f door2Rot = new Vector3f(0, 0, 0); - public Vector3f prevDoorPos = new Vector3f(0, 0, 0); - public Vector3f prevDoorRot = new Vector3f(0, 0, 0); - public Vector3f prevDoor2Pos = new Vector3f(0, 0, 0); - public Vector3f prevDoor2Rot = new Vector3f(0, 0, 0); + public boolean isShowedPosition = false; - public boolean deployedSmoke = false; + public int tickCount = 0; + //Gun recoil + public boolean isRecoil = false; + public float recoilPos = 0; + public float lastRecoilPos = 0; + public int recoilTimer = 0; + + public Vector3f lastPos = new Vector3f(0, 0, 0); + public boolean hugeBoat = false; + public boolean onDeck = false; + public double deckHeight = 0; + public int deckCheck = 0; + public int prevDeckCheck = 0; + + public boolean isMecha = false; + public boolean disabled = false; - //Dangerous sentry stuff - /** - * Stops the sentry shooting whoever placed it or their teammates - */ - public EntityPlayer placer = null; /** - * For getting the placer after a reload + * The angle of the propeller for the renderer */ - public String placerName = null; - public Entity target = null; + public float propAngle = 0; + public float prevPropAngle = 0; + + public float rotorAngle = 0; + public float prevRotorAngle = 0; + + //Flares + public int flareDelay = 0; + public int ticksFlareUsing = 0; + public boolean varFlare; + + //IT1 stuff + public float drakonDoorAngle = 0; + public float drakonArmAngle = 0; + public float drakonRailAngle = 0; + + public float prevDrakonDoorAngle = 0; + public float prevDrakonArmAngle = 0; + public float prevDrakonRailAngle = 0; + + public boolean reloadingDrakon = false; + public boolean canFireIT1 = true; + + public int stage = 1; + public int reloadAnimTime = 0; + + public boolean toDeactivate = false; + public int timeTillDeactivate = 0; - public AnimTankTrack rightTrack; - public AnimTankTrack leftTrack; + // + public boolean canFire = true; - public AnimTrackLink[] trackLinksLeft = new AnimTrackLink[0]; - public AnimTrackLink[] trackLinksRight = new AnimTrackLink[0]; - public EntityVehicle(World world) { + @SideOnly(Side.CLIENT) + public EntityLivingBase camera; + + protected int invulnerableUnmountCount; + + private ItemStack[][] prevInventoryItems = new ItemStack[][]{null, null}; + + public Entity lastAtkEntity = null; + + public Float collisionHardness = 0F; + + public int engineStartDelay; + + //public ArrayList playerIDs = new ArrayList(); + + public EntityDriveable(World world) { super(world); - stepHeight = 1.0F; - } - - //This one deals with spawning from a vehicle spawner - public EntityVehicle(World world, double x, double y, double z, VehicleType type, DriveableData data) { - super(world, type, data); - stepHeight = 1.0F; - setPosition(x, y, z); - initType(type, false); - } - - //This one allows you to deal with spawning from items - public EntityVehicle(World world, double x, double y, double z, EntityPlayer p, VehicleType type, DriveableData data) { - super(world, type, data); - placer = p; - placerName = p.getCommandSenderName(); - stepHeight = 1.0F; - setPosition(x, y, z); - rotateYaw(p.rotationYaw + 90F); - initType(type, false); - setupTracks(type); - } - - public void setupTracks(DriveableType type) { - rightTrack = new AnimTankTrack(type.rightTrackPoints, type.trackLinkLength); - leftTrack = new AnimTankTrack(type.leftTrackPoints, type.trackLinkLength); - int numLinks = Math.round(rightTrack.getTrackLength() / type.trackLinkLength); - trackLinksLeft = new AnimTrackLink[numLinks]; - trackLinksRight = new AnimTrackLink[numLinks]; - for (int i = 0; i < numLinks; i++) { - float progress = 0.01F + (type.trackLinkLength * i); - int trackPart = leftTrack.getTrackPart(progress); - trackLinksLeft[i] = new AnimTrackLink(progress); - trackLinksRight[i] = new AnimTrackLink(progress); - trackLinksLeft[i].position = leftTrack.getPositionOnTrack(progress); - trackLinksRight[i].position = rightTrack.getPositionOnTrack(progress); - trackLinksLeft[i].rot = new RotatedAxes(0, 0, rotateTowards(leftTrack.points.get((trackPart == 0) ? leftTrack.points.size() - 1 : trackPart - 1), trackLinksLeft[i].position)); - trackLinksRight[i].rot = new RotatedAxes(0, 0, rotateTowards(rightTrack.points.get((trackPart == 0) ? rightTrack.points.size() - 1 : trackPart - 1), trackLinksRight[i].position)); - trackLinksLeft[i].zRot = rotateTowards(leftTrack.points.get((trackPart == 0) ? leftTrack.points.size() - 1 : trackPart - 1), trackLinksLeft[i].position); - trackLinksRight[i].zRot = rotateTowards(rightTrack.points.get((trackPart == 0) ? rightTrack.points.size() - 1 : trackPart - 1), trackLinksRight[i].position); + axes = new RotatedAxes(); + prevAxes = new RotatedAxes(); + preventEntitySpawning = true; + if (FlansMod.driveableHitboxes) { + setSize(1F, 1F); + } else { + setSize(0F, 0F); } + yOffset = 6F / 16F; + ignoreFrustumCheck = true; + renderDistanceWeight = 20000D; } - @Override - protected void initType(DriveableType type, boolean clientSide) { - super.initType(type, clientSide); - setupTracks(type); + + public EntityDriveable(World world, DriveableType t, DriveableData d) { + this(world); + driveableType = t.shortName; + driveableData = d; } - @Override - public void readSpawnData(ByteBuf data) { - super.readSpawnData(data); + protected void initType(DriveableType type, boolean clientSide) { + if (type == null) return; + seats = new EntitySeat[type.numPassengers + 1]; + for (int i = 0; i < type.numPassengers + 1; i++) { + if (!clientSide) { + seats[i] = new EntitySeat(worldObj, this, i); + worldObj.spawnEntityInWorld(seats[i]); + } + } + wheels = new EntityWheel[type.wheelPositions.length]; + for (int i = 0; i < wheels.length; i++) { + if (!clientSide) { + wheels[i] = new EntityWheel(worldObj, this, i); + worldObj.spawnEntityInWorld(wheels[i]); + } + } + stepHeight = type.wheelStepHeight; + yOffset = type.yOffset; + + emitterTimers = new int[type.emitters.size()]; + for (int i = 0; i < type.emitters.size(); i++) { + emitterTimers[i] = rand.nextInt(type.emitters.get(i).emitRate); + } + + getEntityData().setBoolean("CanMountEntity", type.canMountEntity); + + //Register Plane to Radar on Spawning + //if(type.onRadar == true) + // RadarRegistry.register(this); + + for (int ps = 0; ps < 2; ps++) { + EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; + if (weaponType == EnumWeaponType.GUN) { + weaponType = EnumWeaponType.NONE; + } + int istart = getInventoryStart(weaponType); + if (istart == driveableData.getAmmoInventoryStart()) { + istart += type.numPassengerGunners; + } + final int isize = getInventorySize(weaponType); + if (istart >= 0 || isize > 0) { + prevInventoryItems[ps] = new ItemStack[isize]; + for (int i = 0; i < isize; i++) { + prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); + } + } + } + + engineStartDelay = type.engineStartTime; } @Override protected void writeEntityToNBT(NBTTagCompound tag) { - super.writeEntityToNBT(tag); - tag.setBoolean("VarDoor", varDoor); + driveableData.writeToNBT(tag); + tag.setString("Type", driveableType); + tag.setFloat("RotationYaw", axes.getYaw()); + tag.setFloat("RotationPitch", axes.getPitch()); + tag.setFloat("RotationRoll", axes.getRoll()); } @Override protected void readEntityFromNBT(NBTTagCompound tag) { - super.readEntityFromNBT(tag); - varDoor = tag.getBoolean("VarDoor"); + driveableType = tag.getString("Type"); + driveableData = new DriveableData(tag); + initType(DriveableType.getDriveable(driveableType), false); + + prevRotationYaw = tag.getFloat("RotationYaw"); + prevRotationPitch = tag.getFloat("RotationPitch"); + prevRotationRoll = tag.getFloat("RotationRoll"); + axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll); + } + + @Override + public void writeSpawnData(ByteBuf data) { + ByteBufUtils.writeUTF8String(data, driveableType); + + NBTTagCompound tag = new NBTTagCompound(); + driveableData.writeToNBT(tag); + ByteBufUtils.writeTag(data, tag); + + data.writeFloat(axes.getYaw()); + data.writeFloat(axes.getPitch()); + data.writeFloat(axes.getRoll()); + + //Write damage + for (EnumDriveablePart ep : EnumDriveablePart.values()) { + DriveablePart part = getDriveableData().parts.get(ep); + data.writeFloat(part.health); + data.writeBoolean(part.onFire); + } + } + + @Override + public void readSpawnData(ByteBuf data) { + try { + driveableType = ByteBufUtils.readUTF8String(data); + driveableData = new DriveableData(ByteBufUtils.readTag(data)); + initType(getDriveableType(), true); + + axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat()); + prevRotationYaw = axes.getYaw(); + prevRotationPitch = axes.getPitch(); + prevRotationRoll = axes.getRoll(); + + //Read damage + for (EnumDriveablePart ep : EnumDriveablePart.values()) { + DriveablePart part = getDriveableData().parts.get(ep); + part.health = data.readFloat(); + part.onFire = data.readBoolean(); + } + + } catch (Exception e) { + FlansMod.log("Failed to retrieve plane type from server."); + super.setDead(); + e.printStackTrace(); + } + + camera = new EntityCamera(worldObj, this); + worldObj.spawnEntityInWorld(camera); } /** * Called with the movement of the mouse. Used in controlling vehicles if need be. * - * @param deltaY - * @param deltaX + * @param deltaY change in Y + * @param deltaX change in X + * @return if mouse movement was handled. */ @Override - public void onMouseMoved(int deltaX, int deltaY) { + public abstract void onMouseMoved(int deltaX, int deltaY); + + @Override + @SideOnly(Side.CLIENT) + public EntityLivingBase getCamera() { + return camera; + } + + protected boolean canSit(int seat) { + return getDriveableType().numPassengers >= seat && seats[seat].riddenByEntity == null; } @Override - public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw) { - super.setPositionRotationAndMotion(x, y, z, yaw, pitch, roll, motX, motY, motZ, velYaw, velPitch, velRoll, throt, steeringYaw); - wheelsYaw = steeringYaw; + protected boolean canTriggerWalking() { + return false; } @Override - public boolean interactFirst(EntityPlayer entityplayer) { - if (isDead) - return false; - if (worldObj.isRemote) - return false; + protected void entityInit() { + } - //If they are using a repair tool, don't put them in - ItemStack currentItem = entityplayer.getCurrentEquippedItem(); - if (currentItem != null && currentItem.getItem() instanceof ItemTool && ((ItemTool) currentItem.getItem()).type.healDriveables) - return true; - VehicleType type = getVehicleType(); - //Check each seat in order to see if the player can sit in it - for (int i = 0; i <= type.numPassengers; i++) { - if (seats[i].interactFirst(entityplayer)) { - if (i == 0) { - shellDelay = type.vehicleShellDelay; - FlansMod.proxy.doTutorialStuff(entityplayer, this); + @Override + public AxisAlignedBB getCollisionBox(Entity entity) { + if (getDriveableType().collisionDamageEnable) { + if (throttle > getDriveableType().collisionDamageThrottle) { + if (entity instanceof EntityLiving) { + entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } else if (entity instanceof EntityPlayer) { + entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); } - return true; } } + return boundingBox; + } + + @Override + public AxisAlignedBB getBoundingBox() { + return boundingBox; + } + + @Override + public boolean canBePushed() { return false; } @Override - public boolean pressKey(int key, EntityPlayer player) { - VehicleType type = getVehicleType(); - DriveableData data = getDriveableData(); - //Send keys which require server side updates to the server - if (worldObj.isRemote && (key == 6 || key == 8 || key == 9)) { - FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); - return true; + public double getMountedYOffset() { + return -0.3D; + } + + /** + * Pass generic damage to the core + */ + @Override + public boolean attackEntityFrom(DamageSource damagesource, float i) { + if (worldObj.isRemote || isDead) return true; +// if(damagesource.getDamageType().indexOf("explosion") < 0) + { + if (isMountedEntity(damagesource.getEntity())) { + return false; + } } - switch (key) { - case 0: //Accelerate : Increase the throttle, up to 1. - { - if (isEngineActive()) { - if (type.useRealisticAcceleration) { - throttle += data.engine.enginePower / type.mass; - } else { - throttle += 0.01F; - } - } - if (throttle > 1F) - throttle = 1F; +// FlansMod.log(String.format("EntityDriveable.attackEntityFrom %.1f: %s : %s : %s", i, +// damagesource.getDamageType(), damagesource.getEntity(), damagesource.getSourceOfDamage())); - return true; - } - case 1: //Decelerate : Decrease the throttle, down to -1, or 0 if the vehicle cannot reverse - { - if (isEngineActive()) { - if (type.useRealisticAcceleration) { - throttle -= data.engine.enginePower / type.mass; - } else { - throttle -= 0.01F; + boolean broken = attackPart(EnumDriveablePart.core, damagesource, i); + if (i > 0) { + //checkParts(); + checkPartsWhenAttacked(); + //If it hit, send a damage update packet + FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); + } + return true; + } + + public boolean isMountedEntity(Entity entity) { + if (entity != null) { + Entity entity2 = this.worldObj.getEntityByID(entity.getEntityId()); + for (Entity seat : seats) { + if (seat.riddenByEntity != null) { + if (seat.riddenByEntity == entity || seat.riddenByEntity == entity2) { + return true; } } + } + } - if (throttle < -1F) - throttle = -1F; - if (throttle < 0F && type.maxNegativeThrottle == 0F) - throttle = 0F; + return false; + } - return true; + @Override + public void setDead() { + super.setDead(); + //Unregister to Radar + //RadarRegistry.unregister(this); + if (worldObj.isRemote) + camera.setDead(); + + for (EntitySeat seat : seats) + if (seat != null) + seat.setDead(); + } + + @Override + public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) { + } + + @Override + public boolean canBeCollidedWith() { + return true; + } + + @Override + public void applyEntityCollision(Entity entity) { + //if(!isPartOfThis(entity)) + //super.applyEntityCollision(entity); + } + + @Override + public void setPositionAndRotation2(double d, double d1, double d2, float f, float f1, int i) { + if (ticksExisted > 1) + return; + if (!(riddenByEntity instanceof EntityPlayer) || !FlansMod.proxy.isThePlayer((EntityPlayer) riddenByEntity)) { + if (syncFromServer) { + serverPositionTransitionTicker = i + 5; + } else { + double var10 = d - posX; + double var12 = d1 - posY; + double var14 = d2 - posZ; + double var16 = var10 * var10 + var12 * var12 + var14 * var14; + + if (var16 <= 1.0D) { + return; + } + + serverPositionTransitionTicker = 3; } - case 2: //Left : Yaw the wheels left - { - if (throttle < 0.3F) - throttle += type.clutchBrake; - wheelsYaw -= 1F; + serverPosX = d; + serverPosY = d1; + serverPosZ = d2; + serverYaw = f; + serverPitch = f1; + } + } + + public void setIT1(boolean canFire, boolean reloading, int stag, int stageTime) { + if (worldObj.isRemote && ticksExisted % 5 == 0) { + canFireIT1 = canFire; + reloadingDrakon = reloading; + stage = stag; + reloadAnimTime = stageTime; + } + } + + public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw) { + if (worldObj.isRemote) { + serverPosX = x; + serverPosY = y; + serverPosZ = z; + serverYaw = yaw; + serverPitch = pitch; + serverRoll = roll; + serverPositionTransitionTicker = 5; + } else { + setPosition(x, y, z); + prevRotationYaw = yaw; + prevRotationPitch = pitch; + prevRotationRoll = roll; + setRotation(yaw, pitch, roll); + } + //Set the motions regardless of side. + motionX = motX; + motionY = motY; + motionZ = motZ; + angularVelocity = new Vector3f(velYaw, velPitch, velRoll); + throttle = throt; + } + + + @Override + public void setVelocity(double d, double d1, double d2) { + motionX = d; + motionY = d1; + motionZ = d2; + } + + @Override + public boolean pressKey(int key, EntityPlayer player) { + if (!worldObj.isRemote && key == 9 && getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) //Primary + { + shoot(false); + return true; + } else if (!worldObj.isRemote && key == 8 && getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) //Secondary + { + shoot(true); + return true; + } + return false; + } + + @Override + public void updateKeyHeldState(int key, boolean held) { + if (worldObj.isRemote) { + FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); + + if (key == 2) { leftTurnHeld = true; - keyHeld = 100; - return true; - } - case 3: //Right : Yaw the wheels right - { - if (throttle < 0.3F) - throttle += type.clutchBrake; - wheelsYaw += 1F; + rightTurnHeld = false; + } else if (key == 3) { rightTurnHeld = true; - keyHeld = 100; - return true; + leftTurnHeld = false; + } else { + leftTurnHeld = false; + rightTurnHeld = false; } - case 4: //Up : Brake - { - throttle *= 0.8F; - if (throttle > 0.001F) - throttle = 0F; - if (throttle < -0.001F) - throttle = 0F; + } + switch (key) { + case 9: + leftMouseHeld = held; + break; + case 8: + rightMouseHeld = held; + break; + } + } - target = null; - return true; + /** + * Shoot method called by pressing / holding shoot buttons + */ + public void shoot(boolean secondary) { + DriveableType type = getDriveableType(); + if (seats[0] == null) + return; + + if (type.IT1 && !canFireIT1 && type.weaponType(secondary) == EnumWeaponType.MISSILE) return; + + if (!canFire || (isUnderWater() && !type.worksUnderWater)) return; + + //Check shoot delay + if (getShootDelay(secondary) <= 0) { + //We can shoot, so grab the available shoot points and the weaponType + ArrayList shootPoints = type.shootPoints(secondary); + EnumWeaponType weaponType = type.weaponType(secondary); + //If there are no shoot points, return + if (shootPoints.size() == 0) + return; + //For alternating guns, move on to the next one + int currentGun = getCurrentGun(secondary); + if (type.alternate(secondary)) { + currentGun = (currentGun + 1) % shootPoints.size(); + setCurrentGun(currentGun, secondary); + shootEach(type, shootPoints.get(currentGun), currentGun, secondary, weaponType); + } else for (int i = 0; i < shootPoints.size(); i++) + shootEach(type, shootPoints.get(i), i, secondary, weaponType); + } + } + + public boolean driverIsCreative() { + return seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode; + } + + public void spawnParticle(ArrayList list, ShootPoint shootPoint, Vector3f v) { + for (ShootParticle s : list) { + float bkx = shootPoint.rootPos.position.x; + float bky = shootPoint.rootPos.position.y; + float bkz = shootPoint.rootPos.position.z; + + Vector3f velocity = new Vector3f(s.x, s.y, s.z); + + //if(shootPoint.rootPos.part == EnumDriveablePart.turret){ + velocity = getDirection(shootPoint, velocity); + //} + + //Vector3f v = getFiringPosition(shootPoint); + + if (shootPoint.rootPos.part == EnumDriveablePart.core) { + Vector3f v2 = axes.findLocalVectorGlobally(shootPoint.rootPos.position); + Vector3f v3 = rotate(seats[0].looking.findLocalVectorGlobally(shootPoint.offPos)); + Vector3f.add(v2, v3, v); + } + + FlansMod.getPacketHandler().sendToAllAround( + new PacketParticle(s.name, posX + v.x, posY + v.y, posZ + v.z, velocity.x, velocity.y, velocity.z), + posX + v.x, posY + v.y, posZ + v.z, 150, dimension); + + shootPoint.rootPos.position.x = bkx; + shootPoint.rootPos.position.y = bky; + shootPoint.rootPos.position.z = bkz; + } + } + + + private void shootEach(DriveableType type, ShootPoint shootPoint, int currentGun, boolean secondary, EnumWeaponType weaponType) { + //Rotate the gun vector to global axes + Vector3f gunVec = getFiringPosition(shootPoint); + Vector3f lookVector = getLookVector(shootPoint); + + if (!secondary && type.fixedPrimaryFire) { + lookVector = axes.findLocalVectorGlobally(type.primaryFireAngle); + if (shootPoint.rootPos.part == EnumDriveablePart.turret) { + lookVector = getPositionOnTurret(type.primaryFireAngle, false); + } + if (shootPoint.rootPos.part == EnumDriveablePart.barrel) { + lookVector = getPositionOnTurret(type.primaryFireAngle, true); } - case 5: //Down : Do nothing - { - Minecraft mc = Minecraft.getMinecraft(); - if (toggleTimer <= 0 && TeamsManager.allowVehicleZoom) { - toggleTimer = 10; - if (mc.gameSettings.fovSetting != 10) { - mc.gameSettings.fovSetting = 10; - mc.gameSettings.mouseSensitivity = 0.2F; - } else if (mc.gameSettings.fovSetting == 10) { - mc.gameSettings.fovSetting = 70; - mc.gameSettings.mouseSensitivity = 0.5F; + } + + if (weaponType == EnumWeaponType.SHELL) + isRecoil = true; + if (shootPoint.rootPos.part == null) return; + if (!isPartIntact(shootPoint.rootPos.part)) return; + + if (disabled) return; + float damageMultiplier = secondary ? type.damageMultiplierSecondary : type.damageMultiplierPrimary; + //If its a pilot gun, then it is using a gun type, so do the following + if (shootPoint.rootPos instanceof PilotGun && ((PilotGun) shootPoint.rootPos).type != null) { + PilotGun pilotGun = (PilotGun) shootPoint.rootPos; + //Get the gun from the plane type and the ammo from the data + GunType gunType = pilotGun.type; + float shellSpeed = gunType.bulletSpeed; + if (type.rangingGun) + shellSpeed = type.bulletSpeed; + ItemStack bulletItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + currentGun]; + //Check that neither is null and that the bullet item is actually a bullet + if (bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable && TeamsManager.bulletsEnabled) { + ShootableType bullet = ((ItemShootable) bulletItemStack.getItem()).type; + if (gunType.isAmmo(bullet)) { + //spawnParticle(gunType, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY,V (float)posZ), null)); + + spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); + //Spawn a new bullet item + worldObj.spawnEntityInWorld(((ItemShootable) bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, gunType.bulletSpread / 2, gunType.damage * damageMultiplier, shellSpeed, bulletItemStack.getItemDamage(), type)); + //Play the shoot sound + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); + //Get the bullet item damage and increment it + int damage = bulletItemStack.getItemDamage(); + bulletItemStack.setItemDamage(damage + 1); + //If the bullet item is completely damaged (empty) + if (damage + 1 == bulletItemStack.getMaxDamage()) { + //Set the damage to 0 and consume one ammo item (unless in creative) + bulletItemStack.setItemDamage(0); + if (!driverIsCreative()) { + bulletItemStack.stackSize--; + if (bulletItemStack.stackSize <= 0) { + onWeaponInventoryChanged(secondary); + bulletItemStack = null; + } + driveableData.setInventorySlotContents(getDriveableType().numPassengerGunners + currentGun, bulletItemStack); + } + } + if (type.shootDelay(secondary) == -1) { + setShootDelay(gunType.getShootDelay(), secondary); + } else { + setShootDelay(type.shootDelay(secondary), secondary); } + //Reset the shoot delay } - return true; } - case 6: //Exit : Get out - { - seats[0].riddenByEntity.setInvisible(false); - //resetZoom(); - seats[0].riddenByEntity.mountEntity(null); - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.exitSound, false); - return true; + } else //One of the other modes + { + switch (weaponType) { + case BOMB: { + if (TeamsManager.bombsEnabled) { + int slot = -1; + for (int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) { + ItemStack bomb = driveableData.getStackInSlot(i); + if (bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) bomb.getItem()).type, weaponType)) { + slot = i; + } + } + + if (slot != -1) { + int spread = 0; + float shellSpeed = 0F; + + ItemStack bulletStack = driveableData.getStackInSlot(slot); + ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); + if (shootPoint.rootPos instanceof PilotGun) { + PilotGun pilotGun = (PilotGun) shootPoint.rootPos; + //Get the gun from the plane type and the ammo from the data + GunType gunType = pilotGun.type; + } + + EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vec3.createVectorHelper(gunVec.x + posX, gunVec.y + posY, gunVec.z + posZ), axes.getYaw(), axes.getPitch(), motionX, motionY, motionZ, (EntityLivingBase) seats[0].riddenByEntity, damageMultiplier, driveableData.getStackInSlot(slot).getItemDamage(), type); + worldObj.spawnEntityInWorld(bulletEntity); + + spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); + + + if (type.shootSound(secondary) != null) + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); + if (!driverIsCreative()) { + bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); + if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { + bulletStack.setItemDamage(0); + bulletStack.stackSize--; + if (bulletStack.stackSize == 0) { + onWeaponInventoryChanged(secondary); + bulletStack = null; + } + } + driveableData.setInventorySlotContents(slot, bulletStack); + } + if (type.shootDelay(secondary) == -1) { + setShootDelay(1, secondary); + } else { + setShootDelay(type.shootDelay(secondary), secondary); + } + } + } + break; + } + case MISSILE: //These two are actually almost identical + case SHELL: { + //int numnum = driveableData.getMissileInventoryStart(); + /*ItemStack AmmoPlaced = driveableData.getStackInSlot(1); + if(AmmoPlaced == null && type.enableReloadTime){ + isAmmoPlaced = false; + break; + } + isAmmoPlaced = true; + setShootDelay(type.shootDelay(secondary), secondary);*/ + tryRecoil(); + + if (TeamsManager.shellsEnabled) { + int slot = -1; + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, weaponType)) { + slot = i; + } + } + + if (slot != -1) { + //int spread = 0; + //float shellSpeed = 3F; + float spread = type.bulletSpread; + float shellSpeed = type.bulletSpeed; + ItemStack bulletStack = driveableData.getStackInSlot(slot); + ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); + EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); + //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY, (float)posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, bulletStack.getItemDamage(), type); + //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); + worldObj.spawnEntityInWorld(bulletEntity); //SHELL + spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); + isRecoil = true; + + if (type.shootSound(secondary) != null) + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); + if (!driverIsCreative()) { + bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); + if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { + bulletStack.setItemDamage(0); + bulletStack.stackSize--; + if (bulletStack.stackSize == 0) { + onWeaponInventoryChanged(secondary); + bulletStack = null; + } + } + driveableData.setInventorySlotContents(slot, bulletStack); + } + if (type.shootDelay(secondary) == -1) { + setShootDelay(1, secondary); + } else { + setShootDelay(type.shootDelay(secondary), secondary); + } + canFireIT1 = false; + } + } + break; + } + case GUN: //Handled above + break; + case MINE: + case NONE: + break; } - case 7: //Inventory - { - if (worldObj.isRemote) { - FlansMod.proxy.openDriveableMenu((EntityPlayer) seats[0].riddenByEntity, worldObj, this); + } + } + + public Vector3f getOrigin(ShootPoint dp) { + //Rotate the gun vector to global axes + Vector3f localGunVec = new Vector3f(dp.rootPos.position); + + if (dp.rootPos.part == EnumDriveablePart.turret) { + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); + //Rotate by the turret angles + localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + //Translate by the turret origin + Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); + } + + return rotate(localGunVec); + } + + public Vector3f getPositionOnTurret(Vector3f vecIn, boolean barrel) { + Vector3f transform = vecIn; + RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); + if (barrel) yawOnlyLooking = seats[0].looking; + + //Calculate the root of the gun + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(transform, getDriveableType().turretOrigin, transform); + //Rotate by the turret angles + transform = yawOnlyLooking.findLocalVectorGlobally(transform); + //Translate by the turret origin + Vector3f.add(transform, getDriveableType().turretOrigin, transform); + Vector3f turretOriginOffset = new Vector3f(getDriveableType().turretOriginOffset); + turretOriginOffset = yawOnlyLooking.findLocalVectorGloballyYaw(turretOriginOffset); + Vector3f.add(transform, turretOriginOffset, transform); + + return rotate(transform); + } + + public Vector3f getDirection(ShootPoint dp, Vector3f vIn) { + //Rotate the gun vector to global axes + Vector3f localGunVec = new Vector3f(vIn); + + //if(dp.rootPos.part == EnumDriveablePart.turret) + //{ + //localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + //} + + localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + + return rotate(localGunVec); + } + + public Vector3f getLookVector(ShootPoint dp) { + return axes.getXAxis(); + } + + public Vector3f getFiringPosition(ShootPoint dp) { + Vector3f rootVector = new Vector3f(dp.rootPos.position); + Vector3f offsetVector = new Vector3f(dp.offPos); + Vector3f localGunVec = new Vector3f(dp.rootPos.position); + + if (dp.rootPos.part == EnumDriveablePart.turret) { + if (offsetVector.x == 0 && offsetVector.y == 0 && offsetVector.z == 0) { + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); + //Rotate by the turret angles + localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + //Translate by the turret origin + Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); + } else { + RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); + + //Calculate the root of the gun + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(rootVector, getDriveableType().turretOrigin, rootVector); + //Rotate by the turret angles + rootVector = yawOnlyLooking.findLocalVectorGlobally(rootVector); + //Translate by the turret origin + Vector3f.add(rootVector, getDriveableType().turretOrigin, rootVector); + + //Calculate the tip of the gun + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(offsetVector, getDriveableType().turretOrigin, offsetVector); + //Rotate by the turret angles + offsetVector = seats[0].looking.findLocalVectorGlobally(offsetVector); + //Translate by the turret origin + + Vector3f.add(rootVector, offsetVector, localGunVec); + } + } + + return rotate(localGunVec); + } + + public boolean isEngineActive() { + return (driverIsCreative() || driveableData.fuelInTank > 0) && engineStartDelay == 0 || getDriveableType().fuelTankSize < 0; + } + + public void correctWheelPos() { + if (this.ticksExisted % (10 * 20) == 0) { + for (EntityWheel wheel : wheels) { + if (wheel == null) continue; + + Vector3f target = axes.findLocalVectorGlobally(getDriveableType().wheelPositions[wheel.ID].position); + target.x += posX; + target.y += posY; + target.z += posZ; + + int tf = 1; + int cf = 1; + int range = 5; + + if (MathHelper.abs(target.x - (float) wheel.posX) > range) { + wheel.posX = (target.x * tf + (float) wheel.posX * cf) / (tf + cf); + } + if (MathHelper.abs(target.y - (float) wheel.posY) > range) { + wheel.posY = (target.y * tf + (float) wheel.posY * cf) / (tf + cf); + } + if (MathHelper.abs(target.z - (float) wheel.posZ) > range) { + wheel.posZ = (target.z * tf + (float) wheel.posZ * cf) / (tf + cf); } - return true; } - case 8: //Shoot shell - case 9: //Shoot bullet - { - return super.pressKey(key, player); + } + } + + @Override + public void onUpdate() { + super.onUpdate(); + //playerIDs.clear(); + DriveableType type = getDriveableType(); + DriveableData data = getDriveableData(); + //if(type.fancyCollision) + //checkCollsionBox(); + hugeBoat = (getDriveableType().floatOnWater && getDriveableType().wheelStepHeight == 0); + //hugeBoat = true; + + if (hugeBoat) { + for (int i = 0; i < worldObj.loadedEntityList.size(); i++) { + Object obj = worldObj.loadedEntityList.get(i); + if (obj instanceof EntityPlayer && !isPartOfThis((Entity) obj)) { + moveRiders((Entity) obj); + } + + if (obj instanceof EntityWheel && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { + //moveRiders((Entity)obj); + } + + if (obj instanceof EntityDriveable && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { + //moveRiders((Entity)obj); + } + } + } + + onDeck = deckCheck != prevDeckCheck; + + //Aesthetics + if (type.IT1 && !disabled) { + boolean fireButtonHeld = false; + if (type.weaponType(false) == EnumWeaponType.MISSILE) fireButtonHeld = leftMouseHeld; + if (type.weaponType(true) == EnumWeaponType.MISSILE) fireButtonHeld = rightMouseHeld; + + prevDrakonDoorAngle = drakonDoorAngle; + prevDrakonArmAngle = drakonArmAngle; + prevDrakonRailAngle = drakonRailAngle; + if (canFireIT1) reloadingDrakon = false; + if (stage == 0) stage = 1; + + if (stage == 8 && fireButtonHeld) { + stage = 1; + timeTillDeactivate = 5; + toDeactivate = true; + } + if (timeTillDeactivate <= 0 && toDeactivate) { + canFireIT1 = false; + toDeactivate = false; + } + + if (reloadAnimTime <= 0) + IT1Reload(); + + reloadAnimTime--; + timeTillDeactivate--; + } + + //Aesthetics + prevPropAngle = propAngle; + prevRotorAngle = rotorAngle; + if (throttle != 0) { + propAngle += (Math.pow(Math.abs(throttle), 0.4)) * 1.5; + rotorAngle += throttle / 7F; + } + + + //Gun recoil + if (leftMouseHeld && !disabled) { + tryRecoil(); + setRecoilTimer(); + } + lastRecoilPos = recoilPos; + + if (recoilPos > 180 - (180 / type.recoilTime)) { + recoilPos = 0; + isRecoil = false; + } + + if (isRecoil) + recoilPos = recoilPos + (180 / type.recoilTime); + + if (recoilTimer >= 0) + recoilTimer--; + + checkInventoryChanged(); + + if (isUnderWater() && !type.worksUnderWater && !hugeBoat) { + throttle = 0; + //this.driveableData.parts.get(EnumDriveablePart.core).health -= 1; + disabled = true; + } else disabled = false; + + + if (type.lockOnToLivings || type.lockOnToMechas || type.lockOnToPlanes || type.lockOnToPlayers || type.lockOnToVehicles) { + if (!worldObj.isRemote && this.seats.length > 0 && lockOnSoundDelay <= 0) { + if (this.seats[0] != null && this.seats[0].riddenByEntity instanceof EntityPlayer) { + // int currentGun = getCurrentGun(false); + // Vector3f playerVec = getOrigin(type.shootPoints(false).get(currentGun)); + Vector3f playerVecRelToVehicle = seats[0].playerLooking.findGlobalVectorLocally(new Vector3f(-1, 0, 0)); + Vector3f playerVec = axes.findGlobalVectorLocally(playerVecRelToVehicle); + + for (Object obj : worldObj.loadedEntityList) { + Entity entity = (Entity) obj; + if ((type.lockOnToMechas && entity instanceof EntityMecha) || + (type.lockOnToVehicles && entity instanceof EntityVehicle) || + (type.lockOnToPlanes && entity instanceof EntityPlane) || + (type.lockOnToPlayers && entity instanceof EntityPlayer) || + (type.lockOnToLivings && entity instanceof EntityLivingBase)) { + if (getDistanceSqToEntity(entity) < type.maxRangeLockOn * type.maxRangeLockOn) { + // Some heckery with vectors rotating about themselves or something + Vector3f relPosVec = new Vector3f(-entity.posX + seats[0].posX, -entity.posY + seats[0].posY, entity.posZ - seats[0].posZ); + float angle = Math.abs(Vector3f.angle(playerVec, relPosVec)); + if (angle < Math.toRadians(type.canLockOnAngle)) { + PacketPlaySound.sendSoundPacket(seats[0].posX, seats[0].posY, seats[0].posZ, 10, dimension, type.lockOnSound, false); + if (entity instanceof EntityDriveable) + PacketPlaySound.sendSoundPacket(entity.posX, entity.posY, entity.posZ, ((EntityDriveable) entity).getDriveableType().lockedOnSoundRange, entity.dimension, ((EntityDriveable) entity).getDriveableType().lockingOnSound, false); + lockOnSoundDelay = type.lockOnSoundTime; + break; + } + } + } + } + } + } + } + if (lockOnSoundDelay > 0) + lockOnSoundDelay--; + + + if (this.ridingEntity != null) { + invulnerableUnmountCount = 20 * 4; + } else if (invulnerableUnmountCount > 0) { + invulnerableUnmountCount--; + } + + if (!worldObj.isRemote) { + for (int i = 0; i < getDriveableType().numPassengers + 1; i++) { + if (seats[i] == null || !seats[i].addedToChunk) { + seats[i] = new EntitySeat(worldObj, this, i); + worldObj.spawnEntityInWorld(seats[i]); + } + } + for (int i = 0; i < type.wheelPositions.length; i++) { + if (wheels[i] == null || !wheels[i].addedToChunk) { + wheels[i] = new EntityWheel(worldObj, this, i); + worldObj.spawnEntityInWorld(wheels[i]); + } + } + } + + //Harvest stuff + //Aesthetics + if (hasEnoughFuel() && isEngineActive()) { + harvesterAngle += throttle / 5F; + } + //Actual harvesting + if (type.harvestBlocks && type.harvestBoxSize != null && type.harvestBoxPos != null && TeamsManager.driveablesBreakBlocks) { + Vector3f size = new Vector3f(type.harvestBoxSize.x / 16F, type.harvestBoxSize.y / 16F, type.harvestBoxSize.z / 16F); + Vector3f pos = new Vector3f(type.harvestBoxPos.x / 16F, type.harvestBoxPos.y / 16F, type.harvestBoxPos.z / 16F); + for (float x = pos.x; x <= pos.x + size.x; x++) { + for (float y = pos.y; y <= pos.y + size.y; y++) { + for (float z = pos.z; z <= pos.z + size.z; z++) { + Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); + + int blockX = (int) Math.round(posX + v.x); + int blockY = (int) Math.round(posY + v.y); + int blockZ = (int) Math.round(posZ + v.z); + Block block = worldObj.getBlock(blockX, blockY, blockZ); + + if (type.materialsHarvested.contains(block.getMaterial()) && block.getBlockHardness(worldObj, blockX, blockY, blockZ) >= 0F) { + if (type.collectHarvest) { + //Add the itemstack to mecha inventory + ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); + for (ItemStack stack : stacks) { + if (!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative()) && !worldObj.isRemote && worldObj.getGameRules().getGameRuleBooleanValue("doTileDrops")) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); + } + } + } else if (type.dropHarvest) { + ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); + for (ItemStack stack : stacks) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); + } + } + //Destroy block + worldObj.func_147480_a(blockX, blockY, blockZ, false); + } + } + } + } + } + + /*if(this.isLockedOn && soundTime <= 0 && !this.worldObj.isRemote) + { + PacketPlaySound.sendSoundPacket(posX,posY,posZ, 5, dimension, type.lockedOnSound, false); + soundTime = type.soundTime; + }*/ + + for (DriveablePart part : getDriveableData().parts.values()) { + if (part.box != null) { + + part.update(this); + //Client side particles + if (worldObj.isRemote) { + if (part.onFire) { + //Pick a random position within the bounding box and spawn a flame there + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); + worldObj.spawnParticle("flame", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); + } + if (part.health > 0 && part.health < part.maxHealth / 2) { + //Pick a random position within the bounding box and spawn a flame there + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); + worldObj.spawnParticle(part.health < part.maxHealth / 4 ? "largesmoke" : "smoke", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); + } + } + //Server side fire handling + if (part.onFire) { + //Rain can put out fire + if (worldObj.isRaining() && rand.nextInt(40) == 0) + part.onFire = false; + //Also water blocks + //Get the centre point of the part + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + part.box.w / 2F, part.box.y + part.box.h / 2F, part.box.z + part.box.d / 2F)); + if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.water) { + part.onFire = false; + } + } else { + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); + if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.lava) { + part.onFire = true; + } + } + } + } + + for (int i = 0; i < type.emitters.size(); i++) { + ParticleEmitter emitter = type.emitters.get(i); + emitterTimers[i]--; + boolean canEmit; + boolean inThrottle = false; + DriveablePart part = getDriveableData().parts.get(EnumDriveablePart.getPart(emitter.part)); + float healthPercentage = part.health / part.maxHealth; + canEmit = isPartIntact(EnumDriveablePart.getPart(emitter.part)) && healthPercentage >= emitter.minHealth && healthPercentage <= emitter.maxHealth; + + if ((throttle >= emitter.minThrottle && throttle <= emitter.maxThrottle)) + inThrottle = true; + if (isMecha) + inThrottle = true; + + if (emitterTimers[i] <= 0) { + if (inThrottle && canEmit) { + //Emit! + Vector3f velocity = new Vector3f(0, 0, 0); + + Vector3f pos = new Vector3f(0, 0, 0); + if (seats != null && seats[0] != null) { + if (EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.turret && EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.barrel) { + Vector3f localPosition = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, + emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, + emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); + + pos = axes.findLocalVectorGlobally(localPosition); + velocity = axes.findLocalVectorGlobally(emitter.velocity); + } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.turret || EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.head && !emitter.part.equals("barrel")) { + + Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, + emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, + emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); + pos = getPositionOnTurret(localPosition2, false); + velocity = getPositionOnTurret(emitter.velocity, false); + } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.barrel) { + Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, + emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, + emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); + + + pos = getPositionOnTurret(localPosition2, true); + velocity = getPositionOnTurret(emitter.velocity, true); + } + //FlansMod.proxy.spawnParticle(emitter.effectType, posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z); + + FlansMod.getPacketHandler().sendToAllAround( + new PacketParticle(emitter.effectType, + posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z), + posX + pos.x, posY + pos.y, posZ + pos.z, 150, dimension); + + } + } + emitterTimers[i] = emitter.emitRate; + } + } + + checkParts(); + + prevRotationYaw = axes.getYaw(); + prevRotationPitch = axes.getPitch(); + prevRotationRoll = axes.getRoll(); + prevAxes = axes.clone(); + + if (riddenByEntity != null && riddenByEntity.isDead) { + riddenByEntity = null; + } + if (riddenByEntity != null && isDead) { + riddenByEntity.mountEntity(null); + } + if (riddenByEntity != null) + riddenByEntity.fallDistance = 0F; + + //If there's no player in the driveable or it cannot thrust, slow the plane and turn off mouse held actions + if ((seats != null && seats[0] != null && seats[0].riddenByEntity == null) || !isEngineActive() && getDriveableType().maxThrottle != 0 && getDriveableType().maxNegativeThrottle != 0) { + throttle *= 0.99F; + } + if (seats != null && seats[0] != null && seats[0].riddenByEntity == null) { + rightMouseHeld = leftMouseHeld = false; + } + + //Check if shooting + if (shootDelayPrimary > 0) + shootDelayPrimary--; + if (shootDelaySecondary > 0) + shootDelaySecondary--; + if (getDriveableType().reloadSoundTick != 15214541 && shootDelayPrimary == getDriveableType().reloadSoundTick) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootReloadSound, false); + } +// on first update + if (this.ticksExisted == 1) { + setShootDelay(getDriveableType().placeTimePrimary, false); + setShootDelay(getDriveableType().placeTimeSecondary, true); + if (!this.worldObj.isRemote) { + if (!getDriveableType().placeSoundPrimary.isEmpty()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().placeSoundPrimary, false); + } + if (!getDriveableType().placeSoundSecondary.isEmpty()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().placeSoundSecondary, false); + } + } + } + if (seats[0] != null && seats[0].riddenByEntity != null && seats[0].riddenByEntity instanceof EntityPlayer && worldObj.isRemote) { + EntityPlayer p = (EntityPlayer) seats[0].riddenByEntity; + if (this.ticksExisted < getDriveableType().placeTimePrimary && (getShootDelay(false) % 100) == 0 ) { + p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use in " + getShootDelay(false)/20 + " seconds.")); + } else if (this.ticksExisted == getDriveableType().placeTimePrimary) { + p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use!")); + } + + if (this.ticksExisted < getDriveableType().placeTimeSecondary && (getShootDelay(true) % 100) == 0) { + p.addChatComponentMessage( + new ChatComponentText("Secondary gun ready to use in " + getShootDelay(true)/20 + " seconds.")); + } else if (this.ticksExisted == getDriveableType().placeTimeSecondary) { + p.addChatComponentMessage(new ChatComponentText("Secondary gun ready to use!")); + } + + if (engineStartDelay > 0 && engineStartDelay % (2.5*20) == 0) { + p.addChatComponentMessage(new ChatComponentText("Engine starting.. " + (float)engineStartDelay/20 + " seconds remaining.")); + } else if (engineStartDelay == 1) { + p.addChatComponentMessage(new ChatComponentText("Engine started!")); + } + } + + if (!worldObj.isRemote) { + if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO) + shoot(false); + if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO) + shoot(true); + minigunSpeedPrimary *= 0.9F; + minigunSpeedSecondary *= 0.9F; + if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN) { + minigunSpeedPrimary += 0.1F; + if (minigunSpeedPrimary > 1F) + shoot(false); + } + if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN) { + minigunSpeedSecondary += 0.1F; + if (minigunSpeedSecondary > 1F) + shoot(true); + } + } + + prevDeckCheck = deckCheck; + + if (engineStartDelay > 0) { engineStartDelay--; } + //Handle fuel + + int fuelMultiplier = 2; + + //The tank is currently full, so do nothing + if (data.fuelInTank >= type.fuelTankSize) + return; + + //Look through the entire inventory for fuel cans, buildcraft fuel buckets and RedstoneFlux power sources + for (int i = 0; i < data.getSizeInventory(); i++) { + ItemStack stack = data.getStackInSlot(i); + if (stack == null || stack.stackSize <= 0) + continue; + Item item = stack.getItem(); + //If we have an electric engine, look for RedstoneFlux power source items, such as power cubes + if (data.engine.useRFPower) { + if (item instanceof IEnergyContainerItem) { + IEnergyContainerItem energy = (IEnergyContainerItem) item; + data.fuelInTank += (fuelMultiplier * energy.extractEnergy(stack, data.engine.RFDrawRate, false)) / data.engine.RFDrawRate; + } + } else { + //Check for Flan's Mod fuel items + if (item instanceof ItemPart) { + PartType part = ((ItemPart) item).type; + //Check it is a fuel item + if (part.category == 9) { + //Put 2 points of fuel + data.fuelInTank += fuelMultiplier; + + //Damage the fuel item to indicate being used up + int damage = stack.getItemDamage(); + stack.setItemDamage(damage + 1); + + //If we have finished this fuel item + if (damage >= stack.getMaxDamage()) { + //Reset the damage to 0 + stack.setItemDamage(0); + //Consume one item + stack.stackSize--; + //If we consumed the last one, destroy the stack + if (stack.stackSize <= 0) + data.setInventorySlotContents(i, null); + } + + //We found a fuel item and consumed some, so we are done + break; + } + } + //Check for Buildcraft oil and fuel buckets + else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftOilBucket) && data.fuelInTank + 1000 * fuelMultiplier <= type.fuelTankSize) { + data.fuelInTank += 1000 * fuelMultiplier; + data.setInventorySlotContents(i, new ItemStack(Items.bucket)); + } else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftFuelBucket) && data.fuelInTank + 2000 * fuelMultiplier <= type.fuelTankSize) { + data.fuelInTank += 2000 * fuelMultiplier; + data.setInventorySlotContents(i, new ItemStack(Items.bucket)); + } + + prevPosX = posX; + prevPosY = posY; + prevPosZ = posZ; + } + } + } + + public void checkInventoryChanged() { + DriveableType type = getDriveableType(); + if (type == null) return; + + if (worldObj.isRemote) return; + + if (!driveableData.inventoryChanged) return; + + driveableData.inventoryChanged = false; + + try { + for (int ps = 0; ps < 2; ps++) { + EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; + if (weaponType == EnumWeaponType.GUN) { + weaponType = EnumWeaponType.NONE; + } + int istart = getInventoryStart(weaponType); + if (istart == driveableData.getAmmoInventoryStart()) { + istart += type.numPassengerGunners; + } + final int isize = getInventorySize(weaponType); + if (istart >= 0 || isize > 0) { + if (prevInventoryItems[ps] == null) { + prevInventoryItems[ps] = new ItemStack[isize]; + } + + for (int i = 0; i < isize; i++) { + ItemStack itemStack = driveableData.getStackInSlot(istart + i); + if (itemStack != null && itemStack.getItem() instanceof ItemBullet) { + if (prevInventoryItems[ps][i] == null || !ItemStack.areItemStacksEqual(itemStack, prevInventoryItems[ps][i])) { + if (type.isValidAmmo(((ItemBullet) itemStack.getItem()).type, weaponType)) { + onWeaponInventoryChanged(ps == 1); + break; + } + } + } + } + + for (int i = 0; i < isize; i++) { + prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void onWeaponInventoryChanged(boolean secondary) { + DriveableType type = getDriveableType(); + if (!secondary) { + if (type.reloadTimePrimary > 0 && getShootDelay(secondary) <= 0) { + setShootDelay(type.reloadTimePrimary, secondary); + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().reloadSoundPrimary, false); + } + } else { + if (type.reloadTimeSecondary > 0 && getShootDelay(secondary) <= 0) { + setShootDelay(type.reloadTimeSecondary, secondary); + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().reloadSoundSecondary, false); + } + } + } + + public int getInventoryStart(EnumWeaponType wt) { + switch (wt) { + case NONE: + case GUN: + return driveableData.getAmmoInventoryStart(); + + case MISSILE: + case SHELL: + return driveableData.getMissileInventoryStart(); + + case BOMB: + case MINE: + return driveableData.getBombInventoryStart(); + + default: + break; + } + return -1; + } + + public int getInventorySize(EnumWeaponType wt) { + switch (wt) { + case NONE: + case GUN: + return driveableData.ammo.length; + + case MISSILE: + case SHELL: + return driveableData.missiles.length; + + case BOMB: + case MINE: + return driveableData.bombs.length; + + default: + break; + } + return -1; + } + + public void checkForCollisions() { + boolean damagePart = false; + boolean crashInWater = false; + double speed = getSpeedXYZ(); + for (DriveablePosition p : getDriveableType().collisionPoints) { + if (driveableData.parts.get(p.part).dead) + continue; + Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position); + Vec3 lastPos = Vec3.createVectorHelper(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z); + + Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position); + Vec3 currentPos = Vec3.createVectorHelper(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z); + + if (FlansMod.DEBUG && worldObj.isRemote) { + worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F)); + } + + MovingObjectPosition hit = worldObj.rayTraceBlocks(lastPos, currentPos, crashInWater); + if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { + int x = hit.blockX; + int y = hit.blockY; + int z = hit.blockZ; + Block blockHit = worldObj.getBlock(x, y, z); + int meta = worldObj.getBlockMetadata(x, y, z); + + float blockHardness = blockHit.getBlockHardness(worldObj, x, y, z); + + float damage = 0; + if (blockHardness > 0.2) { + damage = blockHardness * blockHardness * (float) speed; + } + + if (null == blockHit.getCollisionBoundingBoxFromPool(this.worldObj, x, y, z)) { + damage = 0; + } + + if (damage > 0) { + damagePart = true; + if (!attackPart(p.part, DamageSource.inWall, damage) && TeamsManager.driveablesBreakBlocks) { + // And if it didn't die from the attack, break the block + worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(blockHit) + (meta << 12)); + + if (!worldObj.isRemote) { + blockHit.dropBlockAsItem(worldObj, x, y, z, meta, 1); + worldObj.setBlockToAir(x, y, z); + } + } else { + // The part died! + worldObj.createExplosion(this, currentPos.xCoord, currentPos.yCoord, currentPos.zCoord, 1F, + false); + } + } + } + + } + + if (FlansMod.seatCollisions) { + // This is for preventing vehicle glitching. It makes seats collideable, and stops their motion if + for (EntitySeat seat : seats) { + if (seat == null || wheels == null ||wheels[0] == null || wheels[1] == null || seat.riddenByEntity == null) + continue; + DriveablePosition p = seat.getAsDriveablePosition(); + if (driveableData.parts.get(p.part).dead) + continue; + Vector3f fwd = axes.getXAxis(); + float a = 0F; + if (getSpeedXZ() > 1) { + if (getSpeedXZ() > 2) { + a = 6F; + } else { + a = 3F; + } + } + + double checkY = Math.max((wheels[0].posY + wheels[1].posY)/2F + (this instanceof EntityVehicle ? 1.5 : 0), seat.posY); + Vec3 seatPos = Vec3.createVectorHelper(seat.posX + fwd.x * a, checkY + fwd.y * a, seat.posZ + fwd.z * a); + Vec3 wheelMidPos = Vec3.createVectorHelper((wheels[0].posX + wheels[1].posX)/2F, checkY, (wheels[0].posZ + wheels[1].posZ)/2F); + + MovingObjectPosition hit = worldObj.rayTraceBlocks(seatPos, wheelMidPos, crashInWater); + if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { + int x = hit.blockX; + int y = hit.blockY; + int z = hit.blockZ; + Block blockHit = worldObj.getBlock(x, y, z); + + collisionHardness = blockHit.getBlockHardness(worldObj, x, y, z); + } + } + } + + if (damagePart) { + //This is server side bsns + if (!worldObj.isRemote) { +// checkParts(); + //If it hit, send a damage update packet + FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); + } + } + } + + @Override + protected void fall(float k) { + double fallDist = ((this.posY - this.prevPosY) + this.motionY) / 2; + float damage = (float) (fallDist < -0.3 ? -fallDist * 50 : 0); + + boolean noDamage = true; + if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20) { + DriveableType type = getDriveableType(); + damage = (int) (damage * type.fallDamageFactor); + attackPart(EnumDriveablePart.core, DamageSource.fall, damage); + if (type.wheelPositions.length > 0) { + attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5); + } + + noDamage = false; + } + // FlansMod.log("fall%s : tick=%d damage=%.1f, posY-prevPosY=%.3f, mY=%.3f, fallDist=%.2f", + // noDamage? " no damage":"", this.ticksExisted, damage, this.posY - this.prevPosY, + // this.motionY, fallDist); + } + + /** + * Attack a certain part of a driveable and return whether it broke or not + */ + public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage) { + if (ep == EnumDriveablePart.core) { + if (source.getSourceOfDamage() instanceof EntityLivingBase) { + this.lastAtkEntity = source.getSourceOfDamage(); + } else if (source.getEntity() instanceof EntityLivingBase) { + this.lastAtkEntity = source.getEntity(); + } else { + this.lastAtkEntity = null; + } + } + DriveablePart part = driveableData.parts.get(ep); + // FlansMod.log("EntityDriveable.attackPart %s : %s : damage=%.1f : %s : health=%d", ep.name(), ep.getName(), damage, + // part.type.name(), part.health); + return part.attack(damage, source.isFireDamage()); + } + + /** + * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates + */ + public Vector3f rotate(Vector3f inVec) { + return axes.findLocalVectorGlobally(inVec); + } + + /** + * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates + */ + public Vector3f rotate(Vec3 inVec) { + return rotate(inVec.xCoord, inVec.yCoord, inVec.zCoord); + } + + /** + * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates + */ + public Vector3f rotate(double x, double y, double z) { + return rotate(new Vector3f((float) x, (float) y, (float) z)); + } + + //Rotate the plane locally by some angle about the yaw axis + public void rotateYaw(float rotateBy) { + if (Math.abs(rotateBy) < 0.01F) + return; + axes.rotateLocalYaw(rotateBy); + updatePrevAngles(); + } + + //Rotate the plane locally by some angle about the pitch axis + public void rotatePitch(float rotateBy) { + if (Math.abs(rotateBy) < 0.01F) + return; + axes.rotateLocalPitch(rotateBy); + updatePrevAngles(); + } + + //Rotate the plane locally by some angle about the roll axis + public void rotateRoll(float rotateBy) { + if (Math.abs(rotateBy) < 0.01F) + return; + axes.rotateLocalRoll(rotateBy); + updatePrevAngles(); + } + + public void updatePrevAngles() { + //Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick. + double dYaw = axes.getYaw() - prevRotationYaw; + if (dYaw > 180) + prevRotationYaw += 360F; + if (dYaw < -180) + prevRotationYaw -= 360F; + + double dPitch = axes.getPitch() - prevRotationPitch; + if (dPitch > 180) + prevRotationPitch += 360F; + if (dPitch < -180) + prevRotationPitch -= 360F; + + double dRoll = axes.getRoll() - prevRotationRoll; + if (dRoll > 180) + prevRotationRoll += 360F; + if (dRoll < -180) + prevRotationRoll -= 360F; + } + + public void setRotation(float rotYaw, float rotPitch, float rotRoll) { + axes.setAngles(rotYaw, rotPitch, rotRoll); + } + + //Used to stop self collision + public boolean isPartOfThis(Entity ent) { + for (EntitySeat seat : seats) { + if (seat == null) + continue; + if (ent == seat) + return true; + if (seat.riddenByEntity == ent) + return true; + } + return ent == this; + } + + @Override + public float getShadowSize() { + return 0.0F; + } + + public DriveableType getDriveableType() { + return DriveableType.getDriveable(driveableType); + } + + public DriveableData getDriveableData() { + return driveableData; + } + + @Override + public boolean isDead() { + return isDead; + } + + @Override + public Entity getControllingEntity() { + return seats[0].getControllingEntity(); + } + + @Override + public ItemStack getPickedResult(MovingObjectPosition target) { + ItemStack stack = new ItemStack(getDriveableType().item, 1, 0); + stack.stackTagCompound = new NBTTagCompound(); + driveableData.writeToNBT(stack.stackTagCompound); + return stack; + } + + public boolean hasEnoughFuel() { + //if (seats == null || seats[0] == null || seats[0].riddenByEntity == null) + //return false; + return driverIsCreative() || driveableData.fuelInTank > Math.abs(driveableData.engine.fuelConsumption * throttle) || getDriveableType().fuelTankSize < 0; + } + + //Physics time! Oooh yeah + + public double getSpeedXYZ() { + return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); + } + + public double getSpeedXZ() { + return Math.sqrt(motionX * motionX + motionZ * motionZ); + } + + public double getHackySpeedXYZ() { + double dx = (posX - lastTickPosX); + double dy = (posY - lastTickPosY); + double dz = (posZ - lastTickPosZ); + return Math.sqrt(dx * dx + dy * dy + dz * dz); + // Blocks per tick. + } + + /** + * To be overriden by vehicles to get alternate collision system + */ + public boolean landVehicle() { + return false; + } + + /** + * Overriden by planes for wheel parts + */ + public boolean gearDown() { + return true; + } + + /** + * Whether or not the plane is on the ground + * TODO : Replace with proper check based on wheels + */ + public boolean onGround() { + return onGround; + } + + + //Collision mechanism mkII + @SuppressWarnings("unused") + public void moveRiders(Entity rider) { + if (isPartOfThis(rider)) return; + boolean isHuman = false; + boolean isDriveable = false; + if (!(rider instanceof EntityPlayer)) return; + + + Vector3f riderPos = new Vector3f(rider.posX, rider.posY, rider.posZ); + Vector3f riderMotion = new Vector3f(rider.motionX, rider.motionY, rider.motionY); + Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); + if (rider instanceof EntityVehicle) vehicleMotion = ((EntityVehicle) rider).lastPos; + //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); + Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); + Vector3f relativePos = Vector3f.sub(riderPos, vehiclePos, null); + if (rider instanceof EntityPlayer) isHuman = true; + if (rider instanceof EntityDriveable) isDriveable = true; + relativePos = new Vector3f(relativePos.x, relativePos.y - ((isHuman) ? 0.55F : 0), relativePos.z); + + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); + Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(riderMotion); + + Vector3f ellipsoid = new Vector3f(rider.width / 2, rider.height, rider.width / 2); + + CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), riderMotion); + test.collisionRecursiveDepth = 0; + + Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); + Vector3f eSpaceVelocity = test.velocity; + + //Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); + DriveableType type = getDriveableType(); + //Check parts for collision + if (type.fancyCollision) { + //checkCollision(test, getDriveableType().colbox); + for (CollisionShapeBox sbox : type.collisionBox) { + checkCollision(test, sbox); + } + } else { + for (DriveablePart ppart : getDriveableData().parts.values()) { + ppart.rayTraceRider(this, test); + } + } + + if (test.didCollide) { + Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); + + if (finalPos == null) { + finalPos = new Vector3f(0, 0, 0); + if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [1]"); + } + + Vector3f velocity = Vector3f.sub(finalPos, test.basePoint, null); + test.ConvertESpaceToR3(velocity); + finalPos = new Vector3f(finalPos.x * test.eRad.x, finalPos.y * test.eRad.y, finalPos.z * test.eRad.z); + // TODO: Better way to check this + if (finalPos == null) { + finalPos = new Vector3f(0, 0, 0); + if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [2]"); + } + Vector3f diff = Vector3f.sub(finalPos, vehiclePos, null); + + + if (rider.onGround && (posY + finalPos.y + 10 / 16F) < riderPos.y) { + //finalPos = new Vector3f(finalPos.x, 0, finalPos.z); + } + //boolean onTop = (rider.posY + 0.65 > test.intersectionPoint.y); + + boolean stationary = (throttle == 0); + + //If finalPos returns null, do something about it. Probably not the best way to handle this. + //if(finalPos == null) finalPos = new Vector3f(0,0,0); + + test.ConvertESpaceToR3(finalPos); + boolean onTop = (test.collisionPlaneNormal.y >= 0.5F); + if (posY + finalPos.y + 10 / 16F < riderPos.y) finalPos.y = (riderPos.y - (float) posY - 10F / 16F); + if (!hugeBoat) + rider.setPosition((!onTop) ? riderPos.x + finalPos.x / (48 * Math.abs(relativePos.x)) : riderPos.x, (onTop) ? posY + finalPos.y + 10 / 16F : riderPos.y, (!onTop) ? riderPos.z + finalPos.z / (48 * Math.abs(relativePos.z)) : riderPos.z); + //test.ConvertESpaceToR3(test.intersectionPoint); + //FlansMod.proxy.spawnParticle("flame", test.intersectionPoint.x + posX, test.intersectionPoint.y + posY - 1, test.intersectionPoint.z + posZ, 0, 0, 0); + + if (hugeBoat && !stationary) { + rider.setPosition(riderPos.x, posY + finalPos.y + 9.5 / 16F, riderPos.z); + } else if (hugeBoat && stationary) { + rider.setPosition(riderPos.x, posY + finalPos.y + 10 / 16F, riderPos.z); + } + finalPos = Vector3f.sub(finalPos, riderPos, null); + finalPos.normalise(); + + //rider.motionX = rider.motionX * finalPos.x; + rider.motionY = 0; + //rider.motionZ = rider.motionZ * finalPos.z; + + + //Vector3f intersect = test.intersectionPoint; + //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX + intersect.x, posY + intersect.y, posZ + intersect.z, 0,1,0); + //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX, posY, posZ, 0,1,0); + //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", riderPos.x, riderPos.y, riderPos.z, 0,1,0); + + //worldObj.spawnParticle("crit", posX + finalPos.x, posY + finalPos.y, posZ + finalPos.z, 0,0,0); + //worldObj.spawnParticle("reddust", riderPos.x, riderPos.y - 0.65, riderPos.z, 0,0,0); + + + updateRiderPos(rider, test, finalPos, riderMotion); + + if (getDriveableType().collisionDamageEnable && !test.isOnTop) { + if (throttle > getDriveableType().collisionDamageThrottle) { + boolean canDamage = true; + if (TeamsManager.getInstance() != null && TeamsManager.getInstance().currentRound != null && rider instanceof EntityPlayerMP && seats[0].riddenByEntity instanceof EntityPlayer) { + EntityPlayerMP attacker = (EntityPlayerMP) seats[0].riddenByEntity; + EntityPlayerMP player = (EntityPlayerMP) rider; + if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team != null) { + if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team != null) { + if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team == TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team) { + canDamage = false; + } + } + } + } + for (EntitySeat seat : seats) { + if (rider == seat.lastRiddenByEntity) { + canDamage = false; + break; + } + } + + if (canDamage) { + if (rider instanceof EntityLiving) { + rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } else if (rider instanceof EntityPlayer) { + rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } + } + } + } + if (rider instanceof EntityPlayer) { + EntityPlayer player = (EntityPlayer) rider; + //playerIDs.add(player); + player.onGround = true; + player.isAirBorne = false; + player.fallDistance = 0; + } + + } else { + if (rider instanceof EntityDriveable) { + //((EntityDriveable)rider).onDeck = false; + ((EntityDriveable) rider).deckHeight = 0; + } + } + + + } + + /** + * @SubscribeEvent public void updateRiders(LivingUpdateEvent event){ + *

+ * for(EntityPlayer player: playerIDs){ + * Entity p = (Entity)player; + * if(p == event.entity){ + * player.onGround = true; + * player.isAirBorne = false; + * player.fallDistance = 0; + * playerIDs.remove(player); + * } + * } + * } + */ + + public DamageSource getBulletDamage(boolean headshot) { + DriveableType type = getDriveableType(); + EntityLivingBase owner = (EntityLivingBase) seats[0].riddenByEntity; + if (owner instanceof EntityPlayer) + return (new EntityDamageSourceFlans(getDriveableType().shortName, this, (EntityPlayer) owner, type, headshot, false)).setProjectile(); + else return (new EntityDamageSourceIndirect(type.shortName, this, owner)).setProjectile(); + } + + public void checkCollision(CollisionTest tester, CollisionShapeBox box) { + { + double distance = tester.nearestDistance; + Vector3f collisionPoint = new Vector3f(0, 0, 0); + int surface = 0; + + Vector3f pos = new Vector3f(this.posX, this.posY, this.posZ); + + RotatedAxes shift = axes; + + float f4 = box.pos.x + box.size.x; + float f5 = -box.pos.y + box.size.y; + float f6 = box.pos.z + box.size.z; + + box.pos = new Vector3f(box.pos.x, box.pos.y, box.pos.z); + //if(EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret) return; + //Define box verticies, where z > 0 is right. See shapeboxes in the toolbox for a visual reference + Vector3f p1 = new Vector3f(box.pos.x - box.p1.x, box.pos.y + box.size.y + box.p1.y - box.size.y + 0.625F, box.pos.z - box.p1.z); + Vector3f p2 = new Vector3f(box.pos.x + box.size.x + box.p2.x, box.pos.y + box.size.y + box.p2.y - box.size.y + 0.625F, box.pos.z - box.p2.z); + Vector3f p3 = new Vector3f(box.pos.x + box.size.x + box.p3.x, box.pos.y + box.size.y + box.p3.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p3.z); + Vector3f p4 = new Vector3f(box.pos.x - box.p4.x, box.pos.y + box.size.y + box.p4.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p4.z); + Vector3f p5 = new Vector3f(box.pos.x - box.p5.x, box.pos.y - box.p5.y - box.size.y + 0.625F, box.pos.z - box.p5.z); + Vector3f p6 = new Vector3f(box.pos.x + box.size.x + box.p6.x, box.pos.y - box.p6.y - box.size.y + 0.625F, box.pos.z - box.p6.z); + Vector3f p7 = new Vector3f(box.pos.x + box.size.x + box.p7.x, box.pos.y - box.p7.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p7.z); + Vector3f p8 = new Vector3f(box.pos.x - box.p8.x, box.pos.y - box.p8.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p8.z); + + if (EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret && seats[0] != null) { + p1 = getPositionOnTurret(p1, false); //Front upper left + p2 = getPositionOnTurret(p2, false); //Front upper right + p3 = getPositionOnTurret(p3, false); //Rear upper right + p4 = getPositionOnTurret(p4, false); //Rear upper left + p5 = getPositionOnTurret(p5, false); //Front lower left + p6 = getPositionOnTurret(p6, false); //Front lower right + p7 = getPositionOnTurret(p7, false); //Rear lower right + p8 = getPositionOnTurret(p8, false); //Rear lower left + } else { + p1 = shift.findLocalVectorGlobally(p1); + p2 = shift.findLocalVectorGlobally(p2); + p3 = shift.findLocalVectorGlobally(p3); + p4 = shift.findLocalVectorGlobally(p4); + p5 = shift.findLocalVectorGlobally(p5); + p6 = shift.findLocalVectorGlobally(p6); + p7 = shift.findLocalVectorGlobally(p7); + p8 = shift.findLocalVectorGlobally(p8); + } + + + //Check top face + double topFaceDist = 100; + + tester.checkTriangle(tester, p3, p2, p1); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); + } + + tester.checkTriangle(tester, p4, p3, p1); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); + } + + if (tester.didCollide) { + tester.isOnTop = true; + topFaceDist = tester.nearestDistance; } - case 10: //Change control mode : Do nothing - { - FlansMod.proxy.changeControlMode((EntityPlayer) seats[0].riddenByEntity); - seats[0].targetYaw = seats[0].looking.getYaw(); - seats[0].targetPitch = seats[0].looking.getPitch(); - return true; + + //Check front face + tester.checkTriangle(tester, p6, p7, p3); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 2; + tester.part = EnumDriveablePart.getPart(box.part); } - case 11: //Roll left : Do nothing - { - seats[0].targetYaw -= seats[0].seatInfo.aimingSpeed.x; - return true; + tester.checkTriangle(tester, p3, p2, p6); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 2; + tester.part = EnumDriveablePart.getPart(box.part); } - case 12: //Roll right : Do nothing - { - seats[0].targetYaw += seats[0].seatInfo.aimingSpeed.x; - return true; + + + //Check rear face + tester.checkTriangle(tester, p4, p1, p5); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 3; + tester.part = EnumDriveablePart.getPart(box.part); } - case 13: // Gear : Do nothing - { - if (seats[0].targetPitch < -seats[0].seatInfo.minPitch) - seats[0].targetPitch += seats[0].seatInfo.aimingSpeed.y; - return true; + tester.checkTriangle(tester, p5, p8, p4); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 3; + tester.part = EnumDriveablePart.getPart(box.part); } - case 14: // Door - { - if (toggleTimer <= 0) { - varDoor = !varDoor; - if (type.hasDoor) - player.addChatMessage(new ChatComponentText("Doors " + (varDoor ? "opened" : "closed"))); - toggleTimer = 10; - FlansMod.getPacketHandler().sendToServer(new PacketVehicleControl(this)); - } - return true; + + //Check Left Face + tester.checkTriangle(tester, p6, p5, p1); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 4; + tester.part = EnumDriveablePart.getPart(box.part); } - case 15: // Wing : Do nothing - { - if (seats[0].targetPitch > -seats[0].seatInfo.maxPitch) - seats[0].targetPitch -= seats[0].seatInfo.aimingSpeed.y; - return true; + tester.checkTriangle(tester, p1, p2, p6); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 4; + tester.part = EnumDriveablePart.getPart(box.part); } - case 16: // Trim Button - { - //applyTorque(new Vector3f(axes.getRoll() / 10, 0F, 0F)); - return true; + + //Check right face + tester.checkTriangle(tester, p8, p7, p3); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 5; + tester.part = EnumDriveablePart.getPart(box.part); } - case 17: //Park - { - break; + tester.checkTriangle(tester, p3, p4, p8); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 5; + tester.part = EnumDriveablePart.getPart(box.part); } - case 18: //Flare - { - if (type.hasFlare && this.ticksFlareUsing <= 0 && this.flareDelay <= 0) { - this.ticksFlareUsing = type.timeFlareUsing * 20; - this.flareDelay = type.flareDelay; - dischargeSmoke(); - if (worldObj.isRemote) { - FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); - } else { - dischargeSmoke(); - if (!type.flareSound.isEmpty()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.flareSound, false); - } - } - return true; - } - break; + //Check bottom face + tester.checkTriangle(tester, p5, p6, p7); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); } - } - return false; - } - @SideOnly(Side.CLIENT) - public void resetZoom() { - if (TeamsManager.allowVehicleZoom) { - Minecraft mc = Minecraft.getMinecraft(); - if (mc.gameSettings.fovSetting == 10) { - mc.gameSettings.fovSetting = 70; - mc.gameSettings.mouseSensitivity = 0.5F; + tester.checkTriangle(tester, p8, p7, p5); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); } - } - } - @Override - public Vector3f getLookVector(ShootPoint dp) { - return rotate(seats[0].looking.getXAxis()); - } + if (tester.didCollide) { + tester.isOnTop = true; + topFaceDist = tester.nearestDistance; + } + Vector3f.add(p1, pos, p1); + Vector3f.add(p2, pos, p2); + Vector3f.add(p3, pos, p3); + Vector3f.add(p4, pos, p4); + Vector3f.add(p5, pos, p5); + Vector3f.add(p6, pos, p6); + Vector3f.add(p7, pos, p7); + Vector3f.add(p8, pos, p8); + + String particleType = "crit"; + + + if (FlansMod.DEBUG) { + FlansMod.proxy.spawnParticle(particleType, p1.x, p1.y, p1.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p2.x, p2.y, p2.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p3.x, p3.y, p3.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p4.x, p4.y, p4.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p5.x, p5.y, p5.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p6.x, p6.y, p6.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p7.x, p7.y, p7.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p8.x, p8.y, p8.z, 0, 0, 0); + + renderTri(p1, p2, p3); + renderTri(p3, p4, p1); + } + + if (tester.nearestDistance < topFaceDist) tester.isOnTop = false; - @Override - public void onUpdate() { - double bkPrevPosY = this.prevPosY; - super.onUpdate(); - animateFancyTracks(); - if (worldObj.isRemote) { - for (Entity e : findEntitiesWithinbounds()) { - if (!isPartOfThis(e) && e instanceof EntityPlayer) { - moveRiders(e); - } - } + if (surface == 1) tester.isOnTop = true; } - //wheelsYaw -= 1F; + } + public void renderTri(Vector3f p1, Vector3f p2, Vector3f p3) { + Vector3f pos = new Vector3f(posX, posY, posZ); + Vector3f p1a = Vector3f.add(p1, pos, null); + Vector3f p2a = Vector3f.add(p2, pos, null); + Vector3f p3a = Vector3f.add(p3, pos, null); - //Get vehicle type - VehicleType type = this.getVehicleType(); - DriveableData data = getDriveableData(); - if (type == null) { - FlansMod.log("Vehicle type null. Not ticking vehicle"); - return; - } + renderLine(p1a, p2a); + renderLine(p2a, p3a); + renderLine(p3a, p1a); + } - if (type.shootWithOpenDoor) { - canFire = varDoor; + public void renderLine(Vector3f in, Vector3f out) { + float dx = out.x - in.x; + float dy = out.y - in.y; + float dz = out.z - in.z; + Vector3f diff = Vector3f.sub(out, in, null); + diff.normalise(); + float distance = (float) Math.sqrt((dx * dx) + (dy * dy) + (dz * dz)); + for (int i = 0; i < 10; i++) { + float dist2 = (distance / 10) * i; + Vector3f newVec = new Vector3f(in.x + (dist2 * diff.x), in.y + (dist2 * diff.y), in.z + (dist2 * diff.z)); + FlansMod.proxy.spawnParticle("reddust", newVec.x, newVec.y, newVec.z, 0, 0, 0); } + } - //Work out if this is the client side and the player is driving - boolean thePlayerIsDrivingThis = worldObj.isRemote && seats[0] != null - && seats[0].riddenByEntity instanceof EntityPlayer - && FlansMod.proxy.isThePlayer((EntityPlayer) seats[0].riddenByEntity); - //Despawning - ticksSinceUsed++; - if (!worldObj.isRemote && seats[0].riddenByEntity != null) - ticksSinceUsed = 0; - if (!worldObj.isRemote && TeamsManager.vehicleLife > 0 && ticksSinceUsed > TeamsManager.vehicleLife * 20) { - setDead(); - } + public Vector3f collideWithDriveable(CollisionTest tester, Vector3f Pos, Vector3f vel) { + float unitScale = 1 / 16F; + float veryCloseDistance = 0.005F * unitScale; - if (this.worldObj.isRemote && (this.varFlare || this.ticksFlareUsing > (type.timeFlareUsing * 20) - 5)) { - if (this.ticksExisted % 5 == 0) { - deployedSmoke = true; + if (tester.collisionRecursiveDepth > 2) return Pos; + + tester.basePoint = Pos; + tester.didCollide = false; + + if (getDriveableType().fancyCollision) { + //checkCollision(tester, getDriveableType().colbox); + for (CollisionShapeBox sbox : getDriveableType().collisionBox) { + checkCollision(tester, sbox); + } + } else { + for (DriveablePart ppart : getDriveableData().parts.values()) { + ppart.rayTraceRider(this, tester); } } - if (type.setPlayerInvisible && !this.worldObj.isRemote && seats[0].riddenByEntity != null) - seats[0].riddenByEntity.setInvisible(true); + //If no collision, we just move along the velocity + if (tester.didCollide = false) return Vector3f.add(Pos, vel, null); - if (this.ticksFlareUsing <= 0) deployedSmoke = false; - if (this.ticksFlareUsing > 0) - this.ticksFlareUsing--; - if (this.flareDelay > 0) - this.flareDelay--; + //Collision occurred, time to sort this out + Vector3f destinationPoint = Vector3f.add(Pos, vel, null); + Vector3f newBasePoint = Pos; - //Shooting, inventories, etc. - //Decrement shell and gun timers - if (shellDelay > 0) - shellDelay--; - if (gunDelay > 0) - gunDelay--; - if (toggleTimer > 0) - toggleTimer--; - if (soundPosition > 0) - soundPosition--; - if (idlePosition > 0) - idlePosition--; + if (tester.nearestDistance >= veryCloseDistance) { + vel.normalise(); + vel.scale((float) (tester.nearestDistance - veryCloseDistance)); + newBasePoint = Vector3f.add(tester.basePoint, vel, null); - if (type.tank && !hasBothTracks()) throttle = 0; - if (disabled || !hasBothTracks()) wheelsYaw = 0; + if (vel.normalise().equals(new Vector3f(0, 0, 0))) return Vector3f.add(Pos, vel, null); - //Rotate the wheels - if (hasEnoughFuel() && isEngineActive()) { - wheelsAngle += throttle / 3.25F; - } + vel.normalise(); - prevDoorPos = doorPos; - prevDoorRot = doorRot; - prevDoor2Pos = door2Pos; - prevDoor2Rot = door2Rot; - - if (!varDoor) { - doorPos = transformPart(doorPos, type.doorPos1, type.doorRate); - doorRot = transformPart(doorRot, type.doorRot1, type.doorRotRate); - door2Pos = transformPart(door2Pos, type.door2Pos1, type.door2Rate); - door2Rot = transformPart(door2Rot, type.door2Rot1, type.door2RotRate); - } else { - doorPos = transformPart(doorPos, type.doorPos2, type.doorRate); - doorRot = transformPart(doorRot, type.doorRot2, type.doorRotRate); - door2Pos = transformPart(door2Pos, type.door2Pos2, type.door2Rate); - door2Rot = transformPart(door2Rot, type.door2Rot2, type.door2RotRate); - } - - //Return the wheels to their resting position - wheelsYaw *= 0.9F; - - //Limit wheel angles - if (wheelsYaw > 20) - wheelsYaw = 20; - if (wheelsYaw < -20) - wheelsYaw = -20; - - //Player is not driving this. Update its position from server update packets - if (worldObj.isRemote && !thePlayerIsDrivingThis) { - //The driveable is currently moving towards its server position. Continue doing so. - if (serverPositionTransitionTicker > 0) { - double x = posX + (serverPosX - posX) / serverPositionTransitionTicker; - double y = posY + (serverPosY - posY) / serverPositionTransitionTicker; - double z = posZ + (serverPosZ - posZ) / serverPositionTransitionTicker; - double dYaw = MathHelper.wrapAngleTo180_double(serverYaw - axes.getYaw()); - double dPitch = MathHelper.wrapAngleTo180_double(serverPitch - axes.getPitch()); - double dRoll = MathHelper.wrapAngleTo180_double(serverRoll - axes.getRoll()); - rotationYaw = (float) (axes.getYaw() + dYaw / serverPositionTransitionTicker); - rotationPitch = (float) (axes.getPitch() + dPitch / serverPositionTransitionTicker); - float rotationRoll = (float) (axes.getRoll() + dRoll / serverPositionTransitionTicker); - --serverPositionTransitionTicker; - setPosition(x, y, z); - setRotation(rotationYaw, rotationPitch, rotationRoll); - //return; - } - //If the driveable is at its server position and does not have the next update, it should just simulate itself as a server side driveable would, so continue - } - - //Movement - - correctWheelPos(); - - Vector3f amountToMoveCar = new Vector3f(); - - for (EntityWheel wheel : wheels) { - if (wheel == null) - continue; + //Change polygon intersection point so that the sliding plane is unaffected by the fact we move slightly less than collision tells us + Vector3f.sub(tester.intersectionPoint, new Vector3f(vel.x * veryCloseDistance, vel.y * veryCloseDistance, vel.z * veryCloseDistance), tester.intersectionPoint); + } - double prevPosYWheel = wheel.posY; - - //Hacky way of forcing the car to step up blocks - onGround = true; - wheel.onGround = true; - - //Update angles - wheel.rotationYaw = axes.getYaw(); - //Front wheels - if (!type.tank && (wheel.ID == 2 || wheel.ID == 3)) { - wheel.rotationYaw += wheelsYaw; - } - - wheel.motionX *= 0.9F; - wheel.motionY *= this.posY - bkPrevPosY < 0 ? 0.999F : 0.9F; - wheel.motionZ *= 0.9F; - - //Apply velocity - //If the player driving this is in creative, then we can thrust, no matter what - boolean canThrustCreatively = !TeamsManager.vehiclesNeedFuel || type.fuelTankSize < 0 || (seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode); - //Otherwise, check the fuel tanks! - if ((canThrustCreatively || type.fuelTankSize < 0 || data.fuelInTank > Math.abs(data.engine.fuelConsumption * throttle)) && isEngineActive()) { - if (getVehicleType().tank) { - boolean left = wheel.ID == 0 || wheel.ID == 3; - - float turningDrag = 0.02F; - wheel.motionX *= 1F - (Math.abs(wheelsYaw) * turningDrag); - wheel.motionZ *= 1F - (Math.abs(wheelsYaw) * turningDrag); - float velocityScale = 0; - if (isUnderWater()) { - velocityScale = 0.04F * (throttle > 0 ? type.maxThrottleInWater : type.maxNegativeThrottle) - * data.engine.engineSpeed; - } else { - velocityScale = 0.04F * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) - * data.engine.engineSpeed; + //Determine the sliding plane + Vector3f slidePlaneOrigin = tester.intersectionPoint; + if (tester.intersectionPoint == null) return Vector3f.add(Pos, vel, null); + Vector3f slidePlaneNormal = Vector3f.sub(newBasePoint, tester.intersectionPoint, null); + slidePlaneNormal.normalise(); - } - float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); - float effectiveWheelSpeed = (throttle + (wheelsYaw * (left ? 1 : -1) * steeringScale)) * velocityScale; - wheel.motionX += effectiveWheelSpeed * Math.cos(wheel.rotationYaw * 3.14159265F / 180F); - wheel.motionZ += effectiveWheelSpeed * Math.sin(wheel.rotationYaw * 3.14159265F / 180F); - yawSpeed += effectiveWheelSpeed * Math.sin(wheel.rotationYaw * 3.14159265F / 180F); - } else { - //if(getVehicleType().fourWheelDrive || wheel.ID == 0 || wheel.ID == 1) - { - float velocityScale = 0; - if (isUnderWater()) { - velocityScale = 0.1F * throttle - * (throttle > 0 ? type.maxThrottleInWater : type.maxNegativeThrottle) - * data.engine.engineSpeed; - } else { - velocityScale = 0.1F * throttle - * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) - * data.engine.engineSpeed; + tester.collisionPlaneNormal = slidePlaneNormal; + CollisionPlane plane = new CollisionPlane(slidePlaneOrigin, slidePlaneNormal); - } - wheel.motionX += Math.cos(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale; - wheel.motionZ += Math.sin(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale; - } + double sDV = plane.signedDistanceTo(destinationPoint); + Vector3f scaledNormal = new Vector3f(slidePlaneNormal.x * sDV, slidePlaneNormal.y * sDV, slidePlaneNormal.z * sDV); + Vector3f newDestPoint = Vector3f.sub(destinationPoint, scaledNormal, null); - //Apply steering - if (wheel.ID == 2 || wheel.ID == 3) { - float velocityScale = 0.01F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier) * (throttle > 0 ? 1 : -1); + //Generate slide vector + Vector3f newVelocityVector = Vector3f.sub(newDestPoint, tester.intersectionPoint, null); - wheel.motionX -= wheel.getSpeedXZ() * Math.sin(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale * wheelsYaw; - wheel.motionZ += wheel.getSpeedXZ() * Math.cos(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale * wheelsYaw; - } else { - wheel.motionX *= 0.9F; - wheel.motionZ *= 0.9F; - } - } + if (newVelocityVector.length() < veryCloseDistance) { + return newBasePoint; + } - if (!canThrustCreatively && TeamsManager.vehiclesNeedFuel) { - data.fuelInTank -= Math.abs(data.engine.fuelConsumption * throttle) * 0.1; - } - } + tester.collisionRecursiveDepth++; - wheel.moveEntity(wheel.motionX, wheel.motionY, wheel.motionZ); + return collideWithDriveable(tester, newBasePoint, newVelocityVector); + } - //Pull wheels towards car - Vector3f targetWheelPos = axes.findLocalVectorGlobally(getVehicleType().wheelPositions[wheel.ID].position); + @SuppressWarnings("unused") + public void updateRiderPos(Entity rider, CollisionTest test, Vector3f pos, Vector3f motion) { + boolean isDriveable = rider instanceof EntityDriveable; + Vector3f vehicleMotion = lastPos; - Vector3f currentWheelPos = new Vector3f(wheel.posX - posX, wheel.posY - posY, wheel.posZ - posZ); + Vector3f riderMountPoint = new Vector3f(rider.posX - posX, rider.posY - posY, rider.posZ - posZ); - Vector3f dPos = ((Vector3f) Vector3f.sub(targetWheelPos, currentWheelPos, null).scale(type.wheelSpringStrength)); + float yawDiff = axes.getYaw() - prevAxes.getYaw(); + float pitchDiff = axes.getPitch() - prevAxes.getPitch(); + float rollDiff = axes.getRoll() - prevAxes.getRoll(); - if (dPos.length() > 0.001F) { - wheel.moveEntity(dPos.x, dPos.y, dPos.z); - dPos.scale(0.5F); - Vector3f.sub(amountToMoveCar, dPos, amountToMoveCar); - } + RotatedAxes velAxes = new RotatedAxes(axes.getYaw() + yawDiff, axes.getPitch() + pitchDiff, axes.getRoll() + rollDiff); - float avgWheelHeight = 0F; + Vector3f currentLocalPos = axes.findGlobalVectorLocally(riderMountPoint); + Vector3f nextGlobalPos = velAxes.findLocalVectorGlobally(currentLocalPos); - //Secondary check whether all wheels are on ground... - if (wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { - avgWheelHeight = (float) (wheels[0].posX + wheels[1].posX + wheels[2].posX + wheels[3].posX) / 4; - if (!wheels[0].onGround && !wheels[1].onGround && !wheels[2].onGround && !wheels[3].onGround) { - allWheelsOnGround = false; - } else { - allWheelsOnGround = true; - } - } + Vector3f diff = new Vector3f(0, 0, 0); - //Now we apply gravity - if (!(type.floatOnWater && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, -type.floatOffset, 0))) && !wheel.onDeck) { - float a = type.maxFallSpeed; - float g = type.gravity; + //Some rubbish null checks + if (nextGlobalPos == null) nextGlobalPos = new Vector3f(0, 0, 0); - if (wheel.onGround) { - a *= 1F/2F; - g *= 3/2F; - } + Vector3f.add(vehicleMotion, diff, diff); + rider.setPosition(nextGlobalPos.x + posX + ((hugeBoat) ? diff.x / (1.5) : 0), (!isDriveable) ? rider.posY : ((EntityDriveable) rider).deckHeight, nextGlobalPos.z + posZ + ((hugeBoat) ? diff.z / (1.5) : 0)); - if (wheel.motionY >= 0) { - wheel.motionY -= g; - } else if (wheel.motionY >= -a) { - wheel.motionY -= g * (wheel.motionY + a); - } - } else if ((type.floatOnWater && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, -type.floatOffset, 0))) && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, 1 - type.floatOffset, 0)) && !wheel.onDeck) { - wheel.moveEntity(0F, 1F, 0F); - } else if ((type.floatOnWater && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, -type.floatOffset, 0))) && !worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, 1 - type.floatOffset, 0)) || wheel.onDeck) { - wheel.moveEntity(0F, 0F, 0F); - this.roll = 0; - this.pitch = 0; - }/* else { - wheel.moveEntity(0F, (!onDeck) ? -1.2F : 0, 0F); - }*/ - - if ((throttle >= 1.1 || throttle <= -1.1)) { - Vector3f motionVec = new Vector3f(0, 0, 0); - Vector3f targetVec = type.wheelPositions[wheel.ID].position; - targetVec = axes.findLocalVectorGlobally(targetVec); - if (throttle > 0.1) motionVec = new Vector3f(1, 0, 0); - if (throttle < -0.1) motionVec = new Vector3f(-1, 0, 0); - if ((wheel.ID == 2 || wheel.ID == 3) && wheelsYaw >= 0.1) motionVec = new Vector3f(motionVec.x, 0, 1); - if ((wheel.ID == 0 || wheel.ID == 1) && wheelsYaw <= -0.1) motionVec = new Vector3f(motionVec.x, 0, -1); - motionVec = axes.findLocalVectorGlobally(motionVec); - Vector3f test1Pos = new Vector3f(posX + targetVec.x + motionVec.x, posY + targetVec.y, posZ + targetVec.z + motionVec.z); - boolean test1 = worldObj.isAirBlock(Math.round(test1Pos.x), Math.round(test1Pos.y), Math.round(test1Pos.z)); - boolean test2 = worldObj.isAirBlock(Math.round(test1Pos.x), Math.round(test1Pos.y + type.wheelStepHeight), Math.round(test1Pos.z)); - if (!test1 && !test2) { - // Tests to see if we are ascending tall terrain, or stuck in the ground. - throttle *= 0.6; - for (EntityWheel wheel2 : wheels) { - Vector3f wheelPos3 = axes.findLocalVectorGlobally(type.wheelPositions[wheel2.ID].position); - } - } + if (hugeBoat) { + if (lastPos.x == 0 && lastPos.y == 0 && lastPos.z == 0) { + if (rider.motionY < 0) rider.motionY = 0; + } + } else { + if (lastPos.x != 0 || lastPos.y != 0 || lastPos.z != 0) { + rider.motionX = diff.x; + rider.motionY = diff.y; + rider.motionZ = diff.z; } } + } - if (wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { - lastPos.x = (float) (wheels[0].motionX + wheels[1].motionX + wheels[2].motionX + wheels[3].motionX) / 4; - lastPos.y = (float) (wheels[0].motionY + wheels[1].motionY + wheels[2].motionY + wheels[3].motionY) / 4; - lastPos.z = (float) (wheels[0].motionZ + wheels[1].motionZ + wheels[2].motionZ + wheels[3].motionZ) / 4; + /** + * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit + */ + public ArrayList attackFromBullet(Vector3f origin, Vector3f motion) { + //Make an array to contain the hits + ArrayList hits = new ArrayList(); + //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates + Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); + Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); + //Check each part + for (DriveablePart part : getDriveableData().parts.values()) { + //Ray trace the bullet + DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector); + if (hit != null) + hits.add(hit); } + return hits; + } + /** + * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit + */ + public ArrayList attackFromBulletButBetter(Vector3f origin, Vector3f motion, float size) { + ArrayList hits = new ArrayList(); - double bmy = this.motionY; - this.motionY = amountToMoveCar.y; - if (collisionHardness > 0.2F) { - amountToMoveCar.x = -axes.getXAxis().x*(float)getSpeedXZ()*0.1F; - amountToMoveCar.z = -axes.getXAxis().z*(float)getSpeedXZ()*0.1F; - } - collisionHardness = 0F; - moveEntity(amountToMoveCar.x, amountToMoveCar.y, amountToMoveCar.z); - - this.motionY = bmy; - if (wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { - Vector3f frontAxleCentre = new Vector3f((wheels[2].posX + wheels[3].posX) / 2F, (wheels[2].posY + wheels[3].posY) / 2F, (wheels[2].posZ + wheels[3].posZ) / 2F); - Vector3f backAxleCentre = new Vector3f((wheels[0].posX + wheels[1].posX) / 2F, (wheels[0].posY + wheels[1].posY) / 2F, (wheels[0].posZ + wheels[1].posZ) / 2F); - Vector3f leftSideCentre = new Vector3f((wheels[0].posX + wheels[3].posX) / 2F, (wheels[0].posY + wheels[3].posY) / 2F, (wheels[0].posZ + wheels[3].posZ) / 2F); - Vector3f rightSideCentre = new Vector3f((wheels[1].posX + wheels[2].posX) / 2F, (wheels[1].posY + wheels[2].posY) / 2F, (wheels[1].posZ + wheels[2].posZ) / 2F); + Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); + //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); + Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); + Vector3f relativePos = Vector3f.sub(origin, vehiclePos, null); - if (frontAxleCentre.y > backAxleCentre.y) { - if (throttle > 0) { - float diff = frontAxleCentre.y - backAxleCentre.y; - float dx = frontAxleCentre.x - backAxleCentre.x; - dx = (float) Math.sqrt(dx * dx); - float dz = frontAxleCentre.z - backAxleCentre.z; - dz = (float) Math.sqrt(dz * dz); - float dist = (float) Math.sqrt(dx + dz); - diff = diff / dist; - throttle *= (1F - (diff / 60)); - // Slows down the vehicle when going uphill. - } - } + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); + Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(motion); - float dx = frontAxleCentre.x - backAxleCentre.x; - float dy = frontAxleCentre.y - backAxleCentre.y; - float dz = frontAxleCentre.z - backAxleCentre.z; - float drx = leftSideCentre.x - rightSideCentre.x; - float dry = leftSideCentre.y - rightSideCentre.y; - float drz = leftSideCentre.z - rightSideCentre.z; + Vector3f ellipsoid = new Vector3f(size, size, size); + CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), motion); + test.collisionRecursiveDepth = 0; - float dxz = (float) Math.sqrt(dx * dx + dz * dz); - float drxz = (float) Math.sqrt(drx * drx + drz * drz); + Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); + Vector3f eSpaceVelocity = test.velocity; - float tyaw = (float) Math.atan2(dz, dx); - float tpitch = -(float) Math.atan2(dy, dxz); - float troll = 0F; - if (type.canRoll) { - troll = -(float) Math.atan2(dry, drxz); - } + for (DriveablePart ppart : getDriveableData().parts.values()) { + ppart.rayTraceRider(this, test); + } - yaw = tyaw; - pitch = Lerp(pitch, tpitch, 0.2F); - roll = Lerp(roll, troll, 0.2F); + if (test.didCollide) { + Vector3f hitPos = new Vector3f(0, 0, 0); + Vector3f intersect2 = new Vector3f(test.ConvertESpaceToR3(test.intersectionPoint)); + Vector3f.sub(origin, intersect2, hitPos); + float f = (hitPos.length() / motion.length()); + DriveableHit hit = new DriveableHit(this, test.part, f); + hits.add(hit); + } - if (type.tank) { - float effectiveWheelSpeed; - if (isEngineActive()) { - float velocityScale = 0.04F * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) - * data.engine.engineSpeed; - float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); - effectiveWheelSpeed = ((wheelsYaw * steeringScale)) * velocityScale; - } else { - effectiveWheelSpeed = 0; - } + return hits; - yaw = axes.getYaw() / 180F * 3.14159F + effectiveWheelSpeed; - } else { - float velocityScale = 0.1F * throttle * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) * data.engine.engineSpeed; - float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); - float effectiveWheelSpeed = ((wheelsYaw * steeringScale)) * velocityScale; - yaw = axes.getYaw() / 180F * 3.14159F + (effectiveWheelSpeed); - } + } - axes.setAngles(yaw * 180F / 3.14159F, pitch * 180F / 3.14159F, roll * 180F / 3.14159F); + /** + * Called if the bullet actually hit the part returned by the raytrace + * + * @param penetratingPower + */ + public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower) { + DriveablePart part = getDriveableData().parts.get(hit.part); + if (bullet != null) + penetratingPower = part.hitByBullet(bullet, hit, penetratingPower); + else + penetratingPower -= 5F; + + //This is server side bsns + if (!worldObj.isRemote) { + checkParts(); + //If it hit, send a damage update packet + FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); } - if (this.ridingEntity != null) { - if (this.ridingEntity.getClass().toString().indexOf("mcheli.aircraft.MCH_EntitySeat") > 0) { - axes.setAngles(this.ridingEntity.rotationYaw + 90, 0, 0); + return penetratingPower; + } + + /** + * A simple raytracer for the driveable. Called by tools + */ + public DriveablePart raytraceParts(Vector3f origin, Vector3f motion) { + //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates + Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); + Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); + //Check each part + for (DriveablePart part : getDriveableData().parts.values()) { + //Ray trace the bullet + if (part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null) { + return part; } } + return null; + } - checkForCollisions(); + /** + * For overriding for toggles such as gear up / down on planes + */ + public boolean canHitPart(EnumDriveablePart part) { + return true; + } - //Sounds - //Starting sound - if (Math.abs(throttle) > 0.01F && Math.abs(throttle) < 0.2F && soundPosition == 0 && hasEnoughFuel()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.startSoundRange, dimension, type.startSound, false); - soundPosition = type.startSoundLength; - } - //Flying sound - if (throttle >= 0.2F && soundPosition == 0 && hasEnoughFuel() && isEngineActive()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.engineSound, false); - soundPosition = type.engineSoundLength; - } - if (seats[0] != null) { - if (throttle <= 0.01F && throttle >= -0.2F && seats[0].riddenByEntity != null && idlePosition == 0) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.idleSound, false); - idlePosition = type.idleSoundLength; + /** + * Internal method for checking that all parts are ok, destroying broken ones, dropping items and making sure that child parts are destroyed when their parents are + */ + public void checkParts() { + for (DriveablePart part : getDriveableData().parts.values()) { + if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { + killPart(part); } } - //Back sound - if (throttle <= -0.2F && soundPosition == 0 && hasEnoughFuel() && isEngineActive()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.backSoundRange, dimension, type.backSound, false); - soundPosition = type.backSoundLength; - } - for (EntitySeat seat : seats) { - if (seat != null) { - seat.updatePosition(); - } - } - - //Calculate movement on the client and then send position, rotation etc to the server - if (thePlayerIsDrivingThis) { - FlansMod.getPacketHandler().sendToServer(new PacketVehicleControl(this)); - serverPosX = posX; - serverPosY = posY; - serverPosZ = posZ; - serverYaw = axes.getYaw(); - //if(type.IT1) - //FlansMod.getPacketHandler().sendToServer(new PacketIT1Reload(this)); - } - - //If this is the server, send position updates to everyone, having received them from the driver - if (!worldObj.isRemote && ticksExisted % 5 == 0) { - FlansMod.getPacketHandler().sendToAllAround(new PacketVehicleControl(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); - //if(type.IT1) - //FlansMod.getPacketHandler().sendToAllAround(new PacketIT1Reload(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); - - } - - int animSpeed = 4; - - if ((throttle > 0.05 && throttle <= 0.33) || (throttle < -0.05 && throttle >= -0.33)) { - animSpeed = 3; - } else if ((throttle > 0.33 && throttle <= 0.66) || (throttle < -0.33 && throttle >= -0.66)) { - animSpeed = 2; - } else if ((throttle > 0.66 && throttle <= 0.9) || (throttle < -0.66 && throttle >= -0.9)) { - animSpeed = 1; - } else if ((throttle > 0.9 && throttle <= 1) || (throttle < -0.9 && throttle >= -1)) { - animSpeed = 0; - } - - boolean turningLeft = false; - boolean turningRight = false; - - if (throttle > 0.05) { - animCountLeft--; - animCountRight--; - } else if (throttle < -0.05) { - animCountLeft++; - animCountRight++; - } else if (wheelsYaw < -1) { - turningLeft = true; - animCountLeft++; - animCountRight--; - animSpeed = 1; - if (soundPosition == 0 && hasEnoughFuel() && type.tank && isEngineActive()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.engineSound, false); - soundPosition = type.engineSoundLength; - } - } else if (wheelsYaw > 1) { - turningRight = true; - animCountLeft--; - animCountRight++; - animSpeed = 1; - if (soundPosition == 0 && hasEnoughFuel() && type.tank && isEngineActive() && isEngineActive()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.engineSound, false); - soundPosition = type.engineSoundLength; - } - } else { - turningLeft = false; - turningRight = false; - } + //If the core was destroyed, kill the driveable + if (getDriveableData().parts.get(EnumDriveablePart.core).dead) { + int seatNum = seats.length; - if (animCountLeft <= 0) { - animCountLeft = animSpeed; - animFrameLeft++; - } + DriveableType type = getDriveableType(); - if (animCountRight <= 0) { - animCountRight = animSpeed; - animFrameRight++; - } + if (!worldObj.isRemote) { + for (EntitySeat seat : seats) { + if (seat.riddenByEntity instanceof EntityPlayer) { +// ((EntityPlayer)seats[i].riddenByEntity).addPotionEffect(new PotionEffect(Potion.harm.id, 10, 5)); + Entity entity = seat.riddenByEntity; + seat.riddenByEntity.setInvisible(false); + seat.riddenByEntity.mountEntity(null); + if (this.lastAtkEntity instanceof EntityPlayer) { + entity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) this.lastAtkEntity), 10000000); + } else if (this.lastAtkEntity instanceof EntityLivingBase) { + entity.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) this.lastAtkEntity), 10000000); + } + } + } - if (throttle < 0 || turningLeft) { - if (animCountLeft >= animSpeed) { - animCountLeft = 0; - animFrameLeft--; + if (type.isExplosionWhenDestroyed) +//Create a flans mod explosion rather than a standard MC one. allows control over death boom + { + new FlansModExplosion(worldObj, this, null, type, posX, posY, posZ, + type.deathExplosionRadius, type.deathExplosionPower,TeamsManager.explosions && type.deathExplosionBreaksBlocks, + type.deathExplosionDamageVsLiving, type.deathExplosionDamageVsPlayer, type.deathExplosionDamageVsPlane, type.deathExplosionDamageVsVehicle, seatNum, seatNum); + + } + if(!worldObj.isRemote && type.deathFireRadius > 0.1F) + { + for(float i = -type.deathFireRadius; i < type.deathFireRadius; i++) + { + for(float j = -type.deathFireRadius; j < type.deathFireRadius; j++) + { + for(float k = -type.deathFireRadius; k < type.deathFireRadius; k++) + { + int x = MathHelper.floor_double(i + posX); + int y = MathHelper.floor_double(j + posY); + int z = MathHelper.floor_double(k + posZ); + if(i * i + j * j + k * k <= type.deathFireRadius * type.deathFireRadius && worldObj.getBlock(x, y, z) == Blocks.air && rand.nextBoolean()) + { + worldObj.setBlock(x, y, z, Blocks.fire, 0, 3); + } + } + } + } + } + + for (DriveablePart part : driveableData.parts.values()) { + if (part.health > 0 && !part.dead) + killPart(part); + } } - } - - if (throttle < 0 || turningRight) { - if (animCountRight >= animSpeed) { - animCountRight = 0; - animFrameRight--; + setDead(); + if(lastAtkEntity!=null&&lastAtkEntity instanceof EntityPlayerMP) { + if (TeamsManager.instance.currentRound != null) { + TeamsManager.instance.currentRound.gametype.vehicleDestroyed(this, (EntityPlayerMP) lastAtkEntity); + } } } - if (animFrameLeft > type.animFrames) { - animFrameLeft = 0; - } - if (animFrameLeft < 0) { - animFrameLeft = type.animFrames; - } + } - if (animFrameRight > type.animFrames) { - animFrameRight = 0; - } - if (animFrameRight < 0) { - animFrameRight = type.animFrames; + public void checkPartsWhenAttacked() { + for (DriveablePart part : getDriveableData().parts.values()) { + if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { + killPart(part); + } } + } - // Decrease throttle each tick. - if (throttle > 0) - throttle -= type.throttleDecay; - else if (throttle < 0) - throttle += type.throttleDecay; - - //Catch to round the throttle down to zero. - if (throttle < type.throttleDecay && throttle > -type.throttleDecay) - throttle = 0; - - //if(seats[0].riddenByEntity == null) throttle = 1F; - - //boolean sentry2; - //sentry2 = false; - /** - if(sentry2){ - if(target != null && target.isDead) - target = null; - } - - if(target == null && sentry2) - { - target = getValidTarget(); - } - - if(target != null) - { - - double dX = target.posX - posX; - double dY = target.posY - (posY); - double dZ = target.posZ - posZ; - boolean canShootHomingMissile = false; - - double distanceToTarget = target.getDistanceToEntity(this); - dX += (target.posX - target.prevPosX) * (distanceToTarget/type.bulletSpeed); - dY += (target.posY - target.prevPosY) * (distanceToTarget/type.bulletSpeed); - dZ += (target.posZ - target.prevPosZ) * (distanceToTarget/type.bulletSpeed); - - int slot = -1; - for(int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) - { - ItemStack bomb = driveableData.getStackInSlot(i); - if(bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)bomb.getItem()).type, EnumWeaponType.SHELL)) - { - slot = i; - } - } - - if(slot != -1) - { - ItemStack bulletStack = driveableData.getStackInSlot(slot); - ItemBullet bulletItem = (ItemBullet)bulletStack.getItem(); - - - } - //distanceToTarget = Math.sqrt((dX * dX) + (dZ * dZ)); - Vector3f initialMot = (this.getPositionOnTurret(new Vector3f(type.bulletSpeed, 0, 0), true)); - float bulletSpeed2 = (float)Math.sqrt((initialMot.x * initialMot.x) + (initialMot.z * initialMot.z)); - float travelTime = (float)distanceToTarget/type.bulletSpeed; - dY += initialMot.y + (0.02F * travelTime); - distanceToTarget = Math.sqrt(dX * dX + dY * dY + dZ * dZ); - float targetRange = 150F; - if(distanceToTarget > targetRange) - target = null; - else if(!canShootHomingMissile) - { - float newYaw = (float)Math.atan2(dZ, dX) * 180F / 3.14159F - axes.getYaw(); - float newPitch = -(float)Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180F / 3.14159F - axes.getPitch(); - - float turnSpeed = 0.25F; - for(; newYaw > 180F; newYaw -= 360F) {} - for(; newYaw <= -180F; newYaw += 360F) {} - - - if(newPitch > -seats[0].seatInfo.minPitch) - newPitch = -seats[0].seatInfo.minPitch; - if(newPitch < -seats[0].seatInfo.maxPitch) - newPitch = -seats[0].seatInfo.maxPitch; - //seats[0].targetYaw = newYaw; - //seats[0].targetPitch = newPitch; - seats[0].looking.setAngles(moveToTarget(seats[0].looking.getYaw(), newYaw, seats[0].seatInfo.aimingSpeed.x), moveToTarget(seats[0].looking.getPitch(), newPitch, seats[0].seatInfo.aimingSpeed.y), 0F); - } - } - */ - - //rotateYaw(10); - } - - public Entity getValidTarget() { - - if (placer == null && placerName != null) - placer = worldObj.getPlayerEntityByName(placerName); - float targetRange = 150F; - Entity target = null; - for (Object obj : worldObj.getEntitiesWithinAABBExcludingEntity(this, boundingBox.expand(targetRange, targetRange, targetRange))) { - Entity candidateEntity = (Entity) obj; - boolean targetMobs = true; - boolean targetPlayers = false; - boolean targetPlanes = true; - boolean targetVehicles = true; - if ((targetMobs && candidateEntity instanceof EntityBat) || (targetPlayers && candidateEntity instanceof EntityPlayer) || (targetPlanes && candidateEntity instanceof EntityPlane) || (targetVehicles && candidateEntity instanceof EntityVehicle)) { - //Check that this entity is actually in range and visible - if (candidateEntity.getDistanceToEntity(this) < targetRange) { - targetRange = candidateEntity.getDistanceToEntity(this); - if (isPartOfThis(candidateEntity)) candidateEntity = null; - if (candidateEntity instanceof EntityPlayer) { - if (candidateEntity == placer || candidateEntity.getCommandSenderName().equals(placerName)) - candidateEntity = null; - if (TeamsManager.enabled && TeamsManager.getInstance().currentRound != null && placer != null) { - PlayerData placerData = PlayerHandler.getPlayerData(placer, worldObj.isRemote ? Side.CLIENT : Side.SERVER); - PlayerData candidateData = PlayerHandler.getPlayerData((EntityPlayer) candidateEntity, worldObj.isRemote ? Side.CLIENT : Side.SERVER); - if (candidateData.team == Team.spectators || candidateData.team == null) - candidateEntity = null; - if (!TeamsManager.getInstance().currentRound.gametype.playerCanAttack((EntityPlayerMP) placer, placerData.team, (EntityPlayerMP) candidateEntity, candidateData.team)) - candidateEntity = null; - } + /** + * Internal method for killing driveable parts + */ + private void killPart(DriveablePart part) { + if (part.dead) + return; + part.health = 0; + part.dead = true; + + //Drop items + DriveableType type = getDriveableType(); + if (!worldObj.isRemote) { + Vector3f pos = new Vector3f(0, 0, 0); + + //Get the midpoint of the part + if (part.box != null) + pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); + + ArrayList drops = type.getItemsRequired(part, getDriveableData().engine); + if (drops != null) { + //Drop each ItemStack + for (ItemStack stack : drops) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy())); + } + } + dropItemsOnPartDeath(pos, part); + + //Inventory is in the core, so drop it if the core is broken + if (part.type == EnumDriveablePart.core) { + for (int i = 0; i < getDriveableData().getSizeInventory(); i++) { + ItemStack stack = getDriveableData().getStackInSlot(i); + if (stack != null) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack)); } - target = candidateEntity; } } } - if (target != null) - return target; - else return null; + + //Kill all child parts to stop things floating unconnected + for (EnumDriveablePart child : part.type.getChildren()) { + killPart(getDriveableData().parts.get(child)); + } } - public void animateFancyTracks() { - float funkypart = getVehicleType().trackLinkFix; - boolean funk = true; - float funk2 = 0; - for (int i = 0; i < trackLinksLeft.length; i++) { - trackLinksLeft[i].prevPosition = trackLinksLeft[i].position; - trackLinksLeft[i].prevZRot = trackLinksLeft[i].zRot; - float speed = throttle * 1.5F - (wheelsYaw / 12); - trackLinksLeft[i].progress += speed; - if (trackLinksLeft[i].progress > leftTrack.getTrackLength()) - trackLinksLeft[i].progress -= leftTrack.getTrackLength(); - if (trackLinksLeft[i].progress < 0) trackLinksLeft[i].progress += leftTrack.getTrackLength(); - trackLinksLeft[i].position = leftTrack.getPositionOnTrack(trackLinksLeft[i].progress); - for (; trackLinksLeft[i].zRot > 180F; trackLinksLeft[i].zRot -= 360F) { - } - for (; trackLinksLeft[i].zRot <= -180F; trackLinksLeft[i].zRot += 360F) { - } - float newAngle = rotateTowards(leftTrack.points.get(leftTrack.getTrackPart(trackLinksLeft[i].progress)), trackLinksLeft[i].position); - int part = leftTrack.getTrackPart(trackLinksLeft[i].progress); - if (funk) funk2 = (speed < 0) ? 0 : 1; - else funk2 = (speed < 0) ? -1 : 0; - trackLinksLeft[i].zRot = Lerp(trackLinksLeft[i].zRot, newAngle, (part != (funkypart + funk2)) ? 0.5F : 1); + /** + * Method for planes, vehicles and whatnot to drop their own specific items if they wish + */ + protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part); - } + @Override + public float getPlayerRoll() { + return axes.getRoll(); + } + + @Override + public void explode() { - for (int i = 0; i < trackLinksRight.length; i++) { - trackLinksRight[i].prevPosition = trackLinksRight[i].position; - trackLinksRight[i].prevZRot = trackLinksRight[i].zRot; - float speed = throttle * 1.5F + (wheelsYaw / 12); - trackLinksRight[i].progress += speed; - if (trackLinksRight[i].progress > rightTrack.getTrackLength()) - trackLinksRight[i].progress -= leftTrack.getTrackLength(); - if (trackLinksRight[i].progress < 0) trackLinksRight[i].progress += rightTrack.getTrackLength(); - trackLinksRight[i].position = rightTrack.getPositionOnTrack(trackLinksRight[i].progress); - float newAngle = rotateTowards(rightTrack.points.get(rightTrack.getTrackPart(trackLinksRight[i].progress)), trackLinksRight[i].position); - int part = rightTrack.getTrackPart(trackLinksRight[i].progress); - if (funk) funk2 = (speed < 0) ? 0 : 1; - else funk2 = (speed < 0) ? -1 : 0; - trackLinksRight[i].zRot = Lerp(trackLinksRight[i].zRot, newAngle, (part != (funkypart + funk2)) ? 0.5F : 1); - } } - public float rotateTowards(Vector3f point, Vector3f original) { + @Override + public float getCameraDistance() { + return getDriveableType().cameraDistance; + } - float angle = (float) Math.atan2(point.y - original.y, point.x - original.x); - return angle; + public boolean isPartIntact(EnumDriveablePart part) { + DriveablePart thisPart = getDriveableData().parts.get(part); + return thisPart.maxHealth == 0 || thisPart.health > 0; } - public void dischargeSmoke() { - VehicleType type = this.getVehicleType(); - for (int i = 0; i < type.smokers.size(); i++) { - SmokePoint smoker = type.smokers.get(i); - Vector3f dir = smoker.direction; - Vector3f pos = smoker.position; - int time = smoker.detTime; + public abstract boolean hasMouseControlMode(); - dir = axes.findLocalVectorGlobally(dir); - pos = axes.findLocalVectorGlobally(pos); + public abstract String getBombInventoryName(); - if (EnumDriveablePart.getPart(smoker.part) == EnumDriveablePart.turret) { - dir = rotate(seats[0].looking.findLocalVectorGlobally(smoker.direction)); - pos = getPositionOnTurret(smoker.position, false); - } + public abstract String getMissileInventoryName(); - //FlansMod.getPacketHandler().sendToAllAround(new PacketSmokeGrenade(posX + pos.x/16, posY + pos.y/16, posZ + pos.z/16, dir.x, dir.y, dir.z, time), posX, posY, posZ, 150, dimension); + public boolean rotateWithTurret(Seat seat) { + return seat.part == EnumDriveablePart.turret; + } - //FlansMod.proxy.spawnSmokeGrenade("flansmod.smoker", posX + pos.x/16, posY + pos.y/16, posZ + pos.z/16, dir.x, dir.y, dir.z, time); + @Override + public String getCommandSenderName() { + return getDriveableType().name; + } - FlansMod.getPacketHandler().sendToAllAround(new PacketParticle("flansmod.smoker", posX + pos.x / 16, posY + pos.y / 16, posZ + pos.z / 16, dir.x, dir.y, dir.z), posX, posY, posZ, 150, dimension); - } + @SideOnly(Side.CLIENT) + public boolean showInventory(int seat) { + return seat != 0 || !FlansModClient.controlModeMouse; } - public float Lerp(float start, float end, float percent) { - float result = (start + percent * (end - start)); + //------------------------------------- + // Getters and setters for dual fields + //------------------------------------- - return result; + public float getShootDelay(boolean secondary) { + return secondary ? shootDelaySecondary : shootDelayPrimary; } - public static float Clamp(float val, float min, float max) { - return Math.max(min, Math.min(max, val)); + public boolean canLaunchIT1() { + return canFireIT1; } - public List findEntitiesWithinbounds() { - VehicleType type = this.getVehicleType(); - AxisAlignedBB initialBox = this.boundingBox.copy(); - List riddenEntities = worldObj.getEntitiesWithinAABB(Entity.class, initialBox); + public float getMinigunSpeed(boolean secondary) { + return secondary ? minigunSpeedSecondary : minigunSpeedPrimary; + } - Vector3f size = new Vector3f(type.harvestBoxSize.x / 8F, type.harvestBoxSize.y / 8F, type.harvestBoxSize.z / 8F); - Vector3f pos = new Vector3f(type.harvestBoxPos.x / 8F, type.harvestBoxPos.y / 8F, type.harvestBoxPos.z / 8F); - boolean fancy = false; - if (!fancy) { - for (float x = pos.x; x <= pos.x + size.x; x++) { - for (float y = pos.y; y <= pos.y + size.y; y++) { - for (float z = pos.z; z <= pos.z + size.z; z++) { - Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); + public int getCurrentGun(boolean secondary) { + return secondary ? currentGunSecondary : currentGunPrimary; + } - double entX = (posX + v.x); - double entY = (posY + v.y); - double entZ = (posZ + v.z); - AxisAlignedBB checkBox = this.boundingBox.copy().offset(v.x, v.y, v.z); + public void setShootDelay(float i, boolean secondary) { + setRecoilTimer(); + // If current delay is greater than i, use that. If current delay is less than 0, add that to new shoot delay + if (secondary) + shootDelaySecondary = i > shootDelaySecondary ? (shootDelaySecondary < 0 ? i + shootDelaySecondary : i) : shootDelaySecondary; + else + shootDelayPrimary = i > shootDelayPrimary ? (shootDelayPrimary < 0 ? i + shootDelayPrimary : i) : shootDelayPrimary; + } - List entityhere = worldObj.getEntitiesWithinAABB(Entity.class, checkBox); + public void setMinigunSpeed(float f, boolean secondary) { + if (secondary) + minigunSpeedSecondary = f; + else minigunSpeedPrimary = f; + } - for (int i = 0; i < entityhere.size(); i++) { - if (entityhere.get(i) instanceof EntityPlayer && !isPartOfThis(entityhere.get(i))) - riddenEntities.add(entityhere.get(i)); - } - //Iterator iter = entityhere.iterator(); - /** - while( iter.hasNext() ) - { - Entity entity = iter.next(); - if(isPartOfThis(entity)) iter.remove(); - if(entity instanceof EntityBullet) iter.remove(); - } */ + public void setCurrentGun(int i, boolean secondary) { + if (secondary) + currentGunSecondary = i; + else currentGunPrimary = i; + } - } - } - } - } else { - AxisAlignedBB checkBox = this.getBoundingBox().copy().expand(50, 50, 50); + public void setEntityMarker(int tick) { + this.isShowedPosition = true; + this.tickCount = tick; + } - List entityhere = worldObj.getEntitiesWithinAABB(EntityPlayer.class, checkBox); + public void IT1Reload() { + DriveableType type = getDriveableType(); - for (int i = 0; i < entityhere.size(); i++) { - if (entityhere.get(i) instanceof EntityPlayer) { - riddenEntities.add(entityhere.get(i)); - //AxisAlignedBB checkBox2 = this.boundingBox.copy().offset(this.posX - entityhere.get(i).posX,this.posY - entityhere.get(i).posY, this.posZ - entityhere.get(i).posZ); - } - } + if (stage == 1) { + //canFireIT1 = false; + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 5); + + if (drakonRailAngle == -10) stage++; } - return riddenEntities; - } - public Vector3f transformPart(Vector3f current, Vector3f target, Vector3f rate) { - Vector3f newPos = current; - if (Math.sqrt((current.x - target.x) * (current.x - target.x)) > rate.x / 2) { - if (current.x > target.x) { - current.x = current.x - rate.x; - } else if (current.x < target.x) { - current.x = current.x + rate.x; - } - } else { - current.x = target.x; + if (stage == 2) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonDoorAngle == -90) stage++; } - if (Math.sqrt((current.y - target.y) * (current.y - target.y)) > rate.y / 2) { - if (current.y > target.y) { - current.y = current.y - rate.y; - } else if (current.y < target.y) { - current.y = current.y + rate.y; - } - } else { - current.y = target.y; + if (stage == 3) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 179, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonArmAngle == 179) stage++; } - if (Math.sqrt((current.z - target.z) * (current.z - target.z)) > rate.z / 2) { - if (current.z > target.z) { - current.z = current.z - rate.z; - } else if (current.z < target.z) { - current.z = current.z + rate.z; + if (stage == 4) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonDoorAngle == 0) { + if (IT1Loaded()) { + stage++; + reloadAnimTime = 60; + } } - } else { - current.z = target.z; } - return newPos; - } + if (stage == 5) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + reloadingDrakon = true; - @Override - protected void fall(float k) { - if (k <= 10) return; - float damage = MathHelper.ceiling_float_int(k) * 2; + if (drakonDoorAngle == -90) stage++; + } - boolean no_damage = true; - if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20) { - DriveableType type = getDriveableType(); - damage = (int) (damage * type.fallDamageFactor); - attackPart(EnumDriveablePart.core, DamageSource.fall, damage); - if (type.wheelPositions.length > 0) { - attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5); - } + if (stage == 6) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - no_damage = false; + if (drakonArmAngle == 0) stage++; } - // FlansMod.log("fall%s : tick=%d damage=%.1f", no_damage? " no damage":"", this.ticksExisted, damage); - } - private float averageAngles(float a, float b) { - float pi = (float) Math.PI; - while (a > b + pi) { a -= 2 * pi; } - while (a < b - pi) { a += 2 * pi; } + if (stage == 7) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, 0, 1); - float avg = (a + b) / 2F; + if (drakonRailAngle == 0 && drakonDoorAngle == 0) { + stage++; + canFireIT1 = true; + reloadingDrakon = false; + } + } - while (avg > pi) { avg -= 2 * pi; } - while (avg < -pi) { avg += 2 * pi; } + if (stage == 8) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + if (worldObj.isRemote && this.ticksExisted > 2) + drakonRailAngle = moveToTarget(drakonRailAngle, -seats[0].looking.getPitch(), seats[0].seatInfo.aimingSpeed.y); + //reloadAnimTime = 60; - return avg; + if (!IT1Loaded()) { + stage = 1; + canFireIT1 = false; + } + } } - private Vec3 subtract(Vec3 a, Vec3 b) { - return Vec3.createVectorHelper(a.xCoord - b.xCoord, a.yCoord - b.yCoord, a.zCoord - b.zCoord); - } + public float moveToTarget(float current, float target, float speed) { - private Vec3 crossProduct(Vec3 a, Vec3 b) { - return Vec3.createVectorHelper(a.yCoord * b.zCoord - a.zCoord * b.yCoord, a.zCoord * b.xCoord - a.xCoord * b.zCoord, a.xCoord * b.yCoord - a.yCoord * b.xCoord); - } + float pitchToMove = (float) ((Math.sqrt(target * target)) - Math.sqrt((current * current))); + for (; pitchToMove > 180F; pitchToMove -= 360F) { + } + for (; pitchToMove <= -180F; pitchToMove += 360F) { + } - @Override - public boolean landVehicle() { - return true; - } + float signDeltaY = 0; + if (pitchToMove > speed) { + signDeltaY = 1; + } else if (pitchToMove < -speed) { + signDeltaY = -1; + } else { + signDeltaY = 0; + return target; + } - @Override - public boolean attackEntityFrom(DamageSource damagesource, float i) { - if (worldObj.isRemote || isDead) - return true; - VehicleType type = getVehicleType(); - - if (damagesource.damageType.equals("player") - && damagesource.getEntity().onGround - && (seats[0] == null || seats[0].riddenByEntity == null) - && ((damagesource.getEntity() instanceof EntityPlayer && ((EntityPlayer)damagesource.getEntity()).capabilities.isCreativeMode) || TeamsManager.survivalCanBreakVehicles)) { - ItemStack vehicleStack = new ItemStack(type.item, 1, driveableData.paintjobID); - vehicleStack.stackTagCompound = new NBTTagCompound(); - driveableData.writeToNBT(vehicleStack.stackTagCompound); - if (!worldObj.isRemote && damagesource.getEntity() instanceof EntityPlayer) { FlansMod.log("Player %s broke vehicle %s (%d) at (%f, %f, %f)", ((EntityPlayerMP)damagesource.getEntity()).getDisplayName(), type.shortName, getEntityId(), posX, posY, posZ); } - entityDropItem(vehicleStack, 0.5F); - setDead(); + if (current > target) { + current = current - speed; + } else if (current < target) { + current = current + speed; } - return super.attackEntityFrom(damagesource, i); - } - - public VehicleType getVehicleType() { - return VehicleType.getVehicle(driveableType); - } - @Override - public float getPlayerRoll() { - return axes.getRoll(); + return current; } - public void Recoil() { + public boolean IT1Loaded() { + DriveableType type = getDriveableType(); + boolean loaded = false; + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.MISSILE)) { + loaded = true; + } + } + return loaded; } - @Override - protected void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part) { - } + public void tryRecoil() { + int slot = -1; + DriveableType type = getDriveableType(); + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { + slot = i; + } + } - @Override - public String getBombInventoryName() { - return "Mines"; + if (recoilTimer <= 0 && slot != -1) + isRecoil = true; } - @Override - public String getMissileInventoryName() { - return "Shells"; - } + public void setRecoilTimer() { + int slot = -1; + DriveableType type = getDriveableType(); + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { + slot = i; + } + } - @Override - public boolean hasMouseControlMode() { - return false; + if (recoilTimer <= 0 && slot != -1) + recoilTimer = (int) getDriveableType().shootDelayPrimary; } @Override - @SideOnly(Side.CLIENT) - public EntityLivingBase getCamera() { - return null; - } - - public boolean hasBothTracks() { - boolean tracks = true; - if (!isPartIntact(EnumDriveablePart.leftTrack)) { - tracks = false; - } - - if (!isPartIntact(EnumDriveablePart.rightTrack)) { - tracks = false; - } - - return tracks; + public boolean isInRangeToRenderDist(double d) { + double d1 = this.renderDistanceWeight; + return d < d1 * d1; } - @Override - public void setDead() { - super.setDead(); - for (EntityWheel wheel : wheels) - if (wheel != null) - wheel.setDead(); + // Returns if the bounding box is under the + public boolean isUnderWater() { + return worldObj.isAnyLiquid(this.boundingBox.copy().offset(0, getDriveableType().maxDepth, 0)); } } + From 9b591065da5c4f9961e4e83ba8573890b9794d12 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 16:33:37 +0200 Subject: [PATCH 09/25] big minigames update. part 1 handling destroying vehicles by all --- src/main/java/com/flansmod/common/teams/GameType.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/GameType.java b/src/main/java/com/flansmod/common/teams/GameType.java index efdd94c3..740b55b3 100644 --- a/src/main/java/com/flansmod/common/teams/GameType.java +++ b/src/main/java/com/flansmod/common/teams/GameType.java @@ -135,10 +135,9 @@ public void entityKilled(Entity entity, DamageSource source) { } - public void vehicleDestroyed(EntityDriveable driveable2, EntityBullet bullet){ - if (bullet!=null && driveable2!=null) { - if (bullet.owner != null) { - EntityPlayerMP attacker = (EntityPlayerMP) bullet.owner; + public void vehicleDestroyed(EntityDriveable driveable2, EntityPlayerMP attacker){ + if (driveable2!=null) { + if (attacker != null) { EntityDriveable driveable = driveable2; // if(driveable.riddenByEntity!=null && // driveable.riddenByEntity instanceof EntityPlayer && From da6d1b85e29674a8265e85c1bfe56428e34361d1 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 18:06:47 +0200 Subject: [PATCH 10/25] Revert "big minigames update. part 1" This reverts commit 41245367b7eddebf8ae2750826ddd055e7a8c62c. --- .../common/driveables/EntityVehicle.java | 3613 +++++------------ 1 file changed, 1080 insertions(+), 2533 deletions(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityVehicle.java b/src/main/java/com/flansmod/common/driveables/EntityVehicle.java index 9d9916d1..7e815bab 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityVehicle.java +++ b/src/main/java/com/flansmod/common/driveables/EntityVehicle.java @@ -1,2802 +1,1349 @@ package com.flansmod.common.driveables; -import cofh.api.energy.IEnergyContainerItem; -import com.flansmod.api.IControllable; import com.flansmod.api.IExplodeable; -import com.flansmod.client.EntityCamera; -import com.flansmod.client.FlansModClient; -import com.flansmod.client.debug.EntityDebugVector; +import com.flansmod.client.model.AnimTankTrack; +import com.flansmod.client.model.AnimTrackLink; import com.flansmod.common.FlansMod; +import com.flansmod.common.PlayerData; +import com.flansmod.common.PlayerHandler; import com.flansmod.common.RotatedAxes; -import com.flansmod.common.driveables.DriveableType.ParticleEmitter; -import com.flansmod.common.driveables.DriveableType.ShootParticle; -import com.flansmod.common.driveables.collisions.CollisionPlane; -import com.flansmod.common.driveables.collisions.CollisionShapeBox; -import com.flansmod.common.driveables.collisions.CollisionTest; -import com.flansmod.common.driveables.mechas.EntityMecha; -import com.flansmod.common.guns.*; -import com.flansmod.common.guns.raytracing.BulletHit; -import com.flansmod.common.guns.raytracing.DriveableHit; -import com.flansmod.common.network.PacketDriveableDamage; -import com.flansmod.common.network.PacketDriveableKeyHeld; +import com.flansmod.common.driveables.VehicleType.SmokePoint; +import com.flansmod.common.network.PacketDriveableKey; import com.flansmod.common.network.PacketParticle; import com.flansmod.common.network.PacketPlaySound; -import com.flansmod.common.parts.ItemPart; -import com.flansmod.common.parts.PartType; +import com.flansmod.common.network.PacketVehicleControl; +import com.flansmod.common.teams.Team; import com.flansmod.common.teams.TeamsManager; +import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Vector3f; -import cpw.mods.fml.common.network.ByteBufUtils; -import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.passive.EntityBat; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.*; -import net.minecraft.util.MovingObjectPosition.MovingObjectType; import net.minecraft.world.World; -import java.util.ArrayList; +import java.util.List; -public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData { - public boolean syncFromServer = true; - /** - * Ticks since last server update. Use to smoothly transition to new position - */ - public int serverPositionTransitionTicker; - /** - * Server side position, as synced by PacketVehicleControl packets - */ - public double serverPosX, serverPosY, serverPosZ; - /** - * Server side rotation, as synced by PacketVehicleControl packets - */ - public double serverYaw, serverPitch, serverRoll; - - /** - * The driveable data which contains the inventory, the engine and the fuel - */ - public DriveableData driveableData; - /** - * The shortName of the driveable type, used to obtain said type - */ - public String driveableType; - - /** - * The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to obtain the thrust - */ - public float throttle; - /** - * The wheels on this plane - */ - public EntityWheel[] wheels; - public boolean fuelling; +public class EntityVehicle extends EntityDriveable implements IExplodeable { /** - * Extra prevRotation field for smoothness in all 3 rotational axes + * Weapon delays */ - public float prevRotationRoll; + public int shellDelay, gunDelay; /** - * Angular velocity + * Position of looping sounds */ - public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F); - + public int soundPosition; + public int idlePosition; /** - * Whether each mouse button is held + * Front wheel yaw, used to control the vehicle steering */ - public boolean leftMouseHeld = false, rightMouseHeld = false; - + public float wheelsYaw; /** - * Shoot delay variables + * Despawn time */ - public float shootDelayPrimary, shootDelaySecondary; + private int ticksSinceUsed = 0; /** - * Minigun speed variables + * Aesthetic door switch */ - public float minigunSpeedPrimary, minigunSpeedSecondary; + public boolean varDoor; /** - * Current gun variables for alternating weapons. + * Wheel rotation angle. Only applies to vehicles that set a rotating wheels flag */ - public int currentGunPrimary, currentGunSecondary; - + public float wheelsAngle; /** - * Angle of harvester aesthetic piece + * Delayer for door button */ - public float harvesterAngle; - - public RotatedAxes prevAxes; - public RotatedAxes axes; + public int toggleTimer = 0; - public EntitySeat[] seats; + public float yaw = 0; + public float pitch = 0; + public float roll = 0; - public int lockOnSoundDelay; + public float yawSpeed = 0; - private int[] emitterTimers; - - public int animCountLeft = 0; - public int animFrameLeft = 0; - public int animCountRight = 0; - public int animFrameRight = 0; + // Used for better falling + private float fallVelocity = 0; + //Handling stuff + public int keyHeld = 0; public boolean leftTurnHeld = false; public boolean rightTurnHeld = false; + public boolean allWheelsOnGround; + //Some nonsense + boolean lockTurretForward = false; + //Animation vectors + public Vector3f doorPos = new Vector3f(0, 0, 0); + public Vector3f doorRot = new Vector3f(0, 0, 0); + public Vector3f door2Pos = new Vector3f(0, 0, 0); + public Vector3f door2Rot = new Vector3f(0, 0, 0); - public boolean isShowedPosition = false; - - public int tickCount = 0; + public Vector3f prevDoorPos = new Vector3f(0, 0, 0); + public Vector3f prevDoorRot = new Vector3f(0, 0, 0); + public Vector3f prevDoor2Pos = new Vector3f(0, 0, 0); + public Vector3f prevDoor2Rot = new Vector3f(0, 0, 0); - //Gun recoil - public boolean isRecoil = false; - public float recoilPos = 0; - public float lastRecoilPos = 0; - public int recoilTimer = 0; + public boolean deployedSmoke = false; - public Vector3f lastPos = new Vector3f(0, 0, 0); - public boolean hugeBoat = false; - public boolean onDeck = false; - public double deckHeight = 0; - public int deckCheck = 0; - public int prevDeckCheck = 0; - - public boolean isMecha = false; - public boolean disabled = false; + //Dangerous sentry stuff /** - * The angle of the propeller for the renderer + * Stops the sentry shooting whoever placed it or their teammates */ - public float propAngle = 0; - public float prevPropAngle = 0; - - public float rotorAngle = 0; - public float prevRotorAngle = 0; - - //Flares - public int flareDelay = 0; - public int ticksFlareUsing = 0; - public boolean varFlare; - - //IT1 stuff - public float drakonDoorAngle = 0; - public float drakonArmAngle = 0; - public float drakonRailAngle = 0; - - public float prevDrakonDoorAngle = 0; - public float prevDrakonArmAngle = 0; - public float prevDrakonRailAngle = 0; - - public boolean reloadingDrakon = false; - public boolean canFireIT1 = true; - - public int stage = 1; - public int reloadAnimTime = 0; - - public boolean toDeactivate = false; - public int timeTillDeactivate = 0; - - // - public boolean canFire = true; - - - @SideOnly(Side.CLIENT) - public EntityLivingBase camera; - - protected int invulnerableUnmountCount; - - private ItemStack[][] prevInventoryItems = new ItemStack[][]{null, null}; - - public Entity lastAtkEntity = null; - - public Float collisionHardness = 0F; + public EntityPlayer placer = null; + /** + * For getting the placer after a reload + */ + public String placerName = null; + public Entity target = null; - public int engineStartDelay; + public AnimTankTrack rightTrack; + public AnimTankTrack leftTrack; - //public ArrayList playerIDs = new ArrayList(); + public AnimTrackLink[] trackLinksLeft = new AnimTrackLink[0]; + public AnimTrackLink[] trackLinksRight = new AnimTrackLink[0]; - public EntityDriveable(World world) { + public EntityVehicle(World world) { super(world); - axes = new RotatedAxes(); - prevAxes = new RotatedAxes(); - preventEntitySpawning = true; - if (FlansMod.driveableHitboxes) { - setSize(1F, 1F); - } else { - setSize(0F, 0F); - } - yOffset = 6F / 16F; - ignoreFrustumCheck = true; - renderDistanceWeight = 20000D; - } - - - public EntityDriveable(World world, DriveableType t, DriveableData d) { - this(world); - driveableType = t.shortName; - driveableData = d; - } - - protected void initType(DriveableType type, boolean clientSide) { - if (type == null) return; - seats = new EntitySeat[type.numPassengers + 1]; - for (int i = 0; i < type.numPassengers + 1; i++) { - if (!clientSide) { - seats[i] = new EntitySeat(worldObj, this, i); - worldObj.spawnEntityInWorld(seats[i]); - } - } - wheels = new EntityWheel[type.wheelPositions.length]; - for (int i = 0; i < wheels.length; i++) { - if (!clientSide) { - wheels[i] = new EntityWheel(worldObj, this, i); - worldObj.spawnEntityInWorld(wheels[i]); - } - } - stepHeight = type.wheelStepHeight; - yOffset = type.yOffset; - - emitterTimers = new int[type.emitters.size()]; - for (int i = 0; i < type.emitters.size(); i++) { - emitterTimers[i] = rand.nextInt(type.emitters.get(i).emitRate); - } - - getEntityData().setBoolean("CanMountEntity", type.canMountEntity); - - //Register Plane to Radar on Spawning - //if(type.onRadar == true) - // RadarRegistry.register(this); - - for (int ps = 0; ps < 2; ps++) { - EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; - if (weaponType == EnumWeaponType.GUN) { - weaponType = EnumWeaponType.NONE; - } - int istart = getInventoryStart(weaponType); - if (istart == driveableData.getAmmoInventoryStart()) { - istart += type.numPassengerGunners; - } - final int isize = getInventorySize(weaponType); - if (istart >= 0 || isize > 0) { - prevInventoryItems[ps] = new ItemStack[isize]; - for (int i = 0; i < isize; i++) { - prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); - } - } + stepHeight = 1.0F; + } + + //This one deals with spawning from a vehicle spawner + public EntityVehicle(World world, double x, double y, double z, VehicleType type, DriveableData data) { + super(world, type, data); + stepHeight = 1.0F; + setPosition(x, y, z); + initType(type, false); + } + + //This one allows you to deal with spawning from items + public EntityVehicle(World world, double x, double y, double z, EntityPlayer p, VehicleType type, DriveableData data) { + super(world, type, data); + placer = p; + placerName = p.getCommandSenderName(); + stepHeight = 1.0F; + setPosition(x, y, z); + rotateYaw(p.rotationYaw + 90F); + initType(type, false); + setupTracks(type); + } + + public void setupTracks(DriveableType type) { + rightTrack = new AnimTankTrack(type.rightTrackPoints, type.trackLinkLength); + leftTrack = new AnimTankTrack(type.leftTrackPoints, type.trackLinkLength); + int numLinks = Math.round(rightTrack.getTrackLength() / type.trackLinkLength); + trackLinksLeft = new AnimTrackLink[numLinks]; + trackLinksRight = new AnimTrackLink[numLinks]; + for (int i = 0; i < numLinks; i++) { + float progress = 0.01F + (type.trackLinkLength * i); + int trackPart = leftTrack.getTrackPart(progress); + trackLinksLeft[i] = new AnimTrackLink(progress); + trackLinksRight[i] = new AnimTrackLink(progress); + trackLinksLeft[i].position = leftTrack.getPositionOnTrack(progress); + trackLinksRight[i].position = rightTrack.getPositionOnTrack(progress); + trackLinksLeft[i].rot = new RotatedAxes(0, 0, rotateTowards(leftTrack.points.get((trackPart == 0) ? leftTrack.points.size() - 1 : trackPart - 1), trackLinksLeft[i].position)); + trackLinksRight[i].rot = new RotatedAxes(0, 0, rotateTowards(rightTrack.points.get((trackPart == 0) ? rightTrack.points.size() - 1 : trackPart - 1), trackLinksRight[i].position)); + trackLinksLeft[i].zRot = rotateTowards(leftTrack.points.get((trackPart == 0) ? leftTrack.points.size() - 1 : trackPart - 1), trackLinksLeft[i].position); + trackLinksRight[i].zRot = rotateTowards(rightTrack.points.get((trackPart == 0) ? rightTrack.points.size() - 1 : trackPart - 1), trackLinksRight[i].position); } - - engineStartDelay = type.engineStartTime; } @Override - protected void writeEntityToNBT(NBTTagCompound tag) { - driveableData.writeToNBT(tag); - tag.setString("Type", driveableType); - tag.setFloat("RotationYaw", axes.getYaw()); - tag.setFloat("RotationPitch", axes.getPitch()); - tag.setFloat("RotationRoll", axes.getRoll()); + protected void initType(DriveableType type, boolean clientSide) { + super.initType(type, clientSide); + setupTracks(type); } @Override - protected void readEntityFromNBT(NBTTagCompound tag) { - driveableType = tag.getString("Type"); - driveableData = new DriveableData(tag); - initType(DriveableType.getDriveable(driveableType), false); - - prevRotationYaw = tag.getFloat("RotationYaw"); - prevRotationPitch = tag.getFloat("RotationPitch"); - prevRotationRoll = tag.getFloat("RotationRoll"); - axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll); + public void readSpawnData(ByteBuf data) { + super.readSpawnData(data); } @Override - public void writeSpawnData(ByteBuf data) { - ByteBufUtils.writeUTF8String(data, driveableType); - - NBTTagCompound tag = new NBTTagCompound(); - driveableData.writeToNBT(tag); - ByteBufUtils.writeTag(data, tag); - - data.writeFloat(axes.getYaw()); - data.writeFloat(axes.getPitch()); - data.writeFloat(axes.getRoll()); - - //Write damage - for (EnumDriveablePart ep : EnumDriveablePart.values()) { - DriveablePart part = getDriveableData().parts.get(ep); - data.writeFloat(part.health); - data.writeBoolean(part.onFire); - } + protected void writeEntityToNBT(NBTTagCompound tag) { + super.writeEntityToNBT(tag); + tag.setBoolean("VarDoor", varDoor); } @Override - public void readSpawnData(ByteBuf data) { - try { - driveableType = ByteBufUtils.readUTF8String(data); - driveableData = new DriveableData(ByteBufUtils.readTag(data)); - initType(getDriveableType(), true); - - axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat()); - prevRotationYaw = axes.getYaw(); - prevRotationPitch = axes.getPitch(); - prevRotationRoll = axes.getRoll(); - - //Read damage - for (EnumDriveablePart ep : EnumDriveablePart.values()) { - DriveablePart part = getDriveableData().parts.get(ep); - part.health = data.readFloat(); - part.onFire = data.readBoolean(); - } - - } catch (Exception e) { - FlansMod.log("Failed to retrieve plane type from server."); - super.setDead(); - e.printStackTrace(); - } - - camera = new EntityCamera(worldObj, this); - worldObj.spawnEntityInWorld(camera); + protected void readEntityFromNBT(NBTTagCompound tag) { + super.readEntityFromNBT(tag); + varDoor = tag.getBoolean("VarDoor"); } /** * Called with the movement of the mouse. Used in controlling vehicles if need be. * - * @param deltaY change in Y - * @param deltaX change in X - * @return if mouse movement was handled. + * @param deltaY + * @param deltaX */ @Override - public abstract void onMouseMoved(int deltaX, int deltaY); - - @Override - @SideOnly(Side.CLIENT) - public EntityLivingBase getCamera() { - return camera; - } - - protected boolean canSit(int seat) { - return getDriveableType().numPassengers >= seat && seats[seat].riddenByEntity == null; - } - - @Override - protected boolean canTriggerWalking() { - return false; - } - - @Override - protected void entityInit() { - } - - - @Override - public AxisAlignedBB getCollisionBox(Entity entity) { - if (getDriveableType().collisionDamageEnable) { - if (throttle > getDriveableType().collisionDamageThrottle) { - if (entity instanceof EntityLiving) { - entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } else if (entity instanceof EntityPlayer) { - entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } - } - } - return boundingBox; - } - - @Override - public AxisAlignedBB getBoundingBox() { - return boundingBox; - } - - @Override - public boolean canBePushed() { - return false; - } - - @Override - public double getMountedYOffset() { - return -0.3D; + public void onMouseMoved(int deltaX, int deltaY) { } - /** - * Pass generic damage to the core - */ @Override - public boolean attackEntityFrom(DamageSource damagesource, float i) { - if (worldObj.isRemote || isDead) return true; -// if(damagesource.getDamageType().indexOf("explosion") < 0) - { - if (isMountedEntity(damagesource.getEntity())) { - return false; - } - } - -// FlansMod.log(String.format("EntityDriveable.attackEntityFrom %.1f: %s : %s : %s", i, -// damagesource.getDamageType(), damagesource.getEntity(), damagesource.getSourceOfDamage())); - - boolean broken = attackPart(EnumDriveablePart.core, damagesource, i); - if (i > 0) { - //checkParts(); - checkPartsWhenAttacked(); - //If it hit, send a damage update packet - FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); - } - return true; - } - - public boolean isMountedEntity(Entity entity) { - if (entity != null) { - Entity entity2 = this.worldObj.getEntityByID(entity.getEntityId()); - for (Entity seat : seats) { - if (seat.riddenByEntity != null) { - if (seat.riddenByEntity == entity || seat.riddenByEntity == entity2) { - return true; - } - } - } - } - - return false; + public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw) { + super.setPositionRotationAndMotion(x, y, z, yaw, pitch, roll, motX, motY, motZ, velYaw, velPitch, velRoll, throt, steeringYaw); + wheelsYaw = steeringYaw; } @Override - public void setDead() { - super.setDead(); - //Unregister to Radar - //RadarRegistry.unregister(this); + public boolean interactFirst(EntityPlayer entityplayer) { + if (isDead) + return false; if (worldObj.isRemote) - camera.setDead(); - - for (EntitySeat seat : seats) - if (seat != null) - seat.setDead(); - } - - @Override - public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) { - } - - @Override - public boolean canBeCollidedWith() { - return true; - } - - @Override - public void applyEntityCollision(Entity entity) { - //if(!isPartOfThis(entity)) - //super.applyEntityCollision(entity); - } + return false; - @Override - public void setPositionAndRotation2(double d, double d1, double d2, float f, float f1, int i) { - if (ticksExisted > 1) - return; - if (!(riddenByEntity instanceof EntityPlayer) || !FlansMod.proxy.isThePlayer((EntityPlayer) riddenByEntity)) { - if (syncFromServer) { - serverPositionTransitionTicker = i + 5; - } else { - double var10 = d - posX; - double var12 = d1 - posY; - double var14 = d2 - posZ; - double var16 = var10 * var10 + var12 * var12 + var14 * var14; + //If they are using a repair tool, don't put them in + ItemStack currentItem = entityplayer.getCurrentEquippedItem(); + if (currentItem != null && currentItem.getItem() instanceof ItemTool && ((ItemTool) currentItem.getItem()).type.healDriveables) + return true; - if (var16 <= 1.0D) { - return; + VehicleType type = getVehicleType(); + //Check each seat in order to see if the player can sit in it + for (int i = 0; i <= type.numPassengers; i++) { + if (seats[i].interactFirst(entityplayer)) { + if (i == 0) { + shellDelay = type.vehicleShellDelay; + FlansMod.proxy.doTutorialStuff(entityplayer, this); } - - serverPositionTransitionTicker = 3; + return true; } - serverPosX = d; - serverPosY = d1; - serverPosZ = d2; - serverYaw = f; - serverPitch = f1; - } - } - - public void setIT1(boolean canFire, boolean reloading, int stag, int stageTime) { - if (worldObj.isRemote && ticksExisted % 5 == 0) { - canFireIT1 = canFire; - reloadingDrakon = reloading; - stage = stag; - reloadAnimTime = stageTime; - } - } - - public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw) { - if (worldObj.isRemote) { - serverPosX = x; - serverPosY = y; - serverPosZ = z; - serverYaw = yaw; - serverPitch = pitch; - serverRoll = roll; - serverPositionTransitionTicker = 5; - } else { - setPosition(x, y, z); - prevRotationYaw = yaw; - prevRotationPitch = pitch; - prevRotationRoll = roll; - setRotation(yaw, pitch, roll); } - //Set the motions regardless of side. - motionX = motX; - motionY = motY; - motionZ = motZ; - angularVelocity = new Vector3f(velYaw, velPitch, velRoll); - throttle = throt; - } - - - @Override - public void setVelocity(double d, double d1, double d2) { - motionX = d; - motionY = d1; - motionZ = d2; + return false; } @Override public boolean pressKey(int key, EntityPlayer player) { - if (!worldObj.isRemote && key == 9 && getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) //Primary - { - shoot(false); - return true; - } else if (!worldObj.isRemote && key == 8 && getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) //Secondary - { - shoot(true); + VehicleType type = getVehicleType(); + DriveableData data = getDriveableData(); + //Send keys which require server side updates to the server + if (worldObj.isRemote && (key == 6 || key == 8 || key == 9)) { + FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); return true; } - return false; - } - - @Override - public void updateKeyHeldState(int key, boolean held) { - if (worldObj.isRemote) { - FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); - - if (key == 2) { - leftTurnHeld = true; - rightTurnHeld = false; - } else if (key == 3) { - rightTurnHeld = true; - leftTurnHeld = false; - } else { - leftTurnHeld = false; - rightTurnHeld = false; - } - } switch (key) { - case 9: - leftMouseHeld = held; - break; - case 8: - rightMouseHeld = held; - break; - } - } - - /** - * Shoot method called by pressing / holding shoot buttons - */ - public void shoot(boolean secondary) { - DriveableType type = getDriveableType(); - if (seats[0] == null) - return; - - if (type.IT1 && !canFireIT1 && type.weaponType(secondary) == EnumWeaponType.MISSILE) return; - - if (!canFire || (isUnderWater() && !type.worksUnderWater)) return; - - //Check shoot delay - if (getShootDelay(secondary) <= 0) { - //We can shoot, so grab the available shoot points and the weaponType - ArrayList shootPoints = type.shootPoints(secondary); - EnumWeaponType weaponType = type.weaponType(secondary); - //If there are no shoot points, return - if (shootPoints.size() == 0) - return; - //For alternating guns, move on to the next one - int currentGun = getCurrentGun(secondary); - if (type.alternate(secondary)) { - currentGun = (currentGun + 1) % shootPoints.size(); - setCurrentGun(currentGun, secondary); - shootEach(type, shootPoints.get(currentGun), currentGun, secondary, weaponType); - } else for (int i = 0; i < shootPoints.size(); i++) - shootEach(type, shootPoints.get(i), i, secondary, weaponType); - } - } - - public boolean driverIsCreative() { - return seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode; - } - - public void spawnParticle(ArrayList list, ShootPoint shootPoint, Vector3f v) { - for (ShootParticle s : list) { - float bkx = shootPoint.rootPos.position.x; - float bky = shootPoint.rootPos.position.y; - float bkz = shootPoint.rootPos.position.z; - - Vector3f velocity = new Vector3f(s.x, s.y, s.z); - - //if(shootPoint.rootPos.part == EnumDriveablePart.turret){ - velocity = getDirection(shootPoint, velocity); - //} + case 0: //Accelerate : Increase the throttle, up to 1. + { + if (isEngineActive()) { + if (type.useRealisticAcceleration) { + throttle += data.engine.enginePower / type.mass; + } else { + throttle += 0.01F; + } + } - //Vector3f v = getFiringPosition(shootPoint); + if (throttle > 1F) + throttle = 1F; - if (shootPoint.rootPos.part == EnumDriveablePart.core) { - Vector3f v2 = axes.findLocalVectorGlobally(shootPoint.rootPos.position); - Vector3f v3 = rotate(seats[0].looking.findLocalVectorGlobally(shootPoint.offPos)); - Vector3f.add(v2, v3, v); + return true; } + case 1: //Decelerate : Decrease the throttle, down to -1, or 0 if the vehicle cannot reverse + { + if (isEngineActive()) { + if (type.useRealisticAcceleration) { + throttle -= data.engine.enginePower / type.mass; + } else { + throttle -= 0.01F; + } + } - FlansMod.getPacketHandler().sendToAllAround( - new PacketParticle(s.name, posX + v.x, posY + v.y, posZ + v.z, velocity.x, velocity.y, velocity.z), - posX + v.x, posY + v.y, posZ + v.z, 150, dimension); - - shootPoint.rootPos.position.x = bkx; - shootPoint.rootPos.position.y = bky; - shootPoint.rootPos.position.z = bkz; - } - } - - - private void shootEach(DriveableType type, ShootPoint shootPoint, int currentGun, boolean secondary, EnumWeaponType weaponType) { - //Rotate the gun vector to global axes - Vector3f gunVec = getFiringPosition(shootPoint); - Vector3f lookVector = getLookVector(shootPoint); + if (throttle < -1F) + throttle = -1F; + if (throttle < 0F && type.maxNegativeThrottle == 0F) + throttle = 0F; - if (!secondary && type.fixedPrimaryFire) { - lookVector = axes.findLocalVectorGlobally(type.primaryFireAngle); - if (shootPoint.rootPos.part == EnumDriveablePart.turret) { - lookVector = getPositionOnTurret(type.primaryFireAngle, false); + return true; } - if (shootPoint.rootPos.part == EnumDriveablePart.barrel) { - lookVector = getPositionOnTurret(type.primaryFireAngle, true); + case 2: //Left : Yaw the wheels left + { + if (throttle < 0.3F) + throttle += type.clutchBrake; + wheelsYaw -= 1F; + leftTurnHeld = true; + keyHeld = 100; + return true; } - } - - if (weaponType == EnumWeaponType.SHELL) - isRecoil = true; - if (shootPoint.rootPos.part == null) return; - if (!isPartIntact(shootPoint.rootPos.part)) return; - - if (disabled) return; - float damageMultiplier = secondary ? type.damageMultiplierSecondary : type.damageMultiplierPrimary; - //If its a pilot gun, then it is using a gun type, so do the following - if (shootPoint.rootPos instanceof PilotGun && ((PilotGun) shootPoint.rootPos).type != null) { - PilotGun pilotGun = (PilotGun) shootPoint.rootPos; - //Get the gun from the plane type and the ammo from the data - GunType gunType = pilotGun.type; - float shellSpeed = gunType.bulletSpeed; - if (type.rangingGun) - shellSpeed = type.bulletSpeed; - ItemStack bulletItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + currentGun]; - //Check that neither is null and that the bullet item is actually a bullet - if (bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable && TeamsManager.bulletsEnabled) { - ShootableType bullet = ((ItemShootable) bulletItemStack.getItem()).type; - if (gunType.isAmmo(bullet)) { - //spawnParticle(gunType, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY,V (float)posZ), null)); - - spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); - //Spawn a new bullet item - worldObj.spawnEntityInWorld(((ItemShootable) bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, gunType.bulletSpread / 2, gunType.damage * damageMultiplier, shellSpeed, bulletItemStack.getItemDamage(), type)); - //Play the shoot sound - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); - //Get the bullet item damage and increment it - int damage = bulletItemStack.getItemDamage(); - bulletItemStack.setItemDamage(damage + 1); - //If the bullet item is completely damaged (empty) - if (damage + 1 == bulletItemStack.getMaxDamage()) { - //Set the damage to 0 and consume one ammo item (unless in creative) - bulletItemStack.setItemDamage(0); - if (!driverIsCreative()) { - bulletItemStack.stackSize--; - if (bulletItemStack.stackSize <= 0) { - onWeaponInventoryChanged(secondary); - bulletItemStack = null; - } - driveableData.setInventorySlotContents(getDriveableType().numPassengerGunners + currentGun, bulletItemStack); - } - } - if (type.shootDelay(secondary) == -1) { - setShootDelay(gunType.getShootDelay(), secondary); - } else { - setShootDelay(type.shootDelay(secondary), secondary); - } - //Reset the shoot delay - } + case 3: //Right : Yaw the wheels right + { + if (throttle < 0.3F) + throttle += type.clutchBrake; + wheelsYaw += 1F; + rightTurnHeld = true; + keyHeld = 100; + return true; } - } else //One of the other modes - { - switch (weaponType) { - case BOMB: { - if (TeamsManager.bombsEnabled) { - int slot = -1; - for (int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) { - ItemStack bomb = driveableData.getStackInSlot(i); - if (bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) bomb.getItem()).type, weaponType)) { - slot = i; - } - } - - if (slot != -1) { - int spread = 0; - float shellSpeed = 0F; - - ItemStack bulletStack = driveableData.getStackInSlot(slot); - ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); - if (shootPoint.rootPos instanceof PilotGun) { - PilotGun pilotGun = (PilotGun) shootPoint.rootPos; - //Get the gun from the plane type and the ammo from the data - GunType gunType = pilotGun.type; - } - - EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vec3.createVectorHelper(gunVec.x + posX, gunVec.y + posY, gunVec.z + posZ), axes.getYaw(), axes.getPitch(), motionX, motionY, motionZ, (EntityLivingBase) seats[0].riddenByEntity, damageMultiplier, driveableData.getStackInSlot(slot).getItemDamage(), type); - worldObj.spawnEntityInWorld(bulletEntity); - - spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); - - - if (type.shootSound(secondary) != null) - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); - if (!driverIsCreative()) { - bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); - if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { - bulletStack.setItemDamage(0); - bulletStack.stackSize--; - if (bulletStack.stackSize == 0) { - onWeaponInventoryChanged(secondary); - bulletStack = null; - } - } - driveableData.setInventorySlotContents(slot, bulletStack); - } - if (type.shootDelay(secondary) == -1) { - setShootDelay(1, secondary); - } else { - setShootDelay(type.shootDelay(secondary), secondary); - } - } - } - break; - } - case MISSILE: //These two are actually almost identical - case SHELL: { - //int numnum = driveableData.getMissileInventoryStart(); - /*ItemStack AmmoPlaced = driveableData.getStackInSlot(1); - if(AmmoPlaced == null && type.enableReloadTime){ - isAmmoPlaced = false; - break; - } - isAmmoPlaced = true; - setShootDelay(type.shootDelay(secondary), secondary);*/ - tryRecoil(); - - if (TeamsManager.shellsEnabled) { - int slot = -1; - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, weaponType)) { - slot = i; - } - } + case 4: //Up : Brake + { + throttle *= 0.8F; + if (throttle > 0.001F) + throttle = 0F; + if (throttle < -0.001F) + throttle = 0F; - if (slot != -1) { - //int spread = 0; - //float shellSpeed = 3F; - float spread = type.bulletSpread; - float shellSpeed = type.bulletSpeed; - ItemStack bulletStack = driveableData.getStackInSlot(slot); - ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); - EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); - //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY, (float)posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, bulletStack.getItemDamage(), type); - //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); - worldObj.spawnEntityInWorld(bulletEntity); //SHELL - spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); - isRecoil = true; - - if (type.shootSound(secondary) != null) - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); - if (!driverIsCreative()) { - bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); - if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { - bulletStack.setItemDamage(0); - bulletStack.stackSize--; - if (bulletStack.stackSize == 0) { - onWeaponInventoryChanged(secondary); - bulletStack = null; - } - } - driveableData.setInventorySlotContents(slot, bulletStack); - } - if (type.shootDelay(secondary) == -1) { - setShootDelay(1, secondary); - } else { - setShootDelay(type.shootDelay(secondary), secondary); - } - canFireIT1 = false; - } + target = null; + return true; + } + case 5: //Down : Do nothing + { + Minecraft mc = Minecraft.getMinecraft(); + if (toggleTimer <= 0 && TeamsManager.allowVehicleZoom) { + toggleTimer = 10; + if (mc.gameSettings.fovSetting != 10) { + mc.gameSettings.fovSetting = 10; + mc.gameSettings.mouseSensitivity = 0.2F; + } else if (mc.gameSettings.fovSetting == 10) { + mc.gameSettings.fovSetting = 70; + mc.gameSettings.mouseSensitivity = 0.5F; } - break; } - case GUN: //Handled above - break; - case MINE: - case NONE: - break; + return true; } - } - } - - public Vector3f getOrigin(ShootPoint dp) { - //Rotate the gun vector to global axes - Vector3f localGunVec = new Vector3f(dp.rootPos.position); - - if (dp.rootPos.part == EnumDriveablePart.turret) { - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); - //Rotate by the turret angles - localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - //Translate by the turret origin - Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); - } - - return rotate(localGunVec); - } - - public Vector3f getPositionOnTurret(Vector3f vecIn, boolean barrel) { - Vector3f transform = vecIn; - RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); - if (barrel) yawOnlyLooking = seats[0].looking; - - //Calculate the root of the gun - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(transform, getDriveableType().turretOrigin, transform); - //Rotate by the turret angles - transform = yawOnlyLooking.findLocalVectorGlobally(transform); - //Translate by the turret origin - Vector3f.add(transform, getDriveableType().turretOrigin, transform); - Vector3f turretOriginOffset = new Vector3f(getDriveableType().turretOriginOffset); - turretOriginOffset = yawOnlyLooking.findLocalVectorGloballyYaw(turretOriginOffset); - Vector3f.add(transform, turretOriginOffset, transform); - - return rotate(transform); - } - - public Vector3f getDirection(ShootPoint dp, Vector3f vIn) { - //Rotate the gun vector to global axes - Vector3f localGunVec = new Vector3f(vIn); - - //if(dp.rootPos.part == EnumDriveablePart.turret) - //{ - //localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - //} - - localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - - return rotate(localGunVec); - } - - public Vector3f getLookVector(ShootPoint dp) { - return axes.getXAxis(); - } - - public Vector3f getFiringPosition(ShootPoint dp) { - Vector3f rootVector = new Vector3f(dp.rootPos.position); - Vector3f offsetVector = new Vector3f(dp.offPos); - Vector3f localGunVec = new Vector3f(dp.rootPos.position); - - if (dp.rootPos.part == EnumDriveablePart.turret) { - if (offsetVector.x == 0 && offsetVector.y == 0 && offsetVector.z == 0) { - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); - //Rotate by the turret angles - localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); - //Translate by the turret origin - Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); - } else { - RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); - - //Calculate the root of the gun - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(rootVector, getDriveableType().turretOrigin, rootVector); - //Rotate by the turret angles - rootVector = yawOnlyLooking.findLocalVectorGlobally(rootVector); - //Translate by the turret origin - Vector3f.add(rootVector, getDriveableType().turretOrigin, rootVector); - - //Calculate the tip of the gun - //Untranslate by the turret origin, to get the rotation about the right point - Vector3f.sub(offsetVector, getDriveableType().turretOrigin, offsetVector); - //Rotate by the turret angles - offsetVector = seats[0].looking.findLocalVectorGlobally(offsetVector); - //Translate by the turret origin - - Vector3f.add(rootVector, offsetVector, localGunVec); + case 6: //Exit : Get out + { + seats[0].riddenByEntity.setInvisible(false); + //resetZoom(); + seats[0].riddenByEntity.mountEntity(null); + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.exitSound, false); + return true; } - } - - return rotate(localGunVec); - } - - public boolean isEngineActive() { - return (driverIsCreative() || driveableData.fuelInTank > 0) && engineStartDelay == 0 || getDriveableType().fuelTankSize < 0; - } - - public void correctWheelPos() { - if (this.ticksExisted % (10 * 20) == 0) { - for (EntityWheel wheel : wheels) { - if (wheel == null) continue; - - Vector3f target = axes.findLocalVectorGlobally(getDriveableType().wheelPositions[wheel.ID].position); - target.x += posX; - target.y += posY; - target.z += posZ; - - int tf = 1; - int cf = 1; - int range = 5; - - if (MathHelper.abs(target.x - (float) wheel.posX) > range) { - wheel.posX = (target.x * tf + (float) wheel.posX * cf) / (tf + cf); - } - if (MathHelper.abs(target.y - (float) wheel.posY) > range) { - wheel.posY = (target.y * tf + (float) wheel.posY * cf) / (tf + cf); - } - if (MathHelper.abs(target.z - (float) wheel.posZ) > range) { - wheel.posZ = (target.z * tf + (float) wheel.posZ * cf) / (tf + cf); + case 7: //Inventory + { + if (worldObj.isRemote) { + FlansMod.proxy.openDriveableMenu((EntityPlayer) seats[0].riddenByEntity, worldObj, this); } + return true; } - } - } - - @Override - public void onUpdate() { - super.onUpdate(); - //playerIDs.clear(); - DriveableType type = getDriveableType(); - DriveableData data = getDriveableData(); - //if(type.fancyCollision) - //checkCollsionBox(); - hugeBoat = (getDriveableType().floatOnWater && getDriveableType().wheelStepHeight == 0); - //hugeBoat = true; - - if (hugeBoat) { - for (int i = 0; i < worldObj.loadedEntityList.size(); i++) { - Object obj = worldObj.loadedEntityList.get(i); - if (obj instanceof EntityPlayer && !isPartOfThis((Entity) obj)) { - moveRiders((Entity) obj); - } - - if (obj instanceof EntityWheel && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { - //moveRiders((Entity)obj); - } - - if (obj instanceof EntityDriveable && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { - //moveRiders((Entity)obj); - } - } - } - - onDeck = deckCheck != prevDeckCheck; - - //Aesthetics - if (type.IT1 && !disabled) { - boolean fireButtonHeld = false; - if (type.weaponType(false) == EnumWeaponType.MISSILE) fireButtonHeld = leftMouseHeld; - if (type.weaponType(true) == EnumWeaponType.MISSILE) fireButtonHeld = rightMouseHeld; - - prevDrakonDoorAngle = drakonDoorAngle; - prevDrakonArmAngle = drakonArmAngle; - prevDrakonRailAngle = drakonRailAngle; - if (canFireIT1) reloadingDrakon = false; - if (stage == 0) stage = 1; - - if (stage == 8 && fireButtonHeld) { - stage = 1; - timeTillDeactivate = 5; - toDeactivate = true; - } - if (timeTillDeactivate <= 0 && toDeactivate) { - canFireIT1 = false; - toDeactivate = false; - } - - if (reloadAnimTime <= 0) - IT1Reload(); - - reloadAnimTime--; - timeTillDeactivate--; - } - - //Aesthetics - prevPropAngle = propAngle; - prevRotorAngle = rotorAngle; - if (throttle != 0) { - propAngle += (Math.pow(Math.abs(throttle), 0.4)) * 1.5; - rotorAngle += throttle / 7F; - } - - - //Gun recoil - if (leftMouseHeld && !disabled) { - tryRecoil(); - setRecoilTimer(); - } - lastRecoilPos = recoilPos; - - if (recoilPos > 180 - (180 / type.recoilTime)) { - recoilPos = 0; - isRecoil = false; - } - - if (isRecoil) - recoilPos = recoilPos + (180 / type.recoilTime); - - if (recoilTimer >= 0) - recoilTimer--; - - checkInventoryChanged(); - - if (isUnderWater() && !type.worksUnderWater && !hugeBoat) { - throttle = 0; - //this.driveableData.parts.get(EnumDriveablePart.core).health -= 1; - disabled = true; - } else disabled = false; - - - if (type.lockOnToLivings || type.lockOnToMechas || type.lockOnToPlanes || type.lockOnToPlayers || type.lockOnToVehicles) { - if (!worldObj.isRemote && this.seats.length > 0 && lockOnSoundDelay <= 0) { - if (this.seats[0] != null && this.seats[0].riddenByEntity instanceof EntityPlayer) { - // int currentGun = getCurrentGun(false); - // Vector3f playerVec = getOrigin(type.shootPoints(false).get(currentGun)); - Vector3f playerVecRelToVehicle = seats[0].playerLooking.findGlobalVectorLocally(new Vector3f(-1, 0, 0)); - Vector3f playerVec = axes.findGlobalVectorLocally(playerVecRelToVehicle); - - for (Object obj : worldObj.loadedEntityList) { - Entity entity = (Entity) obj; - if ((type.lockOnToMechas && entity instanceof EntityMecha) || - (type.lockOnToVehicles && entity instanceof EntityVehicle) || - (type.lockOnToPlanes && entity instanceof EntityPlane) || - (type.lockOnToPlayers && entity instanceof EntityPlayer) || - (type.lockOnToLivings && entity instanceof EntityLivingBase)) { - if (getDistanceSqToEntity(entity) < type.maxRangeLockOn * type.maxRangeLockOn) { - // Some heckery with vectors rotating about themselves or something - Vector3f relPosVec = new Vector3f(-entity.posX + seats[0].posX, -entity.posY + seats[0].posY, entity.posZ - seats[0].posZ); - float angle = Math.abs(Vector3f.angle(playerVec, relPosVec)); - if (angle < Math.toRadians(type.canLockOnAngle)) { - PacketPlaySound.sendSoundPacket(seats[0].posX, seats[0].posY, seats[0].posZ, 10, dimension, type.lockOnSound, false); - if (entity instanceof EntityDriveable) - PacketPlaySound.sendSoundPacket(entity.posX, entity.posY, entity.posZ, ((EntityDriveable) entity).getDriveableType().lockedOnSoundRange, entity.dimension, ((EntityDriveable) entity).getDriveableType().lockingOnSound, false); - lockOnSoundDelay = type.lockOnSoundTime; - break; - } - } - } - } - } - } - } - if (lockOnSoundDelay > 0) - lockOnSoundDelay--; - - - if (this.ridingEntity != null) { - invulnerableUnmountCount = 20 * 4; - } else if (invulnerableUnmountCount > 0) { - invulnerableUnmountCount--; - } - - if (!worldObj.isRemote) { - for (int i = 0; i < getDriveableType().numPassengers + 1; i++) { - if (seats[i] == null || !seats[i].addedToChunk) { - seats[i] = new EntitySeat(worldObj, this, i); - worldObj.spawnEntityInWorld(seats[i]); - } - } - for (int i = 0; i < type.wheelPositions.length; i++) { - if (wheels[i] == null || !wheels[i].addedToChunk) { - wheels[i] = new EntityWheel(worldObj, this, i); - worldObj.spawnEntityInWorld(wheels[i]); - } - } - } - - //Harvest stuff - //Aesthetics - if (hasEnoughFuel() && isEngineActive()) { - harvesterAngle += throttle / 5F; - } - //Actual harvesting - if (type.harvestBlocks && type.harvestBoxSize != null && type.harvestBoxPos != null && TeamsManager.driveablesBreakBlocks) { - Vector3f size = new Vector3f(type.harvestBoxSize.x / 16F, type.harvestBoxSize.y / 16F, type.harvestBoxSize.z / 16F); - Vector3f pos = new Vector3f(type.harvestBoxPos.x / 16F, type.harvestBoxPos.y / 16F, type.harvestBoxPos.z / 16F); - for (float x = pos.x; x <= pos.x + size.x; x++) { - for (float y = pos.y; y <= pos.y + size.y; y++) { - for (float z = pos.z; z <= pos.z + size.z; z++) { - Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); - - int blockX = (int) Math.round(posX + v.x); - int blockY = (int) Math.round(posY + v.y); - int blockZ = (int) Math.round(posZ + v.z); - Block block = worldObj.getBlock(blockX, blockY, blockZ); - - if (type.materialsHarvested.contains(block.getMaterial()) && block.getBlockHardness(worldObj, blockX, blockY, blockZ) >= 0F) { - if (type.collectHarvest) { - //Add the itemstack to mecha inventory - ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); - for (ItemStack stack : stacks) { - if (!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative()) && !worldObj.isRemote && worldObj.getGameRules().getGameRuleBooleanValue("doTileDrops")) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); - } - } - } else if (type.dropHarvest) { - ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); - for (ItemStack stack : stacks) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); - } - } - //Destroy block - worldObj.func_147480_a(blockX, blockY, blockZ, false); - } - } - } - } - } - - /*if(this.isLockedOn && soundTime <= 0 && !this.worldObj.isRemote) - { - PacketPlaySound.sendSoundPacket(posX,posY,posZ, 5, dimension, type.lockedOnSound, false); - soundTime = type.soundTime; - }*/ - - for (DriveablePart part : getDriveableData().parts.values()) { - if (part.box != null) { - - part.update(this); - //Client side particles - if (worldObj.isRemote) { - if (part.onFire) { - //Pick a random position within the bounding box and spawn a flame there - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); - worldObj.spawnParticle("flame", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); - } - if (part.health > 0 && part.health < part.maxHealth / 2) { - //Pick a random position within the bounding box and spawn a flame there - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); - worldObj.spawnParticle(part.health < part.maxHealth / 4 ? "largesmoke" : "smoke", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); - } - } - //Server side fire handling - if (part.onFire) { - //Rain can put out fire - if (worldObj.isRaining() && rand.nextInt(40) == 0) - part.onFire = false; - //Also water blocks - //Get the centre point of the part - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + part.box.w / 2F, part.box.y + part.box.h / 2F, part.box.z + part.box.d / 2F)); - if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.water) { - part.onFire = false; - } - } else { - Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); - if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.lava) { - part.onFire = true; - } - } - } - } - - for (int i = 0; i < type.emitters.size(); i++) { - ParticleEmitter emitter = type.emitters.get(i); - emitterTimers[i]--; - boolean canEmit; - boolean inThrottle = false; - DriveablePart part = getDriveableData().parts.get(EnumDriveablePart.getPart(emitter.part)); - float healthPercentage = part.health / part.maxHealth; - canEmit = isPartIntact(EnumDriveablePart.getPart(emitter.part)) && healthPercentage >= emitter.minHealth && healthPercentage <= emitter.maxHealth; - - if ((throttle >= emitter.minThrottle && throttle <= emitter.maxThrottle)) - inThrottle = true; - if (isMecha) - inThrottle = true; - - if (emitterTimers[i] <= 0) { - if (inThrottle && canEmit) { - //Emit! - Vector3f velocity = new Vector3f(0, 0, 0); - - Vector3f pos = new Vector3f(0, 0, 0); - if (seats != null && seats[0] != null) { - if (EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.turret && EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.barrel) { - Vector3f localPosition = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, - emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, - emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); - - pos = axes.findLocalVectorGlobally(localPosition); - velocity = axes.findLocalVectorGlobally(emitter.velocity); - } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.turret || EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.head && !emitter.part.equals("barrel")) { - - Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, - emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, - emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); - pos = getPositionOnTurret(localPosition2, false); - velocity = getPositionOnTurret(emitter.velocity, false); - } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.barrel) { - Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, - emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, - emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); - - - pos = getPositionOnTurret(localPosition2, true); - velocity = getPositionOnTurret(emitter.velocity, true); - } - //FlansMod.proxy.spawnParticle(emitter.effectType, posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z); - - FlansMod.getPacketHandler().sendToAllAround( - new PacketParticle(emitter.effectType, - posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z), - posX + pos.x, posY + pos.y, posZ + pos.z, 150, dimension); - - } - } - emitterTimers[i] = emitter.emitRate; - } - } - - checkParts(); - - prevRotationYaw = axes.getYaw(); - prevRotationPitch = axes.getPitch(); - prevRotationRoll = axes.getRoll(); - prevAxes = axes.clone(); - - if (riddenByEntity != null && riddenByEntity.isDead) { - riddenByEntity = null; - } - if (riddenByEntity != null && isDead) { - riddenByEntity.mountEntity(null); - } - if (riddenByEntity != null) - riddenByEntity.fallDistance = 0F; - - //If there's no player in the driveable or it cannot thrust, slow the plane and turn off mouse held actions - if ((seats != null && seats[0] != null && seats[0].riddenByEntity == null) || !isEngineActive() && getDriveableType().maxThrottle != 0 && getDriveableType().maxNegativeThrottle != 0) { - throttle *= 0.99F; - } - if (seats != null && seats[0] != null && seats[0].riddenByEntity == null) { - rightMouseHeld = leftMouseHeld = false; - } - - //Check if shooting - if (shootDelayPrimary > 0) - shootDelayPrimary--; - if (shootDelaySecondary > 0) - shootDelaySecondary--; - if (getDriveableType().reloadSoundTick != 15214541 && shootDelayPrimary == getDriveableType().reloadSoundTick) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootReloadSound, false); - } -// on first update - if (this.ticksExisted == 1) { - setShootDelay(getDriveableType().placeTimePrimary, false); - setShootDelay(getDriveableType().placeTimeSecondary, true); - if (!this.worldObj.isRemote) { - if (!getDriveableType().placeSoundPrimary.isEmpty()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().placeSoundPrimary, false); - } - if (!getDriveableType().placeSoundSecondary.isEmpty()) { - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().placeSoundSecondary, false); - } - } - } - if (seats[0] != null && seats[0].riddenByEntity != null && seats[0].riddenByEntity instanceof EntityPlayer && worldObj.isRemote) { - EntityPlayer p = (EntityPlayer) seats[0].riddenByEntity; - if (this.ticksExisted < getDriveableType().placeTimePrimary && (getShootDelay(false) % 100) == 0 ) { - p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use in " + getShootDelay(false)/20 + " seconds.")); - } else if (this.ticksExisted == getDriveableType().placeTimePrimary) { - p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use!")); - } - - if (this.ticksExisted < getDriveableType().placeTimeSecondary && (getShootDelay(true) % 100) == 0) { - p.addChatComponentMessage( - new ChatComponentText("Secondary gun ready to use in " + getShootDelay(true)/20 + " seconds.")); - } else if (this.ticksExisted == getDriveableType().placeTimeSecondary) { - p.addChatComponentMessage(new ChatComponentText("Secondary gun ready to use!")); - } - - if (engineStartDelay > 0 && engineStartDelay % (2.5*20) == 0) { - p.addChatComponentMessage(new ChatComponentText("Engine starting.. " + (float)engineStartDelay/20 + " seconds remaining.")); - } else if (engineStartDelay == 1) { - p.addChatComponentMessage(new ChatComponentText("Engine started!")); - } - } - - if (!worldObj.isRemote) { - if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO) - shoot(false); - if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO) - shoot(true); - minigunSpeedPrimary *= 0.9F; - minigunSpeedSecondary *= 0.9F; - if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN) { - minigunSpeedPrimary += 0.1F; - if (minigunSpeedPrimary > 1F) - shoot(false); - } - if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN) { - minigunSpeedSecondary += 0.1F; - if (minigunSpeedSecondary > 1F) - shoot(true); - } - } - - prevDeckCheck = deckCheck; - - if (engineStartDelay > 0) { engineStartDelay--; } - //Handle fuel - - int fuelMultiplier = 2; - - //The tank is currently full, so do nothing - if (data.fuelInTank >= type.fuelTankSize) - return; - - //Look through the entire inventory for fuel cans, buildcraft fuel buckets and RedstoneFlux power sources - for (int i = 0; i < data.getSizeInventory(); i++) { - ItemStack stack = data.getStackInSlot(i); - if (stack == null || stack.stackSize <= 0) - continue; - Item item = stack.getItem(); - //If we have an electric engine, look for RedstoneFlux power source items, such as power cubes - if (data.engine.useRFPower) { - if (item instanceof IEnergyContainerItem) { - IEnergyContainerItem energy = (IEnergyContainerItem) item; - data.fuelInTank += (fuelMultiplier * energy.extractEnergy(stack, data.engine.RFDrawRate, false)) / data.engine.RFDrawRate; - } - } else { - //Check for Flan's Mod fuel items - if (item instanceof ItemPart) { - PartType part = ((ItemPart) item).type; - //Check it is a fuel item - if (part.category == 9) { - //Put 2 points of fuel - data.fuelInTank += fuelMultiplier; - - //Damage the fuel item to indicate being used up - int damage = stack.getItemDamage(); - stack.setItemDamage(damage + 1); - - //If we have finished this fuel item - if (damage >= stack.getMaxDamage()) { - //Reset the damage to 0 - stack.setItemDamage(0); - //Consume one item - stack.stackSize--; - //If we consumed the last one, destroy the stack - if (stack.stackSize <= 0) - data.setInventorySlotContents(i, null); - } - - //We found a fuel item and consumed some, so we are done - break; - } - } - //Check for Buildcraft oil and fuel buckets - else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftOilBucket) && data.fuelInTank + 1000 * fuelMultiplier <= type.fuelTankSize) { - data.fuelInTank += 1000 * fuelMultiplier; - data.setInventorySlotContents(i, new ItemStack(Items.bucket)); - } else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftFuelBucket) && data.fuelInTank + 2000 * fuelMultiplier <= type.fuelTankSize) { - data.fuelInTank += 2000 * fuelMultiplier; - data.setInventorySlotContents(i, new ItemStack(Items.bucket)); - } - - prevPosX = posX; - prevPosY = posY; - prevPosZ = posZ; - } - } - } - - public void checkInventoryChanged() { - DriveableType type = getDriveableType(); - if (type == null) return; - - if (worldObj.isRemote) return; - - if (!driveableData.inventoryChanged) return; - - driveableData.inventoryChanged = false; - - try { - for (int ps = 0; ps < 2; ps++) { - EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; - if (weaponType == EnumWeaponType.GUN) { - weaponType = EnumWeaponType.NONE; - } - int istart = getInventoryStart(weaponType); - if (istart == driveableData.getAmmoInventoryStart()) { - istart += type.numPassengerGunners; - } - final int isize = getInventorySize(weaponType); - if (istart >= 0 || isize > 0) { - if (prevInventoryItems[ps] == null) { - prevInventoryItems[ps] = new ItemStack[isize]; - } - - for (int i = 0; i < isize; i++) { - ItemStack itemStack = driveableData.getStackInSlot(istart + i); - if (itemStack != null && itemStack.getItem() instanceof ItemBullet) { - if (prevInventoryItems[ps][i] == null || !ItemStack.areItemStacksEqual(itemStack, prevInventoryItems[ps][i])) { - if (type.isValidAmmo(((ItemBullet) itemStack.getItem()).type, weaponType)) { - onWeaponInventoryChanged(ps == 1); - break; - } - } - } - } - - for (int i = 0; i < isize; i++) { - prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void onWeaponInventoryChanged(boolean secondary) { - DriveableType type = getDriveableType(); - if (!secondary) { - if (type.reloadTimePrimary > 0 && getShootDelay(secondary) <= 0) { - setShootDelay(type.reloadTimePrimary, secondary); - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().reloadSoundPrimary, false); - } - } else { - if (type.reloadTimeSecondary > 0 && getShootDelay(secondary) <= 0) { - setShootDelay(type.reloadTimeSecondary, secondary); - PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, - getDriveableType().reloadSoundSecondary, false); - } - } - } - - public int getInventoryStart(EnumWeaponType wt) { - switch (wt) { - case NONE: - case GUN: - return driveableData.getAmmoInventoryStart(); - - case MISSILE: - case SHELL: - return driveableData.getMissileInventoryStart(); - - case BOMB: - case MINE: - return driveableData.getBombInventoryStart(); - - default: - break; - } - return -1; - } - - public int getInventorySize(EnumWeaponType wt) { - switch (wt) { - case NONE: - case GUN: - return driveableData.ammo.length; - - case MISSILE: - case SHELL: - return driveableData.missiles.length; - - case BOMB: - case MINE: - return driveableData.bombs.length; - - default: - break; - } - return -1; - } - - public void checkForCollisions() { - boolean damagePart = false; - boolean crashInWater = false; - double speed = getSpeedXYZ(); - for (DriveablePosition p : getDriveableType().collisionPoints) { - if (driveableData.parts.get(p.part).dead) - continue; - Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position); - Vec3 lastPos = Vec3.createVectorHelper(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z); - - Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position); - Vec3 currentPos = Vec3.createVectorHelper(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z); - - if (FlansMod.DEBUG && worldObj.isRemote) { - worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F)); - } - - MovingObjectPosition hit = worldObj.rayTraceBlocks(lastPos, currentPos, crashInWater); - if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { - int x = hit.blockX; - int y = hit.blockY; - int z = hit.blockZ; - Block blockHit = worldObj.getBlock(x, y, z); - int meta = worldObj.getBlockMetadata(x, y, z); - - float blockHardness = blockHit.getBlockHardness(worldObj, x, y, z); - - float damage = 0; - if (blockHardness > 0.2) { - damage = blockHardness * blockHardness * (float) speed; - } - - if (null == blockHit.getCollisionBoundingBoxFromPool(this.worldObj, x, y, z)) { - damage = 0; - } - - if (damage > 0) { - damagePart = true; - if (!attackPart(p.part, DamageSource.inWall, damage) && TeamsManager.driveablesBreakBlocks) { - // And if it didn't die from the attack, break the block - worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(blockHit) + (meta << 12)); - - if (!worldObj.isRemote) { - blockHit.dropBlockAsItem(worldObj, x, y, z, meta, 1); - worldObj.setBlockToAir(x, y, z); - } - } else { - // The part died! - worldObj.createExplosion(this, currentPos.xCoord, currentPos.yCoord, currentPos.zCoord, 1F, - false); - } - } - } - - } - - if (FlansMod.seatCollisions) { - // This is for preventing vehicle glitching. It makes seats collideable, and stops their motion if - for (EntitySeat seat : seats) { - if (seat == null || wheels == null ||wheels[0] == null || wheels[1] == null || seat.riddenByEntity == null) - continue; - DriveablePosition p = seat.getAsDriveablePosition(); - if (driveableData.parts.get(p.part).dead) - continue; - Vector3f fwd = axes.getXAxis(); - float a = 0F; - if (getSpeedXZ() > 1) { - if (getSpeedXZ() > 2) { - a = 6F; - } else { - a = 3F; - } - } - - double checkY = Math.max((wheels[0].posY + wheels[1].posY)/2F + (this instanceof EntityVehicle ? 1.5 : 0), seat.posY); - Vec3 seatPos = Vec3.createVectorHelper(seat.posX + fwd.x * a, checkY + fwd.y * a, seat.posZ + fwd.z * a); - Vec3 wheelMidPos = Vec3.createVectorHelper((wheels[0].posX + wheels[1].posX)/2F, checkY, (wheels[0].posZ + wheels[1].posZ)/2F); - - MovingObjectPosition hit = worldObj.rayTraceBlocks(seatPos, wheelMidPos, crashInWater); - if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { - int x = hit.blockX; - int y = hit.blockY; - int z = hit.blockZ; - Block blockHit = worldObj.getBlock(x, y, z); - - collisionHardness = blockHit.getBlockHardness(worldObj, x, y, z); - } - } - } - - if (damagePart) { - //This is server side bsns - if (!worldObj.isRemote) { -// checkParts(); - //If it hit, send a damage update packet - FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); - } - } - } - - @Override - protected void fall(float k) { - double fallDist = ((this.posY - this.prevPosY) + this.motionY) / 2; - float damage = (float) (fallDist < -0.3 ? -fallDist * 50 : 0); - - boolean noDamage = true; - if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20) { - DriveableType type = getDriveableType(); - damage = (int) (damage * type.fallDamageFactor); - attackPart(EnumDriveablePart.core, DamageSource.fall, damage); - if (type.wheelPositions.length > 0) { - attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5); - } - - noDamage = false; - } - // FlansMod.log("fall%s : tick=%d damage=%.1f, posY-prevPosY=%.3f, mY=%.3f, fallDist=%.2f", - // noDamage? " no damage":"", this.ticksExisted, damage, this.posY - this.prevPosY, - // this.motionY, fallDist); - } - - /** - * Attack a certain part of a driveable and return whether it broke or not - */ - public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage) { - if (ep == EnumDriveablePart.core) { - if (source.getSourceOfDamage() instanceof EntityLivingBase) { - this.lastAtkEntity = source.getSourceOfDamage(); - } else if (source.getEntity() instanceof EntityLivingBase) { - this.lastAtkEntity = source.getEntity(); - } else { - this.lastAtkEntity = null; - } - } - DriveablePart part = driveableData.parts.get(ep); - // FlansMod.log("EntityDriveable.attackPart %s : %s : damage=%.1f : %s : health=%d", ep.name(), ep.getName(), damage, - // part.type.name(), part.health); - return part.attack(damage, source.isFireDamage()); - } - - /** - * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates - */ - public Vector3f rotate(Vector3f inVec) { - return axes.findLocalVectorGlobally(inVec); - } - - /** - * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates - */ - public Vector3f rotate(Vec3 inVec) { - return rotate(inVec.xCoord, inVec.yCoord, inVec.zCoord); - } - - /** - * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates - */ - public Vector3f rotate(double x, double y, double z) { - return rotate(new Vector3f((float) x, (float) y, (float) z)); - } - - //Rotate the plane locally by some angle about the yaw axis - public void rotateYaw(float rotateBy) { - if (Math.abs(rotateBy) < 0.01F) - return; - axes.rotateLocalYaw(rotateBy); - updatePrevAngles(); - } - - //Rotate the plane locally by some angle about the pitch axis - public void rotatePitch(float rotateBy) { - if (Math.abs(rotateBy) < 0.01F) - return; - axes.rotateLocalPitch(rotateBy); - updatePrevAngles(); - } - - //Rotate the plane locally by some angle about the roll axis - public void rotateRoll(float rotateBy) { - if (Math.abs(rotateBy) < 0.01F) - return; - axes.rotateLocalRoll(rotateBy); - updatePrevAngles(); - } - - public void updatePrevAngles() { - //Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick. - double dYaw = axes.getYaw() - prevRotationYaw; - if (dYaw > 180) - prevRotationYaw += 360F; - if (dYaw < -180) - prevRotationYaw -= 360F; - - double dPitch = axes.getPitch() - prevRotationPitch; - if (dPitch > 180) - prevRotationPitch += 360F; - if (dPitch < -180) - prevRotationPitch -= 360F; - - double dRoll = axes.getRoll() - prevRotationRoll; - if (dRoll > 180) - prevRotationRoll += 360F; - if (dRoll < -180) - prevRotationRoll -= 360F; - } - - public void setRotation(float rotYaw, float rotPitch, float rotRoll) { - axes.setAngles(rotYaw, rotPitch, rotRoll); - } - - //Used to stop self collision - public boolean isPartOfThis(Entity ent) { - for (EntitySeat seat : seats) { - if (seat == null) - continue; - if (ent == seat) - return true; - if (seat.riddenByEntity == ent) - return true; - } - return ent == this; - } - - @Override - public float getShadowSize() { - return 0.0F; - } - - public DriveableType getDriveableType() { - return DriveableType.getDriveable(driveableType); - } - - public DriveableData getDriveableData() { - return driveableData; - } - - @Override - public boolean isDead() { - return isDead; - } - - @Override - public Entity getControllingEntity() { - return seats[0].getControllingEntity(); - } - - @Override - public ItemStack getPickedResult(MovingObjectPosition target) { - ItemStack stack = new ItemStack(getDriveableType().item, 1, 0); - stack.stackTagCompound = new NBTTagCompound(); - driveableData.writeToNBT(stack.stackTagCompound); - return stack; - } - - public boolean hasEnoughFuel() { - //if (seats == null || seats[0] == null || seats[0].riddenByEntity == null) - //return false; - return driverIsCreative() || driveableData.fuelInTank > Math.abs(driveableData.engine.fuelConsumption * throttle) || getDriveableType().fuelTankSize < 0; - } - - //Physics time! Oooh yeah - - public double getSpeedXYZ() { - return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); - } - - public double getSpeedXZ() { - return Math.sqrt(motionX * motionX + motionZ * motionZ); - } - - public double getHackySpeedXYZ() { - double dx = (posX - lastTickPosX); - double dy = (posY - lastTickPosY); - double dz = (posZ - lastTickPosZ); - return Math.sqrt(dx * dx + dy * dy + dz * dz); - // Blocks per tick. - } - - /** - * To be overriden by vehicles to get alternate collision system - */ - public boolean landVehicle() { - return false; - } - - /** - * Overriden by planes for wheel parts - */ - public boolean gearDown() { - return true; - } - - /** - * Whether or not the plane is on the ground - * TODO : Replace with proper check based on wheels - */ - public boolean onGround() { - return onGround; - } - - - //Collision mechanism mkII - @SuppressWarnings("unused") - public void moveRiders(Entity rider) { - if (isPartOfThis(rider)) return; - boolean isHuman = false; - boolean isDriveable = false; - if (!(rider instanceof EntityPlayer)) return; - - - Vector3f riderPos = new Vector3f(rider.posX, rider.posY, rider.posZ); - Vector3f riderMotion = new Vector3f(rider.motionX, rider.motionY, rider.motionY); - Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); - if (rider instanceof EntityVehicle) vehicleMotion = ((EntityVehicle) rider).lastPos; - //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); - Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); - Vector3f relativePos = Vector3f.sub(riderPos, vehiclePos, null); - if (rider instanceof EntityPlayer) isHuman = true; - if (rider instanceof EntityDriveable) isDriveable = true; - relativePos = new Vector3f(relativePos.x, relativePos.y - ((isHuman) ? 0.55F : 0), relativePos.z); - - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); - Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(riderMotion); - - Vector3f ellipsoid = new Vector3f(rider.width / 2, rider.height, rider.width / 2); - - CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), riderMotion); - test.collisionRecursiveDepth = 0; - - Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); - Vector3f eSpaceVelocity = test.velocity; - - //Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); - DriveableType type = getDriveableType(); - //Check parts for collision - if (type.fancyCollision) { - //checkCollision(test, getDriveableType().colbox); - for (CollisionShapeBox sbox : type.collisionBox) { - checkCollision(test, sbox); - } - } else { - for (DriveablePart ppart : getDriveableData().parts.values()) { - ppart.rayTraceRider(this, test); - } - } - - if (test.didCollide) { - Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); - - if (finalPos == null) { - finalPos = new Vector3f(0, 0, 0); - if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [1]"); - } - - Vector3f velocity = Vector3f.sub(finalPos, test.basePoint, null); - test.ConvertESpaceToR3(velocity); - finalPos = new Vector3f(finalPos.x * test.eRad.x, finalPos.y * test.eRad.y, finalPos.z * test.eRad.z); - // TODO: Better way to check this - if (finalPos == null) { - finalPos = new Vector3f(0, 0, 0); - if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [2]"); - } - Vector3f diff = Vector3f.sub(finalPos, vehiclePos, null); - - - if (rider.onGround && (posY + finalPos.y + 10 / 16F) < riderPos.y) { - //finalPos = new Vector3f(finalPos.x, 0, finalPos.z); - } - //boolean onTop = (rider.posY + 0.65 > test.intersectionPoint.y); - - boolean stationary = (throttle == 0); - - //If finalPos returns null, do something about it. Probably not the best way to handle this. - //if(finalPos == null) finalPos = new Vector3f(0,0,0); - - test.ConvertESpaceToR3(finalPos); - boolean onTop = (test.collisionPlaneNormal.y >= 0.5F); - if (posY + finalPos.y + 10 / 16F < riderPos.y) finalPos.y = (riderPos.y - (float) posY - 10F / 16F); - if (!hugeBoat) - rider.setPosition((!onTop) ? riderPos.x + finalPos.x / (48 * Math.abs(relativePos.x)) : riderPos.x, (onTop) ? posY + finalPos.y + 10 / 16F : riderPos.y, (!onTop) ? riderPos.z + finalPos.z / (48 * Math.abs(relativePos.z)) : riderPos.z); - //test.ConvertESpaceToR3(test.intersectionPoint); - //FlansMod.proxy.spawnParticle("flame", test.intersectionPoint.x + posX, test.intersectionPoint.y + posY - 1, test.intersectionPoint.z + posZ, 0, 0, 0); - - if (hugeBoat && !stationary) { - rider.setPosition(riderPos.x, posY + finalPos.y + 9.5 / 16F, riderPos.z); - } else if (hugeBoat && stationary) { - rider.setPosition(riderPos.x, posY + finalPos.y + 10 / 16F, riderPos.z); - } - finalPos = Vector3f.sub(finalPos, riderPos, null); - finalPos.normalise(); - - //rider.motionX = rider.motionX * finalPos.x; - rider.motionY = 0; - //rider.motionZ = rider.motionZ * finalPos.z; - - - //Vector3f intersect = test.intersectionPoint; - //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX + intersect.x, posY + intersect.y, posZ + intersect.z, 0,1,0); - //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX, posY, posZ, 0,1,0); - //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", riderPos.x, riderPos.y, riderPos.z, 0,1,0); - - //worldObj.spawnParticle("crit", posX + finalPos.x, posY + finalPos.y, posZ + finalPos.z, 0,0,0); - //worldObj.spawnParticle("reddust", riderPos.x, riderPos.y - 0.65, riderPos.z, 0,0,0); - - - updateRiderPos(rider, test, finalPos, riderMotion); - - if (getDriveableType().collisionDamageEnable && !test.isOnTop) { - if (throttle > getDriveableType().collisionDamageThrottle) { - boolean canDamage = true; - if (TeamsManager.getInstance() != null && TeamsManager.getInstance().currentRound != null && rider instanceof EntityPlayerMP && seats[0].riddenByEntity instanceof EntityPlayer) { - EntityPlayerMP attacker = (EntityPlayerMP) seats[0].riddenByEntity; - EntityPlayerMP player = (EntityPlayerMP) rider; - if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team != null) { - if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team != null) { - if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team == TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team) { - canDamage = false; - } - } - } - } - for (EntitySeat seat : seats) { - if (rider == seat.lastRiddenByEntity) { - canDamage = false; - break; - } - } - - if (canDamage) { - if (rider instanceof EntityLiving) { - rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } else if (rider instanceof EntityPlayer) { - rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); - } - } - } - } - if (rider instanceof EntityPlayer) { - EntityPlayer player = (EntityPlayer) rider; - //playerIDs.add(player); - player.onGround = true; - player.isAirBorne = false; - player.fallDistance = 0; - } - - } else { - if (rider instanceof EntityDriveable) { - //((EntityDriveable)rider).onDeck = false; - ((EntityDriveable) rider).deckHeight = 0; - } - } - - - } - - /** - * @SubscribeEvent public void updateRiders(LivingUpdateEvent event){ - *

- * for(EntityPlayer player: playerIDs){ - * Entity p = (Entity)player; - * if(p == event.entity){ - * player.onGround = true; - * player.isAirBorne = false; - * player.fallDistance = 0; - * playerIDs.remove(player); - * } - * } - * } - */ - - public DamageSource getBulletDamage(boolean headshot) { - DriveableType type = getDriveableType(); - EntityLivingBase owner = (EntityLivingBase) seats[0].riddenByEntity; - if (owner instanceof EntityPlayer) - return (new EntityDamageSourceFlans(getDriveableType().shortName, this, (EntityPlayer) owner, type, headshot, false)).setProjectile(); - else return (new EntityDamageSourceIndirect(type.shortName, this, owner)).setProjectile(); - } - - public void checkCollision(CollisionTest tester, CollisionShapeBox box) { - { - double distance = tester.nearestDistance; - Vector3f collisionPoint = new Vector3f(0, 0, 0); - int surface = 0; - - Vector3f pos = new Vector3f(this.posX, this.posY, this.posZ); - - RotatedAxes shift = axes; - - float f4 = box.pos.x + box.size.x; - float f5 = -box.pos.y + box.size.y; - float f6 = box.pos.z + box.size.z; - - box.pos = new Vector3f(box.pos.x, box.pos.y, box.pos.z); - //if(EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret) return; - //Define box verticies, where z > 0 is right. See shapeboxes in the toolbox for a visual reference - Vector3f p1 = new Vector3f(box.pos.x - box.p1.x, box.pos.y + box.size.y + box.p1.y - box.size.y + 0.625F, box.pos.z - box.p1.z); - Vector3f p2 = new Vector3f(box.pos.x + box.size.x + box.p2.x, box.pos.y + box.size.y + box.p2.y - box.size.y + 0.625F, box.pos.z - box.p2.z); - Vector3f p3 = new Vector3f(box.pos.x + box.size.x + box.p3.x, box.pos.y + box.size.y + box.p3.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p3.z); - Vector3f p4 = new Vector3f(box.pos.x - box.p4.x, box.pos.y + box.size.y + box.p4.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p4.z); - Vector3f p5 = new Vector3f(box.pos.x - box.p5.x, box.pos.y - box.p5.y - box.size.y + 0.625F, box.pos.z - box.p5.z); - Vector3f p6 = new Vector3f(box.pos.x + box.size.x + box.p6.x, box.pos.y - box.p6.y - box.size.y + 0.625F, box.pos.z - box.p6.z); - Vector3f p7 = new Vector3f(box.pos.x + box.size.x + box.p7.x, box.pos.y - box.p7.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p7.z); - Vector3f p8 = new Vector3f(box.pos.x - box.p8.x, box.pos.y - box.p8.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p8.z); - - if (EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret && seats[0] != null) { - p1 = getPositionOnTurret(p1, false); //Front upper left - p2 = getPositionOnTurret(p2, false); //Front upper right - p3 = getPositionOnTurret(p3, false); //Rear upper right - p4 = getPositionOnTurret(p4, false); //Rear upper left - p5 = getPositionOnTurret(p5, false); //Front lower left - p6 = getPositionOnTurret(p6, false); //Front lower right - p7 = getPositionOnTurret(p7, false); //Rear lower right - p8 = getPositionOnTurret(p8, false); //Rear lower left - } else { - p1 = shift.findLocalVectorGlobally(p1); - p2 = shift.findLocalVectorGlobally(p2); - p3 = shift.findLocalVectorGlobally(p3); - p4 = shift.findLocalVectorGlobally(p4); - p5 = shift.findLocalVectorGlobally(p5); - p6 = shift.findLocalVectorGlobally(p6); - p7 = shift.findLocalVectorGlobally(p7); - p8 = shift.findLocalVectorGlobally(p8); - } - - - //Check top face - double topFaceDist = 100; - - tester.checkTriangle(tester, p3, p2, p1); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); - } - - tester.checkTriangle(tester, p4, p3, p1); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); - } - - if (tester.didCollide) { - tester.isOnTop = true; - topFaceDist = tester.nearestDistance; - } - - //Check front face - tester.checkTriangle(tester, p6, p7, p3); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 2; - tester.part = EnumDriveablePart.getPart(box.part); - } - tester.checkTriangle(tester, p3, p2, p6); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 2; - tester.part = EnumDriveablePart.getPart(box.part); + case 8: //Shoot shell + case 9: //Shoot bullet + { + return super.pressKey(key, player); } - - - //Check rear face - tester.checkTriangle(tester, p4, p1, p5); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 3; - tester.part = EnumDriveablePart.getPart(box.part); + case 10: //Change control mode : Do nothing + { + FlansMod.proxy.changeControlMode((EntityPlayer) seats[0].riddenByEntity); + seats[0].targetYaw = seats[0].looking.getYaw(); + seats[0].targetPitch = seats[0].looking.getPitch(); + return true; } - tester.checkTriangle(tester, p5, p8, p4); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 3; - tester.part = EnumDriveablePart.getPart(box.part); + case 11: //Roll left : Do nothing + { + seats[0].targetYaw -= seats[0].seatInfo.aimingSpeed.x; + return true; } - - //Check Left Face - tester.checkTriangle(tester, p6, p5, p1); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 4; - tester.part = EnumDriveablePart.getPart(box.part); + case 12: //Roll right : Do nothing + { + seats[0].targetYaw += seats[0].seatInfo.aimingSpeed.x; + return true; } - tester.checkTriangle(tester, p1, p2, p6); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 4; - tester.part = EnumDriveablePart.getPart(box.part); + case 13: // Gear : Do nothing + { + if (seats[0].targetPitch < -seats[0].seatInfo.minPitch) + seats[0].targetPitch += seats[0].seatInfo.aimingSpeed.y; + return true; } - - //Check right face - tester.checkTriangle(tester, p8, p7, p3); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 5; - tester.part = EnumDriveablePart.getPart(box.part); + case 14: // Door + { + if (toggleTimer <= 0) { + varDoor = !varDoor; + if (type.hasDoor) + player.addChatMessage(new ChatComponentText("Doors " + (varDoor ? "opened" : "closed"))); + toggleTimer = 10; + FlansMod.getPacketHandler().sendToServer(new PacketVehicleControl(this)); + } + return true; } - tester.checkTriangle(tester, p3, p4, p8); - if (tester.didCollide && tester.nearestDistance < distance) { - distance = tester.nearestDistance; - collisionPoint = tester.intersectionPoint; - surface = 5; - tester.part = EnumDriveablePart.getPart(box.part); + case 15: // Wing : Do nothing + { + if (seats[0].targetPitch > -seats[0].seatInfo.maxPitch) + seats[0].targetPitch -= seats[0].seatInfo.aimingSpeed.y; + return true; } - - //Check bottom face - tester.checkTriangle(tester, p5, p6, p7); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); + case 16: // Trim Button + { + //applyTorque(new Vector3f(axes.getRoll() / 10, 0F, 0F)); + return true; } - - tester.checkTriangle(tester, p8, p7, p5); - if (tester.didCollide && tester.nearestDistance < distance) { - collisionPoint = tester.intersectionPoint; - surface = 1; - tester.part = EnumDriveablePart.getPart(box.part); + case 17: //Park + { + break; } - if (tester.didCollide) { - tester.isOnTop = true; - topFaceDist = tester.nearestDistance; + case 18: //Flare + { + if (type.hasFlare && this.ticksFlareUsing <= 0 && this.flareDelay <= 0) { + this.ticksFlareUsing = type.timeFlareUsing * 20; + this.flareDelay = type.flareDelay; + dischargeSmoke(); + if (worldObj.isRemote) { + FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); + } else { + dischargeSmoke(); + if (!type.flareSound.isEmpty()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.flareSound, false); + } + } + return true; + } + break; } + } + return false; + } - Vector3f.add(p1, pos, p1); - Vector3f.add(p2, pos, p2); - Vector3f.add(p3, pos, p3); - Vector3f.add(p4, pos, p4); - Vector3f.add(p5, pos, p5); - Vector3f.add(p6, pos, p6); - Vector3f.add(p7, pos, p7); - Vector3f.add(p8, pos, p8); - - String particleType = "crit"; - - - if (FlansMod.DEBUG) { - FlansMod.proxy.spawnParticle(particleType, p1.x, p1.y, p1.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p2.x, p2.y, p2.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p3.x, p3.y, p3.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p4.x, p4.y, p4.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p5.x, p5.y, p5.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p6.x, p6.y, p6.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p7.x, p7.y, p7.z, 0, 0, 0); - FlansMod.proxy.spawnParticle(particleType, p8.x, p8.y, p8.z, 0, 0, 0); - - renderTri(p1, p2, p3); - renderTri(p3, p4, p1); + @SideOnly(Side.CLIENT) + public void resetZoom() { + if (TeamsManager.allowVehicleZoom) { + Minecraft mc = Minecraft.getMinecraft(); + if (mc.gameSettings.fovSetting == 10) { + mc.gameSettings.fovSetting = 70; + mc.gameSettings.mouseSensitivity = 0.5F; } - - if (tester.nearestDistance < topFaceDist) tester.isOnTop = false; - - - if (surface == 1) tester.isOnTop = true; } + } + @Override + public Vector3f getLookVector(ShootPoint dp) { + return rotate(seats[0].looking.getXAxis()); } - public void renderTri(Vector3f p1, Vector3f p2, Vector3f p3) { - Vector3f pos = new Vector3f(posX, posY, posZ); - Vector3f p1a = Vector3f.add(p1, pos, null); - Vector3f p2a = Vector3f.add(p2, pos, null); - Vector3f p3a = Vector3f.add(p3, pos, null); - renderLine(p1a, p2a); - renderLine(p2a, p3a); - renderLine(p3a, p1a); - } + @Override + public void onUpdate() { + double bkPrevPosY = this.prevPosY; - public void renderLine(Vector3f in, Vector3f out) { - float dx = out.x - in.x; - float dy = out.y - in.y; - float dz = out.z - in.z; - Vector3f diff = Vector3f.sub(out, in, null); - diff.normalise(); - float distance = (float) Math.sqrt((dx * dx) + (dy * dy) + (dz * dz)); - for (int i = 0; i < 10; i++) { - float dist2 = (distance / 10) * i; - Vector3f newVec = new Vector3f(in.x + (dist2 * diff.x), in.y + (dist2 * diff.y), in.z + (dist2 * diff.z)); - FlansMod.proxy.spawnParticle("reddust", newVec.x, newVec.y, newVec.z, 0, 0, 0); + super.onUpdate(); + animateFancyTracks(); + if (worldObj.isRemote) { + for (Entity e : findEntitiesWithinbounds()) { + if (!isPartOfThis(e) && e instanceof EntityPlayer) { + moveRiders(e); + } + } } - } + //wheelsYaw -= 1F; - public Vector3f collideWithDriveable(CollisionTest tester, Vector3f Pos, Vector3f vel) { - float unitScale = 1 / 16F; - float veryCloseDistance = 0.005F * unitScale; - if (tester.collisionRecursiveDepth > 2) return Pos; + //Get vehicle type + VehicleType type = this.getVehicleType(); + DriveableData data = getDriveableData(); + if (type == null) { + FlansMod.log("Vehicle type null. Not ticking vehicle"); + return; + } + + if (type.shootWithOpenDoor) { + canFire = varDoor; + } - tester.basePoint = Pos; - tester.didCollide = false; + //Work out if this is the client side and the player is driving + boolean thePlayerIsDrivingThis = worldObj.isRemote && seats[0] != null + && seats[0].riddenByEntity instanceof EntityPlayer + && FlansMod.proxy.isThePlayer((EntityPlayer) seats[0].riddenByEntity); - if (getDriveableType().fancyCollision) { - //checkCollision(tester, getDriveableType().colbox); - for (CollisionShapeBox sbox : getDriveableType().collisionBox) { - checkCollision(tester, sbox); - } - } else { - for (DriveablePart ppart : getDriveableData().parts.values()) { - ppart.rayTraceRider(this, tester); - } + //Despawning + ticksSinceUsed++; + if (!worldObj.isRemote && seats[0].riddenByEntity != null) + ticksSinceUsed = 0; + if (!worldObj.isRemote && TeamsManager.vehicleLife > 0 && ticksSinceUsed > TeamsManager.vehicleLife * 20) { + setDead(); } - //If no collision, we just move along the velocity - if (tester.didCollide = false) return Vector3f.add(Pos, vel, null); + if (this.worldObj.isRemote && (this.varFlare || this.ticksFlareUsing > (type.timeFlareUsing * 20) - 5)) { + if (this.ticksExisted % 5 == 0) { + deployedSmoke = true; + } + } + if (type.setPlayerInvisible && !this.worldObj.isRemote && seats[0].riddenByEntity != null) + seats[0].riddenByEntity.setInvisible(true); - //Collision occurred, time to sort this out - Vector3f destinationPoint = Vector3f.add(Pos, vel, null); - Vector3f newBasePoint = Pos; + if (this.ticksFlareUsing <= 0) deployedSmoke = false; - if (tester.nearestDistance >= veryCloseDistance) { - vel.normalise(); - vel.scale((float) (tester.nearestDistance - veryCloseDistance)); - newBasePoint = Vector3f.add(tester.basePoint, vel, null); + if (this.ticksFlareUsing > 0) + this.ticksFlareUsing--; + if (this.flareDelay > 0) + this.flareDelay--; - if (vel.normalise().equals(new Vector3f(0, 0, 0))) return Vector3f.add(Pos, vel, null); + //Shooting, inventories, etc. + //Decrement shell and gun timers + if (shellDelay > 0) + shellDelay--; + if (gunDelay > 0) + gunDelay--; + if (toggleTimer > 0) + toggleTimer--; + if (soundPosition > 0) + soundPosition--; + if (idlePosition > 0) + idlePosition--; - vel.normalise(); + if (type.tank && !hasBothTracks()) throttle = 0; + if (disabled || !hasBothTracks()) wheelsYaw = 0; - //Change polygon intersection point so that the sliding plane is unaffected by the fact we move slightly less than collision tells us - Vector3f.sub(tester.intersectionPoint, new Vector3f(vel.x * veryCloseDistance, vel.y * veryCloseDistance, vel.z * veryCloseDistance), tester.intersectionPoint); + //Rotate the wheels + if (hasEnoughFuel() && isEngineActive()) { + wheelsAngle += throttle / 3.25F; } - //Determine the sliding plane - Vector3f slidePlaneOrigin = tester.intersectionPoint; - if (tester.intersectionPoint == null) return Vector3f.add(Pos, vel, null); - Vector3f slidePlaneNormal = Vector3f.sub(newBasePoint, tester.intersectionPoint, null); - slidePlaneNormal.normalise(); + prevDoorPos = doorPos; + prevDoorRot = doorRot; + prevDoor2Pos = door2Pos; + prevDoor2Rot = door2Rot; - tester.collisionPlaneNormal = slidePlaneNormal; - CollisionPlane plane = new CollisionPlane(slidePlaneOrigin, slidePlaneNormal); + if (!varDoor) { + doorPos = transformPart(doorPos, type.doorPos1, type.doorRate); + doorRot = transformPart(doorRot, type.doorRot1, type.doorRotRate); + door2Pos = transformPart(door2Pos, type.door2Pos1, type.door2Rate); + door2Rot = transformPart(door2Rot, type.door2Rot1, type.door2RotRate); + } else { + doorPos = transformPart(doorPos, type.doorPos2, type.doorRate); + doorRot = transformPart(doorRot, type.doorRot2, type.doorRotRate); + door2Pos = transformPart(door2Pos, type.door2Pos2, type.door2Rate); + door2Rot = transformPart(door2Rot, type.door2Rot2, type.door2RotRate); + } + + //Return the wheels to their resting position + wheelsYaw *= 0.9F; + + //Limit wheel angles + if (wheelsYaw > 20) + wheelsYaw = 20; + if (wheelsYaw < -20) + wheelsYaw = -20; + + //Player is not driving this. Update its position from server update packets + if (worldObj.isRemote && !thePlayerIsDrivingThis) { + //The driveable is currently moving towards its server position. Continue doing so. + if (serverPositionTransitionTicker > 0) { + double x = posX + (serverPosX - posX) / serverPositionTransitionTicker; + double y = posY + (serverPosY - posY) / serverPositionTransitionTicker; + double z = posZ + (serverPosZ - posZ) / serverPositionTransitionTicker; + double dYaw = MathHelper.wrapAngleTo180_double(serverYaw - axes.getYaw()); + double dPitch = MathHelper.wrapAngleTo180_double(serverPitch - axes.getPitch()); + double dRoll = MathHelper.wrapAngleTo180_double(serverRoll - axes.getRoll()); + rotationYaw = (float) (axes.getYaw() + dYaw / serverPositionTransitionTicker); + rotationPitch = (float) (axes.getPitch() + dPitch / serverPositionTransitionTicker); + float rotationRoll = (float) (axes.getRoll() + dRoll / serverPositionTransitionTicker); + --serverPositionTransitionTicker; + setPosition(x, y, z); + setRotation(rotationYaw, rotationPitch, rotationRoll); + //return; + } + //If the driveable is at its server position and does not have the next update, it should just simulate itself as a server side driveable would, so continue + } + + //Movement + + correctWheelPos(); + + Vector3f amountToMoveCar = new Vector3f(); + + for (EntityWheel wheel : wheels) { + if (wheel == null) + continue; - double sDV = plane.signedDistanceTo(destinationPoint); - Vector3f scaledNormal = new Vector3f(slidePlaneNormal.x * sDV, slidePlaneNormal.y * sDV, slidePlaneNormal.z * sDV); - Vector3f newDestPoint = Vector3f.sub(destinationPoint, scaledNormal, null); + double prevPosYWheel = wheel.posY; + + //Hacky way of forcing the car to step up blocks + onGround = true; + wheel.onGround = true; + + //Update angles + wheel.rotationYaw = axes.getYaw(); + //Front wheels + if (!type.tank && (wheel.ID == 2 || wheel.ID == 3)) { + wheel.rotationYaw += wheelsYaw; + } + + wheel.motionX *= 0.9F; + wheel.motionY *= this.posY - bkPrevPosY < 0 ? 0.999F : 0.9F; + wheel.motionZ *= 0.9F; + + //Apply velocity + //If the player driving this is in creative, then we can thrust, no matter what + boolean canThrustCreatively = !TeamsManager.vehiclesNeedFuel || type.fuelTankSize < 0 || (seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode); + //Otherwise, check the fuel tanks! + if ((canThrustCreatively || type.fuelTankSize < 0 || data.fuelInTank > Math.abs(data.engine.fuelConsumption * throttle)) && isEngineActive()) { + if (getVehicleType().tank) { + boolean left = wheel.ID == 0 || wheel.ID == 3; + + float turningDrag = 0.02F; + wheel.motionX *= 1F - (Math.abs(wheelsYaw) * turningDrag); + wheel.motionZ *= 1F - (Math.abs(wheelsYaw) * turningDrag); + float velocityScale = 0; + if (isUnderWater()) { + velocityScale = 0.04F * (throttle > 0 ? type.maxThrottleInWater : type.maxNegativeThrottle) + * data.engine.engineSpeed; + } else { + velocityScale = 0.04F * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) + * data.engine.engineSpeed; - //Generate slide vector - Vector3f newVelocityVector = Vector3f.sub(newDestPoint, tester.intersectionPoint, null); + } + float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); + float effectiveWheelSpeed = (throttle + (wheelsYaw * (left ? 1 : -1) * steeringScale)) * velocityScale; + wheel.motionX += effectiveWheelSpeed * Math.cos(wheel.rotationYaw * 3.14159265F / 180F); + wheel.motionZ += effectiveWheelSpeed * Math.sin(wheel.rotationYaw * 3.14159265F / 180F); + yawSpeed += effectiveWheelSpeed * Math.sin(wheel.rotationYaw * 3.14159265F / 180F); + } else { + //if(getVehicleType().fourWheelDrive || wheel.ID == 0 || wheel.ID == 1) + { + float velocityScale = 0; + if (isUnderWater()) { + velocityScale = 0.1F * throttle + * (throttle > 0 ? type.maxThrottleInWater : type.maxNegativeThrottle) + * data.engine.engineSpeed; + } else { + velocityScale = 0.1F * throttle + * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) + * data.engine.engineSpeed; - if (newVelocityVector.length() < veryCloseDistance) { - return newBasePoint; - } + } + wheel.motionX += Math.cos(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale; + wheel.motionZ += Math.sin(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale; + } - tester.collisionRecursiveDepth++; + //Apply steering + if (wheel.ID == 2 || wheel.ID == 3) { + float velocityScale = 0.01F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier) * (throttle > 0 ? 1 : -1); - return collideWithDriveable(tester, newBasePoint, newVelocityVector); - } + wheel.motionX -= wheel.getSpeedXZ() * Math.sin(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale * wheelsYaw; + wheel.motionZ += wheel.getSpeedXZ() * Math.cos(wheel.rotationYaw * 3.14159265F / 180F) * velocityScale * wheelsYaw; + } else { + wheel.motionX *= 0.9F; + wheel.motionZ *= 0.9F; + } + } + + if (!canThrustCreatively && TeamsManager.vehiclesNeedFuel) { + data.fuelInTank -= Math.abs(data.engine.fuelConsumption * throttle) * 0.1; + } + } - @SuppressWarnings("unused") - public void updateRiderPos(Entity rider, CollisionTest test, Vector3f pos, Vector3f motion) { - boolean isDriveable = rider instanceof EntityDriveable; - Vector3f vehicleMotion = lastPos; + wheel.moveEntity(wheel.motionX, wheel.motionY, wheel.motionZ); - Vector3f riderMountPoint = new Vector3f(rider.posX - posX, rider.posY - posY, rider.posZ - posZ); + //Pull wheels towards car + Vector3f targetWheelPos = axes.findLocalVectorGlobally(getVehicleType().wheelPositions[wheel.ID].position); - float yawDiff = axes.getYaw() - prevAxes.getYaw(); - float pitchDiff = axes.getPitch() - prevAxes.getPitch(); - float rollDiff = axes.getRoll() - prevAxes.getRoll(); + Vector3f currentWheelPos = new Vector3f(wheel.posX - posX, wheel.posY - posY, wheel.posZ - posZ); - RotatedAxes velAxes = new RotatedAxes(axes.getYaw() + yawDiff, axes.getPitch() + pitchDiff, axes.getRoll() + rollDiff); + Vector3f dPos = ((Vector3f) Vector3f.sub(targetWheelPos, currentWheelPos, null).scale(type.wheelSpringStrength)); - Vector3f currentLocalPos = axes.findGlobalVectorLocally(riderMountPoint); - Vector3f nextGlobalPos = velAxes.findLocalVectorGlobally(currentLocalPos); + if (dPos.length() > 0.001F) { + wheel.moveEntity(dPos.x, dPos.y, dPos.z); + dPos.scale(0.5F); + Vector3f.sub(amountToMoveCar, dPos, amountToMoveCar); + } - Vector3f diff = new Vector3f(0, 0, 0); + float avgWheelHeight = 0F; - //Some rubbish null checks - if (nextGlobalPos == null) nextGlobalPos = new Vector3f(0, 0, 0); + //Secondary check whether all wheels are on ground... + if (wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { + avgWheelHeight = (float) (wheels[0].posX + wheels[1].posX + wheels[2].posX + wheels[3].posX) / 4; + if (!wheels[0].onGround && !wheels[1].onGround && !wheels[2].onGround && !wheels[3].onGround) { + allWheelsOnGround = false; + } else { + allWheelsOnGround = true; + } + } - Vector3f.add(vehicleMotion, diff, diff); - rider.setPosition(nextGlobalPos.x + posX + ((hugeBoat) ? diff.x / (1.5) : 0), (!isDriveable) ? rider.posY : ((EntityDriveable) rider).deckHeight, nextGlobalPos.z + posZ + ((hugeBoat) ? diff.z / (1.5) : 0)); + //Now we apply gravity + if (!(type.floatOnWater && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, -type.floatOffset, 0))) && !wheel.onDeck) { + float a = type.maxFallSpeed; + float g = type.gravity; + if (wheel.onGround) { + a *= 1F/2F; + g *= 3/2F; + } - if (hugeBoat) { - if (lastPos.x == 0 && lastPos.y == 0 && lastPos.z == 0) { - if (rider.motionY < 0) rider.motionY = 0; - } - } else { - if (lastPos.x != 0 || lastPos.y != 0 || lastPos.z != 0) { - rider.motionX = diff.x; - rider.motionY = diff.y; - rider.motionZ = diff.z; + if (wheel.motionY >= 0) { + wheel.motionY -= g; + } else if (wheel.motionY >= -a) { + wheel.motionY -= g * (wheel.motionY + a); + } + + } else if ((type.floatOnWater && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, -type.floatOffset, 0))) && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, 1 - type.floatOffset, 0)) && !wheel.onDeck) { + wheel.moveEntity(0F, 1F, 0F); + } else if ((type.floatOnWater && worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, -type.floatOffset, 0))) && !worldObj.isAnyLiquid(wheel.boundingBox.copy().offset(0, 1 - type.floatOffset, 0)) || wheel.onDeck) { + wheel.moveEntity(0F, 0F, 0F); + this.roll = 0; + this.pitch = 0; + }/* else { + wheel.moveEntity(0F, (!onDeck) ? -1.2F : 0, 0F); + }*/ + + if ((throttle >= 1.1 || throttle <= -1.1)) { + Vector3f motionVec = new Vector3f(0, 0, 0); + Vector3f targetVec = type.wheelPositions[wheel.ID].position; + targetVec = axes.findLocalVectorGlobally(targetVec); + if (throttle > 0.1) motionVec = new Vector3f(1, 0, 0); + if (throttle < -0.1) motionVec = new Vector3f(-1, 0, 0); + if ((wheel.ID == 2 || wheel.ID == 3) && wheelsYaw >= 0.1) motionVec = new Vector3f(motionVec.x, 0, 1); + if ((wheel.ID == 0 || wheel.ID == 1) && wheelsYaw <= -0.1) motionVec = new Vector3f(motionVec.x, 0, -1); + motionVec = axes.findLocalVectorGlobally(motionVec); + Vector3f test1Pos = new Vector3f(posX + targetVec.x + motionVec.x, posY + targetVec.y, posZ + targetVec.z + motionVec.z); + boolean test1 = worldObj.isAirBlock(Math.round(test1Pos.x), Math.round(test1Pos.y), Math.round(test1Pos.z)); + boolean test2 = worldObj.isAirBlock(Math.round(test1Pos.x), Math.round(test1Pos.y + type.wheelStepHeight), Math.round(test1Pos.z)); + if (!test1 && !test2) { + // Tests to see if we are ascending tall terrain, or stuck in the ground. + throttle *= 0.6; + for (EntityWheel wheel2 : wheels) { + Vector3f wheelPos3 = axes.findLocalVectorGlobally(type.wheelPositions[wheel2.ID].position); + } + } } } - } - /** - * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit - */ - public ArrayList attackFromBullet(Vector3f origin, Vector3f motion) { - //Make an array to contain the hits - ArrayList hits = new ArrayList(); - //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates - Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); - Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); - //Check each part - for (DriveablePart part : getDriveableData().parts.values()) { - //Ray trace the bullet - DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector); - if (hit != null) - hits.add(hit); + if (wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { + lastPos.x = (float) (wheels[0].motionX + wheels[1].motionX + wheels[2].motionX + wheels[3].motionX) / 4; + lastPos.y = (float) (wheels[0].motionY + wheels[1].motionY + wheels[2].motionY + wheels[3].motionY) / 4; + lastPos.z = (float) (wheels[0].motionZ + wheels[1].motionZ + wheels[2].motionZ + wheels[3].motionZ) / 4; } - return hits; - } - /** - * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit - */ - public ArrayList attackFromBulletButBetter(Vector3f origin, Vector3f motion, float size) { - ArrayList hits = new ArrayList(); + double bmy = this.motionY; + this.motionY = amountToMoveCar.y; + if (collisionHardness > 0.2F) { + amountToMoveCar.x = -axes.getXAxis().x*(float)getSpeedXZ()*0.1F; + amountToMoveCar.z = -axes.getXAxis().z*(float)getSpeedXZ()*0.1F; + } + collisionHardness = 0F; + moveEntity(amountToMoveCar.x, amountToMoveCar.y, amountToMoveCar.z); - Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); - //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); - Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); - Vector3f relativePos = Vector3f.sub(origin, vehiclePos, null); + this.motionY = bmy; - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); - Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(motion); + if (wheels[0] != null && wheels[1] != null && wheels[2] != null && wheels[3] != null) { + Vector3f frontAxleCentre = new Vector3f((wheels[2].posX + wheels[3].posX) / 2F, (wheels[2].posY + wheels[3].posY) / 2F, (wheels[2].posZ + wheels[3].posZ) / 2F); + Vector3f backAxleCentre = new Vector3f((wheels[0].posX + wheels[1].posX) / 2F, (wheels[0].posY + wheels[1].posY) / 2F, (wheels[0].posZ + wheels[1].posZ) / 2F); + Vector3f leftSideCentre = new Vector3f((wheels[0].posX + wheels[3].posX) / 2F, (wheels[0].posY + wheels[3].posY) / 2F, (wheels[0].posZ + wheels[3].posZ) / 2F); + Vector3f rightSideCentre = new Vector3f((wheels[1].posX + wheels[2].posX) / 2F, (wheels[1].posY + wheels[2].posY) / 2F, (wheels[1].posZ + wheels[2].posZ) / 2F); - Vector3f ellipsoid = new Vector3f(size, size, size); + if (frontAxleCentre.y > backAxleCentre.y) { + if (throttle > 0) { + float diff = frontAxleCentre.y - backAxleCentre.y; + float dx = frontAxleCentre.x - backAxleCentre.x; + dx = (float) Math.sqrt(dx * dx); + float dz = frontAxleCentre.z - backAxleCentre.z; + dz = (float) Math.sqrt(dz * dz); + float dist = (float) Math.sqrt(dx + dz); + diff = diff / dist; + throttle *= (1F - (diff / 60)); + // Slows down the vehicle when going uphill. + } + } - CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), motion); - test.collisionRecursiveDepth = 0; + float dx = frontAxleCentre.x - backAxleCentre.x; + float dy = frontAxleCentre.y - backAxleCentre.y; + float dz = frontAxleCentre.z - backAxleCentre.z; + float drx = leftSideCentre.x - rightSideCentre.x; + float dry = leftSideCentre.y - rightSideCentre.y; + float drz = leftSideCentre.z - rightSideCentre.z; - Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); - Vector3f eSpaceVelocity = test.velocity; - for (DriveablePart ppart : getDriveableData().parts.values()) { - ppart.rayTraceRider(this, test); - } + float dxz = (float) Math.sqrt(dx * dx + dz * dz); + float drxz = (float) Math.sqrt(drx * drx + drz * drz); - if (test.didCollide) { - Vector3f hitPos = new Vector3f(0, 0, 0); - Vector3f intersect2 = new Vector3f(test.ConvertESpaceToR3(test.intersectionPoint)); - Vector3f.sub(origin, intersect2, hitPos); - float f = (hitPos.length() / motion.length()); - DriveableHit hit = new DriveableHit(this, test.part, f); - hits.add(hit); - } + float tyaw = (float) Math.atan2(dz, dx); + float tpitch = -(float) Math.atan2(dy, dxz); + float troll = 0F; + if (type.canRoll) { + troll = -(float) Math.atan2(dry, drxz); + } - return hits; + yaw = tyaw; + pitch = Lerp(pitch, tpitch, 0.2F); + roll = Lerp(roll, troll, 0.2F); - } + if (type.tank) { + float effectiveWheelSpeed; + if (isEngineActive()) { + float velocityScale = 0.04F * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) + * data.engine.engineSpeed; + float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); + effectiveWheelSpeed = ((wheelsYaw * steeringScale)) * velocityScale; + } else { + effectiveWheelSpeed = 0; + } - /** - * Called if the bullet actually hit the part returned by the raytrace - * - * @param penetratingPower - */ - public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower) { - DriveablePart part = getDriveableData().parts.get(hit.part); - if (bullet != null) - penetratingPower = part.hitByBullet(bullet, hit, penetratingPower); - else - penetratingPower -= 5F; - - //This is server side bsns - if (!worldObj.isRemote) { - checkParts(); - //If it hit, send a damage update packet - FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); - } + yaw = axes.getYaw() / 180F * 3.14159F + effectiveWheelSpeed; + } else { + float velocityScale = 0.1F * throttle * (throttle > 0 ? type.maxThrottle : type.maxNegativeThrottle) * data.engine.engineSpeed; + float steeringScale = 0.1F * (wheelsYaw > 0 ? type.turnLeftModifier : type.turnRightModifier); + float effectiveWheelSpeed = ((wheelsYaw * steeringScale)) * velocityScale; + yaw = axes.getYaw() / 180F * 3.14159F + (effectiveWheelSpeed); + } - return penetratingPower; - } + axes.setAngles(yaw * 180F / 3.14159F, pitch * 180F / 3.14159F, roll * 180F / 3.14159F); + } - /** - * A simple raytracer for the driveable. Called by tools - */ - public DriveablePart raytraceParts(Vector3f origin, Vector3f motion) { - //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates - Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); - Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); - Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); - //Check each part - for (DriveablePart part : getDriveableData().parts.values()) { - //Ray trace the bullet - if (part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null) { - return part; + if (this.ridingEntity != null) { + if (this.ridingEntity.getClass().toString().indexOf("mcheli.aircraft.MCH_EntitySeat") > 0) { + axes.setAngles(this.ridingEntity.rotationYaw + 90, 0, 0); } } - return null; - } - /** - * For overriding for toggles such as gear up / down on planes - */ - public boolean canHitPart(EnumDriveablePart part) { - return true; - } + checkForCollisions(); - /** - * Internal method for checking that all parts are ok, destroying broken ones, dropping items and making sure that child parts are destroyed when their parents are - */ - public void checkParts() { - for (DriveablePart part : getDriveableData().parts.values()) { - if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { - killPart(part); + //Sounds + //Starting sound + if (Math.abs(throttle) > 0.01F && Math.abs(throttle) < 0.2F && soundPosition == 0 && hasEnoughFuel()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.startSoundRange, dimension, type.startSound, false); + soundPosition = type.startSoundLength; + } + //Flying sound + if (throttle >= 0.2F && soundPosition == 0 && hasEnoughFuel() && isEngineActive()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.engineSound, false); + soundPosition = type.engineSoundLength; + } + if (seats[0] != null) { + if (throttle <= 0.01F && throttle >= -0.2F && seats[0].riddenByEntity != null && idlePosition == 0) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.idleSound, false); + idlePosition = type.idleSoundLength; } } + //Back sound + if (throttle <= -0.2F && soundPosition == 0 && hasEnoughFuel() && isEngineActive()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.backSoundRange, dimension, type.backSound, false); + soundPosition = type.backSoundLength; + } - //If the core was destroyed, kill the driveable - if (getDriveableData().parts.get(EnumDriveablePart.core).dead) { - int seatNum = seats.length; + for (EntitySeat seat : seats) { + if (seat != null) { + seat.updatePosition(); + } + } + + //Calculate movement on the client and then send position, rotation etc to the server + if (thePlayerIsDrivingThis) { + FlansMod.getPacketHandler().sendToServer(new PacketVehicleControl(this)); + serverPosX = posX; + serverPosY = posY; + serverPosZ = posZ; + serverYaw = axes.getYaw(); + //if(type.IT1) + //FlansMod.getPacketHandler().sendToServer(new PacketIT1Reload(this)); + } + + //If this is the server, send position updates to everyone, having received them from the driver + if (!worldObj.isRemote && ticksExisted % 5 == 0) { + FlansMod.getPacketHandler().sendToAllAround(new PacketVehicleControl(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); + //if(type.IT1) + //FlansMod.getPacketHandler().sendToAllAround(new PacketIT1Reload(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension); + + } + + int animSpeed = 4; + + if ((throttle > 0.05 && throttle <= 0.33) || (throttle < -0.05 && throttle >= -0.33)) { + animSpeed = 3; + } else if ((throttle > 0.33 && throttle <= 0.66) || (throttle < -0.33 && throttle >= -0.66)) { + animSpeed = 2; + } else if ((throttle > 0.66 && throttle <= 0.9) || (throttle < -0.66 && throttle >= -0.9)) { + animSpeed = 1; + } else if ((throttle > 0.9 && throttle <= 1) || (throttle < -0.9 && throttle >= -1)) { + animSpeed = 0; + } + + boolean turningLeft = false; + boolean turningRight = false; + + if (throttle > 0.05) { + animCountLeft--; + animCountRight--; + } else if (throttle < -0.05) { + animCountLeft++; + animCountRight++; + } else if (wheelsYaw < -1) { + turningLeft = true; + animCountLeft++; + animCountRight--; + animSpeed = 1; + if (soundPosition == 0 && hasEnoughFuel() && type.tank && isEngineActive()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.engineSound, false); + soundPosition = type.engineSoundLength; + } + } else if (wheelsYaw > 1) { + turningRight = true; + animCountLeft--; + animCountRight++; + animSpeed = 1; + if (soundPosition == 0 && hasEnoughFuel() && type.tank && isEngineActive() && isEngineActive()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.engineSoundRange, dimension, type.engineSound, false); + soundPosition = type.engineSoundLength; + } + } else { + turningLeft = false; + turningRight = false; + } - DriveableType type = getDriveableType(); + if (animCountLeft <= 0) { + animCountLeft = animSpeed; + animFrameLeft++; + } - if (!worldObj.isRemote) { - for (EntitySeat seat : seats) { - if (seat.riddenByEntity instanceof EntityPlayer) { -// ((EntityPlayer)seats[i].riddenByEntity).addPotionEffect(new PotionEffect(Potion.harm.id, 10, 5)); - Entity entity = seat.riddenByEntity; - seat.riddenByEntity.setInvisible(false); - seat.riddenByEntity.mountEntity(null); - if (this.lastAtkEntity instanceof EntityPlayer) { - entity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) this.lastAtkEntity), 10000000); - } else if (this.lastAtkEntity instanceof EntityLivingBase) { - entity.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) this.lastAtkEntity), 10000000); - } - } - } + if (animCountRight <= 0) { + animCountRight = animSpeed; + animFrameRight++; + } - if (type.isExplosionWhenDestroyed) -//Create a flans mod explosion rather than a standard MC one. allows control over death boom - { - new FlansModExplosion(worldObj, this, null, type, posX, posY, posZ, - type.deathExplosionRadius, type.deathExplosionPower,TeamsManager.explosions && type.deathExplosionBreaksBlocks, - type.deathExplosionDamageVsLiving, type.deathExplosionDamageVsPlayer, type.deathExplosionDamageVsPlane, type.deathExplosionDamageVsVehicle, seatNum, seatNum); - - } - if(!worldObj.isRemote && type.deathFireRadius > 0.1F) - { - for(float i = -type.deathFireRadius; i < type.deathFireRadius; i++) - { - for(float j = -type.deathFireRadius; j < type.deathFireRadius; j++) - { - for(float k = -type.deathFireRadius; k < type.deathFireRadius; k++) - { - int x = MathHelper.floor_double(i + posX); - int y = MathHelper.floor_double(j + posY); - int z = MathHelper.floor_double(k + posZ); - if(i * i + j * j + k * k <= type.deathFireRadius * type.deathFireRadius && worldObj.getBlock(x, y, z) == Blocks.air && rand.nextBoolean()) - { - worldObj.setBlock(x, y, z, Blocks.fire, 0, 3); - } - } - } - } - } - - for (DriveablePart part : driveableData.parts.values()) { - if (part.health > 0 && !part.dead) - killPart(part); - } + if (throttle < 0 || turningLeft) { + if (animCountLeft >= animSpeed) { + animCountLeft = 0; + animFrameLeft--; } - setDead(); - if(lastAtkEntity!=null&&lastAtkEntity instanceof EntityPlayerMP) { - if (TeamsManager.instance.currentRound != null) { - TeamsManager.instance.currentRound.gametype.vehicleDestroyed(this, (EntityPlayerMP) lastAtkEntity); - } + } + + if (throttle < 0 || turningRight) { + if (animCountRight >= animSpeed) { + animCountRight = 0; + animFrameRight--; } } - } + if (animFrameLeft > type.animFrames) { + animFrameLeft = 0; + } + if (animFrameLeft < 0) { + animFrameLeft = type.animFrames; + } - public void checkPartsWhenAttacked() { - for (DriveablePart part : getDriveableData().parts.values()) { - if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { - killPart(part); - } + if (animFrameRight > type.animFrames) { + animFrameRight = 0; + } + if (animFrameRight < 0) { + animFrameRight = type.animFrames; } - } - /** - * Internal method for killing driveable parts - */ - private void killPart(DriveablePart part) { - if (part.dead) - return; - part.health = 0; - part.dead = true; - - //Drop items - DriveableType type = getDriveableType(); - if (!worldObj.isRemote) { - Vector3f pos = new Vector3f(0, 0, 0); - - //Get the midpoint of the part - if (part.box != null) - pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); - - ArrayList drops = type.getItemsRequired(part, getDriveableData().engine); - if (drops != null) { - //Drop each ItemStack - for (ItemStack stack : drops) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy())); - } - } - dropItemsOnPartDeath(pos, part); - - //Inventory is in the core, so drop it if the core is broken - if (part.type == EnumDriveablePart.core) { - for (int i = 0; i < getDriveableData().getSizeInventory(); i++) { - ItemStack stack = getDriveableData().getStackInSlot(i); - if (stack != null) { - worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack)); + // Decrease throttle each tick. + if (throttle > 0) + throttle -= type.throttleDecay; + else if (throttle < 0) + throttle += type.throttleDecay; + + //Catch to round the throttle down to zero. + if (throttle < type.throttleDecay && throttle > -type.throttleDecay) + throttle = 0; + + //if(seats[0].riddenByEntity == null) throttle = 1F; + + //boolean sentry2; + //sentry2 = false; + /** + if(sentry2){ + if(target != null && target.isDead) + target = null; + } + + if(target == null && sentry2) + { + target = getValidTarget(); + } + + if(target != null) + { + + double dX = target.posX - posX; + double dY = target.posY - (posY); + double dZ = target.posZ - posZ; + boolean canShootHomingMissile = false; + + double distanceToTarget = target.getDistanceToEntity(this); + dX += (target.posX - target.prevPosX) * (distanceToTarget/type.bulletSpeed); + dY += (target.posY - target.prevPosY) * (distanceToTarget/type.bulletSpeed); + dZ += (target.posZ - target.prevPosZ) * (distanceToTarget/type.bulletSpeed); + + int slot = -1; + for(int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) + { + ItemStack bomb = driveableData.getStackInSlot(i); + if(bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)bomb.getItem()).type, EnumWeaponType.SHELL)) + { + slot = i; + } + } + + if(slot != -1) + { + ItemStack bulletStack = driveableData.getStackInSlot(slot); + ItemBullet bulletItem = (ItemBullet)bulletStack.getItem(); + + + } + //distanceToTarget = Math.sqrt((dX * dX) + (dZ * dZ)); + Vector3f initialMot = (this.getPositionOnTurret(new Vector3f(type.bulletSpeed, 0, 0), true)); + float bulletSpeed2 = (float)Math.sqrt((initialMot.x * initialMot.x) + (initialMot.z * initialMot.z)); + float travelTime = (float)distanceToTarget/type.bulletSpeed; + dY += initialMot.y + (0.02F * travelTime); + distanceToTarget = Math.sqrt(dX * dX + dY * dY + dZ * dZ); + float targetRange = 150F; + if(distanceToTarget > targetRange) + target = null; + else if(!canShootHomingMissile) + { + float newYaw = (float)Math.atan2(dZ, dX) * 180F / 3.14159F - axes.getYaw(); + float newPitch = -(float)Math.atan2(dY, Math.sqrt(dX * dX + dZ * dZ)) * 180F / 3.14159F - axes.getPitch(); + + float turnSpeed = 0.25F; + for(; newYaw > 180F; newYaw -= 360F) {} + for(; newYaw <= -180F; newYaw += 360F) {} + + + if(newPitch > -seats[0].seatInfo.minPitch) + newPitch = -seats[0].seatInfo.minPitch; + if(newPitch < -seats[0].seatInfo.maxPitch) + newPitch = -seats[0].seatInfo.maxPitch; + //seats[0].targetYaw = newYaw; + //seats[0].targetPitch = newPitch; + seats[0].looking.setAngles(moveToTarget(seats[0].looking.getYaw(), newYaw, seats[0].seatInfo.aimingSpeed.x), moveToTarget(seats[0].looking.getPitch(), newPitch, seats[0].seatInfo.aimingSpeed.y), 0F); + } + } + */ + + //rotateYaw(10); + } + + public Entity getValidTarget() { + + if (placer == null && placerName != null) + placer = worldObj.getPlayerEntityByName(placerName); + float targetRange = 150F; + Entity target = null; + for (Object obj : worldObj.getEntitiesWithinAABBExcludingEntity(this, boundingBox.expand(targetRange, targetRange, targetRange))) { + Entity candidateEntity = (Entity) obj; + boolean targetMobs = true; + boolean targetPlayers = false; + boolean targetPlanes = true; + boolean targetVehicles = true; + if ((targetMobs && candidateEntity instanceof EntityBat) || (targetPlayers && candidateEntity instanceof EntityPlayer) || (targetPlanes && candidateEntity instanceof EntityPlane) || (targetVehicles && candidateEntity instanceof EntityVehicle)) { + //Check that this entity is actually in range and visible + if (candidateEntity.getDistanceToEntity(this) < targetRange) { + targetRange = candidateEntity.getDistanceToEntity(this); + if (isPartOfThis(candidateEntity)) candidateEntity = null; + if (candidateEntity instanceof EntityPlayer) { + if (candidateEntity == placer || candidateEntity.getCommandSenderName().equals(placerName)) + candidateEntity = null; + if (TeamsManager.enabled && TeamsManager.getInstance().currentRound != null && placer != null) { + PlayerData placerData = PlayerHandler.getPlayerData(placer, worldObj.isRemote ? Side.CLIENT : Side.SERVER); + PlayerData candidateData = PlayerHandler.getPlayerData((EntityPlayer) candidateEntity, worldObj.isRemote ? Side.CLIENT : Side.SERVER); + if (candidateData.team == Team.spectators || candidateData.team == null) + candidateEntity = null; + if (!TeamsManager.getInstance().currentRound.gametype.playerCanAttack((EntityPlayerMP) placer, placerData.team, (EntityPlayerMP) candidateEntity, candidateData.team)) + candidateEntity = null; + } } + target = candidateEntity; } } } - - //Kill all child parts to stop things floating unconnected - for (EnumDriveablePart child : part.type.getChildren()) { - killPart(getDriveableData().parts.get(child)); - } + if (target != null) + return target; + else return null; } - /** - * Method for planes, vehicles and whatnot to drop their own specific items if they wish - */ - protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part); - - @Override - public float getPlayerRoll() { - return axes.getRoll(); - } + public void animateFancyTracks() { + float funkypart = getVehicleType().trackLinkFix; + boolean funk = true; + float funk2 = 0; + for (int i = 0; i < trackLinksLeft.length; i++) { + trackLinksLeft[i].prevPosition = trackLinksLeft[i].position; + trackLinksLeft[i].prevZRot = trackLinksLeft[i].zRot; + float speed = throttle * 1.5F - (wheelsYaw / 12); + trackLinksLeft[i].progress += speed; + if (trackLinksLeft[i].progress > leftTrack.getTrackLength()) + trackLinksLeft[i].progress -= leftTrack.getTrackLength(); + if (trackLinksLeft[i].progress < 0) trackLinksLeft[i].progress += leftTrack.getTrackLength(); + trackLinksLeft[i].position = leftTrack.getPositionOnTrack(trackLinksLeft[i].progress); + for (; trackLinksLeft[i].zRot > 180F; trackLinksLeft[i].zRot -= 360F) { + } + for (; trackLinksLeft[i].zRot <= -180F; trackLinksLeft[i].zRot += 360F) { + } + float newAngle = rotateTowards(leftTrack.points.get(leftTrack.getTrackPart(trackLinksLeft[i].progress)), trackLinksLeft[i].position); + int part = leftTrack.getTrackPart(trackLinksLeft[i].progress); + if (funk) funk2 = (speed < 0) ? 0 : 1; + else funk2 = (speed < 0) ? -1 : 0; + trackLinksLeft[i].zRot = Lerp(trackLinksLeft[i].zRot, newAngle, (part != (funkypart + funk2)) ? 0.5F : 1); - @Override - public void explode() { + } + for (int i = 0; i < trackLinksRight.length; i++) { + trackLinksRight[i].prevPosition = trackLinksRight[i].position; + trackLinksRight[i].prevZRot = trackLinksRight[i].zRot; + float speed = throttle * 1.5F + (wheelsYaw / 12); + trackLinksRight[i].progress += speed; + if (trackLinksRight[i].progress > rightTrack.getTrackLength()) + trackLinksRight[i].progress -= leftTrack.getTrackLength(); + if (trackLinksRight[i].progress < 0) trackLinksRight[i].progress += rightTrack.getTrackLength(); + trackLinksRight[i].position = rightTrack.getPositionOnTrack(trackLinksRight[i].progress); + float newAngle = rotateTowards(rightTrack.points.get(rightTrack.getTrackPart(trackLinksRight[i].progress)), trackLinksRight[i].position); + int part = rightTrack.getTrackPart(trackLinksRight[i].progress); + if (funk) funk2 = (speed < 0) ? 0 : 1; + else funk2 = (speed < 0) ? -1 : 0; + trackLinksRight[i].zRot = Lerp(trackLinksRight[i].zRot, newAngle, (part != (funkypart + funk2)) ? 0.5F : 1); + } } - @Override - public float getCameraDistance() { - return getDriveableType().cameraDistance; - } + public float rotateTowards(Vector3f point, Vector3f original) { - public boolean isPartIntact(EnumDriveablePart part) { - DriveablePart thisPart = getDriveableData().parts.get(part); - return thisPart.maxHealth == 0 || thisPart.health > 0; + float angle = (float) Math.atan2(point.y - original.y, point.x - original.x); + return angle; } - public abstract boolean hasMouseControlMode(); + public void dischargeSmoke() { + VehicleType type = this.getVehicleType(); + for (int i = 0; i < type.smokers.size(); i++) { + SmokePoint smoker = type.smokers.get(i); + Vector3f dir = smoker.direction; + Vector3f pos = smoker.position; + int time = smoker.detTime; - public abstract String getBombInventoryName(); + dir = axes.findLocalVectorGlobally(dir); + pos = axes.findLocalVectorGlobally(pos); - public abstract String getMissileInventoryName(); + if (EnumDriveablePart.getPart(smoker.part) == EnumDriveablePart.turret) { + dir = rotate(seats[0].looking.findLocalVectorGlobally(smoker.direction)); + pos = getPositionOnTurret(smoker.position, false); + } - public boolean rotateWithTurret(Seat seat) { - return seat.part == EnumDriveablePart.turret; - } + //FlansMod.getPacketHandler().sendToAllAround(new PacketSmokeGrenade(posX + pos.x/16, posY + pos.y/16, posZ + pos.z/16, dir.x, dir.y, dir.z, time), posX, posY, posZ, 150, dimension); - @Override - public String getCommandSenderName() { - return getDriveableType().name; - } + //FlansMod.proxy.spawnSmokeGrenade("flansmod.smoker", posX + pos.x/16, posY + pos.y/16, posZ + pos.z/16, dir.x, dir.y, dir.z, time); - @SideOnly(Side.CLIENT) - public boolean showInventory(int seat) { - return seat != 0 || !FlansModClient.controlModeMouse; + FlansMod.getPacketHandler().sendToAllAround(new PacketParticle("flansmod.smoker", posX + pos.x / 16, posY + pos.y / 16, posZ + pos.z / 16, dir.x, dir.y, dir.z), posX, posY, posZ, 150, dimension); + } } - //------------------------------------- - // Getters and setters for dual fields - //------------------------------------- - - public float getShootDelay(boolean secondary) { - return secondary ? shootDelaySecondary : shootDelayPrimary; - } + public float Lerp(float start, float end, float percent) { + float result = (start + percent * (end - start)); - public boolean canLaunchIT1() { - return canFireIT1; + return result; } - public float getMinigunSpeed(boolean secondary) { - return secondary ? minigunSpeedSecondary : minigunSpeedPrimary; + public static float Clamp(float val, float min, float max) { + return Math.max(min, Math.min(max, val)); } - public int getCurrentGun(boolean secondary) { - return secondary ? currentGunSecondary : currentGunPrimary; - } + public List findEntitiesWithinbounds() { + VehicleType type = this.getVehicleType(); + AxisAlignedBB initialBox = this.boundingBox.copy(); + List riddenEntities = worldObj.getEntitiesWithinAABB(Entity.class, initialBox); - public void setShootDelay(float i, boolean secondary) { - setRecoilTimer(); - // If current delay is greater than i, use that. If current delay is less than 0, add that to new shoot delay - if (secondary) - shootDelaySecondary = i > shootDelaySecondary ? (shootDelaySecondary < 0 ? i + shootDelaySecondary : i) : shootDelaySecondary; - else - shootDelayPrimary = i > shootDelayPrimary ? (shootDelayPrimary < 0 ? i + shootDelayPrimary : i) : shootDelayPrimary; - } + Vector3f size = new Vector3f(type.harvestBoxSize.x / 8F, type.harvestBoxSize.y / 8F, type.harvestBoxSize.z / 8F); + Vector3f pos = new Vector3f(type.harvestBoxPos.x / 8F, type.harvestBoxPos.y / 8F, type.harvestBoxPos.z / 8F); + boolean fancy = false; + if (!fancy) { + for (float x = pos.x; x <= pos.x + size.x; x++) { + for (float y = pos.y; y <= pos.y + size.y; y++) { + for (float z = pos.z; z <= pos.z + size.z; z++) { + Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); - public void setMinigunSpeed(float f, boolean secondary) { - if (secondary) - minigunSpeedSecondary = f; - else minigunSpeedPrimary = f; - } + double entX = (posX + v.x); + double entY = (posY + v.y); + double entZ = (posZ + v.z); + AxisAlignedBB checkBox = this.boundingBox.copy().offset(v.x, v.y, v.z); - public void setCurrentGun(int i, boolean secondary) { - if (secondary) - currentGunSecondary = i; - else currentGunPrimary = i; - } + List entityhere = worldObj.getEntitiesWithinAABB(Entity.class, checkBox); - public void setEntityMarker(int tick) { - this.isShowedPosition = true; - this.tickCount = tick; - } + for (int i = 0; i < entityhere.size(); i++) { + if (entityhere.get(i) instanceof EntityPlayer && !isPartOfThis(entityhere.get(i))) + riddenEntities.add(entityhere.get(i)); + } + //Iterator iter = entityhere.iterator(); + /** + while( iter.hasNext() ) + { + Entity entity = iter.next(); + if(isPartOfThis(entity)) iter.remove(); + if(entity instanceof EntityBullet) iter.remove(); + } */ - public void IT1Reload() { - DriveableType type = getDriveableType(); + } + } + } + } else { + AxisAlignedBB checkBox = this.getBoundingBox().copy().expand(50, 50, 50); + List entityhere = worldObj.getEntitiesWithinAABB(EntityPlayer.class, checkBox); - if (stage == 1) { - //canFireIT1 = false; - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 5); + for (int i = 0; i < entityhere.size(); i++) { + if (entityhere.get(i) instanceof EntityPlayer) { + riddenEntities.add(entityhere.get(i)); + //AxisAlignedBB checkBox2 = this.boundingBox.copy().offset(this.posX - entityhere.get(i).posX,this.posY - entityhere.get(i).posY, this.posZ - entityhere.get(i).posZ); + } + } - if (drakonRailAngle == -10) stage++; } + return riddenEntities; + } + public Vector3f transformPart(Vector3f current, Vector3f target, Vector3f rate) { + Vector3f newPos = current; - if (stage == 2) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonDoorAngle == -90) stage++; + if (Math.sqrt((current.x - target.x) * (current.x - target.x)) > rate.x / 2) { + if (current.x > target.x) { + current.x = current.x - rate.x; + } else if (current.x < target.x) { + current.x = current.x + rate.x; + } + } else { + current.x = target.x; } - if (stage == 3) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 179, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonArmAngle == 179) stage++; + if (Math.sqrt((current.y - target.y) * (current.y - target.y)) > rate.y / 2) { + if (current.y > target.y) { + current.y = current.y - rate.y; + } else if (current.y < target.y) { + current.y = current.y + rate.y; + } + } else { + current.y = target.y; } - if (stage == 4) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - - if (drakonDoorAngle == 0) { - if (IT1Loaded()) { - stage++; - reloadAnimTime = 60; - } + if (Math.sqrt((current.z - target.z) * (current.z - target.z)) > rate.z / 2) { + if (current.z > target.z) { + current.z = current.z - rate.z; + } else if (current.z < target.z) { + current.z = current.z + rate.z; } + } else { + current.z = target.z; } - if (stage == 5) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); - reloadingDrakon = true; + return newPos; + } - if (drakonDoorAngle == -90) stage++; - } + @Override + protected void fall(float k) { + if (k <= 10) return; + float damage = MathHelper.ceiling_float_int(k) * 2; - if (stage == 6) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + boolean no_damage = true; + if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20) { + DriveableType type = getDriveableType(); + damage = (int) (damage * type.fallDamageFactor); + attackPart(EnumDriveablePart.core, DamageSource.fall, damage); + if (type.wheelPositions.length > 0) { + attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5); + } - if (drakonArmAngle == 0) stage++; + no_damage = false; } + // FlansMod.log("fall%s : tick=%d damage=%.1f", no_damage? " no damage":"", this.ticksExisted, damage); + } - if (stage == 7) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - drakonRailAngle = moveToTarget(drakonRailAngle, 0, 1); + private float averageAngles(float a, float b) { + float pi = (float) Math.PI; + while (a > b + pi) { a -= 2 * pi; } + while (a < b - pi) { a += 2 * pi; } - if (drakonRailAngle == 0 && drakonDoorAngle == 0) { - stage++; - canFireIT1 = true; - reloadingDrakon = false; - } - } + float avg = (a + b) / 2F; - if (stage == 8) { - drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); - drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); - if (worldObj.isRemote && this.ticksExisted > 2) - drakonRailAngle = moveToTarget(drakonRailAngle, -seats[0].looking.getPitch(), seats[0].seatInfo.aimingSpeed.y); - //reloadAnimTime = 60; + while (avg > pi) { avg -= 2 * pi; } + while (avg < -pi) { avg += 2 * pi; } - if (!IT1Loaded()) { - stage = 1; - canFireIT1 = false; - } - } + return avg; } - public float moveToTarget(float current, float target, float speed) { + private Vec3 subtract(Vec3 a, Vec3 b) { + return Vec3.createVectorHelper(a.xCoord - b.xCoord, a.yCoord - b.yCoord, a.zCoord - b.zCoord); + } - float pitchToMove = (float) ((Math.sqrt(target * target)) - Math.sqrt((current * current))); - for (; pitchToMove > 180F; pitchToMove -= 360F) { - } - for (; pitchToMove <= -180F; pitchToMove += 360F) { - } + private Vec3 crossProduct(Vec3 a, Vec3 b) { + return Vec3.createVectorHelper(a.yCoord * b.zCoord - a.zCoord * b.yCoord, a.zCoord * b.xCoord - a.xCoord * b.zCoord, a.xCoord * b.yCoord - a.yCoord * b.xCoord); + } - float signDeltaY = 0; - if (pitchToMove > speed) { - signDeltaY = 1; - } else if (pitchToMove < -speed) { - signDeltaY = -1; - } else { - signDeltaY = 0; - return target; - } + @Override + public boolean landVehicle() { + return true; + } + @Override + public boolean attackEntityFrom(DamageSource damagesource, float i) { + if (worldObj.isRemote || isDead) + return true; - if (current > target) { - current = current - speed; - } else if (current < target) { - current = current + speed; + VehicleType type = getVehicleType(); + + if (damagesource.damageType.equals("player") + && damagesource.getEntity().onGround + && (seats[0] == null || seats[0].riddenByEntity == null) + && ((damagesource.getEntity() instanceof EntityPlayer && ((EntityPlayer)damagesource.getEntity()).capabilities.isCreativeMode) || TeamsManager.survivalCanBreakVehicles)) { + ItemStack vehicleStack = new ItemStack(type.item, 1, driveableData.paintjobID); + vehicleStack.stackTagCompound = new NBTTagCompound(); + driveableData.writeToNBT(vehicleStack.stackTagCompound); + if (!worldObj.isRemote && damagesource.getEntity() instanceof EntityPlayer) { FlansMod.log("Player %s broke vehicle %s (%d) at (%f, %f, %f)", ((EntityPlayerMP)damagesource.getEntity()).getDisplayName(), type.shortName, getEntityId(), posX, posY, posZ); } + entityDropItem(vehicleStack, 0.5F); + setDead(); } + return super.attackEntityFrom(damagesource, i); + } - return current; + public VehicleType getVehicleType() { + return VehicleType.getVehicle(driveableType); } - public boolean IT1Loaded() { - DriveableType type = getDriveableType(); - boolean loaded = false; - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.MISSILE)) { - loaded = true; - } - } + @Override + public float getPlayerRoll() { + return axes.getRoll(); + } + + public void Recoil() { - return loaded; } - public void tryRecoil() { - int slot = -1; - DriveableType type = getDriveableType(); - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { - slot = i; - } - } + @Override + protected void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part) { + } - if (recoilTimer <= 0 && slot != -1) - isRecoil = true; + @Override + public String getBombInventoryName() { + return "Mines"; } - public void setRecoilTimer() { - int slot = -1; - DriveableType type = getDriveableType(); - for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { - ItemStack shell = driveableData.getStackInSlot(i); - if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { - slot = i; - } - } + @Override + public String getMissileInventoryName() { + return "Shells"; + } - if (recoilTimer <= 0 && slot != -1) - recoilTimer = (int) getDriveableType().shootDelayPrimary; + @Override + public boolean hasMouseControlMode() { + return false; } @Override - public boolean isInRangeToRenderDist(double d) { - double d1 = this.renderDistanceWeight; - return d < d1 * d1; + @SideOnly(Side.CLIENT) + public EntityLivingBase getCamera() { + return null; + } + + public boolean hasBothTracks() { + boolean tracks = true; + if (!isPartIntact(EnumDriveablePart.leftTrack)) { + tracks = false; + } + + if (!isPartIntact(EnumDriveablePart.rightTrack)) { + tracks = false; + } + + return tracks; } - // Returns if the bounding box is under the - public boolean isUnderWater() { - return worldObj.isAnyLiquid(this.boundingBox.copy().offset(0, getDriveableType().maxDepth, 0)); + @Override + public void setDead() { + super.setDead(); + for (EntityWheel wheel : wheels) + if (wheel != null) + wheel.setDead(); } } - From d1e860d4da09994ac12559ee9f091ead658deff4 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 18:07:14 +0200 Subject: [PATCH 11/25] Revert "big minigames update. part 1" This reverts commit 6d06115a291e17f7d403852d551cb0c15a19b8f6. --- .../common/driveables/EntityDriveable.java | 2841 ++++++++++++++++- 1 file changed, 2705 insertions(+), 136 deletions(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index 740b55b3..28976ef3 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -1,233 +1,2802 @@ -package com.flansmod.common.teams; +package com.flansmod.common.driveables; -import java.util.HashMap; -import java.util.List; -import java.util.Random; - -import com.flansmod.common.driveables.EntityDriveable; -import com.flansmod.common.driveables.EntityPlane; -import com.flansmod.common.driveables.EntityVehicle; -import com.flansmod.common.driveables.EnumPlaneMode; -import com.flansmod.common.guns.EntityBullet; +import cofh.api.energy.IEnergyContainerItem; +import com.flansmod.api.IControllable; +import com.flansmod.api.IExplodeable; +import com.flansmod.client.EntityCamera; +import com.flansmod.client.FlansModClient; +import com.flansmod.client.debug.EntityDebugVector; +import com.flansmod.common.FlansMod; +import com.flansmod.common.RotatedAxes; +import com.flansmod.common.driveables.DriveableType.ParticleEmitter; +import com.flansmod.common.driveables.DriveableType.ShootParticle; +import com.flansmod.common.driveables.collisions.CollisionPlane; +import com.flansmod.common.driveables.collisions.CollisionShapeBox; +import com.flansmod.common.driveables.collisions.CollisionTest; +import com.flansmod.common.driveables.mechas.EntityMecha; +import com.flansmod.common.guns.*; +import com.flansmod.common.guns.raytracing.BulletHit; +import com.flansmod.common.guns.raytracing.DriveableHit; +import com.flansmod.common.network.PacketDriveableDamage; +import com.flansmod.common.network.PacketDriveableKeyHeld; +import com.flansmod.common.network.PacketParticle; +import com.flansmod.common.network.PacketPlaySound; +import com.flansmod.common.parts.ItemPart; +import com.flansmod.common.parts.PartType; +import com.flansmod.common.teams.TeamsManager; +import com.flansmod.common.vector.Vector3f; +import cpw.mods.fml.common.network.ByteBufUtils; +import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.DamageSource; -import net.minecraft.util.EntityDamageSource; -import net.minecraft.util.Vec3; +import net.minecraft.util.*; +import net.minecraft.util.MovingObjectPosition.MovingObjectType; +import net.minecraft.world.World; -import com.flansmod.common.FlansMod; -import com.flansmod.common.PlayerData; -import com.flansmod.common.PlayerHandler; -import com.flansmod.common.network.PacketBase; -import com.flansmod.common.types.InfoType; +import java.util.ArrayList; + +public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData { + public boolean syncFromServer = true; + /** + * Ticks since last server update. Use to smoothly transition to new position + */ + public int serverPositionTransitionTicker; + /** + * Server side position, as synced by PacketVehicleControl packets + */ + public double serverPosX, serverPosY, serverPosZ; + /** + * Server side rotation, as synced by PacketVehicleControl packets + */ + public double serverYaw, serverPitch, serverRoll; -public abstract class GameType { - public static HashMap gameTypes = new HashMap<>(); - public static TeamsManager teamsManager = TeamsManager.getInstance(); - public static Random rand = new Random(); + /** + * The driveable data which contains the inventory, the engine and the fuel + */ + public DriveableData driveableData; + /** + * The shortName of the driveable type, used to obtain said type + */ + public String driveableType; - public static GameType getGameType(String type) { - return gameTypes.get(type); - } + /** + * The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to obtain the thrust + */ + public float throttle; + /** + * The wheels on this plane + */ + public EntityWheel[] wheels; - public String name; - public String shortName; - public int numTeamsRequired; + public boolean fuelling; + /** + * Extra prevRotation field for smoothness in all 3 rotational axes + */ + public float prevRotationRoll; + /** + * Angular velocity + */ + public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F); - public GameType(String name, String shortName, int numTeams) { - this.name = name; - this.shortName = shortName; - numTeamsRequired = numTeams; - gameTypes.put(this.shortName, this); - } + /** + * Whether each mouse button is held + */ + public boolean leftMouseHeld = false, rightMouseHeld = false; /** - * Called when a round starts + * Shoot delay variables + */ + public float shootDelayPrimary, shootDelaySecondary; + /** + * Minigun speed variables */ - public abstract void roundStart(); + public float minigunSpeedPrimary, minigunSpeedSecondary; + /** + * Current gun variables for alternating weapons. + */ + public int currentGunPrimary, currentGunSecondary; /** - * Called when a round ends. (The point at which scoreboards are displayed) + * Angle of harvester aesthetic piece */ - public abstract void roundEnd(); + public float harvesterAngle; + + public RotatedAxes prevAxes; + public RotatedAxes axes; + + public EntitySeat[] seats; + + public int lockOnSoundDelay; + + private int[] emitterTimers; + + public int animCountLeft = 0; + public int animFrameLeft = 0; + public int animCountRight = 0; + public int animFrameRight = 0; + + public boolean leftTurnHeld = false; + public boolean rightTurnHeld = false; + + + public boolean isShowedPosition = false; + + public int tickCount = 0; + + //Gun recoil + public boolean isRecoil = false; + public float recoilPos = 0; + public float lastRecoilPos = 0; + public int recoilTimer = 0; + + public Vector3f lastPos = new Vector3f(0, 0, 0); + public boolean hugeBoat = false; + public boolean onDeck = false; + public double deckHeight = 0; + public int deckCheck = 0; + public int prevDeckCheck = 0; + + public boolean isMecha = false; + public boolean disabled = false; /** - * Called when the scoreboards and voting are finished + * The angle of the propeller for the renderer */ - public abstract void roundCleanup(); + public float propAngle = 0; + public float prevPropAngle = 0; + + public float rotorAngle = 0; + public float prevRotorAngle = 0; + + //Flares + public int flareDelay = 0; + public int ticksFlareUsing = 0; + public boolean varFlare; + + //IT1 stuff + public float drakonDoorAngle = 0; + public float drakonArmAngle = 0; + public float drakonRailAngle = 0; + + public float prevDrakonDoorAngle = 0; + public float prevDrakonArmAngle = 0; + public float prevDrakonRailAngle = 0; + + public boolean reloadingDrakon = false; + public boolean canFireIT1 = true; + + public int stage = 1; + public int reloadAnimTime = 0; - public abstract boolean teamHasWon(Team team); + public boolean toDeactivate = false; + public int timeTillDeactivate = 0; - public void tick() { + // + public boolean canFire = true; + + + @SideOnly(Side.CLIENT) + public EntityLivingBase camera; + + protected int invulnerableUnmountCount; + + private ItemStack[][] prevInventoryItems = new ItemStack[][]{null, null}; + + public Entity lastAtkEntity = null; + + public Float collisionHardness = 0F; + + public int engineStartDelay; + + //public ArrayList playerIDs = new ArrayList(); + + public EntityDriveable(World world) { + super(world); + axes = new RotatedAxes(); + prevAxes = new RotatedAxes(); + preventEntitySpawning = true; + if (FlansMod.driveableHitboxes) { + setSize(1F, 1F); + } else { + setSize(0F, 0F); + } + yOffset = 6F / 16F; + ignoreFrustumCheck = true; + renderDistanceWeight = 20000D; } - public Team[] getTeamsCanSpawnAs(TeamsRound currentRound, EntityPlayer player) { - return currentRound.teams; + + public EntityDriveable(World world, DriveableType t, DriveableData d) { + this(world); + driveableType = t.shortName; + driveableData = d; } - public void playerJoined(EntityPlayerMP player) { + protected void initType(DriveableType type, boolean clientSide) { + if (type == null) return; + seats = new EntitySeat[type.numPassengers + 1]; + for (int i = 0; i < type.numPassengers + 1; i++) { + if (!clientSide) { + seats[i] = new EntitySeat(worldObj, this, i); + worldObj.spawnEntityInWorld(seats[i]); + } + } + wheels = new EntityWheel[type.wheelPositions.length]; + for (int i = 0; i < wheels.length; i++) { + if (!clientSide) { + wheels[i] = new EntityWheel(worldObj, this, i); + worldObj.spawnEntityInWorld(wheels[i]); + } + } + stepHeight = type.wheelStepHeight; + yOffset = type.yOffset; + + emitterTimers = new int[type.emitters.size()]; + for (int i = 0; i < type.emitters.size(); i++) { + emitterTimers[i] = rand.nextInt(type.emitters.get(i).emitRate); + } + + getEntityData().setBoolean("CanMountEntity", type.canMountEntity); + + //Register Plane to Radar on Spawning + //if(type.onRadar == true) + // RadarRegistry.register(this); + + for (int ps = 0; ps < 2; ps++) { + EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; + if (weaponType == EnumWeaponType.GUN) { + weaponType = EnumWeaponType.NONE; + } + int istart = getInventoryStart(weaponType); + if (istart == driveableData.getAmmoInventoryStart()) { + istart += type.numPassengerGunners; + } + final int isize = getInventorySize(weaponType); + if (istart >= 0 || isize > 0) { + prevInventoryItems[ps] = new ItemStack[isize]; + for (int i = 0; i < isize; i++) { + prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); + } + } + } + + engineStartDelay = type.engineStartTime; } - public void playerRespawned(EntityPlayerMP player) { + @Override + protected void writeEntityToNBT(NBTTagCompound tag) { + driveableData.writeToNBT(tag); + tag.setString("Type", driveableType); + tag.setFloat("RotationYaw", axes.getYaw()); + tag.setFloat("RotationPitch", axes.getPitch()); + tag.setFloat("RotationRoll", axes.getRoll()); } - public void playerQuit(EntityPlayerMP player) { + @Override + protected void readEntityFromNBT(NBTTagCompound tag) { + driveableType = tag.getString("Type"); + driveableData = new DriveableData(tag); + initType(DriveableType.getDriveable(driveableType), false); + + prevRotationYaw = tag.getFloat("RotationYaw"); + prevRotationPitch = tag.getFloat("RotationPitch"); + prevRotationRoll = tag.getFloat("RotationRoll"); + axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll); } - //Return true if damage should be dealt. - public boolean playerAttacked(EntityPlayerMP player, DamageSource source) { - return true; + @Override + public void writeSpawnData(ByteBuf data) { + ByteBufUtils.writeUTF8String(data, driveableType); + + NBTTagCompound tag = new NBTTagCompound(); + driveableData.writeToNBT(tag); + ByteBufUtils.writeTag(data, tag); + + data.writeFloat(axes.getYaw()); + data.writeFloat(axes.getPitch()); + data.writeFloat(axes.getRoll()); + + //Write damage + for (EnumDriveablePart ep : EnumDriveablePart.values()) { + DriveablePart part = getDriveableData().parts.get(ep); + data.writeFloat(part.health); + data.writeBoolean(part.onFire); + } } - public void playerKilled(EntityPlayerMP player, DamageSource source) { + @Override + public void readSpawnData(ByteBuf data) { + try { + driveableType = ByteBufUtils.readUTF8String(data); + driveableData = new DriveableData(ByteBufUtils.readTag(data)); + initType(getDriveableType(), true); + + axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat()); + prevRotationYaw = axes.getYaw(); + prevRotationPitch = axes.getPitch(); + prevRotationRoll = axes.getRoll(); + + //Read damage + for (EnumDriveablePart ep : EnumDriveablePart.values()) { + DriveablePart part = getDriveableData().parts.get(ep); + part.health = data.readFloat(); + part.onFire = data.readBoolean(); + } + + } catch (Exception e) { + FlansMod.log("Failed to retrieve plane type from server."); + super.setDead(); + e.printStackTrace(); + } + + camera = new EntityCamera(worldObj, this); + worldObj.spawnEntityInWorld(camera); } - public void baseAttacked(ITeamBase base, DamageSource source) { + /** + * Called with the movement of the mouse. Used in controlling vehicles if need be. + * + * @param deltaY change in Y + * @param deltaX change in X + * @return if mouse movement was handled. + */ + @Override + public abstract void onMouseMoved(int deltaX, int deltaY); + + @Override + @SideOnly(Side.CLIENT) + public EntityLivingBase getCamera() { + return camera; } - public void objectAttacked(ITeamObject object, DamageSource source) { + protected boolean canSit(int seat) { + return getDriveableType().numPassengers >= seat && seats[seat].riddenByEntity == null; } - public void baseClickedByPlayer(ITeamBase base, EntityPlayerMP player) { + @Override + protected boolean canTriggerWalking() { + return false; } - public void objectClickedByPlayer(ITeamObject object, EntityPlayerMP player) { + @Override + protected void entityInit() { } - public boolean playerCanLoot(ItemStack stack, InfoType infoType, EntityPlayer player, Team playerTeam) { - return true; + + @Override + public AxisAlignedBB getCollisionBox(Entity entity) { + if (getDriveableType().collisionDamageEnable) { + if (throttle > getDriveableType().collisionDamageThrottle) { + if (entity instanceof EntityLiving) { + entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } else if (entity instanceof EntityPlayer) { + entity.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } + } + } + return boundingBox; } - public abstract Vec3 getSpawnPoint(EntityPlayerMP player); + @Override + public AxisAlignedBB getBoundingBox() { + return boundingBox; + } - //Return whether or not the variable exists - public boolean setVariable(String variable, String value) { + @Override + public boolean canBePushed() { return false; } - public abstract void readFromNBT(NBTTagCompound tags); + @Override + public double getMountedYOffset() { + return -0.3D; + } + + /** + * Pass generic damage to the core + */ + @Override + public boolean attackEntityFrom(DamageSource damagesource, float i) { + if (worldObj.isRemote || isDead) return true; +// if(damagesource.getDamageType().indexOf("explosion") < 0) + { + if (isMountedEntity(damagesource.getEntity())) { + return false; + } + } - public abstract void saveToNBT(NBTTagCompound tags); +// FlansMod.log(String.format("EntityDriveable.attackEntityFrom %.1f: %s : %s : %s", i, +// damagesource.getDamageType(), damagesource.getEntity(), damagesource.getSourceOfDamage())); - public boolean sortScoreboardByTeam() { + boolean broken = attackPart(EnumDriveablePart.core, damagesource, i); + if (i > 0) { + //checkParts(); + checkPartsWhenAttacked(); + //If it hit, send a damage update packet + FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); + } return true; } - public boolean showZombieScore() { + public boolean isMountedEntity(Entity entity) { + if (entity != null) { + Entity entity2 = this.worldObj.getEntityByID(entity.getEntityId()); + for (Entity seat : seats) { + if (seat.riddenByEntity != null) { + if (seat.riddenByEntity == entity || seat.riddenByEntity == entity2) { + return true; + } + } + } + } + return false; } - /** - * Whether "attacker" can attack "victim" - */ - public boolean playerCanAttack(EntityPlayerMP attacker, Team attackerTeam, EntityPlayerMP victim, Team victimTeam) { - return true; + @Override + public void setDead() { + super.setDead(); + //Unregister to Radar + //RadarRegistry.unregister(this); + if (worldObj.isRemote) + camera.setDead(); + + for (EntitySeat seat : seats) + if (seat != null) + seat.setDead(); } - /** - * Called when any entity is killed. This allows one to track mob deaths too - */ - public void entityKilled(Entity entity, DamageSource source) { + @Override + public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) { + } + @Override + public boolean canBeCollidedWith() { + return true; } - public void vehicleDestroyed(EntityDriveable driveable2, EntityPlayerMP attacker){ - if (driveable2!=null) { - if (attacker != null) { - EntityDriveable driveable = driveable2; -// if(driveable.riddenByEntity!=null && -// driveable.riddenByEntity instanceof EntityPlayer && -// !getPlayerData((EntityPlayerMP) driveable.riddenByEntity).team.equals(getPlayerData(attacker).team)) { - if(true){ //this if() need for next changes - getPlayerInfo(attacker).vehiclesDestroyed++; - if (driveable instanceof EntityPlane) { - EntityPlane plane = (EntityPlane) driveable; - if (plane.mode == EnumPlaneMode.PLANE || plane.mode == EnumPlaneMode.VTOL) { - getPlayerInfo(attacker).addExp(100); - getPlayerInfo(attacker).savePlayerStats(); - } else if (plane.mode == EnumPlaneMode.HELI) { - getPlayerInfo(attacker).addExp(75); - getPlayerInfo(attacker).savePlayerStats(); - } - } else if (driveable instanceof EntityVehicle) { - EntityVehicle vehicle = (EntityVehicle) driveable; - if (vehicle.getVehicleType().tank) { - getPlayerInfo(attacker).addExp(75); - getPlayerInfo(attacker).savePlayerStats(); - } else { - getPlayerInfo(attacker).addExp(50); - getPlayerInfo(attacker).savePlayerStats(); - } - } + @Override + public void applyEntityCollision(Entity entity) { + //if(!isPartOfThis(entity)) + //super.applyEntityCollision(entity); + } + + @Override + public void setPositionAndRotation2(double d, double d1, double d2, float f, float f1, int i) { + if (ticksExisted > 1) + return; + if (!(riddenByEntity instanceof EntityPlayer) || !FlansMod.proxy.isThePlayer((EntityPlayer) riddenByEntity)) { + if (syncFromServer) { + serverPositionTransitionTicker = i + 5; + } else { + double var10 = d - posX; + double var12 = d1 - posY; + double var14 = d2 - posZ; + double var16 = var10 * var10 + var12 * var12 + var14 * var14; + + if (var16 <= 1.0D) { + return; } + + serverPositionTransitionTicker = 3; } + serverPosX = d; + serverPosY = d1; + serverPosZ = d2; + serverYaw = f; + serverPitch = f1; + } + } + + public void setIT1(boolean canFire, boolean reloading, int stag, int stageTime) { + if (worldObj.isRemote && ticksExisted % 5 == 0) { + canFireIT1 = canFire; + reloadingDrakon = reloading; + stage = stag; + reloadAnimTime = stageTime; + } + } + + public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw) { + if (worldObj.isRemote) { + serverPosX = x; + serverPosY = y; + serverPosZ = z; + serverYaw = yaw; + serverPitch = pitch; + serverRoll = roll; + serverPositionTransitionTicker = 5; + } else { + setPosition(x, y, z); + prevRotationYaw = yaw; + prevRotationPitch = pitch; + prevRotationRoll = roll; + setRotation(yaw, pitch, roll); } + //Set the motions regardless of side. + motionX = motX; + motionY = motY; + motionZ = motZ; + angularVelocity = new Vector3f(velYaw, velPitch, velRoll); + throttle = throt; + } + + + @Override + public void setVelocity(double d, double d1, double d2) { + motionX = d; + motionY = d1; + motionZ = d2; } - public void playerChoseTeam(EntityPlayerMP player, Team team, Team newTeam) { + @Override + public boolean pressKey(int key, EntityPlayer player) { + if (!worldObj.isRemote && key == 9 && getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) //Primary + { + shoot(false); + return true; + } else if (!worldObj.isRemote && key == 8 && getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) //Secondary + { + shoot(true); + return true; + } + return false; } - public void playerChoseNewClass(EntityPlayerMP player, PlayerClass playerClass) { + @Override + public void updateKeyHeldState(int key, boolean held) { + if (worldObj.isRemote) { + FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); + + if (key == 2) { + leftTurnHeld = true; + rightTurnHeld = false; + } else if (key == 3) { + rightTurnHeld = true; + leftTurnHeld = false; + } else { + leftTurnHeld = false; + rightTurnHeld = false; + } + } + switch (key) { + case 9: + leftMouseHeld = held; + break; + case 8: + rightMouseHeld = held; + break; + } } - public void playerDefected(EntityPlayerMP player, Team team, Team newTeam) { + /** + * Shoot method called by pressing / holding shoot buttons + */ + public void shoot(boolean secondary) { + DriveableType type = getDriveableType(); + if (seats[0] == null) + return; + + if (type.IT1 && !canFireIT1 && type.weaponType(secondary) == EnumWeaponType.MISSILE) return; + + if (!canFire || (isUnderWater() && !type.worksUnderWater)) return; + + //Check shoot delay + if (getShootDelay(secondary) <= 0) { + //We can shoot, so grab the available shoot points and the weaponType + ArrayList shootPoints = type.shootPoints(secondary); + EnumWeaponType weaponType = type.weaponType(secondary); + //If there are no shoot points, return + if (shootPoints.size() == 0) + return; + //For alternating guns, move on to the next one + int currentGun = getCurrentGun(secondary); + if (type.alternate(secondary)) { + currentGun = (currentGun + 1) % shootPoints.size(); + setCurrentGun(currentGun, secondary); + shootEach(type, shootPoints.get(currentGun), currentGun, secondary, weaponType); + } else for (int i = 0; i < shootPoints.size(); i++) + shootEach(type, shootPoints.get(i), i, secondary, weaponType); + } } - public void playerEnteredTheGame(EntityPlayerMP player, Team team, PlayerClass playerClass) { + public boolean driverIsCreative() { + return seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode; } - //-------------------------------------- - // Helper methods - Do not override - //-------------------------------------- + public void spawnParticle(ArrayList list, ShootPoint shootPoint, Vector3f v) { + for (ShootParticle s : list) { + float bkx = shootPoint.rootPos.position.x; + float bky = shootPoint.rootPos.position.y; + float bkz = shootPoint.rootPos.position.z; + Vector3f velocity = new Vector3f(s.x, s.y, s.z); + //if(shootPoint.rootPos.part == EnumDriveablePart.turret){ + velocity = getDirection(shootPoint, velocity); + //} - public static PlayerData getPlayerData(EntityPlayerMP player) { - return PlayerHandler.getPlayerData(player); + //Vector3f v = getFiringPosition(shootPoint); + + if (shootPoint.rootPos.part == EnumDriveablePart.core) { + Vector3f v2 = axes.findLocalVectorGlobally(shootPoint.rootPos.position); + Vector3f v3 = rotate(seats[0].looking.findLocalVectorGlobally(shootPoint.offPos)); + Vector3f.add(v2, v3, v); + } + + FlansMod.getPacketHandler().sendToAllAround( + new PacketParticle(s.name, posX + v.x, posY + v.y, posZ + v.z, velocity.x, velocity.y, velocity.z), + posX + v.x, posY + v.y, posZ + v.z, 150, dimension); + + shootPoint.rootPos.position.x = bkx; + shootPoint.rootPos.position.y = bky; + shootPoint.rootPos.position.z = bkz; + } } - public static PlayerStats getPlayerInfo(EntityPlayerMP player) { - return PlayerHandler.getPlayerStats(player); + + private void shootEach(DriveableType type, ShootPoint shootPoint, int currentGun, boolean secondary, EnumWeaponType weaponType) { + //Rotate the gun vector to global axes + Vector3f gunVec = getFiringPosition(shootPoint); + Vector3f lookVector = getLookVector(shootPoint); + + if (!secondary && type.fixedPrimaryFire) { + lookVector = axes.findLocalVectorGlobally(type.primaryFireAngle); + if (shootPoint.rootPos.part == EnumDriveablePart.turret) { + lookVector = getPositionOnTurret(type.primaryFireAngle, false); + } + if (shootPoint.rootPos.part == EnumDriveablePart.barrel) { + lookVector = getPositionOnTurret(type.primaryFireAngle, true); + } + } + + if (weaponType == EnumWeaponType.SHELL) + isRecoil = true; + if (shootPoint.rootPos.part == null) return; + if (!isPartIntact(shootPoint.rootPos.part)) return; + + if (disabled) return; + float damageMultiplier = secondary ? type.damageMultiplierSecondary : type.damageMultiplierPrimary; + //If its a pilot gun, then it is using a gun type, so do the following + if (shootPoint.rootPos instanceof PilotGun && ((PilotGun) shootPoint.rootPos).type != null) { + PilotGun pilotGun = (PilotGun) shootPoint.rootPos; + //Get the gun from the plane type and the ammo from the data + GunType gunType = pilotGun.type; + float shellSpeed = gunType.bulletSpeed; + if (type.rangingGun) + shellSpeed = type.bulletSpeed; + ItemStack bulletItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + currentGun]; + //Check that neither is null and that the bullet item is actually a bullet + if (bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable && TeamsManager.bulletsEnabled) { + ShootableType bullet = ((ItemShootable) bulletItemStack.getItem()).type; + if (gunType.isAmmo(bullet)) { + //spawnParticle(gunType, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY,V (float)posZ), null)); + + spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); + //Spawn a new bullet item + worldObj.spawnEntityInWorld(((ItemShootable) bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, gunType.bulletSpread / 2, gunType.damage * damageMultiplier, shellSpeed, bulletItemStack.getItemDamage(), type)); + //Play the shoot sound + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); + //Get the bullet item damage and increment it + int damage = bulletItemStack.getItemDamage(); + bulletItemStack.setItemDamage(damage + 1); + //If the bullet item is completely damaged (empty) + if (damage + 1 == bulletItemStack.getMaxDamage()) { + //Set the damage to 0 and consume one ammo item (unless in creative) + bulletItemStack.setItemDamage(0); + if (!driverIsCreative()) { + bulletItemStack.stackSize--; + if (bulletItemStack.stackSize <= 0) { + onWeaponInventoryChanged(secondary); + bulletItemStack = null; + } + driveableData.setInventorySlotContents(getDriveableType().numPassengerGunners + currentGun, bulletItemStack); + } + } + if (type.shootDelay(secondary) == -1) { + setShootDelay(gunType.getShootDelay(), secondary); + } else { + setShootDelay(type.shootDelay(secondary), secondary); + } + //Reset the shoot delay + } + } + } else //One of the other modes + { + switch (weaponType) { + case BOMB: { + if (TeamsManager.bombsEnabled) { + int slot = -1; + for (int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++) { + ItemStack bomb = driveableData.getStackInSlot(i); + if (bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) bomb.getItem()).type, weaponType)) { + slot = i; + } + } + + if (slot != -1) { + int spread = 0; + float shellSpeed = 0F; + + ItemStack bulletStack = driveableData.getStackInSlot(slot); + ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); + if (shootPoint.rootPos instanceof PilotGun) { + PilotGun pilotGun = (PilotGun) shootPoint.rootPos; + //Get the gun from the plane type and the ammo from the data + GunType gunType = pilotGun.type; + } + + EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vec3.createVectorHelper(gunVec.x + posX, gunVec.y + posY, gunVec.z + posZ), axes.getYaw(), axes.getPitch(), motionX, motionY, motionZ, (EntityLivingBase) seats[0].riddenByEntity, damageMultiplier, driveableData.getStackInSlot(slot).getItemDamage(), type); + worldObj.spawnEntityInWorld(bulletEntity); + + spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); + + + if (type.shootSound(secondary) != null) + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); + if (!driverIsCreative()) { + bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); + if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { + bulletStack.setItemDamage(0); + bulletStack.stackSize--; + if (bulletStack.stackSize == 0) { + onWeaponInventoryChanged(secondary); + bulletStack = null; + } + } + driveableData.setInventorySlotContents(slot, bulletStack); + } + if (type.shootDelay(secondary) == -1) { + setShootDelay(1, secondary); + } else { + setShootDelay(type.shootDelay(secondary), secondary); + } + } + } + break; + } + case MISSILE: //These two are actually almost identical + case SHELL: { + //int numnum = driveableData.getMissileInventoryStart(); + /*ItemStack AmmoPlaced = driveableData.getStackInSlot(1); + if(AmmoPlaced == null && type.enableReloadTime){ + isAmmoPlaced = false; + break; + } + isAmmoPlaced = true; + setShootDelay(type.shootDelay(secondary), secondary);*/ + tryRecoil(); + + if (TeamsManager.shellsEnabled) { + int slot = -1; + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, weaponType)) { + slot = i; + } + } + + if (slot != -1) { + //int spread = 0; + //float shellSpeed = 3F; + float spread = type.bulletSpread; + float shellSpeed = type.bulletSpeed; + ItemStack bulletStack = driveableData.getStackInSlot(slot); + ItemBullet bulletItem = (ItemBullet) bulletStack.getItem(); + EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null), lookVector, (EntityLivingBase) seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); + //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY, (float)posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, bulletStack.getItemDamage(), type); + //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type); + worldObj.spawnEntityInWorld(bulletEntity); //SHELL + spawnParticle(type.shootParticle(secondary), shootPoint, gunVec); + isRecoil = true; + + if (type.shootSound(secondary) != null) + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false); + if (!driverIsCreative()) { + bulletStack.setItemDamage(bulletStack.getItemDamage() + 1); + if (bulletStack.getItemDamage() == bulletStack.getMaxDamage()) { + bulletStack.setItemDamage(0); + bulletStack.stackSize--; + if (bulletStack.stackSize == 0) { + onWeaponInventoryChanged(secondary); + bulletStack = null; + } + } + driveableData.setInventorySlotContents(slot, bulletStack); + } + if (type.shootDelay(secondary) == -1) { + setShootDelay(1, secondary); + } else { + setShootDelay(type.shootDelay(secondary), secondary); + } + canFireIT1 = false; + } + } + break; + } + case GUN: //Handled above + break; + case MINE: + case NONE: + break; + } + } } - public static void sendPacketToPlayer(PacketBase packet, EntityPlayerMP player) { - FlansMod.getPacketHandler().sendTo(packet, player); + public Vector3f getOrigin(ShootPoint dp) { + //Rotate the gun vector to global axes + Vector3f localGunVec = new Vector3f(dp.rootPos.position); + + if (dp.rootPos.part == EnumDriveablePart.turret) { + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); + //Rotate by the turret angles + localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + //Translate by the turret origin + Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); + } + + return rotate(localGunVec); } - public static String[] getPlayerNames() { - return MinecraftServer.getServer().getAllUsernames(); + public Vector3f getPositionOnTurret(Vector3f vecIn, boolean barrel) { + Vector3f transform = vecIn; + RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); + if (barrel) yawOnlyLooking = seats[0].looking; + + //Calculate the root of the gun + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(transform, getDriveableType().turretOrigin, transform); + //Rotate by the turret angles + transform = yawOnlyLooking.findLocalVectorGlobally(transform); + //Translate by the turret origin + Vector3f.add(transform, getDriveableType().turretOrigin, transform); + Vector3f turretOriginOffset = new Vector3f(getDriveableType().turretOriginOffset); + turretOriginOffset = yawOnlyLooking.findLocalVectorGloballyYaw(turretOriginOffset); + Vector3f.add(transform, turretOriginOffset, transform); + + return rotate(transform); } - @SuppressWarnings("unchecked") - public static List getPlayers() { - return MinecraftServer.getServer().getConfigurationManager().playerEntityList; + public Vector3f getDirection(ShootPoint dp, Vector3f vIn) { + //Rotate the gun vector to global axes + Vector3f localGunVec = new Vector3f(vIn); + + //if(dp.rootPos.part == EnumDriveablePart.turret) + //{ + //localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + //} + + localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + + return rotate(localGunVec); } - public static void givePoints(EntityPlayerMP player, int points) { - PlayerData data = getPlayerData(player); - data.score += points; - if (data.team != null) - data.team.score += points; + public Vector3f getLookVector(ShootPoint dp) { + return axes.getXAxis(); } - public static EntityPlayerMP getPlayerFromDamageSource(DamageSource source) { - EntityPlayerMP attacker = null; - if (source instanceof EntityDamageSource) { - if (source.getEntity() instanceof EntityPlayerMP) - attacker = (EntityPlayerMP) source.getEntity(); + public Vector3f getFiringPosition(ShootPoint dp) { + Vector3f rootVector = new Vector3f(dp.rootPos.position); + Vector3f offsetVector = new Vector3f(dp.offPos); + Vector3f localGunVec = new Vector3f(dp.rootPos.position); + + if (dp.rootPos.part == EnumDriveablePart.turret) { + if (offsetVector.x == 0 && offsetVector.y == 0 && offsetVector.z == 0) { + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec); + //Rotate by the turret angles + localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec); + //Translate by the turret origin + Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec); + } else { + RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0); + + //Calculate the root of the gun + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(rootVector, getDriveableType().turretOrigin, rootVector); + //Rotate by the turret angles + rootVector = yawOnlyLooking.findLocalVectorGlobally(rootVector); + //Translate by the turret origin + Vector3f.add(rootVector, getDriveableType().turretOrigin, rootVector); + + //Calculate the tip of the gun + //Untranslate by the turret origin, to get the rotation about the right point + Vector3f.sub(offsetVector, getDriveableType().turretOrigin, offsetVector); + //Rotate by the turret angles + offsetVector = seats[0].looking.findLocalVectorGlobally(offsetVector); + //Translate by the turret origin + + Vector3f.add(rootVector, offsetVector, localGunVec); + } } - return attacker; + + return rotate(localGunVec); } - public EntityPlayerMP getPlayer(String username) { - return MinecraftServer.getServer().getConfigurationManager().func_152612_a(username); + public boolean isEngineActive() { + return (driverIsCreative() || driveableData.fuelInTank > 0) && engineStartDelay == 0 || getDriveableType().fuelTankSize < 0; } - public boolean shouldAutobalance() { - return true; + public void correctWheelPos() { + if (this.ticksExisted % (10 * 20) == 0) { + for (EntityWheel wheel : wheels) { + if (wheel == null) continue; + + Vector3f target = axes.findLocalVectorGlobally(getDriveableType().wheelPositions[wheel.ID].position); + target.x += posX; + target.y += posY; + target.z += posZ; + + int tf = 1; + int cf = 1; + int range = 5; + + if (MathHelper.abs(target.x - (float) wheel.posX) > range) { + wheel.posX = (target.x * tf + (float) wheel.posX * cf) / (tf + cf); + } + if (MathHelper.abs(target.y - (float) wheel.posY) > range) { + wheel.posY = (target.y * tf + (float) wheel.posY * cf) / (tf + cf); + } + if (MathHelper.abs(target.z - (float) wheel.posZ) > range) { + wheel.posZ = (target.z * tf + (float) wheel.posZ * cf) / (tf + cf); + } + } + } } -} + + @Override + public void onUpdate() { + super.onUpdate(); + //playerIDs.clear(); + DriveableType type = getDriveableType(); + DriveableData data = getDriveableData(); + //if(type.fancyCollision) + //checkCollsionBox(); + hugeBoat = (getDriveableType().floatOnWater && getDriveableType().wheelStepHeight == 0); + //hugeBoat = true; + + if (hugeBoat) { + for (int i = 0; i < worldObj.loadedEntityList.size(); i++) { + Object obj = worldObj.loadedEntityList.get(i); + if (obj instanceof EntityPlayer && !isPartOfThis((Entity) obj)) { + moveRiders((Entity) obj); + } + + if (obj instanceof EntityWheel && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { + //moveRiders((Entity)obj); + } + + if (obj instanceof EntityDriveable && !isPartOfThis((Entity) obj) && getDistanceToEntity((Entity) obj) <= getDriveableType().bulletDetectionRadius) { + //moveRiders((Entity)obj); + } + } + } + + onDeck = deckCheck != prevDeckCheck; + + //Aesthetics + if (type.IT1 && !disabled) { + boolean fireButtonHeld = false; + if (type.weaponType(false) == EnumWeaponType.MISSILE) fireButtonHeld = leftMouseHeld; + if (type.weaponType(true) == EnumWeaponType.MISSILE) fireButtonHeld = rightMouseHeld; + + prevDrakonDoorAngle = drakonDoorAngle; + prevDrakonArmAngle = drakonArmAngle; + prevDrakonRailAngle = drakonRailAngle; + if (canFireIT1) reloadingDrakon = false; + if (stage == 0) stage = 1; + + if (stage == 8 && fireButtonHeld) { + stage = 1; + timeTillDeactivate = 5; + toDeactivate = true; + } + if (timeTillDeactivate <= 0 && toDeactivate) { + canFireIT1 = false; + toDeactivate = false; + } + + if (reloadAnimTime <= 0) + IT1Reload(); + + reloadAnimTime--; + timeTillDeactivate--; + } + + //Aesthetics + prevPropAngle = propAngle; + prevRotorAngle = rotorAngle; + if (throttle != 0) { + propAngle += (Math.pow(Math.abs(throttle), 0.4)) * 1.5; + rotorAngle += throttle / 7F; + } + + + //Gun recoil + if (leftMouseHeld && !disabled) { + tryRecoil(); + setRecoilTimer(); + } + lastRecoilPos = recoilPos; + + if (recoilPos > 180 - (180 / type.recoilTime)) { + recoilPos = 0; + isRecoil = false; + } + + if (isRecoil) + recoilPos = recoilPos + (180 / type.recoilTime); + + if (recoilTimer >= 0) + recoilTimer--; + + checkInventoryChanged(); + + if (isUnderWater() && !type.worksUnderWater && !hugeBoat) { + throttle = 0; + //this.driveableData.parts.get(EnumDriveablePart.core).health -= 1; + disabled = true; + } else disabled = false; + + + if (type.lockOnToLivings || type.lockOnToMechas || type.lockOnToPlanes || type.lockOnToPlayers || type.lockOnToVehicles) { + if (!worldObj.isRemote && this.seats.length > 0 && lockOnSoundDelay <= 0) { + if (this.seats[0] != null && this.seats[0].riddenByEntity instanceof EntityPlayer) { + // int currentGun = getCurrentGun(false); + // Vector3f playerVec = getOrigin(type.shootPoints(false).get(currentGun)); + Vector3f playerVecRelToVehicle = seats[0].playerLooking.findGlobalVectorLocally(new Vector3f(-1, 0, 0)); + Vector3f playerVec = axes.findGlobalVectorLocally(playerVecRelToVehicle); + + for (Object obj : worldObj.loadedEntityList) { + Entity entity = (Entity) obj; + if ((type.lockOnToMechas && entity instanceof EntityMecha) || + (type.lockOnToVehicles && entity instanceof EntityVehicle) || + (type.lockOnToPlanes && entity instanceof EntityPlane) || + (type.lockOnToPlayers && entity instanceof EntityPlayer) || + (type.lockOnToLivings && entity instanceof EntityLivingBase)) { + if (getDistanceSqToEntity(entity) < type.maxRangeLockOn * type.maxRangeLockOn) { + // Some heckery with vectors rotating about themselves or something + Vector3f relPosVec = new Vector3f(-entity.posX + seats[0].posX, -entity.posY + seats[0].posY, entity.posZ - seats[0].posZ); + float angle = Math.abs(Vector3f.angle(playerVec, relPosVec)); + if (angle < Math.toRadians(type.canLockOnAngle)) { + PacketPlaySound.sendSoundPacket(seats[0].posX, seats[0].posY, seats[0].posZ, 10, dimension, type.lockOnSound, false); + if (entity instanceof EntityDriveable) + PacketPlaySound.sendSoundPacket(entity.posX, entity.posY, entity.posZ, ((EntityDriveable) entity).getDriveableType().lockedOnSoundRange, entity.dimension, ((EntityDriveable) entity).getDriveableType().lockingOnSound, false); + lockOnSoundDelay = type.lockOnSoundTime; + break; + } + } + } + } + } + } + } + if (lockOnSoundDelay > 0) + lockOnSoundDelay--; + + + if (this.ridingEntity != null) { + invulnerableUnmountCount = 20 * 4; + } else if (invulnerableUnmountCount > 0) { + invulnerableUnmountCount--; + } + + if (!worldObj.isRemote) { + for (int i = 0; i < getDriveableType().numPassengers + 1; i++) { + if (seats[i] == null || !seats[i].addedToChunk) { + seats[i] = new EntitySeat(worldObj, this, i); + worldObj.spawnEntityInWorld(seats[i]); + } + } + for (int i = 0; i < type.wheelPositions.length; i++) { + if (wheels[i] == null || !wheels[i].addedToChunk) { + wheels[i] = new EntityWheel(worldObj, this, i); + worldObj.spawnEntityInWorld(wheels[i]); + } + } + } + + //Harvest stuff + //Aesthetics + if (hasEnoughFuel() && isEngineActive()) { + harvesterAngle += throttle / 5F; + } + //Actual harvesting + if (type.harvestBlocks && type.harvestBoxSize != null && type.harvestBoxPos != null && TeamsManager.driveablesBreakBlocks) { + Vector3f size = new Vector3f(type.harvestBoxSize.x / 16F, type.harvestBoxSize.y / 16F, type.harvestBoxSize.z / 16F); + Vector3f pos = new Vector3f(type.harvestBoxPos.x / 16F, type.harvestBoxPos.y / 16F, type.harvestBoxPos.z / 16F); + for (float x = pos.x; x <= pos.x + size.x; x++) { + for (float y = pos.y; y <= pos.y + size.y; y++) { + for (float z = pos.z; z <= pos.z + size.z; z++) { + Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z)); + + int blockX = (int) Math.round(posX + v.x); + int blockY = (int) Math.round(posY + v.y); + int blockZ = (int) Math.round(posZ + v.z); + Block block = worldObj.getBlock(blockX, blockY, blockZ); + + if (type.materialsHarvested.contains(block.getMaterial()) && block.getBlockHardness(worldObj, blockX, blockY, blockZ) >= 0F) { + if (type.collectHarvest) { + //Add the itemstack to mecha inventory + ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); + for (ItemStack stack : stacks) { + if (!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative()) && !worldObj.isRemote && worldObj.getGameRules().getGameRuleBooleanValue("doTileDrops")) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); + } + } + } else if (type.dropHarvest) { + ArrayList stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0); + for (ItemStack stack : stacks) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack)); + } + } + //Destroy block + worldObj.func_147480_a(blockX, blockY, blockZ, false); + } + } + } + } + } + + /*if(this.isLockedOn && soundTime <= 0 && !this.worldObj.isRemote) + { + PacketPlaySound.sendSoundPacket(posX,posY,posZ, 5, dimension, type.lockedOnSound, false); + soundTime = type.soundTime; + }*/ + + for (DriveablePart part : getDriveableData().parts.values()) { + if (part.box != null) { + + part.update(this); + //Client side particles + if (worldObj.isRemote) { + if (part.onFire) { + //Pick a random position within the bounding box and spawn a flame there + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); + worldObj.spawnParticle("flame", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); + } + if (part.health > 0 && part.health < part.maxHealth / 2) { + //Pick a random position within the bounding box and spawn a flame there + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d)); + worldObj.spawnParticle(part.health < part.maxHealth / 4 ? "largesmoke" : "smoke", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0); + } + } + //Server side fire handling + if (part.onFire) { + //Rain can put out fire + if (worldObj.isRaining() && rand.nextInt(40) == 0) + part.onFire = false; + //Also water blocks + //Get the centre point of the part + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + part.box.w / 2F, part.box.y + part.box.h / 2F, part.box.z + part.box.d / 2F)); + if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.water) { + part.onFire = false; + } + } else { + Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); + if (worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.lava) { + part.onFire = true; + } + } + } + } + + for (int i = 0; i < type.emitters.size(); i++) { + ParticleEmitter emitter = type.emitters.get(i); + emitterTimers[i]--; + boolean canEmit; + boolean inThrottle = false; + DriveablePart part = getDriveableData().parts.get(EnumDriveablePart.getPart(emitter.part)); + float healthPercentage = part.health / part.maxHealth; + canEmit = isPartIntact(EnumDriveablePart.getPart(emitter.part)) && healthPercentage >= emitter.minHealth && healthPercentage <= emitter.maxHealth; + + if ((throttle >= emitter.minThrottle && throttle <= emitter.maxThrottle)) + inThrottle = true; + if (isMecha) + inThrottle = true; + + if (emitterTimers[i] <= 0) { + if (inThrottle && canEmit) { + //Emit! + Vector3f velocity = new Vector3f(0, 0, 0); + + Vector3f pos = new Vector3f(0, 0, 0); + if (seats != null && seats[0] != null) { + if (EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.turret && EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.barrel) { + Vector3f localPosition = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, + emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, + emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); + + pos = axes.findLocalVectorGlobally(localPosition); + velocity = axes.findLocalVectorGlobally(emitter.velocity); + } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.turret || EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.head && !emitter.part.equals("barrel")) { + + Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, + emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, + emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); + pos = getPositionOnTurret(localPosition2, false); + velocity = getPositionOnTurret(emitter.velocity, false); + } else if (EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.barrel) { + Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f, + emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f, + emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f); + + + pos = getPositionOnTurret(localPosition2, true); + velocity = getPositionOnTurret(emitter.velocity, true); + } + //FlansMod.proxy.spawnParticle(emitter.effectType, posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z); + + FlansMod.getPacketHandler().sendToAllAround( + new PacketParticle(emitter.effectType, + posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z), + posX + pos.x, posY + pos.y, posZ + pos.z, 150, dimension); + + } + } + emitterTimers[i] = emitter.emitRate; + } + } + + checkParts(); + + prevRotationYaw = axes.getYaw(); + prevRotationPitch = axes.getPitch(); + prevRotationRoll = axes.getRoll(); + prevAxes = axes.clone(); + + if (riddenByEntity != null && riddenByEntity.isDead) { + riddenByEntity = null; + } + if (riddenByEntity != null && isDead) { + riddenByEntity.mountEntity(null); + } + if (riddenByEntity != null) + riddenByEntity.fallDistance = 0F; + + //If there's no player in the driveable or it cannot thrust, slow the plane and turn off mouse held actions + if ((seats != null && seats[0] != null && seats[0].riddenByEntity == null) || !isEngineActive() && getDriveableType().maxThrottle != 0 && getDriveableType().maxNegativeThrottle != 0) { + throttle *= 0.99F; + } + if (seats != null && seats[0] != null && seats[0].riddenByEntity == null) { + rightMouseHeld = leftMouseHeld = false; + } + + //Check if shooting + if (shootDelayPrimary > 0) + shootDelayPrimary--; + if (shootDelaySecondary > 0) + shootDelaySecondary--; + if (getDriveableType().reloadSoundTick != 15214541 && shootDelayPrimary == getDriveableType().reloadSoundTick) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootReloadSound, false); + } +// on first update + if (this.ticksExisted == 1) { + setShootDelay(getDriveableType().placeTimePrimary, false); + setShootDelay(getDriveableType().placeTimeSecondary, true); + if (!this.worldObj.isRemote) { + if (!getDriveableType().placeSoundPrimary.isEmpty()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().placeSoundPrimary, false); + } + if (!getDriveableType().placeSoundSecondary.isEmpty()) { + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().placeSoundSecondary, false); + } + } + } + if (seats[0] != null && seats[0].riddenByEntity != null && seats[0].riddenByEntity instanceof EntityPlayer && worldObj.isRemote) { + EntityPlayer p = (EntityPlayer) seats[0].riddenByEntity; + if (this.ticksExisted < getDriveableType().placeTimePrimary && (getShootDelay(false) % 100) == 0 ) { + p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use in " + getShootDelay(false)/20 + " seconds.")); + } else if (this.ticksExisted == getDriveableType().placeTimePrimary) { + p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use!")); + } + + if (this.ticksExisted < getDriveableType().placeTimeSecondary && (getShootDelay(true) % 100) == 0) { + p.addChatComponentMessage( + new ChatComponentText("Secondary gun ready to use in " + getShootDelay(true)/20 + " seconds.")); + } else if (this.ticksExisted == getDriveableType().placeTimeSecondary) { + p.addChatComponentMessage(new ChatComponentText("Secondary gun ready to use!")); + } + + if (engineStartDelay > 0 && engineStartDelay % (2.5*20) == 0) { + p.addChatComponentMessage(new ChatComponentText("Engine starting.. " + (float)engineStartDelay/20 + " seconds remaining.")); + } else if (engineStartDelay == 1) { + p.addChatComponentMessage(new ChatComponentText("Engine started!")); + } + } + + if (!worldObj.isRemote) { + if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO) + shoot(false); + if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO) + shoot(true); + minigunSpeedPrimary *= 0.9F; + minigunSpeedSecondary *= 0.9F; + if (leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN) { + minigunSpeedPrimary += 0.1F; + if (minigunSpeedPrimary > 1F) + shoot(false); + } + if (rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN) { + minigunSpeedSecondary += 0.1F; + if (minigunSpeedSecondary > 1F) + shoot(true); + } + } + + prevDeckCheck = deckCheck; + + if (engineStartDelay > 0) { engineStartDelay--; } + //Handle fuel + + int fuelMultiplier = 2; + + //The tank is currently full, so do nothing + if (data.fuelInTank >= type.fuelTankSize) + return; + + //Look through the entire inventory for fuel cans, buildcraft fuel buckets and RedstoneFlux power sources + for (int i = 0; i < data.getSizeInventory(); i++) { + ItemStack stack = data.getStackInSlot(i); + if (stack == null || stack.stackSize <= 0) + continue; + Item item = stack.getItem(); + //If we have an electric engine, look for RedstoneFlux power source items, such as power cubes + if (data.engine.useRFPower) { + if (item instanceof IEnergyContainerItem) { + IEnergyContainerItem energy = (IEnergyContainerItem) item; + data.fuelInTank += (fuelMultiplier * energy.extractEnergy(stack, data.engine.RFDrawRate, false)) / data.engine.RFDrawRate; + } + } else { + //Check for Flan's Mod fuel items + if (item instanceof ItemPart) { + PartType part = ((ItemPart) item).type; + //Check it is a fuel item + if (part.category == 9) { + //Put 2 points of fuel + data.fuelInTank += fuelMultiplier; + + //Damage the fuel item to indicate being used up + int damage = stack.getItemDamage(); + stack.setItemDamage(damage + 1); + + //If we have finished this fuel item + if (damage >= stack.getMaxDamage()) { + //Reset the damage to 0 + stack.setItemDamage(0); + //Consume one item + stack.stackSize--; + //If we consumed the last one, destroy the stack + if (stack.stackSize <= 0) + data.setInventorySlotContents(i, null); + } + + //We found a fuel item and consumed some, so we are done + break; + } + } + //Check for Buildcraft oil and fuel buckets + else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftOilBucket) && data.fuelInTank + 1000 * fuelMultiplier <= type.fuelTankSize) { + data.fuelInTank += 1000 * fuelMultiplier; + data.setInventorySlotContents(i, new ItemStack(Items.bucket)); + } else if (FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftFuelBucket) && data.fuelInTank + 2000 * fuelMultiplier <= type.fuelTankSize) { + data.fuelInTank += 2000 * fuelMultiplier; + data.setInventorySlotContents(i, new ItemStack(Items.bucket)); + } + + prevPosX = posX; + prevPosY = posY; + prevPosZ = posZ; + } + } + } + + public void checkInventoryChanged() { + DriveableType type = getDriveableType(); + if (type == null) return; + + if (worldObj.isRemote) return; + + if (!driveableData.inventoryChanged) return; + + driveableData.inventoryChanged = false; + + try { + for (int ps = 0; ps < 2; ps++) { + EnumWeaponType weaponType = ps == 0 ? type.primary : type.secondary; + if (weaponType == EnumWeaponType.GUN) { + weaponType = EnumWeaponType.NONE; + } + int istart = getInventoryStart(weaponType); + if (istart == driveableData.getAmmoInventoryStart()) { + istart += type.numPassengerGunners; + } + final int isize = getInventorySize(weaponType); + if (istart >= 0 || isize > 0) { + if (prevInventoryItems[ps] == null) { + prevInventoryItems[ps] = new ItemStack[isize]; + } + + for (int i = 0; i < isize; i++) { + ItemStack itemStack = driveableData.getStackInSlot(istart + i); + if (itemStack != null && itemStack.getItem() instanceof ItemBullet) { + if (prevInventoryItems[ps][i] == null || !ItemStack.areItemStacksEqual(itemStack, prevInventoryItems[ps][i])) { + if (type.isValidAmmo(((ItemBullet) itemStack.getItem()).type, weaponType)) { + onWeaponInventoryChanged(ps == 1); + break; + } + } + } + } + + for (int i = 0; i < isize; i++) { + prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void onWeaponInventoryChanged(boolean secondary) { + DriveableType type = getDriveableType(); + if (!secondary) { + if (type.reloadTimePrimary > 0 && getShootDelay(secondary) <= 0) { + setShootDelay(type.reloadTimePrimary, secondary); + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().reloadSoundPrimary, false); + } + } else { + if (type.reloadTimeSecondary > 0 && getShootDelay(secondary) <= 0) { + setShootDelay(type.reloadTimeSecondary, secondary); + PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, + getDriveableType().reloadSoundSecondary, false); + } + } + } + + public int getInventoryStart(EnumWeaponType wt) { + switch (wt) { + case NONE: + case GUN: + return driveableData.getAmmoInventoryStart(); + + case MISSILE: + case SHELL: + return driveableData.getMissileInventoryStart(); + + case BOMB: + case MINE: + return driveableData.getBombInventoryStart(); + + default: + break; + } + return -1; + } + + public int getInventorySize(EnumWeaponType wt) { + switch (wt) { + case NONE: + case GUN: + return driveableData.ammo.length; + + case MISSILE: + case SHELL: + return driveableData.missiles.length; + + case BOMB: + case MINE: + return driveableData.bombs.length; + + default: + break; + } + return -1; + } + + public void checkForCollisions() { + boolean damagePart = false; + boolean crashInWater = false; + double speed = getSpeedXYZ(); + for (DriveablePosition p : getDriveableType().collisionPoints) { + if (driveableData.parts.get(p.part).dead) + continue; + Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position); + Vec3 lastPos = Vec3.createVectorHelper(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z); + + Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position); + Vec3 currentPos = Vec3.createVectorHelper(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z); + + if (FlansMod.DEBUG && worldObj.isRemote) { + worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F)); + } + + MovingObjectPosition hit = worldObj.rayTraceBlocks(lastPos, currentPos, crashInWater); + if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { + int x = hit.blockX; + int y = hit.blockY; + int z = hit.blockZ; + Block blockHit = worldObj.getBlock(x, y, z); + int meta = worldObj.getBlockMetadata(x, y, z); + + float blockHardness = blockHit.getBlockHardness(worldObj, x, y, z); + + float damage = 0; + if (blockHardness > 0.2) { + damage = blockHardness * blockHardness * (float) speed; + } + + if (null == blockHit.getCollisionBoundingBoxFromPool(this.worldObj, x, y, z)) { + damage = 0; + } + + if (damage > 0) { + damagePart = true; + if (!attackPart(p.part, DamageSource.inWall, damage) && TeamsManager.driveablesBreakBlocks) { + // And if it didn't die from the attack, break the block + worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(blockHit) + (meta << 12)); + + if (!worldObj.isRemote) { + blockHit.dropBlockAsItem(worldObj, x, y, z, meta, 1); + worldObj.setBlockToAir(x, y, z); + } + } else { + // The part died! + worldObj.createExplosion(this, currentPos.xCoord, currentPos.yCoord, currentPos.zCoord, 1F, + false); + } + } + } + + } + + if (FlansMod.seatCollisions) { + // This is for preventing vehicle glitching. It makes seats collideable, and stops their motion if + for (EntitySeat seat : seats) { + if (seat == null || wheels == null ||wheels[0] == null || wheels[1] == null || seat.riddenByEntity == null) + continue; + DriveablePosition p = seat.getAsDriveablePosition(); + if (driveableData.parts.get(p.part).dead) + continue; + Vector3f fwd = axes.getXAxis(); + float a = 0F; + if (getSpeedXZ() > 1) { + if (getSpeedXZ() > 2) { + a = 6F; + } else { + a = 3F; + } + } + + double checkY = Math.max((wheels[0].posY + wheels[1].posY)/2F + (this instanceof EntityVehicle ? 1.5 : 0), seat.posY); + Vec3 seatPos = Vec3.createVectorHelper(seat.posX + fwd.x * a, checkY + fwd.y * a, seat.posZ + fwd.z * a); + Vec3 wheelMidPos = Vec3.createVectorHelper((wheels[0].posX + wheels[1].posX)/2F, checkY, (wheels[0].posZ + wheels[1].posZ)/2F); + + MovingObjectPosition hit = worldObj.rayTraceBlocks(seatPos, wheelMidPos, crashInWater); + if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { + int x = hit.blockX; + int y = hit.blockY; + int z = hit.blockZ; + Block blockHit = worldObj.getBlock(x, y, z); + + collisionHardness = blockHit.getBlockHardness(worldObj, x, y, z); + } + } + } + + if (damagePart) { + //This is server side bsns + if (!worldObj.isRemote) { +// checkParts(); + //If it hit, send a damage update packet + FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); + } + } + } + + @Override + protected void fall(float k) { + double fallDist = ((this.posY - this.prevPosY) + this.motionY) / 2; + float damage = (float) (fallDist < -0.3 ? -fallDist * 50 : 0); + + boolean noDamage = true; + if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20) { + DriveableType type = getDriveableType(); + damage = (int) (damage * type.fallDamageFactor); + attackPart(EnumDriveablePart.core, DamageSource.fall, damage); + if (type.wheelPositions.length > 0) { + attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5); + } + + noDamage = false; + } + // FlansMod.log("fall%s : tick=%d damage=%.1f, posY-prevPosY=%.3f, mY=%.3f, fallDist=%.2f", + // noDamage? " no damage":"", this.ticksExisted, damage, this.posY - this.prevPosY, + // this.motionY, fallDist); + } + + /** + * Attack a certain part of a driveable and return whether it broke or not + */ + public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage) { + if (ep == EnumDriveablePart.core) { + if (source.getSourceOfDamage() instanceof EntityLivingBase) { + this.lastAtkEntity = source.getSourceOfDamage(); + } else if (source.getEntity() instanceof EntityLivingBase) { + this.lastAtkEntity = source.getEntity(); + } else { + this.lastAtkEntity = null; + } + } + DriveablePart part = driveableData.parts.get(ep); + // FlansMod.log("EntityDriveable.attackPart %s : %s : damage=%.1f : %s : health=%d", ep.name(), ep.getName(), damage, + // part.type.name(), part.health); + return part.attack(damage, source.isFireDamage()); + } + + /** + * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates + */ + public Vector3f rotate(Vector3f inVec) { + return axes.findLocalVectorGlobally(inVec); + } + + /** + * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates + */ + public Vector3f rotate(Vec3 inVec) { + return rotate(inVec.xCoord, inVec.yCoord, inVec.zCoord); + } + + /** + * Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates + */ + public Vector3f rotate(double x, double y, double z) { + return rotate(new Vector3f((float) x, (float) y, (float) z)); + } + + //Rotate the plane locally by some angle about the yaw axis + public void rotateYaw(float rotateBy) { + if (Math.abs(rotateBy) < 0.01F) + return; + axes.rotateLocalYaw(rotateBy); + updatePrevAngles(); + } + + //Rotate the plane locally by some angle about the pitch axis + public void rotatePitch(float rotateBy) { + if (Math.abs(rotateBy) < 0.01F) + return; + axes.rotateLocalPitch(rotateBy); + updatePrevAngles(); + } + + //Rotate the plane locally by some angle about the roll axis + public void rotateRoll(float rotateBy) { + if (Math.abs(rotateBy) < 0.01F) + return; + axes.rotateLocalRoll(rotateBy); + updatePrevAngles(); + } + + public void updatePrevAngles() { + //Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick. + double dYaw = axes.getYaw() - prevRotationYaw; + if (dYaw > 180) + prevRotationYaw += 360F; + if (dYaw < -180) + prevRotationYaw -= 360F; + + double dPitch = axes.getPitch() - prevRotationPitch; + if (dPitch > 180) + prevRotationPitch += 360F; + if (dPitch < -180) + prevRotationPitch -= 360F; + + double dRoll = axes.getRoll() - prevRotationRoll; + if (dRoll > 180) + prevRotationRoll += 360F; + if (dRoll < -180) + prevRotationRoll -= 360F; + } + + public void setRotation(float rotYaw, float rotPitch, float rotRoll) { + axes.setAngles(rotYaw, rotPitch, rotRoll); + } + + //Used to stop self collision + public boolean isPartOfThis(Entity ent) { + for (EntitySeat seat : seats) { + if (seat == null) + continue; + if (ent == seat) + return true; + if (seat.riddenByEntity == ent) + return true; + } + return ent == this; + } + + @Override + public float getShadowSize() { + return 0.0F; + } + + public DriveableType getDriveableType() { + return DriveableType.getDriveable(driveableType); + } + + public DriveableData getDriveableData() { + return driveableData; + } + + @Override + public boolean isDead() { + return isDead; + } + + @Override + public Entity getControllingEntity() { + return seats[0].getControllingEntity(); + } + + @Override + public ItemStack getPickedResult(MovingObjectPosition target) { + ItemStack stack = new ItemStack(getDriveableType().item, 1, 0); + stack.stackTagCompound = new NBTTagCompound(); + driveableData.writeToNBT(stack.stackTagCompound); + return stack; + } + + public boolean hasEnoughFuel() { + //if (seats == null || seats[0] == null || seats[0].riddenByEntity == null) + //return false; + return driverIsCreative() || driveableData.fuelInTank > Math.abs(driveableData.engine.fuelConsumption * throttle) || getDriveableType().fuelTankSize < 0; + } + + //Physics time! Oooh yeah + + public double getSpeedXYZ() { + return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ); + } + + public double getSpeedXZ() { + return Math.sqrt(motionX * motionX + motionZ * motionZ); + } + + public double getHackySpeedXYZ() { + double dx = (posX - lastTickPosX); + double dy = (posY - lastTickPosY); + double dz = (posZ - lastTickPosZ); + return Math.sqrt(dx * dx + dy * dy + dz * dz); + // Blocks per tick. + } + + /** + * To be overriden by vehicles to get alternate collision system + */ + public boolean landVehicle() { + return false; + } + + /** + * Overriden by planes for wheel parts + */ + public boolean gearDown() { + return true; + } + + /** + * Whether or not the plane is on the ground + * TODO : Replace with proper check based on wheels + */ + public boolean onGround() { + return onGround; + } + + + //Collision mechanism mkII + @SuppressWarnings("unused") + public void moveRiders(Entity rider) { + if (isPartOfThis(rider)) return; + boolean isHuman = false; + boolean isDriveable = false; + if (!(rider instanceof EntityPlayer)) return; + + + Vector3f riderPos = new Vector3f(rider.posX, rider.posY, rider.posZ); + Vector3f riderMotion = new Vector3f(rider.motionX, rider.motionY, rider.motionY); + Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); + if (rider instanceof EntityVehicle) vehicleMotion = ((EntityVehicle) rider).lastPos; + //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); + Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); + Vector3f relativePos = Vector3f.sub(riderPos, vehiclePos, null); + if (rider instanceof EntityPlayer) isHuman = true; + if (rider instanceof EntityDriveable) isDriveable = true; + relativePos = new Vector3f(relativePos.x, relativePos.y - ((isHuman) ? 0.55F : 0), relativePos.z); + + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); + Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(riderMotion); + + Vector3f ellipsoid = new Vector3f(rider.width / 2, rider.height, rider.width / 2); + + CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), riderMotion); + test.collisionRecursiveDepth = 0; + + Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); + Vector3f eSpaceVelocity = test.velocity; + + //Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); + DriveableType type = getDriveableType(); + //Check parts for collision + if (type.fancyCollision) { + //checkCollision(test, getDriveableType().colbox); + for (CollisionShapeBox sbox : type.collisionBox) { + checkCollision(test, sbox); + } + } else { + for (DriveablePart ppart : getDriveableData().parts.values()) { + ppart.rayTraceRider(this, test); + } + } + + if (test.didCollide) { + Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity); + + if (finalPos == null) { + finalPos = new Vector3f(0, 0, 0); + if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [1]"); + } + + Vector3f velocity = Vector3f.sub(finalPos, test.basePoint, null); + test.ConvertESpaceToR3(velocity); + finalPos = new Vector3f(finalPos.x * test.eRad.x, finalPos.y * test.eRad.y, finalPos.z * test.eRad.z); + // TODO: Better way to check this + if (finalPos == null) { + finalPos = new Vector3f(0, 0, 0); + if (FlansMod.debugMode) FlansMod.log("EntityDriveable.java moveRiders> finalPos is null [2]"); + } + Vector3f diff = Vector3f.sub(finalPos, vehiclePos, null); + + + if (rider.onGround && (posY + finalPos.y + 10 / 16F) < riderPos.y) { + //finalPos = new Vector3f(finalPos.x, 0, finalPos.z); + } + //boolean onTop = (rider.posY + 0.65 > test.intersectionPoint.y); + + boolean stationary = (throttle == 0); + + //If finalPos returns null, do something about it. Probably not the best way to handle this. + //if(finalPos == null) finalPos = new Vector3f(0,0,0); + + test.ConvertESpaceToR3(finalPos); + boolean onTop = (test.collisionPlaneNormal.y >= 0.5F); + if (posY + finalPos.y + 10 / 16F < riderPos.y) finalPos.y = (riderPos.y - (float) posY - 10F / 16F); + if (!hugeBoat) + rider.setPosition((!onTop) ? riderPos.x + finalPos.x / (48 * Math.abs(relativePos.x)) : riderPos.x, (onTop) ? posY + finalPos.y + 10 / 16F : riderPos.y, (!onTop) ? riderPos.z + finalPos.z / (48 * Math.abs(relativePos.z)) : riderPos.z); + //test.ConvertESpaceToR3(test.intersectionPoint); + //FlansMod.proxy.spawnParticle("flame", test.intersectionPoint.x + posX, test.intersectionPoint.y + posY - 1, test.intersectionPoint.z + posZ, 0, 0, 0); + + if (hugeBoat && !stationary) { + rider.setPosition(riderPos.x, posY + finalPos.y + 9.5 / 16F, riderPos.z); + } else if (hugeBoat && stationary) { + rider.setPosition(riderPos.x, posY + finalPos.y + 10 / 16F, riderPos.z); + } + finalPos = Vector3f.sub(finalPos, riderPos, null); + finalPos.normalise(); + + //rider.motionX = rider.motionX * finalPos.x; + rider.motionY = 0; + //rider.motionZ = rider.motionZ * finalPos.z; + + + //Vector3f intersect = test.intersectionPoint; + //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX + intersect.x, posY + intersect.y, posZ + intersect.z, 0,1,0); + //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX, posY, posZ, 0,1,0); + //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", riderPos.x, riderPos.y, riderPos.z, 0,1,0); + + //worldObj.spawnParticle("crit", posX + finalPos.x, posY + finalPos.y, posZ + finalPos.z, 0,0,0); + //worldObj.spawnParticle("reddust", riderPos.x, riderPos.y - 0.65, riderPos.z, 0,0,0); + + + updateRiderPos(rider, test, finalPos, riderMotion); + + if (getDriveableType().collisionDamageEnable && !test.isOnTop) { + if (throttle > getDriveableType().collisionDamageThrottle) { + boolean canDamage = true; + if (TeamsManager.getInstance() != null && TeamsManager.getInstance().currentRound != null && rider instanceof EntityPlayerMP && seats[0].riddenByEntity instanceof EntityPlayer) { + EntityPlayerMP attacker = (EntityPlayerMP) seats[0].riddenByEntity; + EntityPlayerMP player = (EntityPlayerMP) rider; + if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team != null) { + if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team != null) { + if (TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team == TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team) { + canDamage = false; + } + } + } + } + for (EntitySeat seat : seats) { + if (rider == seat.lastRiddenByEntity) { + canDamage = false; + break; + } + } + + if (canDamage) { + if (rider instanceof EntityLiving) { + rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } else if (rider instanceof EntityPlayer) { + rider.attackEntityFrom(DamageSource.generic, throttle * getDriveableType().collisionDamageTimes); + } + } + } + } + if (rider instanceof EntityPlayer) { + EntityPlayer player = (EntityPlayer) rider; + //playerIDs.add(player); + player.onGround = true; + player.isAirBorne = false; + player.fallDistance = 0; + } + + } else { + if (rider instanceof EntityDriveable) { + //((EntityDriveable)rider).onDeck = false; + ((EntityDriveable) rider).deckHeight = 0; + } + } + + + } + + /** + * @SubscribeEvent public void updateRiders(LivingUpdateEvent event){ + *

+ * for(EntityPlayer player: playerIDs){ + * Entity p = (Entity)player; + * if(p == event.entity){ + * player.onGround = true; + * player.isAirBorne = false; + * player.fallDistance = 0; + * playerIDs.remove(player); + * } + * } + * } + */ + + public DamageSource getBulletDamage(boolean headshot) { + DriveableType type = getDriveableType(); + EntityLivingBase owner = (EntityLivingBase) seats[0].riddenByEntity; + if (owner instanceof EntityPlayer) + return (new EntityDamageSourceFlans(getDriveableType().shortName, this, (EntityPlayer) owner, type, headshot, false)).setProjectile(); + else return (new EntityDamageSourceIndirect(type.shortName, this, owner)).setProjectile(); + } + + public void checkCollision(CollisionTest tester, CollisionShapeBox box) { + { + double distance = tester.nearestDistance; + Vector3f collisionPoint = new Vector3f(0, 0, 0); + int surface = 0; + + Vector3f pos = new Vector3f(this.posX, this.posY, this.posZ); + + RotatedAxes shift = axes; + + float f4 = box.pos.x + box.size.x; + float f5 = -box.pos.y + box.size.y; + float f6 = box.pos.z + box.size.z; + + box.pos = new Vector3f(box.pos.x, box.pos.y, box.pos.z); + //if(EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret) return; + //Define box verticies, where z > 0 is right. See shapeboxes in the toolbox for a visual reference + Vector3f p1 = new Vector3f(box.pos.x - box.p1.x, box.pos.y + box.size.y + box.p1.y - box.size.y + 0.625F, box.pos.z - box.p1.z); + Vector3f p2 = new Vector3f(box.pos.x + box.size.x + box.p2.x, box.pos.y + box.size.y + box.p2.y - box.size.y + 0.625F, box.pos.z - box.p2.z); + Vector3f p3 = new Vector3f(box.pos.x + box.size.x + box.p3.x, box.pos.y + box.size.y + box.p3.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p3.z); + Vector3f p4 = new Vector3f(box.pos.x - box.p4.x, box.pos.y + box.size.y + box.p4.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p4.z); + Vector3f p5 = new Vector3f(box.pos.x - box.p5.x, box.pos.y - box.p5.y - box.size.y + 0.625F, box.pos.z - box.p5.z); + Vector3f p6 = new Vector3f(box.pos.x + box.size.x + box.p6.x, box.pos.y - box.p6.y - box.size.y + 0.625F, box.pos.z - box.p6.z); + Vector3f p7 = new Vector3f(box.pos.x + box.size.x + box.p7.x, box.pos.y - box.p7.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p7.z); + Vector3f p8 = new Vector3f(box.pos.x - box.p8.x, box.pos.y - box.p8.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p8.z); + + if (EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret && seats[0] != null) { + p1 = getPositionOnTurret(p1, false); //Front upper left + p2 = getPositionOnTurret(p2, false); //Front upper right + p3 = getPositionOnTurret(p3, false); //Rear upper right + p4 = getPositionOnTurret(p4, false); //Rear upper left + p5 = getPositionOnTurret(p5, false); //Front lower left + p6 = getPositionOnTurret(p6, false); //Front lower right + p7 = getPositionOnTurret(p7, false); //Rear lower right + p8 = getPositionOnTurret(p8, false); //Rear lower left + } else { + p1 = shift.findLocalVectorGlobally(p1); + p2 = shift.findLocalVectorGlobally(p2); + p3 = shift.findLocalVectorGlobally(p3); + p4 = shift.findLocalVectorGlobally(p4); + p5 = shift.findLocalVectorGlobally(p5); + p6 = shift.findLocalVectorGlobally(p6); + p7 = shift.findLocalVectorGlobally(p7); + p8 = shift.findLocalVectorGlobally(p8); + } + + + //Check top face + double topFaceDist = 100; + + tester.checkTriangle(tester, p3, p2, p1); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); + } + + tester.checkTriangle(tester, p4, p3, p1); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); + } + + if (tester.didCollide) { + tester.isOnTop = true; + topFaceDist = tester.nearestDistance; + } + + //Check front face + tester.checkTriangle(tester, p6, p7, p3); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 2; + tester.part = EnumDriveablePart.getPart(box.part); + } + tester.checkTriangle(tester, p3, p2, p6); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 2; + tester.part = EnumDriveablePart.getPart(box.part); + } + + + //Check rear face + tester.checkTriangle(tester, p4, p1, p5); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 3; + tester.part = EnumDriveablePart.getPart(box.part); + } + tester.checkTriangle(tester, p5, p8, p4); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 3; + tester.part = EnumDriveablePart.getPart(box.part); + } + + //Check Left Face + tester.checkTriangle(tester, p6, p5, p1); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 4; + tester.part = EnumDriveablePart.getPart(box.part); + } + tester.checkTriangle(tester, p1, p2, p6); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 4; + tester.part = EnumDriveablePart.getPart(box.part); + } + + //Check right face + tester.checkTriangle(tester, p8, p7, p3); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 5; + tester.part = EnumDriveablePart.getPart(box.part); + } + tester.checkTriangle(tester, p3, p4, p8); + if (tester.didCollide && tester.nearestDistance < distance) { + distance = tester.nearestDistance; + collisionPoint = tester.intersectionPoint; + surface = 5; + tester.part = EnumDriveablePart.getPart(box.part); + } + + //Check bottom face + tester.checkTriangle(tester, p5, p6, p7); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); + } + + tester.checkTriangle(tester, p8, p7, p5); + if (tester.didCollide && tester.nearestDistance < distance) { + collisionPoint = tester.intersectionPoint; + surface = 1; + tester.part = EnumDriveablePart.getPart(box.part); + } + + if (tester.didCollide) { + tester.isOnTop = true; + topFaceDist = tester.nearestDistance; + } + + Vector3f.add(p1, pos, p1); + Vector3f.add(p2, pos, p2); + Vector3f.add(p3, pos, p3); + Vector3f.add(p4, pos, p4); + Vector3f.add(p5, pos, p5); + Vector3f.add(p6, pos, p6); + Vector3f.add(p7, pos, p7); + Vector3f.add(p8, pos, p8); + + String particleType = "crit"; + + + if (FlansMod.DEBUG) { + FlansMod.proxy.spawnParticle(particleType, p1.x, p1.y, p1.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p2.x, p2.y, p2.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p3.x, p3.y, p3.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p4.x, p4.y, p4.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p5.x, p5.y, p5.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p6.x, p6.y, p6.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p7.x, p7.y, p7.z, 0, 0, 0); + FlansMod.proxy.spawnParticle(particleType, p8.x, p8.y, p8.z, 0, 0, 0); + + renderTri(p1, p2, p3); + renderTri(p3, p4, p1); + } + + if (tester.nearestDistance < topFaceDist) tester.isOnTop = false; + + + if (surface == 1) tester.isOnTop = true; + } + + } + + public void renderTri(Vector3f p1, Vector3f p2, Vector3f p3) { + Vector3f pos = new Vector3f(posX, posY, posZ); + Vector3f p1a = Vector3f.add(p1, pos, null); + Vector3f p2a = Vector3f.add(p2, pos, null); + Vector3f p3a = Vector3f.add(p3, pos, null); + + renderLine(p1a, p2a); + renderLine(p2a, p3a); + renderLine(p3a, p1a); + } + + public void renderLine(Vector3f in, Vector3f out) { + float dx = out.x - in.x; + float dy = out.y - in.y; + float dz = out.z - in.z; + Vector3f diff = Vector3f.sub(out, in, null); + diff.normalise(); + float distance = (float) Math.sqrt((dx * dx) + (dy * dy) + (dz * dz)); + for (int i = 0; i < 10; i++) { + float dist2 = (distance / 10) * i; + Vector3f newVec = new Vector3f(in.x + (dist2 * diff.x), in.y + (dist2 * diff.y), in.z + (dist2 * diff.z)); + FlansMod.proxy.spawnParticle("reddust", newVec.x, newVec.y, newVec.z, 0, 0, 0); + } + } + + + public Vector3f collideWithDriveable(CollisionTest tester, Vector3f Pos, Vector3f vel) { + float unitScale = 1 / 16F; + float veryCloseDistance = 0.005F * unitScale; + + if (tester.collisionRecursiveDepth > 2) return Pos; + + tester.basePoint = Pos; + tester.didCollide = false; + + if (getDriveableType().fancyCollision) { + //checkCollision(tester, getDriveableType().colbox); + for (CollisionShapeBox sbox : getDriveableType().collisionBox) { + checkCollision(tester, sbox); + } + } else { + for (DriveablePart ppart : getDriveableData().parts.values()) { + ppart.rayTraceRider(this, tester); + } + } + + //If no collision, we just move along the velocity + if (tester.didCollide = false) return Vector3f.add(Pos, vel, null); + + + //Collision occurred, time to sort this out + Vector3f destinationPoint = Vector3f.add(Pos, vel, null); + Vector3f newBasePoint = Pos; + + if (tester.nearestDistance >= veryCloseDistance) { + vel.normalise(); + vel.scale((float) (tester.nearestDistance - veryCloseDistance)); + newBasePoint = Vector3f.add(tester.basePoint, vel, null); + + if (vel.normalise().equals(new Vector3f(0, 0, 0))) return Vector3f.add(Pos, vel, null); + + vel.normalise(); + + //Change polygon intersection point so that the sliding plane is unaffected by the fact we move slightly less than collision tells us + Vector3f.sub(tester.intersectionPoint, new Vector3f(vel.x * veryCloseDistance, vel.y * veryCloseDistance, vel.z * veryCloseDistance), tester.intersectionPoint); + } + + //Determine the sliding plane + Vector3f slidePlaneOrigin = tester.intersectionPoint; + if (tester.intersectionPoint == null) return Vector3f.add(Pos, vel, null); + Vector3f slidePlaneNormal = Vector3f.sub(newBasePoint, tester.intersectionPoint, null); + slidePlaneNormal.normalise(); + + tester.collisionPlaneNormal = slidePlaneNormal; + CollisionPlane plane = new CollisionPlane(slidePlaneOrigin, slidePlaneNormal); + + double sDV = plane.signedDistanceTo(destinationPoint); + Vector3f scaledNormal = new Vector3f(slidePlaneNormal.x * sDV, slidePlaneNormal.y * sDV, slidePlaneNormal.z * sDV); + Vector3f newDestPoint = Vector3f.sub(destinationPoint, scaledNormal, null); + + //Generate slide vector + Vector3f newVelocityVector = Vector3f.sub(newDestPoint, tester.intersectionPoint, null); + + if (newVelocityVector.length() < veryCloseDistance) { + return newBasePoint; + } + + tester.collisionRecursiveDepth++; + + return collideWithDriveable(tester, newBasePoint, newVelocityVector); + } + + @SuppressWarnings("unused") + public void updateRiderPos(Entity rider, CollisionTest test, Vector3f pos, Vector3f motion) { + boolean isDriveable = rider instanceof EntityDriveable; + Vector3f vehicleMotion = lastPos; + + Vector3f riderMountPoint = new Vector3f(rider.posX - posX, rider.posY - posY, rider.posZ - posZ); + + float yawDiff = axes.getYaw() - prevAxes.getYaw(); + float pitchDiff = axes.getPitch() - prevAxes.getPitch(); + float rollDiff = axes.getRoll() - prevAxes.getRoll(); + + RotatedAxes velAxes = new RotatedAxes(axes.getYaw() + yawDiff, axes.getPitch() + pitchDiff, axes.getRoll() + rollDiff); + + Vector3f currentLocalPos = axes.findGlobalVectorLocally(riderMountPoint); + Vector3f nextGlobalPos = velAxes.findLocalVectorGlobally(currentLocalPos); + + Vector3f diff = new Vector3f(0, 0, 0); + + //Some rubbish null checks + if (nextGlobalPos == null) nextGlobalPos = new Vector3f(0, 0, 0); + + Vector3f.add(vehicleMotion, diff, diff); + rider.setPosition(nextGlobalPos.x + posX + ((hugeBoat) ? diff.x / (1.5) : 0), (!isDriveable) ? rider.posY : ((EntityDriveable) rider).deckHeight, nextGlobalPos.z + posZ + ((hugeBoat) ? diff.z / (1.5) : 0)); + + + if (hugeBoat) { + if (lastPos.x == 0 && lastPos.y == 0 && lastPos.z == 0) { + if (rider.motionY < 0) rider.motionY = 0; + } + } else { + if (lastPos.x != 0 || lastPos.y != 0 || lastPos.z != 0) { + rider.motionX = diff.x; + rider.motionY = diff.y; + rider.motionZ = diff.z; + } + } + } + + /** + * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit + */ + public ArrayList attackFromBullet(Vector3f origin, Vector3f motion) { + //Make an array to contain the hits + ArrayList hits = new ArrayList(); + //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates + Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); + Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); + //Check each part + for (DriveablePart part : getDriveableData().parts.values()) { + //Ray trace the bullet + DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector); + if (hit != null) + hits.add(hit); + } + return hits; + } + + /** + * Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit + */ + public ArrayList attackFromBulletButBetter(Vector3f origin, Vector3f motion, float size) { + ArrayList hits = new ArrayList(); + + + Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z); + //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion); + Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ); + Vector3f relativePos = Vector3f.sub(origin, vehiclePos, null); + + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos); + Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(motion); + + Vector3f ellipsoid = new Vector3f(size, size, size); + + CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), motion); + test.collisionRecursiveDepth = 0; + + Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position); + Vector3f eSpaceVelocity = test.velocity; + + for (DriveablePart ppart : getDriveableData().parts.values()) { + ppart.rayTraceRider(this, test); + } + + if (test.didCollide) { + Vector3f hitPos = new Vector3f(0, 0, 0); + Vector3f intersect2 = new Vector3f(test.ConvertESpaceToR3(test.intersectionPoint)); + Vector3f.sub(origin, intersect2, hitPos); + float f = (hitPos.length() / motion.length()); + DriveableHit hit = new DriveableHit(this, test.part, f); + hits.add(hit); + } + + return hits; + + } + + /** + * Called if the bullet actually hit the part returned by the raytrace + * + * @param penetratingPower + */ + public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower) { + DriveablePart part = getDriveableData().parts.get(hit.part); + if (bullet != null) + penetratingPower = part.hitByBullet(bullet, hit, penetratingPower); + else + penetratingPower -= 5F; + + //This is server side bsns + if (!worldObj.isRemote) { + checkParts(); + //If it hit, send a damage update packet + if(part.type.equals(EnumDriveablePart.core) && part.dead){ + if(TeamsManager.instance.currentRound!=null) + TeamsManager.instance.currentRound.gametype.vehicleDestroyed(part.owner, bullet); + } + FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); + } + + return penetratingPower; + } + + /** + * A simple raytracer for the driveable. Called by tools + */ + public DriveablePart raytraceParts(Vector3f origin, Vector3f motion) { + //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates + Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float) posX, (float) posY, (float) posZ), null); + Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector); + Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion); + //Check each part + for (DriveablePart part : getDriveableData().parts.values()) { + //Ray trace the bullet + if (part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null) { + return part; + } + } + return null; + } + + /** + * For overriding for toggles such as gear up / down on planes + */ + public boolean canHitPart(EnumDriveablePart part) { + return true; + } + + /** + * Internal method for checking that all parts are ok, destroying broken ones, dropping items and making sure that child parts are destroyed when their parents are + */ + public void checkParts() { + for (DriveablePart part : getDriveableData().parts.values()) { + if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { + killPart(part); + } + } + + //If the core was destroyed, kill the driveable + if (getDriveableData().parts.get(EnumDriveablePart.core).dead) { + int seatNum = seats.length; + + DriveableType type = getDriveableType(); + + if (!worldObj.isRemote) { + for (EntitySeat seat : seats) { + if (seat.riddenByEntity instanceof EntityPlayer) { +// ((EntityPlayer)seats[i].riddenByEntity).addPotionEffect(new PotionEffect(Potion.harm.id, 10, 5)); + Entity entity = seat.riddenByEntity; + seat.riddenByEntity.setInvisible(false); + seat.riddenByEntity.mountEntity(null); + if (this.lastAtkEntity instanceof EntityPlayer) { + entity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) this.lastAtkEntity), 10000000); + } else if (this.lastAtkEntity instanceof EntityLivingBase) { + entity.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) this.lastAtkEntity), 10000000); + } + } + } + + if (type.isExplosionWhenDestroyed) +//Create a flans mod explosion rather than a standard MC one. allows control over death boom + { + new FlansModExplosion(worldObj, this, null, type, posX, posY, posZ, + type.deathExplosionRadius, type.deathExplosionPower,TeamsManager.explosions && type.deathExplosionBreaksBlocks, + type.deathExplosionDamageVsLiving, type.deathExplosionDamageVsPlayer, type.deathExplosionDamageVsPlane, type.deathExplosionDamageVsVehicle, seatNum, seatNum); + + } + if(!worldObj.isRemote && type.deathFireRadius > 0.1F) + { + for(float i = -type.deathFireRadius; i < type.deathFireRadius; i++) + { + for(float j = -type.deathFireRadius; j < type.deathFireRadius; j++) + { + for(float k = -type.deathFireRadius; k < type.deathFireRadius; k++) + { + int x = MathHelper.floor_double(i + posX); + int y = MathHelper.floor_double(j + posY); + int z = MathHelper.floor_double(k + posZ); + if(i * i + j * j + k * k <= type.deathFireRadius * type.deathFireRadius && worldObj.getBlock(x, y, z) == Blocks.air && rand.nextBoolean()) + { + worldObj.setBlock(x, y, z, Blocks.fire, 0, 3); + } + } + } + } + } + + for (DriveablePart part : driveableData.parts.values()) { + if (part.health > 0 && !part.dead) + killPart(part); + } + } + setDead(); + + } + + } + + public void checkPartsWhenAttacked() { + for (DriveablePart part : getDriveableData().parts.values()) { + if (part != null && !part.dead && part.health <= 0 && part.maxHealth > 0) { + killPart(part); + } + } + } + + /** + * Internal method for killing driveable parts + */ + private void killPart(DriveablePart part) { + if (part.dead) + return; + part.health = 0; + part.dead = true; + + //Drop items + DriveableType type = getDriveableType(); + if (!worldObj.isRemote) { + Vector3f pos = new Vector3f(0, 0, 0); + + //Get the midpoint of the part + if (part.box != null) + pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F)); + + ArrayList drops = type.getItemsRequired(part, getDriveableData().engine); + if (drops != null) { + //Drop each ItemStack + for (ItemStack stack : drops) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy())); + } + } + dropItemsOnPartDeath(pos, part); + + //Inventory is in the core, so drop it if the core is broken + if (part.type == EnumDriveablePart.core) { + for (int i = 0; i < getDriveableData().getSizeInventory(); i++) { + ItemStack stack = getDriveableData().getStackInSlot(i); + if (stack != null) { + worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack)); + } + } + } + } + + //Kill all child parts to stop things floating unconnected + for (EnumDriveablePart child : part.type.getChildren()) { + killPart(getDriveableData().parts.get(child)); + } + } + + /** + * Method for planes, vehicles and whatnot to drop their own specific items if they wish + */ + protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part); + + @Override + public float getPlayerRoll() { + return axes.getRoll(); + } + + @Override + public void explode() { + + } + + @Override + public float getCameraDistance() { + return getDriveableType().cameraDistance; + } + + public boolean isPartIntact(EnumDriveablePart part) { + DriveablePart thisPart = getDriveableData().parts.get(part); + return thisPart.maxHealth == 0 || thisPart.health > 0; + } + + public abstract boolean hasMouseControlMode(); + + public abstract String getBombInventoryName(); + + public abstract String getMissileInventoryName(); + + public boolean rotateWithTurret(Seat seat) { + return seat.part == EnumDriveablePart.turret; + } + + @Override + public String getCommandSenderName() { + return getDriveableType().name; + } + + @SideOnly(Side.CLIENT) + public boolean showInventory(int seat) { + return seat != 0 || !FlansModClient.controlModeMouse; + } + + //------------------------------------- + // Getters and setters for dual fields + //------------------------------------- + + public float getShootDelay(boolean secondary) { + return secondary ? shootDelaySecondary : shootDelayPrimary; + } + + public boolean canLaunchIT1() { + return canFireIT1; + } + + public float getMinigunSpeed(boolean secondary) { + return secondary ? minigunSpeedSecondary : minigunSpeedPrimary; + } + + public int getCurrentGun(boolean secondary) { + return secondary ? currentGunSecondary : currentGunPrimary; + } + + public void setShootDelay(float i, boolean secondary) { + setRecoilTimer(); + // If current delay is greater than i, use that. If current delay is less than 0, add that to new shoot delay + if (secondary) + shootDelaySecondary = i > shootDelaySecondary ? (shootDelaySecondary < 0 ? i + shootDelaySecondary : i) : shootDelaySecondary; + else + shootDelayPrimary = i > shootDelayPrimary ? (shootDelayPrimary < 0 ? i + shootDelayPrimary : i) : shootDelayPrimary; + } + + public void setMinigunSpeed(float f, boolean secondary) { + if (secondary) + minigunSpeedSecondary = f; + else minigunSpeedPrimary = f; + } + + public void setCurrentGun(int i, boolean secondary) { + if (secondary) + currentGunSecondary = i; + else currentGunPrimary = i; + } + + public void setEntityMarker(int tick) { + this.isShowedPosition = true; + this.tickCount = tick; + } + + public void IT1Reload() { + DriveableType type = getDriveableType(); + + + if (stage == 1) { + //canFireIT1 = false; + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 5); + + if (drakonRailAngle == -10) stage++; + } + + + if (stage == 2) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonDoorAngle == -90) stage++; + } + + if (stage == 3) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 179, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonArmAngle == 179) stage++; + } + + if (stage == 4) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonDoorAngle == 0) { + if (IT1Loaded()) { + stage++; + reloadAnimTime = 60; + } + } + } + + if (stage == 5) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + reloadingDrakon = true; + + if (drakonDoorAngle == -90) stage++; + } + + if (stage == 6) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1); + + if (drakonArmAngle == 0) stage++; + } + + if (stage == 7) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + drakonRailAngle = moveToTarget(drakonRailAngle, 0, 1); + + if (drakonRailAngle == 0 && drakonDoorAngle == 0) { + stage++; + canFireIT1 = true; + reloadingDrakon = false; + } + } + + if (stage == 8) { + drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10); + drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3); + if (worldObj.isRemote && this.ticksExisted > 2) + drakonRailAngle = moveToTarget(drakonRailAngle, -seats[0].looking.getPitch(), seats[0].seatInfo.aimingSpeed.y); + //reloadAnimTime = 60; + + if (!IT1Loaded()) { + stage = 1; + canFireIT1 = false; + } + } + } + + public float moveToTarget(float current, float target, float speed) { + + float pitchToMove = (float) ((Math.sqrt(target * target)) - Math.sqrt((current * current))); + for (; pitchToMove > 180F; pitchToMove -= 360F) { + } + for (; pitchToMove <= -180F; pitchToMove += 360F) { + } + + float signDeltaY = 0; + if (pitchToMove > speed) { + signDeltaY = 1; + } else if (pitchToMove < -speed) { + signDeltaY = -1; + } else { + signDeltaY = 0; + return target; + } + + + if (current > target) { + current = current - speed; + } else if (current < target) { + current = current + speed; + } + + return current; + } + + public boolean IT1Loaded() { + DriveableType type = getDriveableType(); + boolean loaded = false; + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.MISSILE)) { + loaded = true; + } + } + + return loaded; + } + + public void tryRecoil() { + int slot = -1; + DriveableType type = getDriveableType(); + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { + slot = i; + } + } + + if (recoilTimer <= 0 && slot != -1) + isRecoil = true; + } + + public void setRecoilTimer() { + int slot = -1; + DriveableType type = getDriveableType(); + for (int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++) { + ItemStack shell = driveableData.getStackInSlot(i); + if (shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet) shell.getItem()).type, EnumWeaponType.SHELL)) { + slot = i; + } + } + + if (recoilTimer <= 0 && slot != -1) + recoilTimer = (int) getDriveableType().shootDelayPrimary; + } + + @Override + public boolean isInRangeToRenderDist(double d) { + double d1 = this.renderDistanceWeight; + return d < d1 * d1; + } + + // Returns if the bounding box is under the + public boolean isUnderWater() { + return worldObj.isAnyLiquid(this.boundingBox.copy().offset(0, getDriveableType().maxDepth, 0)); + } +} + From 68e376bc722f67d4589254f01a412131e3a69cc0 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Tue, 8 Feb 2022 18:23:19 +0200 Subject: [PATCH 12/25] big minigames update --- .../flansmod/common/driveables/EntityDriveable.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index 28976ef3..9d9916d1 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -2385,10 +2385,6 @@ public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingP if (!worldObj.isRemote) { checkParts(); //If it hit, send a damage update packet - if(part.type.equals(EnumDriveablePart.core) && part.dead){ - if(TeamsManager.instance.currentRound!=null) - TeamsManager.instance.currentRound.gametype.vehicleDestroyed(part.owner, bullet); - } FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension); } @@ -2485,7 +2481,11 @@ public void checkParts() { } } setDead(); - + if(lastAtkEntity!=null&&lastAtkEntity instanceof EntityPlayerMP) { + if (TeamsManager.instance.currentRound != null) { + TeamsManager.instance.currentRound.gametype.vehicleDestroyed(this, (EntityPlayerMP) lastAtkEntity); + } + } } } From 28d9c0986d6521b559c168b1d03d6f813f085da4 Mon Sep 17 00:00:00 2001 From: GolddolphinSKB-Fexcraftian <22482566+GolddolphinSKB-Fexcraftian@users.noreply.github.com> Date: Thu, 10 Feb 2022 00:11:07 +0000 Subject: [PATCH 13/25] Fix dupe --- .../flansmod/common/driveables/ContainerDriveableInventory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/flansmod/common/driveables/ContainerDriveableInventory.java b/src/main/java/com/flansmod/common/driveables/ContainerDriveableInventory.java index 55928c55..4db14db1 100644 --- a/src/main/java/com/flansmod/common/driveables/ContainerDriveableInventory.java +++ b/src/main/java/com/flansmod/common/driveables/ContainerDriveableInventory.java @@ -212,7 +212,7 @@ protected boolean mergeItemStack(ItemStack stack, int startIndex, int endIndex, flag = true; } else if (itemstack.stackSize < maxLimit) { - stack.stackSize = maxLimit; + stack.stackSize -= maxLimit -itemstack.stackSize; itemstack.stackSize = maxLimit; slot.onSlotChanged(); flag = true; From c0337d4bcff200d5e5ae326ede0736636c69a7c2 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:14:12 +0200 Subject: [PATCH 14/25] globla player stats fix globla player stats reset after server restart fix --- src/main/java/com/flansmod/common/PlayerHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/flansmod/common/PlayerHandler.java b/src/main/java/com/flansmod/common/PlayerHandler.java index 14e5e4d9..f8e3e712 100644 --- a/src/main/java/com/flansmod/common/PlayerHandler.java +++ b/src/main/java/com/flansmod/common/PlayerHandler.java @@ -36,6 +36,7 @@ @SuppressWarnings("unused") public class PlayerHandler { private static final Random rand = new Random(); + private boolean statsSynced=false; public static Map serverSideData = new HashMap(); public static Map clientSideData = new HashMap(); public static Map serverSidePlayerStats = new HashMap(); @@ -105,6 +106,11 @@ public void serverTick() { getPlayerData((EntityPlayer) player).tick((EntityPlayer) player); } } + if(!statsSynced){ + for(PlayerStats stats : PlayerStats.getAllPlayersStats()){ + serverSidePlayerStats.put(stats.nickname,stats); + } + } } public void clientTick() { From d1312e4764db8234ab9963f14969f2b6086df4ca Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:15:46 +0200 Subject: [PATCH 15/25] globla player stats fix globla player stats reset after server restart fix --- .../flansmod/common/teams/PlayerStats.java | 366 +++++++++--------- 1 file changed, 178 insertions(+), 188 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/PlayerStats.java b/src/main/java/com/flansmod/common/teams/PlayerStats.java index a682c1fe..14ba38c6 100644 --- a/src/main/java/com/flansmod/common/teams/PlayerStats.java +++ b/src/main/java/com/flansmod/common/teams/PlayerStats.java @@ -1,222 +1,212 @@ -package com.flansmod.common.teams; - -import com.flansmod.common.FlansMod; -import net.minecraft.command.ICommandSender; +package com.flansmod.common; + +import com.flansmod.common.driveables.EntityDriveable; +import com.flansmod.common.driveables.EntitySeat; +import com.flansmod.common.guns.EntityBullet; +import com.flansmod.common.guns.EntityDamageSourceFlans; +import com.flansmod.common.guns.EntityGrenade; +import com.flansmod.common.guns.ShootableType; +import com.flansmod.common.network.PacketRequestDebug; +import com.flansmod.common.teams.PlayerStats; +import com.flansmod.common.teams.TeamsManager; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent; +import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent; +import cpw.mods.fml.relauncher.Side; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.ChatComponentText; -import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.living.LivingAttackEvent; +import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; -import java.io.*; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class PlayerStats { - - private World world; - private EntityPlayerMP playerMP; - public String nickname = "NaN"; - public int kills = 0; //done - public int deaths = 0; //done - public int exp = 0; //done - public int totalExp = 0; //done - public int rank = 1; //done - public double avg = 0; //done - public double longestKill = 0; //done - public int playedRounds = 0; //done - public double playTime = 0; - public int MVPCount = 0; //done - public int capturedFlags = 0; //done - public int savedFlags = 0; //done - public int vehiclesDestroyed = 0; //done 75% - - public PlayerStats(World world, EntityPlayerMP player) { - playerMP = player; - this.world = world; - nickname = player.getDisplayName(); - savePlayerStats(); +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +@SuppressWarnings("unused") +public class PlayerHandler { + private static final Random rand = new Random(); + private boolean statsSynced=false; + public static Map serverSideData = new HashMap(); + public static Map clientSideData = new HashMap(); + public static Map serverSidePlayerStats = new HashMap(); + public static Map clientSidePlayerStats = new HashMap(); + public static ArrayList clientsToRemoveAfterThisRound = new ArrayList(); + + public PlayerHandler() { + MinecraftForge.EVENT_BUS.register(this); + FMLCommonHandler.instance().bus().register(this); } - private PlayerStats() { - + @SubscribeEvent + public void onEntityHurt(LivingAttackEvent event) { + EntityLivingBase entity = event.entityLiving; + if (entity.ridingEntity instanceof EntityDriveable || entity.ridingEntity instanceof EntitySeat) { + event.setCanceled(true); + } } - public void savePlayerStats() { - File dir = new File(world.getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); - dir.mkdirs(); - dir.setReadable(true); - dir.setWritable(true); - File file = new File(dir, playerMP.getDisplayName() + " " + playerMP.getUniqueID().toString() + ".dat"); - dir.mkdirs(); - dir.setReadable(true); - dir.setWritable(true); - checkFileExists(file); - try { - NBTTagCompound tags = new NBTTagCompound(); - - tags.setString("Nickname", playerMP.getDisplayName()); - tags.setInteger("Kills", kills); - tags.setInteger("Deaths", deaths); - tags.setInteger("Exp", exp); - tags.setInteger("Total Exp", totalExp); - tags.setInteger("Rank", rank); - tags.setDouble("AVG", avg); - tags.setDouble("Longest Kill", longestKill); - tags.setInteger("Rounds Played", playedRounds); - tags.setDouble("Play Time", playTime); - tags.setInteger("MVP Count", MVPCount); - tags.setInteger("Flags Captured", capturedFlags); - tags.setInteger("Flags Saved", savedFlags); - tags.setInteger("Vehicles Destroyed", vehiclesDestroyed); - - - CompressedStreamTools.write(tags, new DataOutputStream(new FileOutputStream(file))); - } catch (Exception e) { - FlansMod.log("Failed to save to teams.dat"); - e.printStackTrace(); + @SubscribeEvent + public void onLivingHurtEvent(LivingHurtEvent event) { + float damage = event.ammount; + if (damage > 0 && event.source instanceof EntityDamageSourceFlans) { + EntityDamageSourceFlans source = (EntityDamageSourceFlans) event.source; + + ShootableType shootableType = null; + Entity damageSouceEntity = source.getDamageSourceEntity(); + if (damageSouceEntity instanceof EntityBullet) { + shootableType = ((EntityBullet) damageSouceEntity).type; + } + if (damageSouceEntity instanceof EntityGrenade) { + shootableType = ((EntityGrenade) damageSouceEntity).type; + } + if (shootableType != null && shootableType.ignoreArmorProbability > 0 && rand.nextFloat() < shootableType.ignoreArmorProbability) { + EntityLivingBase entity = event.entityLiving; + float f1 = damage; + damage = Math.max(damage - entity.getAbsorptionAmount(), 0.0F); + entity.setAbsorptionAmount(entity.getAbsorptionAmount() - (f1 - damage)); + + damage *= shootableType.ignoreArmorDamageFactor; + + if (damage != 0.0F) { + float health = entity.getHealth(); + entity.setHealth(health - damage); + entity.func_110142_aN().func_94547_a(source, health, damage); + entity.setAbsorptionAmount(entity.getAbsorptionAmount() - damage); + +// FlansMod.log("Ignore armor damage = " + damage); + } + + event.setCanceled(true); + } } } + @SubscribeEvent + public void onEntityKilled(LivingDeathEvent event) { + EntityLivingBase entity = event.entityLiving; + if (entity instanceof EntityPlayer) { + getPlayerData((EntityPlayer) entity).playerKilled(); + } + } - private static boolean checkFileExists(File file) { - if (!file.exists()) { - try { - file.createNewFile(); - FlansMod.log("Created new file"); - } catch (Exception e) { - FlansMod.log("Failed to create file"); - FlansMod.log(file.getAbsolutePath()); - e.printStackTrace(); + public void serverTick() { + for (WorldServer world : MinecraftServer.getServer().worldServers) { + for (Object player : world.playerEntities) { + getPlayerData((EntityPlayer) player).tick((EntityPlayer) player); + } + } + if(!statsSynced){ + for(PlayerStats stats : PlayerStats.getAllPlayersStats()){ + serverSidePlayerStats.put(stats.nickname,stats); + statsSynced=true; } - return false; } - return true; } - public void addExp(float a) { - exp += a; - totalExp += a; - if (exp >= 1000) { - rank++; - exp = exp - 1000; + public void clientTick() { + if (Minecraft.getMinecraft().theWorld != null) { + for (Object player : Minecraft.getMinecraft().theWorld.playerEntities) { + getPlayerData((EntityPlayer) player).tick((EntityPlayer) player); + } } } - public void updateLongestKill(float distance) { - addExp(distance / 10); - if (distance > longestKill) { - longestKill = distance; - } + public static PlayerData getPlayerData(EntityPlayer player) { + if (player == null) + return null; + return getPlayerData(player.getCommandSenderName(), player.worldObj.isRemote ? Side.CLIENT : Side.SERVER); } - public void updateAVG() { - avg = (double) kills / playedRounds; + public static PlayerData getPlayerData(String username) { + return getPlayerData(username, Side.SERVER); } + public static PlayerData getPlayerData(EntityPlayer player, Side side) { + if (player == null) + return null; + return getPlayerData(player.getCommandSenderName(), side); + } - public static PlayerStats getPlayerStatsFromFile(String name) { - PlayerStats toSend = new PlayerStats(); - File dir = new File(MinecraftServer.getServer().getEntityWorld().getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); - for (File file : dir.listFiles()) { - if (file.getName().startsWith(name)) { - checkFileExists(file); - try { - NBTTagCompound tags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(file))); - toSend.nickname = tags.getString("Nickname"); - toSend.kills = tags.getInteger("Kills"); - toSend.deaths = tags.getInteger("Deaths"); - toSend.exp = tags.getInteger("Exp"); - toSend.totalExp = tags.getInteger("Total Exp"); - toSend.rank = tags.getInteger("Rank"); - toSend.avg = tags.getDouble("AVG"); - toSend.longestKill = tags.getDouble("Longest Kill"); - toSend.playedRounds = tags.getInteger("Rounds Played"); - toSend.playTime = tags.getDouble("Play Time"); - toSend.MVPCount = tags.getInteger("MVP Count"); - toSend.capturedFlags = tags.getInteger("Flags Captured"); - toSend.savedFlags = tags.getInteger("Flags Saved"); - toSend.vehiclesDestroyed = tags.getInteger("Vehicles Destroyed"); - return toSend; - } catch (Exception e) { - FlansMod.log("Failed to save to teams.dat"); - e.printStackTrace(); - return null; - } - } + public static PlayerData getPlayerData(String username, Side side) { + if (side.isClient()) { + if (!clientSideData.containsKey(username)) + clientSideData.put(username, new PlayerData(username)); + } else { + if (!serverSideData.containsKey(username)) + serverSideData.put(username, new PlayerData(username)); } - return null; + return side.isClient() ? clientSideData.get(username) : serverSideData.get(username); } - public static void printLeaderboardExp(ICommandSender sender) { - List nameList = new ArrayList<>(); - File dir = new File(MinecraftServer.getServer().getEntityWorld().getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); - for (File file : dir.listFiles()) { - checkFileExists(file); - try { - NBTTagCompound tags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(file))); - String nickname = tags.getString("Nickname"); - nameList.add(nickname); - } catch (Exception e) { - FlansMod.log("Failed to print leaderboard"); - e.printStackTrace(); - } + //--- + + public static PlayerStats getPlayerStats(EntityPlayerMP player) { + if (player == null) + return null; + return getPlayerStats(player, player.worldObj.isRemote ? Side.CLIENT : Side.SERVER); + } + + public static PlayerStats getPlayerStats(EntityPlayerMP player, Side side) { + String username = player.getCommandSenderName(); + if (side.isClient()) { + if (!clientSidePlayerStats.containsKey(username)) + clientSidePlayerStats.put(username, new PlayerStats(player.worldObj, player)); + } else { + if (!serverSidePlayerStats.containsKey(username)) + serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, player)); } - Collections.sort(nameList, new ComparatorExp()); - int counter1 = 0; - for (String name : nameList) { - switch (counter1) { - case 0: - sender.addChatMessage(new ChatComponentText("\u00a76\u00a7l1. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 1: - sender.addChatMessage(new ChatComponentText("\u00a74\u00a7l2. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 2: - sender.addChatMessage(new ChatComponentText("\u00a7a\u00a7l3. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 3: - sender.addChatMessage(new ChatComponentText("\u00a7l4. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 4: - sender.addChatMessage(new ChatComponentText("\u00a7l5. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 5: - sender.addChatMessage(new ChatComponentText("\u00a7l6. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 6: - sender.addChatMessage(new ChatComponentText("\u00a7l7. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 7: - sender.addChatMessage(new ChatComponentText("\u00a7l8. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 8: - sender.addChatMessage(new ChatComponentText("\u00a7l9. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 9: - sender.addChatMessage(new ChatComponentText("\u00a7l10. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; - case 10: - sender.addChatMessage(new ChatComponentText("\u00a7b\u00a7l"+nameList.indexOf(sender.getCommandSenderName())+1+". " + sender.getCommandSenderName() + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); - break; + return side.isClient() ? clientSidePlayerStats.get(username) : serverSidePlayerStats.get(username); + } + + @SubscribeEvent + public void onPlayerEvent(PlayerEvent event) { + if (event instanceof PlayerLoggedInEvent) { + if (event.player instanceof EntityPlayerMP) { + FlansMod.packetHandler.sendTo(new PacketRequestDebug(false), (EntityPlayerMP) event.player); } - counter1++; - if (counter1 >= 11) break; + + EntityPlayer player = event.player; + String username = player.getCommandSenderName(); + if (!serverSideData.containsKey(username)) + serverSideData.put(username, new PlayerData(username)); + clientsToRemoveAfterThisRound.remove(username); + if (!serverSidePlayerStats.containsKey(username)) + serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, (EntityPlayerMP)player)); + + } else if (event instanceof PlayerLoggedOutEvent) { + EntityPlayer player = event.player; + String username = player.getCommandSenderName(); + if (TeamsManager.getInstance().currentRound == null) + serverSideData.remove(username); + else clientsToRemoveAfterThisRound.add(username); + } else if (event instanceof PlayerRespawnEvent) { + EntityPlayer player = event.player; + String username = player.getCommandSenderName(); + if (!serverSideData.containsKey(username)) + serverSideData.put(username, new PlayerData(username)); + if (!serverSidePlayerStats.containsKey(username)) + serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, (EntityPlayerMP)player)); + } - counter1 = 0; } -} -class ComparatorExp implements Comparator { - @Override - public int compare(String a, String b) { - PlayerStats info1 = PlayerStats.getPlayerStatsFromFile(a); - PlayerStats info2 = PlayerStats.getPlayerStatsFromFile(b); - if (info1 == null || info2 == null) - return 0; - return info2.totalExp - info1.totalExp; + /** + * Called by teams manager to remove lingering player data + */ + public static void roundEnded() { + for (String username : clientsToRemoveAfterThisRound) { + serverSideData.remove(username); + } } } From 726cf1f171db938925adc25d45949be970a684e0 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:35:53 +0200 Subject: [PATCH 16/25] crash fix 1 --- .../flansmod/common/teams/GameTypeCTF.java | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/GameTypeCTF.java b/src/main/java/com/flansmod/common/teams/GameTypeCTF.java index 5f1ac274..08b6bc31 100644 --- a/src/main/java/com/flansmod/common/teams/GameTypeCTF.java +++ b/src/main/java/com/flansmod/common/teams/GameTypeCTF.java @@ -37,39 +37,50 @@ public void roundEnd() teamB.sortPlayers(); EntityPlayerMP bestPlayerA = null; EntityPlayerMP bestPlayerB = null; - for(String name : teamA.members){ - getPlayerInfo(getPlayer(name)).playedRounds++; - getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerStats(); + if(teamA.members!=null) { + for (String name : teamA.members) { + getPlayerInfo(getPlayer(name)).playedRounds++; + getPlayerInfo(getPlayer(name)).updateAVG(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); + } } - for(String name : teamB.members){ - getPlayerInfo(getPlayer(name)).playedRounds++; - getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerStats(); + if(teamB.members!=null) { + for (String name : teamB.members) { + getPlayerInfo(getPlayer(name)).playedRounds++; + getPlayerInfo(getPlayer(name)).updateAVG(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); + } } - for(String name : teamA.members){ - PlayerData data = getPlayerData(getPlayer(name)); - int bestScore=0; - if(data.score>bestScore){ - bestPlayerA=getPlayer(name); - bestScore=data.score; + if(teamA.members!=null) { + for (String name : teamA.members) { + PlayerData data = getPlayerData(getPlayer(name)); + int bestScore = 0; + if (data.score > bestScore) { + bestPlayerA = getPlayer(name); + bestScore = data.score; + } } } - for(String name : teamB.members){ - PlayerData data = getPlayerData(getPlayer(name)); - int bestScore=0; - if(data.score>bestScore){ - bestPlayerB=getPlayer(name); - bestScore=data.score; + if(teamB.members!=null) { + for (String name : teamB.members) { + PlayerData data = getPlayerData(getPlayer(name)); + int bestScore = 0; + if (data.score > bestScore) { + bestPlayerB = getPlayer(name); + bestScore = data.score; + } } } - - getPlayerInfo(bestPlayerA).addExp(250); - getPlayerInfo(bestPlayerB).addExp(250); - getPlayerInfo(bestPlayerA).MVPCount++; - getPlayerInfo(bestPlayerB).MVPCount++; - getPlayerInfo(bestPlayerA).savePlayerStats(); - getPlayerInfo(bestPlayerB).savePlayerStats(); + if(bestPlayerA!=null){ + getPlayerInfo(bestPlayerA).addExp(250); + getPlayerInfo(bestPlayerA).MVPCount++; + getPlayerInfo(bestPlayerA).savePlayerStats(); + } + if(bestPlayerB!=null){ + getPlayerInfo(bestPlayerB).addExp(250); + getPlayerInfo(bestPlayerB).MVPCount++; + getPlayerInfo(bestPlayerB).savePlayerStats(); + } } } From 8125deddee3c31e1deafd1030a6ab578f02b68a9 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:36:41 +0200 Subject: [PATCH 17/25] crash fix 2 --- .../com/flansmod/common/teams/GameTypeDM.java | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/GameTypeDM.java b/src/main/java/com/flansmod/common/teams/GameTypeDM.java index c187824b..8c056a26 100644 --- a/src/main/java/com/flansmod/common/teams/GameTypeDM.java +++ b/src/main/java/com/flansmod/common/teams/GameTypeDM.java @@ -37,40 +37,50 @@ public void roundEnd() teamB.sortPlayers(); EntityPlayerMP bestPlayerA = null; EntityPlayerMP bestPlayerB = null; - for(String name : teamA.members){ - getPlayerInfo(getPlayer(name)).playedRounds++; - getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerStats(); + if(teamA.members!=null) { + for (String name : teamA.members) { + getPlayerInfo(getPlayer(name)).playedRounds++; + getPlayerInfo(getPlayer(name)).updateAVG(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); + } } - for(String name : teamB.members){ - getPlayerInfo(getPlayer(name)).playedRounds++; - getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerStats(); + if(teamB.members!=null) { + for (String name : teamB.members) { + getPlayerInfo(getPlayer(name)).playedRounds++; + getPlayerInfo(getPlayer(name)).updateAVG(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); + } } - for(String name : teamA.members){ - PlayerData data = getPlayerData(getPlayer(name)); - int bestScore=0; - if(data.score>bestScore){ - bestPlayerA=getPlayer(name); - bestScore=data.score; + if(teamA.members!=null) { + for (String name : teamA.members) { + PlayerData data = getPlayerData(getPlayer(name)); + int bestScore = 0; + if (data.score > bestScore) { + bestPlayerA = getPlayer(name); + bestScore = data.score; + } } } - for(String name : teamB.members){ - PlayerData data = getPlayerData(getPlayer(name)); - int bestScore=0; - if(data.score>bestScore){ - bestPlayerB=getPlayer(name); - bestScore=data.score; + if(teamB.members!=null) { + for (String name : teamB.members) { + PlayerData data = getPlayerData(getPlayer(name)); + int bestScore = 0; + if (data.score > bestScore) { + bestPlayerB = getPlayer(name); + bestScore = data.score; + } } } - if(getPlayerData(bestPlayerA).score>getPlayerData(bestPlayerB).score){ - getPlayerInfo(bestPlayerA).addExp(250); - getPlayerInfo(bestPlayerA).MVPCount++; - getPlayerInfo(bestPlayerA).savePlayerStats(); - } else if(getPlayerData(bestPlayerA).score getPlayerData(bestPlayerB).score) { + getPlayerInfo(bestPlayerA).addExp(250); + getPlayerInfo(bestPlayerA).MVPCount++; + getPlayerInfo(bestPlayerA).savePlayerStats(); + } else if (getPlayerData(bestPlayerA).score < getPlayerData(bestPlayerB).score) { + getPlayerInfo(bestPlayerB).addExp(250); + getPlayerInfo(bestPlayerB).MVPCount++; + getPlayerInfo(bestPlayerB).savePlayerStats(); + } } } } From ce7ff83698ceb9a3bcdc63112aac26791e341cf5 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:37:33 +0200 Subject: [PATCH 18/25] crash fix 3 --- .../flansmod/common/teams/GameTypeTDM.java | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/GameTypeTDM.java b/src/main/java/com/flansmod/common/teams/GameTypeTDM.java index 55304294..b10908ee 100644 --- a/src/main/java/com/flansmod/common/teams/GameTypeTDM.java +++ b/src/main/java/com/flansmod/common/teams/GameTypeTDM.java @@ -35,39 +35,50 @@ public void roundEnd() teamB.sortPlayers(); EntityPlayerMP bestPlayerA = null; EntityPlayerMP bestPlayerB = null; - for(String name : teamA.members){ - getPlayerInfo(getPlayer(name)).playedRounds++; - getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerStats(); + if(teamA.members!=null) { + for (String name : teamA.members) { + getPlayerInfo(getPlayer(name)).playedRounds++; + getPlayerInfo(getPlayer(name)).updateAVG(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); + } } - for(String name : teamB.members){ - getPlayerInfo(getPlayer(name)).playedRounds++; - getPlayerInfo(getPlayer(name)).updateAVG(); - getPlayerInfo(getPlayer(name)).savePlayerStats(); + if(teamB.members!=null) { + for (String name : teamB.members) { + getPlayerInfo(getPlayer(name)).playedRounds++; + getPlayerInfo(getPlayer(name)).updateAVG(); + getPlayerInfo(getPlayer(name)).savePlayerStats(); + } } - for(String name : teamA.members){ - PlayerData data = getPlayerData(getPlayer(name)); - int bestScore=0; - if(data.score>bestScore){ - bestPlayerA=getPlayer(name); - bestScore=data.score; + if(teamA.members!=null) { + for (String name : teamA.members) { + PlayerData data = getPlayerData(getPlayer(name)); + int bestScore = 0; + if (data.score > bestScore) { + bestPlayerA = getPlayer(name); + bestScore = data.score; + } } } - for(String name : teamB.members){ - PlayerData data = getPlayerData(getPlayer(name)); - int bestScore=0; - if(data.score>bestScore){ - bestPlayerB=getPlayer(name); - bestScore=data.score; + if(teamB.members!=null) { + for (String name : teamB.members) { + PlayerData data = getPlayerData(getPlayer(name)); + int bestScore = 0; + if (data.score > bestScore) { + bestPlayerB = getPlayer(name); + bestScore = data.score; + } } } - - getPlayerInfo(bestPlayerA).addExp(250); - getPlayerInfo(bestPlayerB).addExp(250); - getPlayerInfo(bestPlayerA).MVPCount++; - getPlayerInfo(bestPlayerB).MVPCount++; - getPlayerInfo(bestPlayerA).savePlayerStats(); - getPlayerInfo(bestPlayerB).savePlayerStats(); + if(bestPlayerA!=null){ + getPlayerInfo(bestPlayerA).addExp(250); + getPlayerInfo(bestPlayerA).MVPCount++; + getPlayerInfo(bestPlayerA).savePlayerStats(); + } + if(bestPlayerB!=null){ + getPlayerInfo(bestPlayerB).addExp(250); + getPlayerInfo(bestPlayerB).MVPCount++; + getPlayerInfo(bestPlayerB).savePlayerStats(); + } } } From 242446e2e13719ebe03720f414d907cc5e4fd7c3 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Thu, 17 Feb 2022 09:01:35 +0200 Subject: [PATCH 19/25] global player stats fix --- .../flansmod/common/teams/PlayerStats.java | 391 ++++++++++-------- 1 file changed, 219 insertions(+), 172 deletions(-) diff --git a/src/main/java/com/flansmod/common/teams/PlayerStats.java b/src/main/java/com/flansmod/common/teams/PlayerStats.java index 14ba38c6..da2bef3c 100644 --- a/src/main/java/com/flansmod/common/teams/PlayerStats.java +++ b/src/main/java/com/flansmod/common/teams/PlayerStats.java @@ -1,212 +1,259 @@ -package com.flansmod.common; - -import com.flansmod.common.driveables.EntityDriveable; -import com.flansmod.common.driveables.EntitySeat; -import com.flansmod.common.guns.EntityBullet; -import com.flansmod.common.guns.EntityDamageSourceFlans; -import com.flansmod.common.guns.EntityGrenade; -import com.flansmod.common.guns.ShootableType; -import com.flansmod.common.network.PacketRequestDebug; -import com.flansmod.common.teams.PlayerStats; -import com.flansmod.common.teams.TeamsManager; -import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.common.eventhandler.SubscribeEvent; -import cpw.mods.fml.common.gameevent.PlayerEvent; -import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent; -import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent; -import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent; -import cpw.mods.fml.relauncher.Side; -import net.minecraft.client.Minecraft; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +package com.flansmod.common.teams; + +import com.flansmod.common.FlansMod; +import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.WorldServer; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.living.LivingAttackEvent; -import net.minecraftforge.event.entity.living.LivingDeathEvent; -import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; +import java.io.*; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -@SuppressWarnings("unused") -public class PlayerHandler { - private static final Random rand = new Random(); - private boolean statsSynced=false; - public static Map serverSideData = new HashMap(); - public static Map clientSideData = new HashMap(); - public static Map serverSidePlayerStats = new HashMap(); - public static Map clientSidePlayerStats = new HashMap(); - public static ArrayList clientsToRemoveAfterThisRound = new ArrayList(); - - public PlayerHandler() { - MinecraftForge.EVENT_BUS.register(this); - FMLCommonHandler.instance().bus().register(this); - } +import java.util.Collections; +import java.util.Comparator; +import java.util.List; - @SubscribeEvent - public void onEntityHurt(LivingAttackEvent event) { - EntityLivingBase entity = event.entityLiving; - if (entity.ridingEntity instanceof EntityDriveable || entity.ridingEntity instanceof EntitySeat) { - event.setCanceled(true); - } +public class PlayerStats { + + private World world; + private EntityPlayerMP playerMP; + public String nickname = "NaN"; + public int kills = 0; //done + public int deaths = 0; //done + public int exp = 0; //done + public int totalExp = 0; //done + public int rank = 1; //done + public double avg = 0; //done + public double longestKill = 0; //done + public int playedRounds = 0; //done + public double playTime = 0; + public int MVPCount = 0; //done + public int capturedFlags = 0; //done + public int savedFlags = 0; //done + public int vehiclesDestroyed = 0; //done 75% + + public PlayerStats(World world, EntityPlayerMP player) { + playerMP = player; + this.world = world; + nickname = player.getDisplayName(); + savePlayerStats(); } - @SubscribeEvent - public void onLivingHurtEvent(LivingHurtEvent event) { - float damage = event.ammount; - if (damage > 0 && event.source instanceof EntityDamageSourceFlans) { - EntityDamageSourceFlans source = (EntityDamageSourceFlans) event.source; + private PlayerStats() { - ShootableType shootableType = null; - Entity damageSouceEntity = source.getDamageSourceEntity(); - if (damageSouceEntity instanceof EntityBullet) { - shootableType = ((EntityBullet) damageSouceEntity).type; - } - if (damageSouceEntity instanceof EntityGrenade) { - shootableType = ((EntityGrenade) damageSouceEntity).type; - } - if (shootableType != null && shootableType.ignoreArmorProbability > 0 && rand.nextFloat() < shootableType.ignoreArmorProbability) { - EntityLivingBase entity = event.entityLiving; - float f1 = damage; - damage = Math.max(damage - entity.getAbsorptionAmount(), 0.0F); - entity.setAbsorptionAmount(entity.getAbsorptionAmount() - (f1 - damage)); + } - damage *= shootableType.ignoreArmorDamageFactor; + public EntityPlayerMP getPlayer(String username) { + return MinecraftServer.getServer().getConfigurationManager().func_152612_a(username); + } - if (damage != 0.0F) { - float health = entity.getHealth(); - entity.setHealth(health - damage); - entity.func_110142_aN().func_94547_a(source, health, damage); - entity.setAbsorptionAmount(entity.getAbsorptionAmount() - damage); + public void savePlayerStats() { + File dir = new File(MinecraftServer.getServer().getEntityWorld().getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); + dir.mkdirs(); + dir.setReadable(true); + dir.setWritable(true); + File file = new File(dir, getPlayer(nickname).getDisplayName() + " " + getPlayer(nickname).getUniqueID().toString() + ".dat"); + dir.mkdirs(); + dir.setReadable(true); + dir.setWritable(true); + checkFileExists(file); + try { + NBTTagCompound tags = new NBTTagCompound(); -// FlansMod.log("Ignore armor damage = " + damage); - } + tags.setString("Nickname", nickname); + tags.setInteger("Kills", kills); + tags.setInteger("Deaths", deaths); + tags.setInteger("Exp", exp); + tags.setInteger("Total Exp", totalExp); + tags.setInteger("Rank", rank); + tags.setDouble("AVG", avg); + tags.setDouble("Longest Kill", longestKill); + tags.setInteger("Rounds Played", playedRounds); + tags.setDouble("Play Time", playTime); + tags.setInteger("MVP Count", MVPCount); + tags.setInteger("Flags Captured", capturedFlags); + tags.setInteger("Flags Saved", savedFlags); + tags.setInteger("Vehicles Destroyed", vehiclesDestroyed); - event.setCanceled(true); - } - } - } - @SubscribeEvent - public void onEntityKilled(LivingDeathEvent event) { - EntityLivingBase entity = event.entityLiving; - if (entity instanceof EntityPlayer) { - getPlayerData((EntityPlayer) entity).playerKilled(); + CompressedStreamTools.write(tags, new DataOutputStream(new FileOutputStream(file))); + } catch (Exception e) { + FlansMod.log("Failed to save to teams.dat"); + e.printStackTrace(); } } - public void serverTick() { - for (WorldServer world : MinecraftServer.getServer().worldServers) { - for (Object player : world.playerEntities) { - getPlayerData((EntityPlayer) player).tick((EntityPlayer) player); - } - } - if(!statsSynced){ - for(PlayerStats stats : PlayerStats.getAllPlayersStats()){ - serverSidePlayerStats.put(stats.nickname,stats); - statsSynced=true; + + private static boolean checkFileExists(File file) { + if (!file.exists()) { + try { + file.createNewFile(); + FlansMod.log("Created new file"); + } catch (Exception e) { + FlansMod.log("Failed to create file"); + FlansMod.log(file.getAbsolutePath()); + e.printStackTrace(); } + return false; } + return true; } - public void clientTick() { - if (Minecraft.getMinecraft().theWorld != null) { - for (Object player : Minecraft.getMinecraft().theWorld.playerEntities) { - getPlayerData((EntityPlayer) player).tick((EntityPlayer) player); - } + public void addExp(float a) { + exp += a; + totalExp += a; + if (exp >= 1000) { + rank++; + exp = exp - 1000; } } - public static PlayerData getPlayerData(EntityPlayer player) { - if (player == null) - return null; - return getPlayerData(player.getCommandSenderName(), player.worldObj.isRemote ? Side.CLIENT : Side.SERVER); + public void updateLongestKill(float distance) { + addExp(distance / 10); + if (distance > longestKill) { + longestKill = distance; + } } - public static PlayerData getPlayerData(String username) { - return getPlayerData(username, Side.SERVER); + public void updateAVG() { + avg = (double) kills / playedRounds; } - public static PlayerData getPlayerData(EntityPlayer player, Side side) { - if (player == null) - return null; - return getPlayerData(player.getCommandSenderName(), side); - } - public static PlayerData getPlayerData(String username, Side side) { - if (side.isClient()) { - if (!clientSideData.containsKey(username)) - clientSideData.put(username, new PlayerData(username)); - } else { - if (!serverSideData.containsKey(username)) - serverSideData.put(username, new PlayerData(username)); + public static PlayerStats getPlayerStatsFromFile(String name) { + PlayerStats toSend = new PlayerStats(); + File dir = new File(MinecraftServer.getServer().getEntityWorld().getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); + for (File file : dir.listFiles()) { + if (file.getName().startsWith(name)) { + checkFileExists(file); + try { + NBTTagCompound tags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(file))); + toSend.nickname = tags.getString("Nickname"); + toSend.kills = tags.getInteger("Kills"); + toSend.deaths = tags.getInteger("Deaths"); + toSend.exp = tags.getInteger("Exp"); + toSend.totalExp = tags.getInteger("Total Exp"); + toSend.rank = tags.getInteger("Rank"); + toSend.avg = tags.getDouble("AVG"); + toSend.longestKill = tags.getDouble("Longest Kill"); + toSend.playedRounds = tags.getInteger("Rounds Played"); + toSend.playTime = tags.getDouble("Play Time"); + toSend.MVPCount = tags.getInteger("MVP Count"); + toSend.capturedFlags = tags.getInteger("Flags Captured"); + toSend.savedFlags = tags.getInteger("Flags Saved"); + toSend.vehiclesDestroyed = tags.getInteger("Vehicles Destroyed"); + return toSend; + } catch (Exception e) { + FlansMod.log("Failed to save to teams.dat"); + e.printStackTrace(); + return null; + } + } } - return side.isClient() ? clientSideData.get(username) : serverSideData.get(username); - } - - //--- - - public static PlayerStats getPlayerStats(EntityPlayerMP player) { - if (player == null) - return null; - return getPlayerStats(player, player.worldObj.isRemote ? Side.CLIENT : Side.SERVER); + return null; } - public static PlayerStats getPlayerStats(EntityPlayerMP player, Side side) { - String username = player.getCommandSenderName(); - if (side.isClient()) { - if (!clientSidePlayerStats.containsKey(username)) - clientSidePlayerStats.put(username, new PlayerStats(player.worldObj, player)); - } else { - if (!serverSidePlayerStats.containsKey(username)) - serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, player)); + public static void printLeaderboardExp(ICommandSender sender) { + List nameList = new ArrayList<>(); + File dir = new File(MinecraftServer.getServer().getEntityWorld().getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); + for (File file : dir.listFiles()) { + checkFileExists(file); + try { + NBTTagCompound tags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(file))); + String nickname = tags.getString("Nickname"); + nameList.add(nickname); + } catch (Exception e) { + FlansMod.log("Failed to print leaderboard"); + e.printStackTrace(); + } + } + Collections.sort(nameList, new ComparatorExp()); + int counter1 = 0; + for (String name : nameList) { + switch (counter1) { + case 0: + sender.addChatMessage(new ChatComponentText("\u00a76\u00a7l1. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 1: + sender.addChatMessage(new ChatComponentText("\u00a74\u00a7l2. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 2: + sender.addChatMessage(new ChatComponentText("\u00a7a\u00a7l3. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 3: + sender.addChatMessage(new ChatComponentText("\u00a7l4. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 4: + sender.addChatMessage(new ChatComponentText("\u00a7l5. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 5: + sender.addChatMessage(new ChatComponentText("\u00a7l6. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 6: + sender.addChatMessage(new ChatComponentText("\u00a7l7. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 7: + sender.addChatMessage(new ChatComponentText("\u00a7l8. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 8: + sender.addChatMessage(new ChatComponentText("\u00a7l9. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 9: + sender.addChatMessage(new ChatComponentText("\u00a7l10. " + name + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + case 10: + sender.addChatMessage(new ChatComponentText("\u00a7b\u00a7l"+nameList.indexOf(sender.getCommandSenderName())+1+". " + sender.getCommandSenderName() + " - Rank " + getPlayerStatsFromFile(name).rank + "(" + getPlayerStatsFromFile(name).totalExp + " Exp)")); + break; + } + counter1++; + if (counter1 >= 11) break; } - return side.isClient() ? clientSidePlayerStats.get(username) : serverSidePlayerStats.get(username); + counter1 = 0; } - @SubscribeEvent - public void onPlayerEvent(PlayerEvent event) { - if (event instanceof PlayerLoggedInEvent) { - if (event.player instanceof EntityPlayerMP) { - FlansMod.packetHandler.sendTo(new PacketRequestDebug(false), (EntityPlayerMP) event.player); + public static List getAllPlayersStats() { + List listToSend = new ArrayList<>(); + File dir = new File(MinecraftServer.getServer().getEntityWorld().getSaveHandler().getWorldDirectory() + "\\FlansMod players statistics\\"); + if(dir.listFiles()==null) return null; + for (File file : dir.listFiles()) { + checkFileExists(file); + try { + PlayerStats toSend = new PlayerStats(); + NBTTagCompound tags = CompressedStreamTools.read(new DataInputStream(new FileInputStream(file))); + toSend.nickname = tags.getString("Nickname"); + toSend.kills = tags.getInteger("Kills"); + toSend.deaths = tags.getInteger("Deaths"); + toSend.exp = tags.getInteger("Exp"); + toSend.totalExp = tags.getInteger("Total Exp"); + toSend.rank = tags.getInteger("Rank"); + toSend.avg = tags.getDouble("AVG"); + toSend.longestKill = tags.getDouble("Longest Kill"); + toSend.playedRounds = tags.getInteger("Rounds Played"); + toSend.playTime = tags.getDouble("Play Time"); + toSend.MVPCount = tags.getInteger("MVP Count"); + toSend.capturedFlags = tags.getInteger("Flags Captured"); + toSend.savedFlags = tags.getInteger("Flags Saved"); + toSend.vehiclesDestroyed = tags.getInteger("Vehicles Destroyed"); + listToSend.add(toSend); + } catch (Exception e) { + FlansMod.log("Failed to save to teams.dat"); + e.printStackTrace(); + return null; } - - EntityPlayer player = event.player; - String username = player.getCommandSenderName(); - if (!serverSideData.containsKey(username)) - serverSideData.put(username, new PlayerData(username)); - clientsToRemoveAfterThisRound.remove(username); - if (!serverSidePlayerStats.containsKey(username)) - serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, (EntityPlayerMP)player)); - - } else if (event instanceof PlayerLoggedOutEvent) { - EntityPlayer player = event.player; - String username = player.getCommandSenderName(); - if (TeamsManager.getInstance().currentRound == null) - serverSideData.remove(username); - else clientsToRemoveAfterThisRound.add(username); - } else if (event instanceof PlayerRespawnEvent) { - EntityPlayer player = event.player; - String username = player.getCommandSenderName(); - if (!serverSideData.containsKey(username)) - serverSideData.put(username, new PlayerData(username)); - if (!serverSidePlayerStats.containsKey(username)) - serverSidePlayerStats.put(username, new PlayerStats(player.worldObj, (EntityPlayerMP)player)); - } + return listToSend; } +} - /** - * Called by teams manager to remove lingering player data - */ - public static void roundEnded() { - for (String username : clientsToRemoveAfterThisRound) { - serverSideData.remove(username); - } +class ComparatorExp implements Comparator { + @Override + public int compare(String a, String b) { + PlayerStats info1 = PlayerStats.getPlayerStatsFromFile(a); + PlayerStats info2 = PlayerStats.getPlayerStatsFromFile(b); + if (info1 == null || info2 == null) + return 0; + return info2.totalExp - info1.totalExp; } } From c97ef23d8e048f16e0f4811e563af711dd802e07 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Fri, 18 Feb 2022 09:04:59 +0200 Subject: [PATCH 20/25] crash fix --- src/main/java/com/flansmod/common/PlayerHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/flansmod/common/PlayerHandler.java b/src/main/java/com/flansmod/common/PlayerHandler.java index f8e3e712..cb65ba37 100644 --- a/src/main/java/com/flansmod/common/PlayerHandler.java +++ b/src/main/java/com/flansmod/common/PlayerHandler.java @@ -107,6 +107,7 @@ public void serverTick() { } } if(!statsSynced){ + if(PlayerStats.getAllPlayersStats()==null) statsSynced=true; for(PlayerStats stats : PlayerStats.getAllPlayersStats()){ serverSidePlayerStats.put(stats.nickname,stats); } From 70679961224101b8a0faf5cfa76ee994eacbc11b Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Mon, 21 Feb 2022 11:35:03 +0200 Subject: [PATCH 21/25] crash fix --- src/main/java/com/flansmod/common/PlayerHandler.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/flansmod/common/PlayerHandler.java b/src/main/java/com/flansmod/common/PlayerHandler.java index cb65ba37..fd1e07f0 100644 --- a/src/main/java/com/flansmod/common/PlayerHandler.java +++ b/src/main/java/com/flansmod/common/PlayerHandler.java @@ -106,10 +106,13 @@ public void serverTick() { getPlayerData((EntityPlayer) player).tick((EntityPlayer) player); } } - if(!statsSynced){ - if(PlayerStats.getAllPlayersStats()==null) statsSynced=true; - for(PlayerStats stats : PlayerStats.getAllPlayersStats()){ - serverSidePlayerStats.put(stats.nickname,stats); + if(TeamsManager.getInstance().currentRound!=null) { + if (!statsSynced) { + if (PlayerStats.getAllPlayersStats() == null) statsSynced = true; + for (PlayerStats stats : PlayerStats.getAllPlayersStats()) { + serverSidePlayerStats.put(stats.nickname, stats); + statsSynced = true; + } } } } From e095307695ab02f1e4da6f9e4220d41c7316664a Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Mon, 21 Feb 2022 11:39:38 +0200 Subject: [PATCH 22/25] minigames update protection from the destruction of friendly vehicles in mini games --- .../common/driveables/EntityDriveable.java | 98 +++++++++++-------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index 9d9916d1..3a9e328d 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -7,6 +7,8 @@ import com.flansmod.client.FlansModClient; import com.flansmod.client.debug.EntityDebugVector; import com.flansmod.common.FlansMod; +import com.flansmod.common.PlayerData; +import com.flansmod.common.PlayerHandler; import com.flansmod.common.RotatedAxes; import com.flansmod.common.driveables.DriveableType.ParticleEmitter; import com.flansmod.common.driveables.DriveableType.ShootParticle; @@ -1302,21 +1304,21 @@ public void onUpdate() { } if (seats[0] != null && seats[0].riddenByEntity != null && seats[0].riddenByEntity instanceof EntityPlayer && worldObj.isRemote) { EntityPlayer p = (EntityPlayer) seats[0].riddenByEntity; - if (this.ticksExisted < getDriveableType().placeTimePrimary && (getShootDelay(false) % 100) == 0 ) { - p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use in " + getShootDelay(false)/20 + " seconds.")); + if (this.ticksExisted < getDriveableType().placeTimePrimary && (getShootDelay(false) % 100) == 0) { + p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use in " + getShootDelay(false) / 20 + " seconds.")); } else if (this.ticksExisted == getDriveableType().placeTimePrimary) { p.addChatComponentMessage(new ChatComponentText("Primary gun ready to use!")); } if (this.ticksExisted < getDriveableType().placeTimeSecondary && (getShootDelay(true) % 100) == 0) { p.addChatComponentMessage( - new ChatComponentText("Secondary gun ready to use in " + getShootDelay(true)/20 + " seconds.")); + new ChatComponentText("Secondary gun ready to use in " + getShootDelay(true) / 20 + " seconds.")); } else if (this.ticksExisted == getDriveableType().placeTimeSecondary) { p.addChatComponentMessage(new ChatComponentText("Secondary gun ready to use!")); } - if (engineStartDelay > 0 && engineStartDelay % (2.5*20) == 0) { - p.addChatComponentMessage(new ChatComponentText("Engine starting.. " + (float)engineStartDelay/20 + " seconds remaining.")); + if (engineStartDelay > 0 && engineStartDelay % (2.5 * 20) == 0) { + p.addChatComponentMessage(new ChatComponentText("Engine starting.. " + (float) engineStartDelay / 20 + " seconds remaining.")); } else if (engineStartDelay == 1) { p.addChatComponentMessage(new ChatComponentText("Engine started!")); } @@ -1343,7 +1345,9 @@ public void onUpdate() { prevDeckCheck = deckCheck; - if (engineStartDelay > 0) { engineStartDelay--; } + if (engineStartDelay > 0) { + engineStartDelay--; + } //Handle fuel int fuelMultiplier = 2; @@ -1572,7 +1576,7 @@ public void checkForCollisions() { if (FlansMod.seatCollisions) { // This is for preventing vehicle glitching. It makes seats collideable, and stops their motion if for (EntitySeat seat : seats) { - if (seat == null || wheels == null ||wheels[0] == null || wheels[1] == null || seat.riddenByEntity == null) + if (seat == null || wheels == null || wheels[0] == null || wheels[1] == null || seat.riddenByEntity == null) continue; DriveablePosition p = seat.getAsDriveablePosition(); if (driveableData.parts.get(p.part).dead) @@ -1587,9 +1591,9 @@ public void checkForCollisions() { } } - double checkY = Math.max((wheels[0].posY + wheels[1].posY)/2F + (this instanceof EntityVehicle ? 1.5 : 0), seat.posY); + double checkY = Math.max((wheels[0].posY + wheels[1].posY) / 2F + (this instanceof EntityVehicle ? 1.5 : 0), seat.posY); Vec3 seatPos = Vec3.createVectorHelper(seat.posX + fwd.x * a, checkY + fwd.y * a, seat.posZ + fwd.z * a); - Vec3 wheelMidPos = Vec3.createVectorHelper((wheels[0].posX + wheels[1].posX)/2F, checkY, (wheels[0].posZ + wheels[1].posZ)/2F); + Vec3 wheelMidPos = Vec3.createVectorHelper((wheels[0].posX + wheels[1].posX) / 2F, checkY, (wheels[0].posZ + wheels[1].posZ) / 2F); MovingObjectPosition hit = worldObj.rayTraceBlocks(seatPos, wheelMidPos, crashInWater); if (hit != null && hit.typeOfHit == MovingObjectType.BLOCK) { @@ -1638,6 +1642,7 @@ protected void fall(float k) { * Attack a certain part of a driveable and return whether it broke or not */ public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage) { + boolean isFriendly = false; if (ep == EnumDriveablePart.core) { if (source.getSourceOfDamage() instanceof EntityLivingBase) { this.lastAtkEntity = source.getSourceOfDamage(); @@ -1647,9 +1652,28 @@ public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damag this.lastAtkEntity = null; } } + if(TeamsManager.getInstance().currentRound!=null){ + if(source instanceof EntityDamageSourceFlans){ + EntityPlayerMP driver = null; + for(EntitySeat seat : this.seats){ + if(seat.riddenByEntity!=null && seat.riddenByEntity instanceof EntityPlayerMP){ + driver = (EntityPlayerMP)seat.riddenByEntity; + } + } + if(driver!=null) { + EntityDamageSourceFlans dsf = (EntityDamageSourceFlans) source; + EntityPlayerMP attacker = (EntityPlayerMP) dsf.shooter; + PlayerData attackerData = PlayerHandler.getPlayerData(attacker); + PlayerData driverData = PlayerHandler.getPlayerData(driver); + if(attackerData.team.shortName.equals(driverData.team.shortName)){ + isFriendly = true; + damage=0; + } + } + + } + } DriveablePart part = driveableData.parts.get(ep); - // FlansMod.log("EntityDriveable.attackPart %s : %s : damage=%.1f : %s : health=%d", ep.name(), ep.getName(), damage, - // part.type.name(), part.health); return part.attack(damage, source.isFireDamage()); } @@ -2170,7 +2194,7 @@ public void checkCollision(CollisionTest tester, CollisionShapeBox box) { renderTri(p1, p2, p3); renderTri(p3, p4, p1); } - + if (tester.nearestDistance < topFaceDist) tester.isOnTop = false; @@ -2376,6 +2400,7 @@ public ArrayList attackFromBulletButBetter(Vector3f origin, Vector3f */ public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower) { DriveablePart part = getDriveableData().parts.get(hit.part); + if (bullet != null) penetratingPower = part.hitByBullet(bullet, hit, penetratingPower); else @@ -2449,31 +2474,26 @@ public void checkParts() { if (type.isExplosionWhenDestroyed) //Create a flans mod explosion rather than a standard MC one. allows control over death boom - { - new FlansModExplosion(worldObj, this, null, type, posX, posY, posZ, - type.deathExplosionRadius, type.deathExplosionPower,TeamsManager.explosions && type.deathExplosionBreaksBlocks, - type.deathExplosionDamageVsLiving, type.deathExplosionDamageVsPlayer, type.deathExplosionDamageVsPlane, type.deathExplosionDamageVsVehicle, seatNum, seatNum); - - } - if(!worldObj.isRemote && type.deathFireRadius > 0.1F) - { - for(float i = -type.deathFireRadius; i < type.deathFireRadius; i++) - { - for(float j = -type.deathFireRadius; j < type.deathFireRadius; j++) - { - for(float k = -type.deathFireRadius; k < type.deathFireRadius; k++) - { - int x = MathHelper.floor_double(i + posX); - int y = MathHelper.floor_double(j + posY); - int z = MathHelper.floor_double(k + posZ); - if(i * i + j * j + k * k <= type.deathFireRadius * type.deathFireRadius && worldObj.getBlock(x, y, z) == Blocks.air && rand.nextBoolean()) - { - worldObj.setBlock(x, y, z, Blocks.fire, 0, 3); - } - } - } - } - } + { + new FlansModExplosion(worldObj, this, null, type, posX, posY, posZ, + type.deathExplosionRadius, type.deathExplosionPower, TeamsManager.explosions && type.deathExplosionBreaksBlocks, + type.deathExplosionDamageVsLiving, type.deathExplosionDamageVsPlayer, type.deathExplosionDamageVsPlane, type.deathExplosionDamageVsVehicle, seatNum, seatNum); + + } + if (!worldObj.isRemote && type.deathFireRadius > 0.1F) { + for (float i = -type.deathFireRadius; i < type.deathFireRadius; i++) { + for (float j = -type.deathFireRadius; j < type.deathFireRadius; j++) { + for (float k = -type.deathFireRadius; k < type.deathFireRadius; k++) { + int x = MathHelper.floor_double(i + posX); + int y = MathHelper.floor_double(j + posY); + int z = MathHelper.floor_double(k + posZ); + if (i * i + j * j + k * k <= type.deathFireRadius * type.deathFireRadius && worldObj.getBlock(x, y, z) == Blocks.air && rand.nextBoolean()) { + worldObj.setBlock(x, y, z, Blocks.fire, 0, 3); + } + } + } + } + } for (DriveablePart part : driveableData.parts.values()) { if (part.health > 0 && !part.dead) @@ -2481,13 +2501,13 @@ public void checkParts() { } } setDead(); - if(lastAtkEntity!=null&&lastAtkEntity instanceof EntityPlayerMP) { + if (lastAtkEntity != null && lastAtkEntity instanceof EntityPlayerMP) { if (TeamsManager.instance.currentRound != null) { + System.out.println(); TeamsManager.instance.currentRound.gametype.vehicleDestroyed(this, (EntityPlayerMP) lastAtkEntity); } } } - } public void checkPartsWhenAttacked() { From de667f92338c90c65d6f50abf5f6b4551a8a31f8 Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Mon, 21 Feb 2022 11:42:17 +0200 Subject: [PATCH 23/25] minigames update protection from the destruction of friendly vehicles in mini games --- .../flansmod/common/guns/EntityBullet.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/flansmod/common/guns/EntityBullet.java b/src/main/java/com/flansmod/common/guns/EntityBullet.java index 2adb7699..fa35bef4 100644 --- a/src/main/java/com/flansmod/common/guns/EntityBullet.java +++ b/src/main/java/com/flansmod/common/guns/EntityBullet.java @@ -1,5 +1,6 @@ package com.flansmod.common.guns; +import com.flansmod.common.driveables.*; import io.netty.buffer.ByteBuf; import java.util.ArrayList; @@ -8,6 +9,7 @@ import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; @@ -33,10 +35,6 @@ import com.flansmod.common.PlayerData; import com.flansmod.common.PlayerHandler; import com.flansmod.common.RotatedAxes; -import com.flansmod.common.driveables.EntityDriveable; -import com.flansmod.common.driveables.EntityPlane; -import com.flansmod.common.driveables.EntitySeat; -import com.flansmod.common.driveables.EntityVehicle; import com.flansmod.common.driveables.mechas.EntityMecha; import com.flansmod.common.guns.raytracing.BlockHit; import com.flansmod.common.guns.raytracing.BulletHit; @@ -586,10 +584,25 @@ else if (motionZ != 0) if (bulletHit instanceof DriveableHit) { if (type.entityHitSoundEnable) PacketPlaySound.sendSoundPacket(posX, posY, posZ, type.hitSoundRange, dimension, type.hitSound, true); - + boolean isFriendly=false; DriveableHit driveableHit = (DriveableHit) bulletHit; driveableHit.driveable.lastAtkEntity = owner; - penetratingPower = driveableHit.driveable.bulletHit(this, driveableHit, penetratingPower); + if(TeamsManager.getInstance().currentRound!=null) { + for (EntitySeat seat : driveableHit.driveable.seats) { + if (seat.riddenByEntity != null && seat.riddenByEntity instanceof EntityPlayerMP) { + PlayerData dataDriver = PlayerHandler.getPlayerData((EntityPlayerMP) seat.riddenByEntity); + PlayerData dataAttacker = PlayerHandler.getPlayerData((EntityPlayerMP) owner); + if (dataDriver.team.shortName.equals(dataAttacker.team.shortName)) { + isFriendly = true; + } + } + } + } + if(isFriendly){ + penetratingPower=0; + } else { + penetratingPower = driveableHit.driveable.bulletHit(this, driveableHit, penetratingPower); + } if (!worldObj.isRemote) { if (owner instanceof EntityPlayer) { From 7707f50922a59def130d0f8172c200c658563b6f Mon Sep 17 00:00:00 2001 From: SecretAgent12 <51740316+SecretAgent12@users.noreply.github.com> Date: Wed, 23 Feb 2022 12:54:52 +0200 Subject: [PATCH 24/25] removed println --- .../java/com/flansmod/common/driveables/EntityDriveable.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java index 3a9e328d..45fa1cf1 100644 --- a/src/main/java/com/flansmod/common/driveables/EntityDriveable.java +++ b/src/main/java/com/flansmod/common/driveables/EntityDriveable.java @@ -2503,7 +2503,6 @@ public void checkParts() { setDead(); if (lastAtkEntity != null && lastAtkEntity instanceof EntityPlayerMP) { if (TeamsManager.instance.currentRound != null) { - System.out.println(); TeamsManager.instance.currentRound.gametype.vehicleDestroyed(this, (EntityPlayerMP) lastAtkEntity); } } From 4c3b2ac7a05e31675d7a126ca5a1299aaccb572a Mon Sep 17 00:00:00 2001 From: Unknown025 <11259556+Unknown025@users.noreply.github.com> Date: Wed, 2 Mar 2022 01:30:12 -0800 Subject: [PATCH 25/25] Minor refactoring. --- .../com/flansmod/client/tmt/ModelPool.java | 101 +- .../client/tmt/ModelRendererTurbo.java | 4510 ++++++++--------- 2 files changed, 2231 insertions(+), 2380 deletions(-) diff --git a/src/main/java/com/flansmod/client/tmt/ModelPool.java b/src/main/java/com/flansmod/client/tmt/ModelPool.java index 62e05881..f313439e 100644 --- a/src/main/java/com/flansmod/client/tmt/ModelPool.java +++ b/src/main/java/com/flansmod/client/tmt/ModelPool.java @@ -1,63 +1,54 @@ package com.flansmod.client.tmt; +import com.flansmod.common.FlansMod; +import cpw.mods.fml.common.Loader; + import java.io.File; import java.util.HashMap; import java.util.Map; -import com.flansmod.common.FlansMod; - -import cpw.mods.fml.common.Loader; +public class ModelPool { + public static final Class OBJ = ModelPoolObjEntry.class; + private static final Map modelMap = new HashMap<>(); + private static final String[] resourceDir = new String[]{ + "/resources/models/", + "/resources/mod/models/", + "/Flan/" + }; -public class ModelPool -{ - public static ModelPoolEntry addFile(String file, Class modelClass, Map group, Map textureGroup) - { - ModelPoolEntry entry = null; - if(modelMap.containsKey(file)) - { - entry = modelMap.get(file); - entry.applyGroups(group, textureGroup); - return entry; - } - try - { - entry = (ModelPoolEntry)modelClass.newInstance(); - } - catch(Exception e) - { - FlansMod.log("A new " + entry.getClass().getName() + " could not be initialized."); - FlansMod.log(e.getMessage()); - return null; - } - File modelFile = null; - for(int i = 0; i < resourceDir.length && (modelFile == null || !modelFile.exists()); i++) - { - String absPath = new File(Loader.instance().getConfigDir().getParent(), resourceDir[i]).getAbsolutePath(); - if(!absPath.endsWith("/") || !absPath.endsWith("\\")) - absPath+= "/"; - modelFile = entry.checkValidPath(absPath + file); - } - if(modelFile == null || !modelFile.exists()) - { - FlansMod.log("The model with the name " + file + " does not exist."); - return null; - } - entry.groups = new HashMap(); - entry.textures = new HashMap(); - entry.name = file; - entry.setGroup("0"); - entry.setTextureGroup("0"); - entry.getModel(modelFile); - entry.applyGroups(group, textureGroup); - modelMap.put(file, entry); - return entry; - } - - private static Map modelMap = new HashMap(); - private static String[] resourceDir = new String[] { - "/resources/models/", - "/resources/mod/models/", - "/Flan/" - }; - public static final Class OBJ = ModelPoolObjEntry.class; + public static ModelPoolEntry addFile(String file, Class modelClass, Map group, Map textureGroup) { + ModelPoolEntry entry = null; + if (modelMap.containsKey(file)) { + entry = modelMap.get(file); + entry.applyGroups(group, textureGroup); + return entry; + } + try { + entry = (ModelPoolEntry) modelClass.newInstance(); + } catch (Exception e) { + FlansMod.log("A new " + entry.getClass().getName() + " could not be initialized."); + FlansMod.log(e.getMessage()); + return null; + } + File modelFile = null; + for (int i = 0; i < resourceDir.length && (modelFile == null || !modelFile.exists()); i++) { + String absPath = new File(Loader.instance().getConfigDir().getParent(), resourceDir[i]).getAbsolutePath(); + if (!absPath.endsWith("/") || !absPath.endsWith("\\")) + absPath += "/"; + modelFile = entry.checkValidPath(absPath + file); + } + if (modelFile == null || !modelFile.exists()) { + FlansMod.log("The model with the name " + file + " does not exist."); + return null; + } + entry.groups = new HashMap<>(); + entry.textures = new HashMap<>(); + entry.name = file; + entry.setGroup("0"); + entry.setTextureGroup("0"); + entry.getModel(modelFile); + entry.applyGroups(group, textureGroup); + modelMap.put(file, entry); + return entry; + } } diff --git a/src/main/java/com/flansmod/client/tmt/ModelRendererTurbo.java b/src/main/java/com/flansmod/client/tmt/ModelRendererTurbo.java index e5887350..af25d964 100644 --- a/src/main/java/com/flansmod/client/tmt/ModelRendererTurbo.java +++ b/src/main/java/com/flansmod/client/tmt/ModelRendererTurbo.java @@ -1,15 +1,5 @@ package com.flansmod.client.tmt; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.lwjgl.opengl.GL11; - import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.model.TexturedQuad; @@ -19,2341 +9,2211 @@ import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +import java.util.*; + /** * An extension to the ModelRenderer class. It basically is a copy to ModelRenderer, * however, it contains various new methods to make your models. *

* Since the ModelRendererTurbo class gets loaded during startup, the models made - * can be very complex. This is why I can afford to add, for example, Wavefont OBJ + * can be very complex. This is why I can afford to add, for example, Wavefront OBJ * support or have the addSprite method, methods that add a lot of vertices and * polygons. - * @author GaryCXJk * + * @author GaryCXJk */ -public class ModelRendererTurbo extends ModelRenderer -{ - public boolean glow = false; - public ModelRendererTurbo(ModelBase modelbase, String s) - { - super(modelbase, s); - flip = false; - compiled = false; - displayList = 0; - mirror = false; - showModel = true; - field_1402_i = false; - vertices = new PositionTextureVertex[0]; - faces = new TexturedPolygon[0]; - forcedRecompile = false; - transformGroup = new HashMap(); - transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); - textureGroup = new HashMap(); - textureGroup.put("0", new TextureGroup()); - currentTextureGroup = textureGroup.get("0"); - boxName = s; - - defaultTexture = ""; - - useLegacyCompiler = false; - } - - public ModelRendererTurbo(ModelBase modelbase) - { - this(modelbase, null); - } - - /** - * Creates a new ModelRenderTurbo object. It requires the coordinates of the - * position of the texture. - * @param modelbase - * @param textureX the x-coordinate on the texture - * @param textureY the y-coordinate on the texture - */ - public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY) - { - this(modelbase, textureX, textureY, 64, 32); - } - - /** - * Creates a new ModelRenderTurbo object. It requires the coordinates of the - * position of the texture, but also allows you to specify the width and height - * of the texture, allowing you to use bigger textures instead. - * @param modelbase - * @param textureX - * @param textureY - * @param textureU - * @param textureV - */ - public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY, int textureU, int textureV) - { - this(modelbase); - textureOffsetX = textureX; - textureOffsetY = textureY; - textureWidth = textureU; - textureHeight = textureV; - } - - /** - * Creates a new polygon. - * @param verts an array of vertices - */ - public void addPolygon(PositionTextureVertex[] verts) - { - copyTo(verts, new TexturedPolygon[] {new TexturedPolygon(verts)}); - } - - /** - * Creates a new polygon, and adds UV mapping to it. - * @param verts an array of vertices - * @param uv an array of UV coordinates - */ - public void addPolygon(PositionTextureVertex[] verts, int[][] uv) - { - try - { - for(int i = 0; i < verts.length; i++) - { - verts[i] = verts[i].setTexturePosition(uv[i][0] / textureWidth, uv[i][1] / textureHeight); - } - } - finally - { - addPolygon(verts); - } - } - - /** - * Creates a new polygon with a given UV. - * @param verts an array of vertices - * @param u1 - * @param v1 - * @param u2 - * @param v2 - */ - public void addPolygon(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) - { - copyTo(verts, new TexturedPolygon[] {addPolygonReturn(verts, u1, v1, u2, v2)}); - } - - private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2, float q1, float q2, float q3, float q4) - { - if(verts.length < 3) - return null; - float uOffs = 1.0F / (textureWidth * 10.0F); - float vOffs = 1.0F / (textureHeight * 10.0F); - if(verts.length < 4) - { - float xMin = -1; - float yMin = -1; - float xMax = 0; - float yMax = 0; - - for (PositionTextureVertex vert : verts) { - float xPos = vert.texturePositionX; - float yPos = vert.texturePositionY; - xMax = Math.max(xMax, xPos); - xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); - yMax = Math.max(yMax, yPos); - yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); - } - float uMin = u1 / textureWidth + uOffs; - float vMin = v1 / textureHeight + vOffs; - float uSize = (u2 - u1) / textureWidth - uOffs * 2; - float vSize = (v2 - v1) / textureHeight - vOffs * 2; - - float xSize = xMax - xMin; - float ySize = yMax - yMin; - for(int i = 0; i < verts.length; i++) - { - float xPos = verts[i].texturePositionX; - float yPos = verts[i].texturePositionY; - xPos = (xPos - xMin) / xSize; - yPos = (yPos - yMin) / ySize; - verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); - } - } - else - { - verts[0] = verts[0].setTexturePosition((u2 / textureWidth - uOffs)*q1, (v1 / textureHeight + vOffs)*q1, q1); - verts[1] = verts[1].setTexturePosition((u1 / textureWidth + uOffs)*q2, (v1 / textureHeight + vOffs)*q2, q2); - verts[2] = verts[2].setTexturePosition((u1 / textureWidth + uOffs)*q3, (v2 / textureHeight - vOffs)*q3, q3); - verts[3] = verts[3].setTexturePosition((u2 / textureWidth - uOffs)*q4, (v2 / textureHeight - vOffs)*q4, q4); - } - return new TexturedPolygon(verts); - } - - private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) - { - if(verts.length < 3) - return null; - float uOffs = 1.0F / (textureWidth * 10.0F); - float vOffs = 1.0F / (textureHeight * 10.0F); - if(verts.length < 4) - { - float xMin = -1; - float yMin = -1; - float xMax = 0; - float yMax = 0; - - for (PositionTextureVertex vert : verts) { - float xPos = vert.texturePositionX; - float yPos = vert.texturePositionY; - xMax = Math.max(xMax, xPos); - xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); - yMax = Math.max(yMax, yPos); - yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); - } - float uMin = u1 / textureWidth + uOffs; - float vMin = v1 / textureHeight + vOffs; - float uSize = (u2 - u1) / textureWidth - uOffs * 2; - float vSize = (v2 - v1) / textureHeight - vOffs * 2; - - float xSize = xMax - xMin; - float ySize = yMax - yMin; - for(int i = 0; i < verts.length; i++) - { - float xPos = verts[i].texturePositionX; - float yPos = verts[i].texturePositionY; - xPos = (xPos - xMin) / xSize; - yPos = (yPos - yMin) / ySize; - verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); - } - } - else - { - verts[0] = verts[0].setTexturePosition(u2 / textureWidth - uOffs, v1 / textureHeight + vOffs); - verts[1] = verts[1].setTexturePosition(u1 / textureWidth + uOffs, v1 / textureHeight + vOffs); - verts[2] = verts[2].setTexturePosition(u1 / textureWidth + uOffs, v2 / textureHeight - vOffs); - verts[3] = verts[3].setTexturePosition(u2 / textureWidth - uOffs, v2 / textureHeight - vOffs); - } - return new TexturedPolygon(verts); - } - - /** - * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, - * as the method requires eight vector coordinates. - * @param v a float array with three values, the x, y and z coordinates of the vertex - * @param v1 a float array with three values, the x, y and z coordinates of the vertex - * @param v2 a float array with three values, the x, y and z coordinates of the vertex - * @param v3 a float array with three values, the x, y and z coordinates of the vertex - * @param v4 a float array with three values, the x, y and z coordinates of the vertex - * @param v5 a float array with three values, the x, y and z coordinates of the vertex - * @param v6 a float array with three values, the x, y and z coordinates of the vertex - * @param v7 a float array with three values, the x, y and z coordinates of the vertex - * @param w the width of the shape, used in determining the texture - * @param h the height of the shape, used in determining the texture - * @param d the depth of the shape, used in determining the texture - */ - public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d) - { - float[] var1 = new float[] {1,1,1,1,1,1,1,1,1,1,1,1}; - addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d, var1); - } - - /** - * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, - * as the method requires eight vector coordinates. Also does some special texture mapping. - * @param v a float array with three values, the x, y and z coordinates of the vertex - * @param v1 a float array with three values, the x, y and z coordinates of the vertex - * @param v2 a float array with three values, the x, y and z coordinates of the vertex - * @param v3 a float array with three values, the x, y and z coordinates of the vertex - * @param v4 a float array with three values, the x, y and z coordinates of the vertex - * @param v5 a float array with three values, the x, y and z coordinates of the vertex - * @param v6 a float array with three values, the x, y and z coordinates of the vertex - * @param v7 a float array with three values, the x, y and z coordinates of the vertex - * @param w the width of the shape, used in determining the texture - * @param h the height of the shape, used in determining the texture - * @param d the depth of the shape, used in determining the texture - * @param qParam Array containing the q parameters in the order xBack, xBottom, xFront, xTop, yBack, yFront, yLeft, yRight, zBottom, zLeft, zRight, zTop - */ - public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d, float[] qParam) - { - PositionTextureVertex[] verts = new PositionTextureVertex[8]; - TexturedPolygon[] poly = new TexturedPolygon[6]; - PositionTextureVertex positionTexturevertex = new PositionTextureVertex(v[0], v[1], v[2], 0.0F, 0.0F); - PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(v1[0], v1[1], v1[2], 0.0F, 8F); - PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(v2[0], v2[1], v2[2], 8F, 8F); - PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(v3[0], v3[1], v3[2], 8F, 0.0F); - PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(v4[0], v4[1], v4[2], 0.0F, 0.0F); - PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(v5[0], v5[1], v5[2], 0.0F, 8F); - PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(v6[0], v6[1], v6[2], 8F, 8F); - PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(v7[0], v7[1], v7[2], 8F, 0.0F); - verts[0] = positionTexturevertex; - verts[1] = positionTexturevertex1; - verts[2] = positionTexturevertex2; - verts[3] = positionTexturevertex3; - verts[4] = positionTexturevertex4; - verts[5] = positionTexturevertex5; - verts[6] = positionTexturevertex6; - verts[7] = positionTexturevertex7; - poly[0] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 - }, textureOffsetX + d + w, textureOffsetY + d, textureOffsetX + d + w + d, textureOffsetY + d + h, - 1F, qParam[7], qParam[10]*qParam[7], qParam[10]); - poly[1] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 - }, textureOffsetX, textureOffsetY + d, textureOffsetX + d, textureOffsetY + d + h, - qParam[9]*qParam[6], qParam[9], 1F, qParam[6]); - poly[2] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 - }, textureOffsetX + d, textureOffsetY, textureOffsetX + d + w, textureOffsetY + d, - 1F, qParam[8], qParam[1]*qParam[8], qParam[1]); - poly[3] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 - }, textureOffsetX + d + w, textureOffsetY, textureOffsetX + d + w + w, textureOffsetY + d, - qParam[3], qParam[3]*qParam[11], qParam[11], 1F); - poly[4] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 - }, textureOffsetX + d, textureOffsetY + d, textureOffsetX + d + w, textureOffsetY + d + h, - qParam[0], qParam[0]*qParam[4], qParam[4], 1F); - poly[5] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 - }, textureOffsetX + d + w + d, textureOffsetY + d, textureOffsetX + d + w + d + w, textureOffsetY + d + h, - qParam[2]*qParam[5], qParam[2], 1F, qParam[5]); - if(mirror ^ flip) - { - for (TexturedPolygon aPoly : poly) { - aPoly.flipFace(); - } - - } - - copyTo(verts, poly); - } - - /** - * Adds a new box to the model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - */ - @Override - public ModelRendererTurbo addBox(float x, float y, float z, int w, int h, int d) - { - addBox(x, y, z, w, h, d, 0.0F); - return this; - } - - /** - * Adds a new box to the model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - * @param expansion the expansion of the box. It increases the size in each direction by that many. - */ - @Override - public void addBox(float x, float y, float z, int w, int h, int d, float expansion) - { - addBox(x, y, z, w, h, d, expansion, 1F); - } - - /** - * Adds a new box to the model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - * @param expansion the expansion of the box. It increases the size in each direction by that many. It's independent from the scale. - * @param scale - */ - public void addBox(float x, float y, float z, int w, int h, int d, float expansion, float scale) - { - float scaleX = w * scale; - float scaleY = h * scale; - float scaleZ = d * scale; - - float x1 = x + scaleX; - float y1 = y + scaleY; - float z1 = z + scaleZ; - - float expX = expansion + scaleX - w; - float expY = expansion + scaleY - h; - float expZ = expansion + scaleZ - d; - - x -= expX; - y -= expY; - z -= expZ; - x1 += expansion; - y1 += expansion; - z1 += expansion; - if(mirror) - { - float xTemp = x1; - x1 = x; - x = xTemp; - } - - float[] v = {x, y, z}; - float[] v1 = {x1, y, z}; - float[] v2 = {x1, y1, z}; - float[] v3 = {x, y1, z}; - float[] v4 = {x, y, z1}; - float[] v5 = {x1, y, z1}; - float[] v6 = {x1, y1, z1}; - float[] v7 = {x, y1, z1}; - addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); - } - - /** - * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. - * You can use the static variables MR_RIGHT, MR_LEFT, - * MR_FRONT, MR_BACK, MR_TOP and - * MR_BOTTOM. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - * @param scale the "scale" of the box. It only increases the size in each direction by that many. - * @param bottomScale the "scale" of the bottom - * @param dir the side the scaling is applied to - */ - public void addTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bottomScale, int dir) - { - float f4 = x + w; - float f5 = y + h; - float f6 = z + d; - x -= scale; - y -= scale; - z -= scale; - f4 += scale; - f5 += scale; - f6 += scale; - - int m = (mirror ? -1 : 1); - if(mirror) - { - float f7 = f4; - f4 = x; - x = f7; - } - - float[] v = {x, y, z}; - float[] v1 = {f4, y, z}; - float[] v2 = {f4, f5, z}; - float[] v3 = {x, f5, z}; - float[] v4 = {x, y, f6}; - float[] v5 = {f4, y, f6}; - float[] v6 = {f4, f5, f6}; - float[] v7 = {x, f5, f6}; - - switch(dir) - { - case MR_RIGHT: - v[1] -= bottomScale; - v[2] -= bottomScale; - v3[1] += bottomScale; - v3[2] -= bottomScale; - v4[1] -= bottomScale; - v4[2] += bottomScale; - v7[1] += bottomScale; - v7[2] += bottomScale; - break; - case MR_LEFT: - v1[1] -= bottomScale; - v1[2] -= bottomScale; - v2[1] += bottomScale; - v2[2] -= bottomScale; - v5[1] -= bottomScale; - v5[2] += bottomScale; - v6[1] += bottomScale; - v6[2] += bottomScale; - break; - case MR_FRONT: - v[0] -= m * bottomScale; - v[1] -= bottomScale; - v1[0] += m * bottomScale; - v1[1] -= bottomScale; - v2[0] += m * bottomScale; - v2[1] += bottomScale; - v3[0] -= m * bottomScale; - v3[1] += bottomScale; - break; - case MR_BACK: - v4[0] -= m * bottomScale; - v4[1] -= bottomScale; - v5[0] += m * bottomScale; - v5[1] -= bottomScale; - v6[0] += m * bottomScale; - v6[1] += bottomScale; - v7[0] -= m * bottomScale; - v7[1] += bottomScale; - break; - case MR_TOP: - v[0] -= m * bottomScale; - v[2] -= bottomScale; - v1[0] += m * bottomScale; - v1[2] -= bottomScale; - v4[0] -= m * bottomScale; - v4[2] += bottomScale; - v5[0] += m * bottomScale; - v5[2] += bottomScale; - break; - case MR_BOTTOM: - v2[0] += m * bottomScale; - v2[2] -= bottomScale; - v3[0] -= m * bottomScale; - v3[2] -= bottomScale; - v6[0] += m * bottomScale; - v6[2] += bottomScale; - v7[0] -= m * bottomScale; - v7[2] += bottomScale; - break; - } - - float[] qValues = new float[] { - Math.abs((v[0] - v1[0])/(v3[0]-v2[0])), - Math.abs((v[0] - v1[0])/(v4[0]-v5[0])), - Math.abs((v4[0] - v5[0])/(v7[0]-v6[0])), - Math.abs((v3[0] - v2[0])/(v7[0]-v6[0])), - - Math.abs((v[1] - v3[1])/(v1[1]-v2[1])), - Math.abs((v4[1] - v7[1])/(v5[1]-v6[1])), - Math.abs((v[1] - v3[1])/(v4[1]-v7[1])), - Math.abs((v1[1] - v2[1])/(v5[1]-v6[1])), - - Math.abs((v[2] - v4[2])/(v1[2]-v5[2])), - Math.abs((v[2] - v4[2])/(v3[2]-v7[2])), - Math.abs((v1[2] - v5[2])/(v2[2]-v6[2])), - Math.abs((v3[2] - v7[2])/(v2[2]-v6[2])) - }; - - addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); - } - - /** - * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. - * You can use the static variables MR_RIGHT, MR_LEFT, - * MR_FRONT, MR_BACK, MR_TOP and - * MR_BOTTOM. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - * @param scale the "scale" of the box. It only increases the size in each direction by that many. - * @param bScale1 the "scale" of the bottom - Top - * @param bScale2 the "scale" of the bottom - Bottom - * @param bScale3 the "scale" of the bottom - Left - * @param bScale4 the "scale" of the bottom - Right - * @param dir the side the scaling is applied to - */ - public void addFlexBox(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, int dir) - { - float f4 = x + w; - float f5 = y + h; - float f6 = z + d; - x -= scale; - y -= scale; - z -= scale; - f4 += scale; - f5 += scale; - f6 += scale; - - int m = (mirror ? -1 : 1); - if(mirror) - { - float f7 = f4; - f4 = x; - x = f7; - } - - float[] v = {x, y, z}; - float[] v1 = {f4, y, z}; - float[] v2 = {f4, f5, z}; - float[] v3 = {x, f5, z}; - float[] v4 = {x, y, f6}; - float[] v5 = {f4, y, f6}; - float[] v6 = {f4, f5, f6}; - float[] v7 = {x, f5, f6}; - - switch(dir) - { - case MR_RIGHT: - v[1] -= bScale1; - v[2] -= bScale3; - v3[1] += bScale2; - v3[2] -= bScale3; - v4[1] -= bScale1; - v4[2] += bScale4; - v7[1] += bScale2; - v7[2] += bScale4; - break; - case MR_LEFT: - v1[1] -= bScale1; - v1[2] -= bScale3; - v2[1] += bScale2; - v2[2] -= bScale3; - v5[1] -= bScale1; - v5[2] += bScale4; - v6[1] += bScale2; - v6[2] += bScale4; - break; - case MR_FRONT: - v[0] -= m * bScale4; - v[1] -= bScale1; - v1[0] += m * bScale3; - v1[1] -= bScale1; - v2[0] += m * bScale3; - v2[1] += bScale2; - v3[0] -= m * bScale4; - v3[1] += bScale2; - break; - case MR_BACK: - v4[0] -= m * bScale4; - v4[1] -= bScale1; - v5[0] += m * bScale3; - v5[1] -= bScale1; - v6[0] += m * bScale3; - v6[1] += bScale2; - v7[0] -= m * bScale4; - v7[1] += bScale2; - break; - case MR_TOP: - v[0] -= m * bScale1; - v[2] -= bScale3; - v1[0] += m * bScale2; - v1[2] -= bScale3; - v4[0] -= m * bScale1; - v4[2] += bScale4; - v5[0] += m * bScale2; - v5[2] += bScale4; - break; - case MR_BOTTOM: - v2[0] += m * bScale2; - v2[2] -= bScale3; - v3[0] -= m * bScale1; - v3[2] -= bScale3; - v6[0] += m * bScale2; - v6[2] += bScale4; - v7[0] -= m * bScale1; - v7[2] += bScale4; - break; - } - - float[] qValues = new float[] { - Math.abs((v[0] - v1[0])/(v3[0]-v2[0])), - Math.abs((v[0] - v1[0])/(v4[0]-v5[0])), - Math.abs((v4[0] - v5[0])/(v7[0]-v6[0])), - Math.abs((v3[0] - v2[0])/(v7[0]-v6[0])), - - Math.abs((v[1] - v3[1])/(v1[1]-v2[1])), - Math.abs((v4[1] - v7[1])/(v5[1]-v6[1])), - Math.abs((v[1] - v3[1])/(v4[1]-v7[1])), - Math.abs((v1[1] - v2[1])/(v5[1]-v6[1])), - - Math.abs((v[2] - v4[2])/(v1[2]-v5[2])), - Math.abs((v[2] - v4[2])/(v3[2]-v7[2])), - Math.abs((v1[2] - v5[2])/(v2[2]-v6[2])), - Math.abs((v3[2] - v7[2])/(v2[2]-v6[2])) - }; - - addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); - } - - /** - * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. - * You can use the static variables MR_RIGHT, MR_LEFT, - * MR_FRONT, MR_BACK, MR_TOP and - * MR_BOTTOM. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - * @param scale the "scale" of the box. It only increases the size in each direction by that many. - * @param bScale1 the "scale" of the bottom - Top - * @param bScale2 the "scale" of the bottom - Bottom - * @param bScale3 the "scale" of the bottom - Left - * @param bScale4 the "scale" of the bottom - Right - * @param fScale1 the "scale" of the top - Left - * @param fScale2 the "scale" of the top - Right - * @param dir the side the scaling is applied to - */ - public void addFlexTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, float fScale1, float fScale2, int dir) - { - float f4 = x + w; - float f5 = y + h; - float f6 = z + d; - x -= scale; - y -= scale; - z -= scale; - f4 += scale; - f5 += scale; - f6 += scale; - - int m = (mirror ? -1 : 1); - if(mirror) - { - float f7 = f4; - f4 = x; - x = f7; - } - - float[] v = {x, y, z}; - float[] v1 = {f4, y, z}; - float[] v2 = {f4, f5, z}; - float[] v3 = {x, f5, z}; - float[] v4 = {x, y, f6}; - float[] v5 = {f4, y, f6}; - float[] v6 = {f4, f5, f6}; - float[] v7 = {x, f5, f6}; - - - switch(dir) - { - case MR_RIGHT: - v[2] -= fScale1; - v1[2] -= fScale1; - v4[2] += fScale2; - v5[2] += fScale2; - - v[1] -= bScale1; - v[2] -= bScale3; - v3[1] += bScale2; - v3[2] -= bScale3; - v4[1] -= bScale1; - v4[2] += bScale4; - v7[1] += bScale2; - v7[2] += bScale4; - break; - case MR_LEFT: - v[2] -= fScale1; - v1[2] -= fScale1; - v4[2] += fScale2; - v5[2] += fScale2; - - v1[1] -= bScale1; - v1[2] -= bScale3; - v2[1] += bScale2; - v2[2] -= bScale3; - v5[1] -= bScale1; - v5[2] += bScale4; - v6[1] += bScale2; - v6[2] += bScale4; - break; - case MR_FRONT: - v1[1] -= fScale1; - v5[1] -= fScale1; - v2[1] += fScale2; - v6[1] += fScale2; - - v[0] -= m * bScale4; - v[1] -= bScale1; - v1[0] += m * bScale3; - v1[1] -= bScale1; - v2[0] += m * bScale3; - v2[1] += bScale2; - v3[0] -= m * bScale4; - v3[1] += bScale2; - break; - case MR_BACK: - v1[1] -= fScale1; - v5[1] -= fScale1; - v2[1] += fScale2; - v6[1] += fScale2; - - v4[0] -= m * bScale4; - v4[1] -= bScale1; - v5[0] += m * bScale3; - v5[1] -= bScale1; - v6[0] += m * bScale3; - v6[1] += bScale2; - v7[0] -= m * bScale4; - v7[1] += bScale2; - break; - case MR_TOP: - v1[2] -= fScale1; - v2[2] -= fScale1; - v5[2] += fScale2; - v6[2] += fScale2; - - v[0] -= m * bScale1; - v[2] -= bScale3; - v1[0] += m * bScale2; - v1[2] -= bScale3; - v4[0] -= m * bScale1; - v4[2] += bScale4; - v5[0] += m * bScale2; - v5[2] += bScale4; - break; - case MR_BOTTOM: - v1[2] -= fScale1; - v2[2] -= fScale1; - v5[2] += fScale2; - v6[2] += fScale2; - - v2[0] += m * bScale2; - v2[2] -= bScale3; - v3[0] -= m * bScale1; - v3[2] -= bScale3; - v6[0] += m * bScale2; - v6[2] += bScale4; - v7[0] -= m * bScale1; - v7[2] += bScale4; - break; - } - - float[] qValues = new float[] { - Math.abs((v[0] - v1[0])/(v3[0]-v2[0])), - Math.abs((v[0] - v1[0])/(v4[0]-v5[0])), - Math.abs((v4[0] - v5[0])/(v7[0]-v6[0])), - Math.abs((v3[0] - v2[0])/(v7[0]-v6[0])), - - Math.abs((v[1] - v3[1])/(v1[1]-v2[1])), - Math.abs((v4[1] - v7[1])/(v5[1]-v6[1])), - Math.abs((v[1] - v3[1])/(v4[1]-v7[1])), - Math.abs((v1[1] - v2[1])/(v5[1]-v6[1])), - - Math.abs((v[2] - v4[2])/(v1[2]-v5[2])), - Math.abs((v[2] - v4[2])/(v3[2]-v7[2])), - Math.abs((v1[2] - v5[2])/(v2[2]-v6[2])), - Math.abs((v3[2] - v7[2])/(v2[2]-v6[2])) - }; - - addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); - } - - /** - * Adds a box with float width, height and depth. Who knows what it will do to the texture. - * @param x the starting x-positions - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - */ - public void addBox(float x, float y, float z, float w, float h, float d) - { - int rw = MathHelper.ceiling_float_int(w); - int rh = MathHelper.ceiling_float_int(h); - int rd = MathHelper.ceiling_float_int(d); - w -= rw; - h -= rh; - d -= rd; - addShapeBox(x, y, z, rw, rh, rd, 0F, - 0F, 0F, 0F, - w, 0F, 0F, - w, 0F, d, - 0F, 0F, d, - 0F, h, 0F, - w, h, 0F, - w, h, d, - 0F, h, d); - } - - /** - * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. - * You can use the static variables MR_RIGHT, MR_LEFT, - * MR_FRONT, MR_BACK, MR_TOP and - * MR_BOTTOM. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width (over the x-direction) - * @param h the height (over the y-direction) - * @param d the depth (over the z-direction) - * @param scale the "scale" of the box. It only increases the size in each direction by that many. - * @param x0,y0,z0 - x7,y7,z7 the modifiers of the box corners. each corner can changed seperat by x/y/z values - */ - public void addShapeBox(float x, float y, float z, int w, int h, int d, float scale, float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float x5, float y5, float z5, float x6, float y6, float z6, float x7, float y7, float z7) - { - float f4 = x + w; - float f5 = y + h; - float f6 = z + d; - x -= scale; - y -= scale; - z -= scale; - f4 += scale; - f5 += scale; - f6 += scale; - - int m = (mirror ? -1 : 1); - if(mirror) - { - float f7 = f4; - f4 = x; - x = f7; - } - - float[] v = {x - x0, y - y0, z - z0}; - float[] v1 = {f4 + x1, y - y1, z - z1}; - float[] v2 = {f4 + x5, f5 + y5, z - z5}; - float[] v3 = {x - x4, f5 + y4, z - z4}; - float[] v4 = {x - x3, y - y3, f6 + z3}; - float[] v5 = {f4 + x2, y - y2, f6 + z2}; - float[] v6 = {f4 + x6, f5 + y6, f6 + z6}; - float[] v7 = {x - x7, f5 + y7, f6 + z7}; - - float[] qValues = new float[] { - Math.abs((v[0] - v1[0])/(v3[0]-v2[0])), - Math.abs((v[0] - v1[0])/(v4[0]-v5[0])), - Math.abs((v4[0] - v5[0])/(v7[0]-v6[0])), - Math.abs((v3[0] - v2[0])/(v7[0]-v6[0])), - - Math.abs((v[1] - v3[1])/(v1[1]-v2[1])), - Math.abs((v4[1] - v7[1])/(v5[1]-v6[1])), - Math.abs((v[1] - v3[1])/(v4[1]-v7[1])), - Math.abs((v1[1] - v2[1])/(v5[1]-v6[1])), - - Math.abs((v[2] - v4[2])/(v1[2]-v5[2])), - Math.abs((v[2] - v4[2])/(v3[2]-v7[2])), - Math.abs((v1[2] - v5[2])/(v2[2]-v6[2])), - Math.abs((v3[2] - v7[2])/(v2[2]-v6[2])) - }; - - addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); - } - - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param coordinates an array of coordinates that form the shape - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param direction the direction the starting point of the shape is facing - */ - public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) - { - addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); - } - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param coordinates an array of coordinates that form the shape - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param direction the direction the starting point of the shape is facing - * @param faceLengths An array with the length of each face. Used to set - * the texture width of each face on the side manually. - */ - public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) - { - addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); - } - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param coordinates an ArrayList of coordinates that form the shape - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param direction the direction the starting point of the shape is facing - */ - public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) - { - addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); - } - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param coordinates an ArrayList of coordinates that form the shape - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param direction the direction the starting point of the shape is facing - * @param faceLengths An array with the length of each face. Used to set - * the texture width of each face on the side manually. - */ - public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) - { - addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); - } - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param shape a Shape2D which contains the coordinates of the shape points - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param direction the direction the starting point of the shape is facing - */ - public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) - { - addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); - } - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param shape a Shape2D which contains the coordinates of the shape points - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param direction the direction the starting point of the shape is facing - * @param faceLengths An array with the length of each face. Used to set - * the texture width of each face on the side manually. - */ - public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) - { - float rotX = 0; - float rotY = 0; - float rotZ = 0; - switch(direction) - { - case MR_LEFT: - rotY = pi / 2; - break; - case MR_RIGHT: - rotY = -pi / 2; - break; - case MR_TOP: - rotX = pi / 2; - break; - case MR_BOTTOM: - rotX = -pi / 2; - break; - case MR_FRONT: - rotY = pi; - break; - case MR_BACK: - break; - } - addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, faceLengths); - } - - /** - * Creates a shape from a 2D vector shape. - * @param x the starting x position - * @param y the starting y position - * @param z the starting z position - * @param shape a Shape2D which contains the coordinates of the shape points - * @param depth the depth of the shape - * @param shapeTextureWidth the width of the texture of one side of the shape - * @param shapeTextureHeight the height of the texture the shape - * @param sideTextureWidth the width of the texture of the side of the shape - * @param sideTextureHeight the height of the texture of the side of the shape - * @param rotX the rotation around the x-axis - * @param rotY the rotation around the y-axis - * @param rotZ the rotation around the z-axis - */ - public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ) - { - addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, null); - } - - public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ, float[] faceLengths) - { - Shape3D shape3D = shape.extrude(x, y, z, rotX, rotY, rotZ, depth, textureOffsetX, textureOffsetY, textureWidth, textureHeight, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, faceLengths); - - if(flip) - { - for(int idx = 0; idx < shape3D.faces.length; idx++) - { - shape3D.faces[idx].flipFace(); - } - } - - copyTo(shape3D.vertices, shape3D.faces); - } - - /** - * Adds a cube the size of one pixel. It will take a pixel from the texture and - * uses that as the texture of said cube. The accurate name would actually be - * "addVoxel". This method has been added to make it more compatible with Techne, - * and allows for easy single-colored boxes. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param width the width of the box - * @param height the height of the box - * @param length the length of the box - */ - public void addPixel(float x, float y, float z, float width, float height, float length) - { - addPixel(x, y, z, new float[] {width, height, length}, textureOffsetX, textureOffsetY); - } - - /** - * Adds a cube the size of one pixel. It will take a pixel from the texture and - * uses that as the texture of said cube. The accurate name would actually be - * "addVoxel". It will not overwrite the model data, but rather, it will add to - * the model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param scale the "scale" of the cube, where scale is a float integer consisting of three values - * @param w the x-coordinate on the texture - * @param h the y-coordinate on the texture - */ - public void addPixel(float x, float y, float z, float[] scale, int w, int h) - { - PositionTextureVertex[] verts = new PositionTextureVertex[8]; - TexturedPolygon[] poly = new TexturedPolygon[6]; - - float x1 = x + scale[0]; - float y1 = y + scale[1]; - float z1 = z + scale[2]; - - float[] f = {x, y, z}; - float[] f1 = {x1, y, z}; - float[] f2 = {x1, y1, z}; - float[] f3 = {x, y1, z}; - float[] f4 = {x, y, z1}; - float[] f5 = {x1, y, z1}; - float[] f6 = {x1, y1, z1}; - float[] f7 = {x, y1, z1}; - PositionTextureVertex positionTexturevertex = new PositionTextureVertex(f[0], f[1], f[2], 0.0F, 0.0F); - PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(f1[0], f1[1], f1[2], 0.0F, 8F); - PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(f2[0], f2[1], f2[2], 8F, 8F); - PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(f3[0], f3[1], f3[2], 8F, 0.0F); - PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(f4[0], f4[1], f4[2], 0.0F, 0.0F); - PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(f5[0], f5[1], f5[2], 0.0F, 8F); - PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(f6[0], f6[1], f6[2], 8F, 8F); - PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(f7[0], f7[1], f7[2], 8F, 0.0F); - - verts[0] = positionTexturevertex; - verts[1] = positionTexturevertex1; - verts[2] = positionTexturevertex2; - verts[3] = positionTexturevertex3; - verts[4] = positionTexturevertex4; - verts[5] = positionTexturevertex5; - verts[6] = positionTexturevertex6; - verts[7] = positionTexturevertex7; - - poly[0] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 - }, w, h, w + 1, h + 1); - poly[1] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 - }, w, h, w + 1, h + 1); - poly[2] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 - }, w, h, w + 1, h + 1); - poly[3] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 - }, w, h, w + 1, h + 1); - poly[4] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 - }, w, h, w + 1, h + 1); - poly[5] = addPolygonReturn(new PositionTextureVertex[] { - positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 - }, w, h, w + 1, h + 1); - - copyTo(verts, poly); - } - - /** - * Creates a model shaped like the exact image on the texture. Note that this method will - * increase the amount of quads on your model, which could effectively slow down your - * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this - * method to create your model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width of the sprite - * @param h the height of the sprite - * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. - */ - public void addSprite(float x, float y, float z, int w, int h, float expansion) - { - addSprite(x, y, z, w, h, 1, false, false, false, false, false, expansion); - } - - /** - * Creates a model shaped like the exact image on the texture. Note that this method will - * increase the amount of quads on your model, which could effectively slow down your - * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this - * method to create your model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width of the sprite - * @param h the height of the sprite - * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis - * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis - * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis - * @param mirrorX a boolean to define if the sprite should be mirrored - * @param mirrorY a boolean to define if the sprite should be flipped - * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. - */ - public void addSprite(float x, float y, float z, int w, int h, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) - { - addSprite(x, y, z, w, h, 1, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); - } - - /** - * Creates a model shaped like the exact image on the texture. Note that this method will - * increase the amount of quads on your model, which could effectively slow down your - * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this - * method to create your model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width of the sprite - * @param h the height of the sprite - * @param d the depth of the shape itself - * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis - * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis - * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis - * @param mirrorX a boolean to define if the sprite should be mirrored - * @param mirrorY a boolean to define if the sprite should be flipped - * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. - */ - public void addSprite(float x, float y, float z, int w, int h, int d, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) - { - addSprite(x, y, z, w, h, d, 1.0F, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); - } - - /** - * Creates a model shaped like the exact image on the texture. Note that this method will - * increase the amount of quads on your model, which could effectively slow down your - * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this - * method to create your model. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param w the width of the sprite - * @param h the height of the sprite - * @param d the depth of the shape itself - * @param pixelScale the scale of each individual pixel - * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis - * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis - * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis - * @param mirrorX a boolean to define if the sprite should be mirrored - * @param mirrorY a boolean to define if the sprite should be flipped - * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. - */ - public void addSprite(float x, float y, float z, int w, int h, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) - { - String[] mask = new String[h]; - char[] str = new char[w]; - Arrays.fill(str, '1'); - Arrays.fill(mask, new String(str)); - - addSprite(x, y, z, mask, d, pixelScale, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); - } - - /** - * Creates a model shaped like the exact image on the texture. Note that this method will - * increase the amount of quads on your model, which could effectively slow down your - * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this - * method to create your model. - *

- * This method uses a mask string. This way you can reduce the amount of quads used. To - * use this, create a String array, where you use a 1 to signify that the pixel will be - * drawn. Any other character will cause that pixel to not be drawn. - * @param x the starting x-position - * @param y the starting y-position - * @param z the starting z-position - * @param mask an array with the mask string - * @param d the depth of the shape itself - * @param pixelScale the scale of each individual pixel - * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis - * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis - * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis - * @param mirrorX a boolean to define if the sprite should be mirrored - * @param mirrorY a boolean to define if the sprite should be flipped - * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. - */ - public void addSprite(float x, float y, float z, String[] mask, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) - { - int w = mask[0].length(); - int h = mask.length; - - float x1 = x - expansion; - float y1 = y - expansion; - float z1 = z - expansion; - - int wDir = 0; - int hDir = 0; - int dDir = 0; - - float wScale = 1F + (expansion / (w * pixelScale)); - float hScale = 1F + (expansion / (h * pixelScale)); - - if(!rotX) - { - if(!rotY) - { - if(!rotZ) - { - wDir = 0; - hDir = 1; - dDir = 2; - } - else - { - wDir = 1; - hDir = 0; - dDir = 2; - } - } - else - { - if(!rotZ) - { - wDir = 2; - hDir = 1; - dDir = 0; - } - else - { - wDir = 2; - hDir = 0; - dDir = 1; - } - } - } - else - { - if(!rotY) - { - if(!rotZ) - { - wDir = 0; - hDir = 2; - dDir = 1; - } - else - { - wDir = 1; - hDir = 2; - dDir = 0; - } - } - else - { - if(!rotZ) - { - wDir = 2; - hDir = 0; - dDir = 1; - } - else - { - wDir = 2; - hDir = 1; - dDir = 0; - } - } - } - - int texStartX = textureOffsetX + (mirrorX ? w - 1 : 0); - int texStartY = textureOffsetY + (mirrorY ? h - 1 : 0); - int texDirX = (mirrorX ? -1 : 1); - int texDirY = (mirrorY ? -1 : 1); - - float wVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, wDir, 1, 1); - float hVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, hDir, 1, 1); - float dVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, dDir, 1, 1); - - for(int i = 0; i < w; i++) - { - for(int j = 0; j < h; j++) - { - if(mask[j].charAt(i) == '1') - { - addPixel(x1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 0, i, j), - y1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 1, i, j), - z1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 2, i, j), - new float[] {wVoxSize, hVoxSize, dVoxSize}, texStartX + texDirX * i, texStartY + texDirY * j); - } - } - } - } - - private float getPixelSize(float wScale, float hScale, float dScale, int wDir, int hDir, int checkDir, int texPosX, int texPosY) - { - return (wDir == checkDir ? wScale * texPosX : (hDir == checkDir ? hScale * texPosY : dScale)); - } - - /** - * Adds a spherical shape. - * @param x - * @param y - * @param z - * @param r - * @param segs - * @param rings - * @param textureW - * @param textureH - */ - public void addSphere(float x, float y, float z, float r, int segs, int rings, int textureW, int textureH) - { - if(segs < 3) - segs = 3; - rings++; - PositionTextureVertex[] tempVerts = new PositionTextureVertex[segs * (rings - 1) + 2]; - TexturedPolygon[] poly = new TexturedPolygon[segs * rings]; - - tempVerts[0] = new PositionTextureVertex(x, y - r, z, 0, 0); - tempVerts[tempVerts.length - 1] = new PositionTextureVertex(x, y + r, z, 0, 0); - - float uOffs = 1.0F / (textureWidth * 10.0F); - float vOffs = 1.0F / (textureHeight * 10.0F); - float texW = textureW / textureWidth - 2F * uOffs; - float texH = textureH / textureHeight - 2F * vOffs; - float segW = texW / segs; - float segH = texH / rings; - float startU = textureOffsetX / textureWidth; - float startV = textureOffsetY / textureHeight; - - int currentFace = 0; - - for(int j = 1; j < rings; j++) - { - for(int i = 0; i < segs; i++) - { - float yWidth = MathHelper.cos(-pi / 2 + (pi / rings) * j); - float yHeight = MathHelper.sin(-pi / 2 + (pi / rings) * j); - float xSize = MathHelper.sin((pi / segs) * i * 2F + pi) * yWidth; - float zSize = -MathHelper.cos((pi / segs) * i * 2F + pi) * yWidth; - int curVert = 1 + i + segs * (j - 1); - tempVerts[curVert] = new PositionTextureVertex(x + xSize * r, y + yHeight * r, z + zSize * r, 0, 0); - if(i > 0) - { - PositionTextureVertex[] verts; - if(j == 1) - { - verts = new PositionTextureVertex[4]; - verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); - verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); - verts[2] = tempVerts[0].setTexturePosition(startU + segW * (i - 1), startV); - verts[3] = tempVerts[0].setTexturePosition(startU + segW + segW * i, startV); - } - else - { - verts = new PositionTextureVertex[4]; - verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); - verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); - verts[2] = tempVerts[curVert - 1 - segs].setTexturePosition(startU + segW * (i - 1), startV + segH * (j - 1)); - verts[3] = tempVerts[curVert - segs].setTexturePosition(startU + segW * i, startV + segH * (j - 1)); - } - poly[currentFace] = new TexturedPolygon(verts); - currentFace++; - } - } - PositionTextureVertex[] verts; - if(j == 1) - { - verts = new PositionTextureVertex[4]; - verts[0] = tempVerts[1].setTexturePosition(startU + segW * segs, startV + segH * j); - verts[1] = tempVerts[segs].setTexturePosition(startU + segW * (segs - 1), startV + segH * j); - verts[2] = tempVerts[0].setTexturePosition(startU + segW * (segs - 1), startV); - verts[3] = tempVerts[0].setTexturePosition(startU + segW * segs, startV); - } - else - { - verts = new PositionTextureVertex[4]; - verts[0] = tempVerts[1 + segs * (j - 1)].setTexturePosition(startU + texW, startV + segH * j); - verts[1] = tempVerts[segs * (j - 1) + segs].setTexturePosition(startU + texW - segW, startV + segH * j); - verts[2] = tempVerts[segs * (j - 1)].setTexturePosition(startU + texW - segW, startV + segH * (j - 1)); - verts[3] = tempVerts[1 + segs * (j - 1) - segs].setTexturePosition(startU + texW, startV + segH * (j - 1)); - } - poly[currentFace] = new TexturedPolygon(verts); - currentFace++; - } - for(int i = 0; i < segs; i++) - { - PositionTextureVertex[] verts = new PositionTextureVertex[3]; - int curVert = tempVerts.length - (segs + 1); - verts[0] = tempVerts[tempVerts.length - 1].setTexturePosition(startU + segW * (i + 0.5F), startV + texH); - verts[1] = tempVerts[curVert + i].setTexturePosition(startU + segW * i, startV + texH - segH); - verts[2] = tempVerts[curVert + ((i + 1) % segs)].setTexturePosition(startU + segW * (i + 1), startV + texH - segH); - poly[currentFace] = new TexturedPolygon(verts); - currentFace++; - } - - copyTo(tempVerts, poly); - } - - /** - * Adds a cone. - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - */ - public void addCone(float x, float y, float z, float radius, float length, int segments) - { - addCone(x, y, z, radius, length, segments, 1F); - } - - /** - * Adds a cone. - * - * baseScale cannot be zero. If it is, it will automatically be set to 1F. - * - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - * @param baseScale the scaling of the base. Can be negative. - */ - public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale) - { - addCone(x, y, z, radius, length, segments, baseScale, MR_TOP); - } - - /** - * Adds a cone. - * - * baseScale cannot be zero. If it is, it will automatically be set to 1F. - * - * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in - * the top being placed at the (x,y,z). - * - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - * @param baseScale the scaling of the base. Can be negative. - * @param baseDirection the direction it faces - */ - public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection) - { - addCone(x, y, z, radius, length, segments, baseScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F)); - } - - /** - * Adds a cone. - * - * baseScale cannot be zero. If it is, it will automatically be set to 1F. - * - * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in - * the top being placed at the (x,y,z). - * - * The textures for the sides are placed next to each other. - * - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - * @param baseScale the scaling of the base. Can be negative. - * @param baseDirection the direction it faces - * @param textureCircleDiameterW the diameter width of the circle on the texture - * @param textureCircleDiameterH the diameter height of the circle on the texture - */ - public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH) - { - addCylinder(x, y, z, radius, length, segments, baseScale, 0.0F, baseDirection, textureCircleDiameterW, textureCircleDiameterH, 1); - } - - /** - * Adds a cylinder. - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - */ - public void addCylinder(float x, float y, float z, float radius, float length, int segments) - { - addCylinder(x, y, z, radius, length, segments, 1F, 1F); - } - - /** - * Adds a cylinder. - * - * You can make cones by either setting baseScale or topScale to zero. Setting both - * to zero will set the baseScale to 1F. - * - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - * @param baseScale the scaling of the base. Can be negative. - * @param topScale the scaling of the top. Can be negative. - */ - public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale) - { - addCylinder(x, y, z, radius, length, segments, baseScale, topScale, MR_TOP); - } - - /** - * Adds a cylinder. - * - * You can make cones by either setting baseScale or topScale to zero. Setting both - * to zero will set the baseScale to 1F. - * - * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in - * the top being placed at the (x,y,z). - * - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - * @param baseScale the scaling of the base. Can be negative. - * @param topScale the scaling of the top. Can be negative. - * @param baseDirection the direction it faces - */ - public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection) - { - addCylinder(x, y, z, radius, length, segments, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length)); - } - - /** - * Adds a cylinder. - * - * You can make cones by either setting baseScale or topScale to zero. Setting both - * to zero will set the baseScale to 1F. - * - * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in - * the top being placed at the (x,y,z). - * - * The textures for the base and top are placed next to each other, while the body - * will be placed below the circles. - * - * @param x the x-position of the base - * @param y the y-position of the base - * @param z the z-position of the base - * @param radius the radius of the cylinder - * @param length the length of the cylinder - * @param segments the amount of segments the cylinder is made of - * @param baseScale the scaling of the base. Can be negative. - * @param topScale the scaling of the top. Can be negative. - * @param baseDirection the direction it faces - * @param textureCircleDiameterW the diameter width of the circle on the texture - * @param textureCircleDiameterH the diameter height of the circle on the texture - * @param textureH the height of the texture of the body - */ - public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH, int textureH) - { - boolean dirTop = (baseDirection == MR_TOP || baseDirection == MR_BOTTOM); - boolean dirSide = (baseDirection == MR_RIGHT || baseDirection == MR_LEFT); - boolean dirFront = (baseDirection == MR_FRONT || baseDirection == MR_BACK); - boolean dirMirror = (baseDirection == MR_LEFT || baseDirection == MR_BOTTOM || baseDirection == MR_BACK); - - boolean coneBase = (baseScale == 0); - boolean coneTop = (topScale == 0); - - if(coneBase && coneTop) - { - baseScale = 1F; - coneBase = false; - } - - PositionTextureVertex[] tempVerts = new PositionTextureVertex[segments * (coneBase || coneTop ? 1 : 2) + 2]; - TexturedPolygon[] poly = new TexturedPolygon[segments * (coneBase || coneTop ? 2 : 3)]; - - float xLength = (dirSide ? length : 0); - float yLength = (dirTop ? length : 0); - float zLength = (dirFront ? length : 0); - - float xStart = (dirMirror ? x + xLength : x); - float yStart = (dirMirror ? y + yLength : y); - float zStart = (dirMirror ? z + zLength : z); - float xEnd = (!dirMirror ? x + xLength : x); - float yEnd = (!dirMirror ? y + yLength : y); - float zEnd = (!dirMirror ? z + zLength : z); - - tempVerts[0] = new PositionTextureVertex(xStart, yStart, zStart, 0, 0); - tempVerts[tempVerts.length - 1] = new PositionTextureVertex(xEnd, yEnd, zEnd, 0, 0); - - float xCur = xStart; - float yCur = yStart; - float zCur = zStart; - float sCur = (coneBase ? topScale : baseScale); - for(int repeat = 0; repeat < (coneBase || coneTop ? 1 : 2); repeat++) - { - for(int index = 0; index < segments; index++) - { - float xSize = (mirror ^ dirMirror ? -1 : 1) * MathHelper.sin((pi / segments) * index * 2F + pi) * radius * sCur; - float zSize = -MathHelper.cos((pi / segments) * index * 2F + pi) * radius * sCur; - - float xPlace = xCur + (!dirSide ? xSize : 0); - float yPlace = yCur + (!dirTop ? zSize : 0); - float zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); - - tempVerts[1 + index + repeat * segments] = new PositionTextureVertex(xPlace, yPlace, zPlace, 0, 0 ); - } - xCur = xEnd; - yCur = yEnd; - zCur = zEnd; - sCur = topScale; - } - - float uScale = 1.0F / textureWidth; - float vScale = 1.0F / textureHeight; - float uOffset = uScale / 20.0F; - float vOffset = vScale / 20.0F; - float uCircle = textureCircleDiameterW * uScale; - float vCircle = textureCircleDiameterH * vScale; - float uWidth = (uCircle * 2F - uOffset * 2F) / segments; - float vHeight = textureH * vScale - uOffset * 2f; - float uStart = textureOffsetX * uScale; - float vStart = textureOffsetY * vScale; - - PositionTextureVertex[] vert; - for(int index = 0; index < segments; index++) - { - int index2 = (index + 1) % segments; - float uSize = MathHelper.sin((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); - float vSize = MathHelper.cos((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); - float uSize1 = MathHelper.sin((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); - float vSize1 = MathHelper.cos((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); - vert = new PositionTextureVertex[3]; - - vert[0] = tempVerts[0].setTexturePosition(uStart + 0.5F * uCircle, vStart + 0.5F * vCircle); - vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + 0.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); - vert[2] = tempVerts[1 + index].setTexturePosition(uStart + 0.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); - - poly[index] = new TexturedPolygon(vert); - if(mirror ^ flip) - poly[index].flipFace(); - - if(!coneBase && !coneTop) - { - vert = new PositionTextureVertex[4]; - - vert[0] = tempVerts[1 + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle); - vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle); - vert[2] = tempVerts[1 + segments + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle + vHeight); - vert[3] = tempVerts[1 + segments + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle + vHeight); - poly[index + segments] = new TexturedPolygon(vert); - if(mirror ^ flip) - poly[index + segments].flipFace(); - } - - vert = new PositionTextureVertex[3]; - - vert[0] = tempVerts[tempVerts.length - 1].setTexturePosition(uStart + 1.5F * uCircle, vStart + 0.5F * vCircle); - vert[1] = tempVerts[tempVerts.length - 2 - index].setTexturePosition(uStart + 1.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); - vert[2] = tempVerts[tempVerts.length - (1 + segments) + ((segments - index) % segments)].setTexturePosition(uStart + 1.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); - - poly[poly.length - segments + index] = new TexturedPolygon(vert); - if(mirror ^ flip) - poly[poly.length - segments + index].flipFace(); - } - copyTo(tempVerts, poly); - } - - /** - * Adds a Waveform .obj file as a model. Model files use the entire texture file. - * @param file the location of the .obj file. The location is relative to the base directories, - * which are either resources/models or resources/mods/models. - */ - public void addObj(String file) - { - addModel(file, ModelPool.OBJ); - } - - /** - * Adds model format support. Model files use the entire texture file. - * @param file the location of the model file. The location is relative to the base directories, - * which are either resources/models or resources/mods/models. - * @param modelFormat the class of the model format interpreter - */ - public void addModel(String file, Class modelFormat) - { - ModelPoolEntry entry = ModelPool.addFile(file, modelFormat, transformGroup, textureGroup); - if(entry == null) - return; - PositionTextureVertex[] verts = Arrays.copyOf(entry.vertices, entry.vertices.length); - TexturedPolygon[] poly = Arrays.copyOf(entry.faces, entry.faces.length); - if(flip) - { - for (TexturedPolygon face : faces) { - face.flipFace(); - } - } - - copyTo(verts, poly, false); - } - - /** - * Sets a new position for the texture offset. - * @param x the x-coordinate of the texture start - * @param y the y-coordinate of the texture start - */ - @Override - public ModelRendererTurbo setTextureOffset(int x, int y) - { - textureOffsetX = x; - textureOffsetY = y; - return this; - } - - /** - * Sets the position of the shape, relative to the model's origins. Note that changing - * the offsets will not change the pivot of the model. - * @param x the x-position of the shape - * @param y the y-position of the shape - * @param z the z-position of the shape - */ - public void setPosition(float x, float y, float z) - { - rotationPointX = x; - rotationPointY = y; - rotationPointZ = z; - } - - /** - * Mirrors the model in any direction. - * @param x whether the model should be mirrored in the x-direction - * @param y whether the model should be mirrored in the y-direction - * @param z whether the model should be mirrored in the z-direction - */ - public void doMirror(boolean x, boolean y, boolean z) - { - for (TexturedPolygon face : faces) { - PositionTextureVertex[] verts = face.vertexPositions; - for (int j = 0; j < verts.length; j++) { - verts[j].vector3D.xCoord *= (x ? -1 : 1); - verts[j].vector3D.yCoord *= (y ? -1 : 1); - verts[j].vector3D.zCoord *= (z ? -1 : 1); - } - if (x ^ y ^ z) - face.flipFace(); - } - } - - /** - * Sets whether the shape is mirrored or not. This has effect on the way the textures - * get displayed. When working with addSprite, addPixel and addObj, it will be ignored. - * @param isMirrored a boolean to define whether the shape is mirrored - */ - public void setMirrored(boolean isMirrored) - { - mirror = isMirrored; - } - - /** - * Sets whether the shape's faces are flipped or not. When GL_CULL_FACE is enabled, - * it won't render the back faces, effectively giving you the possibility to make - * "hollow" shapes. When working with addSprite and addPixel, it will be ignored. - * @param isFlipped a boolean to define whether the shape is flipped - */ - public void setFlipped(boolean isFlipped) - { - flip = isFlipped; - } - - /** - * Clears the current shape. Since all shapes are stacked into one shape, you can't - * just replace a shape by overwriting the shape with another one. In this case you - * would need to clear the shape first. - */ - public void clear() - { - vertices = new PositionTextureVertex[0]; - faces = new TexturedPolygon[0]; - transformGroup.clear(); - transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); - currentGroup = transformGroup.get("0"); - } - - /** - * Copies an array of vertices and polygons to the current shape. This mainly is - * used to copy each shape to the main class, but you can just use it to copy - * your own shapes, for example from other classes, into the current class. - * @param verts the array of vertices you want to copy - * @param poly the array of polygons you want to copy - */ - public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly) - { - copyTo(verts, poly, true); - } - - public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly, boolean copyGroup) - { - vertices = Arrays.copyOf(vertices, vertices.length + verts.length); - faces = Arrays.copyOf(faces, faces.length + poly.length); - - for(int idx = 0; idx < verts.length; idx++) - { - vertices[vertices.length - verts.length + idx] = verts[idx]; - if(copyGroup && verts[idx] instanceof PositionTransformVertex) - ((PositionTransformVertex)verts[idx]).addGroup(currentGroup); - } - - for(int idx = 0; idx < poly.length; idx++) - { - faces[faces.length - poly.length + idx] = poly[idx]; - if(copyGroup) - currentTextureGroup.addPoly(poly[idx]); - } - } - - /** - * Copies an array of vertices and quads to the current shape. This method - * converts quads to polygons and then calls the main copyTo method. - * @param verts the array of vertices you want to copy - * @param quad the array of quads you want to copy - */ - public void copyTo(PositionTextureVertex[] verts, TexturedQuad[] quad) - { - TexturedPolygon[] poly = new TexturedPolygon[quad.length]; - for(int idx = 0; idx < quad.length; idx++) - { - poly[idx] = new TexturedPolygon((PositionTextureVertex[])quad[idx].vertexPositions); - } - - copyTo(verts, poly); - } - - /** - * Sets the current transformation group. The transformation group is used - * to allow for vertex transformation. If a transformation group does not exist, - * a new one will be created. - * @param groupName the name of the transformation group you want to switch to - */ - public void setGroup(String groupName) - { - setGroup(groupName, new Bone(0, 0, 0, 0), 1D); - } - - /** - * Sets the current transformation group. The transformation group is used - * to allow for vertex transformation. If a transformation group does not exist, - * a new one will be created. - * @param groupName the name of the transformation group you want to switch to - * @param bone the Bone this transformation group is attached to - * @param weight the weight of the transformation group - */ - public void setGroup(String groupName, Bone bone, double weight) - { - if(!transformGroup.containsKey(groupName)) - transformGroup.put(groupName, new TransformGroupBone(bone, weight)); - currentGroup = transformGroup.get(groupName); - } - - /** - * Gets the current transformation group. - * @return the current PositionTransformGroup. - */ - public TransformGroup getGroup() - { - return currentGroup; - } - - /** - * Gets the transformation group with a given group name. - * @return the current PositionTransformGroup. - */ - public TransformGroup getGroup(String groupName) - { - if(!transformGroup.containsKey(groupName)) - return null; - return transformGroup.get(groupName); - } - - /** - * Sets the current texture group, which is used to switch the - * textures on a per-model base. Do note that any model that is - * rendered afterwards will use the same texture. To counter it, - * set a default texture, either at initialization or before - * rendering. - * @param groupName The name of the texture group. If the texture - * group doesn't exist, it creates a new group automatically. - */ - public void setTextureGroup(String groupName) - { - if(!textureGroup.containsKey(groupName)) - { - textureGroup.put(groupName, new TextureGroup()); - } - currentTextureGroup = textureGroup.get(groupName); - } - - /** - * Gets the current texture group. - * @return a TextureGroup object. - */ - public TextureGroup getTextureGroup() - { - return currentTextureGroup; - } - - /** - * Gets the texture group with the given name. - * @param groupName the name of the texture group to return - * @return a TextureGroup object. - */ - public TextureGroup getTextureGroup(String groupName) - { - if(!textureGroup.containsKey(groupName)) - return null; - return textureGroup.get(groupName); - } - - /** - * Sets the texture of the current texture group. - * @param s the filename - */ - public void setGroupTexture(String s) - { - currentTextureGroup.texture = s; - } - - /** - * Sets the default texture. When left as an empty string, - * it will use the texture that has been set previously. - * Note that this will also move on to other rendered models - * of the same entity. - * @param s the filename - */ - public void setDefaultTexture(String s) - { - defaultTexture = s; - } - - /** - * Renders the shape. - * @param worldScale the scale of the shape. Usually is 0.0625. - */ - @Override - public void render(float worldScale) - { - render(worldScale, false); - } - - - /** - * Renders the shape - * @param worldScale The scale of the shape - * @param oldRotateOrder Whether to use the old rotate order (ZYX) instead of the new one (YZX) - */ - public void render(float worldScale, boolean oldRotateOrder) - { - GL11.glPushMatrix(); - if(glow){ - glowOn(); - } - GL11.glAlphaFunc(GL11.GL_GREATER, 0.001F); - GL11.glEnable(GL11.GL_BLEND); - int srcBlend = GL11.glGetInteger(GL11.GL_BLEND_SRC); - int dstBlend = GL11.glGetInteger(GL11.GL_BLEND_DST); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - - if(field_1402_i) - { - return; - } - if(!showModel) - { - return; - } - if(!compiled || forcedRecompile) - { - compileDisplayList(worldScale); - } - if(rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) - { - GL11.glPushMatrix(); - GL11.glTranslatef(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); - if(!oldRotateOrder && rotateAngleY != 0.0F) - { - GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); - } - if(rotateAngleZ != 0.0F) - { - GL11.glRotatef((oldRotateOrder ? -1 : 1) * rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); - } - if(oldRotateOrder && rotateAngleY != 0.0F) - { - GL11.glRotatef(-rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); - } - if(rotateAngleX != 0.0F) - { - GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); - } - - callDisplayList(); - if(childModels != null) - { - for (Object childModel : childModels) { - ((ModelRenderer) childModel).render(worldScale); - } - - } - GL11.glPopMatrix(); - } else - if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) - { - GL11.glTranslatef(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); - callDisplayList(); - if(childModels != null) - { - for (Object childModel : childModels) { - ((ModelRenderer) childModel).render(worldScale); - } - - } - GL11.glTranslatef(-rotationPointX * worldScale, -rotationPointY * worldScale, -rotationPointZ * worldScale); - } else - { - callDisplayList(); - if(childModels != null) - { - for (Object childModel : childModels) { - ((ModelRenderer) childModel).render(worldScale); - } - - } - } - if(glow) { - glowOff(); - } - GL11.glBlendFunc(srcBlend, dstBlend); - GL11.glDisable(GL11.GL_BLEND); - GL11.glPopMatrix(); - } - - @Override - public void renderWithRotation(float f) - { - if(field_1402_i) - { - return; - } - if(!showModel) - { - return; - } - if(!compiled) - { - compileDisplayList(f); - } - GL11.glPushMatrix(); - GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); - if(rotateAngleY != 0.0F) - { - GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); - } - if(rotateAngleX != 0.0F) - { - GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); - } - if(rotateAngleZ != 0.0F) - { - GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); - } - callDisplayList(); - GL11.glPopMatrix(); - } - - @Override - public void postRender(float f) - { - if(field_1402_i) - { - return; - } - if(!showModel) - { - return; - } - if(!compiled || forcedRecompile) - { - compileDisplayList(f); - } - if(rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) - { - GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); - if(rotateAngleZ != 0.0F) - { - GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); - } - if(rotateAngleY != 0.0F) - { - GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); - } - if(rotateAngleX != 0.0F) - { - GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); - } - } else - if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) - { - GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); - } - } - - private void callDisplayList() - { - if(useLegacyCompiler) - GL11.glCallList(displayList); - else - { - TextureManager renderEngine = RenderManager.instance.renderEngine; - - Collection textures = textureGroup.values(); - - Iterator itr = textures.iterator(); - for(int i = 0; itr.hasNext(); i++) - { - TextureGroup curTexGroup = itr.next(); - curTexGroup.loadTexture(); - GL11.glCallList(displayListArray[i]); - if(!defaultTexture.equals("")) - renderEngine.bindTexture(new ResourceLocation("", defaultTexture)); //TODO : Check. Not sure about this one - } - } - } - - private void compileDisplayList(float worldScale) - { - if(useLegacyCompiler) - compileLegacyDisplayList(worldScale); - else - { - Collection textures = textureGroup.values(); - - Iterator itr = textures.iterator(); - displayListArray = new int[textureGroup.size()]; - for(int i = 0; itr.hasNext(); i++) - { - displayListArray[i] = GLAllocation.generateDisplayLists(1); - GL11.glNewList(displayListArray[i], GL11.GL_COMPILE); - TmtTessellator tessellator = TmtTessellator.instance; - - TextureGroup usedGroup = itr.next(); - for(int j = 0; j < usedGroup.poly.size(); j++) - { - usedGroup.poly.get(j).draw(tessellator, worldScale); - } - - GL11.glEndList(); - } - } - - compiled = true; - } - - private void compileLegacyDisplayList(float worldScale) - { - displayList = GLAllocation.generateDisplayLists(1); - GL11.glNewList(displayList, GL11.GL_COMPILE); - TmtTessellator tessellator = TmtTessellator.instance; - for (TexturedPolygon face : faces) { - face.draw(tessellator, worldScale); - } - - GL11.glEndList(); - } - - //lighting stuff - private static float lightmapLastX; +public class ModelRendererTurbo extends ModelRenderer { + public static final int MR_FRONT = 0; + public static final int MR_BACK = 1; + public static final int MR_LEFT = 2; + public static final int MR_RIGHT = 3; + public static final int MR_TOP = 4; + public static final int MR_BOTTOM = 5; + private static final float pi = (float) Math.PI; + //lighting stuff + private static float lightmapLastX; private static float lightmapLastY; - private static boolean optifineBreak = false; - - public static void glowOn() - { - glowOn(15); - } - - public static void glowOn(int glow) - { + private static boolean optifineBreak = false; + public final String boxName; + public boolean glow = false; + public boolean mirror; + public boolean flip; + public boolean showModel; + public boolean field_1402_i; + public boolean forcedRecompile; + public boolean useLegacyCompiler; + public List cubeList; + public List childModels; + private PositionTextureVertex[] vertices; + private TexturedPolygon[] faces; + private int textureOffsetX; + private int textureOffsetY; + private boolean compiled; + private int displayList; + private int[] displayListArray; + private final Map transformGroup; + private final Map textureGroup; + private TransformGroup currentGroup; + private TextureGroup currentTextureGroup; + private String defaultTexture; + + public ModelRendererTurbo(ModelBase modelbase, String s) { + super(modelbase, s); + flip = false; + compiled = false; + displayList = 0; + mirror = false; + showModel = true; + field_1402_i = false; + vertices = new PositionTextureVertex[0]; + faces = new TexturedPolygon[0]; + forcedRecompile = false; + transformGroup = new HashMap<>(); + transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); + textureGroup = new HashMap<>(); + textureGroup.put("0", new TextureGroup()); + currentTextureGroup = textureGroup.get("0"); + boxName = s; + + defaultTexture = ""; + + useLegacyCompiler = false; + } + + public ModelRendererTurbo(ModelBase modelbase) { + this(modelbase, null); + } + + /** + * Creates a new ModelRenderTurbo object. It requires the coordinates of the + * position of the texture. + * + * @param modelbase + * @param textureX the x-coordinate on the texture + * @param textureY the y-coordinate on the texture + */ + public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY) { + this(modelbase, textureX, textureY, 64, 32); + } + + /** + * Creates a new ModelRenderTurbo object. It requires the coordinates of the + * position of the texture, but also allows you to specify the width and height + * of the texture, allowing you to use bigger textures instead. + * + * @param modelbase + * @param textureX + * @param textureY + * @param textureU + * @param textureV + */ + public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY, int textureU, int textureV) { + this(modelbase); + textureOffsetX = textureX; + textureOffsetY = textureY; + textureWidth = textureU; + textureHeight = textureV; + } + + public static void glowOn() { + glowOn(15); + } + + public static void glowOn(int glow) { GL11.glPushAttrib(GL11.GL_LIGHTING_BIT); - + //GL11.glEnable(GL11.GL_BLEND); //GL11.glDisable(GL11.GL_ALPHA_TEST); //GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); - - - + + try { - lightmapLastX = OpenGlHelper.lastBrightnessX; - lightmapLastY = OpenGlHelper.lastBrightnessY; - } catch(NoSuchFieldError e) { - optifineBreak = true; + lightmapLastX = OpenGlHelper.lastBrightnessX; + lightmapLastY = OpenGlHelper.lastBrightnessY; + } catch (NoSuchFieldError e) { + optifineBreak = true; } - - float glowRatioX = Math.min((glow/15F)*240F + lightmapLastX, 240); - float glowRatioY = Math.min((glow/15F)*240F + lightmapLastY, 240); - - if(!optifineBreak) - { - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, glowRatioX, glowRatioY); + + float glowRatioX = Math.min((glow / 15F) * 240F + lightmapLastX, 240); + float glowRatioY = Math.min((glow / 15F) * 240F + lightmapLastY, 240); + + if (!optifineBreak) { + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, glowRatioX, glowRatioY); } } - public static void glowOff() - { - if(!optifineBreak) - { - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lightmapLastX, lightmapLastY); - } - + public static void glowOff() { + if (!optifineBreak) { + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lightmapLastX, lightmapLastY); + } + GL11.glPopAttrib(); } - private PositionTextureVertex vertices[]; - private TexturedPolygon faces[]; - private int textureOffsetX; - private int textureOffsetY; - private boolean compiled; - private int displayList; - private int displayListArray[]; - private Map transformGroup; - private Map textureGroup; - private TransformGroup currentGroup; - private TextureGroup currentTextureGroup; - public boolean mirror; - public boolean flip; - public boolean showModel; - public boolean field_1402_i; - public boolean forcedRecompile; - public boolean useLegacyCompiler; - public List cubeList; - public List childModels; - public final String boxName; - - private String defaultTexture; - - public static final int MR_FRONT = 0; - public static final int MR_BACK = 1; - public static final int MR_LEFT = 2; - public static final int MR_RIGHT = 3; - public static final int MR_TOP = 4; - public static final int MR_BOTTOM = 5; - - private static final float pi = (float) Math.PI; + /** + * Creates a new polygon. + * + * @param verts an array of vertices + */ + public void addPolygon(PositionTextureVertex[] verts) { + copyTo(verts, new TexturedPolygon[]{new TexturedPolygon(verts)}); + } + + /** + * Creates a new polygon, and adds UV mapping to it. + * + * @param verts an array of vertices + * @param uv an array of UV coordinates + */ + public void addPolygon(PositionTextureVertex[] verts, int[][] uv) { + try { + for (int i = 0; i < verts.length; i++) { + verts[i] = verts[i].setTexturePosition(uv[i][0] / textureWidth, uv[i][1] / textureHeight); + } + } finally { + addPolygon(verts); + } + } + + /** + * Creates a new polygon with a given UV. + * + * @param verts an array of vertices + * @param u1 + * @param v1 + * @param u2 + * @param v2 + */ + public void addPolygon(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) { + copyTo(verts, new TexturedPolygon[]{addPolygonReturn(verts, u1, v1, u2, v2)}); + } + + private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2, float q1, float q2, float q3, float q4) { + if (verts.length < 3) + return null; + float uOffs = 1.0F / (textureWidth * 10.0F); + float vOffs = 1.0F / (textureHeight * 10.0F); + if (verts.length < 4) { + float xMin = -1; + float yMin = -1; + float xMax = 0; + float yMax = 0; + + for (PositionTextureVertex vert : verts) { + float xPos = vert.texturePositionX; + float yPos = vert.texturePositionY; + xMax = Math.max(xMax, xPos); + xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); + yMax = Math.max(yMax, yPos); + yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); + } + float uMin = u1 / textureWidth + uOffs; + float vMin = v1 / textureHeight + vOffs; + float uSize = (u2 - u1) / textureWidth - uOffs * 2; + float vSize = (v2 - v1) / textureHeight - vOffs * 2; + + float xSize = xMax - xMin; + float ySize = yMax - yMin; + for (int i = 0; i < verts.length; i++) { + float xPos = verts[i].texturePositionX; + float yPos = verts[i].texturePositionY; + xPos = (xPos - xMin) / xSize; + yPos = (yPos - yMin) / ySize; + verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); + } + } else { + verts[0] = verts[0].setTexturePosition((u2 / textureWidth - uOffs) * q1, (v1 / textureHeight + vOffs) * q1, q1); + verts[1] = verts[1].setTexturePosition((u1 / textureWidth + uOffs) * q2, (v1 / textureHeight + vOffs) * q2, q2); + verts[2] = verts[2].setTexturePosition((u1 / textureWidth + uOffs) * q3, (v2 / textureHeight - vOffs) * q3, q3); + verts[3] = verts[3].setTexturePosition((u2 / textureWidth - uOffs) * q4, (v2 / textureHeight - vOffs) * q4, q4); + } + return new TexturedPolygon(verts); + } + + private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) { + if (verts.length < 3) + return null; + float uOffs = 1.0F / (textureWidth * 10.0F); + float vOffs = 1.0F / (textureHeight * 10.0F); + if (verts.length < 4) { + float xMin = -1; + float yMin = -1; + float xMax = 0; + float yMax = 0; + + for (PositionTextureVertex vert : verts) { + float xPos = vert.texturePositionX; + float yPos = vert.texturePositionY; + xMax = Math.max(xMax, xPos); + xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); + yMax = Math.max(yMax, yPos); + yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); + } + float uMin = u1 / textureWidth + uOffs; + float vMin = v1 / textureHeight + vOffs; + float uSize = (u2 - u1) / textureWidth - uOffs * 2; + float vSize = (v2 - v1) / textureHeight - vOffs * 2; + + float xSize = xMax - xMin; + float ySize = yMax - yMin; + for (int i = 0; i < verts.length; i++) { + float xPos = verts[i].texturePositionX; + float yPos = verts[i].texturePositionY; + xPos = (xPos - xMin) / xSize; + yPos = (yPos - yMin) / ySize; + verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); + } + } else { + verts[0] = verts[0].setTexturePosition(u2 / textureWidth - uOffs, v1 / textureHeight + vOffs); + verts[1] = verts[1].setTexturePosition(u1 / textureWidth + uOffs, v1 / textureHeight + vOffs); + verts[2] = verts[2].setTexturePosition(u1 / textureWidth + uOffs, v2 / textureHeight - vOffs); + verts[3] = verts[3].setTexturePosition(u2 / textureWidth - uOffs, v2 / textureHeight - vOffs); + } + return new TexturedPolygon(verts); + } + + /** + * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, + * as the method requires eight vector coordinates. + * + * @param v a float array with three values, the x, y and z coordinates of the vertex + * @param v1 a float array with three values, the x, y and z coordinates of the vertex + * @param v2 a float array with three values, the x, y and z coordinates of the vertex + * @param v3 a float array with three values, the x, y and z coordinates of the vertex + * @param v4 a float array with three values, the x, y and z coordinates of the vertex + * @param v5 a float array with three values, the x, y and z coordinates of the vertex + * @param v6 a float array with three values, the x, y and z coordinates of the vertex + * @param v7 a float array with three values, the x, y and z coordinates of the vertex + * @param w the width of the shape, used in determining the texture + * @param h the height of the shape, used in determining the texture + * @param d the depth of the shape, used in determining the texture + */ + public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d) { + float[] var1 = new float[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d, var1); + } + + /** + * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, + * as the method requires eight vector coordinates. Also does some special texture mapping. + * + * @param v a float array with three values, the x, y and z coordinates of the vertex + * @param v1 a float array with three values, the x, y and z coordinates of the vertex + * @param v2 a float array with three values, the x, y and z coordinates of the vertex + * @param v3 a float array with three values, the x, y and z coordinates of the vertex + * @param v4 a float array with three values, the x, y and z coordinates of the vertex + * @param v5 a float array with three values, the x, y and z coordinates of the vertex + * @param v6 a float array with three values, the x, y and z coordinates of the vertex + * @param v7 a float array with three values, the x, y and z coordinates of the vertex + * @param w the width of the shape, used in determining the texture + * @param h the height of the shape, used in determining the texture + * @param d the depth of the shape, used in determining the texture + * @param qParam Array containing the q parameters in the order xBack, xBottom, xFront, xTop, yBack, yFront, yLeft, yRight, zBottom, zLeft, zRight, zTop + */ + public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d, float[] qParam) { + PositionTextureVertex[] verts = new PositionTextureVertex[8]; + TexturedPolygon[] poly = new TexturedPolygon[6]; + PositionTextureVertex positionTexturevertex = new PositionTextureVertex(v[0], v[1], v[2], 0.0F, 0.0F); + PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(v1[0], v1[1], v1[2], 0.0F, 8F); + PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(v2[0], v2[1], v2[2], 8F, 8F); + PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(v3[0], v3[1], v3[2], 8F, 0.0F); + PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(v4[0], v4[1], v4[2], 0.0F, 0.0F); + PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(v5[0], v5[1], v5[2], 0.0F, 8F); + PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(v6[0], v6[1], v6[2], 8F, 8F); + PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(v7[0], v7[1], v7[2], 8F, 0.0F); + verts[0] = positionTexturevertex; + verts[1] = positionTexturevertex1; + verts[2] = positionTexturevertex2; + verts[3] = positionTexturevertex3; + verts[4] = positionTexturevertex4; + verts[5] = positionTexturevertex5; + verts[6] = positionTexturevertex6; + verts[7] = positionTexturevertex7; + poly[0] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 + }, textureOffsetX + d + w, textureOffsetY + d, textureOffsetX + d + w + d, textureOffsetY + d + h, + 1F, qParam[7], qParam[10] * qParam[7], qParam[10]); + poly[1] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 + }, textureOffsetX, textureOffsetY + d, textureOffsetX + d, textureOffsetY + d + h, + qParam[9] * qParam[6], qParam[9], 1F, qParam[6]); + poly[2] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 + }, textureOffsetX + d, textureOffsetY, textureOffsetX + d + w, textureOffsetY + d, + 1F, qParam[8], qParam[1] * qParam[8], qParam[1]); + poly[3] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 + }, textureOffsetX + d + w, textureOffsetY, textureOffsetX + d + w + w, textureOffsetY + d, + qParam[3], qParam[3] * qParam[11], qParam[11], 1F); + poly[4] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 + }, textureOffsetX + d, textureOffsetY + d, textureOffsetX + d + w, textureOffsetY + d + h, + qParam[0], qParam[0] * qParam[4], qParam[4], 1F); + poly[5] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 + }, textureOffsetX + d + w + d, textureOffsetY + d, textureOffsetX + d + w + d + w, textureOffsetY + d + h, + qParam[2] * qParam[5], qParam[2], 1F, qParam[5]); + if (mirror ^ flip) { + for (TexturedPolygon aPoly : poly) { + aPoly.flipFace(); + } + + } + + copyTo(verts, poly); + } + + /** + * Adds a new box to the model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + */ + @Override + public ModelRendererTurbo addBox(float x, float y, float z, int w, int h, int d) { + addBox(x, y, z, w, h, d, 0.0F); + return this; + } + + /** + * Adds a new box to the model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param expansion the expansion of the box. It increases the size in each direction by that many. + */ + @Override + public void addBox(float x, float y, float z, int w, int h, int d, float expansion) { + addBox(x, y, z, w, h, d, expansion, 1F); + } + + /** + * Adds a new box to the model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param expansion the expansion of the box. It increases the size in each direction by that many. It's independent from the scale. + * @param scale + */ + public void addBox(float x, float y, float z, int w, int h, int d, float expansion, float scale) { + float scaleX = w * scale; + float scaleY = h * scale; + float scaleZ = d * scale; + + float x1 = x + scaleX; + float y1 = y + scaleY; + float z1 = z + scaleZ; + + float expX = expansion + scaleX - w; + float expY = expansion + scaleY - h; + float expZ = expansion + scaleZ - d; + + x -= expX; + y -= expY; + z -= expZ; + x1 += expansion; + y1 += expansion; + z1 += expansion; + if (mirror) { + float xTemp = x1; + x1 = x; + x = xTemp; + } + + float[] v = {x, y, z}; + float[] v1 = {x1, y, z}; + float[] v2 = {x1, y1, z}; + float[] v3 = {x, y1, z}; + float[] v4 = {x, y, z1}; + float[] v5 = {x1, y, z1}; + float[] v6 = {x1, y1, z1}; + float[] v7 = {x, y1, z1}; + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); + } + + /** + * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. + * You can use the static variables MR_RIGHT, MR_LEFT, + * MR_FRONT, MR_BACK, MR_TOP and + * MR_BOTTOM. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param scale the "scale" of the box. It only increases the size in each direction by that many. + * @param bottomScale the "scale" of the bottom + * @param dir the side the scaling is applied to + */ + public void addTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bottomScale, int dir) { + float f4 = x + w; + float f5 = y + h; + float f6 = z + d; + x -= scale; + y -= scale; + z -= scale; + f4 += scale; + f5 += scale; + f6 += scale; + + int m = (mirror ? -1 : 1); + if (mirror) { + float f7 = f4; + f4 = x; + x = f7; + } + + float[] v = {x, y, z}; + float[] v1 = {f4, y, z}; + float[] v2 = {f4, f5, z}; + float[] v3 = {x, f5, z}; + float[] v4 = {x, y, f6}; + float[] v5 = {f4, y, f6}; + float[] v6 = {f4, f5, f6}; + float[] v7 = {x, f5, f6}; + + switch (dir) { + case MR_RIGHT: + v[1] -= bottomScale; + v[2] -= bottomScale; + v3[1] += bottomScale; + v3[2] -= bottomScale; + v4[1] -= bottomScale; + v4[2] += bottomScale; + v7[1] += bottomScale; + v7[2] += bottomScale; + break; + case MR_LEFT: + v1[1] -= bottomScale; + v1[2] -= bottomScale; + v2[1] += bottomScale; + v2[2] -= bottomScale; + v5[1] -= bottomScale; + v5[2] += bottomScale; + v6[1] += bottomScale; + v6[2] += bottomScale; + break; + case MR_FRONT: + v[0] -= m * bottomScale; + v[1] -= bottomScale; + v1[0] += m * bottomScale; + v1[1] -= bottomScale; + v2[0] += m * bottomScale; + v2[1] += bottomScale; + v3[0] -= m * bottomScale; + v3[1] += bottomScale; + break; + case MR_BACK: + v4[0] -= m * bottomScale; + v4[1] -= bottomScale; + v5[0] += m * bottomScale; + v5[1] -= bottomScale; + v6[0] += m * bottomScale; + v6[1] += bottomScale; + v7[0] -= m * bottomScale; + v7[1] += bottomScale; + break; + case MR_TOP: + v[0] -= m * bottomScale; + v[2] -= bottomScale; + v1[0] += m * bottomScale; + v1[2] -= bottomScale; + v4[0] -= m * bottomScale; + v4[2] += bottomScale; + v5[0] += m * bottomScale; + v5[2] += bottomScale; + break; + case MR_BOTTOM: + v2[0] += m * bottomScale; + v2[2] -= bottomScale; + v3[0] -= m * bottomScale; + v3[2] -= bottomScale; + v6[0] += m * bottomScale; + v6[2] += bottomScale; + v7[0] -= m * bottomScale; + v7[2] += bottomScale; + break; + } + + float[] qValues = new float[]{ + Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), + Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), + Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), + Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), + + Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), + Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), + Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), + Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), + + Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), + Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), + Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), + Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) + }; + + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); + } + + /** + * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. + * You can use the static variables MR_RIGHT, MR_LEFT, + * MR_FRONT, MR_BACK, MR_TOP and + * MR_BOTTOM. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param scale the "scale" of the box. It only increases the size in each direction by that many. + * @param bScale1 the "scale" of the bottom - Top + * @param bScale2 the "scale" of the bottom - Bottom + * @param bScale3 the "scale" of the bottom - Left + * @param bScale4 the "scale" of the bottom - Right + * @param dir the side the scaling is applied to + */ + public void addFlexBox(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, int dir) { + float f4 = x + w; + float f5 = y + h; + float f6 = z + d; + x -= scale; + y -= scale; + z -= scale; + f4 += scale; + f5 += scale; + f6 += scale; + + int m = (mirror ? -1 : 1); + if (mirror) { + float f7 = f4; + f4 = x; + x = f7; + } + + float[] v = {x, y, z}; + float[] v1 = {f4, y, z}; + float[] v2 = {f4, f5, z}; + float[] v3 = {x, f5, z}; + float[] v4 = {x, y, f6}; + float[] v5 = {f4, y, f6}; + float[] v6 = {f4, f5, f6}; + float[] v7 = {x, f5, f6}; + + switch (dir) { + case MR_RIGHT: + v[1] -= bScale1; + v[2] -= bScale3; + v3[1] += bScale2; + v3[2] -= bScale3; + v4[1] -= bScale1; + v4[2] += bScale4; + v7[1] += bScale2; + v7[2] += bScale4; + break; + case MR_LEFT: + v1[1] -= bScale1; + v1[2] -= bScale3; + v2[1] += bScale2; + v2[2] -= bScale3; + v5[1] -= bScale1; + v5[2] += bScale4; + v6[1] += bScale2; + v6[2] += bScale4; + break; + case MR_FRONT: + v[0] -= m * bScale4; + v[1] -= bScale1; + v1[0] += m * bScale3; + v1[1] -= bScale1; + v2[0] += m * bScale3; + v2[1] += bScale2; + v3[0] -= m * bScale4; + v3[1] += bScale2; + break; + case MR_BACK: + v4[0] -= m * bScale4; + v4[1] -= bScale1; + v5[0] += m * bScale3; + v5[1] -= bScale1; + v6[0] += m * bScale3; + v6[1] += bScale2; + v7[0] -= m * bScale4; + v7[1] += bScale2; + break; + case MR_TOP: + v[0] -= m * bScale1; + v[2] -= bScale3; + v1[0] += m * bScale2; + v1[2] -= bScale3; + v4[0] -= m * bScale1; + v4[2] += bScale4; + v5[0] += m * bScale2; + v5[2] += bScale4; + break; + case MR_BOTTOM: + v2[0] += m * bScale2; + v2[2] -= bScale3; + v3[0] -= m * bScale1; + v3[2] -= bScale3; + v6[0] += m * bScale2; + v6[2] += bScale4; + v7[0] -= m * bScale1; + v7[2] += bScale4; + break; + } + + float[] qValues = new float[]{ + Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), + Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), + Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), + Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), + + Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), + Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), + Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), + Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), + + Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), + Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), + Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), + Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) + }; + + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); + } + + /** + * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. + * You can use the static variables MR_RIGHT, MR_LEFT, + * MR_FRONT, MR_BACK, MR_TOP and + * MR_BOTTOM. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param scale the "scale" of the box. It only increases the size in each direction by that many. + * @param bScale1 the "scale" of the bottom - Top + * @param bScale2 the "scale" of the bottom - Bottom + * @param bScale3 the "scale" of the bottom - Left + * @param bScale4 the "scale" of the bottom - Right + * @param fScale1 the "scale" of the top - Left + * @param fScale2 the "scale" of the top - Right + * @param dir the side the scaling is applied to + */ + public void addFlexTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, float fScale1, float fScale2, int dir) { + float f4 = x + w; + float f5 = y + h; + float f6 = z + d; + x -= scale; + y -= scale; + z -= scale; + f4 += scale; + f5 += scale; + f6 += scale; + + int m = (mirror ? -1 : 1); + if (mirror) { + float f7 = f4; + f4 = x; + x = f7; + } + + float[] v = {x, y, z}; + float[] v1 = {f4, y, z}; + float[] v2 = {f4, f5, z}; + float[] v3 = {x, f5, z}; + float[] v4 = {x, y, f6}; + float[] v5 = {f4, y, f6}; + float[] v6 = {f4, f5, f6}; + float[] v7 = {x, f5, f6}; + + + switch (dir) { + case MR_RIGHT: + v[2] -= fScale1; + v1[2] -= fScale1; + v4[2] += fScale2; + v5[2] += fScale2; + + v[1] -= bScale1; + v[2] -= bScale3; + v3[1] += bScale2; + v3[2] -= bScale3; + v4[1] -= bScale1; + v4[2] += bScale4; + v7[1] += bScale2; + v7[2] += bScale4; + break; + case MR_LEFT: + v[2] -= fScale1; + v1[2] -= fScale1; + v4[2] += fScale2; + v5[2] += fScale2; + + v1[1] -= bScale1; + v1[2] -= bScale3; + v2[1] += bScale2; + v2[2] -= bScale3; + v5[1] -= bScale1; + v5[2] += bScale4; + v6[1] += bScale2; + v6[2] += bScale4; + break; + case MR_FRONT: + v1[1] -= fScale1; + v5[1] -= fScale1; + v2[1] += fScale2; + v6[1] += fScale2; + + v[0] -= m * bScale4; + v[1] -= bScale1; + v1[0] += m * bScale3; + v1[1] -= bScale1; + v2[0] += m * bScale3; + v2[1] += bScale2; + v3[0] -= m * bScale4; + v3[1] += bScale2; + break; + case MR_BACK: + v1[1] -= fScale1; + v5[1] -= fScale1; + v2[1] += fScale2; + v6[1] += fScale2; + + v4[0] -= m * bScale4; + v4[1] -= bScale1; + v5[0] += m * bScale3; + v5[1] -= bScale1; + v6[0] += m * bScale3; + v6[1] += bScale2; + v7[0] -= m * bScale4; + v7[1] += bScale2; + break; + case MR_TOP: + v1[2] -= fScale1; + v2[2] -= fScale1; + v5[2] += fScale2; + v6[2] += fScale2; + + v[0] -= m * bScale1; + v[2] -= bScale3; + v1[0] += m * bScale2; + v1[2] -= bScale3; + v4[0] -= m * bScale1; + v4[2] += bScale4; + v5[0] += m * bScale2; + v5[2] += bScale4; + break; + case MR_BOTTOM: + v1[2] -= fScale1; + v2[2] -= fScale1; + v5[2] += fScale2; + v6[2] += fScale2; + + v2[0] += m * bScale2; + v2[2] -= bScale3; + v3[0] -= m * bScale1; + v3[2] -= bScale3; + v6[0] += m * bScale2; + v6[2] += bScale4; + v7[0] -= m * bScale1; + v7[2] += bScale4; + break; + } + + float[] qValues = new float[]{ + Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), + Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), + Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), + Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), + + Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), + Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), + Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), + Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), + + Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), + Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), + Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), + Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) + }; + + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); + } + + /** + * Adds a box with float width, height and depth. Who knows what it will do to the texture. + * + * @param x the starting x-positions + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + */ + public void addBox(float x, float y, float z, float w, float h, float d) { + int rw = MathHelper.ceiling_float_int(w); + int rh = MathHelper.ceiling_float_int(h); + int rd = MathHelper.ceiling_float_int(d); + w -= rw; + h -= rh; + d -= rd; + addShapeBox(x, y, z, rw, rh, rd, 0F, + 0F, 0F, 0F, + w, 0F, 0F, + w, 0F, d, + 0F, 0F, d, + 0F, h, 0F, + w, h, 0F, + w, h, d, + 0F, h, d); + } + + /** + * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. + * You can use the static variables MR_RIGHT, MR_LEFT, + * MR_FRONT, MR_BACK, MR_TOP and + * MR_BOTTOM. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param scale the "scale" of the box. It only increases the size in each direction by that many. + * @param x0,y0,z0 - x7,y7,z7 the modifiers of the box corners. each corner can changed seperat by x/y/z values + */ + public void addShapeBox(float x, float y, float z, int w, int h, int d, float scale, float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float x5, float y5, float z5, float x6, float y6, float z6, float x7, float y7, float z7) { + float f4 = x + w; + float f5 = y + h; + float f6 = z + d; + x -= scale; + y -= scale; + z -= scale; + f4 += scale; + f5 += scale; + f6 += scale; + + int m = (mirror ? -1 : 1); + if (mirror) { + float f7 = f4; + f4 = x; + x = f7; + } + + float[] v = {x - x0, y - y0, z - z0}; + float[] v1 = {f4 + x1, y - y1, z - z1}; + float[] v2 = {f4 + x5, f5 + y5, z - z5}; + float[] v3 = {x - x4, f5 + y4, z - z4}; + float[] v4 = {x - x3, y - y3, f6 + z3}; + float[] v5 = {f4 + x2, y - y2, f6 + z2}; + float[] v6 = {f4 + x6, f5 + y6, f6 + z6}; + float[] v7 = {x - x7, f5 + y7, f6 + z7}; + + float[] qValues = new float[]{ + Math.abs((v[0] - v1[0]) / (v3[0] - v2[0])), + Math.abs((v[0] - v1[0]) / (v4[0] - v5[0])), + Math.abs((v4[0] - v5[0]) / (v7[0] - v6[0])), + Math.abs((v3[0] - v2[0]) / (v7[0] - v6[0])), + + Math.abs((v[1] - v3[1]) / (v1[1] - v2[1])), + Math.abs((v4[1] - v7[1]) / (v5[1] - v6[1])), + Math.abs((v[1] - v3[1]) / (v4[1] - v7[1])), + Math.abs((v1[1] - v2[1]) / (v5[1] - v6[1])), + + Math.abs((v[2] - v4[2]) / (v1[2] - v5[2])), + Math.abs((v[2] - v4[2]) / (v3[2] - v7[2])), + Math.abs((v1[2] - v5[2]) / (v2[2] - v6[2])), + Math.abs((v3[2] - v7[2]) / (v2[2] - v6[2])) + }; + + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an array of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + */ + public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { + addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an array of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + * @param faceLengths An array with the length of each face. Used to set + * the texture width of each face on the side manually. + */ + public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { + addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an ArrayList of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + */ + public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { + addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an ArrayList of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + * @param faceLengths An array with the length of each face. Used to set + * the texture width of each face on the side manually. + */ + public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { + addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param shape a Shape2D which contains the coordinates of the shape points + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + */ + public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { + addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param shape a Shape2D which contains the coordinates of the shape points + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + * @param faceLengths An array with the length of each face. Used to set + * the texture width of each face on the side manually. + */ + public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { + float rotX = 0; + float rotY = 0; + float rotZ = 0; + switch (direction) { + case MR_LEFT: + rotY = pi / 2; + break; + case MR_RIGHT: + rotY = -pi / 2; + break; + case MR_TOP: + rotX = pi / 2; + break; + case MR_BOTTOM: + rotX = -pi / 2; + break; + case MR_FRONT: + rotY = pi; + break; + case MR_BACK: + break; + } + addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, faceLengths); + } + + /** + * Creates a shape from a 2D vector shape. + * + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param shape a Shape2D which contains the coordinates of the shape points + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param rotX the rotation around the x-axis + * @param rotY the rotation around the y-axis + * @param rotZ the rotation around the z-axis + */ + public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ) { + addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, null); + } + + public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ, float[] faceLengths) { + Shape3D shape3D = shape.extrude(x, y, z, rotX, rotY, rotZ, depth, textureOffsetX, textureOffsetY, textureWidth, textureHeight, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, faceLengths); + + if (flip) { + for (int idx = 0; idx < shape3D.faces.length; idx++) { + shape3D.faces[idx].flipFace(); + } + } + + copyTo(shape3D.vertices, shape3D.faces); + } + + /** + * Adds a cube the size of one pixel. It will take a pixel from the texture and + * uses that as the texture of said cube. The accurate name would actually be + * "addVoxel". This method has been added to make it more compatible with Techne, + * and allows for easy single-colored boxes. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param width the width of the box + * @param height the height of the box + * @param length the length of the box + */ + public void addPixel(float x, float y, float z, float width, float height, float length) { + addPixel(x, y, z, new float[]{width, height, length}, textureOffsetX, textureOffsetY); + } + + /** + * Adds a cube the size of one pixel. It will take a pixel from the texture and + * uses that as the texture of said cube. The accurate name would actually be + * "addVoxel". It will not overwrite the model data, but rather, it will add to + * the model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param scale the "scale" of the cube, where scale is a float integer consisting of three values + * @param w the x-coordinate on the texture + * @param h the y-coordinate on the texture + */ + public void addPixel(float x, float y, float z, float[] scale, int w, int h) { + PositionTextureVertex[] verts = new PositionTextureVertex[8]; + TexturedPolygon[] poly = new TexturedPolygon[6]; + + float x1 = x + scale[0]; + float y1 = y + scale[1]; + float z1 = z + scale[2]; + + float[] f = {x, y, z}; + float[] f1 = {x1, y, z}; + float[] f2 = {x1, y1, z}; + float[] f3 = {x, y1, z}; + float[] f4 = {x, y, z1}; + float[] f5 = {x1, y, z1}; + float[] f6 = {x1, y1, z1}; + float[] f7 = {x, y1, z1}; + PositionTextureVertex positionTexturevertex = new PositionTextureVertex(f[0], f[1], f[2], 0.0F, 0.0F); + PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(f1[0], f1[1], f1[2], 0.0F, 8F); + PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(f2[0], f2[1], f2[2], 8F, 8F); + PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(f3[0], f3[1], f3[2], 8F, 0.0F); + PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(f4[0], f4[1], f4[2], 0.0F, 0.0F); + PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(f5[0], f5[1], f5[2], 0.0F, 8F); + PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(f6[0], f6[1], f6[2], 8F, 8F); + PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(f7[0], f7[1], f7[2], 8F, 0.0F); + + verts[0] = positionTexturevertex; + verts[1] = positionTexturevertex1; + verts[2] = positionTexturevertex2; + verts[3] = positionTexturevertex3; + verts[4] = positionTexturevertex4; + verts[5] = positionTexturevertex5; + verts[6] = positionTexturevertex6; + verts[7] = positionTexturevertex7; + + poly[0] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 + }, w, h, w + 1, h + 1); + poly[1] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 + }, w, h, w + 1, h + 1); + poly[2] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 + }, w, h, w + 1, h + 1); + poly[3] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 + }, w, h, w + 1, h + 1); + poly[4] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 + }, w, h, w + 1, h + 1); + poly[5] = addPolygonReturn(new PositionTextureVertex[]{ + positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 + }, w, h, w + 1, h + 1); + + copyTo(verts, poly); + } + + /** + * Creates a model shaped like the exact image on the texture. Note that this method will + * increase the amount of quads on your model, which could effectively slow down your + * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this + * method to create your model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width of the sprite + * @param h the height of the sprite + * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. + */ + public void addSprite(float x, float y, float z, int w, int h, float expansion) { + addSprite(x, y, z, w, h, 1, false, false, false, false, false, expansion); + } + + /** + * Creates a model shaped like the exact image on the texture. Note that this method will + * increase the amount of quads on your model, which could effectively slow down your + * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this + * method to create your model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width of the sprite + * @param h the height of the sprite + * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis + * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis + * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis + * @param mirrorX a boolean to define if the sprite should be mirrored + * @param mirrorY a boolean to define if the sprite should be flipped + * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. + */ + public void addSprite(float x, float y, float z, int w, int h, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { + addSprite(x, y, z, w, h, 1, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); + } + + /** + * Creates a model shaped like the exact image on the texture. Note that this method will + * increase the amount of quads on your model, which could effectively slow down your + * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this + * method to create your model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width of the sprite + * @param h the height of the sprite + * @param d the depth of the shape itself + * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis + * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis + * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis + * @param mirrorX a boolean to define if the sprite should be mirrored + * @param mirrorY a boolean to define if the sprite should be flipped + * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. + */ + public void addSprite(float x, float y, float z, int w, int h, int d, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { + addSprite(x, y, z, w, h, d, 1.0F, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); + } + + /** + * Creates a model shaped like the exact image on the texture. Note that this method will + * increase the amount of quads on your model, which could effectively slow down your + * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this + * method to create your model. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width of the sprite + * @param h the height of the sprite + * @param d the depth of the shape itself + * @param pixelScale the scale of each individual pixel + * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis + * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis + * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis + * @param mirrorX a boolean to define if the sprite should be mirrored + * @param mirrorY a boolean to define if the sprite should be flipped + * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. + */ + public void addSprite(float x, float y, float z, int w, int h, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { + String[] mask = new String[h]; + char[] str = new char[w]; + Arrays.fill(str, '1'); + Arrays.fill(mask, new String(str)); + + addSprite(x, y, z, mask, d, pixelScale, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); + } + + /** + * Creates a model shaped like the exact image on the texture. Note that this method will + * increase the amount of quads on your model, which could effectively slow down your + * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this + * method to create your model. + *

+ * This method uses a mask string. This way you can reduce the amount of quads used. To + * use this, create a String array, where you use a 1 to signify that the pixel will be + * drawn. Any other character will cause that pixel to not be drawn. + * + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param mask an array with the mask string + * @param d the depth of the shape itself + * @param pixelScale the scale of each individual pixel + * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis + * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis + * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis + * @param mirrorX a boolean to define if the sprite should be mirrored + * @param mirrorY a boolean to define if the sprite should be flipped + * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. + */ + public void addSprite(float x, float y, float z, String[] mask, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { + int w = mask[0].length(); + int h = mask.length; + + float x1 = x - expansion; + float y1 = y - expansion; + float z1 = z - expansion; + + int wDir = 0; + int hDir = 0; + int dDir = 0; + + float wScale = 1F + (expansion / (w * pixelScale)); + float hScale = 1F + (expansion / (h * pixelScale)); + + if (!rotX) { + if (!rotY) { + if (!rotZ) { + wDir = 0; + hDir = 1; + dDir = 2; + } else { + wDir = 1; + hDir = 0; + dDir = 2; + } + } else { + if (!rotZ) { + wDir = 2; + hDir = 1; + dDir = 0; + } else { + wDir = 2; + hDir = 0; + dDir = 1; + } + } + } else { + if (!rotY) { + if (!rotZ) { + wDir = 0; + hDir = 2; + dDir = 1; + } else { + wDir = 1; + hDir = 2; + dDir = 0; + } + } else { + if (!rotZ) { + wDir = 2; + hDir = 0; + dDir = 1; + } else { + wDir = 2; + hDir = 1; + dDir = 0; + } + } + } + + int texStartX = textureOffsetX + (mirrorX ? w - 1 : 0); + int texStartY = textureOffsetY + (mirrorY ? h - 1 : 0); + int texDirX = (mirrorX ? -1 : 1); + int texDirY = (mirrorY ? -1 : 1); + + float wVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, wDir, 1, 1); + float hVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, hDir, 1, 1); + float dVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, dDir, 1, 1); + + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + if (mask[j].charAt(i) == '1') { + addPixel(x1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 0, i, j), + y1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 1, i, j), + z1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 2, i, j), + new float[]{wVoxSize, hVoxSize, dVoxSize}, texStartX + texDirX * i, texStartY + texDirY * j); + } + } + } + } + + private float getPixelSize(float wScale, float hScale, float dScale, int wDir, int hDir, int checkDir, int texPosX, int texPosY) { + return (wDir == checkDir ? wScale * texPosX : (hDir == checkDir ? hScale * texPosY : dScale)); + } + + /** + * Adds a spherical shape. + * + * @param x + * @param y + * @param z + * @param r + * @param segs + * @param rings + * @param textureW + * @param textureH + */ + public void addSphere(float x, float y, float z, float r, int segs, int rings, int textureW, int textureH) { + if (segs < 3) + segs = 3; + rings++; + PositionTextureVertex[] tempVerts = new PositionTextureVertex[segs * (rings - 1) + 2]; + TexturedPolygon[] poly = new TexturedPolygon[segs * rings]; + + tempVerts[0] = new PositionTextureVertex(x, y - r, z, 0, 0); + tempVerts[tempVerts.length - 1] = new PositionTextureVertex(x, y + r, z, 0, 0); + + float uOffs = 1.0F / (textureWidth * 10.0F); + float vOffs = 1.0F / (textureHeight * 10.0F); + float texW = textureW / textureWidth - 2F * uOffs; + float texH = textureH / textureHeight - 2F * vOffs; + float segW = texW / segs; + float segH = texH / rings; + float startU = textureOffsetX / textureWidth; + float startV = textureOffsetY / textureHeight; + + int currentFace = 0; + + for (int j = 1; j < rings; j++) { + for (int i = 0; i < segs; i++) { + float yWidth = MathHelper.cos(-pi / 2 + (pi / rings) * j); + float yHeight = MathHelper.sin(-pi / 2 + (pi / rings) * j); + float xSize = MathHelper.sin((pi / segs) * i * 2F + pi) * yWidth; + float zSize = -MathHelper.cos((pi / segs) * i * 2F + pi) * yWidth; + int curVert = 1 + i + segs * (j - 1); + tempVerts[curVert] = new PositionTextureVertex(x + xSize * r, y + yHeight * r, z + zSize * r, 0, 0); + if (i > 0) { + PositionTextureVertex[] verts; + if (j == 1) { + verts = new PositionTextureVertex[4]; + verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); + verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); + verts[2] = tempVerts[0].setTexturePosition(startU + segW * (i - 1), startV); + verts[3] = tempVerts[0].setTexturePosition(startU + segW + segW * i, startV); + } else { + verts = new PositionTextureVertex[4]; + verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); + verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); + verts[2] = tempVerts[curVert - 1 - segs].setTexturePosition(startU + segW * (i - 1), startV + segH * (j - 1)); + verts[3] = tempVerts[curVert - segs].setTexturePosition(startU + segW * i, startV + segH * (j - 1)); + } + poly[currentFace] = new TexturedPolygon(verts); + currentFace++; + } + } + PositionTextureVertex[] verts; + if (j == 1) { + verts = new PositionTextureVertex[4]; + verts[0] = tempVerts[1].setTexturePosition(startU + segW * segs, startV + segH * j); + verts[1] = tempVerts[segs].setTexturePosition(startU + segW * (segs - 1), startV + segH * j); + verts[2] = tempVerts[0].setTexturePosition(startU + segW * (segs - 1), startV); + verts[3] = tempVerts[0].setTexturePosition(startU + segW * segs, startV); + } else { + verts = new PositionTextureVertex[4]; + verts[0] = tempVerts[1 + segs * (j - 1)].setTexturePosition(startU + texW, startV + segH * j); + verts[1] = tempVerts[segs * (j - 1) + segs].setTexturePosition(startU + texW - segW, startV + segH * j); + verts[2] = tempVerts[segs * (j - 1)].setTexturePosition(startU + texW - segW, startV + segH * (j - 1)); + verts[3] = tempVerts[1 + segs * (j - 1) - segs].setTexturePosition(startU + texW, startV + segH * (j - 1)); + } + poly[currentFace] = new TexturedPolygon(verts); + currentFace++; + } + for (int i = 0; i < segs; i++) { + PositionTextureVertex[] verts = new PositionTextureVertex[3]; + int curVert = tempVerts.length - (segs + 1); + verts[0] = tempVerts[tempVerts.length - 1].setTexturePosition(startU + segW * (i + 0.5F), startV + texH); + verts[1] = tempVerts[curVert + i].setTexturePosition(startU + segW * i, startV + texH - segH); + verts[2] = tempVerts[curVert + ((i + 1) % segs)].setTexturePosition(startU + segW * (i + 1), startV + texH - segH); + poly[currentFace] = new TexturedPolygon(verts); + currentFace++; + } + + copyTo(tempVerts, poly); + } + + /** + * Adds a cone. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + */ + public void addCone(float x, float y, float z, float radius, float length, int segments) { + addCone(x, y, z, radius, length, segments, 1F); + } + + /** + * Adds a cone. + *

+ * baseScale cannot be zero. If it is, it will automatically be set to 1F. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + */ + public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale) { + addCone(x, y, z, radius, length, segments, baseScale, MR_TOP); + } + + /** + * Adds a cone. + *

+ * baseScale cannot be zero. If it is, it will automatically be set to 1F. + *

+ * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param baseDirection the direction it faces + */ + public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection) { + addCone(x, y, z, radius, length, segments, baseScale, baseDirection, (int) Math.floor(radius * 2F), (int) Math.floor(radius * 2F)); + } + + /** + * Adds a cone. + *

+ * baseScale cannot be zero. If it is, it will automatically be set to 1F. + *

+ * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + *

+ * The textures for the sides are placed next to each other. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param baseDirection the direction it faces + * @param textureCircleDiameterW the diameter width of the circle on the texture + * @param textureCircleDiameterH the diameter height of the circle on the texture + */ + public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH) { + addCylinder(x, y, z, radius, length, segments, baseScale, 0.0F, baseDirection, textureCircleDiameterW, textureCircleDiameterH, 1); + } + + /** + * Adds a cylinder. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + */ + public void addCylinder(float x, float y, float z, float radius, float length, int segments) { + addCylinder(x, y, z, radius, length, segments, 1F, 1F); + } + + /** + * Adds a cylinder. + *

+ * You can make cones by either setting baseScale or topScale to zero. Setting both + * to zero will set the baseScale to 1F. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param topScale the scaling of the top. Can be negative. + */ + public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale) { + addCylinder(x, y, z, radius, length, segments, baseScale, topScale, MR_TOP); + } + + /** + * Adds a cylinder. + *

+ * You can make cones by either setting baseScale or topScale to zero. Setting both + * to zero will set the baseScale to 1F. + *

+ * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param topScale the scaling of the top. Can be negative. + * @param baseDirection the direction it faces + */ + public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection) { + addCylinder(x, y, z, radius, length, segments, baseScale, topScale, baseDirection, (int) Math.floor(radius * 2F), (int) Math.floor(radius * 2F), (int) Math.floor(length)); + } + + /** + * Adds a cylinder. + *

+ * You can make cones by either setting baseScale or topScale to zero. Setting both + * to zero will set the baseScale to 1F. + *

+ * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + *

+ * The textures for the base and top are placed next to each other, while the body + * will be placed below the circles. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param topScale the scaling of the top. Can be negative. + * @param baseDirection the direction it faces + * @param textureCircleDiameterW the diameter width of the circle on the texture + * @param textureCircleDiameterH the diameter height of the circle on the texture + * @param textureH the height of the texture of the body + */ + public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH, int textureH) { + boolean dirTop = (baseDirection == MR_TOP || baseDirection == MR_BOTTOM); + boolean dirSide = (baseDirection == MR_RIGHT || baseDirection == MR_LEFT); + boolean dirFront = (baseDirection == MR_FRONT || baseDirection == MR_BACK); + boolean dirMirror = (baseDirection == MR_LEFT || baseDirection == MR_BOTTOM || baseDirection == MR_BACK); + + boolean coneBase = (baseScale == 0); + boolean coneTop = (topScale == 0); + + if (coneBase && coneTop) { + baseScale = 1F; + coneBase = false; + } + + PositionTextureVertex[] tempVerts = new PositionTextureVertex[segments * (coneBase || coneTop ? 1 : 2) + 2]; + TexturedPolygon[] poly = new TexturedPolygon[segments * (coneBase || coneTop ? 2 : 3)]; + + float xLength = (dirSide ? length : 0); + float yLength = (dirTop ? length : 0); + float zLength = (dirFront ? length : 0); + + float xStart = (dirMirror ? x + xLength : x); + float yStart = (dirMirror ? y + yLength : y); + float zStart = (dirMirror ? z + zLength : z); + float xEnd = (!dirMirror ? x + xLength : x); + float yEnd = (!dirMirror ? y + yLength : y); + float zEnd = (!dirMirror ? z + zLength : z); + + tempVerts[0] = new PositionTextureVertex(xStart, yStart, zStart, 0, 0); + tempVerts[tempVerts.length - 1] = new PositionTextureVertex(xEnd, yEnd, zEnd, 0, 0); + + float xCur = xStart; + float yCur = yStart; + float zCur = zStart; + float sCur = (coneBase ? topScale : baseScale); + for (int repeat = 0; repeat < (coneBase || coneTop ? 1 : 2); repeat++) { + for (int index = 0; index < segments; index++) { + float xSize = (mirror ^ dirMirror ? -1 : 1) * MathHelper.sin((pi / segments) * index * 2F + pi) * radius * sCur; + float zSize = -MathHelper.cos((pi / segments) * index * 2F + pi) * radius * sCur; + + float xPlace = xCur + (!dirSide ? xSize : 0); + float yPlace = yCur + (!dirTop ? zSize : 0); + float zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); + + tempVerts[1 + index + repeat * segments] = new PositionTextureVertex(xPlace, yPlace, zPlace, 0, 0); + } + xCur = xEnd; + yCur = yEnd; + zCur = zEnd; + sCur = topScale; + } + + float uScale = 1.0F / textureWidth; + float vScale = 1.0F / textureHeight; + float uOffset = uScale / 20.0F; + float vOffset = vScale / 20.0F; + float uCircle = textureCircleDiameterW * uScale; + float vCircle = textureCircleDiameterH * vScale; + float uWidth = (uCircle * 2F - uOffset * 2F) / segments; + float vHeight = textureH * vScale - uOffset * 2f; + float uStart = textureOffsetX * uScale; + float vStart = textureOffsetY * vScale; + + PositionTextureVertex[] vert; + for (int index = 0; index < segments; index++) { + int index2 = (index + 1) % segments; + float uSize = MathHelper.sin((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); + float vSize = MathHelper.cos((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); + float uSize1 = MathHelper.sin((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); + float vSize1 = MathHelper.cos((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); + vert = new PositionTextureVertex[3]; + + vert[0] = tempVerts[0].setTexturePosition(uStart + 0.5F * uCircle, vStart + 0.5F * vCircle); + vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + 0.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); + vert[2] = tempVerts[1 + index].setTexturePosition(uStart + 0.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); + + poly[index] = new TexturedPolygon(vert); + if (mirror ^ flip) + poly[index].flipFace(); + + if (!coneBase && !coneTop) { + vert = new PositionTextureVertex[4]; + + vert[0] = tempVerts[1 + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle); + vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle); + vert[2] = tempVerts[1 + segments + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle + vHeight); + vert[3] = tempVerts[1 + segments + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle + vHeight); + poly[index + segments] = new TexturedPolygon(vert); + if (mirror ^ flip) + poly[index + segments].flipFace(); + } + + vert = new PositionTextureVertex[3]; + + vert[0] = tempVerts[tempVerts.length - 1].setTexturePosition(uStart + 1.5F * uCircle, vStart + 0.5F * vCircle); + vert[1] = tempVerts[tempVerts.length - 2 - index].setTexturePosition(uStart + 1.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); + vert[2] = tempVerts[tempVerts.length - (1 + segments) + ((segments - index) % segments)].setTexturePosition(uStart + 1.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); + + poly[poly.length - segments + index] = new TexturedPolygon(vert); + if (mirror ^ flip) + poly[poly.length - segments + index].flipFace(); + } + copyTo(tempVerts, poly); + } + + /** + * Adds a Waveform .obj file as a model. Model files use the entire texture file. + * + * @param file the location of the .obj file. The location is relative to the base directories, + * which are either resources/models or resources/mods/models. + */ + public void addObj(String file) { + addModel(file, ModelPool.OBJ); + } + + /** + * Adds model format support. Model files use the entire texture file. + * + * @param file the location of the model file. The location is relative to the base directories, + * which are either resources/models or resources/mods/models. + * @param modelFormat the class of the model format interpreter + */ + public void addModel(String file, Class modelFormat) { + ModelPoolEntry entry = ModelPool.addFile(file, modelFormat, transformGroup, textureGroup); + if (entry == null) + return; + PositionTextureVertex[] verts = Arrays.copyOf(entry.vertices, entry.vertices.length); + TexturedPolygon[] poly = Arrays.copyOf(entry.faces, entry.faces.length); + if (flip) { + for (TexturedPolygon face : faces) { + face.flipFace(); + } + } + + copyTo(verts, poly, false); + } + + /** + * Sets a new position for the texture offset. + * + * @param x the x-coordinate of the texture start + * @param y the y-coordinate of the texture start + */ + @Override + public ModelRendererTurbo setTextureOffset(int x, int y) { + textureOffsetX = x; + textureOffsetY = y; + return this; + } + + /** + * Sets the position of the shape, relative to the model's origins. Note that changing + * the offsets will not change the pivot of the model. + * + * @param x the x-position of the shape + * @param y the y-position of the shape + * @param z the z-position of the shape + */ + public void setPosition(float x, float y, float z) { + rotationPointX = x; + rotationPointY = y; + rotationPointZ = z; + } + + /** + * Mirrors the model in any direction. + * + * @param x whether the model should be mirrored in the x-direction + * @param y whether the model should be mirrored in the y-direction + * @param z whether the model should be mirrored in the z-direction + */ + public void doMirror(boolean x, boolean y, boolean z) { + for (TexturedPolygon face : faces) { + PositionTextureVertex[] verts = face.vertexPositions; + for (int j = 0; j < verts.length; j++) { + verts[j].vector3D.xCoord *= (x ? -1 : 1); + verts[j].vector3D.yCoord *= (y ? -1 : 1); + verts[j].vector3D.zCoord *= (z ? -1 : 1); + } + if (x ^ y ^ z) + face.flipFace(); + } + } + + /** + * Sets whether the shape is mirrored or not. This has effect on the way the textures + * get displayed. When working with addSprite, addPixel and addObj, it will be ignored. + * + * @param isMirrored a boolean to define whether the shape is mirrored + */ + public void setMirrored(boolean isMirrored) { + mirror = isMirrored; + } + + /** + * Sets whether the shape's faces are flipped or not. When GL_CULL_FACE is enabled, + * it won't render the back faces, effectively giving you the possibility to make + * "hollow" shapes. When working with addSprite and addPixel, it will be ignored. + * + * @param isFlipped a boolean to define whether the shape is flipped + */ + public void setFlipped(boolean isFlipped) { + flip = isFlipped; + } + + /** + * Clears the current shape. Since all shapes are stacked into one shape, you can't + * just replace a shape by overwriting the shape with another one. In this case you + * would need to clear the shape first. + */ + public void clear() { + vertices = new PositionTextureVertex[0]; + faces = new TexturedPolygon[0]; + transformGroup.clear(); + transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); + currentGroup = transformGroup.get("0"); + } + + /** + * Copies an array of vertices and polygons to the current shape. This mainly is + * used to copy each shape to the main class, but you can just use it to copy + * your own shapes, for example from other classes, into the current class. + * + * @param verts the array of vertices you want to copy + * @param poly the array of polygons you want to copy + */ + public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly) { + copyTo(verts, poly, true); + } + + public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly, boolean copyGroup) { + vertices = Arrays.copyOf(vertices, vertices.length + verts.length); + faces = Arrays.copyOf(faces, faces.length + poly.length); + + for (int idx = 0; idx < verts.length; idx++) { + vertices[vertices.length - verts.length + idx] = verts[idx]; + if (copyGroup && verts[idx] instanceof PositionTransformVertex) + ((PositionTransformVertex) verts[idx]).addGroup(currentGroup); + } + + for (int idx = 0; idx < poly.length; idx++) { + faces[faces.length - poly.length + idx] = poly[idx]; + if (copyGroup) + currentTextureGroup.addPoly(poly[idx]); + } + } + + /** + * Copies an array of vertices and quads to the current shape. This method + * converts quads to polygons and then calls the main copyTo method. + * + * @param verts the array of vertices you want to copy + * @param quad the array of quads you want to copy + */ + public void copyTo(PositionTextureVertex[] verts, TexturedQuad[] quad) { + TexturedPolygon[] poly = new TexturedPolygon[quad.length]; + for (int idx = 0; idx < quad.length; idx++) { + poly[idx] = new TexturedPolygon((PositionTextureVertex[]) quad[idx].vertexPositions); + } + + copyTo(verts, poly); + } + + /** + * Sets the current transformation group. The transformation group is used + * to allow for vertex transformation. If a transformation group does not exist, + * a new one will be created. + * + * @param groupName the name of the transformation group you want to switch to + * @param bone the Bone this transformation group is attached to + * @param weight the weight of the transformation group + */ + public void setGroup(String groupName, Bone bone, double weight) { + if (!transformGroup.containsKey(groupName)) + transformGroup.put(groupName, new TransformGroupBone(bone, weight)); + currentGroup = transformGroup.get(groupName); + } + + /** + * Gets the current transformation group. + * + * @return the current PositionTransformGroup. + */ + public TransformGroup getGroup() { + return currentGroup; + } + + /** + * Sets the current transformation group. The transformation group is used + * to allow for vertex transformation. If a transformation group does not exist, + * a new one will be created. + * + * @param groupName the name of the transformation group you want to switch to + */ + public void setGroup(String groupName) { + setGroup(groupName, new Bone(0, 0, 0, 0), 1D); + } + + /** + * Gets the transformation group with a given group name. + * + * @return the current PositionTransformGroup. + */ + public TransformGroup getGroup(String groupName) { + if (!transformGroup.containsKey(groupName)) + return null; + return transformGroup.get(groupName); + } + + /** + * Gets the current texture group. + * + * @return a TextureGroup object. + */ + public TextureGroup getTextureGroup() { + return currentTextureGroup; + } + + /** + * Sets the current texture group, which is used to switch the + * textures on a per-model base. Do note that any model that is + * rendered afterwards will use the same texture. To counter it, + * set a default texture, either at initialization or before + * rendering. + * + * @param groupName The name of the texture group. If the texture + * group doesn't exist, it creates a new group automatically. + */ + public void setTextureGroup(String groupName) { + if (!textureGroup.containsKey(groupName)) { + textureGroup.put(groupName, new TextureGroup()); + } + currentTextureGroup = textureGroup.get(groupName); + } + + /** + * Gets the texture group with the given name. + * + * @param groupName the name of the texture group to return + * @return a TextureGroup object. + */ + public TextureGroup getTextureGroup(String groupName) { + if (!textureGroup.containsKey(groupName)) + return null; + return textureGroup.get(groupName); + } + + /** + * Sets the texture of the current texture group. + * + * @param s the filename + */ + public void setGroupTexture(String s) { + currentTextureGroup.texture = s; + } + + /** + * Sets the default texture. When left as an empty string, + * it will use the texture that has been set previously. + * Note that this will also move on to other rendered models + * of the same entity. + * + * @param s the filename + */ + public void setDefaultTexture(String s) { + defaultTexture = s; + } + + /** + * Renders the shape. + * + * @param worldScale the scale of the shape. Usually is 0.0625. + */ + @Override + public void render(float worldScale) { + render(worldScale, false); + } + + /** + * Renders the shape + * + * @param worldScale The scale of the shape + * @param oldRotateOrder Whether to use the old rotate order (ZYX) instead of the new one (YZX) + */ + public void render(float worldScale, boolean oldRotateOrder) { + GL11.glPushMatrix(); + if (glow) { + glowOn(); + } + GL11.glAlphaFunc(GL11.GL_GREATER, 0.001F); + GL11.glEnable(GL11.GL_BLEND); + int srcBlend = GL11.glGetInteger(GL11.GL_BLEND_SRC); + int dstBlend = GL11.glGetInteger(GL11.GL_BLEND_DST); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + if (field_1402_i) { + return; + } + if (!showModel) { + return; + } + if (!compiled || forcedRecompile) { + compileDisplayList(worldScale); + } + if (rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) { + GL11.glPushMatrix(); + GL11.glTranslatef(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); + if (!oldRotateOrder && rotateAngleY != 0.0F) { + GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); + } + if (rotateAngleZ != 0.0F) { + GL11.glRotatef((oldRotateOrder ? -1 : 1) * rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); + } + if (oldRotateOrder && rotateAngleY != 0.0F) { + GL11.glRotatef(-rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); + } + if (rotateAngleX != 0.0F) { + GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); + } + + callDisplayList(); + if (childModels != null) { + for (Object childModel : childModels) { + ((ModelRenderer) childModel).render(worldScale); + } + + } + GL11.glPopMatrix(); + } else if (rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) { + GL11.glTranslatef(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); + callDisplayList(); + if (childModels != null) { + for (Object childModel : childModels) { + ((ModelRenderer) childModel).render(worldScale); + } + + } + GL11.glTranslatef(-rotationPointX * worldScale, -rotationPointY * worldScale, -rotationPointZ * worldScale); + } else { + callDisplayList(); + if (childModels != null) { + for (Object childModel : childModels) { + ((ModelRenderer) childModel).render(worldScale); + } + + } + } + if (glow) { + glowOff(); + } + GL11.glBlendFunc(srcBlend, dstBlend); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopMatrix(); + } + + @Override + public void renderWithRotation(float f) { + if (field_1402_i) { + return; + } + if (!showModel) { + return; + } + if (!compiled) { + compileDisplayList(f); + } + GL11.glPushMatrix(); + GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); + if (rotateAngleY != 0.0F) { + GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); + } + if (rotateAngleX != 0.0F) { + GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); + } + if (rotateAngleZ != 0.0F) { + GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); + } + callDisplayList(); + GL11.glPopMatrix(); + } + + @Override + public void postRender(float f) { + if (field_1402_i) { + return; + } + if (!showModel) { + return; + } + if (!compiled || forcedRecompile) { + compileDisplayList(f); + } + if (rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) { + GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); + if (rotateAngleZ != 0.0F) { + GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); + } + if (rotateAngleY != 0.0F) { + GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); + } + if (rotateAngleX != 0.0F) { + GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); + } + } else if (rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) { + GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); + } + } + + private void callDisplayList() { + if (useLegacyCompiler) + GL11.glCallList(displayList); + else { + TextureManager renderEngine = RenderManager.instance.renderEngine; + + Collection textures = textureGroup.values(); + + Iterator itr = textures.iterator(); + for (int i = 0; itr.hasNext(); i++) { + TextureGroup curTexGroup = itr.next(); + curTexGroup.loadTexture(); + GL11.glCallList(displayListArray[i]); + if (!defaultTexture.equals("")) + renderEngine.bindTexture(new ResourceLocation("", defaultTexture)); //TODO : Check. Not sure about this one + } + } + } + + private void compileDisplayList(float worldScale) { + if (useLegacyCompiler) + compileLegacyDisplayList(worldScale); + else { + Collection textures = textureGroup.values(); + + Iterator itr = textures.iterator(); + displayListArray = new int[textureGroup.size()]; + for (int i = 0; itr.hasNext(); i++) { + displayListArray[i] = GLAllocation.generateDisplayLists(1); + GL11.glNewList(displayListArray[i], GL11.GL_COMPILE); + TmtTessellator tessellator = TmtTessellator.instance; + + TextureGroup usedGroup = itr.next(); + for (int j = 0; j < usedGroup.poly.size(); j++) { + usedGroup.poly.get(j).draw(tessellator, worldScale); + } + + GL11.glEndList(); + } + } + + compiled = true; + } + + private void compileLegacyDisplayList(float worldScale) { + displayList = GLAllocation.generateDisplayLists(1); + GL11.glNewList(displayList, GL11.GL_COMPILE); + TmtTessellator tessellator = TmtTessellator.instance; + for (TexturedPolygon face : faces) { + face.draw(tessellator, worldScale); + } + + GL11.glEndList(); + } }