mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 23:27:59 +01:00
Implement kirin ability
This commit is contained in:
parent
dda20777f7
commit
fc1b461046
24 changed files with 559 additions and 53 deletions
|
@ -3,6 +3,7 @@ package com.minelittlepony.unicopia;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.Equine;
|
import com.minelittlepony.unicopia.entity.Equine;
|
||||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||||
|
@ -18,11 +19,13 @@ public interface EquinePredicates {
|
||||||
Predicate<Entity> CHANGELING = physicalRaceMatches(Race.CHANGELING::equals);
|
Predicate<Entity> CHANGELING = physicalRaceMatches(Race.CHANGELING::equals);
|
||||||
|
|
||||||
Predicate<Entity> RACE_INTERACT_WITH_CLOUDS = raceMatches(Race::canInteractWithClouds);
|
Predicate<Entity> RACE_INTERACT_WITH_CLOUDS = raceMatches(Race::canInteractWithClouds);
|
||||||
|
Predicate<Entity> RAGING = IS_PLAYER.and(SpellType.RAGE::isOn);
|
||||||
|
|
||||||
Predicate<Entity> PLAYER_EARTH = IS_PLAYER.and(ofRace(Race.EARTH));
|
Predicate<Entity> PLAYER_EARTH = IS_PLAYER.and(ofRace(Race.EARTH));
|
||||||
Predicate<Entity> PLAYER_BAT = IS_PLAYER.and(BAT);
|
Predicate<Entity> PLAYER_BAT = IS_PLAYER.and(BAT);
|
||||||
Predicate<Entity> PLAYER_UNICORN = IS_PLAYER.and(raceMatches(Race::canCast));
|
Predicate<Entity> PLAYER_UNICORN = IS_PLAYER.and(raceMatches(Race::canCast));
|
||||||
Predicate<Entity> PLAYER_CHANGELING = IS_PLAYER.and(ofRace(Race.CHANGELING));
|
Predicate<Entity> PLAYER_CHANGELING = IS_PLAYER.and(ofRace(Race.CHANGELING));
|
||||||
|
Predicate<Entity> PLAYER_KIRIN = IS_PLAYER.and(ofRace(Race.KIRIN));
|
||||||
Predicate<Entity> PLAYER_PEGASUS = IS_PLAYER.and(e -> ((PlayerEntity)e).getAbilities().creativeMode || RACE_INTERACT_WITH_CLOUDS.test(e));
|
Predicate<Entity> PLAYER_PEGASUS = IS_PLAYER.and(e -> ((PlayerEntity)e).getAbilities().creativeMode || RACE_INTERACT_WITH_CLOUDS.test(e));
|
||||||
|
|
||||||
Predicate<Entity> PLAYER_CAN_USE_EARTH = IS_PLAYER.and(raceMatches(Race::canUseEarth));
|
Predicate<Entity> PLAYER_CAN_USE_EARTH = IS_PLAYER.and(raceMatches(Race::canUseEarth));
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class InteractionManager {
|
||||||
public static final int SOUND_GLIDING = 4;
|
public static final int SOUND_GLIDING = 4;
|
||||||
public static final int SOUND_MAGIC_BEAM = 5;
|
public static final int SOUND_MAGIC_BEAM = 5;
|
||||||
public static final int SOUND_HEART_BEAT = 6;
|
public static final int SOUND_HEART_BEAT = 6;
|
||||||
|
public static final int SOUND_KIRIN_RAGE = 7;
|
||||||
|
|
||||||
public static final int SCREEN_DISPELL_ABILITY = 0;
|
public static final int SCREEN_DISPELL_ABILITY = 0;
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,12 @@ public interface USounds {
|
||||||
SoundEvent ENTITY_PLAYER_CHANGELING_FEED = ENTITY_GENERIC_DRINK;
|
SoundEvent ENTITY_PLAYER_CHANGELING_FEED = ENTITY_GENERIC_DRINK;
|
||||||
SoundEvent ENTITY_PLAYER_CHANGELING_CLIMB = ENTITY_CHICKEN_STEP;
|
SoundEvent ENTITY_PLAYER_CHANGELING_CLIMB = ENTITY_CHICKEN_STEP;
|
||||||
SoundEvent ENTITY_PLAYER_UNICORN_TELEPORT = register("entity.player.unicorn.teleport");
|
SoundEvent ENTITY_PLAYER_UNICORN_TELEPORT = register("entity.player.unicorn.teleport");
|
||||||
|
SoundEvent ENTITY_PLAYER_KIRIN_RAGE = ENTITY_POLAR_BEAR_WARNING;
|
||||||
|
SoundEvent ENTITY_PLAYER_KIRIN_RAGE_LOOP = register("entity.player.kirin.rage.loop");
|
||||||
|
|
||||||
SoundEvent ENTITY_PLAYER_EARS_RINGING = register("entity.player.ears_ring");
|
SoundEvent ENTITY_PLAYER_EARS_RINGING = register("entity.player.ears_ring");
|
||||||
SoundEvent ENTITY_PLAYER_HEARTBEAT = register("entity.player.heartbeat");
|
SoundEvent ENTITY_PLAYER_HEARTBEAT = register("entity.player.heartbeat");
|
||||||
|
SoundEvent ENTITY_PLAYER_HEARTBEAT_LOOP = register("entity.player.heartbeat_loop");
|
||||||
|
|
||||||
SoundEvent ENTITY_PLAYER_WOLOLO = register("entity.player.wololo");
|
SoundEvent ENTITY_PLAYER_WOLOLO = register("entity.player.wololo");
|
||||||
SoundEvent ENTITY_PLAYER_WHISTLE = register("entity.player.whistle");
|
SoundEvent ENTITY_PLAYER_WHISTLE = register("entity.player.whistle");
|
||||||
|
|
|
@ -53,6 +53,9 @@ public interface Abilities {
|
||||||
Ability<?> HANG = register(new BatPonyHangAbility(), "hang", AbilitySlot.TERTIARY);
|
Ability<?> HANG = register(new BatPonyHangAbility(), "hang", AbilitySlot.TERTIARY);
|
||||||
Ability<?> EEEE = register(new BatEeeeAbility(), "eee", AbilitySlot.SECONDARY);
|
Ability<?> EEEE = register(new BatEeeeAbility(), "eee", AbilitySlot.SECONDARY);
|
||||||
|
|
||||||
|
// kirin
|
||||||
|
Ability<?> RAGE = register(new KirinRageAbility(), "rage", AbilitySlot.PRIMARY);
|
||||||
|
|
||||||
static <T extends Ability<?>> T register(T power, String name, AbilitySlot slot) {
|
static <T extends Ability<?>> T register(T power, String name, AbilitySlot slot) {
|
||||||
Identifier id = Unicopia.id(name);
|
Identifier id = Unicopia.id(name);
|
||||||
BY_SLOT.computeIfAbsent(slot, s -> new LinkedHashSet<>()).add(power);
|
BY_SLOT.computeIfAbsent(slot, s -> new LinkedHashSet<>()).add(power);
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.minelittlepony.unicopia.ability;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.Race;
|
||||||
|
import com.minelittlepony.unicopia.USounds;
|
||||||
|
import com.minelittlepony.unicopia.ability.data.Hit;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
|
import com.minelittlepony.unicopia.block.state.StateMaps;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
|
||||||
|
import net.minecraft.particle.ParticleTypes;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kirin ability to transform into a nirik
|
||||||
|
*/
|
||||||
|
public class KirinRageAbility implements Ability<Hit> {
|
||||||
|
@Override
|
||||||
|
public int getWarmupTime(Pony player) {
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCooldownTime(Pony player) {
|
||||||
|
return 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canUse(Race race) {
|
||||||
|
return race == Race.KIRIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Optional<Hit> prepare(Pony player) {
|
||||||
|
return Hit.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Hit.Serializer<Hit> getSerializer() {
|
||||||
|
return Hit.SERIALIZER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getCostEstimate(Pony player) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Pony player, Hit data) {
|
||||||
|
|
||||||
|
if (player.consumeSuperMove()) {
|
||||||
|
player.getMagicalReserves().getCharge().set(0);
|
||||||
|
SpellType.RAGE.withTraits().apply(player, CastingMethod.INNATE);
|
||||||
|
} else {
|
||||||
|
int type = 1 + player.asWorld().random.nextInt(4);
|
||||||
|
player.asEntity().sendMessage(Text.translatable("ability.unicopia.too_calm." + type), true);
|
||||||
|
if (type == 4) {
|
||||||
|
player.getMagicalReserves().getCharge().addPercent(1);
|
||||||
|
}
|
||||||
|
player.asEntity().addExhaustion(1.5F);
|
||||||
|
|
||||||
|
if (StateMaps.BURNABLE.convert(player.asWorld(), player.getOrigin().down())) {
|
||||||
|
player.playSound(USounds.SPELL_FIRE_CRACKLE, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warmUp(Pony player, AbilitySlot slot) {
|
||||||
|
player.spawnParticles(ParticleTypes.LAVA, 4);
|
||||||
|
player.getMagicalReserves().getEnergy().addPercent(1.03F);
|
||||||
|
if (player.asEntity().age % 15 == 0) {
|
||||||
|
player.asWorld().playSound(player.asEntity(), player.getOrigin(), USounds.ENTITY_PLAYER_KIRIN_RAGE, SoundCategory.PLAYERS, 1F, 0.0125F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void coolDown(Pony player, AbilitySlot slot) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.InteractionManager;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
|
||||||
|
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
||||||
|
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.damage.DamageTypes;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.particle.ParticleTypes;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World.ExplosionSourceType;
|
||||||
|
import net.minecraft.world.explosion.Explosion;
|
||||||
|
import net.minecraft.world.explosion.ExplosionBehavior;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal.
|
||||||
|
* <p>
|
||||||
|
* Used by the Rage ability.
|
||||||
|
*/
|
||||||
|
public class RageAbilitySpell extends AbstractSpell {
|
||||||
|
private int age;
|
||||||
|
private int ticksExtenguishing;
|
||||||
|
|
||||||
|
public RageAbilitySpell(CustomisedSpellType<?> type) {
|
||||||
|
super(type);
|
||||||
|
setHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tick(Caster<?> source, Situation situation) {
|
||||||
|
|
||||||
|
if (situation != Situation.BODY || source.asEntity().isRemoved()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.asEntity().isInsideWaterOrBubbleColumn()) {
|
||||||
|
ticksExtenguishing++;
|
||||||
|
source.playSound(SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, 1);
|
||||||
|
source.spawnParticles(ParticleTypes.CLOUD, 12);
|
||||||
|
setDirty();
|
||||||
|
} else {
|
||||||
|
ticksExtenguishing = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksExtenguishing > 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos pos = source.getOrigin();
|
||||||
|
|
||||||
|
if (!source.isClient()) {
|
||||||
|
if (age == 0) {
|
||||||
|
source.asWorld().createExplosion(source.asEntity(), source.damageOf(DamageTypes.FIREBALL), new ExplosionBehavior(){
|
||||||
|
@Override
|
||||||
|
public boolean canDestroyBlock(Explosion explosion, BlockView world, BlockPos pos, BlockState state, float power) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, source.getOriginVector(), 0, true, ExplosionSourceType.MOB);
|
||||||
|
|
||||||
|
if (source instanceof Pony pony) {
|
||||||
|
pony.setAnimation(Animation.ARMS_UP, Recipient.ANYONE, 12);
|
||||||
|
}
|
||||||
|
source.playSound(SoundEvents.ENTITY_POLAR_BEAR_WARNING, 2F, 0.1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.asEntity().isOnGround() && source.asWorld().isAir(pos) && age % 10 == 0) {
|
||||||
|
source.asWorld().setBlockState(pos, Blocks.FIRE.getDefaultState());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source instanceof Pony pony) {
|
||||||
|
if (pony.asEntity().getAttackCooldownProgress(0) == 0) {
|
||||||
|
LivingEntity adversary = pony.asEntity().getPrimeAdversary();
|
||||||
|
if (adversary != null) {
|
||||||
|
adversary.setOnFireFor(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (age % 5 == 0) {
|
||||||
|
source.spawnParticles(ParticleTypes.LAVA, 4);
|
||||||
|
source.subtractEnergyCost(Math.min(12, 3 + source.asEntity().getVelocity().length() * 0.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source instanceof Pony pony) {
|
||||||
|
if (source.isClient() && pony.asEntity().getAttackCooldownProgress(0) == 0) {
|
||||||
|
InteractionManager.instance().playLoopingSound(source.asEntity(), InteractionManager.SOUND_KIRIN_RAGE, source.asWorld().random.nextLong());
|
||||||
|
}
|
||||||
|
pony.getMagicalReserves().getEnergy().add(0.5F + (age / 1000F));
|
||||||
|
pony.getMagicalReserves().getMana().add(-1);
|
||||||
|
if (pony.getMagicalReserves().getMana().get() <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.asWorld().hasRain(pos.up()) && source.asWorld().random.nextInt(15) == 0) {
|
||||||
|
source.playSound(SoundEvents.ENTITY_GENERIC_EXTINGUISH_FIRE, 0.3F);
|
||||||
|
source.spawnParticles(ParticleTypes.CLOUD, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
age++;
|
||||||
|
setDirty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toNBT(NbtCompound compound) {
|
||||||
|
super.toNBT(compound);
|
||||||
|
compound.putInt("age", age);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromNBT(NbtCompound compound) {
|
||||||
|
super.fromNBT(compound);
|
||||||
|
age = compound.getInt("age");
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.TimeControlAbilitySpell;
|
||||||
|
@ -49,6 +50,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<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<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new);
|
||||||
|
public static final SpellType<RageAbilitySpell> RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RageAbilitySpell::new);
|
||||||
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::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<IceSpell> FROST = register("frost", Affinity.GOOD, 0xEABBFF, true, IceSpell.DEFAULT_TRAITS, IceSpell::new);
|
||||||
|
|
|
@ -7,6 +7,7 @@ public interface StateMaps {
|
||||||
BlockStateConverter ICE_AFFECTED = of("ice");
|
BlockStateConverter ICE_AFFECTED = of("ice");
|
||||||
BlockStateConverter SILVERFISH_AFFECTED = of("infestation");
|
BlockStateConverter SILVERFISH_AFFECTED = of("infestation");
|
||||||
BlockStateConverter FIRE_AFFECTED = of("fire");
|
BlockStateConverter FIRE_AFFECTED = of("fire");
|
||||||
|
BlockStateConverter BURNABLE = of("burnable");
|
||||||
ReversableBlockStateConverter HELLFIRE_AFFECTED = of("hellfire");
|
ReversableBlockStateConverter HELLFIRE_AFFECTED = of("hellfire");
|
||||||
|
|
||||||
private static ReversableBlockStateConverter of(String name) {
|
private static ReversableBlockStateConverter of(String name) {
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package com.minelittlepony.unicopia.client;
|
package com.minelittlepony.unicopia.client;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
import com.minelittlepony.unicopia.FlightType;
|
import com.minelittlepony.unicopia.FlightType;
|
||||||
import com.minelittlepony.unicopia.InteractionManager;
|
import com.minelittlepony.unicopia.InteractionManager;
|
||||||
import com.minelittlepony.unicopia.USounds;
|
import com.minelittlepony.unicopia.USounds;
|
||||||
|
@ -20,11 +23,13 @@ import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity;
|
||||||
import com.minelittlepony.unicopia.server.world.Ether;
|
import com.minelittlepony.unicopia.server.world.Ether;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.sound.AggressiveBeeSoundInstance;
|
import net.minecraft.client.sound.AggressiveBeeSoundInstance;
|
||||||
import net.minecraft.client.sound.MovingMinecartSoundInstance;
|
import net.minecraft.client.sound.MovingMinecartSoundInstance;
|
||||||
import net.minecraft.client.sound.PassiveBeeSoundInstance;
|
import net.minecraft.client.sound.PassiveBeeSoundInstance;
|
||||||
import net.minecraft.client.sound.SoundManager;
|
import net.minecraft.client.sound.TickableSoundInstance;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
@ -45,6 +50,8 @@ public class ClientInteractionManager extends InteractionManager {
|
||||||
|
|
||||||
private final Optional<CasterView> clientWorld = Optional.of(() -> MinecraftClient.getInstance().world);
|
private final Optional<CasterView> clientWorld = Optional.of(() -> MinecraftClient.getInstance().world);
|
||||||
|
|
||||||
|
private final Int2ObjectMap<WeakReference<TickableSoundInstance>> playingSounds = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<CasterView> getCasterView(BlockView view) {
|
public Optional<CasterView> getCasterView(BlockView view) {
|
||||||
if (view instanceof ServerWorld world) {
|
if (view instanceof ServerWorld world) {
|
||||||
|
@ -61,43 +68,62 @@ public class ClientInteractionManager extends InteractionManager {
|
||||||
@Override
|
@Override
|
||||||
public void playLoopingSound(Entity source, int type, long seed) {
|
public void playLoopingSound(Entity source, int type, long seed) {
|
||||||
client.execute(() -> {
|
client.execute(() -> {
|
||||||
SoundManager soundManager = client.getSoundManager();
|
|
||||||
|
|
||||||
if (type == SOUND_EARS_RINGING && source instanceof LivingEntity living) {
|
if (type == SOUND_EARS_RINGING && source instanceof LivingEntity living) {
|
||||||
soundManager.playNextTick(new LoopingSoundInstance<>(living,
|
play(type, () -> new LoopingSoundInstance<>(living,
|
||||||
createTicker(100).and(e -> !e.isRemoved()),
|
createTicker(100).and(e -> !e.isRemoved()),
|
||||||
USounds.ENTITY_PLAYER_EARS_RINGING, 0.01F, 2, Random.create(seed)).setFadeIn()
|
USounds.ENTITY_PLAYER_EARS_RINGING, 0.01F, 2, Random.create(seed)).setFadeIn()
|
||||||
);
|
);
|
||||||
} else if (type == SOUND_BEE && source instanceof BeeEntity bee) {
|
} else if (type == SOUND_BEE && source instanceof BeeEntity bee) {
|
||||||
soundManager.playNextTick(
|
play(type, () ->
|
||||||
bee.hasAngerTime()
|
bee.hasAngerTime()
|
||||||
? new AggressiveBeeSoundInstance(bee)
|
? new AggressiveBeeSoundInstance(bee)
|
||||||
: new PassiveBeeSoundInstance(bee)
|
: new PassiveBeeSoundInstance(bee)
|
||||||
);
|
);
|
||||||
} else if (type == SOUND_MINECART && source instanceof AbstractMinecartEntity minecart) {
|
} else if (type == SOUND_MINECART && source instanceof AbstractMinecartEntity minecart) {
|
||||||
soundManager.playNextTick(new MovingMinecartSoundInstance(minecart));
|
play(type, () -> new MovingMinecartSoundInstance(minecart));
|
||||||
} else if (type == SOUND_CHANGELING_BUZZ && source instanceof PlayerEntity player) {
|
} else if (type == SOUND_CHANGELING_BUZZ && source instanceof PlayerEntity player) {
|
||||||
soundManager.playNextTick(new MotionBasedSoundInstance<>(USounds.ENTITY_PLAYER_CHANGELING_BUZZ, player, e -> {
|
play(type, () -> new MotionBasedSoundInstance<>(USounds.ENTITY_PLAYER_CHANGELING_BUZZ, player, e -> {
|
||||||
PlayerPhysics physics = Pony.of(e).getPhysics();
|
PlayerPhysics physics = Pony.of(e).getPhysics();
|
||||||
return physics.isFlying() && physics.getFlightType() == FlightType.INSECTOID;
|
return physics.isFlying() && physics.getFlightType() == FlightType.INSECTOID;
|
||||||
}, 0.25F, 0.5F, 0.66F, Random.create(seed)));
|
}, 0.25F, 0.5F, 0.66F, Random.create(seed)));
|
||||||
} else if (type == SOUND_GLIDING && source instanceof PlayerEntity player && isClientPlayer(player)) {
|
} else if (type == SOUND_GLIDING && source instanceof PlayerEntity player && isClientPlayer(player)) {
|
||||||
soundManager.playNextTick(new MotionBasedSoundInstance<>(USounds.Vanilla.ITEM_ELYTRA_FLYING, player, e -> {
|
play(type, () -> new MotionBasedSoundInstance<>(USounds.Vanilla.ITEM_ELYTRA_FLYING, player, e -> {
|
||||||
Pony pony = Pony.of(e);
|
Pony pony = Pony.of(e);
|
||||||
return pony.getPhysics().isFlying() && pony.getPhysics().getFlightType().isAvian();
|
return pony.getPhysics().isFlying() && pony.getPhysics().getFlightType().isAvian();
|
||||||
}, 0, 1, 1, Random.create(seed)));
|
}, 0, 1, 1, Random.create(seed)));
|
||||||
} else if (type == SOUND_GLIDING && source instanceof PlayerEntity player) {
|
} else if (type == SOUND_GLIDING && source instanceof PlayerEntity player) {
|
||||||
soundManager.playNextTick(new MotionBasedSoundInstance<>(USounds.ENTITY_PLAYER_PEGASUS_FLYING, player, e -> {
|
play(type, () -> new MotionBasedSoundInstance<>(USounds.ENTITY_PLAYER_PEGASUS_FLYING, player, e -> {
|
||||||
Pony pony = Pony.of(e);
|
Pony pony = Pony.of(e);
|
||||||
return pony.getPhysics().isFlying() && pony.getPhysics().getFlightType().isAvian();
|
return pony.getPhysics().isFlying() && pony.getPhysics().getFlightType().isAvian();
|
||||||
}, 0, 1, 1, Random.create(seed)));
|
}, 0, 1, 1, Random.create(seed)));
|
||||||
} else if (type == SOUND_MAGIC_BEAM) {
|
} else if (type == SOUND_MAGIC_BEAM) {
|
||||||
soundManager.playNextTick(new LoopedEntityTrackingSoundInstance(USounds.SPELL_CAST_SHOOT, 0.3F, 1F, source, seed));
|
play(type, () -> new LoopedEntityTrackingSoundInstance(USounds.SPELL_CAST_SHOOT, 0.3F, 1F, source, seed));
|
||||||
} else if (type == SOUND_HEART_BEAT) {
|
} else if (type == SOUND_HEART_BEAT) {
|
||||||
soundManager.playNextTick(new NonLoopingFadeOutSoundInstance(USounds.ENTITY_PLAYER_HEARTBEAT, SoundCategory.PLAYERS, 0.3F, Random.create(seed), 80L));
|
play(type, () -> new NonLoopingFadeOutSoundInstance(USounds.ENTITY_PLAYER_HEARTBEAT_LOOP, SoundCategory.PLAYERS, 0.3F, Random.create(seed), 80L));
|
||||||
|
} else if (type == SOUND_KIRIN_RAGE) {
|
||||||
|
play(type, () -> new FadeOutSoundInstance(USounds.ENTITY_PLAYER_KIRIN_RAGE_LOOP, SoundCategory.AMBIENT, 0.3F, Random.create(seed)) {
|
||||||
|
@Override
|
||||||
|
protected boolean shouldKeepPlaying() {
|
||||||
|
return EquinePredicates.RAGING.test(source);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void play(int type, Supplier<TickableSoundInstance> soundSupplier) {
|
||||||
|
WeakReference<TickableSoundInstance> activeSound = playingSounds.get(type);
|
||||||
|
TickableSoundInstance existing;
|
||||||
|
if (activeSound == null || (existing = activeSound.get()) == null || existing.isDone()) {
|
||||||
|
existing = soundSupplier.get();
|
||||||
|
playingSounds.put(type, new WeakReference<>(existing));
|
||||||
|
playNow(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playNow(TickableSoundInstance sound) {
|
||||||
|
client.getSoundManager().playNextTick(sound);
|
||||||
|
}
|
||||||
|
|
||||||
static Predicate<LivingEntity> createTicker(int ticks) {
|
static Predicate<LivingEntity> createTicker(int ticks) {
|
||||||
int[] ticker = new int[] {ticks};
|
int[] ticker = new int[] {ticks};
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class UHud {
|
||||||
|
|
||||||
float exhaustion = pony.getMagicalReserves().getExhaustion().getPercentFill();
|
float exhaustion = pony.getMagicalReserves().getExhaustion().getPercentFill();
|
||||||
|
|
||||||
if (exhaustion > 0.5F) {
|
if (exhaustion > 0.5F || EquinePredicates.RAGING.test(client.player)) {
|
||||||
Random rng = client.world.random;
|
Random rng = client.world.random;
|
||||||
hudX += rng.nextFloat() - 0.5F;
|
hudX += rng.nextFloat() - 0.5F;
|
||||||
hudY += rng.nextFloat() - 0.5F;
|
hudY += rng.nextFloat() - 0.5F;
|
||||||
|
@ -264,7 +264,7 @@ public class UHud {
|
||||||
client.getSoundManager().play(
|
client.getSoundManager().play(
|
||||||
heartbeatSound = new LoopingSoundInstance<>(client.player, player -> {
|
heartbeatSound = new LoopingSoundInstance<>(client.player, player -> {
|
||||||
return partySound == null && Pony.of(player).getMagicalReserves().getExhaustion().getPercentFill() > 0.5F;
|
return partySound == null && Pony.of(player).getMagicalReserves().getExhaustion().getPercentFill() > 0.5F;
|
||||||
}, USounds.ENTITY_PLAYER_HEARTBEAT, 1, 1, client.world.random)
|
}, USounds.ENTITY_PLAYER_HEARTBEAT_LOOP, 1, 1, client.world.random)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,6 +273,17 @@ public class UHud {
|
||||||
|
|
||||||
renderVignette(context, 0x880000, exhaustion * radius, 0.1F + radius * 0.3F, scaledWidth, scaledHeight);
|
renderVignette(context, 0x880000, exhaustion * radius, 0.1F + radius * 0.3F, scaledWidth, scaledHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float anger = pony.getMagicalReserves().getCharge().getPercentFill();
|
||||||
|
|
||||||
|
if (pony.getObservedSpecies() == Race.KIRIN && anger >= 1F) {
|
||||||
|
float radius = (1 + (float)Math.sin(client.player.age / 25F)) / 5F;
|
||||||
|
renderVignette(context, 0x000000, anger * radius, 0.1F + radius * 0.3F, scaledWidth, scaledHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EquinePredicates.RAGING.test(client.player)) {
|
||||||
|
context.fill(0, 0, scaledWidth, scaledHeight, 0x3AFF0000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderVignette(DrawContext context, int color, float alpha, float radius, int scaledWidth, int scaledHeight) {
|
private void renderVignette(DrawContext context, int color, float alpha, float radius, int scaledWidth, int scaledHeight) {
|
||||||
|
|
|
@ -89,8 +89,15 @@ public class TrinketsDelegateImpl implements TrinketsDelegate {
|
||||||
TrinketsApi.registerTrinket(item, new UnicopiaTrinket(item));
|
TrinketsApi.registerTrinket(item, new UnicopiaTrinket(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<TrinketComponent> getTrinketComponent(LivingEntity entity) {
|
||||||
|
try {
|
||||||
|
return TrinketsApi.getTrinketComponent(entity);
|
||||||
|
} catch (Throwable ingnored) {}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<TrinketInventory> getInventory(LivingEntity entity, Identifier slot) {
|
public Optional<TrinketInventory> getInventory(LivingEntity entity, Identifier slot) {
|
||||||
return TrinketsApi.getTrinketComponent(entity)
|
return getTrinketComponent(entity)
|
||||||
.map(component -> component.getInventory()
|
.map(component -> component.getInventory()
|
||||||
.getOrDefault(slot.getNamespace(), Map.of())
|
.getOrDefault(slot.getNamespace(), Map.of())
|
||||||
.getOrDefault(slot.getPath(), null)
|
.getOrDefault(slot.getPath(), null)
|
||||||
|
@ -98,7 +105,7 @@ public class TrinketsDelegateImpl implements TrinketsDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<TrinketInventory> getInventories(LivingEntity entity) {
|
public Stream<TrinketInventory> getInventories(LivingEntity entity) {
|
||||||
return TrinketsApi.getTrinketComponent(entity)
|
return getTrinketComponent(entity)
|
||||||
.stream()
|
.stream()
|
||||||
.map(component -> component.getInventory())
|
.map(component -> component.getInventory())
|
||||||
.flatMap(groups -> groups.values().stream())
|
.flatMap(groups -> groups.values().stream())
|
||||||
|
@ -106,7 +113,7 @@ public class TrinketsDelegateImpl implements TrinketsDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<SlotGroup> getGroup(LivingEntity entity, Identifier slotId) {
|
public Optional<SlotGroup> getGroup(LivingEntity entity, Identifier slotId) {
|
||||||
return TrinketsApi.getTrinketComponent(entity)
|
return getTrinketComponent(entity)
|
||||||
.stream()
|
.stream()
|
||||||
.map(component -> component.getGroups().get(slotId.getNamespace()))
|
.map(component -> component.getGroups().get(slotId.getNamespace()))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package com.minelittlepony.unicopia.entity.player;
|
package com.minelittlepony.unicopia.entity.player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
|
import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
|
||||||
import com.minelittlepony.unicopia.util.Tickable;
|
import com.minelittlepony.unicopia.util.Tickable;
|
||||||
|
|
||||||
|
@ -11,20 +14,52 @@ import net.minecraft.entity.attribute.EntityAttributeInstance;
|
||||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||||
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
|
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
|
||||||
import net.minecraft.entity.attribute.EntityAttributes;
|
import net.minecraft.entity.attribute.EntityAttributes;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
|
||||||
|
|
||||||
public class PlayerAttributes implements Tickable {
|
public class PlayerAttributes implements Tickable {
|
||||||
private static final EntityAttributeModifier EARTH_PONY_STRENGTH =
|
private final static List<ToggleableAttribute> ATTRIBUTES = List.of(
|
||||||
new EntityAttributeModifier(UUID.fromString("777a5505-521e-480b-b9d5-6ea54f259564"), "Earth Pony Strength", 0.6, Operation.MULTIPLY_TOTAL);
|
new ToggleableAttribute(
|
||||||
private static final EntityAttributeModifier EARTH_PONY_MINING_SPEED =
|
new EntityAttributeModifier(UUID.fromString("777a5505-521e-480b-b9d5-6ea54f259564"), "Earth Pony Strength", 0.6, Operation.MULTIPLY_TOTAL),
|
||||||
new EntityAttributeModifier(UUID.fromString("9fc9e269-152e-0b48-9bd5-564a546e59f2"), "Earth Pony Mining Speed", 0.5, Operation.MULTIPLY_TOTAL);
|
List.of(EntityAttributes.GENERIC_ATTACK_DAMAGE, EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE),
|
||||||
private static final EntityAttributeModifier EARTH_PONY_KNOCKBACK_RESISTANCE =
|
pony -> pony.getCompositeRace().canUseEarth()
|
||||||
new EntityAttributeModifier(UUID.fromString("79e269a8-03e8-b9d5-5853-e25fdcf6706d"), "Earth Pony Knockback Resistance", 6, Operation.ADDITION);
|
),
|
||||||
|
new ToggleableAttribute(
|
||||||
|
new EntityAttributeModifier(UUID.fromString("79e269a8-03e8-b9d5-5853-e25fdcf6706d"), "Earth Pony Knockback Resistance", 6, Operation.ADDITION),
|
||||||
|
List.of(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE),
|
||||||
|
pony -> pony.getCompositeRace().canUseEarth() && pony.asEntity().isSneaking()
|
||||||
|
),
|
||||||
|
new ToggleableAttribute(
|
||||||
|
new EntityAttributeModifier(UUID.fromString("9fc9e269-152e-0b48-9bd5-564a546e59f2"), "Earth Pony Mining Speed", 0.5, Operation.MULTIPLY_TOTAL),
|
||||||
|
List.of(UEntityAttributes.EXTRA_MINING_SPEED),
|
||||||
|
pony -> pony.getCompositeRace().canUseEarth()
|
||||||
|
),
|
||||||
|
|
||||||
private static final EntityAttributeModifier PEGASUS_SPEED =
|
new ToggleableAttribute(
|
||||||
new EntityAttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-9d2d-fb92ee19b4f7"), "Pegasus Speed", 0.2, Operation.MULTIPLY_TOTAL);
|
new EntityAttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-9d2d-fb92ee19b4f7"), "Pegasus Speed", 0.2, Operation.MULTIPLY_TOTAL),
|
||||||
private static final EntityAttributeModifier PEGASUS_REACH =
|
List.of(EntityAttributes.GENERIC_MOVEMENT_SPEED, EntityAttributes.GENERIC_ATTACK_SPEED),
|
||||||
new EntityAttributeModifier(UUID.fromString("707b50a8-03e8-40f4-8553-ecf67025fd6d"), "Pegasus Reach", 1.5, Operation.ADDITION);
|
pony -> pony.getCompositeRace().canFly()
|
||||||
|
),
|
||||||
|
new ToggleableAttribute(
|
||||||
|
new EntityAttributeModifier(UUID.fromString("707b50a8-03e8-40f4-8553-ecf67025fd6d"), "Pegasus Reach", 1.5, Operation.ADDITION),
|
||||||
|
List.of(UEntityAttributes.EXTENDED_REACH_DISTANCE),
|
||||||
|
pony -> pony.getCompositeRace().canFly()
|
||||||
|
),
|
||||||
|
|
||||||
|
new ToggleableAttribute(
|
||||||
|
new EntityAttributeModifier(UUID.fromString("79e269a8-03e8-b9d5-5853-e25fdcf6706e"), "Kirin Knockback Vulnerability", -2, Operation.ADDITION),
|
||||||
|
List.of(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE),
|
||||||
|
pony -> pony.getCompositeRace().includes(Race.KIRIN)
|
||||||
|
),
|
||||||
|
new ToggleableAttribute(
|
||||||
|
new EntityAttributeModifier(UUID.fromString("4991fde9-c685-4930-bbd2-d7a228728bfe"), "Kirin Rage Speed", 0.7, Operation.MULTIPLY_TOTAL),
|
||||||
|
List.of(EntityAttributes.GENERIC_MOVEMENT_SPEED,
|
||||||
|
EntityAttributes.GENERIC_ATTACK_SPEED,
|
||||||
|
EntityAttributes.GENERIC_ATTACK_DAMAGE,
|
||||||
|
EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE,
|
||||||
|
EntityAttributes.GENERIC_ATTACK_KNOCKBACK
|
||||||
|
),
|
||||||
|
SpellType.RAGE::isOn
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
public static final UUID HEALTH_SWAPPING_MODIFIER_ID = UUID.fromString("7b93803e-4b25-11ed-951e-00155d43e0a2");
|
public static final UUID HEALTH_SWAPPING_MODIFIER_ID = UUID.fromString("7b93803e-4b25-11ed-951e-00155d43e0a2");
|
||||||
|
|
||||||
|
@ -40,23 +75,14 @@ public class PlayerAttributes implements Tickable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
PlayerEntity entity = pony.asEntity();
|
ATTRIBUTES.forEach(attribute -> attribute.update(pony));
|
||||||
Race.Composite race = pony.getCompositeRace();
|
|
||||||
|
|
||||||
boolean earth = race.canUseEarth();
|
|
||||||
boolean flight = race.canFly();
|
|
||||||
|
|
||||||
toggleAttribute(entity, EntityAttributes.GENERIC_ATTACK_DAMAGE, EARTH_PONY_STRENGTH, earth);
|
|
||||||
toggleAttribute(entity, EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, EARTH_PONY_STRENGTH, earth);
|
|
||||||
toggleAttribute(entity, EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, EARTH_PONY_KNOCKBACK_RESISTANCE, earth && entity.isSneaking());
|
|
||||||
toggleAttribute(entity, EntityAttributes.GENERIC_MOVEMENT_SPEED, PEGASUS_SPEED, flight);
|
|
||||||
toggleAttribute(entity, EntityAttributes.GENERIC_ATTACK_SPEED, PEGASUS_SPEED, flight);
|
|
||||||
toggleAttribute(entity, UEntityAttributes.EXTENDED_REACH_DISTANCE, PEGASUS_REACH, flight);
|
|
||||||
toggleAttribute(entity, UEntityAttributes.EXTRA_MINING_SPEED, EARTH_PONY_MINING_SPEED, earth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleAttribute(PlayerEntity entity, EntityAttribute attribute, EntityAttributeModifier modifier, boolean enable) {
|
record ToggleableAttribute(EntityAttributeModifier modifier, List<EntityAttribute> attributes, Predicate<Pony> test) {
|
||||||
EntityAttributeInstance instance = entity.getAttributeInstance(attribute);
|
public void update(Pony pony) {
|
||||||
|
boolean enable = test.test(pony);
|
||||||
|
attributes.forEach(attribute -> {
|
||||||
|
EntityAttributeInstance instance = pony.asEntity().getAttributeInstance(attribute);
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
if (!instance.hasModifier(modifier)) {
|
if (!instance.hasModifier(modifier)) {
|
||||||
|
@ -65,6 +91,7 @@ public class PlayerAttributes implements Tickable {
|
||||||
} else {
|
} else {
|
||||||
instance.tryRemoveModifier(modifier.getId());
|
instance.tryRemoveModifier(modifier.getId());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.*;
|
||||||
import com.minelittlepony.unicopia.ability.*;
|
import com.minelittlepony.unicopia.ability.*;
|
||||||
import com.minelittlepony.unicopia.ability.magic.*;
|
import com.minelittlepony.unicopia.ability.magic.*;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.TraitDiscovery;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.TraitDiscovery;
|
||||||
|
@ -52,6 +53,7 @@ import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.PlayerInventory;
|
import net.minecraft.entity.player.PlayerInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.particle.ParticleTypes;
|
||||||
import net.minecraft.registry.tag.DamageTypeTags;
|
import net.minecraft.registry.tag.DamageTypeTags;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
@ -386,7 +388,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
|
|
||||||
if (!getPhysics().isFlying() && !entity.getAbilities().flying && climbingPos != null && getObservedSpecies() == Race.CHANGELING) {
|
if (!getPhysics().isFlying() && !entity.getAbilities().flying && climbingPos != null && getObservedSpecies() == Race.CHANGELING) {
|
||||||
Vec3d vel = entity.getVelocity();
|
Vec3d vel = entity.getVelocity();
|
||||||
if (entity.isSneaky()) {
|
if (entity.isSneaking()) {
|
||||||
entity.setVelocity(vel.x, 0, vel.z);
|
entity.setVelocity(vel.x, 0, vel.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +437,24 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
distanceClimbed = 0;
|
distanceClimbed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getObservedSpecies() == Race.KIRIN) {
|
||||||
|
var charge = getMagicalReserves().getCharge();
|
||||||
|
|
||||||
|
if (charge.getPercentFill() >= 1) {
|
||||||
|
var energy = getMagicalReserves().getEnergy();
|
||||||
|
if (energy.getPercentFill() < 0.002F) {
|
||||||
|
energy.addPercent(1.03F);
|
||||||
|
if (entity.age % 25 == 0) {
|
||||||
|
playSound(USounds.ENTITY_PLAYER_HEARTBEAT, 0.17F + (float)entity.getWorld().random.nextGaussian() * 0.03F, 0.5F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.getAttackCooldownProgress(0) == 0) {
|
||||||
|
charge.addPercent(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return super.beforeUpdate();
|
return super.beforeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,7 +508,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
private void updateAnimations() {
|
private void updateAnimations() {
|
||||||
|
|
||||||
if (distanceClimbed > 0
|
if (distanceClimbed > 0
|
||||||
&& ((animation.isOf(Animation.CLIMB) && entity.isSneaky()) || animation.isOf(Animation.HANG))
|
&& ((animation.isOf(Animation.CLIMB) && entity.isSneaking()) || animation.isOf(Animation.HANG))
|
||||||
&& entity.getClimbingPos().isPresent()
|
&& entity.getClimbingPos().isPresent()
|
||||||
&& entity.getVelocity().length() < 0.08F) {
|
&& entity.getVelocity().length() < 0.08F) {
|
||||||
if (animation.renderBothArms()) {
|
if (animation.renderBothArms()) {
|
||||||
|
@ -644,6 +664,21 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
|
|
||||||
public Optional<Float> modifyDamage(DamageSource cause, float amount) {
|
public Optional<Float> modifyDamage(DamageSource cause, float amount) {
|
||||||
|
|
||||||
|
if (getObservedSpecies() == Race.KIRIN) {
|
||||||
|
var charge = getMagicalReserves().getCharge();
|
||||||
|
charge.addPercent(MathHelper.clamp(amount / 10F, 5, 15));
|
||||||
|
float anger = charge.getPercentFill();
|
||||||
|
getMagicalReserves().getEnergy().addPercent(50 * anger);
|
||||||
|
playSound(USounds.ENTITY_PLAYER_KIRIN_RAGE, 0.2F, 1.25F);
|
||||||
|
spawnParticles(ParticleTypes.LAVA, 2);
|
||||||
|
|
||||||
|
if (anger > 0 && entity.getWorld().random.nextFloat() < anger / 2F) {
|
||||||
|
if (consumeSuperMove()) {
|
||||||
|
SpellType.RAGE.withTraits().apply(this, CastingMethod.INNATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!cause.isIn(DamageTypeTags.BYPASSES_SHIELD)
|
if (!cause.isIn(DamageTypeTags.BYPASSES_SHIELD)
|
||||||
&& !cause.isOf(DamageTypes.MAGIC)
|
&& !cause.isOf(DamageTypes.MAGIC)
|
||||||
&& !cause.isIn(DamageTypeTags.IS_FIRE)
|
&& !cause.isIn(DamageTypeTags.IS_FIRE)
|
||||||
|
|
|
@ -8,6 +8,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.entity.duck.LavaAffine;
|
import com.minelittlepony.unicopia.entity.duck.LavaAffine;
|
||||||
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
|
import com.minelittlepony.unicopia.Race;
|
||||||
|
import com.minelittlepony.unicopia.entity.Equine;
|
||||||
import com.minelittlepony.unicopia.entity.Living;
|
import com.minelittlepony.unicopia.entity.Living;
|
||||||
import com.minelittlepony.unicopia.entity.duck.EntityDuck;
|
import com.minelittlepony.unicopia.entity.duck.EntityDuck;
|
||||||
|
|
||||||
|
@ -37,7 +40,28 @@ abstract class MixinEntity implements EntityDuck {
|
||||||
|
|
||||||
@Inject(method = "isFireImmune", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "isFireImmune", at = @At("HEAD"), cancellable = true)
|
||||||
private void onIsFireImmune(CallbackInfoReturnable<Boolean> info) {
|
private void onIsFireImmune(CallbackInfoReturnable<Boolean> info) {
|
||||||
if (isLavaAffine()) {
|
if (isLavaAffine() || (this instanceof Equine.Container c) && c.get().getCompositeRace().includes(Race.KIRIN)) {
|
||||||
|
info.setReturnValue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "isSneaky", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onIsSneaky(CallbackInfoReturnable<Boolean> info) {
|
||||||
|
if (EquinePredicates.PLAYER_KIRIN.test((Entity)(Object)this)) {
|
||||||
|
info.setReturnValue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "getMaxAir", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onGetMaxAir(CallbackInfoReturnable<Integer> info) {
|
||||||
|
if (EquinePredicates.PLAYER_KIRIN.test((Entity)(Object)this)) {
|
||||||
|
info.setReturnValue(150);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "doesRenderOnFire", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onDoesRenderOnFire(CallbackInfoReturnable<Boolean> info) {
|
||||||
|
if (EquinePredicates.RAGING.test((Entity)(Object)this)) {
|
||||||
info.setReturnValue(true);
|
info.setReturnValue(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.minelittlepony.unicopia.mixin;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.Race;
|
||||||
|
import com.minelittlepony.unicopia.entity.Living;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.mob.WardenEntity;
|
||||||
|
|
||||||
|
@Mixin(WardenEntity.class)
|
||||||
|
abstract class MixinWardenEntity {
|
||||||
|
@Inject(method = "isValidTarget", at = @At("HEAD"), cancellable = true)
|
||||||
|
public void onIsValidTarget(@Nullable Entity entity, CallbackInfoReturnable<Boolean> info) {
|
||||||
|
if (Living.getOrEmpty(entity).filter(l -> l.getCompositeRace().includes(Race.KIRIN)).isPresent()) {
|
||||||
|
info.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,10 @@
|
||||||
"ability.unicopia.indoors": "I can't see the sky from here",
|
"ability.unicopia.indoors": "I can't see the sky from here",
|
||||||
"ability.unicopia.too_low": "I need to get higher up",
|
"ability.unicopia.too_low": "I need to get higher up",
|
||||||
"ability.unicopia.clear_skies": "The skies already look pretty clear",
|
"ability.unicopia.clear_skies": "The skies already look pretty clear",
|
||||||
|
"ability.unicopia.too_calm.1": "I need to get angrier...",
|
||||||
|
"ability.unicopia.too_calm.2": "I don't feel angry...",
|
||||||
|
"ability.unicopia.too_calm.3": "Bruce made it look easier than this...",
|
||||||
|
"ability.unicopia.too_calm.4": "Celestia give me strength...",
|
||||||
|
|
||||||
"itemGroup.unicopia.items": "Unicopia",
|
"itemGroup.unicopia.items": "Unicopia",
|
||||||
"itemGroup.unicopia.foraging": "Unicopia - Foraging",
|
"itemGroup.unicopia.foraging": "Unicopia - Foraging",
|
||||||
|
@ -394,6 +398,7 @@
|
||||||
"ability.unicopia.capture_cloud": "Bust Cloud",
|
"ability.unicopia.capture_cloud": "Bust Cloud",
|
||||||
"ability.unicopia.disguise": "Change Form",
|
"ability.unicopia.disguise": "Change Form",
|
||||||
"ability.unicopia.rainboom": "Sonic Rainboom",
|
"ability.unicopia.rainboom": "Sonic Rainboom",
|
||||||
|
"ability.unicopia.rage": "Rage",
|
||||||
|
|
||||||
"gui.unicopia.trait.label": "Element of %s",
|
"gui.unicopia.trait.label": "Element of %s",
|
||||||
"gui.unicopia.trait.group": "\n %s",
|
"gui.unicopia.trait.group": "\n %s",
|
||||||
|
|
|
@ -65,6 +65,13 @@
|
||||||
"unicopia:changeling/buzz0"
|
"unicopia:changeling/buzz0"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"entity.player.kirin.rage.loop": {
|
||||||
|
"category": "player",
|
||||||
|
"sounds": [
|
||||||
|
{ "name": "unicopia:kirin/rage/dark_matter", "stream": true },
|
||||||
|
{ "name": "unicopia:kirin/rage/dogged", "stream": true }
|
||||||
|
]
|
||||||
|
},
|
||||||
"entity.player.ears_ring": {
|
"entity.player.ears_ring": {
|
||||||
"category": "ambient",
|
"category": "ambient",
|
||||||
"subtitle": "unicopia.subtitle.ears_ringing",
|
"subtitle": "unicopia.subtitle.ears_ringing",
|
||||||
|
@ -72,11 +79,18 @@
|
||||||
"unicopia:ears/ringing"
|
"unicopia:ears/ringing"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"entity.player.heartbeat_loop": {
|
||||||
|
"category": "ambient",
|
||||||
|
"subtitle": "unicopia.subtitle.heartbeat",
|
||||||
|
"sounds": [
|
||||||
|
"unicopia:heartbeat/heartbeat_loop"
|
||||||
|
]
|
||||||
|
},
|
||||||
"entity.player.heartbeat": {
|
"entity.player.heartbeat": {
|
||||||
"category": "ambient",
|
"category": "ambient",
|
||||||
"subtitle": "unicopia.subtitle.heartbeat",
|
"subtitle": "unicopia.subtitle.heartbeat",
|
||||||
"sounds": [
|
"sounds": [
|
||||||
"unicopia:heartbeat/heartbeat"
|
"unicopia:heartbeat/heartbeat_1"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ambient.wind.gust": {
|
"ambient.wind.gust": {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
BIN
src/main/resources/assets/unicopia/sounds/kirin/rage/dogged.ogg
Normal file
BIN
src/main/resources/assets/unicopia/sounds/kirin/rage/dogged.ogg
Normal file
Binary file not shown.
BIN
src/main/resources/assets/unicopia/textures/gui/ability/rage.png
Normal file
BIN
src/main/resources/assets/unicopia/textures/gui/ability/rage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
109
src/main/resources/data/unicopia/state_maps/burnable.json
Normal file
109
src/main/resources/data/unicopia/state_maps/burnable.json
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
{
|
||||||
|
"parent": "unicopia:fire",
|
||||||
|
"replace": false,
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{ "tag": "minecraft:logs_that_burn" }
|
||||||
|
],
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:coal_block",
|
||||||
|
"chance": 0.15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{ "state": "minecraft:snow" },
|
||||||
|
{ "state": "minecraft:snow_block" },
|
||||||
|
{ "builtin": "plants" }
|
||||||
|
],
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:air"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{ "state": "minecraft:ice" },
|
||||||
|
{ "state": "minecraft:frosted_ice" }
|
||||||
|
],
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:water"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:clay" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:brown_concrete"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{ "state": "minecraft:obsidian" },
|
||||||
|
{ "state": "unicopia:frosted_obsidian" }
|
||||||
|
],
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:lava"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:grass_block" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:dirt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:mossy_cobblestone" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:cobblestone"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:mossy_cobblestone_wall" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:cobblestone_wall"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{ "state": "minecraft:mossy_stone_bricks" },
|
||||||
|
{ "state": "minecraft:infested_mossy_stone_bricks" }
|
||||||
|
],
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:stone_bricks"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:podzol" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:coarse_dirt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:farmland" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_property",
|
||||||
|
"property": "moisture",
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": { "state": "minecraft:dirt" },
|
||||||
|
"apply": {
|
||||||
|
"action": "unicopia:set_state",
|
||||||
|
"state": "minecraft:coarse_dirt",
|
||||||
|
"chance": 0.15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -43,6 +43,7 @@
|
||||||
"MixinStateManagerBuilder",
|
"MixinStateManagerBuilder",
|
||||||
"MixinBlockState",
|
"MixinBlockState",
|
||||||
"MixinTargetPredicate",
|
"MixinTargetPredicate",
|
||||||
|
"MixinWardenEntity",
|
||||||
"MixinWorld",
|
"MixinWorld",
|
||||||
"MixinWorldChunk",
|
"MixinWorldChunk",
|
||||||
"trinkets.MixinTrinketSurvivalSlot",
|
"trinkets.MixinTrinketSurvivalSlot",
|
||||||
|
|
Loading…
Reference in a new issue