From bd9a4cbf8ee03ffa0d2d80a60d0255fcb2f67863 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 6 Apr 2021 22:43:21 +0200 Subject: [PATCH] rbmk 3: return of the neutron sources --- src/main/java/com/hbm/blocks/ModBlocks.java | 1 + .../com/hbm/blocks/machine/rbmk/RBMKRod.java | 23 ++ .../entity/projectile/EntityBulletBase.java | 2 +- .../com/hbm/handler/BulletConfiguration.java | 2 + src/main/java/com/hbm/handler/GUIHandler.java | 15 ++ .../hbm/handler/guncfg/GunEnergyFactory.java | 1 + .../inventory/container/ContainerRBMKRod.java | 62 +++++ .../hbm/inventory/gui/GUIMachineRadar.java | 32 ++- .../com/hbm/inventory/gui/GUIRBMKRod.java | 46 ++++ src/main/java/com/hbm/items/ModItems.java | 41 +++- .../com/hbm/items/machine/ItemRBMKRod.java | 109 +++++++++ .../com/hbm/items/weapon/ItemGunBase.java | 4 + .../com/hbm/items/weapon/ItemGunVortex.java | 226 +++++++++++++++++- .../hbm/particle/ParticleVortexCircle.java | 5 + .../com/hbm/particle/ParticleVortexGlow.java | 94 ++++++++ .../hbm/particle/ParticleVortexParticle.java | 119 +++++++++ .../entity/projectile/RenderBullet.java | 6 +- .../machine/TileEntityMachineRadar.java | 48 +++- src/main/java/com/hbm/util/BobMathUtil.java | 3 + src/main/resources/assets/hbm/lang/de_DE.lang | 1 + src/main/resources/assets/hbm/lang/en_US.lang | 1 + .../hbm/textures/blocks/block_actinium.png | Bin 0 -> 554 bytes .../hbm/textures/blocks/block_lanthanium.png | Bin 0 -> 570 bytes .../assets/hbm/textures/gui/gui_radar.png | Bin 2506 -> 0 bytes .../hbm/textures/gui/machine/gui_radar.png | Bin 0 -> 2604 bytes .../textures/models/tank_SUPERHOTSTEAM.png | Bin 2347 -> 2588 bytes .../textures/models/tank_ULTRAHOTSTEAM.png | Bin 0 -> 2347 bytes .../hbm/textures/particle/fresnel_ms.png | Bin 0 -> 14226 bytes 28 files changed, 797 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/hbm/inventory/container/ContainerRBMKRod.java create mode 100644 src/main/java/com/hbm/inventory/gui/GUIRBMKRod.java create mode 100644 src/main/java/com/hbm/particle/ParticleVortexCircle.java create mode 100644 src/main/java/com/hbm/particle/ParticleVortexGlow.java create mode 100644 src/main/java/com/hbm/particle/ParticleVortexParticle.java create mode 100644 src/main/resources/assets/hbm/textures/blocks/block_actinium.png create mode 100644 src/main/resources/assets/hbm/textures/blocks/block_lanthanium.png delete mode 100644 src/main/resources/assets/hbm/textures/gui/gui_radar.png create mode 100644 src/main/resources/assets/hbm/textures/gui/machine/gui_radar.png create mode 100644 src/main/resources/assets/hbm/textures/models/tank_ULTRAHOTSTEAM.png create mode 100644 src/main/resources/assets/hbm/textures/particle/fresnel_ms.png diff --git a/src/main/java/com/hbm/blocks/ModBlocks.java b/src/main/java/com/hbm/blocks/ModBlocks.java index e312ecba7..cc2f3e140 100644 --- a/src/main/java/com/hbm/blocks/ModBlocks.java +++ b/src/main/java/com/hbm/blocks/ModBlocks.java @@ -849,6 +849,7 @@ public class ModBlocks { public static Block rbmk_absorber; public static Block rbmk_moderator; public static Block rbmk_console; + public static final int guiID_rbmk_rod = 113; public static Block book_guide; diff --git a/src/main/java/com/hbm/blocks/machine/rbmk/RBMKRod.java b/src/main/java/com/hbm/blocks/machine/rbmk/RBMKRod.java index f4ec08f8c..6c5ecc2b2 100644 --- a/src/main/java/com/hbm/blocks/machine/rbmk/RBMKRod.java +++ b/src/main/java/com/hbm/blocks/machine/rbmk/RBMKRod.java @@ -1,7 +1,11 @@ package com.hbm.blocks.machine.rbmk; +import com.hbm.blocks.ModBlocks; +import com.hbm.main.MainRegistry; import com.hbm.tileentity.machine.rbmk.TileEntityRBMKRod; +import cpw.mods.fml.common.network.internal.FMLNetworkHandler; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; @@ -12,6 +16,25 @@ public class RBMKRod extends RBMKBase { return new TileEntityRBMKRod(); } + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) { + if(world.isRemote) + { + return true; + } else if(!player.isSneaking()) + { + int[] pos = this.findCore(world, x, y, z); + + if(pos == null) + return false; + + FMLNetworkHandler.openGui(player, MainRegistry.instance, ModBlocks.guiID_rbmk_rod, world, pos[0], pos[1], pos[2]); + return true; + } else { + return true; + } + } + @Override public int getRenderType(){ return this.renderIDRods; diff --git a/src/main/java/com/hbm/entity/projectile/EntityBulletBase.java b/src/main/java/com/hbm/entity/projectile/EntityBulletBase.java index 596fd670b..451bb9219 100644 --- a/src/main/java/com/hbm/entity/projectile/EntityBulletBase.java +++ b/src/main/java/com/hbm/entity/projectile/EntityBulletBase.java @@ -427,7 +427,7 @@ public class EntityBulletBase extends Entity implements IProjectile { if(config.bImpact != null) config.bImpact.behaveBlockHit(this, bX, bY, bZ); - if(!worldObj.isRemote) + if(!worldObj.isRemote && !config.liveAfterImpact) this.setDead(); if(config.incendiary > 0 && !this.worldObj.isRemote) { diff --git a/src/main/java/com/hbm/handler/BulletConfiguration.java b/src/main/java/com/hbm/handler/BulletConfiguration.java index ae4625c07..05eaf5e5a 100644 --- a/src/main/java/com/hbm/handler/BulletConfiguration.java +++ b/src/main/java/com/hbm/handler/BulletConfiguration.java @@ -55,6 +55,8 @@ public class BulletConfiguration { public boolean isSpectral; //whether or not the bullet should break glass public boolean doesBreakGlass; + //whether the bullet should stay alive after colliding with a block + public boolean liveAfterImpact; //bullet effects public List effects; diff --git a/src/main/java/com/hbm/handler/GUIHandler.java b/src/main/java/com/hbm/handler/GUIHandler.java index f5513e5f4..f6b71b03a 100644 --- a/src/main/java/com/hbm/handler/GUIHandler.java +++ b/src/main/java/com/hbm/handler/GUIHandler.java @@ -8,6 +8,7 @@ import com.hbm.inventory.inv.InventoryLeadBox; import com.hbm.items.ModItems; import com.hbm.tileentity.bomb.*; import com.hbm.tileentity.machine.*; +import com.hbm.tileentity.machine.rbmk.TileEntityRBMKRod; import com.hbm.tileentity.turret.*; import net.minecraft.entity.player.EntityPlayer; @@ -784,6 +785,13 @@ public class GUIHandler implements IGuiHandler { } return null; } + + case ModBlocks.guiID_rbmk_rod: { + if(entity instanceof TileEntityRBMKRod) { + return new ContainerRBMKRod(player.inventory, (TileEntityRBMKRod) entity); + } + return null; + } } // NON-TE CONTAINERS @@ -1556,6 +1564,13 @@ public class GUIHandler implements IGuiHandler { } return null; } + + case ModBlocks.guiID_rbmk_rod: { + if(entity instanceof TileEntityRBMKRod) { + return new GUIRBMKRod(player.inventory, (TileEntityRBMKRod) entity); + } + return null; + } } // ITEM GUIS diff --git a/src/main/java/com/hbm/handler/guncfg/GunEnergyFactory.java b/src/main/java/com/hbm/handler/guncfg/GunEnergyFactory.java index 908e1d97a..d1aca7661 100644 --- a/src/main/java/com/hbm/handler/guncfg/GunEnergyFactory.java +++ b/src/main/java/com/hbm/handler/guncfg/GunEnergyFactory.java @@ -286,6 +286,7 @@ public class GunEnergyFactory { bullet.bulletsMax = 5; bullet.dmgMin = 10000; bullet.dmgMax = 25000; + bullet.liveAfterImpact = true; bullet.style = bullet.STYLE_BOLT; bullet.trail = bullet.BOLT_ZOMG; diff --git a/src/main/java/com/hbm/inventory/container/ContainerRBMKRod.java b/src/main/java/com/hbm/inventory/container/ContainerRBMKRod.java new file mode 100644 index 000000000..2056fa0df --- /dev/null +++ b/src/main/java/com/hbm/inventory/container/ContainerRBMKRod.java @@ -0,0 +1,62 @@ +package com.hbm.inventory.container; + +import com.hbm.tileentity.machine.rbmk.TileEntityRBMKRod; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class ContainerRBMKRod extends Container { + + private TileEntityRBMKRod rbmk; + + public ContainerRBMKRod(InventoryPlayer invPlayer, TileEntityRBMKRod tedf) { + rbmk = tedf; + + this.addSlotToContainer(new Slot(tedf, 0, 80, 45)); + + for(int i = 0; i < 3; i++) { + for(int j = 0; j < 9; j++) { + this.addSlotToContainer(new Slot(invPlayer, j + i * 9 + 9, 8 + j * 18, 84 + i * 18 + 20)); + } + } + + for(int i = 0; i < 9; i++) { + this.addSlotToContainer(new Slot(invPlayer, i, 8 + i * 18, 142 + 20)); + } + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer p_82846_1_, int par2) { + ItemStack var3 = null; + Slot var4 = (Slot) this.inventorySlots.get(par2); + + if(var4 != null && var4.getHasStack()) { + ItemStack var5 = var4.getStack(); + var3 = var5.copy(); + + if(par2 <= rbmk.getSizeInventory() - 1) { + if(!this.mergeItemStack(var5, rbmk.getSizeInventory(), this.inventorySlots.size(), true)) { + return null; + } + } else if(!this.mergeItemStack(var5, 0, rbmk.getSizeInventory(), false)) { + return null; + } + + if(var5.stackSize == 0) { + var4.putStack((ItemStack) null); + } else { + var4.onSlotChanged(); + } + } + + return var3; + } + + @Override + public boolean canInteractWith(EntityPlayer player) { + return rbmk.isUseableByPlayer(player); + } +} diff --git a/src/main/java/com/hbm/inventory/gui/GUIMachineRadar.java b/src/main/java/com/hbm/inventory/gui/GUIMachineRadar.java index 3579892fb..984898875 100644 --- a/src/main/java/com/hbm/inventory/gui/GUIMachineRadar.java +++ b/src/main/java/com/hbm/inventory/gui/GUIMachineRadar.java @@ -21,12 +21,13 @@ import net.minecraft.util.ResourceLocation; public class GUIMachineRadar extends GuiInfoContainer { - private static ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/gui_radar.png"); + private static ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/machine/gui_radar.png"); private TileEntityMachineRadar diFurnace; public GUIMachineRadar(InventoryPlayer invPlayer, TileEntityMachineRadar tedf) { super(new ContainerMachineRadar(invPlayer, tedf)); diFurnace = tedf; + texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/machine/gui_radar.png"); this.xSize = 216; this.ySize = 234; @@ -38,9 +39,10 @@ public class GUIMachineRadar extends GuiInfoContainer { this.drawElectricityInfo(this, mouseX, mouseY, guiLeft + 8, guiTop + 221, 200, 7, diFurnace.power, diFurnace.maxPower); - this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 103, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.detectMissiles") ); - this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 113, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.detectPlayers")); - this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 123, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.smartMode")); + this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 98, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.detectMissiles") ); + this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 108, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.detectPlayers")); + this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 118, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.smartMode")); + this.drawCustomInfoStat(mouseX, mouseY, guiLeft - 10, guiTop + 128, 8, 8, mouseX, mouseY, I18nUtil.resolveKeyArray("radar.redMode")); if(!diFurnace.nearbyMissiles.isEmpty()) { for(int[] m : diFurnace.nearbyMissiles) { @@ -65,20 +67,25 @@ public class GUIMachineRadar extends GuiInfoContainer { protected void mouseClicked(int x, int y, int i) { super.mouseClicked(x, y, i); - if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 103 < y && guiTop + 103 + 8 >= y) { + if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 98 < y && guiTop + 98 + 8 >= y) { mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); PacketDispatcher.wrapper.sendToServer(new AuxButtonPacket(diFurnace.xCoord, diFurnace.yCoord, diFurnace.zCoord, 0, 0)); } - if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 113 < y && guiTop + 113 + 8 >= y) { + if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 108 < y && guiTop + 108 + 8 >= y) { mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); PacketDispatcher.wrapper.sendToServer(new AuxButtonPacket(diFurnace.xCoord, diFurnace.yCoord, diFurnace.zCoord, 0, 1)); } - if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 123 < y && guiTop + 123 + 8 >= y) { + if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 118 < y && guiTop + 118 + 8 >= y) { mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); PacketDispatcher.wrapper.sendToServer(new AuxButtonPacket(diFurnace.xCoord, diFurnace.yCoord, diFurnace.zCoord, 0, 2)); } + + if(guiLeft -10 <= x && guiLeft + -10 + 8 > x && guiTop + 128 < y && guiTop + 128 + 8 >= y) { + mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); + PacketDispatcher.wrapper.sendToServer(new AuxButtonPacket(diFurnace.xCoord, diFurnace.yCoord, diFurnace.zCoord, 0, 3)); + } } @Override @@ -93,16 +100,19 @@ public class GUIMachineRadar extends GuiInfoContainer { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); Minecraft.getMinecraft().getTextureManager().bindTexture(texture); drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); - drawTexturedModalRect(guiLeft - 14, guiTop + 99, 216, 198, 14, 36); + drawTexturedModalRect(guiLeft - 14, guiTop + 94, 216, 198, 14, 46); if(diFurnace.scanMissiles) - drawTexturedModalRect(guiLeft - 10, guiTop + 103, 230, 202, 8, 8); + drawTexturedModalRect(guiLeft - 10, guiTop + 98, 230, 202, 8, 8); if(diFurnace.scanPlayers) - drawTexturedModalRect(guiLeft - 10, guiTop + 113, 230, 212, 8, 8); + drawTexturedModalRect(guiLeft - 10, guiTop + 108, 230, 212, 8, 8); if(diFurnace.smartMode) - drawTexturedModalRect(guiLeft - 10, guiTop + 123, 230, 222, 8, 8); + drawTexturedModalRect(guiLeft - 10, guiTop + 118, 230, 222, 8, 8); + + if(diFurnace.redMode) + drawTexturedModalRect(guiLeft - 10, guiTop + 128, 230, 232, 8, 8); if(diFurnace.power > 0) { int i = (int)diFurnace.getPowerScaled(200); diff --git a/src/main/java/com/hbm/inventory/gui/GUIRBMKRod.java b/src/main/java/com/hbm/inventory/gui/GUIRBMKRod.java new file mode 100644 index 000000000..b048a5926 --- /dev/null +++ b/src/main/java/com/hbm/inventory/gui/GUIRBMKRod.java @@ -0,0 +1,46 @@ +package com.hbm.inventory.gui; + +import org.lwjgl.opengl.GL11; + +import com.hbm.inventory.container.ContainerRBMKRod; +import com.hbm.lib.RefStrings; +import com.hbm.tileentity.machine.rbmk.TileEntityRBMKRod; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; + +public class GUIRBMKRod extends GuiContainer { + + private static ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/reactors/gui_rbmk_element.png"); + private TileEntityRBMKRod rod; + + public GUIRBMKRod(InventoryPlayer invPlayer, TileEntityRBMKRod tedf) { + super(new ContainerRBMKRod(invPlayer, tedf)); + rod = tedf; + + this.xSize = 176; + this.ySize = 186; + } + + @Override + protected void drawGuiContainerForegroundLayer(int i, int j) { + String name = this.rod.hasCustomInventoryName() ? this.rod.getInventoryName() : I18n.format(this.rod.getInventoryName()); + + this.fontRendererObj.drawString(name, this.xSize / 2 - this.fontRendererObj.getStringWidth(name) / 2, 6, 4210752); + this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 96 + 2, 4210752); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float p_146976_1_, int p_146976_2_, int p_146976_3_) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getMinecraft().getTextureManager().bindTexture(texture); + drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + + if(rod.slots[0] != null) { + drawTexturedModalRect(guiLeft + 34, guiTop + 21, 176, 0, 18, 67); + } + } +} diff --git a/src/main/java/com/hbm/items/ModItems.java b/src/main/java/com/hbm/items/ModItems.java index 7e180ff15..1a326b3b3 100644 --- a/src/main/java/com/hbm/items/ModItems.java +++ b/src/main/java/com/hbm/items/ModItems.java @@ -3082,17 +3082,36 @@ public class ModItems { rod_quad_tritium = new ItemHazard(2F).setUnlocalizedName("rod_quad_tritium").setMaxStackSize(1).setCreativeTab(MainRegistry.controlTab).setContainerItem(ModItems.rod_quad_empty).setTextureName(RefStrings.MODID + ":rod_quad_tritium"); rbmk_fuel_empty = new Item().setUnlocalizedName("rbmk_fuel_empty").setMaxStackSize(1).setCreativeTab(MainRegistry.controlTab).setTextureName(RefStrings.MODID + ":rbmk_fuel_empty"); - //todo: make one item and handle all of this trash with metadata - rbmk_fuel_meu = new ItemRBMKRod("Medium Enriched Uranium").setUnlocalizedName("rbmk_fuel_meu").setTextureName(RefStrings.MODID + ":rbmk_fuel_meu"); - rbmk_fuel_thmeu = new ItemRBMKRod("Thorium with MEU Driver Fuel").setUnlocalizedName("rbmk_fuel_thmeu").setTextureName(RefStrings.MODID + ":rbmk_fuel_thmeu"); - rbmk_fuel_lep = new ItemRBMKRod("Low Enriched Plutonium").setUnlocalizedName("rbmk_fuel_lep").setTextureName(RefStrings.MODID + ":rbmk_fuel_lep"); - rbmk_fuel_mep = new ItemRBMKRod("Medium Enriched Plutonium").setUnlocalizedName("rbmk_fuel_mep").setTextureName(RefStrings.MODID + ":rbmk_fuel_mep"); - rbmk_fuel_mox = new ItemRBMKRod("Mixed LEU & LEP Oxide").setUnlocalizedName("rbmk_fuel_mox").setTextureName(RefStrings.MODID + ":rbmk_fuel_mox"); - rbmk_fuel_les = new ItemRBMKRod("Low Enriched Schrabidium").setUnlocalizedName("rbmk_fuel_les").setTextureName(RefStrings.MODID + ":rbmk_fuel_les"); - rbmk_fuel_mes = new ItemRBMKRod("Medium Enriched Schrabidium").setUnlocalizedName("rbmk_fuel_mes").setTextureName(RefStrings.MODID + ":rbmk_fuel_mes"); - rbmk_fuel_hes = new ItemRBMKRod("Highly Enriched Schrabidium").setUnlocalizedName("rbmk_fuel_hes").setTextureName(RefStrings.MODID + ":rbmk_fuel_hes"); - rbmk_fuel_po210be = new ItemRBMKRod("Polonium-210 & Beryllium Neutron Source").setUnlocalizedName("rbmk_fuel_po210be").setTextureName(RefStrings.MODID + ":rbmk_fuel_po210be"); - rbmk_fuel_pu238be = new ItemRBMKRod("Plutonium-238 & Beryllium Neutron Source").setUnlocalizedName("rbmk_fuel_pu238be").setTextureName(RefStrings.MODID + ":rbmk_fuel_pu238be"); + rbmk_fuel_meu = new ItemRBMKRod("Medium Enriched Uranium") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_meu").setTextureName(RefStrings.MODID + ":rbmk_fuel_meu"); + rbmk_fuel_thmeu = new ItemRBMKRod("Thorium with MEU Driver Fuel") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_thmeu").setTextureName(RefStrings.MODID + ":rbmk_fuel_thmeu"); + rbmk_fuel_lep = new ItemRBMKRod("Low Enriched Plutonium") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_lep").setTextureName(RefStrings.MODID + ":rbmk_fuel_lep"); + rbmk_fuel_mep = new ItemRBMKRod("Medium Enriched Plutonium") + .setYield(10D) + .setStats(15, 100).setUnlocalizedName("rbmk_fuel_mep").setTextureName(RefStrings.MODID + ":rbmk_fuel_mep"); + rbmk_fuel_mox = new ItemRBMKRod("Mixed LEU & LEP Oxide") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_mox").setTextureName(RefStrings.MODID + ":rbmk_fuel_mox"); + rbmk_fuel_les = new ItemRBMKRod("Low Enriched Schrabidium") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_les").setTextureName(RefStrings.MODID + ":rbmk_fuel_les"); + rbmk_fuel_mes = new ItemRBMKRod("Medium Enriched Schrabidium") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_mes").setTextureName(RefStrings.MODID + ":rbmk_fuel_mes"); + rbmk_fuel_hes = new ItemRBMKRod("Highly Enriched Schrabidium") + .setYield(10D) + .setStats(0, 100).setUnlocalizedName("rbmk_fuel_hes").setTextureName(RefStrings.MODID + ":rbmk_fuel_hes"); + rbmk_fuel_po210be = new ItemRBMKRod("Polonium-210 & Beryllium Neutron Source") + .setYield(10D) + .setStats(50, 70).setUnlocalizedName("rbmk_fuel_po210be").setTextureName(RefStrings.MODID + ":rbmk_fuel_po210be"); + rbmk_fuel_pu238be = new ItemRBMKRod("Plutonium-238 & Beryllium Neutron Source") + .setYield(10D) + .setStats(35, 60).setUnlocalizedName("rbmk_fuel_pu238be").setTextureName(RefStrings.MODID + ":rbmk_fuel_pu238be"); trinitite = new ItemHazard().addRadiation(ItemHazard.trn * ItemHazard.ingot).toItem().setUnlocalizedName("trinitite").setCreativeTab(MainRegistry.partsTab).setTextureName(RefStrings.MODID + ":trinitite_new"); nuclear_waste_long = new ItemHazard(5F).setUnlocalizedName("nuclear_waste_long").setCreativeTab(MainRegistry.partsTab).setTextureName(RefStrings.MODID + ":nuclear_waste_long"); diff --git a/src/main/java/com/hbm/items/machine/ItemRBMKRod.java b/src/main/java/com/hbm/items/machine/ItemRBMKRod.java index c4cdefee8..52197502b 100644 --- a/src/main/java/com/hbm/items/machine/ItemRBMKRod.java +++ b/src/main/java/com/hbm/items/machine/ItemRBMKRod.java @@ -8,11 +8,18 @@ import com.hbm.main.MainRegistry; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumChatFormatting; public class ItemRBMKRod extends ItemHazard { String fullName = ""; + double funcStart; + double funcEnd; + double xGen = 0.5D;; + double xBurn = 50D; + double heat = 1D; + double yield; public ItemRBMKRod(String fullName) { @@ -22,11 +29,113 @@ public class ItemRBMKRod extends ItemHazard { this.setMaxStackSize(1); this.setCreativeTab(MainRegistry.controlTab); } + + public ItemRBMKRod setYield(double yield) { + this.yield = yield; + return this; + } + + public ItemRBMKRod setStats(double funcStart, double funcEnd) { + this.funcStart = funcStart; + this.funcEnd = funcEnd; + return this; + } + + public double burn(ItemStack stack, double flux) { + return 0; + } + + /** + * @param flux [0;100] ...or at least those are sane levels + * @return the amount of reactivity yielded, unmodified by xenon + */ + public double reactivityFunc(double flux) { + return funcStart + (funcEnd - funcStart) * flux / 100D; //goodness gracious i guessed the right formula on the first try! + } + + public double xenonGenFunc(double flux) { + return flux * xGen; + } + + public double xenonBurnFunc(double flux) { + return (flux * flux) / xBurn; + } + + /** + * @param stack + * @return enrichment [0;1] + */ + public double getEnrichment(ItemStack stack) { + return getYield(stack) / ((ItemRBMKRod) stack.getItem()).yield; + } @Override public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean bool) { list.add(EnumChatFormatting.ITALIC + this.fullName); + + if(funcStart > 0) { + list.add(EnumChatFormatting.RED + "Self-igniting"); + } + + list.add(EnumChatFormatting.GREEN + "Depletion: " + (100D - ((getYield(stack) * 1000D / yield) / 10D)) + "%"); + list.add(EnumChatFormatting.LIGHT_PURPLE + "Xenon poison: " + ((getPoison(stack) * 10D) / 10D) + "%"); + list.add(EnumChatFormatting.GOLD + "Heat per tick at full power: " + heat); + list.add(EnumChatFormatting.YELLOW + "Flux function:"); + list.add(EnumChatFormatting.WHITE + " f(0) = " + funcStart); + list.add(EnumChatFormatting.WHITE + " f(1) = " + funcEnd); + list.add(EnumChatFormatting.WHITE + " f(x) = " + funcStart + " + " + (funcEnd - funcStart) + " * x"); + list.add(EnumChatFormatting.YELLOW + "Xenon gen function:"); + list.add(EnumChatFormatting.WHITE + " g(x) = x * " + xGen); + list.add(EnumChatFormatting.YELLOW + "Xenon burn function:"); + list.add(EnumChatFormatting.WHITE + " b(x) = x² * " + xBurn); + super.addInformation(stack, player, list, bool); } + + public static void setYield(ItemStack stack, double yield) { + + if(!stack.hasTagCompound()) + stack.stackTagCompound = new NBTTagCompound(); + + stack.stackTagCompound.setDouble("yield", yield); + } + + public static double getYield(ItemStack stack) { + + if(stack.hasTagCompound()) { + return stack.stackTagCompound.getDouble("yield"); + } + + if(stack.getItem() instanceof ItemRBMKRod) { + return ((ItemRBMKRod)stack.getItem()).yield; + } + + return 0; + } + + public static void setPoison(ItemStack stack, double yield) { + + if(!stack.hasTagCompound()) + stack.stackTagCompound = new NBTTagCompound(); + + stack.stackTagCompound.setDouble("xenon", yield); + } + + public static double getPoison(ItemStack stack) { + + if(stack.hasTagCompound()) { + return stack.stackTagCompound.getDouble("xenon"); + } + + return 0; + } + + public boolean showDurabilityBar(ItemStack stack) { + return getDurabilityForDisplay(stack) < 1D; + } + + public double getDurabilityForDisplay(ItemStack stack) { + return getEnrichment(stack); + } } diff --git a/src/main/java/com/hbm/items/weapon/ItemGunBase.java b/src/main/java/com/hbm/items/weapon/ItemGunBase.java index 908c1c1ff..0d405e614 100644 --- a/src/main/java/com/hbm/items/weapon/ItemGunBase.java +++ b/src/main/java/com/hbm/items/weapon/ItemGunBase.java @@ -223,6 +223,9 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD { spawnProjectile(world, player, stack, BulletConfigSyncingUtil.getKey(config)); } + useUpAmmo(player, stack, false); + player.inventoryContainer.detectAndSendChanges(); + setItemWear(stack, getItemWear(stack) + config.wear); } @@ -611,6 +614,7 @@ public class ItemGunBase extends Item implements IHoldableWeapon, IItemHUD { if(config.allowsInfinity && EnchantmentHelper.getEnchantmentLevel(Enchantment.infinity.effectId, stack) > 0) return; + if(config.reloadType != mainConfig.RELOAD_NONE) { setMag(stack, getMag(stack) - 1); } else { diff --git a/src/main/java/com/hbm/items/weapon/ItemGunVortex.java b/src/main/java/com/hbm/items/weapon/ItemGunVortex.java index 916b7c7aa..8b2be3d0c 100644 --- a/src/main/java/com/hbm/items/weapon/ItemGunVortex.java +++ b/src/main/java/com/hbm/items/weapon/ItemGunVortex.java @@ -1,30 +1,244 @@ package com.hbm.items.weapon; +import java.util.List; + +import org.lwjgl.opengl.GL11; + import com.hbm.entity.projectile.EntityBeamVortex; import com.hbm.handler.GunConfiguration; +import com.hbm.lib.Library; +import com.hbm.lib.ModDamageSource; +import com.hbm.main.MainRegistry; import com.hbm.packet.GunAnimationPacket; import com.hbm.packet.PacketDispatcher; +import com.hbm.particle.ParticleVortexCircle; +import com.hbm.particle.ParticleVortexGlow; +import com.hbm.particle.ParticleVortexParticle; import com.hbm.render.anim.HbmAnimations.AnimType; +import com.hbm.util.BobMathUtil; +import com.hbm.util.EntityDamageUtil; +import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +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.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.MathHelper; +import net.minecraft.util.Vec3; import net.minecraft.world.World; public class ItemGunVortex extends ItemGunBase { - + + @SideOnly(Side.CLIENT) + private long lastFireTime; + public ItemGunVortex(GunConfiguration config) { super(config); } - - //spawns the actual projectile, can be overridden to change projectile entity + + /*@Override protected void spawnProjectile(World world, EntityPlayer player, ItemStack stack, int config) { + //EntityBeamVortex beam = new EntityBeamVortex(world, player); + //world.spawnEntity(beam); + //100 blocks is its current max range, but I'm sure that could be increased if necessary. + List entsOnBeam = Library.rayTraceEntitiesOnLine(player, 100, 1).getRight(); - EntityBeamVortex beam = new EntityBeamVortex(world, player); - world.spawnEntityInWorld(beam); + for(Entity e : entsOnBeam){ + + if(!(e instanceof EntityLivingBase)) + continue; + + float dmg = 30; + EntityDamageUtil.attackEntityFromIgnoreIFrame(e, ModDamageSource.radiation, dmg); + } if(this.mainConfig.animations.containsKey(AnimType.CYCLE) && player instanceof EntityPlayerMP) PacketDispatcher.wrapper.sendTo(new GunAnimationPacket(AnimType.CYCLE.ordinal()), (EntityPlayerMP) player); - + PacketDispatcher.wrapper.sendToAllAround(new GunFXPacket(player, FXType.FIRE), new TargetPoint(world.provider.dimensionId, player.posX, player.posY, player.posZ, 1)); } + + //This method should also solve the supershotgun issue where it doesn't fire some of the time (maybe?) + @Override + @SideOnly(Side.CLIENT) + public void onFireClient(ItemStack stack, EntityPlayer player, boolean shouldDoThirdPerson) { + //If I'm going to do more particle systems like this maybe I should write some kind of abstraction around it to make it less messy. + NBTTagCompound tag = new NBTTagCompound(); + Vec3d pos = null; + if(stack == player.getHeldItemMainhand()){ + pos = new Vec3d(-0.16, -0.20, 1).rotatePitch(-(float) Math.toRadians(player.rotationPitch)).rotateYaw(-(float) Math.toRadians(player.rotationYawHead)); + } else { + pos = new Vec3d(0.16, -0.20, 1).rotatePitch(-(float) Math.toRadians(player.rotationPitch)).rotateYaw(-(float) Math.toRadians(player.rotationYawHead)); + } + pos = pos.add(player.getPositionEyes(1F)); + Vec3d view = BobMathUtil.getVectorFromAngle(BobMathUtil.getEulerAngles(player.getLookVec()).addVector(0, 3, 0)); + Vec3d hitPos = null; + Vec3d hitNormal = null; + RayTraceResult r = Library.rayTraceIncludeEntities(player, 100, MainRegistry.proxy.partialTicks()); + if(r == null || r.typeOfHit == Type.MISS){ + hitPos = player.getLook(MainRegistry.proxy.partialTicks()).scale(100).add(pos); + } else { + hitPos = r.hitVec; + hitNormal = new Vec3d(r.sideHit.getFrontOffsetX(), r.sideHit.getFrontOffsetY(), r.sideHit.getFrontOffsetZ()); + } + + tag.setString("type", "spark"); + tag.setString("mode", "coneBurst"); + tag.setDouble("posX", pos.x-player.motionX); + tag.setDouble("posY", pos.y-player.motionY); + tag.setDouble("posZ", pos.z-player.motionZ); + tag.setDouble("dirX", view.x); + tag.setDouble("dirY", view.y); + tag.setDouble("dirZ", view.z); + tag.setFloat("r", 0.2F); + tag.setFloat("g", 0.8F); + tag.setFloat("b", 0.9F); + tag.setFloat("a", 1.5F); + tag.setInteger("lifetime", 1); + tag.setFloat("width", 0.01F); + tag.setFloat("length", 2F); + tag.setFloat("gravity", 0); + tag.setFloat("angle", 15F); + tag.setInteger("count", 12); + MainRegistry.proxy.effectNT(tag); + + ParticleVortexBeam beam = new ParticleVortexBeam(player.world, pos.x, pos.y, pos.z, hitPos.x, hitPos.y, hitPos.z, shouldDoThirdPerson); + beam.color(0.5F, 0.8F, 0.9F, 2.0F); + beam.width(0.125F); + Minecraft.getMinecraft().effectRenderer.addEffect(beam); + + ParticleVortexFireFlash flash = new ParticleVortexFireFlash(player.world, pos.x, pos.y, pos.z, hitPos.x, hitPos.y, hitPos.z); + flash.color(0.5F, 0.8F, 0.9F, 1F); + flash.width(0.5F); + Minecraft.getMinecraft().effectRenderer.addEffect(flash); + + Vec3 line = hitPos.subtract(pos); + int circleParticles = (int) line.lengthVector(); + for(int i = 0; i < circleParticles; i ++){ + Vec3 circlePos = line.scale(i/(float)circleParticles).add(pos); + ParticleVortexCircle c = new ParticleVortexCircle(player.worldObj, circlePos.x, circlePos.y, circlePos.z, 0.5F+player.worldObj.rand.nextFloat()*0.3F); + c.color(0.5F, 0.8F, 0.9F, 0.15F); + c.lifetime((int) (15+(i/(float)circleParticles)*10)); + Minecraft.getMinecraft().effectRenderer.addEffect(c); + } + + int extraParticles = (int) line.lengthVector(); + for(int i = 0; i < extraParticles; i ++){ + Vec3d circlePos = line.scale((i/(float)circleParticles)*0.25).add(pos); + float randX = (float) (player.worldObj.rand.nextGaussian()-0.5) * 0.01F; + float randY = (float) (player.worldObj.rand.nextGaussian()-0.5) * 0.01F; + float randZ = (float) (player.worldObj.rand.nextGaussian()-0.5) * 0.01F; + ParticleVortexParticle c = new ParticleVortexParticle(player.worldObj, circlePos.x+randX, circlePos.y+randY, circlePos.z+randZ, 0.5F); + c.color(0.5F, 0.8F, 0.9F, 0.15F); + c.lifetime(30); + Minecraft.getMinecraft().effectRenderer.addEffect(c); + } + + ParticleVortexGlow glow = new ParticleVortexGlow(player.worldObj, pos.x, pos.y, pos.z, 2F); + glow.color(0.3F, 0.7F, 1F, 0.5F); + glow.lifetime(15); + Minecraft.getMinecraft().effectRenderer.addEffect(glow); + + if(hitNormal != null){ + Vec3d sparkAxis = line.normalize().scale(0.25); + switch(r.sideHit.getAxis()){ + case X: + sparkAxis = new Vec3d(-sparkAxis.x, sparkAxis.y, sparkAxis.z); + break; + case Y: + sparkAxis = new Vec3d(sparkAxis.x, -sparkAxis.y, sparkAxis.z); + break; + case Z: + sparkAxis = new Vec3d(sparkAxis.x, sparkAxis.y, -sparkAxis.z); + break; + } + tag = new NBTTagCompound(); + tag.setString("type", "spark"); + tag.setString("mode", "coneBurst"); + tag.setDouble("posX", hitPos.x); + tag.setDouble("posY", hitPos.y); + tag.setDouble("posZ", hitPos.z); + tag.setDouble("dirX", sparkAxis.x); + tag.setDouble("dirY", sparkAxis.y+0.1); + tag.setDouble("dirZ", sparkAxis.z); + tag.setFloat("r", 0.2F); + tag.setFloat("g", 0.8F); + tag.setFloat("b", 0.9F); + tag.setFloat("a", 1.5F); + tag.setInteger("lifetime", 20); + tag.setInteger("randLifetime", 30); + tag.setFloat("width", 0.015F); + tag.setFloat("length", 0.5F); + tag.setFloat("gravity", 0.05F); + tag.setFloat("angle", 70F); + tag.setInteger("count", 15); + tag.setFloat("randomVelocity", 0.1F); + MainRegistry.proxy.effectNT(tag); + + ParticleVortexHit hit = new ParticleVortexHit(player.world, hitPos.x, hitPos.y, hitPos.z, 2.5F+player.world.rand.nextFloat()*0.5F, 90); + hit.color(0.4F, 0.8F, 1F, 0.25F); + hit.lifetime(20); + ParticleVortexHit hit2 = new ParticleVortexHit(player.world, hitPos.x, hitPos.y, hitPos.z, 2.5F+player.world.rand.nextFloat()*0.5F, -90); + hit2.color(0.4F, 0.8F, 1F, 0.25F); + hit2.lifetime(20); + Minecraft.getMinecraft().effectRenderer.addEffect(hit); + Minecraft.getMinecraft().effectRenderer.addEffect(hit2); + } + + MainRegistry.proxy.setRecoil(3); + lastFireTime = System.currentTimeMillis(); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasCustomHudElement() { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public void renderHud(ScaledResolution res, GuiIngame gui, ItemStack stack, float partialTicks) { + float x = res.getScaledWidth()/2; + float y = res.getScaledHeight()/2; + + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.vortex_hud_reticle); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glColor4f(0.4F, 0.9F, 0.9F, 1.0F); + GL11.glEnable(GL11.GL_BLEND); + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE, SourceFactor.ONE, DestFactor.ZERO); + RenderHelper.drawGuiRect(x - 11F, y - 11F, 0, 0, 22, 22, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.vortex_hud_circle); + + //Running off of system time gives less wonky results than relying on server updating the nbt tag. + long time = System.currentTimeMillis(); + + //float cooldown = (this.mainConfig.rateOfFire-getDelay(stack)+partialTicks)/(float)this.mainConfig.rateOfFire; + //Adding 0.05 so it doesn't start at nothing makes it look better in my opinion. + //It's 55 instead of 50 (50 ms in one tick) because xon lets you fire slightly before the cooldown is over. This extends the cooldown slightly beyond the real one. + float cooldown = MathHelper.clamp((time-lastFireTime)/(float)(mainConfig.rateOfFire*55), 0, 1)+0.05F; + final int SUBDIVISIONS = 64; + Tessellator tes = Tessellator.instance; + tes.startDrawing(GL11.GL_TRIANGLE_FAN); + + tes.setColorRGBA_F(0.4F, 0.9F, 0.9F, 0.4F); + tes.addVertexWithUV(x, y, 0, 0.5, 0.5); + + for(int i = 0; i < SUBDIVISIONS+1; i ++){ + //Should be quite fast because MathHelper uses a sin table... right? + float ratio = i/(float)SUBDIVISIONS; + float x2 = MathHelper.sin((float) (ratio*Math.PI*2+0.5*Math.PI)); + float y2 = MathHelper.cos((float) (ratio*Math.PI*2+0.5*Math.PI)); + float alphaMult = 1-ratio < cooldown ? 1 : 0; + buf.pos(x+x2*11, y+y2*11, 0).tex(BobMathUtil.remap01(x2, -1, 1), BobMathUtil.remap01(y2, -1, 1)).color(0.4F, 0.9F, 0.9F, 0.4F*alphaMult).endVertex(); + } + tes.draw(); + + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); + GlStateManager.disableBlend(); + }*/ } diff --git a/src/main/java/com/hbm/particle/ParticleVortexCircle.java b/src/main/java/com/hbm/particle/ParticleVortexCircle.java new file mode 100644 index 000000000..bdde31949 --- /dev/null +++ b/src/main/java/com/hbm/particle/ParticleVortexCircle.java @@ -0,0 +1,5 @@ +package com.hbm.particle; + +public class ParticleVortexCircle { + +} diff --git a/src/main/java/com/hbm/particle/ParticleVortexGlow.java b/src/main/java/com/hbm/particle/ParticleVortexGlow.java new file mode 100644 index 000000000..1f32cd493 --- /dev/null +++ b/src/main/java/com/hbm/particle/ParticleVortexGlow.java @@ -0,0 +1,94 @@ +package com.hbm.particle; + +import org.lwjgl.opengl.GL11; + +import com.hbm.lib.RefStrings; +import com.hbm.util.BobMathUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +public class ParticleVortexGlow extends EntityFX { + + public static final ResourceLocation fresnel_ms = new ResourceLocation(RefStrings.MODID, "textures/particle/fresnel_ms.png"); + public float workingAlpha; + + public ParticleVortexGlow(World worldIn, double posXIn, double posYIn, double posZIn, float scale) { + super(worldIn, posXIn, posYIn, posZIn); + this.particleScale = scale; + } + + public ParticleVortexGlow color(float colR, float colG, float colB, float colA) { + this.particleRed = colR; + this.particleGreen = colG; + this.particleBlue = colB; + this.particleAlpha = colA; + workingAlpha = colA; + return this; + } + + public ParticleVortexGlow lifetime(int lifetime) { + this.particleMaxAge = lifetime; + return this; + } + + @Override + public void onUpdate() { + this.particleAge++; + if(this.particleAge >= this.particleMaxAge) { + this.setDead(); + } + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public void renderParticle(Tessellator tess, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + + Minecraft.getMinecraft().getTextureManager().bindTexture(fresnel_ms); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + float timeScale = (this.particleAge + partialTicks) / (float) this.particleMaxAge; + float shrink = MathHelper.clamp_float(1 - BobMathUtil.remap((float) MathHelper.clamp_float(timeScale, 0, 1), 0.6F, 1F, 0.6F, 1F), 0, 1); + this.workingAlpha = shrink * particleAlpha; + + float f4 = 0.1F * (this.particleScale + shrink * particleScale * 4); + + float f5 = (float) (this.prevPosX + (this.posX - this.prevPosX) * (double) partialTicks - interpPosX); + float f6 = (float) (this.prevPosY + (this.posY - this.prevPosY) * (double) partialTicks - interpPosY); + float f7 = (float) (this.prevPosZ + (this.posZ - this.prevPosZ) * (double) partialTicks - interpPosZ); + Vec3[] avec3d = new Vec3[] { + Vec3.createVectorHelper((double) (-rotationX * f4 - rotationXY * f4), (double) (-rotationZ * f4), (double) (-rotationYZ * f4 - rotationXZ * f4)), + Vec3.createVectorHelper((double) (-rotationX * f4 + rotationXY * f4), (double) (rotationZ * f4), (double) (-rotationYZ * f4 + rotationXZ * f4)), + Vec3.createVectorHelper((double) (rotationX * f4 + rotationXY * f4), (double) (rotationZ * f4), (double) (rotationYZ * f4 + rotationXZ * f4)), + Vec3.createVectorHelper((double) (rotationX * f4 - rotationXY * f4), (double) (-rotationZ * f4), (double) (rotationYZ * f4 - rotationXZ * f4)) + }; + + tess.setColorRGBA_F(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha); + tess.setNormal(0.0F, 1.0F, 0.0F); + tess.setBrightness(240); + + tess.startDrawingQuads(); + tess.addVertexWithUV((double) f5 + avec3d[0].xCoord, (double) f6 + avec3d[0].yCoord, (double) f7 + avec3d[0].zCoord, 1, 1); + tess.addVertexWithUV((double) f5 + avec3d[1].xCoord, (double) f6 + avec3d[1].yCoord, (double) f7 + avec3d[1].zCoord, 1, 0); + tess.addVertexWithUV((double) f5 + avec3d[2].xCoord, (double) f6 + avec3d[2].yCoord, (double) f7 + avec3d[2].zCoord, 0, 0); + tess.addVertexWithUV((double) f5 + avec3d[3].xCoord, (double) f6 + avec3d[3].yCoord, (double) f7 + avec3d[3].zCoord, 0, 1); + + tess.draw(); + + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glDepthMask(true); + GL11.glDisable(GL11.GL_BLEND); + } +} diff --git a/src/main/java/com/hbm/particle/ParticleVortexParticle.java b/src/main/java/com/hbm/particle/ParticleVortexParticle.java new file mode 100644 index 000000000..fdaf489ee --- /dev/null +++ b/src/main/java/com/hbm/particle/ParticleVortexParticle.java @@ -0,0 +1,119 @@ +package com.hbm.particle; + +import org.lwjgl.opengl.GL11; + +import com.hbm.lib.RefStrings; +import com.hbm.util.BobMathUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +public class ParticleVortexParticle extends EntityFX { + + public static final ResourceLocation fresnel_ms = new ResourceLocation(RefStrings.MODID, "textures/particle/fresnel_ms.png"); + + public float workingAlpha; + public int timeUntilChange = 0; + + public ParticleVortexParticle(World worldIn, double posXIn, double posYIn, double posZIn, float scale) { + super(worldIn, posXIn, posYIn, posZIn); + this.particleScale = scale; + this.motionX = (rand.nextFloat() - 0.5) * 0.02; + this.motionY = (rand.nextFloat() - 0.5) * 0.02; + this.motionZ = (rand.nextFloat() - 0.5) * 0.02; + timeUntilChange = rand.nextInt(5) + 1; + } + + public ParticleVortexParticle color(float colR, float colG, float colB, float colA) { + this.particleRed = colR; + this.particleGreen = colG; + this.particleBlue = colB; + this.particleAlpha = colA; + workingAlpha = colA; + return this; + } + + public ParticleVortexParticle lifetime(int lifetime) { + this.particleMaxAge = lifetime; + return this; + } + + @Override + public void onUpdate() { + + this.particleAge++; + timeUntilChange--; + + if(this.particleAge >= this.particleMaxAge) { + this.setDead(); + } + + this.prevPosX = posX; + this.prevPosY = posY; + this.prevPosZ = posZ; + this.posX += this.motionX; + this.posY += this.motionY; + this.posZ += this.motionZ; + + if(timeUntilChange == 0) { + timeUntilChange = rand.nextInt(5) + 1; + // Not quite as smooth as the actual noise I think xonotic uses, but + // it's good enough. + this.motionX = (rand.nextFloat() - 0.5) * 0.02; + this.motionY = (rand.nextFloat() - 0.5) * 0.02; + this.motionZ = (rand.nextFloat() - 0.5) * 0.02; + } + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public void renderParticle(Tessellator tess, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + + Minecraft.getMinecraft().getTextureManager().bindTexture(fresnel_ms); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + float timeScale = (this.particleAge + partialTicks) / (float) this.particleMaxAge; + float shrink = MathHelper.clamp_float(1 - BobMathUtil.remap((float) MathHelper.clamp_float(timeScale, 0, 1), 0.6F, 1F, 0.6F, 1F), 0, 1); + this.workingAlpha = shrink * particleAlpha; + + float f4 = 0.1F * (this.particleScale + shrink * particleScale * 4); + + float f5 = (float) (this.prevPosX + (this.posX - this.prevPosX) * (double) partialTicks - interpPosX); + float f6 = (float) (this.prevPosY + (this.posY - this.prevPosY) * (double) partialTicks - interpPosY); + float f7 = (float) (this.prevPosZ + (this.posZ - this.prevPosZ) * (double) partialTicks - interpPosZ); + Vec3[] avec3d = new Vec3[] { + Vec3.createVectorHelper((double) (-rotationX * f4 - rotationXY * f4), (double) (-rotationZ * f4), (double) (-rotationYZ * f4 - rotationXZ * f4)), + Vec3.createVectorHelper((double) (-rotationX * f4 + rotationXY * f4), (double) (rotationZ * f4), (double) (-rotationYZ * f4 + rotationXZ * f4)), + Vec3.createVectorHelper((double) (rotationX * f4 + rotationXY * f4), (double) (rotationZ * f4), (double) (rotationYZ * f4 + rotationXZ * f4)), + Vec3.createVectorHelper((double) (rotationX * f4 - rotationXY * f4), (double) (-rotationZ * f4), (double) (rotationYZ * f4 - rotationXZ * f4)) + }; + + tess.setColorRGBA_F(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha); + tess.setNormal(0.0F, 1.0F, 0.0F); + tess.setBrightness(240); + + tess.startDrawingQuads(); + tess.addVertexWithUV((double) f5 + avec3d[0].xCoord, (double) f6 + avec3d[0].yCoord, (double) f7 + avec3d[0].zCoord, 1, 1); + tess.addVertexWithUV((double) f5 + avec3d[1].xCoord, (double) f6 + avec3d[1].yCoord, (double) f7 + avec3d[1].zCoord, 1, 0); + tess.addVertexWithUV((double) f5 + avec3d[2].xCoord, (double) f6 + avec3d[2].yCoord, (double) f7 + avec3d[2].zCoord, 0, 0); + tess.addVertexWithUV((double) f5 + avec3d[3].xCoord, (double) f6 + avec3d[3].yCoord, (double) f7 + avec3d[3].zCoord, 0, 1); + + tess.draw(); + + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glDepthMask(true); + GL11.glDisable(GL11.GL_BLEND); + } +} diff --git a/src/main/java/com/hbm/render/entity/projectile/RenderBullet.java b/src/main/java/com/hbm/render/entity/projectile/RenderBullet.java index 11ea0b503..b19c898bb 100644 --- a/src/main/java/com/hbm/render/entity/projectile/RenderBullet.java +++ b/src/main/java/com/hbm/render/entity/projectile/RenderBullet.java @@ -316,9 +316,9 @@ public class RenderBullet extends Render { case BulletConfiguration.BOLT_ZOMG: Random rand = new Random(eID * eID); - red = rand.nextInt(2) * 0.8F; - green = rand.nextInt(2) * 0.8F; - blue = rand.nextInt(2) * 0.8F; + red = rand.nextInt(2) * 0.6F; + green = rand.nextInt(2) * 0.6F; + blue = rand.nextInt(2) * 0.6F; break; } diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineRadar.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineRadar.java index a72d67644..150e1a736 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineRadar.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineRadar.java @@ -31,6 +31,7 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo public boolean scanMissiles = true; public boolean scanPlayers = true; public boolean smartMode = true; + public boolean redMode = true; public float prevRotation; public float rotation; @@ -98,6 +99,7 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo case 0: this.scanMissiles = !this.scanMissiles; break; case 1: this.scanPlayers = !this.scanPlayers; break; case 2: this.smartMode = !this.smartMode; break; + case 3: this.redMode = !this.redMode; break; } } @@ -131,21 +133,39 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo if(!entList.isEmpty()) { - double maxRange = WeaponConfig.radarRange * Math.sqrt(2D); - - int power = 0; - - for(int i = 0; i < entList.size(); i++) { + /// PROXIMITY /// + if(redMode) { - Entity e = entList.get(i); - double dist = Math.sqrt(Math.pow(e.posX - xCoord, 2) + Math.pow(e.posZ - zCoord, 2)); - int p = 15 - (int)Math.floor(dist / maxRange * 15); + double maxRange = WeaponConfig.radarRange * Math.sqrt(2D); - if(p > power) - power = p; + int power = 0; + + for(int i = 0; i < entList.size(); i++) { + + Entity e = entList.get(i); + double dist = Math.sqrt(Math.pow(e.posX - xCoord, 2) + Math.pow(e.posZ - zCoord, 2)); + int p = 15 - (int)Math.floor(dist / maxRange * 15); + + if(p > power) + power = p; + } + + return power; + + /// TIER /// + } else { + + int power = 0; + + for(int i = 0; i < nearbyMissiles.size(); i++) { + + if(nearbyMissiles.get(i)[3] + 1 > power) { + power = nearbyMissiles.get(i)[3] + 1; + } + } + + return power; } - - return power; } return 0; @@ -158,6 +178,7 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo data.setBoolean("scanMissiles", scanMissiles); data.setBoolean("scanPlayers", scanPlayers); data.setBoolean("smartMode", smartMode); + data.setBoolean("redMode", redMode); data.setInteger("count", this.nearbyMissiles.size()); for(int i = 0; i < this.nearbyMissiles.size(); i++) { @@ -177,6 +198,7 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo this.scanMissiles = data.getBoolean("scanMissiles"); this.scanPlayers = data.getBoolean("scanPlayers"); this.smartMode = data.getBoolean("smartMode"); + this.redMode = data.getBoolean("redMode"); int count = data.getInteger("count"); @@ -217,6 +239,7 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo this.scanMissiles = nbt.getBoolean("scanMissiles"); this.scanPlayers = nbt.getBoolean("scanPlayers"); this.smartMode = nbt.getBoolean("smartMode"); + this.redMode = nbt.getBoolean("redMode"); } @Override @@ -226,6 +249,7 @@ public class TileEntityMachineRadar extends TileEntityTickingBase implements ICo nbt.setBoolean("scanMissiles", scanMissiles); nbt.setBoolean("scanPlayers", scanPlayers); nbt.setBoolean("smartMode", smartMode); + nbt.setBoolean("redMode", redMode); } @Override diff --git a/src/main/java/com/hbm/util/BobMathUtil.java b/src/main/java/com/hbm/util/BobMathUtil.java index 071f5e361..5fb71ca24 100644 --- a/src/main/java/com/hbm/util/BobMathUtil.java +++ b/src/main/java/com/hbm/util/BobMathUtil.java @@ -32,4 +32,7 @@ public class BobMathUtil { return angle; } + public static float remap(float num, float min1, float max1, float min2, float max2){ + return ((num - min1) / (max1 - min1)) * (max2 - min2) + min2; + } } diff --git a/src/main/resources/assets/hbm/lang/de_DE.lang b/src/main/resources/assets/hbm/lang/de_DE.lang index 2b2a8458a..d0b848158 100644 --- a/src/main/resources/assets/hbm/lang/de_DE.lang +++ b/src/main/resources/assets/hbm/lang/de_DE.lang @@ -2308,6 +2308,7 @@ potion.hbm_telekinesis=! ! ! radar.detectMissiles=Raketen erkennen radar.detectPlayers=Spieler erkennen +radar.redMode=Redstone Mode$Ein: Redstonesignal basiert auf Nähe$Aus: Redstonesignal basiert auf Größe radar.smartMode=Smart Mode$Redstonesignal ignoriert aufsteigende Raketen tile.absorber.name=Strahlungs-Absorber diff --git a/src/main/resources/assets/hbm/lang/en_US.lang b/src/main/resources/assets/hbm/lang/en_US.lang index 7068c5c38..c50e3dd13 100644 --- a/src/main/resources/assets/hbm/lang/en_US.lang +++ b/src/main/resources/assets/hbm/lang/en_US.lang @@ -2319,6 +2319,7 @@ potion.hbm_telekinesis=! ! ! radar.detectMissiles=Detect Missiles radar.detectPlayers=Detect Players +radar.redMode=Redstone Mode$On: Redstone output based on range$Off: Redstone output based on tier radar.smartMode=Smart Mode$Redstone output ignores ascending missiles tile.absorber.name=Radiation Absorber diff --git a/src/main/resources/assets/hbm/textures/blocks/block_actinium.png b/src/main/resources/assets/hbm/textures/blocks/block_actinium.png new file mode 100644 index 0000000000000000000000000000000000000000..b909aa3ba8031e221185bfb7a9ffa1ed7148f60e GIT binary patch literal 554 zcmV+_0@eMAP)#=$*d(c=4rz94P^jNDUQ2c0E8@)*`EN+84T`0d;;K^lm!L%mY1Cl&l^nuY?e9y zMH{Ixyn4|gv(~9DD3O#dxL~H6{h>((YtA(c&sWH?Wjh!avzhZCi!pm*UndE_0pM!g!6NcI;{X5v07*qoM6N<$g0U literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hbm/textures/blocks/block_lanthanium.png b/src/main/resources/assets/hbm/textures/blocks/block_lanthanium.png new file mode 100644 index 0000000000000000000000000000000000000000..31479d52db83d488ce097c63029ae881178be5e6 GIT binary patch literal 570 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 diff --git a/src/main/resources/assets/hbm/textures/gui/machine/gui_radar.png b/src/main/resources/assets/hbm/textures/gui/machine/gui_radar.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1d186a92c6bcff24abc3daa79a62b585d55236 GIT binary patch literal 2604 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 Z{s*CY%eebw+4KMa002ovPDHLkV1m55-A@1j delta 2321 zcmV+s3GVis6sr=DGk*x;Nkl-+ylEeCwtKhJlcAPiLlfzs5tdNAF<4A6AtpWFI>8);zts`(vKuW zz*$DJOh-WkbtY9tu!L6Hnj~j3gM;sGhyE>*eRxDA5qh8L#1kf`@ zx2yLY(c$Jt<`TfQT|ZM>x&4R^H+y);CVjawsw!3%xPArM?e&obw2lpE=6SXg07wn##dUL`C;Y}T0m)&&OW`i|aE;Y3t{FH%l$A1LzbaA}|z`#Cu@gktmL;p#HC;$Kk zV`gG3J80fpek1a@kx==ILzM5QE-1|okKgrERsY}i4?*>VF~gRhe|9zgYp(!Xg}^5E z%f5jUy?0RJN&!-Ich#QFYuBEbv2e1pAKAL1k`jk5%w6s~0HzJv9y1;W!kbF>ZaS1;z@_qapjx*;QZx(L+qHW7pEHZ_J z#=m+{N~X<7ELQPRNeQwEZ=VoP8`rAuQ2a(eM%?N}Yd7X?T0kUu@% z+jXYjQZ_LbiO76q;=79&jv+`aRjv@BSbx^kKX5_AR6QKy#mQfga&j5-U^@u_Fsg1W z&%X<&Cf{~^sG(+mN6`EKiWKhK6+idgqN`0Q|6#%OO|DKB)BeexEWZ73oSlswRS8@# z0RW)7sq*0SOx)PPP}!>sMB;d$jk=qCJ?D?qHy4yyU<3#Yr5ZDKj8Gnu#K4f81b@uX zI@9<-b?@DePc*l_{jmwu6RUhg5z&4DE2Af@V;D5H-yytp%1@VD1GqBw0^3&wXFUBb z_bJ$wcw8~<7l4l33Ahu$0Zg~mn|~@n9K8*6CxC;PDhZtN#M|Ru12~YWgm$L*04}-> zbY+|^xIMGV8GEF@5lfHE3x9i~w`Z~sVmNC3aBF#c-SIu0#xt)h&AfCPjP@5al8i<-5Ez9}AOfA*bf%{q<7)~lbk-*1H@ zynsDEknmy>;w3;3ZN01)^@ro18RT)(5=QVIYdkj`EHhCj6i z0ft}!UjhH4J3Jc%cNutrNm;s_9M-Znwjt5h^g$%)#Q~2;1`+|>KW)sukF!>qf98cE zAD)+SPk%SNA7`yH7YI=_OoOj{aqj)>Z02rq!e1&j<&4sq2|XDkcz;a{Kzw3PTGkbu zlY?qeSxGhiS^5iuX7#DB6c zP?9A>G@)m}_(X=R{r=+Q{dHiid8Zusqz)g@gS%R7$E5j_7yhOGVmT)8|qS1!+eF+iLtvBu32 zg~t6r%2{R}?!H+xYW}LCTXjx_DK;}1l5hz>F8Bf-V}H&ycfZpCUT9l{eBTS< zirw=;3#VIp52-LP1efdMiU}}l*8l(jJ?f^iY;{vvfFv++Yh=v6!eHsvpDa>-SXc4+ zch1=@)TU*+em?*#2?@@RLzvWYeE9_n6HZ|yAT1bJo=?c)?~Crt|HUZ24TvJVNhHFo z#i$*U5pns&V_SmiF z-Ir+4A<|0_EkGgP+B`=l$Pf11!T|&l@f_uLg<{8!Q2+dJ0w_Qta%+gsD*yn9q=aGu zNS3DcdaSpcYgZp1K@=$>%)Ij*y}$2aXp@cwBOPp$dmE&4mP-+f zYE*rHw}}q`VAQCpJ~f1?_V5GcFZtE4x@I8zga`=CGDZ^y4D5Zwfol~@57;IU3}s-z r06_YRNF)T9w8eDe#*Ld<&3^%y$O;h{n`RUM015yANkvXXu0mjfc&cDL diff --git a/src/main/resources/assets/hbm/textures/models/tank_ULTRAHOTSTEAM.png b/src/main/resources/assets/hbm/textures/models/tank_ULTRAHOTSTEAM.png new file mode 100644 index 0000000000000000000000000000000000000000..c95495fd85a2eaec40f25ca0685b23f82678c0c6 GIT binary patch literal 2347 zcmV+`3Dow9P)D?yaDK;gfpB`DC z+?D5n0-f!bt3f#1f&UkpWz8m*HPV1thGor0mNn4;*x7!$apO`TXFKquAfCd%EHj}y z1NY&)(rRfj4PyWRYZq=fSsupSd8_eqVR9>Z^v$%S%ezIqIB$|8Brrp3#&tb4{dY^> zZt8sNrUiz9ka16Ergp!^L$XKjV8I_&l|Gk0ASo|gx~Squ628)pBt*bkO#Ne{?blQt z=YQ3vI@Uyk-Wl=FG^Dc~csfuh*h?^1Mw&&n{rCRS!jMLVw_oz6$c6h;`E=mCn%>+& z+fZy_8wc-SX=AK{Vj9<)a6bTrLPVZ1fg~+%AJ)`#VjdGMmM(lbMtU$qTpPczrhBsr z1M9R9XNYGs0jyvx{lTr9dygA%4@VpmU%NV{HdZWAhNE82!vxSXMYpT>9MR$CN9Gd1 zwOv0`Tewn##dUL`C;Y}T0 zm)&&OW`i|aE;Y3t{FH%l#{}_oalHh000JKW@0QmXx>|XBl5VB zQ2C2Pl<%i5D9sL!-}O^f|KIixLG^<%!*}9^V5{E9#UG6&orVZL2Gad%Qn@acNt_A==q_1$T4>yGX7Wa%B zyO^&{V%P!gaDBZA1_5yiKQ8ip{2Pul=NoSpZv3Kc%U3Kig@nexdQeKH%}6X(@li<$ zvI%dW5KkM|s{pLpe6~w>Ha|*K@N#l`@nY>*9m5v|NAZw9J>J`Orr%OFF&2r)d}ZRh zix`d}NGw&Z5TRJs)IV@R!&E&S! z|B4ju+Z8|e-J+{aDgR-?^i8f#7SsO8o-DroZ=9Wt9aRZjF986cx~cNu^Gw{>!BE+& z3q<00ppCkleLd%o)HfHDSzrVR3#A$}c8pLSlElD}oCM6!I@9<-b?@DePc*l_{jmwu z6RUhg5z&4DE2Af@V;D5H-yytp%1@VD1GqBw0^3&wXFUBb_bJ$wcw8~<7l4l33Ahu$ z0Zg~mn<_yZy$y6HfPMI;G$5_?EtrZ57oqMJ7;Bo{<#0?r>Fs-I1-%<(yAdt>o{)Rub1_6d(0bc?CqdPns1a}#Dfk|1q zoE+A&Hnt(r*7QLn>BRw$M+OoB+&^v1zK^q3nt$enA|IZYaZi6YyB}w*G8YI@G)#l9 zd~xpm>}=+4a>8FKHsy@cnF&1^BzR2>Kzw3PTGkbulY?qeSxGhiS^5iuX7#DB6cP?9A>G@)m}_(X=R{r=+Qa0x#y_yQhd&NX+x(*a&+TZDYy3*n00^Fa%zTY3+vFfas{>*IS%)Y{4>DHetQhr!h@%eYo*)7zjWx9Sp04xa!&W}Tw)Ny?I z1q%~SVI&|e7+9W9$l~vd?#%ziD83DdBD_f?!mP!p9_+Y!YB=nRqe05er!mPG2Ai+^ zK||k&!+;URl}OyLfSH6sG9Jet0HA-QulCrj=G~WQ&>_-G5G_C<-`YG!Cdd!=+`<6_ z67d}6c7DlVOA(7|RDFN9i4Oo^)TpXHHH4}5@B`&9`PHww zW+3~72nftFMiT}M?0v(5YZXfm*d`DRWnjPnK>CVEBm|hW#dPDwjhk7`e*u`t3K1Ba RW)uJb002ovPDHLkV1hXmT^0ZU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hbm/textures/particle/fresnel_ms.png b/src/main/resources/assets/hbm/textures/particle/fresnel_ms.png new file mode 100644 index 0000000000000000000000000000000000000000..dad9ee5e41dae0b78145d2e5b76853f17898833a GIT binary patch literal 14226 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