TF-ProjectKorra/src/com/projectkorra/projectkorra/firebending/FireBurst.java
Vahagn Tovmasian 3c1d6b7b85
Blue Fire Update & Firebending Refactor (#1062)
## 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.
2020-07-11 22:05:45 -07:00

276 lines
7.7 KiB
Java

package com.projectkorra.projectkorra.firebending;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
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.BlueFireAbility;
import com.projectkorra.projectkorra.ability.FireAbility;
import com.projectkorra.projectkorra.attribute.Attribute;
public class FireBurst extends FireAbility {
@Attribute("Charged")
private boolean charged;
@Attribute(Attribute.DAMAGE)
private int damage;
@Attribute(Attribute.CHARGE_DURATION)
private long chargeTime;
@Attribute(Attribute.RANGE)
private long range;
@Attribute(Attribute.COOLDOWN)
private long cooldown;
private double angleTheta;
private double anglePhi;
private double particlesPercentage;
private ArrayList<FireBlast> blasts;
public FireBurst(final Player player) {
super(player);
this.charged = false;
this.damage = getConfig().getInt("Abilities.Fire.FireBurst.Damage");
this.chargeTime = getConfig().getLong("Abilities.Fire.FireBurst.ChargeTime");
this.range = getConfig().getLong("Abilities.Fire.FireBurst.Range");
this.cooldown = getConfig().getLong("Abilities.Fire.FireBurst.Cooldown");
this.angleTheta = getConfig().getDouble("Abilities.Fire.FireBurst.AngleTheta");
this.anglePhi = getConfig().getDouble("Abilities.Fire.FireBurst.AnglePhi");
this.particlesPercentage = getConfig().getDouble("Abilities.Fire.FireBurst.ParticlesPercentage");
this.blasts = new ArrayList<>();
if (!this.bPlayer.canBend(this) || hasAbility(player, FireBurst.class)) {
return;
}
long chargeTimeMod = 0;
if (isDay(player.getWorld())) {
chargeTimeMod = (long) (this.getDayFactor(chargeTime) - chargeTime);
}
chargeTimeMod = (long) (bPlayer.canUseSubElement(SubElement.BLUE_FIRE) ? (chargeTime / BlueFireAbility.getCooldownFactor() - chargeTime) + chargeTimeMod : chargeTimeMod);
if (this.bPlayer.isAvatarState()) {
this.chargeTime = getConfig().getLong("Abilities.Avatar.AvatarState.Fire.FireBurst.Damage");
this.damage = getConfig().getInt("Abilities.Avatar.AvatarState.Fire.FireBurst.Damage");
this.cooldown = getConfig().getLong("Abilities.Avatar.AvatarState.Fire.FireBurst.Cooldown");
}
this.chargeTime += chargeTimeMod;
this.start();
}
public static void coneBurst(final Player player) {
final FireBurst burst = getAbility(player, FireBurst.class);
if (burst != null) {
burst.coneBurst();
}
}
private void coneBurst() {
if (this.charged) {
final Location location = this.player.getEyeLocation();
final List<Block> safeBlocks = GeneralMethods.getBlocksAroundPoint(this.player.getLocation(), 2);
final Vector vector = location.getDirection();
final double angle = Math.toRadians(30);
double x, y, z;
final double r = 1;
for (double theta = 0; theta <= 180; theta += this.angleTheta) {
final double dphi = this.anglePhi / Math.sin(Math.toRadians(theta));
for (double phi = 0; phi < 360; phi += dphi) {
final double rphi = Math.toRadians(phi);
final double rtheta = Math.toRadians(theta);
x = r * Math.cos(rphi) * Math.sin(rtheta);
y = r * Math.sin(rphi) * Math.sin(rtheta);
z = r * Math.cos(rtheta);
final Vector direction = new Vector(x, z, y);
if (direction.angle(vector) <= angle) {
final FireBlast fblast = new FireBlast(location, direction.normalize(), this.player, this.damage, safeBlocks);
fblast.setRange(this.range);
fblast.setFireBurst(true);
}
}
}
this.bPlayer.addCooldown(this);
}
this.remove();
}
/**
* To combat the sphere FireBurst lag we are only going to show a certain
* percentage of FireBurst particles at a time per tick. As the bursts
* spread out then we can show more at a time.
*/
public void handleSmoothParticles() {
for (int i = 0; i < this.blasts.size(); i++) {
final FireBlast fblast = this.blasts.get(i);
final int toggleTime = (int) (i % (100.0 / this.particlesPercentage));
new BukkitRunnable() {
@Override
public void run() {
fblast.setShowParticles(true);
}
}.runTaskLater(ProjectKorra.plugin, toggleTime);
}
}
@Override
public void progress() {
if (!this.bPlayer.canBendIgnoreCooldowns(this)) {
this.remove();
return;
}
if (System.currentTimeMillis() > this.getStartTime() + this.chargeTime && !this.charged) {
this.charged = true;
}
if (!this.player.isSneaking()) {
if (this.charged) {
this.sphereBurst();
} else {
this.remove();
}
} else if (this.charged) {
final Location location = this.player.getEyeLocation();
location.add(location.getDirection());
playFirebendingParticles(location, 1, .01, .01, .01);
}
}
private void sphereBurst() {
if (this.charged) {
final Location location = this.player.getEyeLocation();
final List<Block> safeblocks = GeneralMethods.getBlocksAroundPoint(this.player.getLocation(), 2);
double x, y, z;
final double r = 1;
for (double theta = 0; theta <= 180; theta += this.angleTheta) {
final double dphi = this.anglePhi / Math.sin(Math.toRadians(theta));
for (double phi = 0; phi < 360; phi += dphi) {
final double rphi = Math.toRadians(phi);
final double rtheta = Math.toRadians(theta);
x = r * Math.cos(rphi) * Math.sin(rtheta);
y = r * Math.sin(rphi) * Math.sin(rtheta);
z = r * Math.cos(rtheta);
final Vector direction = new Vector(x, z, y);
final FireBlast fblast = new FireBlast(location, direction.normalize(), this.player, this.damage, safeblocks);
fblast.setRange(this.range);
fblast.setShowParticles(false);
fblast.setFireBurst(true);
this.blasts.add(fblast);
}
}
this.bPlayer.addCooldown(this);
}
this.remove();
this.handleSmoothParticles();
}
@Override
public String getName() {
return "FireBurst";
}
@Override
public Location getLocation() {
return this.player != null ? this.player.getLocation() : null;
}
@Override
public long getCooldown() {
return this.cooldown;
}
@Override
public boolean isSneakAbility() {
return true;
}
@Override
public boolean isHarmlessAbility() {
return false;
}
public boolean isCharged() {
return this.charged;
}
public void setCharged(final boolean charged) {
this.charged = charged;
}
public int getDamage() {
return this.damage;
}
public void setDamage(final int damage) {
this.damage = damage;
}
public long getChargeTime() {
return this.chargeTime;
}
public void setChargeTime(final long chargeTime) {
this.chargeTime = chargeTime;
}
public long getRange() {
return this.range;
}
public void setRange(final long range) {
this.range = range;
}
public double getAngleTheta() {
return this.angleTheta;
}
public void setAngleTheta(final double angleTheta) {
this.angleTheta = angleTheta;
}
public double getAnglePhi() {
return this.anglePhi;
}
public void setAnglePhi(final double anglePhi) {
this.anglePhi = anglePhi;
}
public double getParticlesPercentage() {
return this.particlesPercentage;
}
public void setParticlesPercentage(final double particlesPercentage) {
this.particlesPercentage = particlesPercentage;
}
public ArrayList<FireBlast> getBlasts() {
return this.blasts;
}
public void setCooldown(final long cooldown) {
this.cooldown = cooldown;
}
}