The rainboom ability now requires you to perform tricks (diving and dashing) to charge it. #107

- 10 dashes or dives = 1 rainboom, but you can charge up multiple at a time by doing more.
- Flying whilst exhausted now deals damage but players who push through it are rewarded with another level
- Gusts of wind are now reduced by levelling up
This commit is contained in:
Sollace 2023-08-09 22:10:02 +01:00
parent 67e51b1f22
commit 15d43d5ab1
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
12 changed files with 154 additions and 35 deletions

View file

@ -12,6 +12,7 @@ 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
@ -28,6 +29,11 @@ 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();
@ -37,7 +43,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
@Override @Override
public Hit tryActivate(Pony player) { public Hit tryActivate(Pony player) {
if (!player.asEntity().isCreative() && player.getMagicalReserves().getMana().getPercentFill() < 0.2F) { if (!player.asEntity().isCreative() && !player.canUseSuperMove()) {
return null; return null;
} }
@ -55,7 +61,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
@Override @Override
public double getCostEstimate(Pony player) { public double getCostEstimate(Pony player) {
return 90F; return 0;
} }
@Override @Override
@ -64,6 +70,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
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));
player.subtractEnergyCost(4); player.subtractEnergyCost(4);
player.getMagicalReserves().getCharge().add(2);
return true; return true;
} }
@ -77,9 +84,10 @@ public class PegasusRainboomAbility implements Ability<Hit> {
return; return;
} }
player.subtractEnergyCost(9); 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);
}
} }
@Override @Override

View file

@ -21,6 +21,7 @@ public interface UCriteria {
CustomEventCriterion.Trigger KILL_PHANTOM_WHILE_FLYING = CUSTOM_EVENT.createTrigger("kill_phantom_while_flying"); CustomEventCriterion.Trigger KILL_PHANTOM_WHILE_FLYING = CUSTOM_EVENT.createTrigger("kill_phantom_while_flying");
CustomEventCriterion.Trigger USE_CONSUMPTION = CUSTOM_EVENT.createTrigger("use_consumption"); CustomEventCriterion.Trigger USE_CONSUMPTION = CUSTOM_EVENT.createTrigger("use_consumption");
CustomEventCriterion.Trigger USE_SOULMATE = CUSTOM_EVENT.createTrigger("use_soulmate"); CustomEventCriterion.Trigger USE_SOULMATE = CUSTOM_EVENT.createTrigger("use_soulmate");
CustomEventCriterion.Trigger SECOND_WIND = CUSTOM_EVENT.createTrigger("second_wind");
static void bootstrap() { } static void bootstrap() { }
} }

View file

@ -33,6 +33,7 @@ class ManaRingSlot extends Slot {
if (!uHud.client.player.isCreative()) { if (!uHud.client.player.isCreative()) {
renderRing(matrices, 13, 9, 0, mana.getXp(), 0x88880099, tickDelta); renderRing(matrices, 13, 9, 0, mana.getXp(), 0x88880099, tickDelta);
renderRing(matrices, 9, 0, 0, mana.getCharge(), 0x0000FF99, tickDelta);
double cost = abilities.getStats().stream() double cost = abilities.getStats().stream()
.mapToDouble(s -> s.getCost(Unicopia.getConfig().hudPage.get())) .mapToDouble(s -> s.getCost(Unicopia.getConfig().hudPage.get()))

View file

@ -47,6 +47,7 @@ public class Main extends MineLPDelegate implements ClientModInitializer {
Vec3d motion = entity.getVelocity(); Vec3d motion = entity.getVelocity();
double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z); double zMotion = Math.sqrt(motion.x * motion.x + motion.z * motion.z);
model.getAttributes().isGoingFast |= zMotion > 0.4F; model.getAttributes().isGoingFast |= zMotion > 0.4F;
model.getAttributes().isGoingFast |= pony.getMotion().isDiving();
} }
model.getAttributes().isGoingFast |= pony.getMotion().isRainbooming(); model.getAttributes().isGoingFast |= pony.getMotion().isRainbooming();
model.getAttributes().isGoingFast &= !pony.getEntityInArms().isPresent(); model.getAttributes().isGoingFast &= !pony.getEntityInArms().isPresent();

View file

@ -127,14 +127,18 @@ public class WorldRenderDelegate {
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(roll)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(roll));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(roll)); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(roll));
if (pony instanceof Pony) { if (pony instanceof Pony p) {
roll = ((Pony)pony).getCamera().calculateRoll(); roll = p.getCamera().calculateRoll();
if (negative) { if (negative) {
roll -= 180; roll -= 180;
} }
matrices.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw)); matrices.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw));
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll)); matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll));
float diveAngle = p.getInterpolator().interpolate("g_kdive", p.getMotion().isDiving() ? 80 : 0, 15);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(diveAngle));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
} }

View file

@ -31,6 +31,11 @@ public interface MagicReserves {
*/ */
Bar getXp(); Bar getXp();
/**
* Temporary mana charge collected by performing certain tasks.
*/
Bar getCharge();
public interface Bar { public interface Bar {
/** /**

View file

@ -1,5 +1,8 @@
package com.minelittlepony.unicopia.entity.player; package com.minelittlepony.unicopia.entity.player;
import java.util.HashMap;
import java.util.Map;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.Tickable; import com.minelittlepony.unicopia.util.Tickable;
@ -10,37 +13,43 @@ import net.minecraft.util.math.MathHelper;
public class ManaContainer implements MagicReserves, Tickable, NbtSerialisable { public class ManaContainer implements MagicReserves, Tickable, NbtSerialisable {
private final Pony pony; private final Pony pony;
private final Map<String, BarInst> bars = new HashMap<>();
private final BarInst energy; private final BarInst energy;
private final BarInst exhaustion; private final BarInst exhaustion;
private final BarInst exertion; private final BarInst exertion;
private final BarInst mana; private final BarInst mana;
private final BarInst xp; private final BarInst xp;
private final BarInst charge;
public ManaContainer(Pony pony) { public ManaContainer(Pony pony) {
this.pony = pony; this.pony = pony;
this.energy = new BarInst(Pony.ENERGY, 100F, 0); this.energy = addBar("energy", new BarInst(Pony.ENERGY, 100F, 0));
this.exhaustion = new BarInst(Pony.EXHAUSTION, 100F, 0); this.exhaustion = addBar("exhaustion", new BarInst(Pony.EXHAUSTION, 100F, 0));
this.exertion = new BarInst(Pony.EXERTION, 10F, 0); this.exertion = addBar("exertion", new BarInst(Pony.EXERTION, 10F, 0));
this.xp = new BarInst(Pony.XP, 1, 0); this.xp = addBar("xp", new BarInst(Pony.XP, 1, 0));
this.mana = new XpCollectingBar(Pony.MANA, 100F, 100F); this.mana = addBar("mana", new XpCollectingBar(Pony.MANA, 100F, 100F));
this.charge = addBar("charge", new BarInst(Pony.CHARGE, 10F, 0) {
@Override
protected float applyLimits(float value) {
return Math.max(0, value);
}
});
}
protected BarInst addBar(String name, BarInst bar) {
bars.put(name, bar);
return bar;
} }
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
compound.put("energy", energy.toNBT()); bars.forEach((key, bar) -> compound.put(key, bar.toNBT()));
compound.put("exhaustion", exhaustion.toNBT());
compound.put("exertion", exertion.toNBT());
compound.put("mana", mana.toNBT());
compound.put("xp", xp.toNBT());
} }
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
energy.fromNBT(compound.getCompound("energy")); bars.forEach((key, bar) -> bar.fromNBT(compound.getCompound(key)));
exhaustion.fromNBT(compound.getCompound("exhaustion"));
exertion.fromNBT(compound.getCompound("exertion"));
mana.fromNBT(compound.getCompound("mana"));
xp.fromNBT(compound.getCompound("xp"));
} }
@Override @Override
@ -68,12 +77,14 @@ public class ManaContainer implements MagicReserves, Tickable, NbtSerialisable {
return xp; return xp;
} }
@Override
public Bar getCharge() {
return charge;
}
@Override @Override
public void tick() { public void tick() {
exertion.tick(); bars.values().forEach(BarInst::tick);
energy.tick();
mana.tick();
xp.tick();
exertion.add(-10); exertion.add(-10);
@ -142,7 +153,7 @@ public class ManaContainer implements MagicReserves, Tickable, NbtSerialisable {
@Override @Override
public float get() { public float get() {
return pony.asEntity().getDataTracker().get(marker); return applyLimits(pony.asEntity().getDataTracker().get(marker));
} }
@Override @Override
@ -152,11 +163,17 @@ public class ManaContainer implements MagicReserves, Tickable, NbtSerialisable {
@Override @Override
public void set(float value) { public void set(float value) {
load(MathHelper.clamp(value, 0, getMax())); load(applyLimits(value));
} }
private void load(float value) { private void load(float value) {
pony.asEntity().getDataTracker().set(marker, value); if (!pony.isClient()) {
pony.asEntity().getDataTracker().set(marker, value);
}
}
protected float applyLimits(float value) {
return MathHelper.clamp(value, 0, getMax());
} }
@Override @Override

View file

@ -11,6 +11,8 @@ public interface Motion {
boolean isGliding(); boolean isGliding();
boolean isDiving();
boolean isRainbooming(); boolean isRainbooming();
float getWingAngle(); float getWingAngle();

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.entity.player;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
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;
@ -53,6 +54,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private int ticksInAir; private int ticksInAir;
private int ticksToGlide; private int ticksToGlide;
private int ticksDiving;
private float thrustScale = 0; private float thrustScale = 0;
@ -118,6 +120,11 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
return ticksToGlide <= 0 && isFlying() && !entity.isSneaking(); return ticksToGlide <= 0 && isFlying() && !entity.isSneaking();
} }
@Override
public boolean isDiving() {
return ticksDiving > 0;
}
@Override @Override
public boolean isRainbooming() { public boolean isRainbooming() {
return pony.getSpellSlot().get(SpellType.RAINBOOM, true).isPresent(); return pony.getSpellSlot().get(SpellType.RAINBOOM, true).isPresent();
@ -313,6 +320,19 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
velocity.y -= 0.2F * getGravitySignum(); velocity.y -= 0.2F * getGravitySignum();
velocity.y /= 2F; velocity.y /= 2F;
} }
double horizontalSpeed = this.getHorizontalMotion();
double verticalSpeed = velocity.y;
if (Abilities.RAINBOOM.canUse(pony.getActualSpecies()) && horizontalSpeed != 0 && verticalSpeed < -0.3F && (verticalSpeed / horizontalSpeed) < -0.3F) {
ticksDiving++;
} else {
ticksDiving = 0;
}
if (ticksDiving > 0 && ticksDiving % 25 == 0) {
pony.getMagicalReserves().getCharge().add(25);
}
} else { } else {
prevStrafe = 0; prevStrafe = 0;
strafe = 0; strafe = 0;
@ -321,6 +341,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
soundPlaying = false; soundPlaying = false;
descentRate = 0; descentRate = 0;
if (Abilities.RAINBOOM.canUse(pony.getActualSpecies()) && entity.isOnGround()) {
pony.getMagicalReserves().getCharge().set(0);
}
if (!creative && type.isAvian()) { if (!creative && type.isAvian()) {
checkAvianTakeoffConditions(velocity); checkAvianTakeoffConditions(velocity);
} }
@ -461,6 +485,19 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
entity.addExhaustion(exhaustion); entity.addExhaustion(exhaustion);
} }
if (pony.getMagicalReserves().getExhaustion().get() > 99 && ticksInAir % 25 == 0) {
entity.damage(pony.damageOf(UDamageTypes.EXHAUSTION), 2);
if (entity.getWorld().random.nextInt(110) == 1 && !pony.isClient()) {
pony.getLevel().add(1);
pony.getMagicalReserves().getCharge().add(4);
pony.getMagicalReserves().getExertion().set(0);
pony.getMagicalReserves().getExhaustion().set(0);
mana.set(mana.getMax() * 100);
UCriteria.SECOND_WIND.trigger(entity);
}
}
} }
} }
} }
@ -624,7 +661,9 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private void applyTurbulance(MutableVector velocity) { private void applyTurbulance(MutableVector velocity) {
int globalEffectStrength = MathHelper.clamp(entity.getWorld().getGameRules().getInt(UGameRules.WEATHER_EFFECTS_STRENGTH), 0, 100); int globalEffectStrength = MathHelper.clamp(entity.getWorld().getGameRules().getInt(UGameRules.WEATHER_EFFECTS_STRENGTH), 0, 100);
float effectStrength = Math.min(1, (float)ticksInAir / MAX_TICKS_TO_WEATHER_EFFECTS) * (globalEffectStrength / 100F); float effectStrength = Math.min(1, (float)ticksInAir / MAX_TICKS_TO_WEATHER_EFFECTS) * (globalEffectStrength / 100F);
Vec3d gust = WeatherConditions.getGustStrength(entity.getWorld(), entity.getBlockPos()).multiply(globalEffectStrength / 100D); Vec3d gust = WeatherConditions.getGustStrength(entity.getWorld(), entity.getBlockPos())
.multiply(globalEffectStrength / 100D)
.multiply(1 / (1 + Math.floor(pony.getLevel().get() / 10F)));
if (effectStrength * gust.getX() >= 1) { if (effectStrength * gust.getX() >= 1) {
SoundEmitter.playSoundAt(entity, USounds.AMBIENT_WIND_GUST, SoundCategory.AMBIENT, 3, 1); SoundEmitter.playSoundAt(entity, USounds.AMBIENT_WIND_GUST, SoundCategory.AMBIENT, 3, 1);

View file

@ -21,6 +21,7 @@ import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck;
import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect; import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
import com.minelittlepony.unicopia.entity.effect.UEffects; import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem; import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
@ -71,6 +72,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
static final TrackedData<Optional<BlockPos>> HANGING_POSITION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS); static final TrackedData<Optional<BlockPos>> HANGING_POSITION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS);
static final TrackedData<Float> MANA = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); static final TrackedData<Float> MANA = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> XP = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT); static final TrackedData<Float> XP = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Float> CHARGE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.FLOAT);
static final TrackedData<Integer> LEVEL = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); static final TrackedData<Integer> LEVEL = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
static final TrackedData<Integer> CORRUPTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER); static final TrackedData<Integer> CORRUPTION = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.INTEGER);
@ -266,6 +268,19 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
return corruption; return corruption;
} }
public boolean canUseSuperMove() {
return getMagicalReserves().getCharge().get() >= getMagicalReserves().getCharge().get();
}
public boolean consumeSuperMove() {
if (canUseSuperMove()) {
Bar charge = getMagicalReserves().getCharge();
charge.set(charge.get() - charge.getMax());
return true;
}
return false;
}
public boolean isSunImmune() { public boolean isSunImmune() {
return ticksSunImmunity > 0; return ticksSunImmunity > 0;
} }

View file

@ -805,19 +805,16 @@
"advancements.unicopia.sky_route.title": "Path of the Pegasus", "advancements.unicopia.sky_route.title": "Path of the Pegasus",
"advancements.unicopia.sky_route.description": "Join the Clousdale Pegasi", "advancements.unicopia.sky_route.description": "Join the Clousdale Pegasi",
"advancements.unicopia.molting_season_1.title": "Molting Season", "advancements.unicopia.molting_season_1.title": "Molting Season",
"advancements.unicopia.molting_season_1.description": "Drop a feather whilst flying", "advancements.unicopia.molting_season_1.description": "Drop a feather whilst flying",
"advancements.unicopia.molting_season_2.title": "Molting Season 2", "advancements.unicopia.molting_season_2.title": "Molting Season 2",
"advancements.unicopia.molting_season_2.description": "Drop 5 feathers whilst flying", "advancements.unicopia.molting_season_2.description": "Drop 5 feathers whilst flying",
"advancements.unicopia.molting_season_3.title": "Molting Season 3", "advancements.unicopia.molting_season_3.title": "Molting Season 3",
"advancements.unicopia.molting_season_3.description": "Drop 15 feathers whilst flying", "advancements.unicopia.molting_season_3.description": "Drop 15 feathers whilst flying",
"advancements.unicopia.rainbow_crash.title": "Dammit, Rainbow", "advancements.unicopia.rainbow_crash.title": "Dammit, Rainbow",
"advancements.unicopia.rainbow_crash.description": "Wage war on the evil glass window nation", "advancements.unicopia.rainbow_crash.description": "Wage war on the evil glass window nation",
"advancements.unicopia.second_wind.title": "Second Wind",
"advancements.unicopia.second_wind.description": "Fly through the pain",
"advancements.unicopia.deter_phantom.title": "What Flies Around", "advancements.unicopia.deter_phantom.title": "What Flies Around",
"advancements.unicopia.deter_phantom.description": "Get up there and give those phantoms a taste of their own medicine", "advancements.unicopia.deter_phantom.description": "Get up there and give those phantoms a taste of their own medicine",

View file

@ -0,0 +1,29 @@
{
"parent": "unicopia:unicopia/pegasus/sky_route",
"display": {
"icon": {
"item": "unicopia:pegasus_badge"
},
"title": {
"translate": "advancements.unicopia.second_wind.title"
},
"description": {
"translate": "advancements.unicopia.second_wind.description"
},
"frame": "task",
"show_toast": true,
"announce_to_chat": true,
"hidden": false
},
"criteria": {
"fly_through_the_pain": {
"trigger": "unicopia:custom",
"conditions": {
"event": "second_wind"
}
}
},
"requirements": [
[ "fly_through_the_pain" ]
]
}