Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bomb investigation #53

Merged
merged 12 commits into from
May 26, 2024
314 changes: 182 additions & 132 deletions src/main/java/dev/adventurecraft/awakening/common/AC_EntityBomb.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package dev.adventurecraft.awakening.common;

import java.util.List;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
Expand All @@ -11,135 +9,187 @@
import net.minecraft.util.math.AxixAlignedBoundingBox;
import net.minecraft.world.World;

import java.util.Random;

public class AC_EntityBomb extends ItemEntity {
private static final double BOMB_DAMAGE = 20.0D;
private static final double BOMB_RANGE = 5.0D;
private static final double BOMB_DESTROY_RANGE = 3.0D;
private static final int BOMB_FUSE = 45;
private int fuse;
private Entity parentEntity;

public AC_EntityBomb(World var1) {
super(var1);
this.setSize(0.5F, 0.5F);
this.stack = new ItemStack(AC_Items.bomb);
this.fuse = 45;
}

public AC_EntityBomb(World var1, Entity var2) {
this(var1);
this.parentEntity = var2;
this.setRotation(var2.yaw, var2.pitch);
this.xVelocity = 0.3D * -Math.sin((double)(this.yaw / 180.0F * 3.141593F)) * Math.cos((double)(this.pitch / 180.0F * 3.141593F));
this.zVelocity = 0.3D * Math.cos((double)(this.yaw / 180.0F * 3.141593F)) * Math.cos((double)(this.pitch / 180.0F * 3.141593F));
this.yVelocity = 0.3D * -Math.sin((double)(this.pitch / 180.0F * 3.141593F)) + (double)0.1F;
this.setPosition(var2.x, var2.y, var2.z);
this.prevX = this.x;
this.prevY = this.y;
this.prevZ = this.z;
}

public void tick() {
super.tick();
if(this.fuse == 45) {
this.world.playSound(this, "random.fuse", 1.0F, 1.0F);
}

--this.fuse;
double var1 = (double)this.fuse / 45.0D;
double var3 = 0.2D * var1;
if(this.fuse == 0) {
explode(this, this.parentEntity, this.world, this.x, this.y, this.z);
} else if(this.fuse % 2 == 0) {
this.world.addParticle("smoke", this.x, this.y + 0.675D + var3, this.z, 0.0D, 0.0D, 0.0D);
} else {
this.world.addParticle("flame", this.x, this.y + 0.675D + var3, this.z, 0.0D, 0.0D, 0.0D);
}

}

public static void explode(Entity var0, Entity var1, World var2, double var3, double var5, double var7) {
var0.remove();
var2.playSound(var3, var5, var7, "random.explode", 4.0F, 1.0F);
List var9 = var2.getEntities(var0, AxixAlignedBoundingBox.createAndAddToList(Math.floor(var3 - 5.0D), Math.floor(var5 - 5.0D), Math.floor(var7 - 5.0D), Math.ceil(var3 + 5.0D), Math.ceil(var5 + 5.0D), Math.ceil(var7 + 5.0D)));

int var10;
for(var10 = 0; var10 < var9.size(); ++var10) {
Entity var11 = (Entity)var9.get(var10);
double var12 = var11.distanceTo(var3, var5, var7);
if(var12 < 5.0D) {
var12 = (5.0D - var12) / 5.0D;
double var14 = var11.x - var3;
double var16 = var11.y - var5;
double var18 = var11.z - var7;
var11.accelerate(var12 * var14, var12 * var16, var12 * var18);
var11.damage(var1, (int)Math.ceil(var12 * 20.0D));
}
}

var10 = (int)var3;
int var22 = (int)var5;
int var23 = (int)var7;

int var15;
int var25;
for(int var13 = -3; var13 <= 3; ++var13) {
for(var25 = -3; var25 <= 3; ++var25) {
for(var15 = -3; var15 <= 3; ++var15) {
Double var26 = Double.valueOf((double)var13 * (double)var13 + (double)(var25 * var25) + (double)(var15 * var15));
if(var26.doubleValue() <= 9.0D) {
int var17 = var2.getBlockId(var10 + var13, var22 + var25, var23 + var15);
if(Block.BY_ID[var17] instanceof AC_BlockBombable) {
var2.setBlock(var10 + var13, var22 + var25, var23 + var15, 0);
}
}
}
}
}

Random var24 = new Random();
var24.setSeed(var2.getWorldTime());

for(var25 = -3; var25 <= 3; ++var25) {
for(var15 = -3; var15 <= 3; ++var15) {
for(int var27 = -3; var27 <= 3; ++var27) {
Double var28 = Double.valueOf((double)var25 * (double)var25 + (double)(var15 * var15) + (double)(var27 * var27));
if(var24.nextInt(3) == 0 && var28.doubleValue() <= 9.0D) {
Double var29 = Double.valueOf((double)var25);
Double var19 = Double.valueOf((double)var15);
Double var20 = Double.valueOf((double)var27);
Double var21 = Double.valueOf(Math.sqrt(var28.doubleValue()) * (0.75D + 0.5D * var24.nextDouble()) * 1.5D / 3.0D);
var29 = Double.valueOf(var29.doubleValue() / var21.doubleValue());
var19 = Double.valueOf(var19.doubleValue() / var21.doubleValue());
var20 = Double.valueOf(var20.doubleValue() / var21.doubleValue());
var2.addParticle("explode", var3, var5, var7, var29.doubleValue(), var19.doubleValue(), var20.doubleValue());
var2.addParticle("smoke", var3, var5, var7, var29.doubleValue(), var19.doubleValue(), var20.doubleValue());
}
}
}
}

}

public boolean damage(Entity var1, int var2) {
if(!this.removed) {
this.setAttacked();
explode(this, this.parentEntity, this.world, this.x, this.y, this.z);
}

return false;
}

public void writeAdditional(CompoundTag var1) {
super.writeAdditional(var1);
var1.put("Fuse", (byte)this.fuse);
}

public void readAdditional(CompoundTag var1) {
super.readAdditional(var1);
this.fuse = var1.getByte("Fuse");
}

public void onPlayerCollision(PlayerEntity var1) {
}
private static final double BOMB_DAMAGE = 20.0D;
private static final double BOMB_RANGE = 5.0D;
private static final double BOMB_DESTROY_RANGE = 3.0D;
private static final int BOMB_FUSE = 45;
private int fuse;
private Entity parentEntity;

public AC_EntityBomb(World var1) {
super(var1);
this.setSize(0.5F, 0.5F);
this.stack = new ItemStack(AC_Items.bomb);
this.fuse = BOMB_FUSE;
}

public AC_EntityBomb(World world, Entity entity) {
this(world);
this.parentEntity = entity;
this.setRotation(entity.yaw, entity.pitch);
this.xVelocity = 0.3D * -Math.sin(this.yaw / 180.0F * 3.141593F) * Math.cos(this.pitch / 180.0F * 3.141593F);
this.zVelocity = 0.3D * Math.cos(this.yaw / 180.0F * 3.141593F) * Math.cos(this.pitch / 180.0F * 3.141593F);
this.yVelocity = 0.3D * -Math.sin(this.pitch / 180.0F * 3.141593F) + (double) 0.1F;
this.setPosition(entity.x, entity.y, entity.z);
this.prevX = this.x;
this.prevY = this.y;
this.prevZ = this.z;
}

public void tick() {
super.tick();
if (this.fuse == 45) {
this.world.playSound(this, "random.fuse", 1.0F, 1.0F);
}

--this.fuse;
double fuseRemaining = (double) this.fuse / BOMB_FUSE;
// The particle effects animate as if the fuse was burning, drawing the fire and smoke lower!
double flameSourceMod = 0.2D * fuseRemaining;

if (this.fuse == 0) {
explode(this, this.parentEntity, this.world, this.x, this.y, this.z);
} else if (this.fuse % 2 == 0) {
this.world.addParticle("smoke", this.x, this.y + 0.675D + flameSourceMod, this.z, 0.0D, 0.0D, 0.0D);
} else {
this.world.addParticle("flame", this.x, this.y + 0.675D + flameSourceMod, this.z, 0.0D, 0.0D, 0.0D);
}

}

/**
* Deals damage around a given entity (radius defined by the BOMB_RANGE)
* @param world The world where the entities will be harmed
* @param exploder The entity that will explode
* @param explosionParent The owner of the explosive (the owner of the damage)
*/
private static void harmEntitiesAround(World world, Entity exploder, Entity explosionParent) {
double x = exploder.x;
double y = exploder.y;
double z = exploder.z;
var victims = world.getEntities(
exploder,
AxixAlignedBoundingBox.createAndAddToList(
Math.floor(x - BOMB_RANGE),
Math.floor(y - BOMB_RANGE),
Math.floor(z - BOMB_RANGE),
Math.ceil(x + BOMB_RANGE),
Math.ceil(y + BOMB_RANGE),
Math.ceil(z + BOMB_RANGE)
)
);

int victimIndex;
int victimAmount = victims.size();
for (victimIndex = 0; victimIndex < victimAmount; ++victimIndex) {
Entity victim = (Entity) victims.get(victimIndex);
// TODO: This is a band-aid fix that prevents players' accumulated hit boxes from being accelerated (and thus accelerating multiple times from a single explosion.)
if (!victim.isAlive()) continue;
// End of band-aid fix
double distanceFromExplosion = victim.distanceTo(x, y, z);
if (distanceFromExplosion < BOMB_RANGE) {
distanceFromExplosion = (BOMB_RANGE - distanceFromExplosion) / BOMB_RANGE; // Percentage of how close the character is
double xForce = victim.x - x;
double yForce = victim.y - y;
double zForce = victim.z - z;
victim.accelerate(distanceFromExplosion * xForce, distanceFromExplosion * yForce, distanceFromExplosion * zForce);
victim.damage(explosionParent, (int) Math.ceil(distanceFromExplosion * BOMB_DAMAGE));
}
}
}

/**
* Destroys blocks around a given block (radius defined by BOMB_DESTROY_RANGE)
* @param world The world to check for bombable blocks
* @param x The source of the explosion's X position.
* @param y The source of the explosion's Y position.
* @param z The source of the explosion's Z position.
*/
private static void destroyBombableBlocksAround(World world, int x, int y, int z) {

int bombDestroyRange = (int) BOMB_DESTROY_RANGE;
// Look for blocks in a volume centered on the explosion's center block's origin corner.
for (int blockOffsetX = -bombDestroyRange; blockOffsetX <= bombDestroyRange; ++blockOffsetX) {
for (int blockOffsetY = -bombDestroyRange; blockOffsetY <= bombDestroyRange; ++blockOffsetY) {
for (int blockOffsetZ = -bombDestroyRange; blockOffsetZ <= bombDestroyRange; ++blockOffsetZ) {
double distanceSquared = (double) blockOffsetX * (double) blockOffsetX + (double) (blockOffsetY * blockOffsetY) + (double) (blockOffsetZ * blockOffsetZ);
if (distanceSquared <= 9.0D) {
int blockAtOffset = world.getBlockId(x + blockOffsetX, y + blockOffsetY, z + blockOffsetZ);
// Remove bombable tiles
if (Block.BY_ID[blockAtOffset] instanceof AC_BlockBombable) {
world.setBlock(x + blockOffsetX, y + blockOffsetY, z + blockOffsetZ, 0);
}
}
}
}
}
}

/**
* Displays explosion particles sourced from a position.
* @param world The world in which to spawn the particles.
* @param x The source of the particles' X position.
* @param y The source of the particles' Y position.
* @param z The source of the particles' Z position.
*/
private static void displayExplosionParticles(World world, double x, double y, double z) {
Random rng = new Random();
rng.setSeed(world.getWorldTime());

// This is for the smoke coming out of the explosion.
for (int xDirectionForce = -3; xDirectionForce <= 3; ++xDirectionForce) { // Used for X
for (int yDirectionForce = -3; yDirectionForce <= 3; ++yDirectionForce) { // Used for Y
for (int zDirectionForce = -3; zDirectionForce <= 3; ++zDirectionForce) {

double distanceSquared = (double) xDirectionForce * (double) xDirectionForce + (double) (yDirectionForce * yDirectionForce) + (double) (zDirectionForce * zDirectionForce);
if (rng.nextInt(3) == 0 && distanceSquared <= 9.0D) {
double launchPower = Math.sqrt(distanceSquared) * (0.375D + 0.25D * rng.nextDouble());
double xDirection = xDirectionForce / launchPower;
double yDirection = yDirectionForce / launchPower;
double zDirection = zDirectionForce / launchPower;

world.addParticle("explode", x, y, z, xDirection, yDirection, zDirection);
world.addParticle("smoke", x, y, z, xDirection, yDirection, zDirection);
}
}
}
}
}

public static void explode(Entity exploder, Entity parent, World world, double x, double y, double z) {
exploder.remove();
world.playSound(x, y, z, "random.explode", 4.0F, 1.0F);

harmEntitiesAround(world, exploder, parent);

destroyBombableBlocksAround(world, (int) x, (int) y, (int) z);

displayExplosionParticles(world, x, y, z);

}

public boolean damage(Entity var1, int var2) {
if (!this.removed) {
this.setAttacked();
explode(this, this.parentEntity, this.world, this.x, this.y, this.z);
}

return false;
}

public void writeAdditional(CompoundTag var1) {
super.writeAdditional(var1);
var1.put("Fuse", (byte) this.fuse);
}

public void readAdditional(CompoundTag var1) {
super.readAdditional(var1);
this.fuse = var1.getByte("Fuse");
}

public void onPlayerCollision(PlayerEntity var1) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ public AC_ItemBomb(int var1) {
this.setTexturePosition(150);
}

public ItemStack use(ItemStack var1, World var2, PlayerEntity var3) {
--var1.count;
var2.spawnEntity(new AC_EntityBomb(var2, var3));
return var1;
public ItemStack use(ItemStack stack, World world, PlayerEntity player) {
--stack.count;
world.spawnEntity(new AC_EntityBomb(world, player));
return stack;
}
}