mirror of
https://github.com/TotalFreedomMC/TF-ProjectKorra.git
synced 2024-06-10 22:34:57 +00:00
3c1d6b7b85
## Additions * Adds Blue Fire SubElement. > *Adds related damage, cooldown, and range modifiers for configuration * Adds Sticks, Sponges, and Chorus Fruit to cookable HeatControl items. * Adds Smoker, BlastFurnace, and extinguished Campfires to blocks which FireBlast can light. * Adds new TempBlock constructor which takes in a `long revertTime` parameter * Adds new blocks to block lists in configuration >* Adds new nether plants to plantBlocks list >* Adds new earth blocks to earthBlocks list ## Fixes * Fixes AvatarState buffs overriding day related buffs for firebending. * Fixes Blaze not going up hills, going through walls (mostly), jumping gaps. * Fixes Furnaces and related blocks not smelting after being activated by FireBlast ## Removals * Removes BlazeArc dependencies for Fire Abilities which ignite the ground. * Removes smoke particles from Fire bending to increase visibility and better emulate the show. ## Misc. Changes * Changes API versioning to 1.16.1 * Fire from Firebending no longer reverts all at once. * Changes Combustion animation to be more beam-like rather than a rehash of FireBlast. * Changes Add, Remove, Display command to properly display space for Blue Fire. * Changes `ElementalAbility#isFire()` to check for SOUL_FIRE_FLAME. * Changes isIgnitable to check whether fire can be placed at that location rather than solely based on flammability. * Changes firebending abilities to use `FireAbility#playFirebendingParticles()` & `FireAbility#createTempFire()` where applicable. * Changes `FireAbility#playFirebendingParticles()` to play blue fire particles when player has the BlueFire subelement.
460 lines
13 KiB
Java
460 lines
13 KiB
Java
package com.projectkorra.projectkorra.firebending;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.BlastFurnace;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.block.BlockFace;
|
|
import org.bukkit.block.data.type.Campfire;
|
|
import org.bukkit.block.Furnace;
|
|
import org.bukkit.block.Smoker;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.util.Vector;
|
|
|
|
import com.projectkorra.projectkorra.GeneralMethods;
|
|
import com.projectkorra.projectkorra.ProjectKorra;
|
|
import com.projectkorra.projectkorra.Element.SubElement;
|
|
import com.projectkorra.projectkorra.ability.AirAbility;
|
|
import com.projectkorra.projectkorra.ability.BlueFireAbility;
|
|
import com.projectkorra.projectkorra.ability.FireAbility;
|
|
import com.projectkorra.projectkorra.ability.util.Collision;
|
|
import com.projectkorra.projectkorra.attribute.Attribute;
|
|
import com.projectkorra.projectkorra.avatar.AvatarState;
|
|
import com.projectkorra.projectkorra.command.Commands;
|
|
import com.projectkorra.projectkorra.firebending.util.FireDamageTimer;
|
|
import com.projectkorra.projectkorra.util.DamageHandler;
|
|
import com.projectkorra.projectkorra.waterbending.plant.PlantRegrowth;
|
|
|
|
public class FireBlast extends FireAbility {
|
|
|
|
private static final int MAX_TICKS = 10000;
|
|
|
|
@Attribute("PowerFurnace")
|
|
private boolean powerFurnace;
|
|
private boolean showParticles;
|
|
private boolean dissipate;
|
|
private boolean isFireBurst = false;
|
|
private boolean fireBurstIgnite;
|
|
private int ticks;
|
|
@Attribute(Attribute.COOLDOWN)
|
|
private long cooldown;
|
|
private double speedFactor;
|
|
@Attribute(Attribute.RANGE)
|
|
private double range;
|
|
@Attribute(Attribute.DAMAGE)
|
|
private double damage;
|
|
@Attribute(Attribute.SPEED)
|
|
private double speed;
|
|
private double collisionRadius;
|
|
@Attribute(Attribute.FIRE_TICK)
|
|
private double fireTicks;
|
|
@Attribute(Attribute.KNOCKBACK)
|
|
private double knockback;
|
|
private double flameRadius;
|
|
private Random random;
|
|
private Location location;
|
|
private Location origin;
|
|
private Vector direction;
|
|
private List<Block> safeBlocks;
|
|
|
|
public FireBlast(final Location location, final Vector direction, final Player player, final int damage, final List<Block> safeBlocks) {
|
|
super(player);
|
|
|
|
if (location.getBlock().isLiquid()) {
|
|
return;
|
|
}
|
|
|
|
this.setFields();
|
|
this.safeBlocks = safeBlocks;
|
|
|
|
this.location = location.clone();
|
|
this.origin = location.clone();
|
|
this.direction = direction.clone().normalize();
|
|
|
|
// The following code determines the total additive modifier between Blue Fire & Day Modifiers
|
|
this.applyModifiers();
|
|
|
|
this.start();
|
|
}
|
|
|
|
public FireBlast(final Player player) {
|
|
super(player);
|
|
|
|
if (this.bPlayer.isOnCooldown("FireBlast")) {
|
|
return;
|
|
} else if (player.getEyeLocation().getBlock().isLiquid() || FireBlastCharged.isCharging(player)) {
|
|
return;
|
|
}
|
|
|
|
this.setFields();
|
|
this.isFireBurst = false;
|
|
this.damage = getConfig().getDouble("Abilities.Fire.FireBlast.Damage");
|
|
this.safeBlocks = new ArrayList<>();
|
|
this.location = player.getEyeLocation();
|
|
this.origin = player.getEyeLocation();
|
|
this.direction = player.getEyeLocation().getDirection().normalize();
|
|
this.location = this.location.add(this.direction.clone());
|
|
|
|
// The following code determines the total additive modifier between Blue Fire & Day Modifiers
|
|
this.applyModifiers();
|
|
|
|
this.start();
|
|
this.bPlayer.addCooldown("FireBlast", this.cooldown);
|
|
}
|
|
|
|
private void applyModifiers() {
|
|
int damageMod = 0;
|
|
int rangeMod = 0;
|
|
|
|
damageMod = (int) (this.getDayFactor(damage) - damage);
|
|
rangeMod = (int) (this.getDayFactor(this.range) - this.range);
|
|
|
|
damageMod = (int) (bPlayer.canUseSubElement(SubElement.BLUE_FIRE) ? (BlueFireAbility.getDamageFactor() * damage - damage) + damageMod : damageMod);
|
|
rangeMod = (int) (bPlayer.canUseSubElement(SubElement.BLUE_FIRE) ? (BlueFireAbility.getRangeFactor() * range - range) + rangeMod : rangeMod);
|
|
|
|
this.range += rangeMod;
|
|
this.damage += damageMod;
|
|
}
|
|
|
|
private void setFields() {
|
|
this.isFireBurst = true;
|
|
this.powerFurnace = true;
|
|
this.showParticles = true;
|
|
this.fireBurstIgnite = getConfig().getBoolean("Abilities.Fire.FireBurst.Ignite");
|
|
this.dissipate = getConfig().getBoolean("Abilities.Fire.FireBlast.Dissipate");
|
|
this.cooldown = getConfig().getLong("Abilities.Fire.FireBlast.Cooldown");
|
|
this.range = getConfig().getDouble("Abilities.Fire.FireBlast.Range");
|
|
this.speed = getConfig().getDouble("Abilities.Fire.FireBlast.Speed");
|
|
this.collisionRadius = getConfig().getDouble("Abilities.Fire.FireBlast.CollisionRadius");
|
|
this.fireTicks = getConfig().getDouble("Abilities.Fire.FireBlast.FireTicks");
|
|
this.knockback = getConfig().getDouble("Abilities.Fire.FireBlast.Knockback");
|
|
this.flameRadius = getConfig().getDouble("Abilities.Fire.FireBlast.FlameParticleRadius");
|
|
this.random = new Random();
|
|
}
|
|
|
|
private void advanceLocation() {
|
|
if (this.isFireBurst) {
|
|
this.flameRadius += 0.06;
|
|
}
|
|
|
|
if (this.showParticles) {
|
|
playFirebendingParticles(this.location, 6, this.flameRadius, this.flameRadius, this.flameRadius);
|
|
}
|
|
|
|
if (GeneralMethods.checkDiagonalWall(this.location, this.direction)) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
this.location = this.location.add(this.direction.clone().multiply(this.speedFactor));
|
|
|
|
if (this.random.nextInt(4) == 0) {
|
|
playFirebendingSound(this.location);
|
|
}
|
|
}
|
|
|
|
private void affect(final Entity entity) {
|
|
if (entity.getUniqueId() != this.player.getUniqueId() && !GeneralMethods.isRegionProtectedFromBuild(this, entity.getLocation()) && !((entity instanceof Player) && Commands.invincible.contains(((Player) entity).getName()))) {
|
|
if (this.bPlayer.isAvatarState()) {
|
|
GeneralMethods.setVelocity(entity, this.direction.clone().multiply(AvatarState.getValue(this.knockback)));
|
|
} else {
|
|
GeneralMethods.setVelocity(entity, this.direction.clone().multiply(this.knockback));
|
|
}
|
|
if (entity instanceof LivingEntity) {
|
|
entity.setFireTicks((int) (this.fireTicks * 20));
|
|
DamageHandler.damageEntity(entity, this.damage, this);
|
|
AirAbility.breakBreathbendingHold(entity);
|
|
new FireDamageTimer(entity, this.player);
|
|
this.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ignite(final Location location) {
|
|
for (final Block block : GeneralMethods.getBlocksAroundPoint(location, this.collisionRadius)) {
|
|
if (isIgnitable(block) && !this.safeBlocks.contains(block) && !GeneralMethods.isRegionProtectedFromBuild(this, block.getLocation())) {
|
|
if (canFireGrief()) {
|
|
if (isPlant(block) || isSnow(block)) {
|
|
new PlantRegrowth(this.player, block);
|
|
}
|
|
}
|
|
createTempFire(block.getLocation());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void progress() {
|
|
if (!this.bPlayer.canBendIgnoreBindsCooldowns(this) || GeneralMethods.isRegionProtectedFromBuild(this, this.location)) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
this.speedFactor = this.speed * (ProjectKorra.time_step / 1000.0);
|
|
this.ticks++;
|
|
|
|
if (this.ticks > MAX_TICKS) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
final Block block = this.location.getBlock();
|
|
if (GeneralMethods.isSolid(block) || block.isLiquid()) {
|
|
if (block.getType() == Material.FURNACE && this.powerFurnace) {
|
|
final Furnace furnace = (Furnace) block.getState();
|
|
furnace.setBurnTime((short) 800);
|
|
furnace.update();
|
|
} else if (block.getType() == Material.SMOKER && this.powerFurnace) {
|
|
final Smoker smoker = (Smoker) block.getState();
|
|
smoker.setBurnTime((short) 800);
|
|
smoker.update();
|
|
} else if (block.getType() == Material.BLAST_FURNACE && this.powerFurnace) {
|
|
final BlastFurnace blastF = (BlastFurnace) block.getState();
|
|
blastF.setBurnTime((short) 800);
|
|
blastF.update();
|
|
} else if (block instanceof Campfire) {
|
|
final Campfire campfire = (Campfire) block.getBlockData();
|
|
if(!campfire.isLit()) {
|
|
if(block.getType() != Material.SOUL_CAMPFIRE || bPlayer.canUseSubElement(SubElement.BLUE_FIRE)) {
|
|
campfire.setLit(true);
|
|
}
|
|
}
|
|
} else if (isIgnitable(block.getRelative(BlockFace.UP))) {
|
|
if ((this.isFireBurst && this.fireBurstIgnite) || !this.isFireBurst) {
|
|
this.ignite(this.location);
|
|
}
|
|
}
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
if (this.location.distanceSquared(this.origin) > this.range * this.range) {
|
|
this.remove();
|
|
return;
|
|
}
|
|
|
|
Entity entity = GeneralMethods.getClosestEntity(this.location, this.collisionRadius);
|
|
if (entity != null) {
|
|
this.affect(entity);
|
|
}
|
|
|
|
this.advanceLocation();
|
|
}
|
|
|
|
/**
|
|
* This method was used for the old collision detection system. Please see
|
|
* {@link Collision} for the new system.
|
|
*/
|
|
@Deprecated
|
|
public static boolean annihilateBlasts(final Location location, final double radius, final Player source) {
|
|
boolean broke = false;
|
|
for (final FireBlast blast : getAbilities(FireBlast.class)) {
|
|
final Location fireBlastLocation = blast.location;
|
|
if (location.getWorld().equals(fireBlastLocation.getWorld()) && !blast.player.equals(source)) {
|
|
if (location.distanceSquared(fireBlastLocation) <= radius * radius) {
|
|
blast.remove();
|
|
broke = true;
|
|
}
|
|
}
|
|
}
|
|
if (FireBlastCharged.annihilateBlasts(location, radius, source)) {
|
|
broke = true;
|
|
}
|
|
return broke;
|
|
}
|
|
|
|
public static ArrayList<FireBlast> getAroundPoint(final Location location, final double radius) {
|
|
final ArrayList<FireBlast> list = new ArrayList<FireBlast>();
|
|
for (final FireBlast fireBlast : getAbilities(FireBlast.class)) {
|
|
final Location fireblastlocation = fireBlast.location;
|
|
if (location.getWorld().equals(fireblastlocation.getWorld())) {
|
|
if (location.distanceSquared(fireblastlocation) <= radius * radius) {
|
|
list.add(fireBlast);
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public static void removeFireBlastsAroundPoint(final Location location, final double radius) {
|
|
for (final FireBlast fireBlast : getAbilities(FireBlast.class)) {
|
|
final Location fireBlastLocation = fireBlast.location;
|
|
if (location.getWorld().equals(fireBlastLocation.getWorld())) {
|
|
if (location.distanceSquared(fireBlastLocation) <= radius * radius) {
|
|
fireBlast.remove();
|
|
}
|
|
}
|
|
}
|
|
FireBlastCharged.removeFireballsAroundPoint(location, radius);
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
return this.isFireBurst ? "FireBurst" : "FireBlast";
|
|
}
|
|
|
|
@Override
|
|
public Location getLocation() {
|
|
return this.location != null ? this.location : this.origin;
|
|
}
|
|
|
|
@Override
|
|
public long getCooldown() {
|
|
return this.cooldown;
|
|
}
|
|
|
|
@Override
|
|
public boolean isSneakAbility() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isHarmlessAbility() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public double getCollisionRadius() {
|
|
return this.collisionRadius;
|
|
}
|
|
|
|
public boolean isPowerFurnace() {
|
|
return this.powerFurnace;
|
|
}
|
|
|
|
public void setPowerFurnace(final boolean powerFurnace) {
|
|
this.powerFurnace = powerFurnace;
|
|
}
|
|
|
|
public boolean isShowParticles() {
|
|
return this.showParticles;
|
|
}
|
|
|
|
public void setShowParticles(final boolean showParticles) {
|
|
this.showParticles = showParticles;
|
|
}
|
|
|
|
public boolean isDissipate() {
|
|
return this.dissipate;
|
|
}
|
|
|
|
public void setDissipate(final boolean dissipate) {
|
|
this.dissipate = dissipate;
|
|
}
|
|
|
|
public int getTicks() {
|
|
return this.ticks;
|
|
}
|
|
|
|
public void setTicks(final int ticks) {
|
|
this.ticks = ticks;
|
|
}
|
|
|
|
public double getSpeedFactor() {
|
|
return this.speedFactor;
|
|
}
|
|
|
|
public void setSpeedFactor(final double speedFactor) {
|
|
this.speedFactor = speedFactor;
|
|
}
|
|
|
|
public double getRange() {
|
|
return this.range;
|
|
}
|
|
|
|
public void setRange(final double range) {
|
|
this.range = range;
|
|
}
|
|
|
|
public double getDamage() {
|
|
return this.damage;
|
|
}
|
|
|
|
public void setDamage(final double damage) {
|
|
this.damage = damage;
|
|
}
|
|
|
|
public double getSpeed() {
|
|
return this.speed;
|
|
}
|
|
|
|
public void setSpeed(final double speed) {
|
|
this.speed = speed;
|
|
}
|
|
|
|
public void setCollisionRadius(final double collisionRadius) {
|
|
this.collisionRadius = collisionRadius;
|
|
}
|
|
|
|
public double getFireTicks() {
|
|
return this.fireTicks;
|
|
}
|
|
|
|
public void setFireTicks(final double fireTicks) {
|
|
this.fireTicks = fireTicks;
|
|
}
|
|
|
|
public double getPushFactor() {
|
|
return this.knockback;
|
|
}
|
|
|
|
public void setPushFactor(final double pushFactor) {
|
|
this.knockback = pushFactor;
|
|
}
|
|
|
|
public Random getRandom() {
|
|
return this.random;
|
|
}
|
|
|
|
public void setRandom(final Random random) {
|
|
this.random = random;
|
|
}
|
|
|
|
public Location getOrigin() {
|
|
return this.origin;
|
|
}
|
|
|
|
public void setOrigin(final Location origin) {
|
|
this.origin = origin;
|
|
}
|
|
|
|
public Vector getDirection() {
|
|
return this.direction;
|
|
}
|
|
|
|
public void setDirection(final Vector direction) {
|
|
this.direction = direction;
|
|
}
|
|
|
|
public static int getMaxTicks() {
|
|
return MAX_TICKS;
|
|
}
|
|
|
|
public List<Block> getSafeBlocks() {
|
|
return this.safeBlocks;
|
|
}
|
|
|
|
public void setCooldown(final long cooldown) {
|
|
this.cooldown = cooldown;
|
|
}
|
|
|
|
public void setLocation(final Location location) {
|
|
this.location = location;
|
|
}
|
|
|
|
public boolean isFireBurst() {
|
|
return this.isFireBurst;
|
|
}
|
|
|
|
public void setFireBurst(final boolean isFireBurst) {
|
|
this.isFireBurst = isFireBurst;
|
|
}
|
|
|
|
}
|