TF-ProjectKorra/src/com/projectkorra/projectkorra/firebending/combo/FireComboStream.java
Christopher Martin 787b303c9f
1.9.1 (#1145)
## Additions
* Adds a built-in bending board sidebar to visualize bound abilities and cooldowns.
  * The board respects worlds where bending is disabled.
  * Players can use the command `/pk board` to toggle the visibility of their board.
  * Includes an API that community developers can use in BendingBoardManager.
  * Adds the `"Properties.BendingBoard"` config option to enable or disable the board server.
  * Adds language file configuration options to control BendingBoard visuals.
    * `"Board.Title"`
      * Controls the title at the top of the board.
      * Supports the standard Minecraft color codes.
    * `"Board.SelectionPrefix"`
      * Controls the prefix shown corresponding to your current hot bar slot.
      * Supports the standard Minecraft color codes.
    * `"Board.EmptySlot"`
      * Controls what is shown for empty slots.
      * Supports the standard Minecraft color codes.
      * `{slot_number}` can be used as a placeholder for the slot number.
    * `"Board.MiscSeparator"`
      * Controls the separation between hot bar binds and temporary cooldowns such as Combos.
      * Supports the standard Minecraft color codes.
* Adds support for KingdomsX version 1.10.19.1
* Adds ability permission check to passive abilities. They should now respect their `bending.ability.<ability name>` permissions.
* Adds `AbilityVelocityAffectEntityEvent`
  * A cancellable event that will fire whenever an ability would alter the velocity of an entity.
* Adds the `Abilities.Earth.EarthSmash.Shoot.CollisionRadius` configuration option
  * Sets the collision radius of shot EarthSmash.

## Fixes
* Fixes FireBlast going through liquids.
* Fixes duplication involving waterlogged containers.
* Fixes being able to not enter the name of a Preset when using the `/pk preset create <name>` command.
* Fixes getDayFactor() not being applied correctly and occasionally producing the wrong value.
* Fixes a rounding issue with some Fire ability damage configuration options.
* Fixes an error when attempting to start EarthGrab.
* Fixes PhaseChange error when melting snow.
* Fixes a memory/process leak in how cooldowns were removed.
  * A player's cooldowns could only be removed when they were online. If a player's cooldown expired while they weren't online, their cooldown would attempt to revert every tick until the player rejoined. This has been resolved so cooldowns can revert while a player is offline.
  * A side effect of this fix is that it is now possible for `PlayerCooldownChangeEvents` to fire while their corresponding Player is offline.
* Fixes an issue with `MultiAbilityManager#hasMultiAbilityBound` where it would return true if any MultiAbility is bound, not if the specified MultiAbility was bound.

## Misc Changes
* Updates Towny version to 0.96.2.0
* DensityShift sand blocks can now be used as a bendable source.
* Changes AvatarState so that its cooldown is applied when the ability ends instead of when it starts.
* Changes togglable abilities such as AvatarState, Illumination, and TremorSense to visually show when they are enabled in the BendingBoard and on BendingPreview in the same way as the ChiBlocking Stances.
* Updated the text of some ability descriptions and instructions.
* Adds new cache to PhaseChange to greatly improve the performance of water/ice updates.
2021-06-07 16:58:29 -07:00

247 lines
7.6 KiB
Java

package com.projectkorra.projectkorra.firebending.combo;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import com.projectkorra.projectkorra.BendingPlayer;
import com.projectkorra.projectkorra.Element.SubElement;
import com.projectkorra.projectkorra.GeneralMethods;
import com.projectkorra.projectkorra.ability.CoreAbility;
import com.projectkorra.projectkorra.ability.ElementalAbility;
import com.projectkorra.projectkorra.command.Commands;
import com.projectkorra.projectkorra.firebending.util.FireDamageTimer;
import com.projectkorra.projectkorra.util.DamageHandler;
import com.projectkorra.projectkorra.util.ParticleEffect;
/***
* Is only here for legacy purposes. All fire combos used to use a form of this
* stream for all their progress methods. If someone else was reliant on that,
* they can use this ability instead.
*/
public class FireComboStream extends BukkitRunnable {
private boolean useNewParticles;
private boolean cancelled;
private boolean collides;
private boolean singlePoint;
private int density;
private int checkCollisionDelay;
private int checkCollisionCounter;
private float spread;
private double collisionRadius;
private final double speed;
private final double distance;
private double damage;
private double fireTicks;
private double knockback;
ParticleEffect particleEffect;
private final Player player;
private final BendingPlayer bPlayer;
private final CoreAbility coreAbility;
private final Vector direction;
private final Location initialLocation;
private final Location location;
public FireComboStream(final Player player, final CoreAbility coreAbility, final Vector direction, final Location location, final double distance, final double speed) {
this.useNewParticles = false;
this.cancelled = false;
this.collides = true;
this.singlePoint = false;
this.density = 1;
this.checkCollisionDelay = 1;
this.checkCollisionCounter = 0;
this.spread = 0;
this.collisionRadius = 2;
this.player = player;
this.bPlayer = BendingPlayer.getBendingPlayer(player);
this.particleEffect = bPlayer.canUseSubElement(SubElement.BLUE_FIRE) ? ParticleEffect.SOUL_FIRE_FLAME : ParticleEffect.FLAME;
this.coreAbility = coreAbility;
this.direction = direction;
this.speed = speed;
this.initialLocation = location.clone();
this.location = location.clone();
this.distance = distance;
}
@Override
public void run() {
final Block block = this.location.getBlock();
if (!ElementalAbility.isAir(block.getRelative(BlockFace.UP).getType()) && !ElementalAbility.isPlant(block)) {
this.remove();
return;
}
for (int i = 0; i < this.density; i++) {
if (this.useNewParticles) {
this.particleEffect.display(this.location, 1, this.spread, this.spread, this.spread);
} else {
this.location.getWorld().playEffect(this.location, Effect.MOBSPAWNER_FLAMES, 0, 15);
}
}
if (GeneralMethods.checkDiagonalWall(this.location, this.direction)) {
this.remove();
return;
}
this.location.add(this.direction.normalize().multiply(this.speed));
try {
this.location.checkFinite();
} catch (IllegalArgumentException e) {
this.remove();
return;
}
if (this.initialLocation.distanceSquared(this.location) > this.distance * this.distance || !Double.isFinite(this.collisionRadius)) {
this.remove();
return;
} else if (this.collides && this.checkCollisionCounter % this.checkCollisionDelay == 0) {
for (final Entity entity : GeneralMethods.getEntitiesAroundPoint(this.location, this.collisionRadius)) {
if (entity instanceof LivingEntity && !entity.equals(this.coreAbility.getPlayer()) && !entity.isDead()) {
this.collision((LivingEntity) entity, this.direction, this.coreAbility);
}
}
}
this.checkCollisionCounter++;
if (this.singlePoint) {
this.remove();
}
}
public void collision(final LivingEntity entity, final Vector direction, final CoreAbility coreAbility) {
if (GeneralMethods.isRegionProtectedFromBuild(this.player, "Blaze", entity.getLocation())) {
return;
}
entity.getLocation().getWorld().playSound(entity.getLocation(), Sound.ENTITY_VILLAGER_HURT, 0.3f, 0.3f);
if (coreAbility.getName().equalsIgnoreCase("FireKick")) {
final FireKick fireKick = CoreAbility.getAbility(this.player, FireKick.class);
if (!fireKick.getAffectedEntities().contains(entity)) {
fireKick.getAffectedEntities().add(entity);
DamageHandler.damageEntity(entity, this.damage, coreAbility);
}
} else if (coreAbility.getName().equalsIgnoreCase("FireSpin")) {
final FireSpin fireSpin = CoreAbility.getAbility(this.player, FireSpin.class);
if (entity instanceof Player) {
if (Commands.invincible.contains(((Player) entity).getName())) {
return;
}
}
if (!fireSpin.getAffectedEntities().contains(entity)) {
fireSpin.getAffectedEntities().add(entity);
final double newKnockback = this.bPlayer.isAvatarState() ? this.knockback + 0.5 : this.knockback;
DamageHandler.damageEntity(entity, this.damage, coreAbility);
GeneralMethods.setVelocity(coreAbility, entity, direction.normalize().multiply(newKnockback));
}
} else if (coreAbility.getName().equalsIgnoreCase("JetBlaze")) {
final JetBlaze jetBlaze = CoreAbility.getAbility(this.player, JetBlaze.class);
if (!jetBlaze.getAffectedEntities().contains(entity)) {
jetBlaze.getAffectedEntities().add(entity);
DamageHandler.damageEntity(entity, this.damage, coreAbility);
entity.setFireTicks((int) (this.fireTicks * 20));
new FireDamageTimer(entity, this.player);
}
} else if (coreAbility.getName().equalsIgnoreCase("FireWheel")) {
final FireWheel fireWheel = CoreAbility.getAbility(this.player, FireWheel.class);
if (!fireWheel.getAffectedEntities().contains(entity)) {
fireWheel.getAffectedEntities().add(entity);
DamageHandler.damageEntity(entity, this.damage, coreAbility);
entity.setFireTicks((int) (this.fireTicks * 20));
new FireDamageTimer(entity, this.player);
this.remove();
}
}
}
@Override
public void cancel() {
this.remove();
}
public Vector getDirection() {
return this.direction.clone();
}
public Location getLocation() {
return this.location;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
public void remove() {
super.cancel();
this.cancelled = true;
}
public CoreAbility getAbility() {
return this.coreAbility;
}
public void setCheckCollisionDelay(final int delay) {
this.checkCollisionDelay = delay;
}
public void setCollides(final boolean b) {
this.collides = b;
}
public void setCollisionRadius(final double radius) {
this.collisionRadius = radius;
}
public void setDensity(final int density) {
this.density = density;
}
public void setDamage(final double damage) {
this.damage = damage;
}
public void setKnockback(final double knockback) {
this.knockback = knockback;
}
public void setFireTicks(final double fireTicks) {
this.fireTicks = fireTicks;
}
public void setParticleEffect(final ParticleEffect effect) {
this.particleEffect = effect;
}
public void setSinglePoint(final boolean b) {
this.singlePoint = b;
}
public void setSpread(final float spread) {
this.spread = spread;
}
public void setUseNewParticles(final boolean b) {
this.useNewParticles = b;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}