Clean up the abilities code

This commit is contained in:
Sollace 2023-08-15 23:18:41 +01:00
parent 3ed4ec746c
commit 3b16930e3b
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
24 changed files with 292 additions and 355 deletions

View file

@ -2,15 +2,13 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.world.World; import net.minecraft.util.Util;
public interface Ability<T extends Hit> { public interface Ability<T extends Hit> {
/** /**
@ -28,10 +26,42 @@ public interface Ability<T extends Hit> {
*/ */
int getCooldownTime(Pony player); int getCooldownTime(Pony player);
/**
* The icon representing this ability on the UI and HUD.
*/
default Identifier getIcon(Pony player) {
return getId().withPath(p -> "textures/gui/ability/" + p + ".png");
}
default int getColor(Pony player) { default int getColor(Pony player) {
return -1; return -1;
} }
/**
* The display name for this ability.
*/
default Text getName(Pony player) {
return Text.translatable(getTranslationKey());
}
default String getTranslationKey() {
return Util.createTranslationKey("ability", getId());
}
default Identifier getId() {
return Abilities.REGISTRY.getId(this);
}
default boolean activateOnEarlyRelease() {
return false;
}
/**
* Checks if the given race is permitted to use this ability
* @param playerSpecies The player's species
*/
boolean canUse(Race playerSpecies);
/** /**
* Called when an ability is about to be triggered. This event occurs on both the client and server so check {@code Pony#isClient} if you need to know which one you're on. * Called when an ability is about to be triggered. This event occurs on both the client and server so check {@code Pony#isClient} if you need to know which one you're on.
* <p> * <p>
@ -40,86 +70,32 @@ public interface Ability<T extends Hit> {
* @return True if the event has been handled. * @return True if the event has been handled.
*/ */
default boolean onQuickAction(Pony player, ActivationType type, Optional<T> data) { default boolean onQuickAction(Pony player, ActivationType type, Optional<T> data) {
return onQuickAction(player, type);
}
@Deprecated
default boolean onQuickAction(Pony player, ActivationType type) {
return false; return false;
} }
/** /**
* Called on the client to get any data required for the quick action. * Called on the client to get any data required for the quick action.
*
* @param player The player
* @param type The type of quick event being triggered
* @return The data to pass on to the quick event handler
*/ */
default Optional<T> prepareQuickAction(Pony player, ActivationType type) { default Optional<T> prepareQuickAction(Pony player, ActivationType type) {
return Optional.empty(); return Optional.empty();
} }
/** /**
* Called to check preconditions for activating the ability. * Gets the serializer to use for reading data over the network.
*
* @param w The world
* @param player The player
* @return True to allow activation
*/ */
default boolean canActivate(World w, Pony player) {
return true;
}
/**
* Checks if the given race is permitted to use this ability
* @param playerSpecies The player's species
*/
boolean canUse(Race playerSpecies);
@Deprecated
@Nullable
T tryActivate(Pony player);
/**
* Called on the client to activate the ability.
*
* @param player The player activating the ability
* @return Data to be sent, or null if activation failed
*/
default Optional<T> prepare(Pony player) {
return Optional.ofNullable(tryActivate(player));
}
Hit.Serializer<T> getSerializer(); Hit.Serializer<T> getSerializer();
/** /**
* The icon representing this ability on the UI and HUD. * Called on the client to get any data required to activate the ability.
*/
default Identifier getIcon(Pony player) {
Identifier id = Abilities.REGISTRY.getId(this);
return new Identifier(id.getNamespace(), "textures/gui/ability/" + id.getPath() + ".png");
}
default Text getName(Pony player) {
return getName();
}
/**
* The display name for this ability.
*/
default Text getName() {
return Text.translatable(getTranslationKey());
}
default String getTranslationKey() {
Identifier id = Abilities.REGISTRY.getId(this);
return "ability." + id.getNamespace() + "." + id.getPath().replace('/', '.');
}
/**
* Server-side counterpart to canActivate.
* *
* Called before applying to determine whether to cancel the command or not. * @param player The player activating the ability
* @return Data to be sent, or Empty if activation failed
*/ */
default boolean canApply(Pony player, T data) { Optional<T> prepare(Pony player);
return true;
}
/** /**
* Called to actually apply the ability. * Called to actually apply the ability.
@ -127,18 +103,19 @@ public interface Ability<T extends Hit> {
* *
* @param player The player that triggered the ability * @param player The player that triggered the ability
* @param data Data previously sent from the client * @param data Data previously sent from the client
* @return True if the ability succeeded. Returning false will cause an ability reset message to be sent to the client.
*/ */
void apply(Pony player, T data); boolean apply(Pony player, T data);
/** /**
* Called every tick until the warmup timer runs out. * Called every tick until the warmup timer runs out.
* @param player The current player * @param player The current player
*/ */
void preApply(Pony player, AbilitySlot slot); void warmUp(Pony player, AbilitySlot slot);
/** /**
* Called every tick until the cooldown timer runs out. * Called every tick until the cooldown timer runs out.
* @param player The current player * @param player The current player
*/ */
void postApply(Pony player, AbilitySlot slot); void coolDown(Pony player, AbilitySlot slot);
} }

View file

@ -37,21 +37,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
Stat stat = getStat(slot); Stat stat = getStat(slot);
if (stat.canSwitchStates()) { if (stat.canSwitchStates()) {
if (pressType == ActivationType.NONE || stat.getAbility(page).filter(ability -> !triggerQuickAction(ability, pressType)).isEmpty()) { stat.clear(pressType, page);
stat.setActiveAbility(null);
}
} }
} }
private <T extends Hit> boolean triggerQuickAction(Ability<T> ability, ActivationType pressType) {
Optional<T> data = ability.prepareQuickAction(player, pressType);
if (ability.onQuickAction(player, pressType, data)) {
Channel.CLIENT_PLAYER_ABILITY.sendToServer(new MsgPlayerAbility<>(ability, data, pressType));
return true;
}
return false;
}
public Optional<Ability<?>> activate(AbilitySlot slot, long page) { public Optional<Ability<?>> activate(AbilitySlot slot, long page) {
Stat stat = getStat(slot); Stat stat = getStat(slot);
if (stat.canSwitchStates()) { if (stat.canSwitchStates()) {
@ -182,42 +171,42 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
} }
public void tick() { public void tick() {
getActiveAbility().ifPresent(this::activate); getActiveAbility().ifPresent(ability -> {
if (warmup > 0) {
warmup--;
ability.warmUp(player, slot);
return;
}
if (cooldown > 0 && cooldown-- > 0) {
ability.coolDown(player, slot);
if (cooldown <= 0) {
setActiveAbility(null);
}
return;
}
tryFire(ability);
});
} }
private <T extends Hit> void activate(Ability<T> ability) { private <T extends Hit> void tryFire(Ability<T> ability) {
if (warmup > 0) {
warmup--;
ability.preApply(player, slot);
return;
}
if (cooldown > 0 && cooldown-- > 0) {
ability.postApply(player, slot);
if (cooldown <= 0) {
setActiveAbility(null);
}
return;
}
if (triggered) { if (triggered) {
return; return;
} }
if (ability.canActivate(player.asWorld(), player)) { triggered = true;
triggered = true; setCooldown(ability.getCooldownTime(player));
setCooldown(ability.getCooldownTime(player));
if (player.isClientPlayer()) { if (player.isClientPlayer()) {
Optional<T> data = ability.prepare(player); Optional<T> data = ability.prepare(player);
if (data.isPresent()) { if (data.isPresent()) {
Channel.CLIENT_PLAYER_ABILITY.sendToServer(new MsgPlayerAbility<>(ability, data, ActivationType.NONE)); Channel.CLIENT_PLAYER_ABILITY.sendToServer(new MsgPlayerAbility<>(ability, data, ActivationType.NONE));
} else { } else {
player.asEntity().playSound(USounds.GUI_ABILITY_FAIL, 1, 1); player.asEntity().playSound(USounds.GUI_ABILITY_FAIL, 1, 1);
setCooldown(0); setCooldown(0);
}
} }
} }
@ -235,6 +224,26 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
return Optional.ofNullable(found.get((int)Math.min(found.size() - 1, page))); return Optional.ofNullable(found.get((int)Math.min(found.size() - 1, page)));
} }
public void clear(ActivationType pressType, long page) {
if (pressType == ActivationType.NONE
|| getAbility(page).filter(ability -> !triggerQuickAction(ability, pressType)).isEmpty()) {
if (warmup > 0) {
getActiveAbility().filter(Ability::activateOnEarlyRelease).ifPresentOrElse(this::tryFire, () -> setActiveAbility(null));
} else {
setActiveAbility(null);
}
}
}
private <T extends Hit> boolean triggerQuickAction(Ability<T> ability, ActivationType pressType) {
Optional<T> data = ability.prepareQuickAction(player, pressType);
if (ability.onQuickAction(player, pressType, data)) {
Channel.CLIENT_PLAYER_ABILITY.sendToServer(new MsgPlayerAbility<>(ability, data, pressType));
return true;
}
return false;
}
public long getMaxPage() { public long getMaxPage() {
return Abilities.BY_SLOT_AND_COMPOSITE_RACE.apply(slot, player.getCompositeRace()).size(); return Abilities.BY_SLOT_AND_COMPOSITE_RACE.apply(slot, player.getCompositeRace()).size();
} }

View file

@ -45,7 +45,7 @@ abstract class AbstractSpellCastingAbility implements Ability<Hit> {
gemSpell.getValue().type().getName().copy().formatted(gemSpell.getValue().type().getAffinity().getColor()) gemSpell.getValue().type().getName().copy().formatted(gemSpell.getValue().type().getAffinity().getColor())
); );
} }
return getName(); return Ability.super.getName(player);
} }
@Override @Override
@ -64,7 +64,7 @@ abstract class AbstractSpellCastingAbility implements Ability<Hit> {
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }
} }

View file

@ -1,10 +1,12 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Numeric;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
@ -23,7 +25,7 @@ import net.minecraft.util.math.random.Random;
* A magic casting ability for unicorns. * A magic casting ability for unicorns.
* (only shields for now) * (only shields for now)
*/ */
public class BatEeeeAbility implements Ability<Hit> { public class BatEeeeAbility implements Ability<Numeric> {
@Override @Override
public int getWarmupTime(Pony player) { public int getWarmupTime(Pony player) {
@ -46,17 +48,17 @@ public class BatEeeeAbility implements Ability<Hit> {
} }
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Numeric> prepare(Pony player) {
return Hit.INSTANCE; return Numeric.of(1);
} }
@Override @Override
public Hit.Serializer<Hit> getSerializer() { public Numeric.Serializer<Numeric> getSerializer() {
return Hit.SERIALIZER; return Numeric.SERIALIZER;
} }
@Override @Override
public void apply(Pony player, Hit data) { public boolean apply(Pony player, Numeric data) {
Random rng = player.asWorld().random; Random rng = player.asWorld().random;
int count = 1 + rng.nextInt(10); int count = 1 + rng.nextInt(10);
@ -105,14 +107,16 @@ public class BatEeeeAbility implements Ability<Hit> {
if (total >= 20) { if (total >= 20) {
UCriteria.SCREECH_TWENTY_MOBS.trigger(player.asEntity()); UCriteria.SCREECH_TWENTY_MOBS.trigger(player.asEntity());
} }
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
player.addParticle(ParticleTypes.BUBBLE_POP, player.getPhysics().getHeadPosition().toCenterPos(), VecHelper.supply(() -> player.asWorld().getRandom().nextGaussian() - 0.5)); player.addParticle(ParticleTypes.BUBBLE_POP, player.getPhysics().getHeadPosition().toCenterPos(), VecHelper.supply(() -> player.asWorld().getRandom().nextGaussian() - 0.5));
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Multi; import com.minelittlepony.unicopia.ability.data.Multi;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -34,17 +36,16 @@ public class BatPonyHangAbility implements Ability<Multi> {
} }
@Override @Override
public Multi tryActivate(Pony player) { public Optional<Multi> prepare(Pony player) {
if (player.isHanging()) { if (player.isHanging()) {
return new Multi(BlockPos.ZERO, 0); return Optional.of(new Multi(BlockPos.ZERO, 0));
} }
return TraceHelper.findBlock(player.asEntity(), 5, 1) return TraceHelper.findBlock(player.asEntity(), 5, 1)
.map(BlockPos::down) .map(BlockPos::down)
.filter(player::canHangAt) .filter(player::canHangAt)
.map(pos -> new Multi(pos, 1)) .map(pos -> new Multi(pos, 1));
.orElse(null);
} }
@Override @Override
@ -53,22 +54,24 @@ public class BatPonyHangAbility implements Ability<Multi> {
} }
@Override @Override
public void apply(Pony player, Multi data) { public boolean apply(Pony player, Multi data) {
if (data.hitType == 0 && player.isHanging()) { if (data.hitType() == 0 && player.isHanging()) {
player.stopHanging(); player.stopHanging();
return; return true;
} }
if (data.hitType == 1 && player.canHangAt(data.pos())) { if (data.hitType() == 1 && player.canHangAt(data.pos().pos())) {
player.startHanging(data.pos()); player.startHanging(data.pos().pos());
} }
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
} }

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
@ -41,7 +42,7 @@ public class CarryAbility implements Ability<Hit> {
} }
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.INSTANCE; return Hit.INSTANCE;
} }
@ -57,7 +58,7 @@ public class CarryAbility implements Ability<Hit> {
} }
@Override @Override
public boolean onQuickAction(Pony player, ActivationType type) { public boolean onQuickAction(Pony player, ActivationType type, Optional<Hit> data) {
if (type == ActivationType.TAP && player.getPhysics().isFlying()) { if (type == ActivationType.TAP && player.getPhysics().isFlying()) {
player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(1, 0.3F)); player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(1, 0.3F));
@ -68,7 +69,7 @@ public class CarryAbility implements Ability<Hit> {
} }
@Override @Override
public void apply(Pony iplayer, Hit data) { public boolean apply(Pony iplayer, Hit data) {
PlayerEntity player = iplayer.asEntity(); PlayerEntity player = iplayer.asEntity();
LivingEntity rider = findRider(player, iplayer.asWorld()); LivingEntity rider = findRider(player, iplayer.asWorld());
@ -90,14 +91,15 @@ public class CarryAbility implements Ability<Hit> {
} }
Living.transmitPassengers(player); Living.transmitPassengers(player);
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
public interface IPickupImmuned { public interface IPickupImmuned {

View file

@ -1,6 +1,8 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
@ -25,19 +27,16 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
@Nullable @Nullable
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
if (player.asEntity().isCreative() || player.getMagicalReserves().getMana().getPercentFill() >= 0.9F) { return Hit.of(player.asEntity().isCreative() || player.getMagicalReserves().getMana().getPercentFill() >= 0.9F);
return Hit.INSTANCE;
}
return null;
} }
@Override @Override
public void apply(Pony iplayer, Hit data) { public boolean apply(Pony iplayer, Hit data) {
PlayerEntity player = iplayer.asEntity(); PlayerEntity player = iplayer.asEntity();
if (!player.isCreative() && iplayer.getMagicalReserves().getMana().getPercentFill() < 0.9F) { if (prepare(iplayer).isEmpty()) {
return; return false;
} }
Trace trace = Trace.create(player, 10, 1, EquinePredicates.VALID_FOR_DISGUISE); Trace trace = Trace.create(player, 10, 1, EquinePredicates.VALID_FOR_DISGUISE);
@ -61,16 +60,17 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
player.calculateDimensions(); player.calculateDimensions();
iplayer.setDirty(); iplayer.setDirty();
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getEnergy().add(20); player.getMagicalReserves().getEnergy().add(20);
player.spawnParticles(UParticles.CHANGELING_MAGIC, 5); player.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getEnergy().set(0); player.getMagicalReserves().getEnergy().set(0);
player.spawnParticles(UParticles.CHANGELING_MAGIC, 5); player.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
} }

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -51,14 +52,8 @@ public class ChangelingFeedAbility implements Ability<Hit> {
@Nullable @Nullable
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
if (canFeed(player)) { return Hit.of(canFeed(player) && !getTargets(player).isEmpty());
if (!getTargets(player).isEmpty()) {
return Hit.INSTANCE;
}
}
return null;
} }
private boolean canFeed(Pony player) { private boolean canFeed(Pony player) {
@ -97,9 +92,9 @@ public class ChangelingFeedAbility implements Ability<Hit> {
} }
@Override @Override
public void apply(Pony iplayer, Hit data) { public boolean apply(Pony iplayer, Hit data) {
if (!canFeed(iplayer)) { if (!canFeed(iplayer)) {
return; return false;
} }
PlayerEntity player = iplayer.asEntity(); PlayerEntity player = iplayer.asEntity();
@ -131,6 +126,8 @@ public class ChangelingFeedAbility implements Ability<Hit> {
} else { } else {
iplayer.playSound(SoundEvents.ENTITY_GENERIC_DRINK, 0.1F, iplayer.getRandomPitch()); iplayer.playSound(SoundEvents.ENTITY_GENERIC_DRINK, 0.1F, iplayer.getRandomPitch());
} }
return true;
} }
public float drainFrom(Pony changeling, LivingEntity living) { public float drainFrom(Pony changeling, LivingEntity living) {
@ -167,12 +164,12 @@ public class ChangelingFeedAbility implements Ability<Hit> {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(6); player.getMagicalReserves().getExertion().add(6);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
if (player.asWorld().random.nextInt(10) == 0) { if (player.asWorld().random.nextInt(10) == 0) {
player.spawnParticles(ParticleTypes.HEART, 1); player.spawnParticles(ParticleTypes.HEART, 1);
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.ability.data.Pos;
@ -35,8 +37,8 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
} }
@Override @Override
public Pos tryActivate(Pony player) { public Optional<Pos> prepare(Pony player) {
return TraceHelper.findBlock(player.asEntity(), 3, 1).map(Pos::new).orElse(null); return TraceHelper.findBlock(player.asEntity(), 3, 1).map(Pos::new);
} }
@Override @Override
@ -50,7 +52,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
} }
@Override @Override
public void apply(Pony player, Pos data) { public boolean apply(Pony player, Pos data) {
int count = 0; int count = 0;
for (BlockPos pos : BlockPos.iterate( for (BlockPos pos : BlockPos.iterate(
@ -62,6 +64,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
if (count > 0) { if (count > 0) {
player.subtractEnergyCost(count / 5D); player.subtractEnergyCost(count / 5D);
} }
return true;
} }
protected int applySingle(World w, BlockState state, BlockPos pos) { protected int applySingle(World w, BlockState state, BlockPos pos) {
@ -77,7 +80,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(30); player.getMagicalReserves().getExertion().add(30);
if (player.asWorld().isClient()) { if (player.asWorld().isClient()) {
@ -86,7 +89,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
} }

View file

@ -113,11 +113,11 @@ public class EarthPonyKickAbility implements Ability<Pos> {
@Nullable @Nullable
@Override @Override
public Pos tryActivate(Pony player) { public Optional<Pos> prepare(Pony player) {
return TraceHelper.findBlock(player.asEntity(), 6 * getKickDirection(player), 1) return TraceHelper.findBlock(player.asEntity(), 6 * getKickDirection(player), 1)
.filter(pos -> TreeType.at(pos, player.asWorld()) != TreeType.NONE) .filter(pos -> TreeType.at(pos, player.asWorld()) != TreeType.NONE)
.map(Pos::new) .map(Pos::new)
.orElseGet(() -> getDefaultKickLocation(player)); .or(() -> Optional.of(getDefaultKickLocation(player)));
} }
private int getKickDirection(Pony player) { private int getKickDirection(Pony player) {
@ -133,33 +133,26 @@ public class EarthPonyKickAbility implements Ability<Pos> {
return new Pos(BlockPos.ofFloored(player.getOriginVector().add(kickVector))); return new Pos(BlockPos.ofFloored(player.getOriginVector().add(kickVector)));
} }
@Override
public boolean canApply(Pony player, Pos data) {
BlockPos pos = data.pos();
TreeType tree = TreeType.at(pos, player.asWorld());
return tree == TreeType.NONE || tree.findBase(player.asWorld(), pos)
.map(base -> tree.countBlocks(player.asWorld(), pos) > 0)
.orElse(false);
}
@Override @Override
public Hit.Serializer<Pos> getSerializer() { public Hit.Serializer<Pos> getSerializer() {
return Pos.SERIALIZER; return Pos.SERIALIZER;
} }
@Override @Override
public void apply(Pony iplayer, Pos data) { public boolean apply(Pony iplayer, Pos data) {
BlockPos pos = data.pos(); BlockPos pos = data.pos();
TreeType tree = TreeType.at(pos, iplayer.asWorld()); TreeType tree = TreeType.at(pos, iplayer.asWorld());
if (tree == TreeType.NONE || tree.findBase(iplayer.asWorld(), pos)
.map(base -> tree.countBlocks(iplayer.asWorld(), pos) > 0)
.orElse(false)) {
return false;
}
iplayer.setAnimation(Animation.KICK, Animation.Recipient.ANYONE); iplayer.setAnimation(Animation.KICK, Animation.Recipient.ANYONE);
iplayer.subtractEnergyCost(tree == TreeType.NONE ? 1 : 3); iplayer.subtractEnergyCost(tree == TreeType.NONE ? 1 : 3);
if (tree == TreeType.NONE) {
return;
}
ParticleUtils.spawnParticle(iplayer.asWorld(), UParticles.GROUND_POUND, data.vec(), Vec3d.ZERO); ParticleUtils.spawnParticle(iplayer.asWorld(), UParticles.GROUND_POUND, data.vec(), Vec3d.ZERO);
PlayerEntity player = iplayer.asEntity(); PlayerEntity player = iplayer.asEntity();
@ -184,15 +177,17 @@ public class EarthPonyKickAbility implements Ability<Pos> {
iplayer.subtractEnergyCost(cost / 7F); iplayer.subtractEnergyCost(cost / 7F);
} }
} }
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(40); player.getMagicalReserves().getExertion().add(40);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
private int dropApples(PlayerEntity player, BlockPos pos) { private int dropApples(PlayerEntity player, BlockPos pos) {

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
@ -66,7 +68,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
@Nullable @Nullable
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
if (!player.asEntity().isOnGround() if (!player.asEntity().isOnGround()
&& player.asEntity().getVelocity().y * player.getPhysics().getGravitySignum() < 0 && player.asEntity().getVelocity().y * player.getPhysics().getGravitySignum() < 0
&& !player.asEntity().getAbilities().flying) { && !player.asEntity().getAbilities().flying) {
@ -74,7 +76,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
return Hit.INSTANCE; return Hit.INSTANCE;
} }
return null; return Optional.empty();
} }
@Override @Override
@ -92,7 +94,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
} }
@Override @Override
public void apply(Pony iplayer, Hit data) { public boolean apply(Pony iplayer, Hit data) {
PlayerEntity player = iplayer.asEntity(); PlayerEntity player = iplayer.asEntity();
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10); iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
@ -152,6 +154,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
iplayer.subtractEnergyCost(rad); iplayer.subtractEnergyCost(rad);
}); });
return true;
} }
public static void spawnEffectAround(Entity source, BlockPos center, double radius, double range) { public static void spawnEffectAround(Entity source, BlockPos center, double radius, double range) {
@ -200,11 +203,11 @@ public class EarthPonyStompAbility implements Ability<Hit> {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(40); player.getMagicalReserves().getExertion().add(40);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
@ -38,13 +40,8 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
@Nullable @Nullable
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.of(player.asEntity().isCreative() || player.getMagicalReserves().getMana().getPercentFill() >= 0.2F);
if (!player.asEntity().isCreative() && player.getMagicalReserves().getMana().getPercentFill() < 0.2F) {
return null;
}
return Hit.INSTANCE;
} }
@Override @Override
@ -58,7 +55,7 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
} }
@Override @Override
public void apply(Pony player, Hit data) { public boolean apply(Pony player, Hit data) {
World w = player.asWorld(); World w = player.asWorld();
ItemStack stack = player.asEntity().getStackInHand(Hand.MAIN_HAND); ItemStack stack = player.asEntity().getStackInHand(Hand.MAIN_HAND);
@ -106,6 +103,7 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
} }
} }
return true;
} }
private void tell(Pony player, String translation) { private void tell(Pony player, String translation) {
@ -113,12 +111,12 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(6); player.getMagicalReserves().getExertion().add(6);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
@ -29,8 +31,8 @@ public class PegasusFlightToggleAbility implements Ability<Hit> {
@Nullable @Nullable
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
return player.asEntity().isCreative() || player.getPhysics().getFlightType().isGrounded() ? null : Hit.INSTANCE; return Hit.of(!player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded());
} }
@Override @Override
@ -53,9 +55,9 @@ public class PegasusFlightToggleAbility implements Ability<Hit> {
} }
@Override @Override
public void apply(Pony player, Hit data) { public boolean apply(Pony player, Hit data) {
if (tryActivate(player) == null) { if (prepare(player).isEmpty()) {
return; return false;
} }
player.subtractEnergyCost(1); player.subtractEnergyCost(1);
@ -69,14 +71,15 @@ public class PegasusFlightToggleAbility implements Ability<Hit> {
} }
player.setDirty(); player.setDirty();
player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE); player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE);
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(6); player.getMagicalReserves().getExertion().add(6);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
@ -12,7 +14,6 @@ import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
/** /**
* Pegasus ability to perform rainbooms * Pegasus ability to perform rainbooms
@ -29,11 +30,6 @@ public class PegasusRainboomAbility implements Ability<Hit> {
return 60; return 60;
} }
@Override
public boolean canActivate(World w, Pony player) {
return player.canUseSuperMove();
}
@Override @Override
public boolean canUse(Race race) { public boolean canUse(Race race) {
return race.canInteractWithClouds(); return race.canInteractWithClouds();
@ -41,17 +37,8 @@ public class PegasusRainboomAbility implements Ability<Hit> {
@Nullable @Nullable
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.of(player.canUseSuperMove() && player.getPhysics().isFlying() && !SpellType.RAINBOOM.isOn(player));
if (!player.asEntity().isCreative() && !player.canUseSuperMove()) {
return null;
}
if (player.getPhysics().isFlying() && !SpellType.RAINBOOM.isOn(player)) {
return Hit.INSTANCE;
}
return null;
} }
@Override @Override
@ -65,7 +52,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
} }
@Override @Override
public boolean onQuickAction(Pony player, ActivationType type) { public boolean onQuickAction(Pony player, ActivationType type, Optional<Hit> data) {
if (type == ActivationType.TAP && player.getPhysics().isFlying() && player.getMagicalReserves().getMana().get() > 40) { if (type == ActivationType.TAP && player.getPhysics().isFlying() && player.getMagicalReserves().getMana().get() > 40) {
player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(2.5F, 0.3F)); player.getPhysics().dashForward((float)player.asWorld().random.nextTriangular(2.5F, 0.3F));
@ -78,25 +65,26 @@ public class PegasusRainboomAbility implements Ability<Hit> {
} }
@Override @Override
public void apply(Pony player, Hit data) { public boolean apply(Pony player, Hit data) {
if (tryActivate(player) == null) { if (prepare(player).isEmpty()) {
return; return false;
} }
if (player.consumeSuperMove()) { if (player.consumeSuperMove()) {
player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO); player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO);
SpellType.RAINBOOM.withTraits().apply(player, CastingMethod.INNATE); SpellType.RAINBOOM.withTraits().apply(player, CastingMethod.INNATE);
} }
return true;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(6); player.getMagicalReserves().getExertion().add(6);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }
} }

View file

@ -1,6 +1,6 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import org.jetbrains.annotations.Nullable; import java.util.Optional;
import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
@ -42,12 +42,8 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility {
} }
@Override @Override
@Nullable public Optional<Hit> prepare(Pony player) {
public Hit tryActivate(Pony player) { return Hit.of(player.canCast() && player.getMagicalReserves().getMana().get() >= getCostEstimate(player));
if (!player.canCast()) {
return null;
}
return Hit.of(player.getMagicalReserves().getMana().get() >= getCostEstimate(player));
} }
@Override @Override
@ -76,9 +72,9 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility {
} }
@Override @Override
public void apply(Pony player, Hit data) { public boolean apply(Pony player, Hit data) {
if (!player.canCast()) { if (!player.canCast()) {
return; return false;
} }
TypedActionResult<ItemStack> amulet = getAmulet(player); TypedActionResult<ItemStack> amulet = getAmulet(player);
@ -123,6 +119,8 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility {
} }
} }
} }
return true;
} }
private TypedActionResult<ItemStack> getAmulet(Pony player) { private TypedActionResult<ItemStack> getAmulet(Pony player) {
@ -141,7 +139,7 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExhaustion().multiply(3.3F); player.getMagicalReserves().getExhaustion().multiply(3.3F);
if (getAmulet(player).getResult() == ActionResult.CONSUME) { if (getAmulet(player).getResult() == ActionResult.CONSUME) {

View file

@ -54,7 +54,7 @@ public class UnicornDispellAbility implements Ability<Pos> {
} }
@Override @Override
public boolean onQuickAction(Pony player, ActivationType type) { public boolean onQuickAction(Pony player, ActivationType type, Optional<Pos> data) {
if (player.getSpecies() != Race.CHANGELING) { if (player.getSpecies() != Race.CHANGELING) {
if (type.getTapCount() > 1) { if (type.getTapCount() > 1) {
@ -84,16 +84,17 @@ public class UnicornDispellAbility implements Ability<Pos> {
} }
@Override @Override
public Pos tryActivate(Pony player) { public Optional<Pos> prepare(Pony player) {
return getTarget(player).map(Caster::getOrigin).map(Pos::new).orElse(null); return getTarget(player).map(Caster::getOrigin).map(Pos::new);
} }
@Override @Override
public void apply(Pony player, Pos data) { public boolean apply(Pony player, Pos data) {
player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE); player.setAnimation(Animation.WOLOLO, Animation.Recipient.ANYONE);
Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> { Caster.stream(VecHelper.findInRange(player.asEntity(), player.asWorld(), data.vec(), 3, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
target.getSpellSlot().clear(); target.getSpellSlot().clear();
}); });
return true;
} }
private Optional<Caster<?>> getTarget(Pony player) { private Optional<Caster<?>> getTarget(Pony player) {
@ -102,12 +103,12 @@ public class UnicornDispellAbility implements Ability<Pos> {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExhaustion().multiply(3.3F); player.getMagicalReserves().getExhaustion().multiply(3.3F);
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
} }
} }

View file

@ -23,9 +23,9 @@ public class UnicornGroupTeleportAbility extends UnicornTeleportAbility {
} }
@Override @Override
public void apply(Pony player, Pos data) { public boolean apply(Pony player, Pos data) {
getComrades(player).forEach(teleportee -> teleport(player, teleportee, data)); getComrades(player).forEach(teleportee -> teleport(player, teleportee, data));
super.apply(player, data); return super.apply(player, data);
} }
private Stream<Caster<?>> getComrades(Pony player) { private Stream<Caster<?>> getComrades(Pony player) {

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell; import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
@ -25,7 +27,7 @@ public class UnicornProjectileAbility extends AbstractSpellCastingAbility {
} }
@Override @Override
public Hit tryActivate(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.of(player.getCharms().getSpellInHand(false).getResult() != ActionResult.FAIL); return Hit.of(player.getCharms().getSpellInHand(false).getResult() != ActionResult.FAIL);
} }
@ -35,7 +37,7 @@ public class UnicornProjectileAbility extends AbstractSpellCastingAbility {
} }
@Override @Override
public boolean onQuickAction(Pony player, ActivationType type) { public boolean onQuickAction(Pony player, ActivationType type, Optional<Hit> data) {
if (type == ActivationType.DOUBLE_TAP) { if (type == ActivationType.DOUBLE_TAP) {
if (!player.isClient()) { if (!player.isClient()) {
TypedActionResult<CustomisedSpellType<?>> thrown = player.getCharms().getSpellInHand(true); TypedActionResult<CustomisedSpellType<?>> thrown = player.getCharms().getSpellInHand(true);
@ -54,7 +56,7 @@ public class UnicornProjectileAbility extends AbstractSpellCastingAbility {
} }
@Override @Override
public void apply(Pony player, Hit data) { public boolean apply(Pony player, Hit data) {
TypedActionResult<CustomisedSpellType<?>> thrown = player.getCharms().getSpellInHand(true); TypedActionResult<CustomisedSpellType<?>> thrown = player.getCharms().getSpellInHand(true);
if (thrown.getResult() != ActionResult.FAIL) { if (thrown.getResult() != ActionResult.FAIL) {
@ -69,11 +71,15 @@ public class UnicornProjectileAbility extends AbstractSpellCastingAbility {
TraceHelper.findEntity(player.asEntity(), 600, 1).filter(((HomingSpell)spell)::setTarget).ifPresent(projectile::setHomingTarget); TraceHelper.findEntity(player.asEntity(), 600, 1).filter(((HomingSpell)spell)::setTarget).ifPresent(projectile::setHomingTarget);
} }
}); });
return true;
} }
return false;
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExhaustion().multiply(3.3F); player.getMagicalReserves().getExhaustion().multiply(3.3F);
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability; package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
@ -32,8 +34,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
@Override @Override
public Identifier getIcon(Pony player) { public Identifier getIcon(Pony player) {
Identifier id = Abilities.REGISTRY.getId(this); return getId().withPath(p -> "textures/gui/ability/" + p + (player.asEntity().isSneaking() ? "_far" : "_near") + ".png");
return new Identifier(id.getNamespace(), "textures/gui/ability/" + id.getPath() + (player.asEntity().isSneaking() ? "_far" : "_near") + ".png");
} }
@Override @Override
@ -41,7 +42,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
if (player.asEntity().isSneaking()) { if (player.asEntity().isSneaking()) {
return Text.translatable(getTranslationKey() + ".far"); return Text.translatable(getTranslationKey() + ".far");
} }
return getName(); return Ability.super.getName(player);
} }
@Override @Override
@ -61,12 +62,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
@Override @Override
public double getCostEstimate(Pony player) { public double getCostEstimate(Pony player) {
Pos pos = tryActivate(player); return prepare(player).map(pos -> pos.distanceTo(player) / 10).orElse(0D);
if (pos == null) {
return 0;
}
return pos.distanceTo(player) / 10;
} }
@Override @Override
@ -75,10 +71,10 @@ public class UnicornTeleportAbility implements Ability<Pos> {
} }
@Override @Override
public Pos tryActivate(Pony player) { public Optional<Pos> prepare(Pony player) {
if (!player.canCast()) { if (!player.canCast()) {
return null; return Optional.empty();
} }
int maxDistance = player.asEntity().isCreative() ? 1000 : 100; int maxDistance = player.asEntity().isCreative() ? 1000 : 100;
@ -121,7 +117,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
} }
return new Pos(pos); return new Pos(pos);
}).orElse(null); });
} }
@Override @Override
@ -130,20 +126,20 @@ public class UnicornTeleportAbility implements Ability<Pos> {
} }
@Override @Override
public void apply(Pony iplayer, Pos data) { public boolean apply(Pony iplayer, Pos data) {
teleport(iplayer, iplayer, data); return teleport(iplayer, iplayer, data);
} }
protected void teleport(Pony teleporter, Caster<?> teleportee, Pos destination) { protected boolean teleport(Pony teleporter, Caster<?> teleportee, Pos destination) {
if (!teleporter.canCast()) { if (!teleporter.canCast()) {
return; return false;
} }
Entity participant = teleportee.asEntity(); Entity participant = teleportee.asEntity();
if (participant == null) { if (participant == null) {
return; return false;
} }
teleportee.asWorld().playSound(null, teleportee.getOrigin(), USounds.ENTITY_PLAYER_UNICORN_TELEPORT, SoundCategory.PLAYERS, 1, 1); teleportee.asWorld().playSound(null, teleportee.getOrigin(), USounds.ENTITY_PLAYER_UNICORN_TELEPORT, SoundCategory.PLAYERS, 1, 1);
@ -177,6 +173,8 @@ public class UnicornTeleportAbility implements Ability<Pos> {
participant.fallDistance /= distance; participant.fallDistance /= distance;
participant.getWorld().playSound(null, destination.pos(), USounds.ENTITY_PLAYER_UNICORN_TELEPORT, SoundCategory.PLAYERS, 1, 1); participant.getWorld().playSound(null, destination.pos(), USounds.ENTITY_PLAYER_UNICORN_TELEPORT, SoundCategory.PLAYERS, 1, 1);
return true;
} }
private boolean enterable(World w, BlockPos pos) { private boolean enterable(World w, BlockPos pos) {
@ -200,13 +198,13 @@ public class UnicornTeleportAbility implements Ability<Pos> {
} }
@Override @Override
public void preApply(Pony player, AbilitySlot slot) { public void warmUp(Pony player, AbilitySlot slot) {
player.getMagicalReserves().getExertion().add(30); player.getMagicalReserves().getExertion().add(30);
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }
@Override @Override
public void postApply(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
player.spawnParticles(MagicParticleEffect.UNICORN, 5); player.spawnParticles(MagicParticleEffect.UNICORN, 5);
} }
} }

View file

@ -1,25 +1,18 @@
package com.minelittlepony.unicopia.ability.data; package com.minelittlepony.unicopia.ability.data;
import java.util.Optional;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
public class Hit { public interface Hit {
Optional<Hit> INSTANCE = Optional.of(new Hit() {});
Serializer<Hit> SERIALIZER = new Serializer<>(buf -> INSTANCE.get(), (buf, t) -> {});
public static final Hit INSTANCE = new Hit(); static Optional<Hit> of(boolean value) {
public static final Serializer<Hit> SERIALIZER = buf -> INSTANCE; return value ? INSTANCE : Optional.empty();
public static Hit of(boolean value) {
return value ? INSTANCE : null;
} }
protected Hit() { public record Serializer<T extends Hit> (
PacketByteBuf.PacketReader<T> read,
} PacketByteBuf.PacketWriter<T> write) {
public void toBuffer(PacketByteBuf buf) {
}
public interface Serializer<T extends Hit> {
T fromBuffer(PacketByteBuf buf);
} }
} }

View file

@ -1,26 +1,16 @@
package com.minelittlepony.unicopia.ability.data; package com.minelittlepony.unicopia.ability.data;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.Vec3i;
public class Multi extends Pos { public record Multi (Pos pos, int hitType) implements Hit {
public static final Serializer<Multi> SERIALIZER = Multi::new; public static final Serializer<Multi> SERIALIZER = new Serializer<>(
buf -> new Multi(Pos.SERIALIZER.read().apply(buf), buf.readInt()),
public final int hitType; (buf, t) -> {
Pos.SERIALIZER.write().accept(buf, t.pos());
Multi(PacketByteBuf buf) { buf.writeInt(t.hitType());
super(buf); });
hitType = buf.readInt();
}
@Override
public void toBuffer(PacketByteBuf buf) {
super.toBuffer(buf);
buf.writeInt(hitType);
}
public Multi(Vec3i pos, int hit) { public Multi(Vec3i pos, int hit) {
super(pos.getX(), pos.getY(), pos.getZ()); this(new Pos(pos), hit);
hitType = hit;
} }
} }

View file

@ -1,22 +1,13 @@
package com.minelittlepony.unicopia.ability.data; package com.minelittlepony.unicopia.ability.data;
import net.minecraft.network.PacketByteBuf; import java.util.Optional;
public class Numeric extends Hit { public record Numeric (int type) implements Hit {
public static final Serializer<Numeric> SERIALIZER = Numeric::new; public static final Serializer<Numeric> SERIALIZER = new Serializer<>(
buf -> new Numeric(buf.readInt()),
(buf, t) -> buf.writeInt(t.type()));
public int type; public static Optional<Numeric> of(int type) {
return Optional.of(new Numeric(type));
Numeric(PacketByteBuf buf) {
type = buf.readInt();
}
@Override
public void toBuffer(PacketByteBuf buf) {
buf.writeInt(type);
}
public Numeric(int t) {
type = t;
} }
} }

View file

@ -2,40 +2,19 @@ package com.minelittlepony.unicopia.ability.data;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
public class Pos extends Hit { public record Pos (int x, int y, int z) implements Hit {
public static final Serializer<Pos> SERIALIZER = new Serializer<>(
buf -> new Pos(buf.readInt(), buf.readInt(), buf.readInt()),
(buf, t) -> {
buf.writeInt(t.x());
buf.writeInt(t.y());
buf.writeInt(t.z());
});
public static final Serializer<Pos> SERIALIZER = Pos::new; public Pos(Vec3i pos) {
this(pos.getX(), pos.getY(), pos.getZ());
public final int x;
public final int y;
public final int z;
Pos(PacketByteBuf buf) {
x = buf.readInt();
y = buf.readInt();
z = buf.readInt();
}
@Override
public void toBuffer(PacketByteBuf buf) {
buf.writeInt(x);
buf.writeInt(y);
buf.writeInt(z);
}
public Pos(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Pos(BlockPos pos) {
x = pos.getX();
y = pos.getY();
z = pos.getZ();
} }
public BlockPos pos() { public BlockPos pos() {

View file

@ -26,7 +26,7 @@ public record MsgPlayerAbility<T extends Hit> (
Ability<T> power = (Ability<T>) Abilities.REGISTRY.get(buffer.readIdentifier()); Ability<T> power = (Ability<T>) Abilities.REGISTRY.get(buffer.readIdentifier());
return new MsgPlayerAbility<>( return new MsgPlayerAbility<>(
power, power,
buffer.readOptional(power.getSerializer()::fromBuffer), buffer.readOptional(power.getSerializer().read()),
ActivationType.of(buffer.readInt()) ActivationType.of(buffer.readInt())
); );
} }
@ -34,7 +34,7 @@ public record MsgPlayerAbility<T extends Hit> (
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeIdentifier(Abilities.REGISTRY.getId(power)); buffer.writeIdentifier(Abilities.REGISTRY.getId(power));
buffer.writeOptional(data, (buf, t) -> t.toBuffer(buf)); buffer.writeOptional(data, power.getSerializer().write());
buffer.writeInt(type.ordinal()); buffer.writeInt(type.ordinal());
} }
@ -48,10 +48,9 @@ public record MsgPlayerAbility<T extends Hit> (
if (type != ActivationType.NONE) { if (type != ActivationType.NONE) {
power.onQuickAction(player, type, data); power.onQuickAction(player, type, data);
} else { } else {
data.filter(data -> power.canApply(player, data)).ifPresentOrElse( if (data.filter(data -> power.apply(player, data)).isEmpty()) {
data -> power.apply(player, data), Channel.CANCEL_PLAYER_ABILITY.sendToPlayer(new MsgCancelPlayerAbility(), sender);
() -> Channel.CANCEL_PLAYER_ABILITY.sendToPlayer(new MsgCancelPlayerAbility(), sender) }
);
} }
} }
} }