mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Unicorns now have the option to takes friends with them when they teleport (at an extra cost)
This commit is contained in:
parent
209ddbb972
commit
fef8de15d8
11 changed files with 89 additions and 57 deletions
|
@ -17,6 +17,7 @@ public interface Abilities {
|
||||||
// unicorn / alicorn
|
// unicorn / alicorn
|
||||||
Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY);
|
Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY);
|
||||||
Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY);
|
Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY);
|
||||||
|
Ability<?> GROUP_TELEPORT = register(new UnicornGroupTeleportAbility(), "group_teleport", AbilitySlot.SECONDARY);
|
||||||
Ability<?> SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.TERTIARY);
|
Ability<?> SHOOT = register(new UnicornProjectileAbility(), "shoot", AbilitySlot.TERTIARY);
|
||||||
|
|
||||||
// earth / alicorn
|
// earth / alicorn
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.minelittlepony.unicopia.ability;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.data.Pos;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unicorn teleport ability with friends
|
||||||
|
*/
|
||||||
|
public class UnicornGroupTeleportAbility extends UnicornTeleportAbility {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getCostEstimate(Pony player) {
|
||||||
|
double cost = super.getCostEstimate(player);
|
||||||
|
|
||||||
|
if (cost == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return cost * (1 + getComrades(player).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(Pony player, Pos data) {
|
||||||
|
getComrades(player).forEach(teleportee -> teleport(player, teleportee, data));
|
||||||
|
super.apply(player, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<Caster<?>> getComrades(Pony player) {
|
||||||
|
return Caster.stream(player.findAllEntitiesInRange(3, e -> FriendshipBraceletItem.isComrade(player, e)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability;
|
||||||
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;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
import com.minelittlepony.unicopia.util.RayTraceHelper;
|
import com.minelittlepony.unicopia.util.RayTraceHelper;
|
||||||
|
@ -12,6 +13,7 @@ import net.minecraft.block.FenceBlock;
|
||||||
import net.minecraft.block.LeavesBlock;
|
import net.minecraft.block.LeavesBlock;
|
||||||
import net.minecraft.block.WallBlock;
|
import net.minecraft.block.WallBlock;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
|
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
|
||||||
import net.minecraft.predicate.entity.EntityPredicates;
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
|
@ -23,6 +25,7 @@ import net.minecraft.util.hit.BlockHitResult;
|
||||||
import net.minecraft.util.hit.HitResult;
|
import net.minecraft.util.hit.HitResult;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,9 +33,6 @@ import net.minecraft.world.World;
|
||||||
*/
|
*/
|
||||||
public class UnicornTeleportAbility implements Ability<Pos> {
|
public class UnicornTeleportAbility implements Ability<Pos> {
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon representing this ability on the UI and HUD.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Identifier getIcon(Pony player, boolean swap) {
|
public Identifier getIcon(Pony player, boolean swap) {
|
||||||
Identifier id = Abilities.REGISTRY.getId(this);
|
Identifier id = Abilities.REGISTRY.getId(this);
|
||||||
|
@ -125,10 +125,15 @@ public class UnicornTeleportAbility implements Ability<Pos> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Pony iplayer, Pos data) {
|
public void apply(Pony iplayer, Pos data) {
|
||||||
iplayer.getWorld().playSound(null, iplayer.getOrigin(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
|
teleport(iplayer, iplayer, data);
|
||||||
|
}
|
||||||
|
|
||||||
PlayerEntity player = iplayer.getMaster();
|
protected void teleport(Pony teleporter, Caster<?> teleportee, Pos destination) {
|
||||||
double distance = data.distanceTo(iplayer) / 10;
|
teleportee.getWorld().playSound(null, teleportee.getOrigin(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
|
||||||
|
|
||||||
|
double distance = destination.distanceTo(teleportee) / 10;
|
||||||
|
|
||||||
|
LivingEntity player = teleportee.getMaster();
|
||||||
|
|
||||||
if (player.hasVehicle()) {
|
if (player.hasVehicle()) {
|
||||||
Entity mount = player.getVehicle();
|
Entity mount = player.getVehicle();
|
||||||
|
@ -140,15 +145,17 @@ public class UnicornTeleportAbility implements Ability<Pos> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec3d offset = teleportee.getOriginVector().subtract(teleporter.getOriginVector());
|
||||||
|
|
||||||
player.teleport(
|
player.teleport(
|
||||||
data.x + (player.getX() - Math.floor(player.getX())),
|
destination.x + offset.x + (player.getX() - Math.floor(player.getX())),
|
||||||
data.y,
|
destination.y + offset.y,
|
||||||
data.z + (player.getZ() - Math.floor(player.getZ())));
|
destination.z + offset.z + (player.getZ() - Math.floor(player.getZ())));
|
||||||
iplayer.subtractEnergyCost(distance);
|
teleporter.subtractEnergyCost(distance);
|
||||||
|
|
||||||
player.fallDistance /= distance;
|
player.fallDistance /= distance;
|
||||||
|
|
||||||
player.world.playSound(null, data.pos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
|
player.world.playSound(null, destination.pos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean enterable(World w, BlockPos pos) {
|
private boolean enterable(World w, BlockPos pos) {
|
||||||
|
|
|
@ -6,8 +6,10 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
import com.minelittlepony.unicopia.Owned;
|
import com.minelittlepony.unicopia.Owned;
|
||||||
import com.minelittlepony.unicopia.entity.Physics;
|
import com.minelittlepony.unicopia.entity.Physics;
|
||||||
|
import com.minelittlepony.unicopia.entity.PonyContainer;
|
||||||
import com.minelittlepony.unicopia.network.EffectSync;
|
import com.minelittlepony.unicopia.network.EffectSync;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleSource;
|
import com.minelittlepony.unicopia.particle.ParticleSource;
|
||||||
import com.minelittlepony.unicopia.util.VecHelper;
|
import com.minelittlepony.unicopia.util.VecHelper;
|
||||||
|
@ -105,7 +107,11 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
||||||
}
|
}
|
||||||
|
|
||||||
default Stream<Caster<?>> findAllSpellsInRange(double radius) {
|
default Stream<Caster<?>> findAllSpellsInRange(double radius) {
|
||||||
return CasterUtils.findInRange(this, radius);
|
return findAllSpellsInRange(radius, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Stream<Caster<?>> findAllSpellsInRange(double radius, @Nullable Predicate<Entity> test) {
|
||||||
|
return stream(findAllEntitiesInRange(radius, test == null ? EquinePredicates.IS_CASTER : EquinePredicates.IS_CASTER.and(test)));
|
||||||
}
|
}
|
||||||
|
|
||||||
default Stream<Entity> findAllEntitiesInRange(double radius, @Nullable Predicate<Entity> test) {
|
default Stream<Entity> findAllEntitiesInRange(double radius, @Nullable Predicate<Entity> test) {
|
||||||
|
@ -115,4 +121,26 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
|
||||||
default Stream<Entity> findAllEntitiesInRange(double radius) {
|
default Stream<Entity> findAllEntitiesInRange(double radius) {
|
||||||
return findAllEntitiesInRange(radius, null);
|
return findAllEntitiesInRange(radius, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Stream<Caster<?>> stream(Stream<Entity> entities) {
|
||||||
|
return entities
|
||||||
|
.map(Caster::of)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to convert the passed entity into a caster using all the known methods.
|
||||||
|
*/
|
||||||
|
static Optional<Caster<?>> of(@Nullable Entity entity) {
|
||||||
|
if (entity instanceof Caster<?>) {
|
||||||
|
return Optional.of((Caster<?>)entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity instanceof LivingEntity && !(entity instanceof Magical)) {
|
||||||
|
return PonyContainer.of(entity).map(PonyContainer::getCaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquinePredicates;
|
|
||||||
import com.minelittlepony.unicopia.entity.PonyContainer;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
|
||||||
|
|
||||||
public class CasterUtils {
|
|
||||||
/**
|
|
||||||
* Finds all surrounding spells within range from the given caster.
|
|
||||||
*/
|
|
||||||
static Stream<Caster<?>> findInRange(Caster<?> source, double radius) {
|
|
||||||
return source.findAllEntitiesInRange(radius, EquinePredicates.IS_CASTER)
|
|
||||||
.map(e -> toCaster(e).filter(o -> o != source))
|
|
||||||
.filter(Optional::isPresent)
|
|
||||||
.map(Optional::get);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to convert the passed entity into a caster using all the known methods.
|
|
||||||
*/
|
|
||||||
public static Optional<Caster<?>> toCaster(@Nullable Entity entity) {
|
|
||||||
if (entity instanceof Caster<?>) {
|
|
||||||
return Optional.of((Caster<?>)entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity instanceof LivingEntity && !(entity instanceof Magical)) {
|
|
||||||
return PonyContainer.of(entity).map(PonyContainer::getCaster);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.FlightType;
|
||||||
import com.minelittlepony.unicopia.InteractionManager;
|
import com.minelittlepony.unicopia.InteractionManager;
|
||||||
import com.minelittlepony.unicopia.Owned;
|
import com.minelittlepony.unicopia.Owned;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.CasterUtils;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
|
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
|
||||||
|
@ -171,7 +170,7 @@ public class Disguise implements NbtSerialisable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CasterUtils.toCaster(entity).ifPresent(c -> c.setSpell(null));
|
Caster.of(entity).ifPresent(c -> c.setSpell(null));
|
||||||
|
|
||||||
if (source.isClient()) {
|
if (source.isClient()) {
|
||||||
source.getWorld().spawnEntity(entity);
|
source.getWorld().spawnEntity(entity);
|
||||||
|
@ -340,7 +339,7 @@ public class Disguise implements NbtSerialisable {
|
||||||
VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
|
VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
|
||||||
|
|
||||||
world.getOtherEntities(entity, box.expand(0.5), predicate.and(e -> {
|
world.getOtherEntities(entity, box.expand(0.5), predicate.and(e -> {
|
||||||
CasterUtils.toCaster(e).flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false)).ifPresent(p -> {
|
Caster.of(e).flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false)).ifPresent(p -> {
|
||||||
p.getDisguise().getCollissionShapes(ctx, shape -> {
|
p.getDisguise().getCollissionShapes(ctx, shape -> {
|
||||||
if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
|
if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
|
||||||
shapes.add(shape);
|
shapes.add(shape);
|
||||||
|
|
|
@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
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.ability.magic.CasterUtils;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
|
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
|
||||||
import com.minelittlepony.unicopia.entity.Creature;
|
import com.minelittlepony.unicopia.entity.Creature;
|
||||||
import com.minelittlepony.unicopia.entity.PonyContainer;
|
import com.minelittlepony.unicopia.entity.PonyContainer;
|
||||||
|
@ -72,7 +72,7 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
|
||||||
|
|
||||||
@Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true)
|
||||||
private void onIsPushable(CallbackInfoReturnable<Boolean> info) {
|
private void onIsPushable(CallbackInfoReturnable<Boolean> info) {
|
||||||
CasterUtils.toCaster(this)
|
Caster.of(this)
|
||||||
.flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false))
|
.flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false))
|
||||||
.map(DisguiseSpell::getDisguise)
|
.map(DisguiseSpell::getDisguise)
|
||||||
.map(Disguise::getAppearance)
|
.map(Disguise::getAppearance)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.CasterUtils;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
@ -18,6 +18,6 @@ abstract class MixinMilkBucketItem extends Item {
|
||||||
|
|
||||||
@Inject(method = "finishUsing", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "finishUsing", at = @At("HEAD"), cancellable = true)
|
||||||
private void finishUsing(ItemStack stack, World world, LivingEntity entity, CallbackInfoReturnable<ItemStack> info) {
|
private void finishUsing(ItemStack stack, World world, LivingEntity entity, CallbackInfoReturnable<ItemStack> info) {
|
||||||
CasterUtils.toCaster(entity).ifPresent(c -> c.setSpell(null));
|
Caster.of(entity).ifPresent(c -> c.setSpell(null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,7 @@
|
||||||
"ability.unicopia.shoot": "Magic Missle",
|
"ability.unicopia.shoot": "Magic Missle",
|
||||||
"ability.unicopia.cast": "Counterspell",
|
"ability.unicopia.cast": "Counterspell",
|
||||||
"ability.unicopia.teleport": "Teleport",
|
"ability.unicopia.teleport": "Teleport",
|
||||||
|
"ability.unicopia.group_teleport": "Teleport (Group)",
|
||||||
"ability.unicopia.grow": "Earthly Nourishment",
|
"ability.unicopia.grow": "Earthly Nourishment",
|
||||||
"ability.unicopia.stomp": "Ground Pound",
|
"ability.unicopia.stomp": "Ground Pound",
|
||||||
"ability.unicopia.kick": "Crushing Blow",
|
"ability.unicopia.kick": "Crushing Blow",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 455 B |
Binary file not shown.
After Width: | Height: | Size: 547 B |
Loading…
Reference in a new issue