mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 03:26:44 +01:00
Add a time change ability for the unicorn amulet
This commit is contained in:
parent
c6ad29eef3
commit
7787ca68b5
15 changed files with 161 additions and 7 deletions
|
@ -20,13 +20,14 @@ public interface Abilities {
|
|||
BiFunction<AbilitySlot, Race.Composite, List<Ability<?>>> BY_SLOT_AND_COMPOSITE_RACE = Util.memoize((slot, race) -> {
|
||||
return BY_SLOT.computeIfAbsent(slot, s -> new LinkedHashSet<>())
|
||||
.stream()
|
||||
.filter(a -> race.any(a::canUse))
|
||||
.filter(a -> a.canUse(race))
|
||||
.toList();
|
||||
});
|
||||
|
||||
// unicorn / alicorn
|
||||
Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY);
|
||||
Ability<?> SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.PRIMARY);
|
||||
Ability<?> TIME = register(new TimeChangeAbility(), "time_control", AbilitySlot.SECONDARY);
|
||||
Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY);
|
||||
Ability<?> GROUP_TELEPORT = register(new UnicornGroupTeleportAbility(), "teleport_group", AbilitySlot.SECONDARY);
|
||||
Ability<?> DISPELL = register(new UnicornDispellAbility(), "dispell", AbilitySlot.TERTIARY);
|
||||
|
|
|
@ -56,6 +56,14 @@ public interface Ability<T extends Hit> {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given race is permitted to use this ability
|
||||
* @param race The player's species
|
||||
*/
|
||||
default boolean canUse(Race.Composite race) {
|
||||
return race.any(this::canUse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given race is permitted to use this ability
|
||||
* @param playerSpecies The player's species
|
||||
|
|
|
@ -262,7 +262,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
|
|||
|
||||
public synchronized Optional<Ability<?>> getActiveAbility() {
|
||||
return activeAbility.filter(ability -> {
|
||||
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && player.getCompositeRace().any(ability::canUse));
|
||||
return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && ability.canUse(player.getCompositeRace()));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package com.minelittlepony.unicopia.ability;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||
import com.minelittlepony.unicopia.ability.data.Hit.Serializer;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
||||
public class TimeChangeAbility implements Ability<Hit> {
|
||||
|
||||
@Override
|
||||
public boolean canUse(Race race) {
|
||||
return race == Race.ALICORN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse(Race.Composite race) {
|
||||
return race.physical() != race.pseudo() && race.pseudo() == Race.UNICORN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCooldownTime(Pony player) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWarmupTime(Pony player) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCostEstimate(Pony player) {
|
||||
return 400;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializer<Hit> getSerializer() {
|
||||
return Hit.SERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Hit> prepare(Pony player) {
|
||||
return Hit.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Pony player, Hit data) {
|
||||
|
||||
if (player.getSpellSlot().contains(SpellType.TIME_CONTROL)) {
|
||||
player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL, true);
|
||||
} else {
|
||||
SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warmUp(Pony player, AbilitySlot slot) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void coolDown(Pony player, AbilitySlot slot) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.Abilities;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
/**
|
||||
* Internal.
|
||||
* <p>
|
||||
* Used by the Rainboom ability.
|
||||
*/
|
||||
public class TimeControlAbilitySpell extends AbstractSpell {
|
||||
|
||||
private Vec3d prevRotation = null;
|
||||
|
||||
public TimeControlAbilitySpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tick(Caster<?> source, Situation situation) {
|
||||
|
||||
if (situation != Situation.BODY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(source instanceof Pony pony) || !Abilities.TIME.canUse(pony.getCompositeRace())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source.asWorld() instanceof ServerWorld sw) {
|
||||
|
||||
float yaw = MathHelper.wrapDegrees(source.asEntity().getHeadYaw());
|
||||
float pitch = MathHelper.wrapDegrees(source.asEntity().getPitch(1)) / 90F;
|
||||
|
||||
if (yaw > 0) {
|
||||
pitch += 90;
|
||||
}
|
||||
|
||||
Vec3d rotation = new Vec3d(pitch, 0, 1);
|
||||
|
||||
if (prevRotation != null) {
|
||||
pitch = (float)MathHelper.lerp(0.05, pitch, rotation.x);
|
||||
|
||||
sw.setTimeOfDay((long)(pitch * 6000));
|
||||
}
|
||||
|
||||
prevRotation = new Vec3d(pitch, 0, 1);
|
||||
}
|
||||
|
||||
return source.subtractEnergyCost(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
super.toNBT(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
super.fromNBT(compound);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
|||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.util.RegistryUtils;
|
||||
|
@ -48,6 +49,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
|||
|
||||
public static final SpellType<DispersableDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new);
|
||||
public static final SpellType<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new);
|
||||
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new);
|
||||
|
||||
public static final SpellType<IceSpell> FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, IceSpell.DEFAULT_TRAITS, IceSpell::new);
|
||||
public static final SpellType<ChillingBreathSpell> CHILLING_BREATH = register("chilling_breath", Affinity.NEUTRAL, 0xFFEAFF, true, ChillingBreathSpell.DEFAULT_TRAITS, ChillingBreathSpell::new);
|
||||
|
|
|
@ -137,7 +137,9 @@ public class UHud {
|
|||
|
||||
slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta));
|
||||
|
||||
if (pony.getObservedSpecies().canCast()) {
|
||||
boolean canCast = Abilities.CAST.canUse(pony.getCompositeRace());
|
||||
|
||||
if (canCast) {
|
||||
Ability<?> ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY)
|
||||
.getAbility(Unicopia.getConfig().hudPage.get())
|
||||
.orElse(null);
|
||||
|
@ -168,7 +170,7 @@ public class UHud {
|
|||
|
||||
matrices.pop();
|
||||
|
||||
if (pony.getObservedSpecies().canCast()) {
|
||||
if (canCast) {
|
||||
renderSpell(context, pony.getCharms().getEquippedSpell(Hand.MAIN_HAND), hudX + 10 - xDirection * 13, hudY + 2);
|
||||
renderSpell(context, pony.getCharms().getEquippedSpell(Hand.OFF_HAND), hudX + 8 - xDirection * 2, hudY - 6);
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
|
||||
if (isBeingCarried()) {
|
||||
Pony carrier = Pony.of(entity.getVehicle()).orElse(null);
|
||||
if (!carrier.getCompositeRace().any(Abilities.CARRY::canUse)) {
|
||||
if (!Abilities.CARRY.canUse(carrier.getCompositeRace())) {
|
||||
entity.stopRiding();
|
||||
entity.refreshPositionAfterTeleport(carrier.getOriginVector());
|
||||
Living.transmitPassengers(carrier.asEntity());
|
||||
|
|
|
@ -336,7 +336,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
|||
double horizontalSpeed = this.getHorizontalMotion();
|
||||
double verticalSpeed = velocity.y;
|
||||
|
||||
if (Abilities.RAINBOOM.canUse(pony.getActualSpecies()) && horizontalSpeed != 0 && verticalSpeed < -0.3F && (verticalSpeed / horizontalSpeed) < -0.3F) {
|
||||
if (Abilities.RAINBOOM.canUse(pony.getCompositeRace()) && horizontalSpeed != 0 && verticalSpeed < -0.3F && (verticalSpeed / horizontalSpeed) < -0.3F) {
|
||||
ticksDiving++;
|
||||
} else {
|
||||
ticksDiving = 0;
|
||||
|
|
|
@ -199,6 +199,9 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
|||
if (AmuletSelectors.ALICORN_AMULET.test(entity)) {
|
||||
return Race.ALICORN;
|
||||
}
|
||||
if (AmuletSelectors.UNICORN_AMULET.test(entity)) {
|
||||
return Race.UNICORN;
|
||||
}
|
||||
|
||||
return getObservedSpecies();
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ public interface UItems {
|
|||
AmuletItem UNICORN_AMULET = register("unicorn_amulet", new AmuletItem(new FabricItemSettings()
|
||||
.maxCount(1)
|
||||
.maxDamage(890)
|
||||
.rarity(Rarity.UNCOMMON), 900), ItemGroups.TOOLS);
|
||||
.rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS);
|
||||
|
||||
GlassesItem SUNGLASSES = register("sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT);
|
||||
GlassesItem BROKEN_SUNGLASSES = register("broken_sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT);
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 984 B |
Binary file not shown.
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 565 B After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Loading…
Reference in a new issue