mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 19:46:42 +01:00
You can now trigger multiple abilities at the same time
This commit is contained in:
parent
9006b2b295
commit
140ee68ae3
13 changed files with 105 additions and 142 deletions
|
@ -14,8 +14,8 @@ public interface Abilities {
|
|||
MutableRegistry<Ability<?>> REGISTRY = new SimpleRegistry<>();
|
||||
|
||||
// unicorn / alicorn
|
||||
Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.PRIMARY);
|
||||
Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.SECONDARY);
|
||||
Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY);
|
||||
Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY);
|
||||
|
||||
// earth / alicorn
|
||||
Ability<?> STOMP = register(new EarthPonyStompAbility(), "stomp", AbilitySlot.PRIMARY);
|
||||
|
@ -30,7 +30,7 @@ public interface Abilities {
|
|||
// changeling
|
||||
Ability<?> DISGUISE = register(new ChangelingDisguiseAbility(), "disguise", AbilitySlot.PRIMARY);
|
||||
Ability<?> FEED = register(new ChangelingFeedAbility(), "feed", AbilitySlot.SECONDARY);
|
||||
Ability<?> TRAP = register(new ChangelingTrapAbility(), "trap", AbilitySlot.TERTIARY);
|
||||
//Ability<?> TRAP = register(new ChangelingTrapAbility(), "trap", AbilitySlot.TERTIARY);
|
||||
|
||||
static <T extends Ability<?>> T register(T power, String name, AbilitySlot slot) {
|
||||
Identifier id = new Identifier("unicopia", name);
|
||||
|
|
|
@ -60,11 +60,11 @@ public interface Ability<T extends Hit> {
|
|||
* Called every tick until the warmup timer runs out.
|
||||
* @param player The current player
|
||||
*/
|
||||
void preApply(Pony player);
|
||||
void preApply(Pony player, AbilitySlot slot);
|
||||
|
||||
/**
|
||||
* Called every tick until the cooldown timer runs out.
|
||||
* @param player The current player
|
||||
*/
|
||||
void postApply(Pony player);
|
||||
void postApply(Pony player, AbilitySlot slot);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import java.util.EnumMap;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
@ -23,39 +21,22 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
|
||||
private final Map<AbilitySlot, Stat> stats = new EnumMap<>(AbilitySlot.class);
|
||||
|
||||
/**
|
||||
* True once the current ability has been triggered.
|
||||
*/
|
||||
private boolean triggered;
|
||||
|
||||
private Optional<Ability<?>> activeAbility = Optional.empty();
|
||||
|
||||
private AbilitySlot activeSlot = AbilitySlot.NONE;
|
||||
|
||||
public AbilityDispatcher(Pony player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current ability can we swapped out.
|
||||
*/
|
||||
boolean canSwitchStates() {
|
||||
return !activeAbility.isPresent() || getStat(getActiveSlot()).canSwitchStates();
|
||||
}
|
||||
public void clear(AbilitySlot slot) {
|
||||
Stat stat = getStat(slot);
|
||||
|
||||
public AbilitySlot getActiveSlot() {
|
||||
return activeSlot;
|
||||
}
|
||||
|
||||
public void cancelAbility(AbilitySlot slot) {
|
||||
if (getActiveSlot() == slot && canSwitchStates()) {
|
||||
setActiveAbility(slot, null);
|
||||
if (stat.canSwitchStates()) {
|
||||
stat.setActiveAbility(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void activate(AbilitySlot slot) {
|
||||
if (canSwitchStates()) {
|
||||
getAbility(slot).ifPresent(ability -> setActiveAbility(slot, ability));
|
||||
Stat stat = getStat(slot);
|
||||
if (stat.canSwitchStates()) {
|
||||
stat.getAbility().ifPresent(stat::setActiveAbility);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,88 +44,13 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
return stats.computeIfAbsent(slot, Stat::new);
|
||||
}
|
||||
|
||||
public Optional<Ability<?>> getAbility(AbilitySlot slot) {
|
||||
Race race = player.getSpecies();
|
||||
return Abilities.BY_SLOT.get(slot).stream().filter(a -> a.canUse(race)).findFirst();
|
||||
}
|
||||
|
||||
protected synchronized void setActiveAbility(AbilitySlot slot, Ability<?> power) {
|
||||
if (activeAbility.orElse(null) != power) {
|
||||
activeSlot = slot;
|
||||
triggered = false;
|
||||
activeAbility = Optional.ofNullable(power);
|
||||
Stat stat = getStat(slot);
|
||||
stat.setWarmup(activeAbility.map(p -> p.getWarmupTime(player)).orElse(0));
|
||||
stat.setCooldown(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected synchronized Optional<Ability<?>> getActiveAbility() {
|
||||
Stat stat = getStat(getActiveSlot());
|
||||
return activeAbility.filter(ability -> {
|
||||
return (!(ability == null || (triggered && stat.warmup == 0 && stat.cooldown == 0)) && ability.canUse(player.getSpecies()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
getActiveAbility().ifPresent(this::activate);
|
||||
}
|
||||
|
||||
private <T extends Hit> void activate(Ability<T> ability) {
|
||||
Stat stat = getStat(getActiveSlot());
|
||||
|
||||
stats.values().forEach(s -> {
|
||||
if (s != stat) {
|
||||
s.idle();
|
||||
}
|
||||
});
|
||||
|
||||
if (stat.warmup > 0) {
|
||||
stat.warmup--;
|
||||
System.out.println("warming up");
|
||||
ability.preApply(player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stat.tickInactive()) {
|
||||
System.out.println("cooling down");
|
||||
ability.postApply(player);
|
||||
|
||||
if (stat.cooldown <= 0) {
|
||||
setActiveAbility(AbilitySlot.NONE, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (triggered) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ability.canActivate(player.getWorld(), player)) {
|
||||
triggered = true;
|
||||
stat.setCooldown(ability.getCooldownTime(player));
|
||||
|
||||
if (player.isClientPlayer()) {
|
||||
T data = ability.tryActivate(player);
|
||||
|
||||
if (data != null) {
|
||||
Channel.PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data));
|
||||
} else {
|
||||
stat.setCooldown(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stat.cooldown <= 0) {
|
||||
setActiveAbility(AbilitySlot.NONE, null);
|
||||
}
|
||||
stats.values().forEach(Stat::tick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(CompoundTag compound) {
|
||||
compound.putBoolean("triggered", triggered);
|
||||
if (compound.contains("stats")) {
|
||||
stats.clear();
|
||||
CompoundTag li = compound.getCompound("stats");
|
||||
|
@ -152,20 +58,13 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
getStat(AbilitySlot.valueOf(key)).fromNBT(li.getCompound(key));
|
||||
});
|
||||
}
|
||||
compound.putInt("activeSlot", activeSlot.ordinal());
|
||||
getActiveAbility().ifPresent(ability -> {
|
||||
compound.putString("activeAbility", Abilities.REGISTRY.getId(ability).toString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(CompoundTag compound) {
|
||||
triggered = compound.getBoolean("triggered");
|
||||
CompoundTag li = new CompoundTag();
|
||||
stats.forEach((key, value) -> li.put(key.name(), value.toNBT()));
|
||||
compound.put("stats", li);
|
||||
activeSlot = compound.contains("activeSlot") ? AbilitySlot.values()[compound.getInt("activeSlot")] : activeSlot;
|
||||
activeAbility = Abilities.REGISTRY.getOrEmpty(new Identifier(compound.getString("activeAbility")));
|
||||
}
|
||||
|
||||
public class Stat implements NbtSerialisable {
|
||||
|
@ -184,6 +83,13 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
|
||||
public final AbilitySlot slot;
|
||||
|
||||
/**
|
||||
* True once the current ability has been triggered.
|
||||
*/
|
||||
private boolean triggered;
|
||||
|
||||
private Optional<Ability<?>> activeAbility = Optional.empty();
|
||||
|
||||
private Stat(AbilitySlot slot) {
|
||||
this.slot = slot;
|
||||
}
|
||||
|
@ -192,7 +98,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
* Returns true if the current ability can we swapped out.
|
||||
*/
|
||||
boolean canSwitchStates() {
|
||||
return (warmup != 0) || (triggered && cooldown == 0);
|
||||
return !activeAbility.isPresent() || (warmup != 0) || (triggered && cooldown == 0);
|
||||
}
|
||||
|
||||
public int getRemainingCooldown() {
|
||||
|
@ -225,17 +131,68 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
warmup = value;
|
||||
}
|
||||
|
||||
public void idle() {
|
||||
public void tick() {
|
||||
getActiveAbility().ifPresent(this::activate);
|
||||
}
|
||||
|
||||
private <T extends Hit> void activate(Ability<T> ability) {
|
||||
if (warmup > 0) {
|
||||
warmup--;
|
||||
ability.preApply(player, slot);
|
||||
return;
|
||||
}
|
||||
if (cooldown > 0) {
|
||||
cooldown--;
|
||||
|
||||
if (cooldown > 0 && cooldown-- > 0) {
|
||||
ability.postApply(player, slot);
|
||||
|
||||
if (cooldown <= 0) {
|
||||
setActiveAbility(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (triggered) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ability.canActivate(player.getWorld(), player)) {
|
||||
triggered = true;
|
||||
setCooldown(ability.getCooldownTime(player));
|
||||
|
||||
if (player.isClientPlayer()) {
|
||||
T data = ability.tryActivate(player);
|
||||
|
||||
if (data != null) {
|
||||
Channel.PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data));
|
||||
} else {
|
||||
setCooldown(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cooldown <= 0) {
|
||||
setActiveAbility(null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tickInactive() {
|
||||
return cooldown > 0 && cooldown-- > 0;
|
||||
public Optional<Ability<?>> getAbility() {
|
||||
Race race = player.getSpecies();
|
||||
return Abilities.BY_SLOT.get(slot).stream().filter(a -> a.canUse(race)).findFirst();
|
||||
}
|
||||
|
||||
protected synchronized void setActiveAbility(Ability<?> power) {
|
||||
if (activeAbility.orElse(null) != power) {
|
||||
triggered = false;
|
||||
activeAbility = Optional.ofNullable(power);
|
||||
setWarmup(activeAbility.map(p -> p.getWarmupTime(player)).orElse(0));
|
||||
setCooldown(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized Optional<Ability<?>> getActiveAbility() {
|
||||
return activeAbility.filter(ability -> {
|
||||
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && ability.canUse(player.getSpecies()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,6 +201,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
compound.putInt("cooldown", cooldown);
|
||||
compound.putInt("maxWarmup", maxWarmup);
|
||||
compound.putInt("maxCooldown", maxCooldown);
|
||||
compound.putBoolean("triggered", triggered);
|
||||
getActiveAbility().ifPresent(ability -> {
|
||||
compound.putString("activeAbility", Abilities.REGISTRY.getId(ability).toString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -252,6 +213,8 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
cooldown = compound.getInt("cooldown");
|
||||
maxWarmup = compound.getInt("maxWarmup");
|
||||
maxCooldown = compound.getInt("maxCooldown");
|
||||
triggered = compound.getBoolean("triggered");
|
||||
activeAbility = Abilities.REGISTRY.getOrEmpty(new Identifier(compound.getString("activeAbility")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,11 +71,11 @@ public class CarryAbility implements Ability<Hit> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
}
|
||||
|
||||
public interface IPickupImmuned {
|
||||
|
|
|
@ -78,13 +78,13 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
player.getMagicalReserves().addEnergy(2);
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.getMagicalReserves().addEnergy(20);
|
||||
player.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
player.getMagicalReserves().setEnergy(0);
|
||||
player.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
|
||||
}
|
||||
|
|
|
@ -148,12 +148,12 @@ public class ChangelingFeedAbility implements Ability<Hit> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.getMagicalReserves().addExertion(6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
player.spawnParticles(ParticleTypes.HEART, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,12 +43,12 @@ public class ChangelingTrapAbility implements Ability<Hit> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,8 +81,8 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
player.getMagicalReserves().addExertion(3);
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.getMagicalReserves().addExertion(30);
|
||||
|
||||
if (player.getWorld().isClient()) {
|
||||
player.spawnParticles(MagicParticleEffect.UNICORN, 1);
|
||||
|
@ -90,7 +90,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,14 +186,14 @@ public class EarthPonyStompAbility implements Ability<Multi> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.getMagicalReserves().addExertion(40);
|
||||
player.getOwner().attemptSprintingParticles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
int timeDiff = getCooldownTime(player) - player.getAbilities().getStat(player.getAbilities().getActiveSlot()).getRemainingCooldown();
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
int timeDiff = getCooldownTime(player) - player.getAbilities().getStat(slot).getRemainingCooldown();
|
||||
|
||||
if (player.getOwner().getEntityWorld().getTime() % 1 == 0 || timeDiff == 0) {
|
||||
spawnParticleRing(player.getOwner(), timeDiff, 1);
|
||||
|
|
|
@ -66,12 +66,12 @@ public class PegasusCloudInteractionAbility implements Ability<Numeric> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.spawnParticles(MagicParticleEffect.UNICORN, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
player.spawnParticles(UParticles.RAIN_DROPS, 5);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,12 +48,12 @@ public class UnicornCastingAbility implements Ability<Hit> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.spawnParticles(MagicParticleEffect.UNICORN, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
player.spawnParticles(MagicParticleEffect.UNICORN, 5);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,13 +151,13 @@ public class UnicornTeleportAbility implements Ability<Pos> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preApply(Pony player) {
|
||||
public void preApply(Pony player, AbilitySlot slot) {
|
||||
player.getMagicalReserves().addExertion(30);
|
||||
player.spawnParticles(MagicParticleEffect.UNICORN, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(Pony player) {
|
||||
public void postApply(Pony player, AbilitySlot slot) {
|
||||
player.spawnParticles(MagicParticleEffect.UNICORN, 5);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class KeyBindingsHandler {
|
|||
}
|
||||
} else if (pressed.remove(i)) {
|
||||
System.out.println("Key up " + slot);
|
||||
iplayer.getAbilities().cancelAbility(slot);
|
||||
iplayer.getAbilities().clear(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue